mirror of
https://github.com/lukaszraczylo/filepuff-mcp.git
synced 2026-10-19 05:57:38 +00:00
perf(lsp): emit workspace-relative paths in definition/references
lsp_query printed absolute paths from URIToFile (e.g. the full /Users/.../internal/... prefix repeated per result) while file_search and the AST summary already relativize. On a find_references across many files that ~60-char root prefix repeats per file group — wasted tokens for the LLM consumer. Extract a Server.relPath helper (dedups the AST summary's inline block) and apply it to definition and references display paths; the absolute path is kept where the file is actually re-read for previews. Adds a relPath unit test (in-workspace relativized, out-of-workspace unchanged).
This commit is contained in:
@@ -213,6 +213,20 @@ func TestASTQuerySkipsDependencyDirs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRelPath verifies workspace-relative display paths (token saving) with a
|
||||||
|
// safe fallback to the original path for anything outside the root.
|
||||||
|
func TestRelPath(t *testing.T) {
|
||||||
|
srv, tmpDir := newFeaturesServer(t)
|
||||||
|
if got := srv.relPath(filepath.Join(tmpDir, "pkg", "a.go")); got != filepath.Join("pkg", "a.go") {
|
||||||
|
t.Errorf("in-workspace path should be relativized, got %q", got)
|
||||||
|
}
|
||||||
|
// Outside the workspace root → returned unchanged (never a ../ escape string).
|
||||||
|
outside := "/definitely/outside/x.go"
|
||||||
|
if got := srv.relPath(outside); got != outside {
|
||||||
|
t.Errorf("out-of-workspace path should be returned as-is, got %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Feature 3 (ast_query): pagination cursor ----
|
// ---- Feature 3 (ast_query): pagination cursor ----
|
||||||
|
|
||||||
// TestASTQueryFirstPageCursor is a strict regression guard: page 1 must emit a
|
// TestASTQueryFirstPageCursor is a strict regression guard: page 1 must emit a
|
||||||
|
|||||||
@@ -263,15 +263,7 @@ func (s *Server) generateASTSummary(ctx context.Context, path string, content []
|
|||||||
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
|
|
||||||
// Get relative path
|
fmt.Fprintf(&sb, "**%s** (%d lines, %s)\n\n", s.relPath(path), countLines(content), lang)
|
||||||
relPath := path
|
|
||||||
if absPath, err := filepath.Abs(path); err == nil {
|
|
||||||
if rel, err := filepath.Rel(s.cfg.WorkspaceRoot, absPath); err == nil && !strings.HasPrefix(rel, "..") {
|
|
||||||
relPath = rel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(&sb, "**%s** (%d lines, %s)\n\n", relPath, countLines(content), lang)
|
|
||||||
sb.WriteString("Symbols:\n")
|
sb.WriteString("Symbols:\n")
|
||||||
|
|
||||||
for _, sym := range symbols {
|
for _, sym := range symbols {
|
||||||
@@ -282,6 +274,18 @@ func (s *Server) generateASTSummary(ctx context.Context, path string, content []
|
|||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// relPath renders path relative to the workspace root for display, saving the
|
||||||
|
// tokens an absolute path would cost. Falls back to the original path when it
|
||||||
|
// can't be relativized (outside the root, or on error).
|
||||||
|
func (s *Server) relPath(path string) string {
|
||||||
|
if absPath, err := filepath.Abs(path); err == nil {
|
||||||
|
if rel, err := filepath.Rel(s.cfg.WorkspaceRoot, absPath); err == nil && !strings.HasPrefix(rel, "..") {
|
||||||
|
return rel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
// symbolKindIcon returns an icon/prefix for a symbol kind.
|
// symbolKindIcon returns an icon/prefix for a symbol kind.
|
||||||
func symbolKindIcon(kind protocol.SymbolKind) string {
|
func symbolKindIcon(kind protocol.SymbolKind) string {
|
||||||
switch kind {
|
switch kind {
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ func (s *Server) lspDefinition(ctx context.Context, file string, line, col int,
|
|||||||
|
|
||||||
for _, loc := range locations {
|
for _, loc := range locations {
|
||||||
filePath := lsp.URIToFile(loc.URI)
|
filePath := lsp.URIToFile(loc.URI)
|
||||||
fmt.Fprintf(&output, "**%s:%d:%d**\n", filePath, loc.Range.Start.Line+1, loc.Range.Start.Character+1)
|
fmt.Fprintf(&output, "**%s:%d:%d**\n", s.relPath(filePath), loc.Range.Start.Line+1, loc.Range.Start.Character+1)
|
||||||
|
|
||||||
preview := s.readFilePreview(filePath, loc.Range.Start.Line+1, 3)
|
preview := s.readFilePreview(filePath, loc.Range.Start.Line+1, 3)
|
||||||
if preview != "" {
|
if preview != "" {
|
||||||
@@ -210,7 +210,9 @@ func (s *Server) lspReferences(ctx context.Context, file string, line, col int,
|
|||||||
fileGroups := make(map[string][]lsp.Location)
|
fileGroups := make(map[string][]lsp.Location)
|
||||||
fileOrder := make([]string, 0)
|
fileOrder := make([]string, 0)
|
||||||
for _, loc := range locations {
|
for _, loc := range locations {
|
||||||
filePath := lsp.URIToFile(loc.URI)
|
// Relativize for display; references are not re-read so the absolute
|
||||||
|
// path isn't needed downstream.
|
||||||
|
filePath := s.relPath(lsp.URIToFile(loc.URI))
|
||||||
if _, seen := fileGroups[filePath]; !seen {
|
if _, seen := fileGroups[filePath]; !seen {
|
||||||
fileOrder = append(fileOrder, filePath)
|
fileOrder = append(fileOrder, filePath)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user