golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.35k stars 17.71k forks source link

x/tools/gopls: autocompletion and highlighting for template variables, like GoLand's gotype #64385

Open mortenson opened 1 year ago

mortenson commented 1 year ago

gopls version

v0.14.2

go env

$ go env
GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/redacted/Library/Caches/go-build'
GOENV='/Users/redacted/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/redacted/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/redacted/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.21.4'
GCCGO='gccgo'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/redacted/project/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/k3/11fb815x3wv5ykpbf2mq_7600000gn/T/go-build1447506697=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

Configured VSCode to support Go templates with gopls.

What did you expect to see?

A way to tell gopls the types of my template variables, and have those types reflected in highlighting and autocomplete. GoLand does this with comments (ref https://www.jetbrains.com/help/go/integration-with-go-templates.html). I think the comments are slightly ugly, so not sure how to address that. Having a way for my custom template functions to work too would be great but isn't as critical.

Besides being good for DX, I think this could catch a ton of typing errors in templates. I currently use https://github.com/jba/templatecheck for that in tests, but that won't help me when viewing/writing tempalte code.

This was referenced in this issue by @a-h : https://github.com/golang/go/issues/36911, but wasn't really followed up on, which is why I'm filing this feature request.

What did you see instead?

No highlighting or autocomplete for template variable types. Hovering over template variables or functions just says field or method.

Editor and settings

VSCode with this config:

{
    "gopls": {
         "build.templateExtensions": ["gtpl"],
         "ui.semanticTokens": true
    },
    "files.associations": {
        "*.gtpl": "gotmpl"
    }
}

Logs

No response

mortenson commented 1 year ago

Checked in some very rough work on this here and am pausing on it for now as I couldn't figure out deeply nested fields: https://github.com/golang/tools/pull/462 , it feels like it's possible, although my POC may be very unpalatable.

adonovan commented 1 year ago

A way to tell gopls the types of my template variables, and have those types reflected in highlighting and autocomplete. GoLand does this with comments (ref https://www.jetbrains.com/help/go/integration-with-go-templates.html). I think the comments are slightly ugly, so not sure how to address that. Having a way for my custom template functions to work too would be great but isn't as critical.

This is an interesting idea, but I don't think we should require users to make ad-hoc changes to the text of their templates to enable this kind of tooling assistance. Either the tool should figure out what type of value is passed to the template evaluator, or there should be a standard way to declare this relation.

Having the tool deduce the type seems tractable in simple cases. If the source contains a call to t = template.Parse followed by t.Execute, then the two can be reconciled. It gets trickier when the flow of values from Parse to Execute is more complicated, or goes through //go:embed.

The standard way has the benefit of being more robust. Also, we could then write a vet check that would statically detect ill-formed templates, and gopls could run it in real time as you edit. Of course, it would require a proposal to change the template package. Alternatively the vet check could use the [future] annotation mechanism (see e.g. https://go.dev/cl/489835) to relate template strings and values (or embedded files).

mortenson commented 1 year ago

Having the tool deduce the type seems tractable in simple cases [...] It gets trickier when the flow of values from Parse to Execute is more complicated, or goes through //go:embed

Sadly I am both using go:embed and Gin (which has many abstraction levels above template rendering) which may make this tricky to trace.

I was thinking that an explicit config (in gopls?) mapping template paths to Go packages/types may be an OK alternative, but annotations could fill a similar gap. Annotations or config have a clear-ish path to making custom template.FuncMaps visible to gopls as well.

adonovan commented 12 months ago

I've filed a proposal (https://github.com/golang/go/issues/64543) to solicit requirements for an annotation mechanism sufficient to express the most common cases that users care about.