|
1 | 1 | local M = {} |
2 | 2 |
|
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 |
18 | 7 |
|
19 | 8 | ---@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 |
25 | 13 | M.ContextEngine = { |
26 | | - bufnr = vim.api.nvim_get_current_buf(), |
| 14 | + bufnr = 0, |
27 | 15 | 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", |
30 | 17 | ctx = { |
31 | | - before = {}, |
| 18 | + scopes = {}, |
32 | 19 | current = {}, |
33 | | - after = {}, |
| 20 | + imports = {}, |
34 | 21 | }, |
35 | 22 | } |
36 | 23 |
|
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 | | - |
47 | 24 | function M.ContextEngine:clear_ctx() |
48 | 25 | self.ctx = { |
49 | | - before = {}, |
| 26 | + scopes = {}, |
50 | 27 | current = {}, |
51 | | - after = {}, |
| 28 | + imports = {}, |
52 | 29 | } |
53 | 30 | end |
54 | 31 |
|
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() |
57 | 41 | end |
58 | 42 |
|
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 {} |
62 | 49 | end |
63 | | - M.ContextEngine:get_currlang() |
64 | 50 |
|
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() |
66 | 92 | 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 |
69 | 99 | end |
70 | 100 |
|
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 |
78 | 108 | end |
79 | 109 |
|
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" |
83 | 113 | end |
84 | | - M.ContextEngine:clear_ctx() |
| 114 | + |
85 | 115 | return lines |
86 | 116 | end |
87 | 117 |
|
|
0 commit comments