Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lsp: support textDocument/documentSymbol #347

Closed
nexovec opened this issue Dec 19, 2023 · 3 comments · Fixed by #848
Closed

lsp: support textDocument/documentSymbol #347

nexovec opened this issue Dec 19, 2023 · 3 comments · Fixed by #848

Comments

@nexovec
Copy link

nexovec commented Dec 19, 2023

Hi, I am missing a feature of the symbol list(the 'Ctrl+Shift+O' menu) in your vscode extension. The result could look like this:
image
It would only have to contain the top-level templ, css, script and type declarations.

@rokf
Copy link

rokf commented Jan 29, 2024

I agree, this would be a convenient improvement 🙂

@joerdav joerdav changed the title [templ-vscode] List of symbols lsp: support textDocument/documentSymbol Jan 30, 2024
@joerdav joerdav added enhancement New feature or request lsp NeedsFix Needs implementing labels Jan 30, 2024
@joerdav
Copy link
Collaborator

joerdav commented Jan 30, 2024

This feature is driven by the following LSP capability: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol

Implementing this should unlock this feature for both vscode and other clients supporting this capability (nvim).

@a-h
Copy link
Owner

a-h commented May 13, 2024

I took a look at how to implement this.

The feature is supposed to list useful stuff in the file - variables etc., and then you can navigate the file using those symbols.

But at the moment, the types for templ's templ (parser.HTMLTemplate), css and other top level elements don't store their position in the templ object model, so first step is to add a field to store that information.

 type HTMLTemplate struct {
+       Position   Range
        Expression Expression
        Children   []Node
 }

Then, populate it during parsing like this:

var template = parse.Func(func(pi *parse.Input) (r HTMLTemplate, ok bool, err error) {
	// templ FuncName(p Person, other Other) {
+	r.Position.From = NewPosition(int64(pi.Index()), uint32(pi.Position().Line), uint32(pi.Position().Col))
	var te templateExpression
	if te, ok, err = templateExpressionParser.Parse(pi); err != nil || !ok {
		return
	}
	r.Expression = te.Expression
+	r.Position.To = NewPosition(int64(pi.Index()), uint32(pi.Position().Line), uint32(pi.Position().Col))

Next, the LSP proxy (in templ/proxy/server.go) has a parseTemplate function. This function doesn't currently store the object model of templ files in the struct, like it does with the source map, or diagnostics (DiagnosticCache), so the next step is to get the server to store a map of file URI to list of symbols in the struct so that we can grab them when DocumentSymbol is called. It shouldn't be an lsp.DocumentSymbol that's stored in the cache, because they're in different packages and we'd end up with a circular dependency, but will be close enough structurally.

Finally, when DocumentSymbol is called, need to call the Go LSP first, then do the rest. Something like this.

func (p *Server) DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []interface{} /* []SymbolInformation | []DocumentSymbol */, err error) {
	p.Log.Info("client -> server: DocumentSymbol")
	defer p.Log.Info("client -> server: DocumentSymbol end")

        //TODO: Convert the templ URI to a Go URI.
	//result, err = p.Target.DocumentSymbol(ctx, params)
	//if err != nil {
		//return
	//}
        //TODO: Rewrite the positions that came back, and remove any items that are not in the source map cache.
       
        //TODO: Grab the symbol data from the `*Server` symbol cache, and populate the results.
	result = append(result, lsp.SymbolInformation{
		Name:          "templ",
		Kind:          lsp.SymbolKindFunction,
		Tags:          []lsp.SymbolTag{},
		Deprecated:    false,
		Location:      lsp.Location{},
		ContainerName: "",
	})
	result = append(result, lsp.SymbolInformation{
		Name:          "css",
		Kind:          lsp.SymbolKindFunction,
		Tags:          []lsp.SymbolTag{},
		Deprecated:    false,
		Location:      lsp.Location{},
		ContainerName: "",
	})
	result = append(result, lsp.SymbolInformation{
		Name:          "script",
		Kind:          lsp.SymbolKindFunction,
		Tags:          []lsp.SymbolTag{},
		Deprecated:    false,
		Location:      lsp.Location{},
		ContainerName: "",
	})
	return
}

If someone wants to have a crack at it, let me know. With tests etc. it's probably a day's work.

@joerdav joerdav added the help wanted Extra attention is needed label May 31, 2024
@linear linear bot added Migrated and removed enhancement New feature or request Migrated NeedsFix Needs implementing help wanted Extra attention is needed lsp labels Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants