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

x/tools/gopls: support fill struct behavior #37576

Closed
frioux opened this issue Feb 28, 2020 · 16 comments
Closed

x/tools/gopls: support fill struct behavior #37576

frioux opened this issue Feb 28, 2020 · 16 comments

Comments

@frioux
Copy link

@frioux frioux commented Feb 28, 2020

What version of Go are you using (go version)?

$ go version
go version go1.14 linux/amd64

Does this issue reproduce with the latest release?

n/a (feature request)

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/frew/.cache/go-build"
GOENV="/home/frew/.config/go/env"
GOEXE=""
GOFLAGS="-mod=readonly"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/frew/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org"
GOROOT="/home/frew/sdk/go1.14"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/frew/sdk/go1.14/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/run/shm/go-build445574914=/tmp/go-build -gno-record-gcc-switches"

What did you do?

n/a (feature request)

What did you expect to see?

n/a (feature request)

What did you see instead?

n/a (feature request)

Feature request

vim-go had a command called :GoFillStruct and it would transform (for example), this:

x := Person{}

into

x := Person{
	Name: "",
	Employed: false,
	Age: 0,
}

Basically it'd set all the fields to their zero value. In govim/govim#709 I was told that this needs to be added to gopls first, so here I am :)

@gopherbot gopherbot added this to the Unreleased milestone Feb 28, 2020
@stamblerre stamblerre changed the title x/tools/gopls: feature Request: fill struct x/tools/gopls: support fill struct behavior Mar 2, 2020
@stamblerre stamblerre modified the milestones: Unreleased, gopls/v1.0.0 Mar 2, 2020
@golang golang deleted a comment from gopherbot Mar 2, 2020
@stamblerre
Copy link
Contributor

@stamblerre stamblerre commented Mar 2, 2020

Thanks for the issue report! I agree that we should support this feature.

@muirdm: Do you think we could fit this behavior into completion?

@muirdm
Copy link

@muirdm muirdm commented Mar 2, 2020

For my understanding, what is the use case for this?

@stamblerre
Copy link
Contributor

@stamblerre stamblerre commented Mar 2, 2020

I don't know if it's particularly useful for the Person case described above, but I would find it useful if the struct contained map values. (My classic example is go/types.Info, which I always find super annoying to create.) My ideal scenario when completing that struct is that, if I have a value of the correct type in scope, it should be used -- otherwise, we should make a map in the struct declaration.

@muirdm
Copy link

@muirdm muirdm commented Mar 2, 2020

The zero value of map is "nil", so this proposal as written wouldn't help in the types.Info case.

In my experience having the literal completion that gives you a candidate for make(map[some.Long]annoying.Map) is already a major improvement. Having structs get automatically filled in with in-scope objects sounds hard to avoid false positives.

@frioux
Copy link
Author

@frioux frioux commented Mar 2, 2020

@muirdm
Copy link

@muirdm muirdm commented Mar 3, 2020

I can see how that could be part of your workflow, but it also seems to overlap with existing facilities such as textDocument/hover which will show you all the struct fields or just a normal completion request in the struct literal, which also will list all the struct fields and their types.

To answer the original question of fitting this into completion, we could but I'm not sure what would trigger the completion or how it would show up clearly to the user. Maybe better as a code action?

@frioux
Copy link
Author

@frioux frioux commented Mar 3, 2020

I don't know what a code action is, but in the original setting it was something the user would explicitly request, rather than fitting into the same workflow as method completion. I personally think that's fine; this is something I'd do a few times a day, not constantly, like method completion.

1 similar comment
@frioux
Copy link
Author

@frioux frioux commented Mar 3, 2020

I don't know what a code action is, but in the original setting it was something the user would explicitly request, rather than fitting into the same workflow as method completion. I personally think that's fine; this is something I'd do a few times a day, not constantly, like method completion.

@leitzler
Copy link
Contributor

@leitzler leitzler commented Mar 6, 2020

I support the codeAction suggestion, seems like it would be a better fit (maybe of kind refactor.rewrite.fillstruct).

As a feature this is something that, at least I, hear people ask for quite often. With the use case to get the field names quickly added when creating a new struct instance. Hover does show the same info, but it would be really helpful if gopls could add it for you so that you don't have to add them manually.

@luciolas
Copy link

@luciolas luciolas commented Apr 6, 2020

Is anyone working on this? Mind if I take a look at implementing this feature?

@stamblerre
Copy link
Contributor

@stamblerre stamblerre commented Apr 6, 2020

I don't believe so, so please go ahead, @luciolas! As a starting point, I would suggest implementing this behavior as a command.

