Skip to content

Commit 43b7f47

Browse files
committed
Feat: new treesitter-based context generator with lua queries
Later will add some more queries For now we only look for the code that is inside of a function
1 parent 86bb7d7 commit 43b7f47

7 files changed

Lines changed: 95 additions & 61 deletions

File tree

lua/model_cmp/context.lua

Lines changed: 87 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,117 @@
11
local M = {}
22

3-
local function get_cursor()
4-
return vim.api.nvim_win_get_cursor(0)
5-
end
6-
7-
local function get_context_before(currentline)
8-
local start = 0
9-
local stop = currentline - 1
10-
return vim.api.nvim_buf_get_lines(0, start, stop, false)
11-
end
12-
13-
local function get_context_after(currentline)
14-
local start = currentline
15-
local stop = -1
16-
return vim.api.nvim_buf_get_lines(0, start, stop, false)
17-
end
3+
---@class ctx
4+
---@field scopes TSNode[] Scopes of each function around the cursor
5+
---@field current string[] Current line the cursor is at
6+
---@field imports string[] This is related to Lsp stuff so we are going to integrate this in future
187

198
---@class ModelCmp.ContextEngine
20-
---@field bufnr integer -- current buffer number
21-
---@field cursor integer[] -- current cursor pos
22-
---@field currlang string -- current language eg: python, c, cpp, markdown
23-
---@field id integer -- context id
24-
---@field ctx table<string, string[]> -- context
9+
---@field bufnr integer current buffer number
10+
---@field cursor integer[] current cursor pos
11+
---@field lang string querylanguage to choose
12+
---@field ctx ctx
2513
M.ContextEngine = {
26-
bufnr = vim.api.nvim_get_current_buf(),
14+
bufnr = 0,
2715
cursor = { 0, 0 },
28-
currlang = "text", -- default if none is set or found
29-
id = 0, -- Need to think how to manipulate this this is imp to put the right virtual text for right context
16+
lang = "text",
3017
ctx = {
31-
before = {},
18+
scopes = {},
3219
current = {},
33-
after = {},
20+
imports = {},
3421
},
3522
}
3623

37-
function M.ContextEngine:get_ctx()
38-
self.cursor = get_cursor()
39-
self.ctx.before = get_context_before(self.cursor[1])
40-
self.ctx.after = get_context_after(self.cursor[1])
41-
self.ctx.current = vim.api.nvim_buf_get_lines(0, self.cursor[1] - 1, self.cursor[1] + 1, false)
42-
if not self.ctx.current then
43-
self.ctx.current = { "" }
44-
end
45-
end
46-
4724
function M.ContextEngine:clear_ctx()
4825
self.ctx = {
49-
before = {},
26+
scopes = {},
5027
current = {},
51-
after = {},
28+
imports = {},
5229
}
5330
end
5431

55-
function M.ContextEngine:get_currlang()
56-
self.currlang = vim.bo.filetype
32+
function M.ContextEngine:get_root()
33+
local parser = vim.treesitter.get_parser(0, self.lang, {})
34+
35+
if parser == nil then
36+
return {}
37+
end
38+
39+
local tree = parser:parse()[1]
40+
return tree:root()
5741
end
5842

59-
function M.generate_context_text()
60-
if next(M.ContextEngine.ctx.current) == nil or M.ContextEngine.ctx.current == nil then
61-
M.ContextEngine:get_ctx()
43+
function M.ContextEngine:get_scopes_and_ranges()
44+
local scope_query = "context-scope"
45+
local ok, query = pcall(vim.treesitter.query.get, self.lang, scope_query)
46+
47+
if not ok or query == nil then
48+
return {}
6249
end
63-
M.ContextEngine:get_currlang()
6450

