Code Monkey home page Code Monkey logo

Comments (8)

tekagg avatar tekagg commented on September 27, 2024 2

@a-h I just added a PR to fix imports on completions that contain functions/structs and so on #138. Basically, all completions that require package imports have the import embedded in the detail field

from templ.

jwhitaker-swiftnav avatar jwhitaker-swiftnav commented on September 27, 2024 1

this looks fab, thanks both!

from templ.

tekagg avatar tekagg commented on September 27, 2024

I was looking to open a ticket for the same issue. Other than this, everything is awesome.
Thank you for such a great work!

Update: I did some digging and I found two possible reasons why this bug is happening:

  • the default imports added by the generator automatically are not available in the sourcemap because they don t exists in *.templ files and because of this the mapping of ranges for text edits when a completion that modifies imports is received will always fail
  • also it seems that the textEdits sent by gopls will always try to change the format of imports to
import (
    "github.com/a-h/templ"
    "context"
    "io"
    "bytes"
)

and couldn t find a way to disable this. There are some ways to disable reorganization of imports only on file save, but not on autocomplete

I m trying to find a way to fix this but it seems a tricky one

from templ.

a-h avatar a-h commented on September 27, 2024

Thanks for the nice feedback, and great bug report @jwhitaker-swiftnav, and thanks for looking into the issue @agalbenus

Looking at the LSP logs when it happened didn't tell me much, but I added some extra logging to print out the full object model of the autocompletion options.

The completion items include "additionalTextEdits" - i.e. they change text that isn't just the bit you're autocompleting - selecting the item also changes the import list.

templ isn't currently rewriting those additional text edits at all, but even if it was, as @agalbenus points out, the imports don't exist in the source file, so there's no proper mapping.

	p.Log.Info("completion: received items", zap.Int("count", len(result.Items)), zap.Any("items", result.Items))
	for i := 0; i < len(result.Items); i++ {
		item := result.Items[i]
		if item.TextEdit != nil {
			item.TextEdit.Range = p.convertGoRangeToTemplRange(templURI, item.TextEdit.Range)
		}
		result.Items[i] = item
	}

Here's the completion list.

{
  "level": "info",
  "ts": "2023-09-03T18:34:45+01:00",
  "caller": "proxy/server.go:335",
  "msg": "completion: received items",
  "count": 7,
  "items": [
    {
      "additionalTextEdits": [
        {
          "range": {
            "start": {
              "line": 6,
              "character": 7
            },
            "end": {
              "line": 6,
              "character": 7
            }
          },
          "newText": "(\n\t"
        },
        {
          "range": {
            "start": {
              "line": 6,
              "character": 8
            },
            "end": {
              "line": 6,
              "character": 10
            }
          },
          "newText": "by"
        },
        {
          "range": {
            "start": {
              "line": 6,
              "character": 11
            },
            "end": {
              "line": 9,
              "character": 1
            }
          },
          "newText": "es\"\n\t\"context\"\n\t\"io\"\n\t\"strconv\"\n\n\t\"github.com/a-h/te"
        },
        {
          "range": {
            "start": {
              "line": 9,
              "character": 3
            },
            "end": {
              "line": 9,
              "character": 13
            }
          },
          "newText": "l"
        },
        {
          "range": {
            "start": {
              "line": 9,
              "character": 14
            },
            "end": {
              "line": 9,
              "character": 14
            }
          },
          "newText": "\n)"
        }
      ],
      "detail": "\"strconv\"",
      "documentation": {
        "kind": "markdown",
        "value": ""
      },
      "filterText": "strconv",
      "insertTextFormat": 2,
      "kind": 9,
      "label": "strconv",
      "preselect": true,
      "sortText": "00000",
      "textEdit": {
        "range": {
          "start": {
            "line": 24,
            "character": 21
          },
          "end": {
            "line": 24,
            "character": 25
          }
        },
        "newText": "strconv"
      }
    },
...
}

I think the way to solve this might be to get templ to do its own addition of import statements. The LSP returns an enum called https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemKind and export const Module = 9;.

      "filterText": "strconv",
      "insertTextFormat": 2,
      "kind": 9,

So it might be a case of if kind == 9 in the message received from gopls, and additionalTextEdits are present, remove them and replace them with a plain Go import statement in the templ file.

from templ.

a-h avatar a-h commented on September 27, 2024

Modifying server.go in the LSP section shows good promise.

        // Rewrite the result positions.
-       p.Log.Info("completion: received items", zap.Int("count", len(result.Items)))
+       p.Log.Info("completion: received items", zap.Int("count", len(result.Items)), zap.Any("items", result.Items))
        for i := 0; i < len(result.Items); i++ {
                item := result.Items[i]
                if item.TextEdit != nil {
                        item.TextEdit.Range = p.convertGoRangeToTemplRange(templURI, item.TextEdit.Range)
                }
+               if item.Kind == lsp.CompletionItemKindModule && len(item.AdditionalTextEdits) > 0 {
+                       item.AdditionalTextEdits = []lsp.TextEdit{
+                               {
+                                       Range: lsp.Range{
+                                               Start: lsp.Position{Line: 1, Character: 0},
+                                               End:   lsp.Position{Line: 1, Character: 0},
+                                       },
+                                       NewText: fmt.Sprintf(`import "%s"`, item.Label),
+                               },
+                       }
+               }
                result.Items[i] = item
        }

This change is really basic - it just puts an import statement in as the first line in the file - it doesn't format the code in that section, e.g. insert appropriate newlines, which I'd really want it to do.

import

from templ.

a-h avatar a-h commented on September 27, 2024

This is more like it...

import
import2

from templ.

a-h avatar a-h commented on September 27, 2024

OK, @jwhitaker-swiftnav, @agalbenus - if you have a chance to check over the changes in that PR, I'd appreciate it!

from templ.

a-h avatar a-h commented on September 27, 2024

The PR is #136

I've just realised that it does a good job of the import, but if you import a function after the package, it still mangles it. I'll take a look at that before I merge.

from templ.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.