@luciolas
Copy link

@luciolas luciolas commented Apr 7, 2020

Ahh, I went ahead and wrote some code in code_action.go. Is there a reason for implementing it as a command?

Secondly, I also tested if completions are viable for a struct fill.
(See GIF below for a small demo on using code action and completions)

X1Lgc2noZR

Thirdly, a few things I have in mind:

  1. Does Code Action support placeholders?
  2. Is it possible to trigger completion while in a placeholder?
@stamblerre
Copy link
Contributor

@stamblerre stamblerre commented Apr 7, 2020

Ahh, I went ahead and wrote some code in code_action.go. Is there a reason for implementing it as a command?

I think either way probably works. I wasn't sure if it necessarily fit under "refactor.rewrite", but I think it works.

Secondly, I also tested if completions are viable for a struct fill.
(See GIF below for a small demo on using code action and completions)

Looks great! Thanks for working on this. I think the code action is a good starting point, and we could possible extend this to be part of completions if we think of a good user experience for it.

Thirdly, a few things I have in mind:

  1. Does Code Action support placeholders?

I don't believe so.

  1. Is it possible to trigger completion while in a placeholder?

I think it should be possible, yes.

@a-h
Copy link
Contributor

@a-h a-h commented Apr 8, 2020

This looks great, I'd also like to see a code action to fill a struct from a variable (merge).

type A struct {
  ID string
  Name string
  Phone string
  Email string
}

type B struct {
  Name string
  Phone string
  Email string
  Fax string
}

In this case, the snippet would need to know the source and destination variable names (they should be in scope). Given variables a and b of type A and B respectively, the snippet would produce something like this.

var a A
// Not present on B.
// a.ID = b.ID
a.Name = b.Email
a.Phone = b.Email
a.Email = b.Email
// Not present on A.
// a.Fax = b.Fax

This would prevent a common mistake of forgetting to copy a field from one type to another, missing a field, or overwriting the wrong names (e.g. a.Fax = b.Email). These types of things pop up as the "last line effect", where developers switch off as they keep track of the fields they have or haven't mapped.

Runtime tools exist such as https://github.com/imdario/mergo but these must use reflection, resulting in poorer performance, and the use of a 3rd party library.

Not sure if this should be a completely different thing (merge?), but this feature looks like a good starting point.

@leitzler
Copy link
Contributor

@leitzler leitzler commented Jun 10, 2020

Can this be close now that https://golang.org/cl/227437 & golang/tools#220 is merged?

@stamblerre
Copy link
Contributor

@stamblerre stamblerre commented Jun 10, 2020

Yep. @joshbaum will be doing some more work on fillstruct to make it work through go/analysis like the rest of our code actions, but that should not change its behavior.

@stamblerre stamblerre closed this Jun 10, 2020
johnboyes added a commit to agilepathway/label-checker that referenced this issue Jul 5, 2020
fillstruct fills a struct literal with default values[1]
This functionality is now available in the gopls language server[2]

[1] https://github.com/davidrjenni/reftools/tree/master/cmd/fillstruct
[2] golang/go#37576 (comment)
johnboyes added a commit to agilepathway/label-checker that referenced this issue Jul 5, 2020
fillstruct fills a struct literal with default values[1]
This functionality is now available in the gopls language server[2]

[1] https://github.com/davidrjenni/reftools/tree/master/cmd/fillstruct
[2] golang/go#37576 (comment)
johnboyes added a commit to agilepathway/label-checker that referenced this issue Jul 5, 2020
fillstruct fills a struct literal with default values[1]
This functionality is now available in the gopls language server[2]

[1] https://github.com/davidrjenni/reftools/tree/master/cmd/fillstruct
[2] golang/go#37576 (comment)
johnboyes added a commit to agilepathway/label-checker that referenced this issue Jul 5, 2020
* Enable Codespaces - add default Go files

Codespaces[1] allows us to use a remote vscode environment embedded in
the browser in GitHub[1]

This commit adds the pre-built container configuration[2] for Go[3].
We can customise this configuration as we wish in future commits.

[1] https://github.com/features/codespaces/
[2] https://docs.github.com/en/github/developing-online-with-codespaces/configuring-codespaces-for-your-project#using-a-pre-built-container-configuration
[3] https://github.com/microsoft/vscode-dev-containers/tree/master/containers/go

* Suppress/fix devcontainer Dockerfile warnings

These were hadolint warnings, and there were three of them, all on
.devcontainer/Dockerfile#L17:

DL3003 Use WORKDIR to switch to a directory

