diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml
index 811b08768c..3dc0e82b6c 100644
--- a/.github/workflows/release-nightly.yml
+++ b/.github/workflows/release-nightly.yml
@@ -1,13 +1,11 @@
name: Release (golang.go-nightly)
# Daily release on 15:00 UTC, monday-thursday.
-# Or, force to release by triggering repository_dispatch events by using
-# curl -v -H "Accept: application/vnd.github.everest-preview+json" -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/golang/vscode-go/dispatches -d '{ "event_type": "force-release" }'
+# Or, trigger with workflow dispatch event.
on:
schedule:
- cron: "0 15 * * MON-THU" # 15 UTC, monday-thursday daily
- repository_dispatch:
- types: [force-release]
+ workflow_dispatch:
jobs:
release:
@@ -15,6 +13,7 @@ jobs:
name: Release Nightly
runs-on: ubuntu-latest
+ environment: nightly
timeout-minutes: 20
steps:
diff --git a/.github/workflows/test-long-all.yml b/.github/workflows/test-long-all.yml
index 182fcededb..8606e513c2 100644
--- a/.github/workflows/test-long-all.yml
+++ b/.github/workflows/test-long-all.yml
@@ -17,7 +17,7 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
version: ['stable', 'insiders']
- go: ['1.15', '1.16', '1.17', '1.18.0-beta1']
+ go: ['1.15', '1.16', '1.17', '1.18.0-beta2']
steps:
- name: Clone repository
diff --git a/.github/workflows/test-long.yml b/.github/workflows/test-long.yml
index 79784f57d9..a1300349a8 100644
--- a/.github/workflows/test-long.yml
+++ b/.github/workflows/test-long.yml
@@ -16,7 +16,7 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest] # TODO: reenable macos-latest
version: ['stable']
- go: ['1.15', '1.16', '1.17', '1.18.0-beta1']
+ go: ['1.15', '1.16', '1.17', '1.18.0-beta2']
steps:
- name: Clone repository
diff --git a/build/all.bash b/build/all.bash
index 4483c8f46c..de29a6a657 100755
--- a/build/all.bash
+++ b/build/all.bash
@@ -43,6 +43,7 @@ go_binaries_info() {
run_test() {
echo "**** Run test ****"
+ df -h | grep shm
npm ci
npm run compile
npm run unit-test
@@ -61,7 +62,7 @@ run_test_in_docker() {
docker build -t vscode-test-env ${GOVERSION:+ --build-arg GOVERSION="${GOVERSION}"} -f ./build/Dockerfile .
# For debug tests, we need ptrace.
- docker run --cap-add SYS_PTRACE --workdir=/workspace -v "$(pwd):/workspace" vscode-test-env ci
+ docker run --cap-add SYS_PTRACE --shm-size=8G --workdir=/workspace -v "$(pwd):/workspace" vscode-test-env ci
}
prepare_nightly() {
diff --git a/codereview.cfg b/codereview.cfg
new file mode 100644
index 0000000000..7b02dc6633
--- /dev/null
+++ b/codereview.cfg
@@ -0,0 +1 @@
+issuerepo: golang/vscode-go
diff --git a/docs/advanced.md b/docs/advanced.md
index 805b292065..b4e367e79d 100644
--- a/docs/advanced.md
+++ b/docs/advanced.md
@@ -3,6 +3,62 @@
This document describes more advanced ways of working with the VS Code Go
extension.
+## Using Go1.18
+
+The latest Go extension (`v0.31.0+` or [Nightly](./nightly.md))
+contains experimental support for the [new Go 1.18 features](https://tip.golang.org/doc/go1.18).
+
+* [Generics](https://go.dev/doc/tutorial/generics): IntelliSense, Code Editing, Diagnostics, Sytax Highlighting, etc.
+* [Fuzzing](https://go.dev/doc/tutorial/fuzz): Run/Debug Test using CodeLens and Test UI (available in Nightly).
+* [Go workspace mode](https://pkg.go.dev/cmd/go@go1.18beta2#hdr-Workspace_maintenance): _WIP_
+
+The latest Go extension (v0.31.0+, or [Nightly](./nightly.md)) supports the new Go 1.18 features with
+the following configuration.
+
+1. Get the preview of Go 1.18 by visiting [the official Go downloads page](https://go.dev/dl/#go1.18beta2).
+The following command will install `go1.18beta2` binary in your `$GOPATH/bin`
+or `GOBIN` directory, and download the Go 1.18 SDK.
+ ```sh
+ go install golang.org/dl/go1.18beta2@latest
+ go1.18beta2 download
+ ```
+
+ The location of the downloaded Go 1.18 SDK directory can be found with
+ ```sh
+ go1.18beta2 env GOROOT
+ ```
+
+2. Configure the extension to use `go1.18beta2`
+(or the `go` binary in the Go 1.18 SDK `bin` directory), using [one of
+the options listed below](https://github.com/golang/vscode-go/blob/master/docs/advanced.md#choosing-a-different-version-of-go).
+
+3. In order to process the new language features, [tools](./tools.md) this extension
+needs rebuilding with Go 1.18. **Please run the [`Go: Install/Update Tools`](commands.md#go-installupdate-tools)
+command to update tools**.
+
+4. (optional) for correct syntax highlighting, we recommend to enable
+[semantic highlighting](https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide)
+by turning on [Gopls' `ui.semanticTokens` setting](https://github.com/golang/vscode-go/blob/master/docs/settings.md#uisemantictokens).
+ ```
+ "gopls": { "ui.semanticTokens": true }
+ ```
+
+### Known Issues
+
+The Go Tools team are actively working on fixing bugs and improving usability
+of the new Go 1.18 features. Please take a look at current known
+[`vscode-go` issues](https://github.com/golang/vscode-go/issues?q=is%3Aissue+label%3Ago1.18+)
+and [`gopls` issues](https://github.com/golang/go/milestone/244).
+
+ * Features that depend on 3rd party tools (`staticcheck`, `golangci-lint`, ...) may not work yet.
+ Please follow the [tracking issue](https://github.com/golang/go/issues/50558).
+ * Support for `go.work` is a work in progress.
+
+In order to pick up the latest fixes, please consider to use the [Nightly](./nightly.md) version of
+the extension. We plan to make prereleases of `gopls` v0.8.0 available frequently.
+The Nightly version installs the pre-release version of `gopls`, so you will be able to pick up the
+latest bug fixes of `gopls` without manual installation.
+
## Choosing a different version of Go
The extension chooses the `go` command using the `PATH` (or `Path`) environment
diff --git a/docs/features.md b/docs/features.md
index 1598ad484f..e658933b43 100644
--- a/docs/features.md
+++ b/docs/features.md
@@ -15,6 +15,7 @@ This document describes the features supported by this extension.
* [Find interface implementations](#find-interface-implementations)
* [Document outline](#document-outline)
* [Toggle between code and tests](#toggle-between-code-and-tests)
+* [Syntax Highlighting](#syntax-highlighting)
* [Code Editing](#code-editing)
* [Snippets](#snippets)
* [Format and organize imports](#format-and-organize-imports)
@@ -103,6 +104,19 @@ Quickly toggle between a file and its corresponding test file by using the [`Go:
+
+## Syntax Highlighting
+
+The default syntax highlighting for Go files is implemented in Visual Studio Code using TextMate grammar, not by this extension.
+
+If you are using `gopls`, you can enable [Semantic Highlighting](https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide) for more accurate syntax highlighting based on semantic tokenization using `"gopls": { "ui.semanticTokens": true }`.
+
+### Go template syntax highlighting
+
+When `gopls`'s semantic tokens feature is enabled, `gopls` also provides semantic tokens for Go template files (language identifier: `gotmpl`). By default, the extension associates all `*.tmpl` or `*.gotmpl` files in the workspace with `gotmpl` language. Users can override the language mode by using Visual Studio Code's UI or the `"files.associations"` setting. See [Visual Studio Code's doc](https://code.visualstudio.com/docs/languages/overview#_changing-the-language-for-the-selected-file) for more details.
+
+
+
## Code Editing
### [Snippets](https://code.visualstudio.com/docs/editor/userdefinedsnippets)
@@ -115,13 +129,16 @@ Predefined snippets for quick coding. These snippets will appear as completion s
Format code and organize imports, either manually or on save.
+The extension formats Go code, organizes imports, and removes unused imports by default. For different behavior, please override per-language default settings following [the instruction](https://github.com/golang/vscode-go/blob/master/docs/advanced.md#formatting-code-and-organizing-imports).
+
+When organizing imports, the imported packages are grouped in the default `goimports` style. In order to group some packages after 3rd-party packages, use [`"gopls": { "formatting.local": }`](https://github.com/golang/vscode-go/blob/master/docs/settings.md#formattinglocal).
+
#### Add import
-Manually add a new import to your file through the [`Go: Add Import`](commands.md#go-add-import) command. Available packages are offered from your `GOPATH` and module cache.
+The extension organizes imports automatically and can add missing imports if the package is present in your module cache already. However, you can also manually add a new import to your file through the [`Go: Add Import`](commands.md#go-add-import) command. Available packages are offered from module cache (or from your `GOPATH` in GOPATH mode).
-
### [Rename symbol](https://code.visualstudio.com/docs/editor/refactoring#_rename-symbol)
Rename all occurrences of a symbol in your workspace.
diff --git a/docs/images/gotmpl.gif b/docs/images/gotmpl.gif
new file mode 100644
index 0000000000..c8fdaed526
Binary files /dev/null and b/docs/images/gotmpl.gif differ
diff --git a/docs/settings.md b/docs/settings.md
index 04682b4734..1a98e1ec1e 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -54,7 +54,6 @@ Alternate tools or alternate paths for the same tools used by the Go extension.
| `dlv` | Alternate tool to use instead of the dlv binary or alternate path to use for the dlv binary.
Default: `"dlv"` |
| `go` | Alternate tool to use instead of the go binary or alternate path to use for the go binary.
Default: `"go"` |
| `go-outline` | Alternate tool to use instead of the go-outline binary or alternate path to use for the go-outline binary.
Default: `"go-outline"` |
-| `gopkgs` | Alternate tool to use instead of the gopkgs binary or alternate path to use for the gopkgs binary.
Default: `"gopkgs"` |
| `gopls` | Alternate tool to use instead of the gopls binary or alternate path to use for the gopls binary.
Default: `"gopls"` |
### `go.autocompleteUnimportedPackages`
@@ -175,7 +174,7 @@ Experimental Feature: Enable/Disable entries from the context menu in the editor
| `fillStruct` | If true, adds command to fill struct literal with default values to the editor context menu
Default: `true` |
| `generateTestForFile` | If true, adds command to generate unit tests for current file to the editor context menu
Default: `true` |
| `generateTestForFunction` | If true, adds command to generate unit tests for function under the cursor to the editor context menu
Default: `true` |
-| `generateTestForPackage` | If true, adds command to generate unit tests for currnt package to the editor context menu
Default: `true` |
+| `generateTestForPackage` | If true, adds command to generate unit tests for current package to the editor context menu
Default: `true` |
| `playground` | If true, adds command to upload the current file or selection to the Go Playground
Default: `true` |
| `removeTags` | If true, adds command to remove configured tags from struct fields to the editor context menu
Default: `true` |
| `testAtCursor` | If true, adds command to run the test under the cursor to the editor context menu
Default: `false` |
@@ -455,6 +454,11 @@ Allowed Options:
Default: `"proxy"`
+### `go.toolsManagement.go`
+
+The path to the `go` binary used to install the Go tools. If it's empty, the same `go` binary chosen for the project will be used for tool installation.
+
+Default: `""`
### `go.trace.server`
Trace the communication between VS Code and the Go language server.
@@ -731,7 +735,7 @@ Example Usage:
| `nilfunc` | check for useless comparisons between functions and nil
A useless comparison is one like f == nil as opposed to f() == nil.
Default: `true` |
| `nilness` | check for redundant or impossible nil comparisons
The nilness checker inspects the control-flow graph of each function in a package and reports nil pointer dereferences, degenerate nil pointers, and panics with nil values. A degenerate comparison is of the form x==nil or x!=nil where x is statically known to be nil or non-nil. These are often a mistake, especially in control flow related to errors. Panics with nil values are checked because they are not detectable by
if r := recover(); r != nil {
This check reports conditions such as:
if f == nil { // impossible condition (f is a function)
}
and:
p := &v
...
if p != nil { // tautological condition
}
and:
if p == nil {
print(*p) // nil dereference
}
and:
if p == nil {
panic(p)
}
Default: `false` |
| `nonewvars` | suggested fixes for "no new vars on left side of :="
This checker provides suggested fixes for type errors of the type "no new vars on left side of :=". For example: z := 1
z := 2
will turn into z := 1
z = 2
Default: `true` |
-| `noresultvalues` | suggested fixes for "no result values expected"
This checker provides suggested fixes for type errors of the type "no result values expected". For example: func z() { return nil }
will turn into func z() { return }
Default: `true` |
+| `noresultvalues` | suggested fixes for unexpected return values
This checker provides suggested fixes for type errors of the type "no result values expected" or "too many return values". For example: func z() { return nil }
will turn into func z() { return }
Default: `true` |
| `printf` | check consistency of Printf format strings and arguments
The check applies to known functions (for example, those in package fmt) as well as any detected wrappers of known functions.
A function that wants to avail itself of printf checking but is not found by this analyzer's heuristics (for example, due to use of dynamic calls) can insert a bogus call:
if false {
_ = fmt.Sprintf(format, args...) // enable printf checking
}
The -funcs flag specifies a comma-separated list of names of additional known formatting functions or methods. If the name contains a period, it must denote a specific function using one of the following forms:
dir/pkg.Function
dir/pkg.Type.Method
(*dir/pkg.Type).Method
Otherwise the name is interpreted as a case-insensitive unqualified identifier such as "errorf". Either way, if a listed name ends in f, the function is assumed to be Printf-like, taking a format string before the argument list. Otherwise it is assumed to be Print-like, taking a list of arguments with no format string.
Default: `true` |
| `shadow` | check for possible unintended shadowing of variables
This analyzer check for shadowed variables. A shadowed variable is a variable declared in an inner scope with the same name and type as a variable in an outer scope, and where the outer variable is mentioned after the inner one is declared.
(This definition can be refined; the module generates too many false positives and is not yet enabled by default.)
For example:
func BadRead(f *os.File, buf []byte) error {
var err error
for {
n, err := f.Read(buf) // shadows the function variable 'err'
if err != nil {
break // causes return of wrong value
}
foo(buf)
}
return err
}
Default: `false` |
| `shift` | check for shifts that equal or exceed the width of the integer
Default: `true` |
@@ -742,6 +746,7 @@ Example Usage:
| `stdmethods` | check signature of methods of well-known interfaces
Sometimes a type may be intended to satisfy an interface but may fail to do so because of a mistake in its method signature. For example, the result of this WriteTo method should be (int64, error), not error, to satisfy io.WriterTo:
type myWriterTo struct{...}
func (myWriterTo) WriteTo(w io.Writer) error { ... }
This check ensures that each method whose name matches one of several well-known interface methods from the standard library has the correct signature for that interface.
Checked method names include: Format GobEncode GobDecode MarshalJSON MarshalXML
Peek ReadByte ReadFrom ReadRune Scan Seek
UnmarshalJSON UnreadByte UnreadRune WriteByte
WriteTo
Default: `true` |
| `stringintconv` | check for string(int) conversions
This checker flags conversions of the form string(x) where x is an integer (but not byte or rune) type. Such conversions are discouraged because they return the UTF-8 representation of the Unicode code point x, and not a decimal string representation of x as one might expect. Furthermore, if x denotes an invalid code point, the conversion cannot be statically rejected.
For conversions that intend on using the code point, consider replacing them with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the string representation of the value in the desired base.
Default: `true` |
| `structtag` | check that struct field tags conform to reflect.StructTag.Get
Also report certain struct tags (json, xml) used with unexported fields.
Default: `true` |
+| `stubmethods` | stub methods analyzer
This analyzer generates method stubs for concrete types in order to implement a target interface
Default: `true` |
| `testinggoroutine` | report calls to (*testing.T).Fatal from goroutines started by a test.
Functions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and Skip{,f,Now} methods of *testing.T, must be called from the test goroutine itself. This checker detects calls to these functions that occur within a goroutine started by the test. For example:
func TestFoo(t *testing.T) { go func() { t.Fatal("oops") // error: (*T).Fatal called from non-test goroutine }() }
Default: `true` |
| `tests` | check for common mistaken usages of tests and examples
The tests checker walks Test, Benchmark and Example functions checking malformed names, wrong signatures and examples documenting non-existent identifiers.
Please see the documentation for package testing in golang.org/pkg/testing for the conventions that are enforced for Tests, Benchmarks, and Examples.
Default: `true` |
| `undeclaredname` | suggested fixes for "undeclared name: <>"
This checker provides suggested fixes for type errors of the type "undeclared name: <>". It will either insert a new statement, such as:
"<> := "
or a new function declaration, such as:
func <>(inferred parameters) { panic("implement me!")
}
Default: `true` |
@@ -751,7 +756,7 @@ Example Usage:
| `unusedparams` | check for unused parameters of functions
The unusedparams analyzer checks functions to see if there are any parameters that are not being used.
To reduce false positives it ignores: - methods - parameters that do not have a name or are underscored - functions in test files - functions with empty bodies or those with just a return stmt
Default: `false` |
| `unusedresult` | check for unused results of calls to some functions
Some functions like fmt.Errorf return a result and have no side effects, so it is always a mistake to discard the result. This analyzer reports calls to certain functions in which the result of the call is ignored.
The set of functions may be controlled using flags.
Default: `true` |
| `unusedwrite` | checks for unused writes
The analyzer reports instances of writes to struct fields and arrays that are never read. Specifically, when a struct object or an array is copied, its elements are copied implicitly by the compiler, and any element write to this copy does nothing with the original object.
For example:
type T struct { x int }
func f(input []T) {
for i, v := range input { // v is a copy
v.x = i // unused write to field x
}
}
Another example is about non-pointer receiver:
type T struct { x int }
func (t T) f() { // t is a copy
t.x = i // unused write to field x
}
Default: `false` |
-| `useany` | check for constraints that could be simplified to "any"
Default: `true` |
+| `useany` | check for constraints that could be simplified to "any"
Default: `false` |
### `ui.diagnostic.annotations`
(Experimental) annotations specifies the various kinds of optimization diagnostics
@@ -841,7 +846,7 @@ Default: `"Both"`
Allowed Options: `CaseInsensitive`, `CaseSensitive`, `FastFuzzy`, `Fuzzy`
-Default: `"Fuzzy"`
+Default: `"FastFuzzy"`
### `ui.navigation.symbolStyle`
(Advanced) symbolStyle controls how symbols are qualified in symbol responses.
diff --git a/docs/tools.md b/docs/tools.md
index 90d391bdf7..bbb3c35327 100644
--- a/docs/tools.md
+++ b/docs/tools.md
@@ -38,10 +38,6 @@ For a comprehensive overview of how to debug your Go programs, please see the [d
### [`dlv-dap`](https://github.com/go-delve/delve)
This extension requires an unstable version of [`dlv`](#dlv) when users opt in to use Delve's native DAP implementation. `dlv-dap` is a `dlv` built from the master, which includes unreleased features. Please see the documentation about [Dlv DAP - Delve's Native DAP implementation](./dlv-dap.md) for details.
-### [`gopkgs`](https://pkg.go.dev/github.com/uudashr/gopkgs?tab=overview)
-
-This tool provides autocompletion for unimported packages. Replacement of `gopkgs` with [`gopls`] is a work-in-progress.
-
### [`go-outline`](https://pkg.go.dev/github.com/ramya-rao-a/go-outline?tab=overview)
This tool provides the information needed to compute the various test code lenses. It will be replaced with [`gopls`].
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index e28abcbd80..fa8498b5af 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -18,7 +18,7 @@ Check the bottom of the VS Code window for any warnings and notifications. For e
Run the [`Go: Locate Configured Go Tools`](commands.md#go-locate-configured-go-tools) command. The output is split into sections.
-In the first indented section, check that at least `gopkgs`, `go-outline`, `dlv`, and `gopls` are installed -- they're necessary for the extension's basic functionality. The other tools [provide optional features](tools.md) and are less important unless you need those features. You can install tools by running the [`Go: Install/Update Tools`](commands.md#go-installupdate-tools) command.
+In the first indented section, check that at least `go-outline`, `dlv`, and `gopls` are installed -- they're necessary for the extension's basic functionality. The other tools [provide optional features](tools.md) and are less important unless you need those features. You can install tools by running the [`Go: Install/Update Tools`](commands.md#go-installupdate-tools) command.
Then, look at the `Workspace Folder` section(s) for the environment in use. Verify that `GOROOT` is set to a valid Go installation; if not, follow the [getting started guide](../README.md#install-go). If `GOPATH` is unset, or surprising, read more about [setting up your `GOPATH`](gopath.md#setting-gopath). Also, `GOMOD` should usually point to your project's `go.mod` file if you're in module mode. (More complicated workspace setups may have a blank `GOMOD`. See the `gopls` [workspace documentation](https://github.com/golang/tools/blob/master/gopls/doc/workspace.md) for more on valid workspace setups.) To change the workspace environment, use settings such as [`go.gopath`](settings.md#go.gopath) and [`go.toolsEnvVars`](settings.md#go.toolsEnvVars).
diff --git a/package-lock.json b/package-lock.json
index 7aaccc3dab..49033a0b5a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "go",
- "version": "0.31.1",
+ "version": "0.32.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "go",
- "version": "0.31.1",
+ "version": "0.32.0",
"license": "MIT",
"dependencies": {
"deep-equal": "2.0.5",
@@ -39,7 +39,7 @@
"fs-extra": "9.1.0",
"get-port": "5.1.1",
"gts": "3.1.0",
- "mocha": "9.1.2",
+ "mocha": "9.2.0",
"prettier": "2.2.1",
"sinon": "9.2.4",
"ts-loader": "7.0.5",
@@ -1067,10 +1067,16 @@
"dev": true
},
"node_modules/chokidar": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
- "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -1243,9 +1249,9 @@
}
},
"node_modules/debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+ "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"dependencies": {
"ms": "2.1.2"
},
@@ -3518,32 +3524,32 @@
}
},
"node_modules/mocha": {
- "version": "9.1.2",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.2.tgz",
- "integrity": "sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w==",
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz",
+ "integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==",
"dev": true,
"dependencies": {
"@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
- "chokidar": "3.5.2",
- "debug": "4.3.2",
+ "chokidar": "3.5.3",
+ "debug": "4.3.3",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
- "glob": "7.1.7",
+ "glob": "7.2.0",
"growl": "1.10.5",
"he": "1.2.0",
"js-yaml": "4.1.0",
"log-symbols": "4.1.0",
"minimatch": "3.0.4",
"ms": "2.1.3",
- "nanoid": "3.1.25",
+ "nanoid": "3.2.0",
"serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
"which": "2.0.2",
- "workerpool": "6.1.5",
+ "workerpool": "6.2.0",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
@@ -3587,6 +3593,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/mocha/node_modules/glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/mocha/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@@ -3649,9 +3675,9 @@
"dev": true
},
"node_modules/nanoid": {
- "version": "3.1.25",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
- "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
+ "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
"dev": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
@@ -5615,9 +5641,9 @@
}
},
"node_modules/workerpool": {
- "version": "6.1.5",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz",
- "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
+ "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
"dev": true
},
"node_modules/wrap-ansi": {
@@ -6548,9 +6574,9 @@
"dev": true
},
"chokidar": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
- "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
"requires": {
"anymatch": "~3.1.2",
@@ -6689,9 +6715,9 @@
}
},
"debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+ "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"requires": {
"ms": "2.1.2"
}
@@ -8364,32 +8390,32 @@
}
},
"mocha": {
- "version": "9.1.2",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.2.tgz",
- "integrity": "sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w==",
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz",
+ "integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==",
"dev": true,
"requires": {
"@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
- "chokidar": "3.5.2",
- "debug": "4.3.2",
+ "chokidar": "3.5.3",
+ "debug": "4.3.3",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
- "glob": "7.1.7",
+ "glob": "7.2.0",
"growl": "1.10.5",
"he": "1.2.0",
"js-yaml": "4.1.0",
"log-symbols": "4.1.0",
"minimatch": "3.0.4",
"ms": "2.1.3",
- "nanoid": "3.1.25",
+ "nanoid": "3.2.0",
"serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
"which": "2.0.2",
- "workerpool": "6.1.5",
+ "workerpool": "6.2.0",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
@@ -8413,6 +8439,20 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
+ "glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
"js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@@ -8462,9 +8502,9 @@
"dev": true
},
"nanoid": {
- "version": "3.1.25",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
- "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
+ "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
"dev": true
},
"natural-compare": {
@@ -9960,9 +10000,9 @@
"dev": true
},
"workerpool": {
- "version": "6.1.5",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz",
- "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
+ "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
"dev": true
},
"wrap-ansi": {
diff --git a/package.json b/package.json
index 663caa1917..7f64f044d2 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "go",
"displayName": "Go",
- "version": "0.31.1",
+ "version": "0.32.0",
"publisher": "golang",
"description": "Rich Go language support for Visual Studio Code",
"author": {
@@ -78,7 +78,7 @@
"fs-extra": "9.1.0",
"get-port": "5.1.1",
"gts": "3.1.0",
- "mocha": "9.1.2",
+ "mocha": "9.2.0",
"prettier": "2.2.1",
"sinon": "9.2.4",
"ts-loader": "7.0.5",
@@ -115,7 +115,8 @@
"go.goroot",
"go.inferGopath",
"go.toolsGopath",
- "go.toolsEnvVars"
+ "go.toolsEnvVars",
+ "go.toolsManagement.go"
]
}
},
@@ -1527,6 +1528,12 @@
"description": "The logging level the extension logs at, defaults to 'error'",
"scope": "machine-overridable"
},
+ "go.toolsManagement.go": {
+ "type": "string",
+ "default": "",
+ "description": "The path to the `go` binary used to install the Go tools. If it's empty, the same `go` binary chosen for the project will be used for tool installation.",
+ "scope": "machine-overridable"
+ },
"go.toolsManagement.checkForUpdates": {
"type": "string",
"default": "proxy",
@@ -1768,7 +1775,7 @@
"generateTestForPackage": {
"type": "boolean",
"default": true,
- "description": "If true, adds command to generate unit tests for currnt package to the editor context menu"
+ "description": "If true, adds command to generate unit tests for current package to the editor context menu"
},
"addImport": {
"type": "boolean",
@@ -1962,11 +1969,6 @@
"default": "go",
"description": "Alternate tool to use instead of the go binary or alternate path to use for the go binary."
},
- "gopkgs": {
- "type": "string",
- "default": "gopkgs",
- "description": "Alternate tool to use instead of the gopkgs binary or alternate path to use for the gopkgs binary."
- },
"gopls": {
"type": "string",
"default": "gopls",
@@ -2276,7 +2278,7 @@
},
"noresultvalues": {
"type": "boolean",
- "markdownDescription": "suggested fixes for \"no result values expected\"\n\nThis checker provides suggested fixes for type errors of the\ntype \"no result values expected\". For example:\n\tfunc z() { return nil }\nwill turn into\n\tfunc z() { return }\n",
+ "markdownDescription": "suggested fixes for unexpected return values\n\nThis checker provides suggested fixes for type errors of the\ntype \"no result values expected\" or \"too many return values\".\nFor example:\n\tfunc z() { return nil }\nwill turn into\n\tfunc z() { return }\n",
"default": true
},
"printf": {
@@ -2329,6 +2331,11 @@
"markdownDescription": "check that struct field tags conform to reflect.StructTag.Get\n\nAlso report certain struct tags (json, xml) used with unexported fields.",
"default": true
},
+ "stubmethods": {
+ "type": "boolean",
+ "markdownDescription": "stub methods analyzer\n\nThis analyzer generates method stubs for concrete types\nin order to implement a target interface",
+ "default": true
+ },
"testinggoroutine": {
"type": "boolean",
"markdownDescription": "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\nfunc TestFoo(t *testing.T) {\n go func() {\n t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n }()\n}\n",
@@ -2377,7 +2384,7 @@
"useany": {
"type": "boolean",
"markdownDescription": "check for constraints that could be simplified to \"any\"",
- "default": true
+ "default": false
}
}
},
@@ -2489,7 +2496,7 @@
"",
""
],
- "default": "Fuzzy",
+ "default": "FastFuzzy",
"scope": "resource"
},
"ui.navigation.symbolStyle": {
diff --git a/src/config.ts b/src/config.ts
index 28efd4d1bd..12f92c59a0 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -5,13 +5,14 @@
*--------------------------------------------------------*/
import vscode = require('vscode');
+import { extensionId } from './const';
-// getGoConfig is declared as an exported const rather than a function, so it can be stubbbed in testing.
+/** getGoConfig is declared as an exported const rather than a function, so it can be stubbbed in testing. */
export const getGoConfig = (uri?: vscode.Uri) => {
return getConfig('go', uri);
};
-// getGoplsConfig returns the user's gopls configuration.
+/** getGoplsConfig returns the user's gopls configuration. */
export function getGoplsConfig(uri?: vscode.Uri) {
return getConfig('gopls', uri);
}
@@ -27,6 +28,27 @@ function getConfig(section: string, uri?: vscode.Uri) {
return vscode.workspace.getConfiguration(section, uri);
}
-// True if the extension is running in known cloud-based IDEs.
-export const IsInCloudIDE =
- process.env.CLOUD_SHELL === 'true' || process.env.CODESPACES === 'true' || !!process.env.GITPOD_WORKSPACE_ID;
+/** ExtensionInfo is a collection of static information about the extension. */
+export class ExtensionInfo {
+ /** Extension version */
+ readonly version?: string;
+ /** The application name of the editor, like 'VS Code' */
+ readonly appName: string;
+ /** True if the extension runs in preview mode (e.g. Nightly) */
+ readonly isPreview: boolean;
+ /** True if the extension runs in well-kwnon cloud IDEs */
+ readonly isInCloudIDE: boolean;
+
+ constructor() {
+ const packageJSON = vscode.extensions.getExtension(extensionId)?.packageJSON;
+ this.version = packageJSON?.version;
+ this.appName = vscode.env.appName;
+ this.isPreview = !!packageJSON?.preview;
+ this.isInCloudIDE =
+ process.env.CLOUD_SHELL === 'true' ||
+ process.env.CODESPACES === 'true' ||
+ !!process.env.GITPOD_WORKSPACE_ID;
+ }
+}
+
+export const extensionInfo = new ExtensionInfo();
diff --git a/src/goBrowsePackage.ts b/src/goBrowsePackage.ts
index c34fc9281b..f032b6bc58 100644
--- a/src/goBrowsePackage.ts
+++ b/src/goBrowsePackage.ts
@@ -100,7 +100,7 @@ async function showPackageList(workDir: string) {
const pkgs: string[] = Array.from(pkgMap.keys());
if (pkgs.length === 0) {
return vscode.window.showErrorMessage(
- 'Could not find packages. Ensure `gopkgs -format {{.Name}};{{.ImportPath}}` runs successfully.'
+ 'Could not find packages. Ensure `go list -f "{{.Name}};{{.ImportPath}}" all` runs successfully.'
);
}
const pkgFromDropdown = await vscode.window.showQuickPick(pkgs.sort(), {
diff --git a/src/goEnv.ts b/src/goEnv.ts
index 6c7be1e69f..59a75655c5 100644
--- a/src/goEnv.ts
+++ b/src/goEnv.ts
@@ -55,7 +55,7 @@ export function toolInstallationEnvironment(): NodeJS.Dict {
// toolExecutionEnvironment returns the environment in which tools should
// be executed. It always returns a new object.
export function toolExecutionEnvironment(uri?: vscode.Uri, addProcessEnv = true): NodeJS.Dict {
- const env = newEnvironment(addProcessEnv);
+ const env = newEnvironment(uri, addProcessEnv);
const gopath = getCurrentGoPath(uri);
if (gopath) {
env['GOPATH'] = gopath;
@@ -69,8 +69,8 @@ export function toolExecutionEnvironment(uri?: vscode.Uri, addProcessEnv = true)
return env;
}
-function newEnvironment(addProcessEnv = true): NodeJS.Dict {
- const toolsEnvVars = getGoConfig()['toolsEnvVars'];
+function newEnvironment(uri?: vscode.Uri, addProcessEnv = true): NodeJS.Dict {
+ const toolsEnvVars = getGoConfig(uri)['toolsEnvVars'];
const env = addProcessEnv ? Object.assign({}, process.env, toolsEnvVars) : Object.assign({}, toolsEnvVars);
if (toolsEnvVars && typeof toolsEnvVars === 'object') {
Object.keys(toolsEnvVars).forEach(
diff --git a/src/goEnvironmentStatus.ts b/src/goEnvironmentStatus.ts
index 8b11e48fba..5c07bb66b3 100644
--- a/src/goEnvironmentStatus.ts
+++ b/src/goEnvironmentStatus.ts
@@ -13,19 +13,12 @@ import moment = require('moment');
import os = require('os');
import path = require('path');
import { promisify } from 'util';
-import { getGoConfig, IsInCloudIDE } from './config';
+import { getGoConfig, extensionInfo } from './config';
import { toolInstallationEnvironment } from './goEnv';
import { logVerbose } from './goLogging';
import { addGoStatus, goEnvStatusbarItem, outputChannel, removeGoStatus } from './goStatus';
import { getFromGlobalState, getFromWorkspaceState, updateGlobalState, updateWorkspaceState } from './stateUtils';
-import {
- getBinPath,
- getCheckForToolsUpdatesConfig,
- getGoVersion,
- getTempFilePath,
- GoVersion,
- rmdirRecursive
-} from './util';
+import { getBinPath, getCheckForToolsUpdatesConfig, getGoVersion, GoVersion } from './util';
import {
correctBinname,
executableFileExists,
@@ -36,19 +29,12 @@ import {
} from './utils/pathUtils';
import vscode = require('vscode');
import WebRequest = require('web-request');
+import { installTool } from './goInstallTools';
-export class GoEnvironmentOption {
- public static fromQuickPickItem({ description, label }: vscode.QuickPickItem): GoEnvironmentOption {
- return new GoEnvironmentOption(description, label);
- }
-
- constructor(public binpath: string, public label: string) {}
-
- public toQuickPickItem(): vscode.QuickPickItem {
- return {
- label: this.label,
- description: this.binpath
- };
+export class GoEnvironmentOption implements vscode.QuickPickItem {
+ readonly description: string;
+ constructor(readonly binpath: string, readonly label: string, readonly available = true) {
+ this.description = available ? binpath : `download ${binpath}`;
}
}
@@ -108,9 +94,7 @@ export async function chooseGoEnvironment() {
}
// create quick pick items
- const uninstalledQuickPicks = uninstalledOptions.map((op) => op.toQuickPickItem());
- const defaultQuickPick = defaultOption ? [defaultOption.toQuickPickItem()] : [];
- const goSDKQuickPicks = goSDKOptions.map((op) => op.toQuickPickItem());
+ const defaultQuickPick = defaultOption ? [defaultOption] : [];
// dedup options by eliminating duplicate paths (description)
const clearOption: vscode.QuickPickItem = { label: CLEAR_SELECTION };
@@ -119,18 +103,15 @@ export async function chooseGoEnvironment() {
description: 'Select the go binary to use'
};
// TODO(hyangah): Add separators after clearOption if github.com/microsoft/vscode#74967 is resolved.
- const options = [
- filePickerOption,
- clearOption,
- ...defaultQuickPick,
- ...goSDKQuickPicks,
- ...uninstalledQuickPicks
- ].reduce((opts, nextOption) => {
- if (opts.find((op) => op.description === nextOption.description || op.label === nextOption.label)) {
- return opts;
- }
- return [...opts, nextOption];
- }, [] as vscode.QuickPickItem[]);
+ const options = [filePickerOption, clearOption, ...defaultQuickPick, ...goSDKOptions, ...uninstalledOptions].reduce(
+ (opts, nextOption) => {
+ if (opts.find((op) => op.description === nextOption.description || op.label === nextOption.label)) {
+ return opts;
+ }
+ return [...opts, nextOption];
+ },
+ [] as vscode.QuickPickItem[]
+ );
// get user's selection, return if none was made
const selection = await vscode.window.showQuickPick(options);
@@ -140,7 +121,7 @@ export async function chooseGoEnvironment() {
// update currently selected go
try {
- await setSelectedGo(GoEnvironmentOption.fromQuickPickItem(selection));
+ await setSelectedGo(selection);
} catch (e) {
vscode.window.showErrorMessage(e.message);
}
@@ -149,15 +130,20 @@ export async function chooseGoEnvironment() {
/**
* update the selected go path and label in the workspace state
*/
-export async function setSelectedGo(goOption: GoEnvironmentOption, promptReload = true): Promise {
+export async function setSelectedGo(goOption: vscode.QuickPickItem, promptReload = true): Promise {
if (!goOption) {
return false;
}
// if the selected go version is not installed, install it
- if (goOption.binpath?.startsWith('go get')) {
- // start a loading indicator
- await downloadGo(goOption);
+ if (goOption instanceof GoEnvironmentOption) {
+ const o = goOption.available ? (goOption as GoEnvironmentOption) : await downloadGo(goOption);
+ // check that the given binary is not already at the beginning of the PATH
+ const go = await getGoVersion();
+ if (!!go && (go.binaryPath === o.binpath || 'Go ' + go.format() === o.label)) {
+ return false;
+ }
+ await updateWorkspaceState('selectedGo', o);
} else if (goOption.label === CLEAR_SELECTION) {
if (!getSelectedGo()) {
return false; // do nothing.
@@ -192,13 +178,6 @@ export async function setSelectedGo(goOption: GoEnvironmentOption, promptReload
return false;
}
await updateWorkspaceState('selectedGo', new GoEnvironmentOption(newGo.binaryPath, formatGoVersion(newGo)));
- } else {
- // check that the given binary is not already at the beginning of the PATH
- const go = await getGoVersion();
- if (!!go && (go.binaryPath === goOption.binpath || 'Go ' + go.format() === goOption.label)) {
- return false;
- }
- await updateWorkspaceState('selectedGo', goOption);
}
// prompt the user to reload the window.
// promptReload defaults to true and should only be false for tests.
@@ -218,87 +197,68 @@ export async function setSelectedGo(goOption: GoEnvironmentOption, promptReload
}
// downloadGo downloads the specified go version available in dl.golang.org.
-async function downloadGo(goOption: GoEnvironmentOption) {
+async function downloadGo(goOption: GoEnvironmentOption): Promise {
+ if (goOption.available) {
+ return Promise.resolve(goOption);
+ }
const execFile = promisify(cp.execFile);
- await vscode.window.withProgress(
+ const newExecutableName = goOption.binpath.split('/').splice(-1)[0];
+
+ return await vscode.window.withProgress(
{
title: `Downloading ${goOption.label}`,
location: vscode.ProgressLocation.Notification
},
async () => {
- outputChannel.show();
outputChannel.clear();
-
- outputChannel.appendLine('Finding Go executable for downloading');
- const goExecutable = getBinPath('go');
- if (!goExecutable) {
- outputChannel.appendLine('Could not find Go executable.');
- throw new Error('Could not find Go tool.');
- }
-
- // TODO(bcloud) dedup repeated logic below which comes from
- // https://github.com/golang/vscode-go/blob/bc23fa854192d04200c8e4f74dca18d2c3021b46/src/goInstallTools.ts#L184
- // Install tools in a temporary directory, to avoid altering go.mod files.
- const mkdtemp = promisify(fs.mkdtemp);
- const toolsTmpDir = await mkdtemp(getTempFilePath('go-tools-'));
- let tmpGoModFile: string;
-
- // Write a temporary go.mod file to avoid version conflicts.
- tmpGoModFile = path.join(toolsTmpDir, 'go.mod');
- const writeFile = promisify(fs.writeFile);
- await writeFile(tmpGoModFile, 'module tools');
-
- // use the current go executable to download the new version
- const env = {
- ...toolInstallationEnvironment(),
- GO111MODULE: 'on'
- };
- const [, ...args] = goOption.binpath.split(' ');
- outputChannel.appendLine(`Running ${goExecutable} ${args.join(' ')}`);
- try {
- await execFile(goExecutable, args, {
- env,
- cwd: toolsTmpDir
- });
- } catch (getErr) {
- outputChannel.appendLine(`Error finding Go: ${getErr}`);
- throw new Error('Could not find Go version.');
+ outputChannel.show();
+ outputChannel.appendLine(`go install ${goOption.binpath}@latest`);
+ const result = await installTool({
+ name: newExecutableName,
+ importPath: goOption.binpath,
+ modulePath: goOption.binpath,
+ description: newExecutableName,
+ isImportant: false
+ });
+ if (result) {
+ outputChannel.appendLine(`Error installing ${goOption.binpath}: ${result}`);
+ throw new Error('Could not install ${goOption.binpath}');
}
-
// run `goX.X download`
- const newExecutableName = args[1].split('/')[2];
const goXExecutable = getBinPath(newExecutableName);
- outputChannel.appendLine(`Running: ${goXExecutable} download`);
+ outputChannel.appendLine(`${goXExecutable} download`);
try {
- await execFile(goXExecutable, ['download'], { env, cwd: toolsTmpDir });
+ await execFile(goXExecutable, ['download']);
} catch (downloadErr) {
outputChannel.appendLine(`Error finishing installation: ${downloadErr}`);
throw new Error('Could not download Go version.');
}
- outputChannel.appendLine('Finding newly downloaded Go');
- const sdkPath = path.join(os.homedir(), 'sdk');
- if (!(await dirExists(sdkPath))) {
+ outputChannel.appendLine(`Checking newly downloaded ${goOption.label} SDK`);
+
+ let sdkPath = '';
+ try {
+ const { stdout } = await execFile(goXExecutable, ['env', 'GOROOT'], {
+ env: toolInstallationEnvironment()
+ });
+ if (stdout) {
+ sdkPath = stdout.trim();
+ }
+ } catch (downloadErr) {
+ outputChannel.appendLine(`Error finishing installation: ${downloadErr}`);
+ throw new Error('Could not download Go version.');
+ }
+ if (!sdkPath || !(await dirExists(sdkPath))) {
outputChannel.appendLine(`SDK path does not exist: ${sdkPath}`);
throw new Error(`SDK path does not exist: ${sdkPath}`);
}
- const readdir = promisify(fs.readdir);
- const subdirs = await readdir(sdkPath);
- const dir = subdirs.find((subdir) => subdir === newExecutableName);
- if (!dir) {
- outputChannel.appendLine('Could not find newly downloaded Go');
- throw new Error('Could not install Go version.');
- }
+ outputChannel.appendLine(`${goOption.label} is available in ${sdkPath}`);
- const binpath = path.join(sdkPath, dir, 'bin', correctBinname('go'));
+ const binpath = path.join(sdkPath, 'bin', correctBinname('go'));
const newOption = new GoEnvironmentOption(binpath, goOption.label);
- await updateWorkspaceState('selectedGo', newOption);
-
- // remove tmp directories
- outputChannel.appendLine('Cleaning up...');
- rmdirRecursive(toolsTmpDir);
outputChannel.appendLine('Success!');
+ return newOption;
}
);
}
@@ -488,21 +448,13 @@ export async function getDefaultGoOption(): Promise {
// fetch information about what Go versions are available to install
let webResults;
try {
- webResults = await WebRequest.json('https://golang.org/dl/?mode=json');
+ webResults = await WebRequest.json('https://go.dev/dl/?mode=json');
} catch (error) {
return [];
}
@@ -513,9 +465,9 @@ async function fetchDownloadableGoVersions(): Promise {
// turn the web result into GoEnvironmentOption model
return webResults.reduce((opts, result: GoVersionWebResult) => {
// TODO: allow downloading from different sites
- const dlPath = `go get golang.org/dl/${result.version}`;
+ const dlPath = `golang.org/dl/${result.version}`;
const label = result.version.replace('go', 'Go ');
- return [...opts, new GoEnvironmentOption(dlPath, label)];
+ return [...opts, new GoEnvironmentOption(dlPath, label, false)];
}, []);
}
@@ -546,8 +498,8 @@ export async function getLatestGoVersions(): Promise {
// TODO(hyangah): consider to remove these hardcoded versions and instead
// show error notification if necessary.
results = [
- new GoEnvironmentOption('go get golang.org/dl/go1.17.1', 'Go 1.17.1'),
- new GoEnvironmentOption('go get golang.org/dl/go1.16.8', 'Go 1.16.8')
+ new GoEnvironmentOption('golang.org/dl/go1.17.6', 'Go 1.17.6', false),
+ new GoEnvironmentOption('golang.org/dl/go1.16.13', 'Go 1.16.13', false)
];
}
}
@@ -559,7 +511,7 @@ const STATUS_BAR_ITEM_NAME = 'Go Notification';
const dismissedGoVersionUpdatesKey = 'dismissedGoVersionUpdates';
export async function offerToInstallLatestGoVersion() {
- if (IsInCloudIDE) {
+ if (extensionInfo.isInCloudIDE) {
return;
}
const goConfig = getGoConfig();
@@ -596,7 +548,7 @@ export async function offerToInstallLatestGoVersion() {
const download = {
title: 'Download',
async command() {
- await vscode.env.openExternal(vscode.Uri.parse('https://golang.org/dl/'));
+ await vscode.env.openExternal(vscode.Uri.parse('https://go.dev/dl/'));
}
};
diff --git a/src/goImport.ts b/src/goImport.ts
index f0fa707e35..fa595a9b9b 100644
--- a/src/goImport.ts
+++ b/src/goImport.ts
@@ -12,7 +12,7 @@ import vscode = require('vscode');
import { ExecuteCommandRequest, ExecuteCommandParams } from 'vscode-languageserver-protocol';
import { toolExecutionEnvironment } from './goEnv';
import { promptForMissingTool } from './goInstallTools';
-import { languageClient } from './goLanguageServer';
+import { languageClient, serverInfo } from './goLanguageServer';
import { documentSymbols, GoOutlineImportsOptions } from './goOutline';
import { getImportablePackages } from './goPackages';
import { getBinPath, getImportPath, parseFilePrelude } from './util';
@@ -20,6 +20,7 @@ import { envPath, getCurrentGoRoot } from './utils/pathUtils';
const missingToolMsg = 'Missing tool: ';
+// listPackages returns 'importable' packages and places std packages first.
export async function listPackages(excludeImportedPkgs = false): Promise {
const importedPkgs =
excludeImportedPkgs && vscode.window.activeTextEditor
@@ -42,13 +43,14 @@ export async function listPackages(excludeImportedPkgs = false): Promise {
- if (languageClient) {
+ const COMMAND = 'gopls.list_known_packages';
+ if (languageClient && serverInfo?.Commands?.includes(COMMAND)) {
try {
const uri = languageClient.code2ProtocolConverter.asTextDocumentIdentifier(
vscode.window.activeTextEditor.document
).uri;
const params: ExecuteCommandParams = {
- command: 'gopls.list_known_packages',
+ command: COMMAND,
arguments: [
{
URI: uri
@@ -162,13 +164,14 @@ export function addImport(arg: { importPath: string }) {
return;
}
- if (languageClient) {
+ const COMMAND = 'gopls.add_import';
+ if (languageClient && serverInfo?.Commands?.includes(COMMAND)) {
try {
const uri = languageClient.code2ProtocolConverter.asTextDocumentIdentifier(
vscode.window.activeTextEditor.document
).uri;
const params: ExecuteCommandParams = {
- command: 'gopls.add_import',
+ command: COMMAND,
arguments: [
{
ImportPath: imp,
diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts
index c6298ff561..bfbbd380d4 100644
--- a/src/goInstallTools.ts
+++ b/src/goInstallTools.ts
@@ -13,7 +13,7 @@ import fs = require('fs');
import path = require('path');
import semver = require('semver');
import { ConfigurationTarget } from 'vscode';
-import { getGoConfig, getGoplsConfig } from './config';
+import { extensionInfo, getGoConfig, getGoplsConfig } from './config';
import { toolExecutionEnvironment, toolInstallationEnvironment } from './goEnv';
import { addGoRuntimeBaseToPATH, clearGoRuntimeBaseFromPATH } from './goEnvironmentStatus';
import { logVerbose } from './goLogging';
@@ -39,10 +39,9 @@ import {
GoVersion,
rmdirRecursive
} from './util';
-import { correctBinname, envPath, getCurrentGoRoot, setCurrentGoRoot } from './utils/pathUtils';
+import { correctBinname, envPath, executableFileExists, getCurrentGoRoot, setCurrentGoRoot } from './utils/pathUtils';
import util = require('util');
import vscode = require('vscode');
-import { isInPreviewMode, RestartReason } from './goLanguageServer';
const STATUS_BAR_ITEM_NAME = 'Go Tools';
@@ -97,12 +96,30 @@ export async function installAllTools(updateExistingToolsOnly = false) {
);
}
+export async function getGoForInstall(goVersion?: GoVersion, silent?: boolean): Promise {
+ const configured = getGoConfig().get('toolsManagement.go');
+ if (!configured) {
+ return goVersion;
+ }
+ if (executableFileExists(configured)) {
+ const go = await getGoVersion(configured);
+ if (go) return go;
+ }
+ if (!silent) {
+ outputChannel.appendLine(
+ `Ignoring misconfigured 'go.toolsManagement.go' (${configured}). Provide a valid Go command.`
+ );
+ }
+ return goVersion;
+}
+
/**
* Installs given array of missing tools. If no input is given, the all tools are installed
*
* @param missing array of tool names and optionally, their versions to be installed.
* If a tool's version is not specified, it will install the latest.
- * @param goVersion version of Go that affects how to install the tool. (e.g. modules vs legacy GOPATH mode)
+ * @param goVersion version of Go used in the project. If go used for tools installation
+ * is not configured or misconfigured, this is used as a fallback.
* @returns a list of tools that failed to install.
*/
export async function installTools(
@@ -119,6 +136,7 @@ export async function installTools(
}
outputChannel.clear();
+ const goForInstall = await getGoForInstall(goVersion);
const envForTools = toolInstallationEnvironment();
const toolsGopath = envForTools['GOPATH'];
let envMsg = `Tools environment: GOPATH=${toolsGopath}`;
@@ -163,7 +181,7 @@ export async function installTools(
for (const tool of missing) {
const modulesOffForTool = modulesOff;
- const failed = await installTool(tool, goVersion, envForTools, !modulesOffForTool);
+ const failed = await installToolWithGo(tool, goForInstall, envForTools, !modulesOffForTool);
if (failed) {
failures.push({ tool, reason: failed });
} else if (tool.name === 'gopls') {
@@ -202,9 +220,17 @@ async function tmpDirForToolInstallation() {
return toolsTmpDir;
}
-export async function installTool(
+// installTool installs the specified tool.
+export async function installTool(tool: ToolAtVersion): Promise {
+ const goVersion = await getGoForInstall(await getGoVersion());
+ const envForTools = toolInstallationEnvironment();
+
+ return await installToolWithGo(tool, goVersion, envForTools, true);
+}
+
+async function installToolWithGo(
tool: ToolAtVersion,
- goVersion: GoVersion,
+ goVersion: GoVersion, // go version to be used for installation.
envForTools: NodeJS.Dict,
modulesOn: boolean
): Promise {
@@ -225,7 +251,7 @@ export async function installTool(
} else {
let version: semver.SemVer | string | undefined = tool.version;
if (!version) {
- if (tool.usePrereleaseInPreviewMode && isInPreviewMode()) {
+ if (tool.usePrereleaseInPreviewMode && extensionInfo.isPreview) {
version = await latestToolVersion(tool, true);
} else if (tool.defaultVersion) {
version = tool.defaultVersion;
@@ -677,11 +703,15 @@ export async function latestToolVersion(tool: Tool, includePrerelease?: boolean)
// inspectGoToolVersion reads the go version and module version
// of the given go tool using `go version -m` command.
export const inspectGoToolVersion = defaultInspectGoToolVersion;
-async function defaultInspectGoToolVersion(binPath: string): Promise<{ goVersion?: string; moduleVersion?: string }> {
+async function defaultInspectGoToolVersion(
+ binPath: string
+): Promise<{ goVersion?: string; moduleVersion?: string; debugInfo?: string }> {
const goCmd = getBinPath('go');
const execFile = util.promisify(cp.execFile);
+ let debugInfo = 'go version -m failed';
try {
const { stdout } = await execFile(goCmd, ['version', '-m', binPath]);
+ debugInfo = stdout;
/* The output format will look like this
if the binary was built in module mode.
@@ -699,17 +729,21 @@ async function defaultInspectGoToolVersion(binPath: string): Promise<{ goVersion
path golang.org/x/tools/gopls
mod golang.org/x/tools/gopls (devel)
dep github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+
+ if the binary was built with a dev version of go, in module mode.
+ /Users/hakim/go/bin/gopls: devel go1.18-41f485b9a7 Mon Jan 31 13:43:52 2022 +0000
+ path golang.org/x/tools/gopls
+ mod golang.org/x/tools/gopls v0.8.0-pre.1 h1:6iHi9bCJ8XndQtBEFFG/DX+eTJrf2lKFv4GI3zLeDOo=
+ ...
*/
const lines = stdout.split('\n', 3);
- const goVersion = lines[0].split(/\s+/)[1];
+ const goVersion = lines[0] && lines[0].match(/\s+(go\d+.\d+\S*)/)[1];
const moduleVersion = lines[2].split(/\s+/)[3];
return { goVersion, moduleVersion };
} catch (e) {
- outputChannel.appendLine(
- `Failed to determine the version of ${binPath}. For debugging, run "go version -m ${binPath}"`
- );
- // either go version failed or stdout is not in the expected format.
- return {};
+ // either go version failed (e.g. the tool was compiled with a more recent version of go)
+ // or stdout is not in the expected format.
+ return { debugInfo };
}
}
diff --git a/src/goLanguageServer.ts b/src/goLanguageServer.ts
index 69b80884d1..1dfe7ccf08 100644
--- a/src/goLanguageServer.ts
+++ b/src/goLanguageServer.ts
@@ -25,6 +25,7 @@ import {
ExecuteCommandSignature,
HandleDiagnosticsSignature,
InitializeError,
+ InitializeResult,
Message,
ProvideCodeLensesSignature,
ProvideCompletionItemsSignature,
@@ -33,8 +34,7 @@ import {
RevealOutputChannelOn
} from 'vscode-languageclient';
import { LanguageClient } from 'vscode-languageclient/node';
-import { getGoConfig, getGoplsConfig, IsInCloudIDE } from './config';
-import { extensionId } from './const';
+import { getGoConfig, getGoplsConfig, extensionInfo } from './config';
import { GoCodeActionProvider } from './goCodeAction';
import { GoDefinitionProvider } from './goDeclaration';
import { toolExecutionEnvironment } from './goEnv';
@@ -76,10 +76,10 @@ import { ProvideFoldingRangeSignature } from 'vscode-languageclient/lib/common/f
import { daysBetween, getStateConfig, maybePromptForGoplsSurvey, timeDay, timeMinute } from './goSurvey';
import { maybePromptForDeveloperSurvey } from './goDeveloperSurvey';
-export interface LanguageServerConfig {
+interface LanguageServerConfig {
serverName: string;
path: string;
- version: string;
+ version?: { version: string; goVersion?: string };
modtime: Date;
enabled: boolean;
flags: string[];
@@ -94,11 +94,22 @@ export interface LanguageServerConfig {
// Global variables used for management of the language client.
// They are global so that the server can be easily restarted with
// new configurations.
+// TODO: refactor it. These can be encapsulated in a single LanguageServer class
+// that keeps track of the state of the active language server instance.
export let languageClient: LanguageClient;
let languageServerDisposable: vscode.Disposable;
export let latestConfig: LanguageServerConfig;
export let serverOutputChannel: vscode.OutputChannel;
export let languageServerIsRunning = false;
+// serverInfo is the information from the server received during initialization.
+export let serverInfo: ServerInfo = undefined;
+
+interface ServerInfo {
+ Name: string;
+ Version?: string;
+ GoVersion?: string;
+ Commands?: string[];
+}
const languageServerStartMutex = new Mutex();
@@ -220,7 +231,7 @@ export async function startLanguageServerWithFallback(ctx: vscode.ExtensionConte
// update to the latest version. We also check if we should prompt users to
// fill out the survey.
function scheduleGoplsSuggestions() {
- if (IsInCloudIDE) {
+ if (extensionInfo.isInCloudIDE) {
return;
}
// Some helper functions.
@@ -255,7 +266,7 @@ function scheduleGoplsSuggestions() {
return;
}
// Prompt the user to enable gopls and record what actions they took.
- await promptAboutGoplsOptOut(false);
+ await promptAboutGoplsOptOut();
// Check if the language server has now been enabled, and if so,
// it will be installed below.
cfg = buildLanguageServerConfig(getGoConfig());
@@ -285,7 +296,8 @@ function scheduleGoplsSuggestions() {
setTimeout(survey, 30 * timeMinute);
}
-export async function promptAboutGoplsOptOut(surveyOnly: boolean) {
+// Ask users to enable gopls. If they still don't want it, ask to fill out opt-out survey with the probability.
+export async function promptAboutGoplsOptOut(probability = 0.5) {
// Check if the configuration is set in the workspace.
const useLanguageServer = getGoConfig().inspect('useLanguageServer');
const workspace = useLanguageServer.workspaceFolderValue === false || useLanguageServer.workspaceValue === false;
@@ -300,14 +312,7 @@ export async function promptAboutGoplsOptOut(surveyOnly: boolean) {
return cfg;
}
cfg.lastDatePrompted = new Date();
- if (surveyOnly) {
- await promptForGoplsOptOutSurvey(
- cfg,
- `Looks like you've disabled the Go language server, which is the recommended default for this extension.
-Would you be willing to tell us why you've disabled it?`
- );
- return cfg;
- }
+
const selected = await vscode.window.showInformationMessage(
`We noticed that you have disabled the language server.
It has [stabilized](https://blog.golang.org/gopls-vscode-go) and is now enabled by default in this extension.
@@ -344,10 +349,12 @@ Would you like to enable it now?`,
break;
case 'Never':
cfg.prompt = false;
- await promptForGoplsOptOutSurvey(
- cfg,
- 'No problem. Would you be willing to tell us why you have opted out of the language server?'
- );
+ if (Math.random() < probability) {
+ await promptForGoplsOptOutSurvey(
+ cfg,
+ 'No problem. Would you be willing to tell us why you have opted out of the language server?'
+ );
+ }
break;
}
return cfg;
@@ -361,10 +368,8 @@ async function promptForGoplsOptOutSurvey(cfg: GoplsOptOutConfig, msg: string):
if (!s) {
return cfg;
}
- let goplsVersion = await getLocalGoplsVersion(latestConfig);
- if (!goplsVersion) {
- goplsVersion = 'na';
- }
+ const localGoplsVersion = await getLocalGoplsVersion(latestConfig);
+ const goplsVersion = localGoplsVersion?.version || 'na';
const goV = await getGoVersion();
let goVersion = 'na';
if (goV) {
@@ -451,9 +456,36 @@ async function startLanguageServer(ctx: vscode.ExtensionContext, config: Languag
languageServerDisposable = languageClient.start();
ctx.subscriptions.push(languageServerDisposable);
await languageClient.onReady();
+ serverInfo = toServerInfo(languageClient.initializeResult);
+
+ console.log(`Server: ${JSON.stringify(serverInfo, null, 2)}`);
return true;
}
+function toServerInfo(res?: InitializeResult): ServerInfo | undefined {
+ if (!res) return undefined;
+
+ const info: ServerInfo = {
+ Commands: res.capabilities?.executeCommandProvider?.commands || [],
+ Name: res.serverInfo?.name || 'unknown'
+ };
+
+ try {
+ interface serverVersionJSON {
+ GoVersion?: string;
+ Version?: string;
+ // before gopls 0.8.0
+ version?: string;
+ }
+ const v = (res.serverInfo?.version ? JSON.parse(res.serverInfo.version) : {});
+ info.Version = v.Version || v.version;
+ info.GoVersion = v.GoVersion;
+ } catch (e) {
+ // gopls is not providing any info, that's ok.
+ }
+ return info;
+}
+
export interface BuildLanguageClientOption extends LanguageServerConfig {
outputChannel?: vscode.OutputChannel;
traceOutputChannel?: vscode.OutputChannel;
@@ -483,7 +515,10 @@ function buildLanguageClientOption(cfg: LanguageServerConfig): BuildLanguageClie
// buildLanguageClient returns a language client built using the given language server config.
// The returned language client need to be started before use.
-export async function buildLanguageClient(cfg: BuildLanguageClientOption): Promise {
+export async function buildLanguageClient(cfg: BuildLanguageClientOption): Promise {
+ if (!cfg.enabled) {
+ return Promise.resolve(undefined);
+ }
const goplsWorkspaceConfig = await adjustGoplsWorkspaceConfiguration(cfg, getGoplsConfig(), 'gopls', undefined);
const documentSelector = [
@@ -666,25 +701,10 @@ export async function buildLanguageClient(cfg: BuildLanguageClientOption): Promi
item.filterText = hardcodedFilterText;
}
}
- // TODO(hyangah): when v1.42+ api is available, we can simplify
- // language-specific configuration lookup using the new
- // ConfigurationScope.
- // const paramHintsEnabled = vscode.workspace.getConfiguration(
- // 'editor.parameterHints',
- // { languageId: 'go', uri: document.uri });
- const editorParamHintsEnabled = vscode.workspace.getConfiguration(
- 'editor.parameterHints',
- document.uri
- )['enabled'];
- const goParamHintsEnabled = vscode.workspace.getConfiguration('[go]', document.uri)[
- 'editor.parameterHints.enabled'
- ];
- let paramHintsEnabled = false;
- if (typeof goParamHintsEnabled === 'undefined') {
- paramHintsEnabled = editorParamHintsEnabled;
- } else {
- paramHintsEnabled = goParamHintsEnabled;
- }
+ const paramHintsEnabled = vscode.workspace.getConfiguration('editor.parameterHints', {
+ languageId: 'go',
+ uri: document.uri
+ });
// If the user has parameterHints (signature help) enabled,
// trigger it for function or method completion items.
if (paramHintsEnabled) {
@@ -832,16 +852,7 @@ async function adjustGoplsWorkspaceConfiguration(
workspaceConfig = passGoConfigToGoplsConfigValues(workspaceConfig, getGoConfig(resource));
// Only modify the user's configurations for the Nightly.
- if (!isInPreviewMode()) {
- return workspaceConfig;
- }
- // allExperiments is only available with gopls/v0.5.2 and above.
- const version = await getLocalGoplsVersion(cfg);
- if (!version) {
- return workspaceConfig;
- }
- const sv = semver.parse(version, true);
- if (!sv || semver.lt(sv, 'v0.5.2')) {
+ if (!extensionInfo.isPreview) {
return workspaceConfig;
}
if (!workspaceConfig['allExperiments']) {
@@ -951,10 +962,6 @@ export async function watchLanguageServerConfiguration(e: vscode.ConfigurationCh
) {
restartLanguageServer('config change');
}
-
- if (e.affectsConfiguration('go.useLanguageServer') && getGoConfig()['useLanguageServer'] === false) {
- promptAboutGoplsOptOut(true);
- }
}
export function buildLanguageServerConfig(goConfig: vscode.WorkspaceConfiguration): LanguageServerConfig {
@@ -965,7 +972,7 @@ export function buildLanguageServerConfig(goConfig: vscode.WorkspaceConfiguratio
const cfg: LanguageServerConfig = {
serverName: '',
path: '',
- version: '', // compute version lazily
+ version: null, // compute version lazily
modtime: null,
enabled: goConfig['useLanguageServer'] === true,
flags: goConfig['languageServerFlags'] || [],
@@ -1065,26 +1072,32 @@ export async function shouldUpdateLanguageServer(
mustCheck?: boolean
): Promise {
// Only support updating gopls for now.
- if (tool.name !== 'gopls' || (!mustCheck && (cfg.checkForUpdates === 'off' || IsInCloudIDE))) {
+ if (tool.name !== 'gopls' || (!mustCheck && (cfg.checkForUpdates === 'off' || extensionInfo.isInCloudIDE))) {
return null;
}
if (!cfg.enabled) {
return null;
}
+ // If the Go version is too old, don't update.
+ const goVersion = await getGoVersion();
+ if (!goVersion || (tool.minimumGoVersion && goVersion.lt(tool.minimumGoVersion.format()))) {
+ return null;
+ }
+
// First, run the "gopls version" command and parse its results.
// TODO(rstambler): Confirm that the gopls binary's modtime matches the
// modtime in the config. Update it if needed.
const usersVersion = await getLocalGoplsVersion(cfg);
// We might have a developer version. Don't make the user update.
- if (usersVersion === '(devel)') {
+ if (usersVersion && usersVersion.version === '(devel)') {
return null;
}
// Get the latest gopls version. If it is for nightly, using the prereleased version is ok.
let latestVersion =
- cfg.checkForUpdates === 'local' ? tool.latestVersion : await latestToolVersion(tool, isInPreviewMode());
+ cfg.checkForUpdates === 'local' ? tool.latestVersion : await latestToolVersion(tool, extensionInfo.isPreview);
// If we failed to get the gopls version, pick the one we know to be latest at the time of this extension's last update
if (!latestVersion) {
@@ -1094,13 +1107,13 @@ export async function shouldUpdateLanguageServer(
// If "gopls" is so old that it doesn't have the "gopls version" command,
// or its version doesn't match our expectations, usersVersion will be empty or invalid.
// Suggest the latestVersion.
- if (!usersVersion || !semver.valid(usersVersion)) {
+ if (!usersVersion || !semver.valid(usersVersion.version)) {
return latestVersion;
}
// The user may have downloaded golang.org/x/tools/gopls@master,
// which means that they have a pseudoversion.
- const usersTime = parseTimestampFromPseudoversion(usersVersion);
+ const usersTime = parseTimestampFromPseudoversion(usersVersion.version);
// If the user has a pseudoversion, get the timestamp for the latest gopls version and compare.
if (usersTime) {
let latestTime = cfg.checkForUpdates
@@ -1114,7 +1127,7 @@ export async function shouldUpdateLanguageServer(
// If the user's version does not contain a timestamp,
// default to a semver comparison of the two versions.
- const usersVersionSemver = semver.parse(usersVersion, {
+ const usersVersionSemver = semver.parse(usersVersion.version, {
includePrerelease: true,
loose: true
});
@@ -1204,6 +1217,14 @@ export const getTimestampForVersion = async (tool: Tool, version: semver.SemVer)
return time;
};
+interface GoplsVersionOutput {
+ GoVersion: string;
+ Main: {
+ Path: string;
+ Version: string;
+ };
+}
+
// getLocalGoplsVersion returns the version of gopls that is currently
// installed on the user's machine. This is determined by running the
// `gopls version` command.
@@ -1213,17 +1234,31 @@ export const getLocalGoplsVersion = async (cfg: LanguageServerConfig) => {
if (!cfg) {
return null;
}
- if (cfg.version !== '') {
+ if (cfg.version) {
return cfg.version;
}
if (cfg.path === '') {
return null;
}
+ const env = toolExecutionEnvironment();
+ const cwd = getWorkspaceFolderPath();
+
const execFile = util.promisify(cp.execFile);
- let output: any;
try {
- const env = toolExecutionEnvironment();
- const cwd = getWorkspaceFolderPath();
+ const { stdout } = await execFile(cfg.path, ['version', '-json'], { env, cwd });
+
+ const v = JSON.parse(stdout);
+ if (v?.Main.Version) {
+ cfg.version = { version: v.Main.Version, goVersion: v.GoVersion };
+ return cfg.version;
+ }
+ } catch (e) {
+ // do nothing
+ }
+
+ // fall back to the old way (pre v0.8.0)
+ let output = '';
+ try {
const { stdout } = await execFile(cfg.path, ['version'], { env, cwd });
output = stdout;
} catch (e) {
@@ -1232,7 +1267,7 @@ export const getLocalGoplsVersion = async (cfg: LanguageServerConfig) => {
return null;
}
- const lines = output.trim().split('\n');
+ const lines = output.trim().split('\n');
switch (lines.length) {
case 0:
// No results, should update.
@@ -1272,7 +1307,7 @@ export const getLocalGoplsVersion = async (cfg: LanguageServerConfig) => {
//
// v0.1.3
//
- cfg.version = split[1];
+ cfg.version = { version: split[1] };
return cfg.version;
};
@@ -1405,7 +1440,6 @@ You will be asked to provide additional information and logs, so PLEASE READ THE
}
// Get the user's version in case the update prompt above failed.
const usersGoplsVersion = await getLocalGoplsVersion(latestConfig);
- const extInfo = getExtensionInfo();
const goVersion = await getGoVersion();
const settings = latestConfig.flags.join(' ');
const title = `gopls: automated issue report (${errKind})`;
@@ -1422,12 +1456,12 @@ Failed to auto-collect gopls trace: ${failureReason}.
const now = new Date();
const body = `
-gopls version: ${usersGoplsVersion}
+gopls version: ${usersGoplsVersion?.version} (${usersGoplsVersion?.goVersion})
gopls flags: ${settings}
update flags: ${latestConfig.checkForUpdates}
-extension version: ${extInfo.version}
+extension version: ${extensionInfo.version}
go version: ${goVersion?.format(true)}
-environment: ${extInfo.appName} ${process.platform}
+environment: ${extensionInfo.appName} ${process.platform}
initialization error: ${initializationError}
issue timestamp: ${now.toUTCString()}
restart history:
@@ -1601,24 +1635,3 @@ function languageServerUsingDefault(cfg: vscode.WorkspaceConfiguration): boolean
const useLanguageServer = cfg.inspect('useLanguageServer');
return useLanguageServer.globalValue === undefined && useLanguageServer.workspaceValue === undefined;
}
-
-interface ExtensionInfo {
- version?: string; // Extension version
- appName: string; // The application name of the editor, like 'VS Code'
- isPreview?: boolean; // if the extension runs in preview mode (e.g. Nightly)
-}
-
-function getExtensionInfo(): ExtensionInfo {
- const packageJSON = vscode.extensions.getExtension(extensionId)?.packageJSON;
- const version = packageJSON?.version;
- const appName = vscode.env.appName;
- const isPreview = !!packageJSON?.preview;
- return { version, appName, isPreview };
-}
-
-// isInPreviewMode returns true if the extension's preview mode is set to true.
-// In the Nightly extension and the dev extension built from master, the preview
-// is set to true.
-export function isInPreviewMode(): boolean {
- return getExtensionInfo().isPreview;
-}
diff --git a/src/goMain.ts b/src/goMain.ts
index 939b2d4c92..5aa45573ba 100644
--- a/src/goMain.ts
+++ b/src/goMain.ts
@@ -9,7 +9,7 @@
'use strict';
import * as path from 'path';
-import { getGoConfig, getGoplsConfig, IsInCloudIDE } from './config';
+import { extensionInfo, getGoConfig, getGoplsConfig } from './config';
import { browsePackages } from './goBrowsePackage';
import { buildCode } from './goBuild';
import { check, notifyIfGeneratedFile, removeTestStatus } from './goCheck';
@@ -38,6 +38,7 @@ import { implCursor } from './goImpl';
import { addImport, addImportToWorkspace } from './goImport';
import { installCurrentPackage } from './goInstall';
import {
+ inspectGoToolVersion,
installAllTools,
installTools,
offerToInstallTools,
@@ -45,7 +46,6 @@ import {
updateGoVarsFromConfig
} from './goInstallTools';
import {
- isInPreviewMode,
languageServerIsRunning,
RestartReason,
showServerOutputChannel,
@@ -71,7 +71,7 @@ import {
testPrevious,
testWorkspace
} from './goTest';
-import { getConfiguredTools } from './goTools';
+import { getConfiguredTools, Tool } from './goTools';
import { vetCode } from './goVet';
import { pickGoProcess, pickProcess } from './pickProcess';
import {
@@ -97,8 +97,7 @@ import {
GoVersion,
handleDiagnosticErrors,
isGoPathSet,
- resolvePath,
- runGoVersionM
+ resolvePath
} from './util';
import { clearCacheForTools, fileExists, getCurrentGoRoot, dirExists, envPath } from './utils/pathUtils';
import { WelcomePanel } from './welcome';
@@ -144,14 +143,8 @@ export async function activate(ctx: vscode.ExtensionContext): Promise {
suggestUpdates(ctx);
offerToInstallLatestGoVersion();
@@ -726,7 +716,7 @@ function showGoWelcomePage(ctx: vscode.ExtensionContext) {
// https://github.com/golang/vscode-go/issue/1179
let goExtensionVersion = '0.30.0';
let goExtensionVersionKey = 'go.extensionVersion';
- if (isInPreviewMode()) {
+ if (extensionInfo.isPreview) {
goExtensionVersion = '0.0.0';
goExtensionVersionKey = 'go.nightlyExtensionVersion';
}
@@ -754,44 +744,6 @@ export function shouldShowGoWelcomePage(showVersions: string[], newVersion: stri
return semver.gte(coercedNew, coercedOld) && showVersions.includes(coercedNew.toString());
}
-async function showGoNightlyWelcomeMessage() {
- const shown = getFromGlobalState(goNightlyPromptKey, false);
- if (shown === true) {
- return;
- }
- const prompt = async () => {
- const selected = await vscode.window.showInformationMessage(
- `Thank you for testing new features by using the Go Nightly extension!
-We'd like to welcome you to share feedback and/or join our community of Go Nightly users and developers.`,
- 'Share feedback',
- 'Community resources'
- );
- switch (selected) {
- case 'Share feedback':
- await vscode.env.openExternal(
- vscode.Uri.parse('https://github.com/golang/vscode-go/blob/master/docs/nightly.md#feedback')
- );
- break;
- case 'Community resources':
- await vscode.env.openExternal(
- vscode.Uri.parse('https://github.com/golang/vscode-go/blob/master/docs/nightly.md#community')
- );
- break;
- default:
- return;
- }
- // Only prompt again if the user clicked one of the buttons.
- // They may want to look at the other option.
- prompt();
- };
- prompt();
-
- // Update state to indicate that we've shown this message to the user.
- updateGlobalState(goNightlyPromptKey, true);
-}
-
-const goNightlyPromptKey = 'goNightlyPrompt';
-
export function deactivate() {
return Promise.all([
cancelRunningTests(),
@@ -876,10 +828,97 @@ function checkToolExists(tool: string) {
}
}
+// exported for testing
+export async function listOutdatedTools(configuredGoVersion: GoVersion, allTools: Tool[]): Promise {
+ if (!configuredGoVersion || !configuredGoVersion.sv) {
+ return [];
+ }
+
+ const { major, minor } = configuredGoVersion.sv;
+
+ const oldTools = await Promise.all(
+ allTools.map(async (tool) => {
+ const toolPath = getBinPath(tool.name);
+ if (!path.isAbsolute(toolPath)) {
+ return;
+ }
+ const m = await inspectGoToolVersion(toolPath);
+ if (!m) {
+ console.log(`failed to get go tool version: ${toolPath}`);
+ return;
+ }
+ const { goVersion } = m;
+ if (!goVersion) {
+ // TODO: we cannot tell whether the tool was compiled with a newer version of go
+ // or compiled in an unconventional way.
+ return;
+ }
+ const toolGoVersion = new GoVersion('', `go version ${goVersion} os/arch`);
+ if (!toolGoVersion || !toolGoVersion.sv) {
+ return tool;
+ }
+ if (
+ major > toolGoVersion.sv.major ||
+ (major === toolGoVersion.sv.major && minor > toolGoVersion.sv.minor)
+ ) {
+ return tool;
+ }
+ // special case: if the tool was compiled with beta or rc, and the current
+ // go version is a stable version, let's ask to recompile.
+ if (
+ major === toolGoVersion.sv.major &&
+ minor === toolGoVersion.sv.minor &&
+ (goVersion.includes('beta') || goVersion.includes('rc')) &&
+ // We assume tools compiled with different rc/beta need to be recompiled.
+ // We test the inequality by checking whether the exact beta or rc version
+ // appears in the `go version` output. e.g.,
+ // configuredGoVersion.version goVersion(tool) update
+ // 'go version go1.18 ...' 'go1.18beta1' Yes
+ // 'go version go1.18beta1 ...' 'go1.18beta1' No
+ // 'go version go1.18beta2 ...' 'go1.18beta1' Yes
+ // 'go version go1.18rc1 ...' 'go1.18beta1' Yes
+ // 'go version go1.18rc1 ...' 'go1.18' No
+ // 'go version devel go1.18-deadbeaf ...' 'go1.18beta1' No (* rare)
+ !configuredGoVersion.version.includes(goVersion)
+ ) {
+ return tool;
+ }
+ return;
+ })
+ );
+ return oldTools.filter((tool) => !!tool);
+}
+
async function suggestUpdates(ctx: vscode.ExtensionContext) {
- // TODO(hyangah): this is to clean up the unused key. Delete this code in 2021 Dec.
- if (ctx.globalState.get('toolsGoInfo')) {
- ctx.globalState.update('toolsGoInfo', null);
+ const configuredGoVersion = await getGoVersion();
+ if (!configuredGoVersion || configuredGoVersion.lt('1.12')) {
+ // User is using an ancient or a dev version of go. Don't suggest updates -
+ // user should know what they are doing.
+ return;
+ }
+
+ const allTools = getConfiguredTools(configuredGoVersion, getGoConfig(), getGoplsConfig());
+ const toolsToUpdate = await listOutdatedTools(configuredGoVersion, allTools);
+ if (toolsToUpdate.length === 0) {
+ return;
+ }
+
+ // If the user has opted in to automatic tool updates, we can update
+ // without prompting.
+ const toolsManagementConfig = getGoConfig()['toolsManagement'];
+ if (toolsManagementConfig && toolsManagementConfig['autoUpdate'] === true) {
+ installTools(toolsToUpdate, configuredGoVersion, true);
+ } else {
+ const updateToolsCmdText = 'Update tools';
+ const selected = await vscode.window.showWarningMessage(
+ `Tools (${toolsToUpdate.map((tool) => tool.name).join(', ')}) need recompiling to work with ${
+ configuredGoVersion.version
+ }`,
+ updateToolsCmdText
+ );
+ if (selected === updateToolsCmdText) {
+ installTools(toolsToUpdate, configuredGoVersion);
+ }
}
}
@@ -955,11 +994,11 @@ async function getConfiguredGoToolsCommand() {
if (goVersionTooOld) {
return `\t${tool.name}:\t${toolPath}: unknown version`;
}
- try {
- const out = await runGoVersionM(toolPath);
- return `\t${tool.name}:${out.replace(/^/gm, '\t')}`;
- } catch (e) {
- return `\t${tool.name}:\t${toolPath}: go version -m failed: ${e}`;
+ const { goVersion, moduleVersion, debugInfo } = await inspectGoToolVersion(toolPath);
+ if (goVersion || moduleVersion) {
+ return `\t${tool.name}:\t${toolPath}\t(version: ${moduleVersion} built with go: ${goVersion})`;
+ } else {
+ return `\t${tool.name}:\t${toolPath}\t(version: unknown - ${debugInfo})`;
}
})
);
@@ -1034,23 +1073,3 @@ export async function setGOROOTEnvVar(configGOROOT: string) {
delete process.env.GOROOT;
}
}
-
-async function checkAlternateTools(goConfig: vscode.WorkspaceConfiguration) {
- const alternateTools = goConfig ? goConfig['alternateTools'] : {};
- // TODO(hyangah): delete this check after 2022-03-01.
- if (alternateTools['dlv-dap']) {
- const msg = `The extension no longer requires a separate 'dlv-dap' binary but uses the 'dlv' binary.
-The "dlv-dap" property of the "go.alternateTools" setting will be ignored.
-Please use the "dlv" property if you need to override the default Go debugger.`;
-
- const selected = await vscode.window.showWarningMessage(msg, 'Open settings.json');
- if (selected === 'Open settings.json') {
- const { workspaceValue } = goConfig.inspect('alternateTools.dlv-dap');
- if (workspaceValue !== undefined) {
- vscode.commands.executeCommand('workbench.action.openWorkspaceSettingsFile');
- } else {
- vscode.commands.executeCommand('workbench.action.openSettingsJson');
- }
- }
- }
-}
diff --git a/src/goModules.ts b/src/goModules.ts
index 61c503c771..5e02282fe1 100644
--- a/src/goModules.ts
+++ b/src/goModules.ts
@@ -19,25 +19,24 @@ import { getBinPath, getGoVersion, getModuleCache, getWorkspaceFolderPath } from
import { envPath, fixDriveCasingInWindows, getCurrentGoRoot } from './utils/pathUtils';
export let GO111MODULE: string;
-async function runGoModEnv(folderPath: string): Promise {
+export async function runGoEnv(folderPath: string, envvars: string[]): Promise {
const goExecutable = getBinPath('go');
if (!goExecutable) {
console.warn(
`Failed to run "go env GOMOD" to find mod file as the "go" binary cannot be found in either GOROOT(${getCurrentGoRoot()}) or PATH(${envPath})`
);
- return;
+ return {};
}
const env = toolExecutionEnvironment();
GO111MODULE = env['GO111MODULE'];
return new Promise((resolve) => {
- cp.execFile(goExecutable, ['env', 'GOMOD'], { cwd: folderPath, env }, (err, stdout) => {
+ const args = ['env', '-json'].concat(envvars);
+ cp.execFile(goExecutable, args, { cwd: folderPath, env }, (err, stdout) => {
if (err) {
- console.warn(`Error when running go env GOMOD: ${err}`);
- return resolve('');
+ console.warn(`Error when running go env ${args}: ${err}`);
+ return resolve({});
}
- const [goMod] = stdout.split('\n');
- if (goMod === '/dev/null' || goMod === 'NUL') resolve('');
- else resolve(goMod);
+ resolve(JSON.parse(stdout));
});
});
}
@@ -65,7 +64,9 @@ export async function getModFolderPath(fileuri: vscode.Uri, isDir?: boolean): Pr
return;
}
- let goModEnvResult = await runGoModEnv(pkgPath);
+ const goModEnvJSON = await runGoEnv(pkgPath, ['GOMOD']);
+ let goModEnvResult =
+ goModEnvJSON['GOMOD'] === '/dev/null' || goModEnvJSON['GOMOD'] === 'NUL' ? '' : goModEnvJSON['GOMOD'];
if (goModEnvResult) {
goModEnvResult = path.dirname(goModEnvResult);
const goConfig = getGoConfig(fileuri);
diff --git a/src/goOutline.ts b/src/goOutline.ts
index 8c9a8f7c2b..da1f453b04 100644
--- a/src/goOutline.ts
+++ b/src/goOutline.ts
@@ -8,9 +8,11 @@
import cp = require('child_process');
import vscode = require('vscode');
+import { ExecuteCommandParams, ExecuteCommandRequest } from 'vscode-languageserver-protocol';
import { getGoConfig } from './config';
import { toolExecutionEnvironment } from './goEnv';
import { promptForMissingTool, promptForUpdatingTool } from './goInstallTools';
+import { languageClient, serverInfo } from './goLanguageServer';
import { getBinPath, getFileArchive, makeMemoizedByteOffsetConverter } from './util';
import { killProcess } from './utils/processUtils';
@@ -189,17 +191,81 @@ function convertToCodeSymbols(
return symbols;
}
+const GOPLS_LIST_IMPORTS = 'gopls.list_imports';
+
export class GoDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
constructor(private includeImports?: boolean) {}
- public provideDocumentSymbols(
+ public async provideDocumentSymbols(
document: vscode.TextDocument,
token: vscode.CancellationToken
- ): Thenable {
+ ): Promise {
if (typeof this.includeImports !== 'boolean') {
const gotoSymbolConfig = getGoConfig(document.uri)['gotoSymbol'];
this.includeImports = gotoSymbolConfig ? gotoSymbolConfig['includeImports'] : false;
}
+
+ // TODO(suzmue): Check the commands available instead of the version.
+ if (languageClient && serverInfo?.Commands?.includes(GOPLS_LIST_IMPORTS)) {
+ const symbols: vscode.DocumentSymbol[] = await vscode.commands.executeCommand(
+ 'vscode.executeDocumentSymbolProvider',
+ document.uri
+ );
+ if (!symbols || symbols.length === 0) {
+ return [];
+ }
+
+ // Stitch the results together to make the results look like
+ // go-outline.
+ let pkgDeclRng = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 0));
+ let pkgName = '';
+
+ // Try to find the package statement.
+ const text = document.getText();
+ const packageStatement = new RegExp('^[ \\t]*package[ \\t]*(\\S+)', 'm');
+ const match = packageStatement.exec(text);
+ if (match && match.length === 2) {
+ const packageDecl = match[0];
+ const start = text.indexOf(packageDecl);
+ pkgDeclRng = new vscode.Range(
+ document.positionAt(start),
+ document.positionAt(start + packageDecl.length)
+ );
+ pkgName = packageDecl[1];
+ }
+ const packageSymbol = new vscode.DocumentSymbol(
+ pkgName,
+ 'package',
+ vscode.SymbolKind.Package,
+ pkgDeclRng,
+ pkgDeclRng
+ );
+ packageSymbol.children = symbols;
+ if (this.includeImports) {
+ try {
+ const imports = await listImports(document);
+ imports?.forEach((value) => {
+ packageSymbol.children.unshift(
+ new vscode.DocumentSymbol(
+ value.Path,
+ 'import',
+ vscode.SymbolKind.Namespace,
+ new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 0)),
+ new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 0))
+ )
+ );
+ });
+ } catch (e) {
+ // Fall back to use go-outline.
+ return this.runGoOutline(document, token);
+ }
+ }
+ return [packageSymbol];
+ }
+ return this.runGoOutline(document, token);
+ }
+
+ private runGoOutline(document: vscode.TextDocument, token: vscode.CancellationToken) {
const options: GoOutlineOptions = {
fileName: document.fileName,
document,
@@ -208,3 +274,17 @@ export class GoDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
return documentSymbols(options, token);
}
}
+
+async function listImports(document: vscode.TextDocument): Promise<{ Path: string; Name: string }[]> {
+ const uri = languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document).uri;
+ const params: ExecuteCommandParams = {
+ command: GOPLS_LIST_IMPORTS,
+ arguments: [
+ {
+ URI: uri
+ }
+ ]
+ };
+ const resp = await languageClient.sendRequest(ExecuteCommandRequest.type, params);
+ return resp.Imports;
+}
diff --git a/src/goPackages.ts b/src/goPackages.ts
index 589644be4a..af221da75b 100644
--- a/src/goPackages.ts
+++ b/src/goPackages.ts
@@ -7,13 +7,13 @@
import cp = require('child_process');
import path = require('path');
+import { promisify } from 'util';
import vscode = require('vscode');
import { toolExecutionEnvironment } from './goEnv';
-import { promptForMissingTool, promptForUpdatingTool } from './goInstallTools';
-import { getBinPath, getCurrentGoPath, isVendorSupported } from './util';
+import { getBinPath, getCurrentGoPath } from './util';
import { envPath, fixDriveCasingInWindows, getCurrentGoRoot, getCurrentGoWorkspaceFromGOPATH } from './utils/pathUtils';
-type GopkgsDone = (res: Map) => void;
+type GoListPkgsDone = (res: Map) => void;
interface Cache {
entry: Map;
lastHit: number;
@@ -24,91 +24,83 @@ export interface PackageInfo {
isStd: boolean;
}
-let gopkgsNotified = false;
+let goListPkgsNotified = false;
let cacheTimeout = 5000;
-const gopkgsSubscriptions: Map = new Map();
-const gopkgsRunning: Set = new Set();
+const goListPkgsSubscriptions: Map = new Map();
+const goListPkgsRunning: Set = new Set();
const allPkgsCache: Map = new Map();
const pkgRootDirs = new Map();
-function gopkgs(workDir?: string): Promise