Skip to content

Commit

Permalink
cmd/govim: add config for defining the gopls environment
Browse files Browse the repository at this point in the history
gopls can be configured with an environment, an environment which is
passed to go/packages. For example, setting GOOS and GOARCH, or setting
GOFLAGS=-tags=other to set a build tag.

Therefore we define a govim config key, "GoplsEnv", for setting this
environment.

For example:

  govim#config#Set("GoplsEnv", {"GOFLAGS": "-mod=readonly"})

As part of this add a test that verifies the behaviour of the above
setting. Setting of build tags does not current work; that is blocked on
golang/go#35548 and will be tested in a follow
up PR.

Fixes #555
  • Loading branch information
myitcv committed Dec 8, 2019
1 parent 55677e1 commit 2b6be93
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 9 deletions.
13 changes: 13 additions & 0 deletions autoload/govim/config.vim
Expand Up @@ -88,6 +88,18 @@ function! s:validGoImportsLocalPrefix(v)
return s:validString(a:v)
endfunction

function! s:validGoplsEnv(v)
if type(a:v) != 4
return [v:false, "value must be a dict"]
endif
for [key, value] in items(a:v)
if type(value) != 1
return [v:false, "value for key ".key." must be a string"]
endif
endfor
return [v:true, ""]
endfunction

function! s:validExperimentalMouseTriggeredHoverPopupOptions(v)
if has_key(a:v, "line")
if type(a:v["line"]) != 0
Expand Down Expand Up @@ -116,6 +128,7 @@ let s:validators = {
\ "CompletionCaseSensitive": function("s:validCompletionCaseSensitive"),
\ "CompleteUnimported": function("s:validCompleteUnimported"),
\ "GoImportsLocalPrefix": function("s:validGoImportsLocalPrefix"),
\ "GoplsEnv": function("s:validGoplsEnv"),
\ "ExperimentalMouseTriggeredHoverPopupOptions": function("s:validExperimentalMouseTriggeredHoverPopupOptions"),
\ "ExperimentalCursorTriggeredHoverPopupOptions": function("s:validExperimentalCursorTriggeredHoverPopupOptions"),
\ }
7 changes: 7 additions & 0 deletions cmd/govim/config/config.go
Expand Up @@ -80,6 +80,13 @@ type Config struct {
// comma-separated list
GoImportsLocalPrefix *string `json:",omitempty"`

// GoplsEnv configures the set of environment variables gopls is using in
// calls to go/packages. This is most easily understood in the context of
// build tags/constraints, where GOOS/GOARCH could be set for example, or
// GOFLAGS set to "-mod=readonly" in order to prevent changes being
// automatically made to go.mod.
GoplsEnv *map[string]string `json:",omitempty"`

// ExperimentalMouseTriggeredHoverPopupOptions is a map of options to apply
// when creating hover-based popup windows triggered by the mouse hovering
// over an identifier. It corresponds to the second argument to popup_create
Expand Down
6 changes: 6 additions & 0 deletions cmd/govim/gopls_client.go
Expand Up @@ -21,6 +21,7 @@ const (
goplsCaseSensitiveCompletion = "caseSensitiveCompletion"
goplsCompleteUnimported = "completeUnimported"
goplsGoImportsLocalPrefix = "local"
goplsEnv = "env"
)

var _ protocol.Client = (*govimplugin)(nil)
Expand Down Expand Up @@ -144,6 +145,11 @@ func (g *govimplugin) Configuration(ctxt context.Context, params *protocol.Param
if g.vimstate.config.GoImportsLocalPrefix != nil {
conf[goplsGoImportsLocalPrefix] = *g.vimstate.config.GoImportsLocalPrefix
}
if g.vimstate.config.GoplsEnv != nil {
// It is safe not to copy the map here because a new config setting from
// Vim creates a new map.
conf[goplsEnv] = *g.vimstate.config.GoplsEnv
}
res[0] = conf

g.logGoplsClientf("Configuration response: %v", pretty.Sprint(res))
Expand Down
35 changes: 26 additions & 9 deletions cmd/govim/internal/vimconfig/vimconfig.go
Expand Up @@ -16,21 +16,23 @@ type VimConfig struct {
CompletionCaseSensitive *int
CompleteUnimported *int
GoImportsLocalPrefix *string
GoplsEnv *map[string]string
ExperimentalMouseTriggeredHoverPopupOptions *map[string]interface{}
ExperimentalCursorTriggeredHoverPopupOptions *map[string]interface{}
}

func (c *VimConfig) ToConfig(d config.Config) config.Config {
v := config.Config{
FormatOnSave: c.FormatOnSave,
QuickfixSigns: boolVal(c.QuickfixSigns, d.QuickfixSigns),
QuickfixAutoDiagnostics: boolVal(c.QuickfixAutoDiagnostics, d.QuickfixAutoDiagnostics),
CompletionDeepCompletions: boolVal(c.CompletionDeepCompletions, d.CompletionDeepCompletions),
CompletionFuzzyMatching: boolVal(c.CompletionFuzzyMatching, d.CompletionFuzzyMatching),
Staticcheck: boolVal(c.Staticcheck, d.Staticcheck),
CompletionCaseSensitive: boolVal(c.CompletionCaseSensitive, d.CompletionCaseSensitive),
CompleteUnimported: boolVal(c.CompleteUnimported, d.CompleteUnimported),
GoImportsLocalPrefix: stringVal(c.GoImportsLocalPrefix, d.GoImportsLocalPrefix),
FormatOnSave: c.FormatOnSave,
QuickfixSigns: boolVal(c.QuickfixSigns, d.QuickfixSigns),
QuickfixAutoDiagnostics: boolVal(c.QuickfixAutoDiagnostics, d.QuickfixAutoDiagnostics),
CompletionDeepCompletions: boolVal(c.CompletionDeepCompletions, d.CompletionDeepCompletions),
CompletionFuzzyMatching: boolVal(c.CompletionFuzzyMatching, d.CompletionFuzzyMatching),
Staticcheck: boolVal(c.Staticcheck, d.Staticcheck),
CompletionCaseSensitive: boolVal(c.CompletionCaseSensitive, d.CompletionCaseSensitive),
CompleteUnimported: boolVal(c.CompleteUnimported, d.CompleteUnimported),
GoImportsLocalPrefix: stringVal(c.GoImportsLocalPrefix, d.GoImportsLocalPrefix),
GoplsEnv: copyStringValMap(c.GoplsEnv, d.GoplsEnv),
ExperimentalMouseTriggeredHoverPopupOptions: copyMap(c.ExperimentalMouseTriggeredHoverPopupOptions, d.ExperimentalMouseTriggeredHoverPopupOptions),
ExperimentalCursorTriggeredHoverPopupOptions: copyMap(c.ExperimentalCursorTriggeredHoverPopupOptions, d.ExperimentalCursorTriggeredHoverPopupOptions),
}
Expand All @@ -55,6 +57,21 @@ func stringVal(i, j *string) *string {
return i
}

func copyStringValMap(i, j *map[string]string) *map[string]string {
toCopy := i
if i == nil {
toCopy = j
if j == nil {
return nil
}
}
res := make(map[string]string)
for ck, cv := range *toCopy {
res[ck] = cv
}
return &res
}

func copyMap(i, j *map[string]interface{}) *map[string]interface{} {
toCopy := i
if i == nil {
Expand Down
@@ -0,0 +1,56 @@
# Test that calling govim#config#Set with a value for GoplsEnv of GOFLAGS
# does the right thing. This will necessarily involve a number of checks
# for the various build flags that can be set via GOFLAGS.

env
vim ex 'e main.go'
errlogmatch -wait 30s 'PublishDiagnostics callback: &protocol.PublishDiagnosticsParams{\n\S+:\s+URI:\s+"file://'$WORK/main.go
vim ex 'copen'
vim ex 'w errors'
vim ex 'cclose'
cmp errors pre.golden
vim ex 'w'

# Verify go.mod has not changed
cmp go.mod go.mod.golden.pre

# Change go.mod from outside Vim
exec go get example.com/blah@v1.0.0
exec go mod tidy
cmp go.mod go.mod.golden.post

# Verify the diagnostic has been updated
errlogmatch -wait 30s 'PublishDiagnostics callback: &protocol.PublishDiagnosticsParams{\n\S+:\s+URI:\s+"file://'$WORK/main.go
vim ex 'copen'
vim ex 'w errors'
vim ex 'cclose'
cmp errors post.golden

# Disabled pending resolution to https://github.com/golang/go/issues/34103
# errlogmatch -count=0 'LogMessage callback: &protocol\.LogMessageParams\{Type:(1|2), Message:".*'

-- go.mod --
module mod.com

go 1.13
-- go.mod.golden.pre --
module mod.com

go 1.13
-- go.mod.golden.post --
module mod.com

go 1.13

require example.com/blah v1.0.0
-- main.go --
package main

import "example.com/blah"

func main() {
println(blah.Name)
}
-- pre.golden --
main.go|3 col 8| could not import example.com/blah (no package for import example.com/blah)
-- post.golden --
3 changes: 3 additions & 0 deletions cmd/govim/testdata/scenario_modreadonly/default_config.json
@@ -0,0 +1,3 @@
{
"GoplsEnv": {"GOFLAGS": "-mod=readonly"}
}

0 comments on commit 2b6be93

Please sign in to comment.