Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
4b62b7e
feat(ast): add find_segment_at_position query function
StanAngeloff Mar 9, 2026
325a4bd
test(ast): add specs for end_col positions and find_segment_at_position
StanAngeloff Mar 9, 2026
7e3986b
feat(config): add experimental config section with lsp flag
StanAngeloff Mar 9, 2026
8b4558c
feat(lsp): add in-process LSP server with hover support
StanAngeloff Mar 9, 2026
4d9647b
feat(init): wire experimental LSP setup behind config flag
StanAngeloff Mar 9, 2026
a1117e4
test(lsp): add specs for experimental LSP hover
StanAngeloff Mar 9, 2026
0c6e6cb
chore: add changeset for experimental LSP hover
StanAngeloff Mar 9, 2026
886ed0e
feat(lsp): add debug and trace logging to LSP server
StanAngeloff Mar 9, 2026
78389bd
refactor(lsp): demote shutdown/terminate logs from info to debug
StanAngeloff Mar 9, 2026
b3c50fc
chore(makefile): enable experimental LSP and TRACE logging in develop…
StanAngeloff Mar 9, 2026
8b2d3cf
feat(lsp): hover on every buffer position (role markers, frontmatter)
StanAngeloff Mar 9, 2026
73b5e11
style(lsp): use italics instead of headers in hover docs, fix PascalC…
StanAngeloff Mar 12, 2026
fc53a83
fix(parser): always set end_line alongside end_col in expression posi…
StanAngeloff Mar 12, 2026
0b2f1a6
feat(lsp): add textDocument/definition for file references and includes
StanAngeloff Mar 12, 2026
b22430c
refactor(lsp): extract resolve_params helper and consolidate logging
StanAngeloff Mar 12, 2026
3d5ff24
feat(config): default experimental.lsp to true when vim.lsp is available
StanAngeloff Mar 12, 2026
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
5 changes: 5 additions & 0 deletions .changeset/experimental-lsp-hover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@flemma-dev/flemma.nvim": minor
---

Added experimental in-process LSP server for chat buffers with hover and goto-definition support. Enable with `experimental = { lsp = true }` in setup. Every buffer position returns a hover result: segments (expressions, thinking blocks, tool use/result, text) show structured dumps, role markers show message summaries with segment breakdowns, and frontmatter shows language and code. Goto-definition (`gd`, `<C-]>`, etc.) on `@./file` references and `{{ include() }}` expressions jumps to the referenced file, reusing the navigation module's path resolution.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ develop:
[\"\$$gpt\"] = \"openai gpt-5.2\", \
}, \
diagnostics = { enabled = true }, \
logging = { enabled = true }, \
logging = { enabled = true, level = "TRACE" }, \
editing = { auto_write = true }, \
tools = { modules = { \"extras.flemma.tools.calculator\" } }, \
}) \
Expand Down
68 changes: 35 additions & 33 deletions lua/flemma/ast/query.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,54 +85,56 @@ function M.find_segment_at_position(doc, lnum, col)
for _, msg in ipairs(doc.messages) do
local msg_start = msg.position.start_line
local msg_end = msg.position.end_line or msg_start
if lnum < msg_start or lnum > msg_end then
goto continue_msg
end

---@type flemma.ast.Segment|nil
local fallback_seg = nil
if lnum >= msg_start and lnum <= msg_end then
---@type flemma.ast.Segment|nil
local fallback_seg = nil
for _, seg in ipairs(msg.segments) do
if not seg.position then
goto continue_seg
end

for _, seg in ipairs(msg.segments) do
if not seg.position then
goto continue_seg
end
local seg_start = seg.position.start_line
local seg_end = seg.position.end_line or seg_start

local seg_start = seg.position.start_line
local seg_end = seg.position.end_line or seg_start
if lnum < seg_start or lnum > seg_end then
goto continue_seg
end

if lnum < seg_start or lnum > seg_end then
goto continue_seg
end
-- Line matches. Refine with column if available.
if lnum == seg_start and seg.position.start_col and seg.position.end_col then
if col >= seg.position.start_col and col <= seg.position.end_col then
return seg, msg
end
goto continue_seg
end

-- Line matches. Refine with column if available.
if lnum == seg_start and seg.position.start_col and seg.position.end_col then
if col >= seg.position.start_col and col <= seg.position.end_col then
-- Multi-line hit beyond first line — definite match
if lnum > seg_start then
return seg, msg
end
goto continue_seg
end

-- Multi-line hit beyond first line — definite match
if lnum > seg_start then
return seg, msg
end
-- Single-line segment without column info — save as fallback
-- so column-aware segments on the same line get a chance to match first
if not seg.position.start_col then
fallback_seg = seg
end

-- Single-line segment without column info — save as fallback
if not fallback_seg then
fallback_seg = seg
::continue_seg::
end

::continue_seg::
end
-- Return fallback if no column-specific match found
if fallback_seg then
return fallback_seg, msg
end

-- Return fallback if no column-specific match found
if fallback_seg then
return fallback_seg, msg
-- Cursor is within the message range but no segment matched
-- (e.g., on the @Role: marker line). Return the message itself.
return nil, msg
end

::continue_msg::
end
return nil, nil
end


return M
8 changes: 8 additions & 0 deletions lua/flemma/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
---@field insert flemma.config.InsertKeymaps
---@field enabled boolean

---@class flemma.config.Experimental
---@field lsp boolean Enable in-process LSP for .chat buffers

---User-facing setup options — every field is optional (merged with defaults).
---@class flemma.Config.Opts
---@field defaults? { dark: { bg: string, fg: string }, light: { bg: string, fg: string } }
Expand All @@ -168,6 +171,7 @@
---@field keymaps? flemma.config.Keymaps
---@field sandbox? flemma.config.SandboxConfig
---@field diagnostics? flemma.config.Diagnostics
---@field experimental? flemma.config.Experimental

---Full resolved config (all fields present after merging with defaults).
---@class flemma.Config : flemma.Config.Opts
Expand All @@ -190,6 +194,7 @@
---@field keymaps flemma.config.Keymaps
---@field sandbox flemma.config.SandboxConfig
---@field diagnostics flemma.config.Diagnostics
---@field experimental flemma.config.Experimental

---@type flemma.Config
return {
Expand Down Expand Up @@ -347,4 +352,7 @@ return {
},
},
},
experimental = {
lsp = vim.lsp ~= nil,
},
}
6 changes: 6 additions & 0 deletions lua/flemma/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ local tools_presets = require("flemma.tools.presets")
local tools_approval = require("flemma.tools.approval")
local cursor = require("flemma.cursor")
local sandbox = require("flemma.sandbox")
local lsp = require("flemma.lsp")

-- Module configuration (will hold merged user opts and defaults)
local config = {}
Expand Down Expand Up @@ -145,6 +146,11 @@ M.setup = function(user_opts)
-- Register built-in sandbox backends and validate availability
sandbox.setup()

-- Set up experimental LSP if enabled
if config.experimental and config.experimental.lsp then
lsp.setup()
end

-- Defer sandbox backend check until the user enters a .chat buffer.
-- By that time, other plugins may have registered additional backends.
if config.sandbox and config.sandbox.enabled then
Expand Down
Loading