feat: debug and gemini
This commit is contained in:
parent
df3a2f6e18
commit
4b198c3bc4
|
|
@ -0,0 +1,239 @@
|
|||
return {
|
||||
'kiddos/gemini.nvim',
|
||||
config = function(gemini_opts)
|
||||
require('gemini').setup(gemini_opts)
|
||||
|
||||
local function get_recursive_cwd_context()
|
||||
local cwd = vim.fn.getcwd()
|
||||
local all_files = vim.fn.globpath(cwd, '**/*', false, true)
|
||||
local context = 'Context: Here is the relevant code from the current project:\n\n'
|
||||
|
||||
-- Define the file extensions you want to allow
|
||||
local allowed_extensions = {
|
||||
'lua',
|
||||
'js',
|
||||
'ts',
|
||||
'py',
|
||||
'go',
|
||||
'c',
|
||||
'cpp',
|
||||
'h',
|
||||
'md',
|
||||
'txt',
|
||||
'html',
|
||||
'css',
|
||||
'json',
|
||||
'toml',
|
||||
'yaml',
|
||||
}
|
||||
|
||||
for _, file in ipairs(all_files) do
|
||||
if vim.fn.isdirectory(file) == 0 then
|
||||
local relative_path = vim.fn.fnamemodify(file, ':.')
|
||||
local ext = vim.fn.fnamemodify(file, ':e') -- Get file extension
|
||||
|
||||
local is_allowed = false
|
||||
for _, allowed in ipairs(allowed_extensions) do
|
||||
if ext == allowed then
|
||||
is_allowed = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Additional check to skip common large/hidden directories like .git
|
||||
if is_allowed and not relative_path:match '%.git/' then
|
||||
local f = io.open(file, 'r')
|
||||
if f then
|
||||
local content = f:read '*all'
|
||||
f:close()
|
||||
-- Limit individual file size to 50KB to protect context window
|
||||
if #content < 50000 then
|
||||
context = context .. string.format('File: `%s`\n```%s\n%s\n```\n\n', relative_path, ext, content)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return context
|
||||
end
|
||||
|
||||
vim.keymap.set('n', '<leader>ga', ':GeminiApply<CR>', { desc = '[G]emini [A]pply' })
|
||||
vim.keymap.set('n', '<leader>gt', function()
|
||||
vim.ui.input({ prompt = 'Gemini Task: ' }, function(input)
|
||||
if input and input ~= '' then
|
||||
vim.cmd('GeminiTask ' .. input)
|
||||
end
|
||||
end)
|
||||
end, { desc = '[G]emini [C]hat with input' })
|
||||
|
||||
vim.keymap.set('n', '<leader>gc', function()
|
||||
vim.ui.input({ prompt = 'Gemini Chat: ' }, function(input)
|
||||
if input and input ~= '' then
|
||||
vim.cmd('GeminiChat ' .. input)
|
||||
end
|
||||
end)
|
||||
end, { desc = '[G]emini [C]hat with input' })
|
||||
|
||||
vim.keymap.set('n', '<leader>ge', function()
|
||||
vim.ui.input({ prompt = 'Gemini Code Explain: ' }, function(input)
|
||||
if input and input ~= '' then
|
||||
vim.cmd('GeminiCodeExplain ' .. input)
|
||||
end
|
||||
end)
|
||||
end, { desc = '[G]emini Code [E]xplain with input' })
|
||||
|
||||
vim.keymap.set('n', '<leader>gr', function()
|
||||
vim.ui.input({ prompt = 'Gemini Code Review: ' }, function(input)
|
||||
if input and input ~= '' then
|
||||
vim.cmd('GeminiCodeReview ' .. input)
|
||||
end
|
||||
end)
|
||||
end, { desc = '[G]emini Code [R]eview with input' })
|
||||
|
||||
vim.keymap.set('n', '<leader>gr', function()
|
||||
vim.ui.input({ prompt = 'Gemini Unit Test: ' }, function(input)
|
||||
if input and input ~= '' then
|
||||
vim.cmd('GeminiUnitTest ' .. input)
|
||||
end
|
||||
end)
|
||||
end, { desc = '[G]emini [U]nit Test with input' })
|
||||
end,
|
||||
opts = {
|
||||
model_config = {
|
||||
model_id = 'gemini-2.5-flash',
|
||||
temperature = 0.10,
|
||||
top_k = 128,
|
||||
response_mime_type = 'text/plain',
|
||||
},
|
||||
chat_config = {
|
||||
enabled = true,
|
||||
},
|
||||
hints = {
|
||||
enabled = true,
|
||||
hints_delay = 2000,
|
||||
insert_result_key = '<S-Tab>',
|
||||
get_prompt = function(node, bufnr)
|
||||
local code_block = vim.treesitter.get_node_text(node, bufnr)
|
||||
local filetype = vim.api.nvim_get_option_value('filetype', { buf = bufnr })
|
||||
local prompt = [[
|
||||
In struction: Use 1 or 2 sentences to describe what the following {filetype} function does:
|
||||
|
||||
```{filetype}
|
||||
{code_block}
|
||||
``]] .. '`'
|
||||
prompt = prompt:gsub('{filetype}', filetype)
|
||||
prompt = prompt:gsub('{code_block}', code_block)
|
||||
return prompt
|
||||
end,
|
||||
},
|
||||
completion = {
|
||||
enabled = true,
|
||||
blacklist_filetypes = { 'help', 'qf', 'json', 'yaml', 'toml', 'xml' },
|
||||
blacklist_filenames = { '.env' },
|
||||
completion_delay = 800,
|
||||
insert_result_key = '<S-Tab>',
|
||||
move_cursor_end = true,
|
||||
can_complete = function()
|
||||
return vim.fn.pumvisible() ~= 1
|
||||
end,
|
||||
get_system_text = function()
|
||||
return "You are a coding AI assistant that autocomplete user's code."
|
||||
.. '\n* Your task is to provide code suggestion at the cursor location marked by <cursor></cursor>.'
|
||||
.. '\n* Your response does not need to contain explaination.'
|
||||
end,
|
||||
get_prompt = function(bufnr, pos)
|
||||
local filetype = vim.api.nvim_get_option_value('filetype', { buf = bufnr })
|
||||
local prompt = 'Below is the content of a %s file `%s`:\n'
|
||||
.. '```%s\n%s\n```\n\n'
|
||||
.. 'Suggest the most likely code at <cursor></cursor>.\n'
|
||||
.. 'Wrap your response in ``` ```\n'
|
||||
.. 'eg.\n```\n```\n\n'
|
||||
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||
local line = pos[1]
|
||||
local col = pos[2]
|
||||
local target_line = lines[line]
|
||||
if target_line then
|
||||
lines[line] = target_line:sub(1, col) .. '<cursor></cursor>' .. target_line:sub(col + 1)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
local code = vim.fn.join(lines, '\n')
|
||||
local abs_path = vim.api.nvim_buf_get_name(bufnr)
|
||||
local filename = vim.fn.fnamemodify(abs_path, ':.')
|
||||
prompt = string.format(prompt, filetype, filename, filetype, code)
|
||||
return prompt
|
||||
end,
|
||||
},
|
||||
instruction = {
|
||||
enabled = true,
|
||||
menu_key = '<Leader><Leader><Leader>g',
|
||||
prompts = {
|
||||
{
|
||||
name = 'Unit Test',
|
||||
command_name = 'GeminiUnitTest',
|
||||
menu = 'Unit Test 🚀',
|
||||
get_prompt = function(lines, bufnr)
|
||||
local code = vim.fn.join(lines, '\n')
|
||||
local filetype = vim.api.nvim_get_option_value('filetype', { buf = bufnr })
|
||||
local prompt = 'Context:\n\n```%s\n%s\n```\n\n' .. 'Objective: Write unit test for the above snippet of code\n'
|
||||
return string.format(prompt, filetype, code)
|
||||
end,
|
||||
},
|
||||
{
|
||||
name = 'Code Review',
|
||||
command_name = 'GeminiCodeReview',
|
||||
menu = 'Code Review 📜',
|
||||
get_prompt = function(lines, bufnr)
|
||||
local code = vim.fn.join(lines, '\n')
|
||||
local filetype = vim.api.nvim_get_option_value('filetype', { buf = bufnr })
|
||||
local prompt = 'Context:\n\n```%s\n%s\n```\n\n'
|
||||
.. 'Objective: Do a thorough code review for the following code.\n'
|
||||
.. 'Provide detail explaination and sincere comments.\n'
|
||||
return string.format(prompt, filetype, code)
|
||||
end,
|
||||
},
|
||||
{
|
||||
name = 'Code Explain',
|
||||
command_name = 'GeminiCodeExplain',
|
||||
menu = 'Code Explain',
|
||||
get_prompt = function(lines, bufnr)
|
||||
local code = vim.fn.join(lines, '\n')
|
||||
local filetype = vim.api.nvim_get_option_value('filetype', { buf = bufnr })
|
||||
local prompt = 'Context:\n\n```%s\n%s\n```\n\n'
|
||||
.. 'Objective: Explain the following code.\n'
|
||||
.. 'Provide detail explaination and sincere comments.\n'
|
||||
return string.format(prompt, filetype, code)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
task = {
|
||||
enabled = true,
|
||||
get_system_text = function()
|
||||
return 'You are an AI assistant that helps user write code.' .. '\n* You should output the new content for the Current Opened File'
|
||||
end,
|
||||
get_prompt = function(bufnr, user_prompt)
|
||||
local buffers = vim.api.nvim_list_bufs()
|
||||
local file_contents = {}
|
||||
|
||||
for _, b in ipairs(buffers) do
|
||||
if vim.api.nvim_buf_is_loaded(b) then -- Only get content from loaded buffers
|
||||
local lines = vim.api.nvim_buf_get_lines(b, 0, -1, false)
|
||||
local abs_path = vim.api.nvim_buf_get_name(b)
|
||||
local filename = vim.fn.fnamemodify(abs_path, ':.')
|
||||
local filetype = vim.api.nvim_get_option_value('filetype', { buf = b })
|
||||
local file_content = table.concat(lines, '\n')
|
||||
file_content = string.format('`%s`:\n\n```%s\n%s\n```\n\n', filename, filetype, file_content)
|
||||
table.insert(file_contents, file_content)
|
||||
end
|
||||
end
|
||||
|
||||
local current_filepath = vim.api.nvim_buf_get_name(bufnr)
|
||||
current_filepath = vim.fn.fnamemodify(current_filepath, ':.')
|
||||
|
||||
local context = table.concat(file_contents, '\n\n')
|
||||
return string.format('%s\n\nCurrent Opened File: %s\n\nTask: %s', context, current_filepath, user_prompt)
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -190,13 +190,20 @@ return {
|
|||
}
|
||||
|
||||
-- Install javascript specific config
|
||||
require('dap-vscode-js').setup {
|
||||
debugger_path = vim.fn.stdpath 'data' .. '/mason/packages/js-debug-adapter',
|
||||
debugger_cmd = { 'js-debug-adapter' },
|
||||
adapters = { 'pwa-node', 'pwa-chrome', 'pwa-msedge', 'node-terminal', 'pwa-extensionHost' },
|
||||
if not dap.adapters['pwa-node'] then
|
||||
require('dap').adapters['pwa-node'] = {
|
||||
type = 'server',
|
||||
host = 'localhost',
|
||||
port = '${port}',
|
||||
executable = {
|
||||
command = 'js-debug-adapter', -- This command comes from Mason
|
||||
args = { '${port}' }, -- formatting the port here prevents EADDRINUSE
|
||||
},
|
||||
}
|
||||
end
|
||||
dap.adapters['pwa-chrome'] = dap.adapters['pwa-node']
|
||||
|
||||
for _, jsLang in ipairs { 'typescript', 'javascript' } do
|
||||
for _, jsLang in ipairs { 'typescript', 'javascript', 'vue' } do
|
||||
require('dap').configurations[jsLang] = {
|
||||
{
|
||||
type = 'pwa-node',
|
||||
|
|
@ -228,49 +235,12 @@ return {
|
|||
internalConsoleOptions = 'neverOpen',
|
||||
},
|
||||
{
|
||||
name = 'Debug Main Process (Electron)',
|
||||
type = 'pwa-node',
|
||||
type = 'pwa-chrome',
|
||||
request = 'launch',
|
||||
program = '${workspaceFolder}/node_modules/.bin/electron',
|
||||
args = {
|
||||
'${workspaceFolder}/dist/index.js',
|
||||
},
|
||||
outFiles = {
|
||||
'${workspaceFolder}/dist/*.js',
|
||||
},
|
||||
resolveSourceMapLocations = {
|
||||
'${workspaceFolder}/dist/**/*.js',
|
||||
'${workspaceFolder}/dist/*.js',
|
||||
},
|
||||
rootPath = '${workspaceFolder}',
|
||||
cwd = '${workspaceFolder}',
|
||||
sourceMaps = true,
|
||||
skipFiles = { '<node_internals>/**' },
|
||||
protocol = 'inspector',
|
||||
console = 'integratedTerminal',
|
||||
},
|
||||
{
|
||||
name = 'Compile & Debug Main Process (Electron)',
|
||||
type = custom_adapter,
|
||||
request = 'launch',
|
||||
preLaunchTask = 'npm run build-ts',
|
||||
program = '${workspaceFolder}/node_modules/.bin/electron',
|
||||
args = {
|
||||
'${workspaceFolder}/dist/index.js',
|
||||
},
|
||||
outFiles = {
|
||||
'${workspaceFolder}/dist/*.js',
|
||||
},
|
||||
resolveSourceMapLocations = {
|
||||
'${workspaceFolder}/dist/**/*.js',
|
||||
'${workspaceFolder}/dist/*.js',
|
||||
},
|
||||
rootPath = '${workspaceFolder}',
|
||||
cwd = '${workspaceFolder}',
|
||||
sourceMaps = true,
|
||||
skipFiles = { '<node_internals>/**' },
|
||||
protocol = 'inspector',
|
||||
console = 'integratedTerminal',
|
||||
name = 'Start Chrome with "localhost"',
|
||||
url = 'http://localhost:5173',
|
||||
webRoot = '${workspaceFolder}',
|
||||
userDataDir = '${workspaceFolder}/.nvim/debug-profile',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue