Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 32 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,46 @@

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

### Lazy.nvim

```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
18 changes: 18 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -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
9 changes: 7 additions & 2 deletions lua/model_cmp/commands.lua
Original file line number Diff line number Diff line change
@@ -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 = {}
Expand All @@ -13,14 +13,19 @@ function M.create_autocmds(group)
if file == "" or file:find 'oil:///' then
return
end
llama.text_changed()
api.send_request()
end
})

vim.api.nvim_create_autocmd({ 'InsertLeave' },
{
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
})
Expand Down
16 changes: 10 additions & 6 deletions lua/model_cmp/context.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,7 +24,7 @@ end
---@field ctx table<string, string[]> -- 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 = {
Expand All @@ -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
Expand Down Expand Up @@ -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) .. "<missing>" .. line:sub(col + 1)
if line == nil then
line = lines .. "\n<missing>\n"
else
lines = lines .. line:sub(1, col) .. "<missing>" .. line:sub(col + 1)
end

-- after
for idx, line in ipairs(M.ContextEngine.ctx.after) do
Expand Down
4 changes: 3 additions & 1 deletion lua/model_cmp/init.lua
Original file line number Diff line number Diff line change
@@ -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 = {}

Expand All @@ -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
10 changes: 5 additions & 5 deletions lua/model_cmp/modelapi/common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
)
Expand Down
4 changes: 2 additions & 2 deletions lua/model_cmp/modelapi/llama.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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({
Expand Down
13 changes: 13 additions & 0 deletions lua/model_cmp/modelapi/prompt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion lua/model_cmp/modelapi/request.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions lua/model_cmp/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
51 changes: 38 additions & 13 deletions lua/model_cmp/virtualtext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,68 @@ 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

if vim.api.nvim_get_mode().mode ~= "i" then
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
Expand Down