DL3008 Pin versions in apt get install.
Instead of `apt-get install <package>`
use `apt-get install <package>=<version>`

DL3015 Avoid additional packages by specifying `--no-install-recommends`

Suppressed the warnings apart from the DL3015 one, which was easy to
fix.

Not fixing the other warnings (for now anyway) as this Dockerfile is
code that has been lifted and shifted from the
`.devcontainer/Dockerfile` in:
https://github.com/microsoft/vscode-dev-containers/tree/master/containers/go

* Update module settings to "on" as we use modules

See:
https://dev.to/maelvls/why-is-go111module-everywhere-and-everything-about-go-modules-24k

* Add shellcheck vscode extension to devcontainer

https://www.shellcheck.net/
https://marketplace.visualstudio.com/items?itemName=timonwong.shellcheck

* Use vscode go language server on devcontainer

https://github.com/golang/vscode-go/blob/master/docs/gopls.md

* Stop installing go dependencies on devcontainer

There is no need to install them as we are using go modules - see:
microsoft/vscode-go#2836

* Set vscode editor go tabsize to correct size of 8

See:
microsoft/vscode-go#2479 (comment)

* Use golangci-lint for vscode devcontainer linting

https://github.com/golangci/golangci-lint

* No longer install Guru on devcontainer

It does not support Go modules:
https://github.com/golang/vscode-go/blob/master/docs/tools.md#guru

* Remove unnecessary gorename from devcontainer

Not needed when using go modules and gopls language server:
https://github.com/golang/vscode-go/blob/master/docs/tools.md#gorename

* Remove unnecessary godoctor from devcontainer

It is not needed when using go modules and the gopls language server:
https://github.com/golang/vscode-go/blob/master/docs/tools.md#godoctor

* Remove unnecessary goimports from devcontainer

Imports are instead handled by the gopls language server:
golang/go#33587 (comment)

* Remove unnecessary golint from devcontainer

Not needed as we are using golangci-lint

* Remove unnecessary gotests from devcontainer

gotests autogenerates table tests boilerplate code.  We don't need this
for this project.

* Remove unnecessary goplay module from devcontainer

We don't need this functionality:
https://github.com/haya14busa/goplay/

* Remove unnecessary gometalinter from devcontainer

Not needed as we are using golangci-lint for linting.

* Remove unnecessary impl module from devcontainer

It does not have support for go modules:
golang/go#37537

* Remove unnecessary fillstruct from devcontainer

fillstruct fills a struct literal with default values[1]
This functionality is now available in the gopls language server[2]

[1] https://github.com/davidrjenni/reftools/tree/master/cmd/fillstruct
[2] golang/go#37576 (comment)

* Add comment to explain why gopkgs is still needed

It is still needed even with gopls:
microsoft/vscode-go#3050 (comment)

* Fix installation of golangci-lint on devcontainer

Prior to this commit, vscode was saying "Analysis tools missing" and
prompting to install it.
Fix was to install golangci-lint via go get, as per:
golangci/golangci-lint#1037 (comment)

* Remove unnecessary gogetdoc from devcontainer

Similar functionality is available in the gopls language server:
fatih/vim-go#2808 (comment)

* Remove unnecessary revive linter from devcontainer

We are using golangci-lint for linting, so no need for revive.

* Remove unnecessary go-tools from devcontainer

go-tools primarily contains staticcheck, which we don't need as we are
using golangci-lint for linting.

* Output go version after building devcontainer

Doing this just to provide assurance that the container has started
successfully, after building.

* Move settings which are not container-specific

The guideline for`devcontainer.json` settings is that they should only
contain settings which _must_ be be changed in a container (e.g.
absolute paths)[1].

Moved the other settings to `.vscode/settings.json` so that they are
more visible, and easier to use when working locally (i.e. not in a
container).

[1] microsoft/vscode-remote-release#874 (comment)

* Up tests timeout as tests are slower on container

The tests seem to run much slower (c. 100 seconds compared to c. 50
seconds) when running on a remote container, compared to locally.
Will investigate to see if this is the same when running on Codespaces.

If the tests are taking 100 seconds we may need to create an issue to
speed them up.

* Add recommended vscode go settings

As per the recommendations at:
https://github.com/golang/tools/blob/master/gopls/doc/vscode.md

* Set dark colour theme for vscode in devcontainer

* Set devcontainer vscode to autosave after 500ms

Adding these settings to the devcontainer settings file rather than the
vscode settings file, as we want them to apply at the machine level.

https://code.visualstudio.com/docs/editor/codebasics#_save-auto-save
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
7 participants
You can’t perform that action at this time.