65-
-- before
51+
local root = self:get_root()
52+
53+
for _, match, _ in query:iter_matches(root, self.bufnr, 0, -1, { all = true }) do
54+
for _, nodes in pairs(match) do
55+
for _, node in ipairs(nodes) do
56+
table.insert(self.ctx.scopes, node)
57+
end
58+
end
59+
end
60+
end
61+
62+
function M.ContextEngine:get_ctx()
63+
self.bufnr = vim.api.nvim_get_current_buf()
64+
self.cursor = vim.api.nvim_win_get_cursor(0)
65+
self.lang = vim.bo.ft
66+
self:get_scopes_and_ranges()
67+
end
68+
69+
---@param node TSNode
70+
---@return boolean
71+
local function scopes_inrange(node, cursor)
72+
local start_r, _, end_r, _ = node:range()
73+
return cursor[1] >= start_r and cursor[1] <= end_r
74+
end
75+
76+
local function node_to_line_array(node_text)
77+
local lines = {}
78+
for line in node_text:gmatch("([^\n]*)[\n]?") do
79+
if line ~= "" then
80+
table.insert(lines, line)
81+
end
82+
end
83+
return lines
84+
end
85+
86+
local function add_missing_tag(line, cursor)
87+
local missing = string.sub(line, 1, cursor[2]) .. "<missing>" .. string.sub(line, cursor[2] + 1, -1)
88+
return missing
89+
end
90+
91+
function M.ContextEngine:generate_context_text()
6692
local lines = [[]]
67-
for _, line in pairs(M.ContextEngine.ctx.before) do
68-
lines = lines .. line .. "\n"
93+
self:get_ctx()
94+
95+
for _, k in ipairs(self.ctx.scopes) do
96+
if scopes_inrange(k, self.cursor) then
97+
lines = vim.treesitter.get_node_text(k, self.bufnr)
98+
end
6999
end
70100

71-
-- current
72-
local line = M.ContextEngine.ctx.current[1]
73-
local col = M.ContextEngine.cursor[2]
74-
if line == nil then
75-
lines = lines .. "\n<missing>\n"
76-
else
77-
lines = lines .. line:sub(1, col) .. "<missing>" .. line:sub(col + 1)
101+
local lines_list = node_to_line_array(lines)
102+
local currentline = vim.api.nvim_buf_get_lines(self.bufnr, self.cursor[1] - 1, self.cursor[1] + 1, false)
103+
104+
for i, _ in ipairs(lines_list) do
105+
if i == self.cursor[1] then
106+
lines_list[i] = add_missing_tag(currentline[1], self.cursor)
107+
end
78108
end
79109

80-
-- after
81-
for _, i in ipairs(M.ContextEngine.ctx.after) do
82-
lines = lines .. i .. "\n"
110+
lines = [[]]
111+
for _, k in ipairs(lines_list) do
112+
lines = lines .. k .. "\n"
83113
end
84-
M.ContextEngine:clear_ctx()
114+
85115
return lines
86116
end
87117

lua/model_cmp/modelapi/common.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ local function check_available()
3535
end
3636

3737
function M.send_request()
38-
local ctx = context.generate_context_text()
39-
local currlang = context.ContextEngine.currlang
38+
local ctx = context.ContextEngine:generate_context_text()
39+
local currlang = context.ContextEngine.lang
4040

4141
local prompt = prompter.generate_prompt(currlang, ctx)
4242
local request

queries/c/context-scope.scm

Whitespace-only changes.

queries/cpp/context-scope.scm

Whitespace-only changes.

queries/lua/context-scope.scm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(function_declaration) @context.scope
2+
(function_definition) @context.scope

queries/python/context-scope.scm

Whitespace-only changes.

scripts/minimal_init.vim

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
set noswapfile
22
set rtp+=.
3-
set rtp+=../plenary.nvim/
3+
set rtp+=../plenary.nvim
4+
set rtp+=~/.local/share/nvim/lazy/nvim-treesitter
45

56
runtime! plugin/plenary.vim
6-
runtime! plugin/model_cmp.lua
7+
runtime! plugin/nvim-treesitter.lua
8+
runtime! plugin/model-cmp.lua

0 commit comments

Comments
 (0)