summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authorThePrimeagen <prime@prime.prime>2025-11-24 07:45:44 -0800
committerThePrimeagen <prime@prime.prime>2025-11-24 07:45:44 -0800
commitf90a3e8661f2d650fcd78ada5b93fcbd65f4792b (patch)
tree9b15941c7c7f8e449026af94f6b084fe158c9ac5 /lua
parent81befc2085b8afe0e4e6d5fd39178bfaafd60d5b (diff)
downloada4-f90a3e8661f2d650fcd78ada5b93fcbd65f4792b.tar.xz
a4-f90a3e8661f2d650fcd78ada5b93fcbd65f4792b.zip
the initial commit of crap
Diffstat (limited to 'lua')
-rw-r--r--lua/dreamy/editor/init.lua4
-rw-r--r--lua/dreamy/editor/lsp.lua105
-rw-r--r--lua/dreamy/editor/treesitter.lua134
-rw-r--r--lua/dreamy/init.lua1
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 @@
+