diff options
| author | ThePrimeagen <prime@prime.prime> | 2025-11-24 07:45:44 -0800 |
|---|---|---|
| committer | ThePrimeagen <prime@prime.prime> | 2025-11-24 07:45:44 -0800 |
| commit | f90a3e8661f2d650fcd78ada5b93fcbd65f4792b (patch) | |
| tree | 9b15941c7c7f8e449026af94f6b084fe158c9ac5 /lua | |
| parent | 81befc2085b8afe0e4e6d5fd39178bfaafd60d5b (diff) | |
| download | a4-f90a3e8661f2d650fcd78ada5b93fcbd65f4792b.tar.xz a4-f90a3e8661f2d650fcd78ada5b93fcbd65f4792b.zip | |
the initial commit of crap
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/dreamy/editor/init.lua | 4 | ||||
| -rw-r--r-- | lua/dreamy/editor/lsp.lua | 105 | ||||
| -rw-r--r-- | lua/dreamy/editor/treesitter.lua | 134 | ||||
| -rw-r--r-- | lua/dreamy/init.lua | 1 |
4 files changed, 244 insertions, 0 deletions
diff --git a/lua/dreamy/editor/init.lua b/lua/dreamy/editor/init.lua new file mode 100644 index 0000000..f9e6d41 --- /dev/null +++ b/lua/dreamy/editor/init.lua @@ -0,0 +1,4 @@ +return { + treesitter = require("dreamy.editor.treesitter"), + lsp = require("dreamy.editor.lsp"), +} diff --git a/lua/dreamy/editor/lsp.lua b/lua/dreamy/editor/lsp.lua new file mode 100644 index 0000000..af8f8a5 --- /dev/null +++ b/lua/dreamy/editor/lsp.lua @@ -0,0 +1,105 @@ +local logger = require("cockpit.logger.logger") + +--- @param node TSNode +local function ts_node_to_lsp_position(node) + local start_row, start_col, _, _ = node:range() -- Treesitter node range + return { line = start_row, character = start_col } +end + +--- @param buffer number +--- @param position number[] +--- @param cb fun(res: LspDefinitionResult[] | nil): nil +local function get_lsp_definitions(buffer, position, cb) + local params = vim.lsp.util.make_position_params() + params.position = position + + --- @param result LspDefinitionResult[] | nil + vim.lsp.buf_request( + buffer, + "textDocument/definition", + params, + function(_, result, ctx, _) + cb(result) + end + ) +end + +--- @class Lsp +--- @field config CockpitOptions +local Lsp = {} +Lsp.__index = Lsp + +function Lsp:new(config) + return setmetatable({ + config = config, + }, self) +end + +--- @param buffer number +--- @param node TSNode[] +--- @param cb fun(res: LspDefinitionResult | nil): nil +function Lsp:get_ts_node_definition(buffer, node, cb) + local range = ts_node_to_lsp_position(node) + get_lsp_definitions(buffer, range, cb) +end + +--- @param resultsList LspDefinitionResult[][] +--- @param buffer number +--- @return LspDefinitionResult[] +function Lsp:_filter_flatten(resultsList, buffer) + local ft = vim.bo[buffer].ft + local out = {} + local filters = self.config.language_import_filter[ft] + logger:debug("filter flatten", "filters", filters, "ft", ft) + for _, results in ipairs(resultsList) do + for _, res in ipairs(results) do + local found = true + for _, filter in ipairs(filters) do + logger:debug( + "filtering lsp definitions", + "filter", + filter, + "uri", + res.uri + ) + if string.find(res.uri, filter) then + found = false + break + end + end + + if res ~= false and found then + logger:debug("adding resource", "uri", res.uri) + table.insert(out, res) + end + end + end + return out +end + +--- @param buffer number +--- @param nodes TSNode[] +--- @param cb fun(res: LspDefinitionResult[]): nil +function Lsp:batch_get_ts_node_definitions(buffer, nodes, cb) + if #nodes == 0 then + return cb({}) + end + + local definitions = {} + for index, node in ipairs(nodes) do + self:get_ts_node_definition(buffer, node, function(def) + if def == nil or #def == 0 then + def = {} + end + + definitions[index] = def + if #definitions == #nodes then + cb(self:_filter_flatten(definitions, buffer)) + end + end) + end +end + +return { + Lsp = Lsp, +} diff --git a/lua/dreamy/editor/treesitter.lua b/lua/dreamy/editor/treesitter.lua new file mode 100644 index 0000000..bb3ce27 --- /dev/null +++ b/lua/dreamy/editor/treesitter.lua @@ -0,0 +1,134 @@ +local geo = require("cockpit.geo") +local Point = geo.Point +local Range = geo.Range + +local M = {} + +local scope_query = "cockpit-scope" +local imports_query = "cockpit-imports" + +local function tree_root() + local buffer = vim.api.nvim_get_current_buf() + local lang = vim.bo.ft + + -- Load the parser and the query. + local ok, parser = pcall(vim.treesitter.get_parser, buffer, lang) + if not ok then + return nil + end + + local tree = parser:parse()[1] + return tree:root() +end + +--- @class Scope +--- @field scope TSNode[] +--- @field range Range[] +--- @field buffer number +--- @field cursor Point +local Scope = {} +Scope.__index = Scope + +--- @param cursor Point +--- @param buffer number +--- @return Scope +function Scope:new(cursor, buffer) + return setmetatable({ + scope = {}, + range = {}, + buffer = buffer, + cursor = cursor, + }, self) +end + +--- @return boolean +function Scope:has_scope() + return #self.range > 0 +end + +--- @param node TSNode +function Scope:push(node) + local range = Range:from_ts_node(node, self.buffer) + if not range:contains(self.cursor) then + return + end + + table.insert(self.range, range) + table.insert(self.scope, node) +end + +function Scope:finalize() + assert(#self.range == #self.scope, "range scope mismatch") + table.sort(self.range, function(a, b) + return a:contains_range(b) + end) +end + +--- if you want cursor just use Point:from_cursor() +--- @param cursor Point +--- @return Scope | nil +function M.scopes(cursor) + local lang = vim.bo.ft + local root = tree_root() + if not root then + -- consider logging + return nil + end + + local buffer = vim.api.nvim_get_current_buf() + local ok, query = pcall(vim.treesitter.query.get, lang, scope_query) + + if not ok or query == nil then + return nil + end + + local scope = Scope:new(cursor, buffer) + scope:push(root) + + for _, match, _ in query:iter_matches(root, buffer, 0, -1, { all = true }) do + for _, nodes in pairs(match) do + for _, node in ipairs(nodes) do + scope:push(node) + end + end + end + + assert( + scope:has_scope(), + 'get smallest scope failed. it should never fail since scopeset should contain the "program" scope' + ) + scope:finalize() + + return scope +end + +--- @return TSNode[] +function M.imports() + local root = tree_root() + if not root then + return {} + end + + local buffer = vim.api.nvim_get_current_buf() + local ok, query = pcall(vim.treesitter.query.get, vim.bo.ft, imports_query) + + if not ok or query == nil then + return {} + end + + local imports = {} + for _, match, _ in query:iter_matches(root, buffer, 0, -1, { all = true }) do + for id, nodes in pairs(match) do + local name = query.captures[id] + if name == "import.name" then + for _, node in ipairs(nodes) do + table.insert(imports, node) + end + end + end + end + + return imports +end + +return M diff --git a/lua/dreamy/init.lua b/lua/dreamy/init.lua index e69de29..8b13789 100644 --- a/lua/dreamy/init.lua +++ b/lua/dreamy/init.lua @@ -0,0 +1 @@ + |
