diff --git a/README.md b/README.md index af112f3..0e7cd8b 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,15 @@ AI autocomplete plugin for neovim +support me!!! it is difficult to develop open source while searching for jobs. scan and support +![IMG-20250829-WA0012](https://github.com/user-attachments/assets/e86526b6-6819-4ae5-a3b7-6698af3f03ee) + + ## How to launch the server -launch the llama-server on http://127.0.0.1:8080 +```bash +llama-server --no-mmap -hf bartowski/Llama-3.2-3B-Instruct-GGUF:Q8_0 +``` ## Installation @@ -12,20 +18,30 @@ launch the llama-server on http://127.0.0.1:8080 ```lua return { - "PyDevC/model-cmp.nvim", - config = function () - require("model_cmp").setup() - end + "PyDevC/model-cmp.nvim", + config = function() + require("model_cmp").setup({ + delay = 1, + + api = { + custom_url = { + url = "http://127.0.0.1", + port = "8080" + } + }, + + virtualtext = { + enable = false, + type = "inline", + + style = { -- This is just a highlight group + fg = "#b53a3a", + italic = false, + bold = false + } + + }, + }) + end, } ``` - -## What technique do we use? - -We actually use few shot prompting with self experimentation - -## Current Limitations - -- limited to the capabilities of the underlying LLM model. -- No configurations -- does not work well with markdown -- Output cpature does not work properly diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..2ff3d38 --- /dev/null +++ b/TODO.md @@ -0,0 +1,18 @@ +# TODO + +- Load multiple lines of vitualtext even if not enough space. +- remove all the extmarks even. +- Capture single line virtual text +- Capture All line capture +- Treat the suggestions as a buffer and move through it for custom suggestions pickup +- manage response gracefully +- improve context engine +- improve modelapi +- setup openai and claude services +- Different prompt style +- Conversational few-shot prompt +- improve commands for different scenarios +- Lsp support +- nvim-cmp support +- Chat options +- more AI models diff --git a/lua/model_cmp/commands.lua b/lua/model_cmp/commands.lua index 1fd1c73..81e4654 100644 --- a/lua/model_cmp/commands.lua +++ b/lua/model_cmp/commands.lua @@ -1,4 +1,4 @@ -local llama = require("model_cmp.modelapi.llama") +local api = require("model_cmp.modelapi.common") local virtualtext = require("model_cmp.virtualtext") local M = {} @@ -13,7 +13,7 @@ function M.create_autocmds(group) if file == "" or file:find 'oil:///' then return end - llama.text_changed() + api.send_request() end }) @@ -21,6 +21,11 @@ function M.create_autocmds(group) { group = group, callback = function(event) + local file = event["file"] + -- also Check for buffer editing in oil.nvim + if file == "" or file:find 'oil:///' then + return + end virtualtext.action.clear_preview() end }) diff --git a/lua/model_cmp/context.lua b/lua/model_cmp/context.lua index 48bcfe4..564945b 100755 --- a/lua/model_cmp/context.lua +++ b/lua/model_cmp/context.lua @@ -8,13 +8,13 @@ end local function get_context_before(currentline) local start = 0 local stop = currentline - 1 - return vim.api.nvim_buf_get_lines(M.ContextEngine.bufnr, start, stop, false) + return vim.api.nvim_buf_get_lines(0, start, stop, false) end local function get_context_after(currentline) - local start = currentline + 1 + local start = currentline local stop = -1 - return vim.api.nvim_buf_get_lines(M.ContextEngine.bufnr, start, stop, false) + return vim.api.nvim_buf_get_lines(0, start, stop, false) end ---@class ModelCmp.ContextEngine @@ -24,7 +24,7 @@ end ---@field ctx table -- context ---@field currlang string -- current language eg: python, c, cpp, markdown M.ContextEngine = { - bufnr = 0, + bufnr = vim.api.nvim_get_current_buf(), id = 0, -- Need to think how to manipulate this this is imp to put the right virtual text for right context cursor = { 0, 0 }, ctx = { @@ -39,7 +39,7 @@ function M.ContextEngine:get_ctx() self.cursor = get_cursor() self.ctx.before = get_context_before(self.cursor[1]) self.ctx.after = get_context_after(self.cursor[1]) - self.ctx.current = vim.api.nvim_buf_get_lines(M.ContextEngine.bufnr, self.cursor[1], self.cursor[1] + 1, false) + self.ctx.current = vim.api.nvim_buf_get_lines(0, self.cursor[1] - 1, self.cursor[1] + 1, false) if not self.ctx.current then self.ctx.current = { "" } end @@ -72,7 +72,11 @@ function M.generate_context_text() local line = M.ContextEngine.ctx.current[1] local col = M.ContextEngine.cursor[2] - lines = lines .. line:sub(1, col) .. "" .. line:sub(col + 1) + if line == nil then + line = lines .. "\n\n" + else + lines = lines .. line:sub(1, col) .. "" .. line:sub(col + 1) + end -- after for idx, line in ipairs(M.ContextEngine.ctx.after) do diff --git a/lua/model_cmp/init.lua b/lua/model_cmp/init.lua index 9b4b5bd..cde1b3f 100644 --- a/lua/model_cmp/init.lua +++ b/lua/model_cmp/init.lua @@ -1,7 +1,7 @@ local commands = require("model_cmp.commands") local mainconfig = require("model_cmp.config") local virtualtext = require("model_cmp.virtualtext") -local modelapi = require("model_cmp.modelapi.managekey") +local api = require("model_cmp.modelapi.common") local M = {} @@ -14,7 +14,9 @@ function M.setup(config) commands.create_autocmds(model_cmp_grp) commands.create_usercmds() + virtualtext.setup(config) + api.setup(config) end return M diff --git a/lua/model_cmp/modelapi/common.lua b/lua/model_cmp/modelapi/common.lua index 4bb08f5..40d5a4f 100644 --- a/lua/model_cmp/modelapi/common.lua +++ b/lua/model_cmp/modelapi/common.lua @@ -58,7 +58,7 @@ end -- we will check if there is a request already made for the given buffer local function check_already_requested(bufnr) - for buffer in pairs(M.requests) do + for _,buffer in pairs(M.requests) do if bufnr == buffer then return true end @@ -82,20 +82,20 @@ function M.send_request() end end - if request ~= nil then + if request == nil then return end - if not check_already_requested(bufnr) then + if check_already_requested(bufnr) then return end - add_request(bufnr) + local index = add_request(bufnr) req.send(request, function(response) vim.schedule(function() local text = utils.decode_response(response) virtualtext.VirtualText:update_preview(text) - remove_request(bufnr) + remove_request(index) end) end ) diff --git a/lua/model_cmp/modelapi/llama.lua b/lua/model_cmp/modelapi/llama.lua index 7ca6234..5d10db9 100644 --- a/lua/model_cmp/modelapi/llama.lua +++ b/lua/model_cmp/modelapi/llama.lua @@ -15,7 +15,7 @@ function M.generate_request() local bufnr = context.ContextEngine.bufnr local prompt = context.generate_context_text() local lang = context.ContextEngine:get_currlang() - local complete_prompt = "# language: " .. lang .. prompt + local complete_prompt = "# language: " .. lang .. "\n" .. prompt local few_shots = systemprompt.complete_few_shots @@ -30,7 +30,7 @@ function M.generate_request() local request = { "-s", "-X", "POST", - generate_url(), + generate_url(custom.custom_url), "-H", "Content-Type: application/json", "-d", vim.fn.json_encode({ diff --git a/lua/model_cmp/modelapi/prompt.lua b/lua/model_cmp/modelapi/prompt.lua index b81359e..1210a23 100644 --- a/lua/model_cmp/modelapi/prompt.lua +++ b/lua/model_cmp/modelapi/prompt.lua @@ -83,4 +83,17 @@ Instructions: ]] } +-- After this we are going to collect and send new data +M.closecall_suggestions = { + role = "user", + content = [[You almost got the right answer, try again with a different but similar result, +]] +} + +M.wrong_suggestion = { + role = "user", + content = [[You predicted wrong, try again with a completly new suggestion but with this code +]] +} + return M diff --git a/lua/model_cmp/modelapi/request.lua b/lua/model_cmp/modelapi/request.lua index f0197ba..c0faf20 100644 --- a/lua/model_cmp/modelapi/request.lua +++ b/lua/model_cmp/modelapi/request.lua @@ -3,7 +3,7 @@ local Job = require("plenary.job") local M = {} -function M.send(bufnr, request_args, callback) +function M.send(request_args, callback) local result = {} local job = Job:new({ command = "curl", diff --git a/lua/model_cmp/utils.lua b/lua/model_cmp/utils.lua index cd60d92..2f2aaf8 100644 --- a/lua/model_cmp/utils.lua +++ b/lua/model_cmp/utils.lua @@ -10,4 +10,7 @@ function M.decode_response(response) return response_table.choices[1].message.content end +function M.trim_codeblock_response(lines) +end + return M diff --git a/lua/model_cmp/virtualtext.lua b/lua/model_cmp/virtualtext.lua index 2549264..c4fc21b 100644 --- a/lua/model_cmp/virtualtext.lua +++ b/lua/model_cmp/virtualtext.lua @@ -17,15 +17,43 @@ M.VirtualText = { ext_ids = {}, } +local function remove_empty_lines() + local start_line = vim.b.start_line + local count = vim.b.count + if start_line and count and count > 0 then + vim.api.nvim_buf_set_lines(0, start_line - 1, start_line + count, false, {}) + vim.b.start_line = nil + vim.b.count = nil + end + vim.api.nvim_win_set_cursor(0,vim.b.cursor) +end + function M.VirtualText:clear_preview(ext_ids_arg) + if vim.b.start_line == nil then + return + end local ext_ids = ext_ids_arg or self.ext_ids for ext_id in pairs(ext_ids) do vim.api.nvim_buf_del_extmark(0, self.ns_id, ext_id) end + remove_empty_lines() +end + +local function insert_empty_lines(current_line, no_line) + local lines = {} + for i = 1, no_line do + table.insert(lines, "") + end + vim.b.start_line = current_line + vim.b.count = no_line + vim.api.nvim_buf_set_lines(0, current_line - 1, current_line - 1, false, lines) end function M.VirtualText:update_preview(text) - if text == nil then + if vim.b.count ~= nil or vim.b.start_line ~= nil then + return + end + if not vim.g.model_cmp_virtualtext_auto_trigger or text == nil then return end @@ -33,27 +61,24 @@ function M.VirtualText:update_preview(text) return end local cursor = context.ContextEngine.cursor + vim.b.cursor = cursor local lines = {} for line in text:gmatch("[^\r\n]+") do table.insert(lines, line) end + insert_empty_lines(cursor[1], #lines) local max_line = vim.api.nvim_buf_line_count(0) - cursor[1] + 1 local extmark = {} for idx, line in ipairs(lines) do - if not line:find "```" then - if idx == max_line then - return - end - table.insert(self.ext_ids, idx) - extmark = { - id = idx, - virt_text = { { line, "CustomVirttextHighlight" } }, - right_gravity = true, - } - vim.api.nvim_buf_set_extmark(0, self.ns_id, cursor[1] + idx - 2, 0, extmark) - end + table.insert(self.ext_ids, idx) + extmark = { + id = idx, + virt_text = { { line, "CustomVirttextHighlight" } }, + right_gravity = true, + } + vim.api.nvim_buf_set_extmark(0, self.ns_id, cursor[1] + idx - 2, 0, extmark) end M.CaptureText = lines end