Updated vim-go to v1.24
This commit is contained in:
parent
35a4e11c1a
commit
075a943af7
106 changed files with 6983 additions and 1637 deletions
|
@ -4,3 +4,5 @@
|
||||||
.dlv/
|
.dlv/
|
||||||
.git/
|
.git/
|
||||||
.viminfo
|
.viminfo
|
||||||
|
issues/
|
||||||
|
autoload/go/**/pkg/
|
||||||
|
|
1
pack/acp/start/vim-go/.github/FUNDING.yml
vendored
Normal file
1
pack/acp/start/vim-go/.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
patreon: bhcleek
|
42
pack/acp/start/vim-go/.github/ISSUE_TEMPLATE.md
vendored
42
pack/acp/start/vim-go/.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,21 +1,47 @@
|
||||||
### What did you do? (required. The issue will be **closed** when not provided.)
|
<!--
|
||||||
|
Before filing an issue, please check if vim-go's help addresses your problem (see `:help go-troubleshooting`).
|
||||||
|
|
||||||
|
Consider executing `:GoReportGitHubIssue` to populate much of this information automatically.
|
||||||
|
-->
|
||||||
|
### What did you do? (required: The issue will be **closed** when not provided)
|
||||||
|
|
||||||
|
<!--
|
||||||
|
If possible, please provide clear steps for reproducing the problem.
|
||||||
|
-->
|
||||||
|
|
||||||
### What did you expect to happen?
|
### What did you expect to happen?
|
||||||
|
|
||||||
|
|
||||||
### What happened instead?
|
### What happened instead?
|
||||||
|
|
||||||
|
|
||||||
### Configuration (**MUST** fill this out):
|
### Configuration (**MUST** fill this out):
|
||||||
|
|
||||||
* vim-go version:
|
#### vim-go version:
|
||||||
|
|
||||||
* `vimrc` you used to reproduce (use a *minimal* vimrc with other plugins disabled; do not link to a 2,000 line vimrc):
|
#### `vimrc` you used to reproduce:
|
||||||
|
<!--
|
||||||
|
Use a *minimal* vimrc with other plugins disabled; do not link to a 2,000 line vimrc.
|
||||||
|
|
||||||
* Vim version (first three lines from `:version`):
|
If this is not provided or is obviously incomplete, the issue may be unceremoniously closed.
|
||||||
|
-->
|
||||||
|
<!-- vimrc -->
|
||||||
|
<details><summary>vimrc</summary><br><pre>
|
||||||
|
|
||||||
* Go version (`go version`):
|
</pre></details>
|
||||||
|
|
||||||
* Go environment (`go env`):
|
#### Vim version (first three lines from `:version`):
|
||||||
|
<!-- :version -->
|
||||||
|
|
||||||
|
#### Go version (`go version`):
|
||||||
|
<!-- go version -->
|
||||||
|
|
||||||
|
#### Go environment
|
||||||
|
<details><summary><code>go env</code> Output:</summary><br><pre>
|
||||||
|
<!-- go env -->
|
||||||
|
|
||||||
|
</pre></details>
|
||||||
|
|
||||||
|
#### gopls version
|
||||||
|
<details><summary><code>gopls version</code> Output:</summary><br><pre>
|
||||||
|
<!-- gopls version -->
|
||||||
|
|
||||||
|
</pre></details>
|
||||||
|
|
60
pack/acp/start/vim-go/.github/workflows/test.yml
vendored
Normal file
60
pack/acp/start/vim-go/.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
name: test
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: lint
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: set up python
|
||||||
|
uses: actions/setup-python@v1.2.0
|
||||||
|
with:
|
||||||
|
python-version: 3.6
|
||||||
|
- name: install vim-vint
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install vim-vint pathlib
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v2.1.0
|
||||||
|
- name: install vim
|
||||||
|
run: $GITHUB_WORKSPACE/scripts/install-vim vim-8.2
|
||||||
|
- name: install tools
|
||||||
|
run: $GITHUB_WORKSPACE/scripts/install-tools vim-8.2
|
||||||
|
- name: lint
|
||||||
|
run: $GITHUB_WORKSPACE/scripts/lint vim-8.2
|
||||||
|
test:
|
||||||
|
name: test
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
go: ['1.14','1.15']
|
||||||
|
vim: ['vim-8.0', 'vim-8.2', 'nvim']
|
||||||
|
steps:
|
||||||
|
- name: setup Go
|
||||||
|
uses: actions/setup-go@v2.0.3
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go }}
|
||||||
|
- name: set up python
|
||||||
|
uses: actions/setup-python@v1.2.0
|
||||||
|
with:
|
||||||
|
python-version: 3.6
|
||||||
|
- name: install covimerage
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install covimerage==0.2.1 codecov pathlib
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v2.1.0
|
||||||
|
- name: install vim
|
||||||
|
run: $GITHUB_WORKSPACE/scripts/install-vim ${{ matrix.vim }}
|
||||||
|
- name: install tools
|
||||||
|
run: $GITHUB_WORKSPACE/scripts/install-tools ${{ matrix.vim }}
|
||||||
|
- name: test
|
||||||
|
run: $GITHUB_WORKSPACE/scripts/test -c ${{ matrix.vim }}
|
||||||
|
- uses: codecov/codecov-action@v1
|
||||||
|
with:
|
||||||
|
# token is not required for public repos
|
||||||
|
#token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
file: $GITHUB_WORKSPACE/coverage.xml
|
||||||
|
flags: unittests
|
||||||
|
name: vim-go
|
||||||
|
fail_ci_if_error: false
|
14
pack/acp/start/vim-go/.gitignore
vendored
14
pack/acp/start/vim-go/.gitignore
vendored
|
@ -1,5 +1,11 @@
|
||||||
.DS_Store
|
|
||||||
/doc/tags
|
|
||||||
/.coverage.covimerage
|
|
||||||
/coverage.xml
|
|
||||||
*.pyc
|
*.pyc
|
||||||
|
.DS_Store
|
||||||
|
/.bash_history
|
||||||
|
/.cache
|
||||||
|
/.config
|
||||||
|
/.coverage.covimerage
|
||||||
|
/.local
|
||||||
|
/.viminfo
|
||||||
|
/coverage.xml
|
||||||
|
/doc/tags
|
||||||
|
/issues
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- 1.12.1
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- env: SCRIPT="test -c" VIM_VERSION=vim-7.4
|
|
||||||
- env: SCRIPT="test -c" VIM_VERSION=vim-8.0
|
|
||||||
- env: SCRIPT="test -c" VIM_VERSION=nvim
|
|
||||||
- env: ENV=vimlint SCRIPT=lint VIM_VERSION=vim-8.0
|
|
||||||
language: python
|
|
||||||
python: 3.6
|
|
||||||
install:
|
|
||||||
- ./scripts/install-vim $VIM_VERSION
|
|
||||||
- |
|
|
||||||
if [ "$ENV" = "vimlint" ]; then
|
|
||||||
pip install vim-vint covimerage codecov pathlib
|
|
||||||
else
|
|
||||||
pip install --user vim-vint covimerage codecov pathlib
|
|
||||||
fi
|
|
||||||
script:
|
|
||||||
- ./scripts/$SCRIPT $VIM_VERSION
|
|
|
@ -1,5 +1,529 @@
|
||||||
## unplanned
|
## unplanned
|
||||||
|
|
||||||
|
## v1.24 - (September 15, 2020)
|
||||||
|
|
||||||
|
IMPROVEMENTS:
|
||||||
|
* Clarify how `g:go_imports_autosave` and `g:go_fmt_autosave` interact.
|
||||||
|
[[GH-2893]](https://github.com/fatih/vim-go/pull/2893)
|
||||||
|
* Document what the working directory will be for `:GoRun`.
|
||||||
|
[[GH-2898]](https://github.com/fatih/vim-go/pull/2898)
|
||||||
|
* Add Ultisnip snippet for wrapping errors.
|
||||||
|
[[GH-2883]](https://github.com/fatih/vim-go/pull/2883)
|
||||||
|
* Beautify the godoc pop up window border.
|
||||||
|
[[GH-2900]](https://github.com/fatih/vim-go/pull/2900)
|
||||||
|
* Default `g:go_doc_url` to https://pkg.go.dev.
|
||||||
|
[[GH-2884]](https://github.com/fatih/vim-go/pull/2884)
|
||||||
|
* Default `g:go_gopls_options` to `[-remote=auto]` to share gopls instances
|
||||||
|
with other plugins and multiple instances of Vim.
|
||||||
|
[[GH-2905]](https://github.com/fatih/vim-go/pull/2905)
|
||||||
|
* Use the module root as the working directory when renaming so that all
|
||||||
|
references to the symbol will be renamed when in module aware mode and
|
||||||
|
`g:go_rename_command` is set to `gopls`.
|
||||||
|
[[GH-2917]](https://github.com/fatih/vim-go/pull/2917)
|
||||||
|
* Change `g:go_rename_command`'s default to `gopls`.
|
||||||
|
[[GH-2922]](https://github.com/fatih/vim-go/pull/2922)
|
||||||
|
* Do not send unnecessary textDocument/didChange notifications to `gopls`.
|
||||||
|
[[GH-2902]](https://github.com/fatih/vim-go/pull/2902)
|
||||||
|
[[GH-2930]](https://github.com/fatih/vim-go/pull/2930)
|
||||||
|
* Stop the debugger when the process being debugged exits.
|
||||||
|
[[GH-2921]](https://github.com/fatih/vim-go/pull/2921)
|
||||||
|
* Use the module package cache as a source of packages candidates when trying
|
||||||
|
to complete package names.
|
||||||
|
[[GH-2936]](https://github.com/fatih/vim-go/pull/2936)
|
||||||
|
[[GH-2939]](https://github.com/fatih/vim-go/pull/2939)
|
||||||
|
* Allow interaction with Vim while waiting for a breakpoint to be hit while
|
||||||
|
debugging.
|
||||||
|
[[GH-2932]](https://github.com/fatih/vim-go/pull/2932)
|
||||||
|
* Refactor Vim signs used for debugging breakpoints to avoid id collision with
|
||||||
|
other plugins.
|
||||||
|
[[GH-2943]](https://github.com/fatih/vim-go/pull/2943)
|
||||||
|
* Refactor debugger's rpc response handling to be asynchronous so that Vim will
|
||||||
|
be responsive while the program being debugged is executing.
|
||||||
|
[[GH-2948]](https://github.com/fatih/vim-go/pull/2948)
|
||||||
|
[[GH-2952]](https://github.com/fatih/vim-go/pull/2952)
|
||||||
|
* Warn when the debugger breaks in a file that has changed since debugging started.
|
||||||
|
[[GH-2950]](https://github.com/fatih/vim-go/pull/2950)
|
||||||
|
* Enable `go-run` mappings that use the terminal to work with Vim in addition to Neovim.
|
||||||
|
[[GH-2956]](https://github.com/fatih/vim-go/pull/2956)
|
||||||
|
* Use existing diagnostics for the file when the file hasn't changed and
|
||||||
|
`g:go_metalinter_command` is `gopls`.
|
||||||
|
[[GH-2960]](https://github.com/fatih/vim-go/pull/2960)
|
||||||
|
* Add a new option, `g:go_code_completion_icase`, to allow ignoring case when
|
||||||
|
filtering completion results.
|
||||||
|
[[GH-2961]](https://github.com/fatih/vim-go/pull/2961)
|
||||||
|
* Make sure tools are not cross-compiled with `:GoInstallBinaries` and
|
||||||
|
`:GoUpdateBinaries`.
|
||||||
|
[[GH-2982]](https://github.com/fatih/vim-go/pull/2982)
|
||||||
|
[[GH-2988]](https://github.com/fatih/vim-go/pull/2988)
|
||||||
|
* Add `:GoDebugHalt` to allow a program being debugged to be paused before it
|
||||||
|
hits a breakpoint.
|
||||||
|
[[GH-2983]](https://github.com/fatih/vim-go/pull/2983)
|
||||||
|
* Clear highlighting of the current line when after resuming when debugging.
|
||||||
|
[[GH-2984]](https://github.com/fatih/vim-go/pull/2984)
|
||||||
|
* Add `:GoDebugAttach` to debug a running process.
|
||||||
|
[[GH-2989]](https://github.com/fatih/vim-go/pull/2989)
|
||||||
|
* Add `g:go_term_reuse` option to allow the reuse of a terminal window.
|
||||||
|
[[GH-2990]](https://github.com/fatih/vim-go/pull/2990)
|
||||||
|
* Add official support for using `gopls`' `gofumpt` workspace setting via
|
||||||
|
`g:go_gopls_gofumpt`.
|
||||||
|
[[GH-2994]](https://github.com/fatih/vim-go/pull/2994)
|
||||||
|
[[GH-3005]](https://github.com/fatih/vim-go/pull/3005)
|
||||||
|
* Add support for using `gopls`' workspace settings that are otherwise not yet
|
||||||
|
officially supported by vim-go.
|
||||||
|
[[GH-2994]](https://github.com/fatih/vim-go/pull/2994)
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
* Fix call to non-existent function in terminal mode edge case.
|
||||||
|
[[GH-2895]](https://github.com/fatih/vim-go/pull/2895)
|
||||||
|
* Do not show errors when adding a text property for highlighting fails.
|
||||||
|
[[GH-2892]](https://github.com/fatih/vim-go/pull/2892)
|
||||||
|
* Include `errcheck` in `g:go_metalinter_enabled`'s default.
|
||||||
|
[[GH-2903]](https://github.com/fatih/vim-go/pull/2903)
|
||||||
|
* Fix display of completion selection information on command-line when
|
||||||
|
`g:go_echo_go_info` is enabled.
|
||||||
|
[[GH-2907]](https://github.com/fatih/vim-go/pull/2907)
|
||||||
|
* Prevent `:GoDebugBreakpoint` from causing delve to exit.
|
||||||
|
[[GH-2908]](https://github.com/fatih/vim-go/pull/2908)
|
||||||
|
* Use the resolved directory name for `gopls`' working directory when `go.mod`
|
||||||
|
is in a symlinked path.
|
||||||
|
[[GH-2913]](https://github.com/fatih/vim-go/pull/2913)
|
||||||
|
* Fix buffer reuse with `:GoDef`.
|
||||||
|
[[GH-2928]](https://github.com/fatih/vim-go/pull/2928)
|
||||||
|
* Handle breakpoints that are already set before calling `:GoDebugStart` or
|
||||||
|
`:GoDebugTest` in some locales that cause the `sign place` output to vary.
|
||||||
|
[[GH-2921]](https://github.com/fatih/vim-go/pull/2921)
|
||||||
|
* Handle diagnostic errors at the end of a .go file.
|
||||||
|
[[GH-2942]](https://github.com/fatih/vim-go/pull/2942)
|
||||||
|
* Fix the `go-implements` mapping to use respect `g:go_implements_mode`.
|
||||||
|
[[GH-2944]](https://github.com/fatih/vim-go/pull/2944)
|
||||||
|
* Handle null results from `gopls` when getting definitions or type definitions
|
||||||
|
from virtual files.
|
||||||
|
[[GH-2951]](https://github.com/fatih/vim-go/pull/2951)
|
||||||
|
* Fix warning when Neovim is older than v0.4.0.
|
||||||
|
[[GH-2959]](https://github.com/fatih/vim-go/pull/2959)
|
||||||
|
* Correct documentation that referred to `g:go_imports_command` to refer to
|
||||||
|
`g:go_imports_mode` instead.
|
||||||
|
[[GH-2969]](https://github.com/fatih/vim-go/pull/2969)
|
||||||
|
* Remove reference to gocode in error message when `g:go_info_mode` is set to
|
||||||
|
an unsupported value.
|
||||||
|
[[GH-2978]](https://github.com/fatih/vim-go/pull/2978)
|
||||||
|
* Make sure debugging commands are configured when debugging a second time
|
||||||
|
within a single Vim session.
|
||||||
|
[[GH-2985]](https://github.com/fatih/vim-go/pull/2985)
|
||||||
|
* Correct documentation in for `:GoModifyTags` when adding a specific tag
|
||||||
|
value.
|
||||||
|
[[GH-3001]](https://github.com/fatih/vim-go/pull/3001)
|
||||||
|
* Fix the path given to `gopls` when `let g:go_metalinter='gopls'` and
|
||||||
|
`:GoMetaLinter` is called without any arguments.
|
||||||
|
[[GH-2992]](https://github.com/fatih/vim-go/pull/2992)
|
||||||
|
* Do not override a user's configuration for `GoDebugBreakpoint` or
|
||||||
|
`GoDebugCurrent` highlight groups.
|
||||||
|
[[GH-2998]](https://github.com/fatih/vim-go/pull/2998)
|
||||||
|
* Apply `gopls` text edits correctly that insert solitary newlines.
|
||||||
|
[[GH-3000]](https://github.com/fatih/vim-go/pull/3000)
|
||||||
|
|
||||||
|
## v1.23 - (May 16, 2020)
|
||||||
|
|
||||||
|
BACKWARDS INCOMPATIBILITIES:
|
||||||
|
* Remove support for gocode.
|
||||||
|
[[GH-2686]](https://github.com/fatih/vim-go/pull/2686)
|
||||||
|
* Require at least Neovim >= 0.4.0
|
||||||
|
[[GH-2853]](https://github.com/fatih/vim-go/pull/2853)
|
||||||
|
[[GH-2856]](https://github.com/fatih/vim-go/pull/2856)
|
||||||
|
[[GH-2863]](https://github.com/fatih/vim-go/pull/2863)
|
||||||
|
|
||||||
|
IMPROVEMENTS:
|
||||||
|
* Make signs for breakpoints configurable.
|
||||||
|
[[GH-2676]](https://github.com/fatih/vim-go/pull/2676)
|
||||||
|
[[GH-2690]](https://github.com/fatih/vim-go/pull/2690)
|
||||||
|
* Enable g:go_gopls_complete_unimported by default to stay aligned with gopls' defaults.
|
||||||
|
[[GH-2695]](https://github.com/fatih/vim-go/pull/2695)
|
||||||
|
* Document mappings that were recently added.
|
||||||
|
[[GH-2699]](https://github.com/fatih/vim-go/pull/2699)
|
||||||
|
* Handle null arrays better in gopls responses.
|
||||||
|
[[GH-2703]](https://github.com/fatih/vim-go/pull/2703)
|
||||||
|
* Use `gopls` defaults by default when they're not otherwise specified in vim-go options.
|
||||||
|
[[GH-2696]](https://github.com/fatih/vim-go/pull/2696)
|
||||||
|
* Add support for `gomodifytags --skip-unexported`
|
||||||
|
[[GH-2660]](https://github.com/fatih/vim-go/pull/2660)
|
||||||
|
* Show problems that prevent golangci-lint from running linters.
|
||||||
|
[[GH-2706]](https://github.com/fatih/vim-go/pull/2706)
|
||||||
|
[[GH-2720]](https://github.com/fatih/vim-go/pull/2720)
|
||||||
|
* Support golangci-lint config file by not using `--disable-all` when
|
||||||
|
`g:go_metalinter_enable` or `g:go_metalinter_autosave_enabled` is set to an
|
||||||
|
empty array.
|
||||||
|
[[GH-2655]](https://github.com/fatih/vim-go/pull/2655)
|
||||||
|
[[GH-2715]](https://github.com/fatih/vim-go/pull/2715)
|
||||||
|
* Add support for Vim8 terminals.
|
||||||
|
[[GH-2639]](https://github.com/fatih/vim-go/pull/2639)
|
||||||
|
[[GH-2736]](https://github.com/fatih/vim-go/pull/2736)
|
||||||
|
* Replace `g:go_gopls_fuzzy_matching` with `g:go_gopls_matcher` in response to
|
||||||
|
`gopls` deprecation of its `fuzzyMatching` option.
|
||||||
|
[[GH-2728]](https://github.com/fatih/vim-go/pull/2728)
|
||||||
|
* Set statuses and progress messages consistently for code quality tools.
|
||||||
|
[[GH-2727]](https://github.com/fatih/vim-go/pull/2727)
|
||||||
|
* Add a new supported value to `g:go_fmt_command` to format with `gopls`.
|
||||||
|
[[GH-2729]](https://github.com/fatih/vim-go/pull/2729)
|
||||||
|
[[GH-2752]](https://github.com/fatih/vim-go/pull/2752)
|
||||||
|
[[GH-2852]](https://github.com/fatih/vim-go/pull/2852)
|
||||||
|
* Handle changes to `go test -v` output.
|
||||||
|
[[GH-2743]](https://github.com/fatih/vim-go/pull/2743)
|
||||||
|
* Add `g:go_gopls_mod_tempfile` to configure `gopls`' `tempModfile`
|
||||||
|
configuration.
|
||||||
|
[[GH-2747]](https://github.com/fatih/vim-go/pull/2747)
|
||||||
|
* Add `g:go_gopls_options` to configure `gopls`' commandline options.
|
||||||
|
[[GH-2747]](https://github.com/fatih/vim-go/pull/2747)
|
||||||
|
* Improve readability of gopls logs.
|
||||||
|
[[GH-2773]](https://github.com/fatih/vim-go/pull/2773)
|
||||||
|
* Introduce `g:go_implements_mode` to allow `:GoImplements` to be satisfied
|
||||||
|
with `gopls`.
|
||||||
|
[[GH-2741]](https://github.com/fatih/vim-go/pull/2741)
|
||||||
|
[[GH-2799]](https://github.com/fatih/vim-go/pull/2799)
|
||||||
|
* Introduce `g:go_imports_mode` to allow `:GoImports` to be satisfied with
|
||||||
|
`gopls`.
|
||||||
|
[[GH-2791]](https://github.com/fatih/vim-go/pull/2791)
|
||||||
|
[[GH-2794]](https://github.com/fatih/vim-go/pull/2794)
|
||||||
|
[[GH-2796]](https://github.com/fatih/vim-go/pull/2796)
|
||||||
|
[[GH-2848]](https://github.com/fatih/vim-go/pull/2848)
|
||||||
|
* Send LSP synchronization messages to `gopls` when the file does not yet exist
|
||||||
|
on disk as long as its directory exists.
|
||||||
|
[[GH-2805]](https://github.com/fatih/vim-go/pull/2805)
|
||||||
|
* Run `gogetdoc` in the buffer's directory so that it will work regardless of
|
||||||
|
the user's working directory in module-aware mode.
|
||||||
|
[[GH-2804]](https://github.com/fatih/vim-go/pull/2804)
|
||||||
|
* Add `g:go_gopls_analyses` to support `gopls`' analyses options.
|
||||||
|
[[GH-2820]](https://github.com/fatih/vim-go/pull/2820)
|
||||||
|
* Add `g:go_gopls_local` to support `gopls`' local option to control how third
|
||||||
|
party imports are organized.
|
||||||
|
[[GH-2821]](https://github.com/fatih/vim-go/pull/2821)
|
||||||
|
* Use gopls to get documentation and documentation links for identifiers under
|
||||||
|
the cursor.
|
||||||
|
[[GH-2822]](https://github.com/fatih/vim-go/pull/2822)
|
||||||
|
[[GH-2839]](https://github.com/fatih/vim-go/pull/2839)
|
||||||
|
* Clarify documentation for terminal options.
|
||||||
|
[[GH-2843]](https://github.com/fatih/vim-go/pull/2843)
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
* Use the discovered full path for gopls when renaming.
|
||||||
|
[[GH-2692]](https://github.com/fatih/vim-go/pull/2692)
|
||||||
|
* Execute commands correctly on windows when `'shell'` is not cmd.exe
|
||||||
|
[[GH-2713]](https://github.com/fatih/vim-go/pull/2713)
|
||||||
|
[[GH-2724]](https://github.com/fatih/vim-go/pull/2724)
|
||||||
|
* Always execute `errcheck` in the current package's directory.
|
||||||
|
[[GH-2726]](https://github.com/fatih/vim-go/pull/2726)
|
||||||
|
* Fix errors when highlighting diagnostics after a `:GoImports`.
|
||||||
|
[[GH-2746]](https://github.com/fatih/vim-go/pull/2746)
|
||||||
|
* Preserve errors from formatting when both formatting and metalinting happen
|
||||||
|
on save.
|
||||||
|
[[GH-2733]](https://github.com/fatih/vim-go/pull/2733)
|
||||||
|
[[GH-2810]](https://github.com/fatih/vim-go/pull/2810)
|
||||||
|
* Preserve ordering of gopls messages in the log.
|
||||||
|
[[GH-2753]](https://github.com/fatih/vim-go/pull/2753)
|
||||||
|
* Fix `:GoDef` on windows when `g:go_def_mode` is set to `gopls`.
|
||||||
|
[[GH-2768]](https://github.com/fatih/vim-go/pull/2768)
|
||||||
|
* Handle null values from `gopls`.
|
||||||
|
[[GH-2778]](https://github.com/fatih/vim-go/pull/2778)
|
||||||
|
* Preserve diagnostics highlights after formatting.
|
||||||
|
[[GH-2779]](https://github.com/fatih/vim-go/pull/2779)
|
||||||
|
* Fix the decoding and encoding of multi-byte file paths received from and sent
|
||||||
|
to `gopls`.
|
||||||
|
[[GH-2784]](https://github.com/fatih/vim-go/pull/2784)
|
||||||
|
* Fix `:GoRun` so that it works as expected when the current working directory
|
||||||
|
is neither in GOPATH nor within a module.
|
||||||
|
[[GH-2782]](https://github.com/fatih/vim-go/pull/2782)
|
||||||
|
[[GH-2818]](https://github.com/fatih/vim-go/pull/2818)
|
||||||
|
[[GH-2842]](https://github.com/fatih/vim-go/pull/2842)
|
||||||
|
* Use absolute file paths for `:GoRun`'s arguments in terminal mode.
|
||||||
|
[[GH-2844]](https://github.com/fatih/vim-go/pull/2844)
|
||||||
|
* Show the command executed by `:GoRun` when `g:go_debug` includes `'shell-commands'`.
|
||||||
|
[[GH-2785]](https://github.com/fatih/vim-go/pull/2785)
|
||||||
|
[[GH-2817]](https://github.com/fatih/vim-go/pull/2817)
|
||||||
|
* Clear the list for formatting errors when `g:go_fmt_command` is `gopls`.
|
||||||
|
[[GH-2790]](https://github.com/fatih/vim-go/pull/2790)
|
||||||
|
* Handle text edits from gopls that are only line insertions.
|
||||||
|
[[GH-2802]](https://github.com/fatih/vim-go/pull/2802)
|
||||||
|
[[GH-2803]](https://github.com/fatih/vim-go/pull/2803)
|
||||||
|
* Add `g:go_imports_autosave` so that imports can be adjusted on save when
|
||||||
|
`g:go_imports_mode` is set to `gopls`.
|
||||||
|
[[GH-2800]](https://github.com/fatih/vim-go/pull/2800)
|
||||||
|
[[GH-2858]](https://github.com/fatih/vim-go/pull/2858)
|
||||||
|
* Correct vim-go's help to correctly identify `g:go_referrer_mode`'s default.
|
||||||
|
[[GH-2832]](https://github.com/fatih/vim-go/pull/2832)
|
||||||
|
* Clear the quickfix list when `:GoLint` succeeds.
|
||||||
|
[[GH-2833]](https://github.com/fatih/vim-go/pull/2833)
|
||||||
|
* Respect arguments to `:GoDocBrowser`.
|
||||||
|
[[GH-2822]](https://github.com/fatih/vim-go/pull/2822)
|
||||||
|
* Use the correct path to documentation for struct fields with `:GoDocBrowser`.
|
||||||
|
[[GH-2822]](https://github.com/fatih/vim-go/pull/2822)
|
||||||
|
* Do not try parsing errors from terminal jobs when the working directory has
|
||||||
|
been removed.
|
||||||
|
[[GH-2824]](https://github.com/fatih/vim-go/pull/2824)
|
||||||
|
* Document that `g:go_jump_to_error` apples to running the metalinter on save,
|
||||||
|
too.
|
||||||
|
[[GH-2854]](https://github.com/fatih/vim-go/pull/2854)
|
||||||
|
* Ignore commented out import statements when executing `:GoImport`.
|
||||||
|
[[GH-2862]](https://github.com/fatih/vim-go/pull/2862)
|
||||||
|
* Interpret file paths in `go vet` errors relative to the current buffer's
|
||||||
|
directory.
|
||||||
|
[[GH-2882]](https://github.com/fatih/vim-go/pull/2882)
|
||||||
|
|
||||||
|
## v1.22 - (January 30, 2020)
|
||||||
|
|
||||||
|
BACKWARDS INCOMPATIBILITIES:
|
||||||
|
* Drop support for Vim 7.4. The minimum required version of Vim is now 8.0.1453.
|
||||||
|
[[GH-2495]](https://github.com/fatih/vim-go/pull/2495)
|
||||||
|
[[GH-2497]](https://github.com/fatih/vim-go/pull/2497)
|
||||||
|
* Drop support for `gometalinter`
|
||||||
|
[[GH-2494]](https://github.com/fatih/vim-go/pull/2494)
|
||||||
|
|
||||||
|
IMPROVEMENTS:
|
||||||
|
* Highlight the `go` keyword in go.mod files.
|
||||||
|
[[GH-2473]](https://github.com/fatih/vim-go/pull/2473)
|
||||||
|
* Use echo functions consistently.
|
||||||
|
[[GH-2458]](https://github.com/fatih/vim-go/pull/2458)
|
||||||
|
* Add support for managing goroutines in debugger.
|
||||||
|
[[GH-2463]](https://github.com/fatih/vim-go/pull/2463)
|
||||||
|
[[GH-2527]](https://github.com/fatih/vim-go/pull/2527)
|
||||||
|
* Document `g:go_doc_popup_window`.
|
||||||
|
[[GH-2506]](https://github.com/fatih/vim-go/pull/2506)
|
||||||
|
* Make `g:go_doc_popup_window=1` work for Neovim, too.
|
||||||
|
[[GH-2451]](https://github.com/fatih/vim-go/pull/2451)
|
||||||
|
[[GH-2512]](https://github.com/fatih/vim-go/pull/2512)
|
||||||
|
* Handle errors jumping to a definition in a file open in another Vim process
|
||||||
|
better.
|
||||||
|
[[GH-2518]](https://github.com/fatih/vim-go/pull/2518)
|
||||||
|
* Improve the UX when the gopls binary is missing.
|
||||||
|
[[GH-2522]](https://github.com/fatih/vim-go/pull/2522)
|
||||||
|
* Use gopls instead of guru for `:GoSameIds`.
|
||||||
|
[[GH-2519]](https://github.com/fatih/vim-go/pull/2519)
|
||||||
|
* Use gopls instead of guru for `:GoReferrers`.
|
||||||
|
[[GH-2535]](https://github.com/fatih/vim-go/pull/2535)
|
||||||
|
* Update documentation for `g:go_addtags_transform`.
|
||||||
|
[[GH-2541]](https://github.com/fatih/vim-go/pull/2541)
|
||||||
|
* Install most helper tools in module aware mode.
|
||||||
|
[[GH-2545]](https://github.com/fatih/vim-go/pull/2545)
|
||||||
|
* Add a new option, `g:go_referrers_mode` to allow the user to choose whether
|
||||||
|
to use gopls or guru for finding references.
|
||||||
|
[[GH-2566]](https://github.com/fatih/vim-go/pull/2566)
|
||||||
|
* Add options to control how gopls responds to completion requests.
|
||||||
|
[[GH-2567]](https://github.com/fatih/vim-go/pull/2567)
|
||||||
|
[[GH-2568]](https://github.com/fatih/vim-go/pull/2568)
|
||||||
|
* Add syntax highlighting for binary literals.
|
||||||
|
[[GH-2557]](https://github.com/fatih/vim-go/pull/2557)
|
||||||
|
* Improve highlighting of invalid numeric literals.
|
||||||
|
[[GH-2571]](https://github.com/fatih/vim-go/pull/2571)
|
||||||
|
[[GH-2587]](https://github.com/fatih/vim-go/pull/2587)
|
||||||
|
[[GH-2589]](https://github.com/fatih/vim-go/pull/2589)
|
||||||
|
[[GH-2584]](https://github.com/fatih/vim-go/pull/2584)
|
||||||
|
[[GH-2597]](https://github.com/fatih/vim-go/pull/2597)
|
||||||
|
[[GH-2599]](https://github.com/fatih/vim-go/pull/2599)
|
||||||
|
* Add highlighting of sections reported by gopls diagnostics' errors
|
||||||
|
and warnings.
|
||||||
|
[[GH-2569]](https://github.com/fatih/vim-go/pull/2569)
|
||||||
|
[[GH-2643]](https://github.com/fatih/vim-go/pull/2643)
|
||||||
|
* Make the highlighting of fzf decls configurable.
|
||||||
|
[[GH-2572]](https://github.com/fatih/vim-go/pull/2572)
|
||||||
|
[[GH-2579]](https://github.com/fatih/vim-go/pull/2579)
|
||||||
|
* Support renaming with gopls.
|
||||||
|
[[GH-2577]](https://github.com/fatih/vim-go/pull/2577)
|
||||||
|
[[GH-2618]](https://github.com/fatih/vim-go/pull/2618)
|
||||||
|
* Add an option, `g:go_gopls_enabled`, to allow gopls integration to be
|
||||||
|
disabled.
|
||||||
|
[[GH-2605]](https://github.com/fatih/vim-go/pull/2605)
|
||||||
|
[[GH-2609]](https://github.com/fatih/vim-go/pull/2609)
|
||||||
|
[[GH-2638]](https://github.com/fatih/vim-go/pull/2638)
|
||||||
|
[[GH-2640]](https://github.com/fatih/vim-go/pull/2640)
|
||||||
|
* Add a buffer level option, `b:go_fmt_options`, to control formatting options
|
||||||
|
per buffer.
|
||||||
|
[[GH-2613]](https://github.com/fatih/vim-go/pull/2613)
|
||||||
|
* Use build tags when running `:GoVet`.
|
||||||
|
[[GH-2615]](https://github.com/fatih/vim-go/pull/2615)
|
||||||
|
* Add new snippets for UltiSnips.
|
||||||
|
[[GH-2623]](https://github.com/fatih/vim-go/pull/2623)
|
||||||
|
[[GH-2627]](https://github.com/fatih/vim-go/pull/2627)
|
||||||
|
* Expand completions as snippets when `g:go_gopls_use_placeholders` is set.
|
||||||
|
[[GH-2624]](https://github.com/fatih/vim-go/pull/2624)
|
||||||
|
* Add a new function, `:GoDiagnostics` and an associated mapping for seeing
|
||||||
|
`gopls` diagnostics. Because of the performance implications on large
|
||||||
|
projects, `g:go_diagnostics_enabled` controls whether all diagnostics are
|
||||||
|
processed or only the diagnostics for the current buffer.
|
||||||
|
[[GH-2612]](https://github.com/fatih/vim-go/pull/2612)
|
||||||
|
* Explain how to find and detect multiple copies of vim-go in the FAQ.
|
||||||
|
[[GH-2632]](https://github.com/fatih/vim-go/pull/2632)
|
||||||
|
* Update the issue template to ask for the gopls version and
|
||||||
|
`:GoReportGitHubIssue` to provide it.
|
||||||
|
[[GH-2630]](https://github.com/fatih/vim-go/pull/2630)
|
||||||
|
* Use text properties when possible for some highlighting cases.
|
||||||
|
[[GH-2652]](https://github.com/fatih/vim-go/pull/2652)
|
||||||
|
[[GH-2662]](https://github.com/fatih/vim-go/pull/2662)
|
||||||
|
[[GH-2663]](https://github.com/fatih/vim-go/pull/2663)
|
||||||
|
[[GH-2672]](https://github.com/fatih/vim-go/pull/2672)
|
||||||
|
[[GH-2678]](https://github.com/fatih/vim-go/pull/2678)
|
||||||
|
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
* Fix removal of missing directories from gopls workspaces.
|
||||||
|
[[GH-2507]](https://github.com/fatih/vim-go/pull/2507)
|
||||||
|
* Change to original window before trying to change directories when term job
|
||||||
|
ends.
|
||||||
|
[[GH-2508]](https://github.com/fatih/vim-go/pull/2508)
|
||||||
|
* Swallow errors when the hover info cannot be determined.
|
||||||
|
[[GH-2515]](https://github.com/fatih/vim-go/pull/2515)
|
||||||
|
* Fix errors when trying to debug lsp and hover.
|
||||||
|
[[GH-2516]](https://github.com/fatih/vim-go/pull/2516)
|
||||||
|
* Reset environment variables on Vim <= 8.0.1831 .
|
||||||
|
[[GH-2523]](https://github.com/fatih/vim-go/pull/2523)
|
||||||
|
* Handle empty results from delve.
|
||||||
|
[[GH-2526]](https://github.com/fatih/vim-go/pull/2526)
|
||||||
|
* Do not overwrite `updatetime` when `g:go_auto_sameids` or
|
||||||
|
`g:go_auto_type_info` is set.
|
||||||
|
[[GH-2529]](https://github.com/fatih/vim-go/pull/2529)
|
||||||
|
* Fix example for `g:go_debug_log_output` in docs.
|
||||||
|
[[GH-2547]](https://github.com/fatih/vim-go/pull/2547)
|
||||||
|
* Use FileChangedShellPost instead of FileChangedShell so that reload messages
|
||||||
|
are not hidden.
|
||||||
|
[[GH-2549]](https://github.com/fatih/vim-go/pull/2549)
|
||||||
|
* Restore cwd after `:GoTest` when `g:go_term_enabled` is set.
|
||||||
|
[[GH-2556]](https://github.com/fatih/vim-go/pull/2556)
|
||||||
|
* Expand struct variable correctly in the variables debug window.
|
||||||
|
[[GH-2574]](https://github.com/fatih/vim-go/pull/2574)
|
||||||
|
* Show output from errcheck when there are failures other than problems it can
|
||||||
|
report.
|
||||||
|
[[GH-2667]](https://github.com/fatih/vim-go/pull/2667)
|
||||||
|
|
||||||
|
## v1.21 - (September 11, 2019)
|
||||||
|
|
||||||
|
BACKWARDS INCOMPATIBILITIES:
|
||||||
|
* `g:go_metalinter_disabled` has been removed.
|
||||||
|
[[GH-2375]](https://github.com/fatih/vim-go/pull/2375)
|
||||||
|
|
||||||
|
IMPROVEMENTS:
|
||||||
|
* Add a new option, `g:go_code_completion_enabled`, to control whether omnifunc
|
||||||
|
is set.
|
||||||
|
[[GH-2229]](https://github.com/fatih/vim-go/pull/2229)
|
||||||
|
* Use build tags with golangci-lint.
|
||||||
|
[[GH-2261]](https://github.com/fatih/vim-go/pull/2261)
|
||||||
|
* Allow debugging of packages outside of GOPATH without a go.mod file.
|
||||||
|
[[GH-2269]](https://github.com/fatih/vim-go/pull/2269)
|
||||||
|
* Show which example failed when Example tests fail
|
||||||
|
[[GH-2277]](https://github.com/fatih/vim-go/pull/2277)
|
||||||
|
* Show function signature and return types in preview window when autocompleting functions and methods.
|
||||||
|
[[GH-2289]](https://github.com/fatih/vim-go/pull/2289)
|
||||||
|
* Improve the user experience when using null modules.
|
||||||
|
[[GH-2300]](https://github.com/fatih/vim-go/pull/2300)
|
||||||
|
* Modify `:GoReportGitHubIssue` to include vim-go configuration values
|
||||||
|
[[GH-2323]](https://github.com/fatih/vim-go/pull/2323)
|
||||||
|
* Respect `g:go_info_mode='gopls'` in go#complete#GetInfo.
|
||||||
|
[[GH-2313]](https://github.com/fatih/vim-go/pull/2313)
|
||||||
|
* Allow `:GoLint`, `:GoErrCheck`, and `:GoDebug` to work in null modules.
|
||||||
|
[[GH-2335]](https://github.com/fatih/vim-go/pull/2335)
|
||||||
|
* Change default value for `g:go_info_mode` and `g:go_def_mode` to `'gopls'`.
|
||||||
|
[[GH-2329]](https://github.com/fatih/vim-go/pull/2329)
|
||||||
|
* Add a new option, `g:go_doc_popup_window` to optionally use a popup window
|
||||||
|
for godoc in Vim 8.1.1513 and later.
|
||||||
|
[[GH-2347]](https://github.com/fatih/vim-go/pull/2347)
|
||||||
|
* Add `:GoAddWorkspace` function to support multiple workspaces with gopls.
|
||||||
|
[[GH-2356]](https://github.com/fatih/vim-go/pull/2356)
|
||||||
|
* Install gopls from its stable package.
|
||||||
|
[[GH-2360]](https://github.com/fatih/vim-go/pull/2360)
|
||||||
|
* Disambiguate progress message when initializing gopls.
|
||||||
|
[[GH-2369]](https://github.com/fatih/vim-go/pull/2369)
|
||||||
|
* Calculate LSP position correctly when on a line that contains multi-byte
|
||||||
|
characters before the position.
|
||||||
|
[[GH-2389]](https://github.com/fatih/vim-go/pull/2389)
|
||||||
|
* Calculate Vim position correctly from LSP text position.
|
||||||
|
[[GH-2395]](https://github.com/fatih/vim-go/pull/2395)
|
||||||
|
* Use the statusline to display gopls initialization status messages and only
|
||||||
|
echo the statuses when `g:go_echo_command_info` is set.
|
||||||
|
[[GH-2422]](https://github.com/fatih/vim-go/pull/2422)
|
||||||
|
* Send configuration to gopls so that build tags will be considered and hover
|
||||||
|
content won't have documentation.
|
||||||
|
[[GH-2429]](https://github.com/fatih/vim-go/pull/2429)
|
||||||
|
* Add a new option, `g:go_term_close_on_exit`, to control whether jobs run in a
|
||||||
|
terminal window will close the terminal window when the job exits.
|
||||||
|
[[GH-2409]](https://github.com/fatih/vim-go/pull/2409)
|
||||||
|
* Allow `g:go_template_file` and `g:go_template_test_files` to reside outside
|
||||||
|
of vim-go's template directory.
|
||||||
|
[[GH-2434]](https://github.com/fatih/vim-go/pull/2434)
|
||||||
|
* Add a new command, `:GoLSPDebugBrowser`, to open a browser to gopls debugging
|
||||||
|
view.
|
||||||
|
[[GH-2436]](https://github.com/fatih/vim-go/pull/2436)
|
||||||
|
* Restart gopls automatically when it is updated via `:GoUpdateBinaries`.
|
||||||
|
[[GH-2453]](https://github.com/fatih/vim-go/pull/2453)
|
||||||
|
* Reset `'more'` while installing binaries to avoid unnecessary more prompts.
|
||||||
|
[[GH-2457]](https://github.com/fatih/vim-go/pull/2457)
|
||||||
|
* Highlight `%w` as a format specifier (for Go 1.13).
|
||||||
|
[[GH-2433]](https://github.com/fatih/vim-go/pull/2433)
|
||||||
|
* Handle changes to Go 1.13's go vet output that gometalinter isn't expecting.
|
||||||
|
[[GH-2475]](https://github.com/fatih/vim-go/pull/2475)
|
||||||
|
* Make `golangci-lint` the default value for `g:go_metalinter_command`.
|
||||||
|
[[GH-2478]](https://github.com/fatih/vim-go/pull/2478)
|
||||||
|
* Parse compiler errors from Go 1.13 `go vet` correctly.
|
||||||
|
[[GH-2485]](https://github.com/fatih/vim-go/pull/2485)
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
* display info about function and function types whose parameters are
|
||||||
|
`interface{}` without truncating the function signature.
|
||||||
|
[[GH-2244]](https://github.com/fatih/vim-go/pull/2244)
|
||||||
|
* install tools that require GOPATH mode when in module mode.
|
||||||
|
[[GH-2253]](https://github.com/fatih/vim-go/pull/2253)
|
||||||
|
* Detect GOPATH when starting `gopls`
|
||||||
|
[[GH-2255]](https://github.com/fatih/vim-go/pull/2255)
|
||||||
|
* Handle `gopls` responses in the same window from which the respective request
|
||||||
|
originated.
|
||||||
|
[[GH-2266]](https://github.com/fatih/vim-go/pull/2266)
|
||||||
|
* Show completion matches from gocode.
|
||||||
|
[[GH-2267]](https://github.com/fatih/vim-go/pull/2267)
|
||||||
|
* Show the completion preview window.
|
||||||
|
[[GH-2268]](https://github.com/fatih/vim-go/pull/2268)
|
||||||
|
* Set the anchor for method documentation correctly.
|
||||||
|
[[GH-2276]](https://github.com/fatih/vim-go/pull/2276)
|
||||||
|
* Respect the LSP information for determining where candidate matches start.
|
||||||
|
[[GH-2291]](https://github.com/fatih/vim-go/pull/2291)
|
||||||
|
* Restore environment variables with backslashes correctly.
|
||||||
|
[[GH-2292]](https://github.com/fatih/vim-go/pull/2292)
|
||||||
|
* Modify handling of gopls output for `:GoInfo` to ensure the value will be
|
||||||
|
displayed.
|
||||||
|
[[GH-2311]](https://github.com/fatih/vim-go/pull/2311)
|
||||||
|
* Run `:GoLint` successfully in null modules.
|
||||||
|
[[GH-2318]](https://github.com/fatih/vim-go/pull/2318)
|
||||||
|
* Ensure actions on save work in new buffers that have not yet been persisted to disk.
|
||||||
|
[[GH-2319]](https://github.com/fatih/vim-go/pull/2319)
|
||||||
|
* Restore population of information in `:GoReportGitHubIssue`.
|
||||||
|
[[GH-2312]](https://github.com/fatih/vim-go/pull/2312)
|
||||||
|
* Do not jump back to the originating window when jumping to definitions with
|
||||||
|
`g:go_def_mode='gopls'`.
|
||||||
|
[[GH-2327]](https://github.com/fatih/vim-go/pull/2327)
|
||||||
|
* Fix getting information about a valid identifier for which gopls returns no
|
||||||
|
information (e.g. calling `:GoInfo` on a package identifier).
|
||||||
|
[[GH-2339]](https://github.com/fatih/vim-go/pull/2339)
|
||||||
|
* Fix tab completion of package names on the cmdline in null modules.
|
||||||
|
[[GH-2342]](https://github.com/fatih/vim-go/pull/2342)
|
||||||
|
* Display identifier info correctly when the identifier has no godoc.
|
||||||
|
[[GH-2373]](https://github.com/fatih/vim-go/pull/2373)
|
||||||
|
* Fix false positives when saving a buffer and `g:go_metalinter_command` is
|
||||||
|
`golangci-lint`.
|
||||||
|
[[GH-2367]](https://github.com/fatih/vim-go/pull/2367)
|
||||||
|
* Fix `:GoDebugRestart`.
|
||||||
|
[[GH-2390]](https://github.com/fatih/vim-go/pull/2390)
|
||||||
|
* Do not execute tests twice in terminal mode.
|
||||||
|
[[GH-2397]](https://github.com/fatih/vim-go/pull/2397)
|
||||||
|
* Do not open a new buffer in Neovim when there are compilation errors and
|
||||||
|
terminal mode is enabled.
|
||||||
|
[[GH-2401]](https://github.com/fatih/vim-go/pull/2401)
|
||||||
|
* Fix error due to typo in implementation of `:GoAddWorkspace`.
|
||||||
|
[[GH-2415]](https://github.com/fatih/vim-go/pull/2401)
|
||||||
|
* Do not format the file automatically when `g:go_format_autosave` is set and
|
||||||
|
the file being written is not the current file.
|
||||||
|
[[GH-2442]](https://github.com/fatih/vim-go/pull/2442)
|
||||||
|
* Fix `go-debug-stepout` mapping.
|
||||||
|
[[GH-2464]](https://github.com/fatih/vim-go/pull/2464)
|
||||||
|
* Handle paths with spaces correctly when executing jobs.
|
||||||
|
[[GH-2472]](https://github.com/fatih/vim-go/pull/2472)
|
||||||
|
* Remove a space in the default value for `g:go_debug_log_output`, so that
|
||||||
|
Delve will start on Windows.
|
||||||
|
[[GH-2480]](https://github.com/fatih/vim-go/pull/2480)
|
||||||
|
|
||||||
## 1.20 - (April 22, 2019)
|
## 1.20 - (April 22, 2019)
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
|
@ -13,7 +537,7 @@ FEATURES:
|
||||||
* New `:GoDefType` command to jump to a type definition from an instance of the
|
* New `:GoDefType` command to jump to a type definition from an instance of the
|
||||||
type.
|
type.
|
||||||
|
|
||||||
BACKWARDS INCOMPATABILITIES:
|
BACKWARDS INCOMPATIBILITIES:
|
||||||
* `g:go_highlight_function_arguments` is renamed to `g:go_highlight_function_parameters`
|
* `g:go_highlight_function_arguments` is renamed to `g:go_highlight_function_parameters`
|
||||||
[[GH-2117]](https://github.com/fatih/vim-go/pull/2117)
|
[[GH-2117]](https://github.com/fatih/vim-go/pull/2117)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM golang:1.12.1
|
FROM golang:1.15.1
|
||||||
|
|
||||||
RUN apt-get update -y && \
|
RUN apt-get update -y --allow-insecure-repositories && \
|
||||||
apt-get install -y build-essential curl git libncurses5-dev python3-pip && \
|
apt-get install -y build-essential curl git libncurses5-dev python3-pip && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
@ -10,11 +10,18 @@ RUN pip3 install vim-vint
|
||||||
RUN useradd -ms /bin/bash -d /vim-go vim-go
|
RUN useradd -ms /bin/bash -d /vim-go vim-go
|
||||||
USER vim-go
|
USER vim-go
|
||||||
|
|
||||||
|
COPY scripts/install-vim /vim-go/scripts/install-vim
|
||||||
|
WORKDIR /vim-go
|
||||||
|
|
||||||
|
RUN scripts/install-vim vim-8.0
|
||||||
|
RUN scripts/install-vim vim-8.2
|
||||||
|
RUN scripts/install-vim nvim
|
||||||
|
|
||||||
COPY . /vim-go/
|
COPY . /vim-go/
|
||||||
WORKDIR /vim-go
|
WORKDIR /vim-go
|
||||||
|
|
||||||
RUN scripts/install-vim vim-7.4
|
RUN scripts/install-tools vim-8.0
|
||||||
RUN scripts/install-vim vim-8.0
|
RUN scripts/install-tools vim-8.2
|
||||||
RUN scripts/install-vim nvim
|
RUN scripts/install-tools nvim
|
||||||
|
|
||||||
ENTRYPOINT ["make"]
|
ENTRYPOINT ["make"]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
VIMS ?= vim-7.4 vim-8.0 nvim
|
VIMS ?= vim-8.0 vim-8.2 nvim
|
||||||
|
|
||||||
all: install lint test
|
all: install lint test
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ install:
|
||||||
@echo "==> Installing Vims: $(VIMS)"
|
@echo "==> Installing Vims: $(VIMS)"
|
||||||
@for vim in $(VIMS); do \
|
@for vim in $(VIMS); do \
|
||||||
./scripts/install-vim $$vim; \
|
./scripts/install-vim $$vim; \
|
||||||
|
./scripts/install-tools $$vim; \
|
||||||
done
|
done
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
@ -16,7 +17,7 @@ test:
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
@echo "==> Running linting tools"
|
@echo "==> Running linting tools"
|
||||||
@./scripts/lint vim-8.0
|
@./scripts/lint vim-8.2
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
@echo "==> Building/starting Docker container"
|
@echo "==> Building/starting Docker container"
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
# vim-go [![Build Status](http://img.shields.io/travis/fatih/vim-go.svg?style=flat-square)](https://travis-ci.org/fatih/vim-go)
|
# vim-go [![Build Status](http://img.shields.io/travis/fatih/vim-go.svg?style=flat-square)](https://travis-ci.org/fatih/vim-go) [![GitHub Actions Status](https://github.com/fatih/vim-go/workflows/test/badge.svg)](https://github.com/fatih/vim-go/actions)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img style="float: right;" src="assets/vim-go.png" alt="Vim-go logo"/>
|
<img style="float: right;" src="assets/vim-go.png" alt="Vim-go logo"/>
|
||||||
|
@ -13,15 +15,15 @@ This plugin adds Go language support for Vim, with the following main features:
|
||||||
* Quickly execute your current file(s) with `:GoRun`.
|
* Quickly execute your current file(s) with `:GoRun`.
|
||||||
* Improved syntax highlighting and folding.
|
* Improved syntax highlighting and folding.
|
||||||
* Debug programs with integrated `delve` support with `:GoDebugStart`.
|
* Debug programs with integrated `delve` support with `:GoDebugStart`.
|
||||||
* Completion support via `gocode` and `gopls`.
|
* Completion and many other features support via `gopls`.
|
||||||
* `gofmt` or `goimports` on save keeps the cursor position and undo history.
|
* formatting on save keeps the cursor position and undo history.
|
||||||
* Go to symbol/declaration with `:GoDef`.
|
* Go to symbol/declaration with `:GoDef`.
|
||||||
* Look up documentation with `:GoDoc` or `:GoDocBrowser`.
|
* Look up documentation with `:GoDoc` or `:GoDocBrowser`.
|
||||||
* Easily import packages via `:GoImport`, remove them via `:GoDrop`.
|
* Easily import packages via `:GoImport`, remove them via `:GoDrop`.
|
||||||
* Precise type-safe renaming of identifiers with `:GoRename`.
|
* Precise type-safe renaming of identifiers with `:GoRename`.
|
||||||
* See which code is covered by tests with `:GoCoverage`.
|
* See which code is covered by tests with `:GoCoverage`.
|
||||||
* Add or remove tags on struct fields with `:GoAddTags` and `:GoRemoveTags`.
|
* Add or remove tags on struct fields with `:GoAddTags` and `:GoRemoveTags`.
|
||||||
* Call `gometalinter` with `:GoMetaLinter` to invoke all possible linters
|
* Call `golangci-lint` with `:GoMetaLinter` to invoke all possible linters
|
||||||
(`golint`, `vet`, `errcheck`, `deadcode`, etc.) and put the result in the
|
(`golint`, `vet`, `errcheck`, `deadcode`, etc.) and put the result in the
|
||||||
quickfix or location list.
|
quickfix or location list.
|
||||||
* Lint your code with `:GoLint`, run your code through `:GoVet` to catch static
|
* Lint your code with `:GoLint`, run your code through `:GoVet` to catch static
|
||||||
|
@ -30,10 +32,12 @@ This plugin adds Go language support for Vim, with the following main features:
|
||||||
`:GoCallees`, and `:GoReferrers`.
|
`:GoCallees`, and `:GoReferrers`.
|
||||||
* ... and many more! Please see [doc/vim-go.txt](doc/vim-go.txt) for more
|
* ... and many more! Please see [doc/vim-go.txt](doc/vim-go.txt) for more
|
||||||
information.
|
information.
|
||||||
|
* The `gopls` instance can be shared with other Vim plugins.
|
||||||
|
* Vim-go's use of `gopls` can be disabled.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
vim-go requires at least Vim 7.4.2009 or Neovim 0.3.1.
|
vim-go requires at least Vim 8.0.1453 or Neovim 0.4.0.
|
||||||
|
|
||||||
The [**latest stable release**](https://github.com/fatih/vim-go/releases/latest) is the
|
The [**latest stable release**](https://github.com/fatih/vim-go/releases/latest) is the
|
||||||
recommended version to use. If you choose to use the master branch instead,
|
recommended version to use. If you choose to use the master branch instead,
|
||||||
|
@ -68,8 +72,28 @@ Depending on your installation method, you may have to generate the plugin's
|
||||||
[`help tags`](http://vimhelp.appspot.com/helphelp.txt.html#%3Ahelptags)
|
[`help tags`](http://vimhelp.appspot.com/helphelp.txt.html#%3Ahelptags)
|
||||||
manually (e.g. `:helptags ALL`).
|
manually (e.g. `:helptags ALL`).
|
||||||
|
|
||||||
We also have an [official vim-go tutorial](https://github.com/fatih/vim-go-tutorial).
|
We also have an [official vim-go tutorial](https://github.com/fatih/vim-go/wiki).
|
||||||
|
|
||||||
|
## FAQ and troubleshooting
|
||||||
|
|
||||||
|
The FAQ and troubleshooting tips are in the documentation and can be quickly
|
||||||
|
accessed using `:help go-troubleshooting`. If you believe you've found a bug or
|
||||||
|
shortcoming in vim-go that is neither addressed by help nor in [existing
|
||||||
|
issues](https://github.com/fatih/vim-go/issues), please open an issue with
|
||||||
|
clear reproduction steps. `:GoReportGitHubIssue` can be used pre-populate a lot
|
||||||
|
of the information needed when creating a new issue.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
All PRs are welcome. If you are planning to contribute a large patch or to
|
||||||
|
integrate a new tool, please create an issue first to get any upfront questions
|
||||||
|
or design decisions out of the way first.
|
||||||
|
|
||||||
|
You can run the tests locally by running `make`. It will lint the VimL for you,
|
||||||
|
lint the documentation, and run the tests against the minimum required version
|
||||||
|
of Vim, other versions of Vim that may be critical to support, and Neovim.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The BSD 3-Clause License - see [`LICENSE`](LICENSE) for more details
|
The BSD 3-Clause License - see [`LICENSE`](LICENSE) for more details
|
||||||
|
|
||||||
|
|
|
@ -121,10 +121,10 @@ function! s:source(mode,...) abort
|
||||||
\ decl.col
|
\ decl.col
|
||||||
\)
|
\)
|
||||||
call add(ret_decls, printf("%s\t%s %s\t%s",
|
call add(ret_decls, printf("%s\t%s %s\t%s",
|
||||||
\ s:color(decl.ident . space, "Function"),
|
\ s:color(decl.ident . space, "goDeclsFzfFunction"),
|
||||||
\ s:color(decl.keyword, "Keyword"),
|
\ s:color(decl.keyword, "goDeclsFzfKeyword"),
|
||||||
\ s:color(pos, "SpecialComment"),
|
\ s:color(pos, "goDeclsFzfSpecialComment"),
|
||||||
\ s:color(decl.full, "Comment"),
|
\ s:color(decl.full, "goDeclsFzfComment"),
|
||||||
\))
|
\))
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,43 @@ function! go#auto#template_autocreate()
|
||||||
call go#template#create()
|
call go#template#create()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#auto#echo_go_info()
|
function! go#auto#complete_done()
|
||||||
|
call s:echo_go_info()
|
||||||
|
call s:ExpandSnippet()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:ExpandSnippet() abort
|
||||||
|
if !exists('v:completed_item') || empty(v:completed_item) || !go#config#GoplsUsePlaceholders()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
let l:engine = go#config#SnippetEngine()
|
||||||
|
|
||||||
|
if l:engine is 'ultisnips'
|
||||||
|
if !get(g:, 'did_plugin_ultisnips', 0)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
" the snippet may have a '{\}' in it. For UltiSnips, that should be spelled
|
||||||
|
" \{}. fmt.Printf is such a snippet that can be used to demonstrate.
|
||||||
|
let l:snippet = substitute(v:completed_item.word, '{\\}', '\{}', 'g')
|
||||||
|
call UltiSnips#Anon(l:snippet, v:completed_item.word, '', 'i')
|
||||||
|
" elseif l:engine is 'neosnippet'
|
||||||
|
" " TODO(bc): make the anonymous expansion for neosnippet work
|
||||||
|
"
|
||||||
|
" if !get(g:, 'loaded_neosnippet') is 1
|
||||||
|
" return
|
||||||
|
" endif
|
||||||
|
"
|
||||||
|
" " neosnippet#anonymous doesn't need a trigger, so replace the
|
||||||
|
" " completed_item.word with an empty string before calling neosnippet#anonymous
|
||||||
|
" let l:snippet = substitute(v:completed_item.word, '{\\}', '\{\}', 'g')
|
||||||
|
" call setline('.', substitute(getline('.'), substitute(v:completed_item.word, '\', '\\', 'g'), '', ''))
|
||||||
|
" call neosnippet#anonymous(l:snippet)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:echo_go_info()
|
||||||
if !go#config#EchoGoInfo()
|
if !go#config#EchoGoInfo()
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
@ -21,46 +57,109 @@ function! go#auto#echo_go_info()
|
||||||
endif
|
endif
|
||||||
let item = v:completed_item
|
let item = v:completed_item
|
||||||
|
|
||||||
if !has_key(item, "info")
|
if !has_key(item, "user_data")
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if empty(item.info)
|
if empty(item.user_data)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
redraws! | echo "vim-go: " | echohl Function | echon item.info | echohl None
|
redraws! | echo "vim-go: " | echohl Function | echon item.user_data | echohl None
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#auto#auto_type_info()
|
let s:timer_id = 0
|
||||||
if !go#config#AutoTypeInfo() || !filereadable(expand('%:p'))
|
|
||||||
|
" go#auto#update_autocmd() will be called on BufEnter,CursorHold. This
|
||||||
|
" configures the augroup according to conditions below.
|
||||||
|
"
|
||||||
|
" | # | has_timer | should_enable | do |
|
||||||
|
" |---|-----------|---------------|------------------------------------|
|
||||||
|
" | 1 | false | false | return early |
|
||||||
|
" | 2 | true | true | return early |
|
||||||
|
" | 3 | true | false | clear the group and stop the timer |
|
||||||
|
" | 4 | false | true | configure the group |
|
||||||
|
function! go#auto#update_autocmd()
|
||||||
|
let has_timer = get(b:, 'has_timer')
|
||||||
|
let should_enable = go#config#AutoTypeInfo() || go#config#AutoSameids()
|
||||||
|
if (!has_timer && !should_enable) || (has_timer && should_enable)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" GoInfo automatic update
|
if has_timer
|
||||||
call go#tool#Info(0)
|
augroup vim-go-buffer-auto
|
||||||
|
autocmd! * <buffer>
|
||||||
|
augroup END
|
||||||
|
let b:has_timer = 0
|
||||||
|
call s:timer_stop()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
augroup vim-go-buffer-auto
|
||||||
|
autocmd! * <buffer>
|
||||||
|
autocmd CursorMoved <buffer> call s:timer_restart()
|
||||||
|
autocmd BufLeave <buffer> call s:timer_stop()
|
||||||
|
augroup END
|
||||||
|
let b:has_timer = 1
|
||||||
|
call s:timer_start()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#auto#auto_sameids()
|
function! s:timer_restart()
|
||||||
if !go#config#AutoSameids() || !filereadable(expand('%:p'))
|
if isdirectory(expand('%:p:h'))
|
||||||
return
|
call s:timer_stop()
|
||||||
|
call s:timer_start()
|
||||||
endif
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
" GoSameId automatic update
|
function! s:timer_stop()
|
||||||
call go#guru#SameIds(0)
|
if s:timer_id
|
||||||
|
call timer_stop(s:timer_id)
|
||||||
|
let s:timer_id = 0
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:timer_start()
|
||||||
|
let s:timer_id = timer_start(go#config#Updatetime(), function('s:handler'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:handler(timer_id)
|
||||||
|
if go#config#AutoTypeInfo()
|
||||||
|
call go#tool#Info(0)
|
||||||
|
endif
|
||||||
|
if go#config#AutoSameids()
|
||||||
|
call go#guru#SameIds(0)
|
||||||
|
endif
|
||||||
|
let s:timer_id = 0
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#auto#fmt_autosave()
|
function! go#auto#fmt_autosave()
|
||||||
if !go#config#FmtAutosave() || !filereadable(expand('%:p'))
|
if !(isdirectory(expand('%:p:h')) && expand('<afile>:p') == expand('%:p'))
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !(go#config#FmtAutosave() || go#config#ImportsAutosave())
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if go#config#ImportsAutosave() && !(go#config#FmtAutosave() && go#config#FmtCommand() == 'goimports')
|
||||||
|
call go#fmt#Format(1)
|
||||||
|
|
||||||
|
" return early when the imports mode is goimports, because there's no need
|
||||||
|
" to format again when goimports was run
|
||||||
|
if go#config#ImportsMode() == 'goimports'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !go#config#FmtAutosave()
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Go code formatting on save
|
|
||||||
call go#fmt#Format(-1)
|
call go#fmt#Format(-1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#auto#metalinter_autosave()
|
function! go#auto#metalinter_autosave()
|
||||||
if !go#config#MetalinterAutosave() || !filereadable(expand('%:p'))
|
if !go#config#MetalinterAutosave() || !isdirectory(expand('%:p:h'))
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -69,7 +168,7 @@ function! go#auto#metalinter_autosave()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#auto#modfmt_autosave()
|
function! go#auto#modfmt_autosave()
|
||||||
if !go#config#ModFmtAutosave() || !filereadable(expand('%:p'))
|
if !(go#config#ModFmtAutosave() && isdirectory(expand('%:p:h')) && expand('<afile>:p') == expand('%:p'))
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -78,7 +177,7 @@ function! go#auto#modfmt_autosave()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#auto#asmfmt_autosave()
|
function! go#auto#asmfmt_autosave()
|
||||||
if !go#config#AsmfmtAutosave() || !filereadable(expand('%:p'))
|
if !(go#config#AsmfmtAutosave() && isdirectory(expand('%:p:h')) && expand('<afile>:p') == expand('%:p'))
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ function! go#cmd#autowrite() abort
|
||||||
for l:nr in range(0, bufnr('$'))
|
for l:nr in range(0, bufnr('$'))
|
||||||
if buflisted(l:nr) && getbufvar(l:nr, '&modified')
|
if buflisted(l:nr) && getbufvar(l:nr, '&modified')
|
||||||
" Sleep one second to make sure people see the message. Otherwise it is
|
" Sleep one second to make sure people see the message. Otherwise it is
|
||||||
" often immediacy overwritten by the async messages (which also don't
|
" often immediately overwritten by the async messages (which also
|
||||||
" invoke the "hit ENTER" prompt).
|
" doesn't invoke the "hit ENTER" prompt).
|
||||||
call go#util#EchoWarning('[No write since last change]')
|
call go#util#EchoWarning('[No write since last change]')
|
||||||
sleep 1
|
sleep 1
|
||||||
return
|
return
|
||||||
|
@ -32,7 +32,7 @@ function! go#cmd#Build(bang, ...) abort
|
||||||
\ map(copy(a:000), "expand(v:val)") +
|
\ map(copy(a:000), "expand(v:val)") +
|
||||||
\ [".", "errors"]
|
\ [".", "errors"]
|
||||||
|
|
||||||
" Vim and Neovim async.
|
" Vim and Neovim async
|
||||||
if go#util#has_job()
|
if go#util#has_job()
|
||||||
call s:cmd_job({
|
call s:cmd_job({
|
||||||
\ 'cmd': ['go'] + args,
|
\ 'cmd': ['go'] + args,
|
||||||
|
@ -41,8 +41,15 @@ function! go#cmd#Build(bang, ...) abort
|
||||||
\ 'statustype': 'build'
|
\ 'statustype': 'build'
|
||||||
\})
|
\})
|
||||||
|
|
||||||
" Vim 7.4 without async
|
" Vim without async
|
||||||
else
|
else
|
||||||
|
let l:status = {
|
||||||
|
\ 'desc': 'current status',
|
||||||
|
\ 'type': 'build',
|
||||||
|
\ 'state': "started",
|
||||||
|
\ }
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
|
|
||||||
let default_makeprg = &makeprg
|
let default_makeprg = &makeprg
|
||||||
let &makeprg = "go " . join(go#util#Shelllist(args), ' ')
|
let &makeprg = "go " . join(go#util#Shelllist(args), ' ')
|
||||||
|
|
||||||
|
@ -68,10 +75,16 @@ function! go#cmd#Build(bang, ...) abort
|
||||||
call go#list#Window(l:listtype, len(errors))
|
call go#list#Window(l:listtype, len(errors))
|
||||||
if !empty(errors) && !a:bang
|
if !empty(errors) && !a:bang
|
||||||
call go#list#JumpToFirst(l:listtype)
|
call go#list#JumpToFirst(l:listtype)
|
||||||
|
let l:status.state = 'failed'
|
||||||
else
|
else
|
||||||
call go#util#EchoSuccess("[build] SUCCESS")
|
let l:status.state = 'success'
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoSuccess("[build] SUCCESS")
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,16 +117,15 @@ endfunction
|
||||||
|
|
||||||
" Run runs the current file (and their dependencies if any) in a new terminal.
|
" Run runs the current file (and their dependencies if any) in a new terminal.
|
||||||
function! go#cmd#RunTerm(bang, mode, files) abort
|
function! go#cmd#RunTerm(bang, mode, files) abort
|
||||||
let cmd = "go run "
|
let cmd = ["go", "run"]
|
||||||
let tags = go#config#BuildTags()
|
if len(go#config#BuildTags()) > 0
|
||||||
if len(tags) > 0
|
call extend(cmd, ["-tags", go#config#BuildTags()])
|
||||||
let cmd .= "-tags " . go#util#Shellescape(tags) . " "
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if empty(a:files)
|
if empty(a:files)
|
||||||
let cmd .= go#util#Shelljoin(go#tool#Files())
|
call extend(cmd, go#tool#Files())
|
||||||
else
|
else
|
||||||
let cmd .= go#util#Shelljoin(map(copy(a:files), "expand(v:val)"), 1)
|
call extend(cmd, map(copy(a:files), funcref('s:expandRunArgs')))
|
||||||
endif
|
endif
|
||||||
call go#term#newmode(a:bang, cmd, s:runerrorformat(), a:mode)
|
call go#term#newmode(a:bang, cmd, s:runerrorformat(), a:mode)
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -123,7 +135,7 @@ endfunction
|
||||||
" suitable for long running apps, because vim is blocking by default and
|
" suitable for long running apps, because vim is blocking by default and
|
||||||
" calling long running apps will block the whole UI.
|
" calling long running apps will block the whole UI.
|
||||||
function! go#cmd#Run(bang, ...) abort
|
function! go#cmd#Run(bang, ...) abort
|
||||||
if has('nvim')
|
if go#config#TermEnabled()
|
||||||
call go#cmd#RunTerm(a:bang, '', a:000)
|
call go#cmd#RunTerm(a:bang, '', a:000)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
@ -134,61 +146,101 @@ function! go#cmd#Run(bang, ...) abort
|
||||||
" anything. Once this is implemented we're going to make :GoRun async
|
" anything. Once this is implemented we're going to make :GoRun async
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let cmd = "go run "
|
let l:status = {
|
||||||
let tags = go#config#BuildTags()
|
\ 'desc': 'current status',
|
||||||
if len(tags) > 0
|
\ 'type': 'run',
|
||||||
let cmd .= "-tags " . go#util#Shellescape(tags) . " "
|
\ 'state': "started",
|
||||||
|
\ }
|
||||||
|
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
|
|
||||||
|
let l:cmd = ['go', 'run']
|
||||||
|
let l:tags = go#config#BuildTags()
|
||||||
|
if len(l:tags) > 0
|
||||||
|
let l:cmd = l:cmd + ['-tags', l:tags]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if a:0 == 0
|
||||||
|
let l:files = go#tool#Files()
|
||||||
|
else
|
||||||
|
let l:files = map(copy(a:000), funcref('s:expandRunArgs'))
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:cmd = l:cmd + l:files
|
||||||
|
|
||||||
|
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||||
|
let l:dir = getcwd()
|
||||||
|
|
||||||
if go#util#IsWin()
|
if go#util#IsWin()
|
||||||
if a:0 == 0
|
try
|
||||||
exec '!' . cmd . go#util#Shelljoin(go#tool#Files(), 1)
|
if go#util#HasDebug('shell-commands')
|
||||||
else
|
call go#util#EchoInfo(printf('shell command: %s', string(l:cmd)))
|
||||||
exec '!' . cmd . go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
|
endif
|
||||||
endif
|
|
||||||
|
|
||||||
|
execute l:cd . fnameescape(expand("%:p:h"))
|
||||||
|
exec printf('!%s', go#util#Shelljoin(l:cmd, 1))
|
||||||
|
finally
|
||||||
|
execute l:cd . fnameescape(l:dir)
|
||||||
|
endtry
|
||||||
|
|
||||||
|
let l:status.state = 'success'
|
||||||
if v:shell_error
|
if v:shell_error
|
||||||
redraws! | echon "vim-go: [run] " | echohl ErrorMsg | echon "FAILED"| echohl None
|
let l:status.state = 'failed'
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
redraws!
|
||||||
|
call go#util#EchoError('[run] FAILED')
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
redraws! | echon "vim-go: [run] " | echohl Function | echon "SUCCESS"| echohl None
|
if go#config#EchoCommandInfo()
|
||||||
|
redraws!
|
||||||
|
call go#util#EchoSuccess('[run] SUCCESS')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" :make expands '%' and '#' wildcards, so they must also be escaped
|
" :make expands '%' and '#' wildcards, so they must also be escaped
|
||||||
let default_makeprg = &makeprg
|
let l:default_makeprg = &makeprg
|
||||||
if a:0 == 0
|
let &makeprg = go#util#Shelljoin(l:cmd, 1)
|
||||||
let &makeprg = cmd . go#util#Shelljoin(go#tool#Files(), 1)
|
|
||||||
else
|
|
||||||
let &makeprg = cmd . go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:listtype = go#list#Type("GoRun")
|
let l:listtype = go#list#Type("GoRun")
|
||||||
|
|
||||||
try
|
let l:status.state = 'success'
|
||||||
|
|
||||||
|
try
|
||||||
" backup user's errorformat, will be restored once we are finished
|
" backup user's errorformat, will be restored once we are finished
|
||||||
let l:old_errorformat = &errorformat
|
let l:old_errorformat = &errorformat
|
||||||
let &errorformat = s:runerrorformat()
|
let &errorformat = s:runerrorformat()
|
||||||
|
|
||||||
|
if go#util#HasDebug('shell-commands')
|
||||||
|
call go#util#EchoInfo('shell command: ' . l:cmd)
|
||||||
|
endif
|
||||||
|
|
||||||
|
execute l:cd . fnameescape(expand("%:p:h"))
|
||||||
if l:listtype == "locationlist"
|
if l:listtype == "locationlist"
|
||||||
exe 'lmake!'
|
exe 'lmake!'
|
||||||
else
|
else
|
||||||
exe 'make!'
|
exe 'make!'
|
||||||
endif
|
endif
|
||||||
finally
|
finally
|
||||||
"restore errorformat
|
"restore the working directory, errformat, and makeprg
|
||||||
|
execute cd . fnameescape(l:dir)
|
||||||
let &errorformat = l:old_errorformat
|
let &errorformat = l:old_errorformat
|
||||||
let &makeprg = default_makeprg
|
let &makeprg = l:default_makeprg
|
||||||
endtry
|
endtry
|
||||||
|
|
||||||
let l:errors = go#list#Get(l:listtype)
|
let l:errors = go#list#Get(l:listtype)
|
||||||
|
|
||||||
call go#list#Window(l:listtype, len(l:errors))
|
call go#list#Window(l:listtype, len(l:errors))
|
||||||
if !empty(l:errors) && !a:bang
|
if !empty(l:errors)
|
||||||
call go#list#JumpToFirst(l:listtype)
|
let l:status.state = 'failed'
|
||||||
|
if !a:bang
|
||||||
|
call go#list#JumpToFirst(l:listtype)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Install installs the package by simple calling 'go install'. If any argument
|
" Install installs the package by simple calling 'go install'. If any argument
|
||||||
|
@ -255,9 +307,18 @@ function! go#cmd#Generate(bang, ...) abort
|
||||||
let &makeprg = "go generate " . goargs . ' ' . gofiles
|
let &makeprg = "go generate " . goargs . ' ' . gofiles
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:listtype = go#list#Type("GoGenerate")
|
let l:status = {
|
||||||
|
\ 'desc': 'current status',
|
||||||
|
\ 'type': 'generate',
|
||||||
|
\ 'state': "started",
|
||||||
|
\ }
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
|
|
||||||
echon "vim-go: " | echohl Identifier | echon "generating ..."| echohl None
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoProgress('generating ...')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:listtype = go#list#Type("GoGenerate")
|
||||||
|
|
||||||
try
|
try
|
||||||
if l:listtype == "locationlist"
|
if l:listtype == "locationlist"
|
||||||
|
@ -273,13 +334,18 @@ function! go#cmd#Generate(bang, ...) abort
|
||||||
let errors = go#list#Get(l:listtype)
|
let errors = go#list#Get(l:listtype)
|
||||||
call go#list#Window(l:listtype, len(errors))
|
call go#list#Window(l:listtype, len(errors))
|
||||||
if !empty(errors)
|
if !empty(errors)
|
||||||
|
let l:status.status = 'failed'
|
||||||
if !a:bang
|
if !a:bang
|
||||||
call go#list#JumpToFirst(l:listtype)
|
call go#list#JumpToFirst(l:listtype)
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
redraws! | echon "vim-go: " | echohl Function | echon "[generate] SUCCESS"| echohl None
|
let l:status.status = 'success'
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
redraws!
|
||||||
|
call go#util#EchoSuccess('[generate] SUCCESS')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
call go#statusline#Update(expand(':%:p:h'), l:status)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:runerrorformat()
|
function! s:runerrorformat()
|
||||||
|
@ -288,6 +354,18 @@ function! s:runerrorformat()
|
||||||
return l:errorformat
|
return l:errorformat
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" s:expandRunArgs expands arguments for go#cmd#Run according to the
|
||||||
|
" documentation of :GoRun. When val is a readable file, it is expanded to the
|
||||||
|
" full path so that go run can be executed in the current buffer's directory.
|
||||||
|
" val is return unaltered otherwise to support non-file arguments to go run.
|
||||||
|
function! s:expandRunArgs(idx, val) abort
|
||||||
|
let l:val = expand(a:val)
|
||||||
|
if !filereadable(l:val)
|
||||||
|
return l:val
|
||||||
|
endif
|
||||||
|
|
||||||
|
return fnamemodify(l:val, ':p')")
|
||||||
|
endfunction
|
||||||
" ---------------------
|
" ---------------------
|
||||||
" | Vim job callbacks |
|
" | Vim job callbacks |
|
||||||
" ---------------------
|
" ---------------------
|
||||||
|
|
|
@ -2,276 +2,48 @@
|
||||||
let s:cpo_save = &cpo
|
let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
function! s:gocodeCommand(cmd, args) abort
|
|
||||||
let l:gocode_bin = "gocode"
|
|
||||||
let l:gomod = go#util#gomod()
|
|
||||||
if filereadable(l:gomod)
|
|
||||||
let l:gocode_bin = "gocode-gomod"
|
|
||||||
endif
|
|
||||||
|
|
||||||
let bin_path = go#path#CheckBinPath(l:gocode_bin)
|
|
||||||
if empty(bin_path)
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
|
|
||||||
let socket_type = go#config#GocodeSocketType()
|
|
||||||
|
|
||||||
let cmd = [bin_path]
|
|
||||||
let cmd = extend(cmd, ['-sock', socket_type])
|
|
||||||
let cmd = extend(cmd, ['-f', 'vim'])
|
|
||||||
|
|
||||||
if go#config#GocodeProposeBuiltins()
|
|
||||||
let cmd = extend(cmd, ['-builtin'])
|
|
||||||
endif
|
|
||||||
|
|
||||||
if go#config#GocodeProposeSource()
|
|
||||||
let cmd = extend(cmd, ['-source'])
|
|
||||||
else
|
|
||||||
let cmd = extend(cmd, ['-fallback-to-source', '-cache'])
|
|
||||||
endif
|
|
||||||
|
|
||||||
if go#config#GocodeUnimportedPackages()
|
|
||||||
let cmd = extend(cmd, ['-unimported-packages'])
|
|
||||||
endif
|
|
||||||
|
|
||||||
let cmd = extend(cmd, [a:cmd])
|
|
||||||
let cmd = extend(cmd, a:args)
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:sync_gocode(cmd, args, input) abort
|
|
||||||
" We might hit cache problems, as gocode doesn't handle different GOPATHs
|
|
||||||
" well. See: https://github.com/nsf/gocode/issues/239
|
|
||||||
let old_goroot = $GOROOT
|
|
||||||
let $GOROOT = go#util#env("goroot")
|
|
||||||
|
|
||||||
try
|
|
||||||
let cmd = s:gocodeCommand(a:cmd, a:args)
|
|
||||||
" gocode can sometimes be slow, so redraw now to avoid waiting for gocode
|
|
||||||
" to return before redrawing automatically.
|
|
||||||
redraw
|
|
||||||
|
|
||||||
let [l:result, l:err] = go#util#Exec(cmd, a:input)
|
|
||||||
finally
|
|
||||||
let $GOROOT = old_goroot
|
|
||||||
endtry
|
|
||||||
|
|
||||||
if l:err != 0
|
|
||||||
return "[0, []]"
|
|
||||||
endif
|
|
||||||
|
|
||||||
if &encoding != 'utf-8'
|
|
||||||
let l:result = iconv(l:result, 'utf-8', &encoding)
|
|
||||||
endif
|
|
||||||
|
|
||||||
return l:result
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:gocodeAutocomplete() abort
|
|
||||||
" use the offset as is, because the cursor position is the position for
|
|
||||||
" which autocomplete candidates are needed.
|
|
||||||
return s:sync_gocode('autocomplete',
|
|
||||||
\ [expand('%:p'), go#util#OffsetCursor()],
|
|
||||||
\ go#util#GetLines())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" go#complete#GoInfo returns the description of the identifier under the
|
" go#complete#GoInfo returns the description of the identifier under the
|
||||||
" cursor.
|
" cursor.
|
||||||
function! go#complete#GetInfo() abort
|
function! go#complete#GetInfo() abort
|
||||||
return s:sync_info(0)
|
return go#lsp#GetInfo()
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#complete#Info(showstatus) abort
|
|
||||||
if go#util#has_job(1)
|
|
||||||
return s:async_info(1, a:showstatus)
|
|
||||||
else
|
|
||||||
return s:sync_info(1)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:async_info(echo, showstatus)
|
|
||||||
let state = {'echo': a:echo}
|
|
||||||
|
|
||||||
" explicitly bind complete to state so that within it, self will
|
|
||||||
" always refer to state. See :help Partial for more information.
|
|
||||||
let state.complete = function('s:complete', [], state)
|
|
||||||
|
|
||||||
" add 1 to the offset, so that the position at the cursor will be included
|
|
||||||
" in gocode's search
|
|
||||||
let offset = go#util#OffsetCursor()+1
|
|
||||||
|
|
||||||
" We might hit cache problems, as gocode doesn't handle different GOPATHs
|
|
||||||
" well. See: https://github.com/nsf/gocode/issues/239
|
|
||||||
let env = {
|
|
||||||
\ "GOROOT": go#util#env("goroot")
|
|
||||||
\ }
|
|
||||||
|
|
||||||
let opts = {
|
|
||||||
\ 'bang': 1,
|
|
||||||
\ 'complete': state.complete,
|
|
||||||
\ 'for': '_',
|
|
||||||
\ }
|
|
||||||
|
|
||||||
if a:showstatus
|
|
||||||
let opts.statustype = 'gocode'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let opts = go#job#Options(l:opts)
|
|
||||||
|
|
||||||
let cmd = s:gocodeCommand('autocomplete',
|
|
||||||
\ [expand('%:p'), offset])
|
|
||||||
|
|
||||||
" TODO(bc): Don't write the buffer to a file; pass the buffer directly to
|
|
||||||
" gocode's stdin. It shouldn't be necessary to use {in_io: 'file', in_name:
|
|
||||||
" s:gocodeFile()}, but unfortunately {in_io: 'buffer', in_buf: bufnr('%')}
|
|
||||||
" doesn't work.
|
|
||||||
call extend(opts, {
|
|
||||||
\ 'env': env,
|
|
||||||
\ 'in_io': 'file',
|
|
||||||
\ 'in_name': s:gocodeFile(),
|
|
||||||
\ })
|
|
||||||
|
|
||||||
call go#job#Start(cmd, opts)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:complete(job, exit_status, messages) abort dict
|
|
||||||
if a:exit_status != 0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
if &encoding != 'utf-8'
|
|
||||||
let i = 0
|
|
||||||
while i < len(a:messages)
|
|
||||||
let a:messages[i] = iconv(a:messages[i], 'utf-8', &encoding)
|
|
||||||
let i += 1
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
|
|
||||||
let result = s:info_filter(self.echo, join(a:messages, "\n"))
|
|
||||||
call s:info_complete(self.echo, result)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:gocodeFile()
|
|
||||||
let file = tempname()
|
|
||||||
call writefile(go#util#GetLines(), file)
|
|
||||||
return file
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:sync_info(echo)
|
|
||||||
" add 1 to the offset, so that the position at the cursor will be included
|
|
||||||
" in gocode's search
|
|
||||||
let offset = go#util#OffsetCursor()+1
|
|
||||||
|
|
||||||
let result = s:sync_gocode('autocomplete',
|
|
||||||
\ [expand('%:p'), offset],
|
|
||||||
\ go#util#GetLines())
|
|
||||||
|
|
||||||
let result = s:info_filter(a:echo, result)
|
|
||||||
return s:info_complete(a:echo, result)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:info_filter(echo, result) abort
|
|
||||||
if empty(a:result)
|
|
||||||
return ""
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:result = eval(a:result)
|
|
||||||
if len(l:result) != 2
|
|
||||||
return ""
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:candidates = l:result[1]
|
|
||||||
if len(l:candidates) == 1
|
|
||||||
" When gocode panics in vim mode, it returns
|
|
||||||
" [0, [{'word': 'PANIC', 'abbr': 'PANIC PANIC PANIC', 'info': 'PANIC PANIC PANIC'}]]
|
|
||||||
if a:echo && l:candidates[0].info ==# "PANIC PANIC PANIC"
|
|
||||||
return ""
|
|
||||||
endif
|
|
||||||
|
|
||||||
return l:candidates[0].info
|
|
||||||
endif
|
|
||||||
|
|
||||||
let filtered = []
|
|
||||||
let wordMatch = '\<' . expand("<cword>") . '\>'
|
|
||||||
" escape single quotes in wordMatch before passing it to filter
|
|
||||||
let wordMatch = substitute(wordMatch, "'", "''", "g")
|
|
||||||
let filtered = filter(l:candidates, "v:val.info =~ '".wordMatch."'")
|
|
||||||
|
|
||||||
if len(l:filtered) == 0
|
|
||||||
return "no matches"
|
|
||||||
elseif len(l:filtered) > 1
|
|
||||||
return "ambiguous match"
|
|
||||||
endif
|
|
||||||
|
|
||||||
return l:filtered[0].info
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:info_complete(echo, result) abort
|
|
||||||
if a:echo
|
|
||||||
call go#util#ShowInfo(a:result)
|
|
||||||
endif
|
|
||||||
|
|
||||||
return a:result
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:trim_bracket(val) abort
|
|
||||||
let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '')
|
|
||||||
return a:val
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:completions = []
|
|
||||||
|
|
||||||
function! go#complete#GocodeComplete(findstart, base) abort
|
|
||||||
"findstart = 1 when we need to get the text length
|
|
||||||
if a:findstart == 1
|
|
||||||
let l:completions = []
|
|
||||||
execute "silent let l:completions = " . s:gocodeAutocomplete()
|
|
||||||
|
|
||||||
if len(l:completions) == 0 || len(l:completions) >= 2 && len(l:completions[1]) == 0
|
|
||||||
" no matches. cancel and leave completion mode.
|
|
||||||
call go#util#EchoInfo("no matches")
|
|
||||||
return -3
|
|
||||||
endif
|
|
||||||
|
|
||||||
let s:completions = l:completions[1]
|
|
||||||
return col('.') - l:completions[0] - 1
|
|
||||||
"findstart = 0 when we need to return the list of completions
|
|
||||||
else
|
|
||||||
let s = getline(".")[col('.') - 1]
|
|
||||||
if s =~ '[(){}\{\}]'
|
|
||||||
return map(copy(s:completions[1]), 's:trim_bracket(v:val)')
|
|
||||||
endif
|
|
||||||
|
|
||||||
return s:completions[1]
|
|
||||||
endif
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#complete#Complete(findstart, base) abort
|
function! go#complete#Complete(findstart, base) abort
|
||||||
let l:state = {'done': 0, 'matches': []}
|
if !go#config#GoplsEnabled()
|
||||||
|
return -3
|
||||||
|
endif
|
||||||
|
|
||||||
function! s:handler(state, matches) abort dict
|
let l:state = {'done': 0, 'matches': [], 'start': -1}
|
||||||
|
|
||||||
|
function! s:handler(state, start, matches) abort dict
|
||||||
|
let a:state.start = a:start
|
||||||
let a:state.matches = a:matches
|
let a:state.matches = a:matches
|
||||||
let a:state.done = 1
|
let a:state.done = 1
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
"findstart = 1 when we need to get the start of the match
|
"findstart = 1 when we need to get the start of the match
|
||||||
if a:findstart == 1
|
if a:findstart == 1
|
||||||
call go#lsp#Completion(expand('%:p'), line('.'), col('.'), funcref('s:handler', [l:state]))
|
let [l:line, l:col] = getpos('.')[1:2]
|
||||||
|
let [l:line, l:col] = go#lsp#lsp#Position(l:line, l:col)
|
||||||
|
let l:completion = go#lsp#Completion(expand('%:p'), l:line, l:col, funcref('s:handler', [l:state]))
|
||||||
|
if l:completion
|
||||||
|
return -3
|
||||||
|
endif
|
||||||
|
|
||||||
while !l:state.done
|
while !l:state.done
|
||||||
sleep 10m
|
sleep 10m
|
||||||
endwhile
|
endwhile
|
||||||
|
|
||||||
let s:completions = l:state.matches
|
|
||||||
|
|
||||||
if len(l:state.matches) == 0
|
if len(l:state.matches) == 0
|
||||||
" no matches. cancel and leave completion mode.
|
" no matches. cancel and leave completion mode.
|
||||||
call go#util#EchoInfo("no matches")
|
call go#util#EchoInfo("no matches")
|
||||||
return -3
|
return -3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return col('.')
|
let s:completions = l:state.matches
|
||||||
|
|
||||||
|
return go#lsp#lsp#PositionOf(getline(l:line+1), l:state.start-1)
|
||||||
|
|
||||||
else "findstart = 0 when we need to return the list of completions
|
else "findstart = 0 when we need to return the list of completions
|
||||||
return s:completions
|
return s:completions
|
||||||
endif
|
endif
|
||||||
|
@ -281,11 +53,11 @@ function! go#complete#ToggleAutoTypeInfo() abort
|
||||||
if go#config#AutoTypeInfo()
|
if go#config#AutoTypeInfo()
|
||||||
call go#config#SetAutoTypeInfo(0)
|
call go#config#SetAutoTypeInfo(0)
|
||||||
call go#util#EchoProgress("auto type info disabled")
|
call go#util#EchoProgress("auto type info disabled")
|
||||||
return
|
else
|
||||||
end
|
call go#config#SetAutoTypeInfo(1)
|
||||||
|
call go#util#EchoProgress("auto type info enabled")
|
||||||
call go#config#SetAutoTypeInfo(1)
|
endif
|
||||||
call go#util#EchoProgress("auto type info enabled")
|
call go#auto#update_autocmd()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
|
|
|
@ -2,23 +2,24 @@
|
||||||
let s:cpo_save = &cpo
|
let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
func! Test_GetInfo()
|
func! Test_GetInfo_gopls()
|
||||||
|
let g:go_info_mode = 'gopls'
|
||||||
|
call s:getinfo()
|
||||||
|
unlet g:go_info_mode
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
func! s:getinfo()
|
||||||
let l:filename = 'complete/complete.go'
|
let l:filename = 'complete/complete.go'
|
||||||
let l:tmp = gotest#load_fixture(l:filename)
|
let l:tmp = gotest#load_fixture(l:filename)
|
||||||
|
try
|
||||||
|
call cursor(8, 3)
|
||||||
|
|
||||||
call cursor(8, 3)
|
let expected = 'func Example(s string)'
|
||||||
|
let actual = go#complete#GetInfo()
|
||||||
let g:go_info_mode = 'gocode'
|
call assert_equal(expected, actual)
|
||||||
let expected = 'func Example(s string)'
|
finally
|
||||||
let actual = go#complete#GetInfo()
|
call delete(l:tmp, 'rf')
|
||||||
call assert_equal(expected, actual)
|
endtry
|
||||||
|
|
||||||
let g:go_info_mode = 'guru'
|
|
||||||
call go#config#InfoMode()
|
|
||||||
let actual = go#complete#GetInfo()
|
|
||||||
call assert_equal(expected, actual)
|
|
||||||
|
|
||||||
unlet g:go_info_mode
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
|
|
|
@ -21,10 +21,12 @@ endfunction
|
||||||
function! go#config#SetBuildTags(value) abort
|
function! go#config#SetBuildTags(value) abort
|
||||||
if a:value is ''
|
if a:value is ''
|
||||||
silent! unlet g:go_build_tags
|
silent! unlet g:go_build_tags
|
||||||
|
call go#lsp#ResetWorkspaceDirectories()
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let g:go_build_tags = a:value
|
let g:go_build_tags = a:value
|
||||||
|
call go#lsp#ResetWorkspaceDirectories()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#TestTimeout() abort
|
function! go#config#TestTimeout() abort
|
||||||
|
@ -47,8 +49,23 @@ function! go#config#TermMode() abort
|
||||||
return get(g:, 'go_term_mode', 'vsplit')
|
return get(g:, 'go_term_mode', 'vsplit')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#TermCloseOnExit() abort
|
||||||
|
return get(g:, 'go_term_close_on_exit', 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#TermReuse() abort
|
||||||
|
return get(g:, 'go_term_reuse', 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#SetTermCloseOnExit(value) abort
|
||||||
|
let g:go_term_close_on_exit = a:value
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#TermEnabled() abort
|
function! go#config#TermEnabled() abort
|
||||||
return has('nvim') && get(g:, 'go_term_enabled', 0)
|
" nvim always support
|
||||||
|
" vim will support if terminal feature exists
|
||||||
|
let l:support = has('nvim') || has('terminal')
|
||||||
|
return support && get(g:, 'go_term_enabled', 0)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#SetTermEnabled(value) abort
|
function! go#config#SetTermEnabled(value) abort
|
||||||
|
@ -72,7 +89,18 @@ function! go#config#StatuslineDuration() abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#SnippetEngine() abort
|
function! go#config#SnippetEngine() abort
|
||||||
return get(g:, 'go_snippet_engine', 'automatic')
|
let l:engine = get(g:, 'go_snippet_engine', 'automatic')
|
||||||
|
if l:engine is? "automatic"
|
||||||
|
if get(g:, 'did_plugin_ultisnips') is 1
|
||||||
|
let l:engine = 'ultisnips'
|
||||||
|
elseif get(g:, 'loaded_neosnippet') is 1
|
||||||
|
let l:engine = 'neosnippet'
|
||||||
|
elseif get(g:, 'loaded_minisnip') is 1
|
||||||
|
let l:engine = 'minisnip'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
return l:engine
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#PlayBrowserCommand() abort
|
function! go#config#PlayBrowserCommand() abort
|
||||||
|
@ -114,7 +142,7 @@ function! go#config#ListAutoclose() abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#InfoMode() abort
|
function! go#config#InfoMode() abort
|
||||||
return get(g:, 'go_info_mode', 'gocode')
|
return get(g:, 'go_info_mode', 'gopls')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GuruScope() abort
|
function! go#config#GuruScope() abort
|
||||||
|
@ -139,30 +167,13 @@ function! go#config#SetGuruScope(scope) abort
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GocodeUnimportedPackages() abort
|
|
||||||
return get(g:, 'go_gocode_unimported_packages', 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix'
|
|
||||||
function! go#config#GocodeSocketType() abort
|
|
||||||
return get(g:, 'go_gocode_socket_type', s:sock_type)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#config#GocodeProposeBuiltins() abort
|
|
||||||
return get(g:, 'go_gocode_propose_builtins', 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#config#GocodeProposeSource() abort
|
|
||||||
return get(g:, 'go_gocode_propose_source', 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#config#EchoCommandInfo() abort
|
function! go#config#EchoCommandInfo() abort
|
||||||
return get(g:, 'go_echo_command_info', 1)
|
return get(g:, 'go_echo_command_info', 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#DocUrl() abort
|
function! go#config#DocUrl() abort
|
||||||
let godoc_url = get(g:, 'go_doc_url', 'https://godoc.org')
|
let godoc_url = get(g:, 'go_doc_url', 'https://pkg.go.dev')
|
||||||
if godoc_url isnot 'https://godoc.org'
|
if godoc_url isnot 'https://pkg.go.dev'
|
||||||
" strip last '/' character if available
|
" strip last '/' character if available
|
||||||
let last_char = strlen(godoc_url) - 1
|
let last_char = strlen(godoc_url) - 1
|
||||||
if godoc_url[last_char] == '/'
|
if godoc_url[last_char] == '/'
|
||||||
|
@ -174,12 +185,15 @@ function! go#config#DocUrl() abort
|
||||||
return godoc_url
|
return godoc_url
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#DocPopupWindow() abort
|
||||||
|
return get(g:, 'go_doc_popup_window', 0)
|
||||||
|
endfunction
|
||||||
function! go#config#DefReuseBuffer() abort
|
function! go#config#DefReuseBuffer() abort
|
||||||
return get(g:, 'go_def_reuse_buffer', 0)
|
return get(g:, 'go_def_reuse_buffer', 0)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#DefMode() abort
|
function! go#config#DefMode() abort
|
||||||
return get(g:, 'go_def_mode', 'guru')
|
return get(g:, 'go_def_mode', 'gopls')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#DeclsIncludes() abort
|
function! go#config#DeclsIncludes() abort
|
||||||
|
@ -192,9 +206,10 @@ endfunction
|
||||||
|
|
||||||
function! go#config#DebugWindows() abort
|
function! go#config#DebugWindows() abort
|
||||||
return get(g:, 'go_debug_windows', {
|
return get(g:, 'go_debug_windows', {
|
||||||
\ 'stack': 'leftabove 20vnew',
|
|
||||||
\ 'out': 'botright 10new',
|
|
||||||
\ 'vars': 'leftabove 30vnew',
|
\ 'vars': 'leftabove 30vnew',
|
||||||
|
\ 'stack': 'leftabove 20new',
|
||||||
|
\ 'goroutines': 'botright 10new',
|
||||||
|
\ 'out': 'botright 5new',
|
||||||
\ }
|
\ }
|
||||||
\ )
|
\ )
|
||||||
|
|
||||||
|
@ -211,7 +226,7 @@ function! go#config#DebugCommands() abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#DebugLogOutput() abort
|
function! go#config#DebugLogOutput() abort
|
||||||
return get(g:, 'go_debug_log_output', 'debugger, rpc')
|
return get(g:, 'go_debug_log_output', 'debugger,rpc')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#LspLog() abort
|
function! go#config#LspLog() abort
|
||||||
|
@ -236,6 +251,10 @@ function! go#config#AddtagsTransform() abort
|
||||||
return get(g:, 'go_addtags_transform', "snakecase")
|
return get(g:, 'go_addtags_transform', "snakecase")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#AddtagsSkipUnexported() abort
|
||||||
|
return get(g:, 'go_addtags_skip_unexported', 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#TemplateAutocreate() abort
|
function! go#config#TemplateAutocreate() abort
|
||||||
return get(g:, "go_template_autocreate", 1)
|
return get(g:, "go_template_autocreate", 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -245,31 +264,15 @@ function! go#config#SetTemplateAutocreate(value) abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#MetalinterCommand() abort
|
function! go#config#MetalinterCommand() abort
|
||||||
return get(g:, "go_metalinter_command", "gometalinter")
|
return get(g:, "go_metalinter_command", "golangci-lint")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#MetalinterAutosaveEnabled() abort
|
function! go#config#MetalinterAutosaveEnabled() abort
|
||||||
let l:default_enabled = ["vet", "golint"]
|
return get(g:, "go_metalinter_autosave_enabled", ["govet", "golint"])
|
||||||
|
|
||||||
if go#config#MetalinterCommand() == "golangci-lint"
|
|
||||||
let l:default_enabled = ["govet", "golint"]
|
|
||||||
endif
|
|
||||||
|
|
||||||
return get(g:, "go_metalinter_autosave_enabled", default_enabled)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#MetalinterEnabled() abort
|
function! go#config#MetalinterEnabled() abort
|
||||||
let l:default_enabled = ["vet", "golint", "errcheck"]
|
return get(g:, "go_metalinter_enabled", ["vet", "golint", "errcheck"])
|
||||||
|
|
||||||
if go#config#MetalinterCommand() == "golangci-lint"
|
|
||||||
let l:default_enabled = ["govet", "golint"]
|
|
||||||
endif
|
|
||||||
|
|
||||||
return get(g:, "go_metalinter_enabled", default_enabled)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! go#config#MetalinterDisabled() abort
|
|
||||||
return get(g:, "go_metalinter_disabled", [])
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GolintBin() abort
|
function! go#config#GolintBin() abort
|
||||||
|
@ -296,6 +299,10 @@ function! go#config#FmtAutosave() abort
|
||||||
return get(g:, "go_fmt_autosave", 1)
|
return get(g:, "go_fmt_autosave", 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#ImportsAutosave() abort
|
||||||
|
return get(g:, 'go_imports_autosave', 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#SetFmtAutosave(value) abort
|
function! go#config#SetFmtAutosave(value) abort
|
||||||
let g:go_fmt_autosave = a:value
|
let g:go_fmt_autosave = a:value
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -340,8 +347,12 @@ function! go#config#FmtCommand() abort
|
||||||
return get(g:, "go_fmt_command", "gofmt")
|
return get(g:, "go_fmt_command", "gofmt")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#ImportsMode() abort
|
||||||
|
return get(g:, "go_imports_mode", "goimports")
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#FmtOptions() abort
|
function! go#config#FmtOptions() abort
|
||||||
return get(g:, "go_fmt_options", {})
|
return get(b:, "go_fmt_options", get(g:, "go_fmt_options", {}))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#FmtFailSilently() abort
|
function! go#config#FmtFailSilently() abort
|
||||||
|
@ -356,8 +367,13 @@ function! go#config#PlayOpenBrowser() abort
|
||||||
return get(g:, "go_play_open_browser", 1)
|
return get(g:, "go_play_open_browser", 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#RenameCommand() abort
|
||||||
|
" delegate to go#config#GorenameBin for backwards compatability.
|
||||||
|
return get(g:, "go_rename_command", go#config#GorenameBin())
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#GorenameBin() abort
|
function! go#config#GorenameBin() abort
|
||||||
return get(g:, "go_gorename_bin", "gorename")
|
return get(g:, "go_gorename_bin", "gopls")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#config#GorenamePrefill() abort
|
function! go#config#GorenamePrefill() abort
|
||||||
|
@ -451,10 +467,22 @@ function! go#config#HighlightVariableDeclarations() abort
|
||||||
return get(g:, 'go_highlight_variable_declarations', 0)
|
return get(g:, 'go_highlight_variable_declarations', 0)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#HighlightDiagnosticErrors() abort
|
||||||
|
return get(g:, 'go_highlight_diagnostic_errors', 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#HighlightDiagnosticWarnings() abort
|
||||||
|
return get(g:, 'go_highlight_diagnostic_warnings', 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#HighlightDebug() abort
|
function! go#config#HighlightDebug() abort
|
||||||
return get(g:, 'go_highlight_debug', 1)
|
return get(g:, 'go_highlight_debug', 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#DebugBreakpointSignText() abort
|
||||||
|
return get(g:, 'go_debug_breakpoint_sign_text', '>')
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#config#FoldEnable(...) abort
|
function! go#config#FoldEnable(...) abort
|
||||||
if a:0 > 0
|
if a:0 > 0
|
||||||
return index(go#config#FoldEnable(), a:1) > -1
|
return index(go#config#FoldEnable(), a:1) > -1
|
||||||
|
@ -466,6 +494,82 @@ function! go#config#EchoGoInfo() abort
|
||||||
return get(g:, "go_echo_go_info", 1)
|
return get(g:, "go_echo_go_info", 1)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#CodeCompletionEnabled() abort
|
||||||
|
return get(g:, "go_code_completion_enabled", 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#CodeCompletionIcase() abort
|
||||||
|
return get(g:, "go_code_completion_icase", 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#Updatetime() abort
|
||||||
|
let go_updatetime = get(g:, 'go_updatetime', 800)
|
||||||
|
return go_updatetime == 0 ? &updatetime : go_updatetime
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#ReferrersMode() abort
|
||||||
|
return get(g:, 'go_referrers_mode', 'gopls')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#ImplementsMode() abort
|
||||||
|
return get(g:, 'go_implements_mode', 'guru')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsCompleteUnimported() abort
|
||||||
|
return get(g:, 'go_gopls_complete_unimported', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsDeepCompletion() abort
|
||||||
|
return get(g:, 'go_gopls_deep_completion', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsMatcher() abort
|
||||||
|
if !exists('g:go_gopls_matcher') && get(g:, 'g:go_gopls_fuzzy_matching', v:null) is 1
|
||||||
|
return 'fuzzy'
|
||||||
|
endif
|
||||||
|
return get(g:, 'go_gopls_matcher', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsStaticCheck() abort
|
||||||
|
return get(g:, 'go_gopls_staticcheck', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsUsePlaceholders() abort
|
||||||
|
return get(g:, 'go_gopls_use_placeholders', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsTempModfile() abort
|
||||||
|
return get(g:, 'go_gopls_temp_modfile', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsAnalyses() abort
|
||||||
|
return get(g:, 'go_gopls_analyses', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsLocal() abort
|
||||||
|
return get(g:, 'go_gopls_local', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsGofumpt() abort
|
||||||
|
return get(g:, 'go_gopls_gofumpt', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsSettings() abort
|
||||||
|
return get(g:, 'go_gopls_settings', v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsEnabled() abort
|
||||||
|
return get(g:, 'go_gopls_enabled', 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#DiagnosticsEnabled() abort
|
||||||
|
return get(g:, 'go_diagnostics_enabled', 0)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#config#GoplsOptions() abort
|
||||||
|
return get(g:, 'go_gopls_options', ['-remote=auto'])
|
||||||
|
endfunction
|
||||||
|
|
||||||
" Set the default value. A value of "1" is a shortcut for this, for
|
" Set the default value. A value of "1" is a shortcut for this, for
|
||||||
" compatibility reasons.
|
" compatibility reasons.
|
||||||
if exists("g:go_gorename_prefill") && g:go_gorename_prefill == 1
|
if exists("g:go_gorename_prefill") && g:go_gorename_prefill == 1
|
||||||
|
|
107
pack/acp/start/vim-go/autoload/go/config_test.vim
Normal file
107
pack/acp/start/vim-go/autoload/go/config_test.vim
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
func! Test_SetBuildTags() abort
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_def_mode = 'gopls'
|
||||||
|
let l:dir = 'test-fixtures/config/buildtags'
|
||||||
|
let l:jumpstart = [0, 4, 2, 0]
|
||||||
|
|
||||||
|
execute 'e ' . printf('%s/buildtags.go', l:dir)
|
||||||
|
let l:jumpstartbuf = bufnr('')
|
||||||
|
|
||||||
|
call setpos('.', [l:jumpstartbuf, l:jumpstart[1], l:jumpstart[2], 0])
|
||||||
|
|
||||||
|
let l:expectedfilename = printf('%s/foo.go', l:dir)
|
||||||
|
|
||||||
|
let l:expected = [0, 5, 1, 0]
|
||||||
|
call assert_notequal(l:expected, l:jumpstart)
|
||||||
|
|
||||||
|
call go#def#Jump('', 0)
|
||||||
|
|
||||||
|
let l:start = reltime()
|
||||||
|
while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call assert_equal(l:expectedfilename, bufname("%"))
|
||||||
|
call assert_equal(l:expected, getpos('.'))
|
||||||
|
|
||||||
|
execute 'e ' . printf('%s/buildtags.go', l:dir)
|
||||||
|
|
||||||
|
" prepare to wait for the workspace/configuration request
|
||||||
|
let g:go_debug=['lsp']
|
||||||
|
|
||||||
|
" set the build constraint
|
||||||
|
call go#config#SetBuildTags('constrained')
|
||||||
|
|
||||||
|
" wait for the workspace/configuration request
|
||||||
|
let l:lsplog = getbufline('__GOLSP_LOG__', 1, '$')
|
||||||
|
let l:start = reltime()
|
||||||
|
while match(l:lsplog, 'workspace/configuration') == -1 && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 50m
|
||||||
|
let l:lsplog = getbufline('__GOLSP_LOG__', 1, '$')
|
||||||
|
endwhile
|
||||||
|
unlet g:go_debug
|
||||||
|
" close the __GOLSP_LOG__ window
|
||||||
|
only
|
||||||
|
|
||||||
|
" verify the cursor position within buildtags.go
|
||||||
|
call setpos('.', [l:jumpstartbuf, l:jumpstart[1], l:jumpstart[2], 0])
|
||||||
|
call assert_equal(l:jumpstart, getpos('.'))
|
||||||
|
|
||||||
|
let l:expectedfilename = printf('%s/constrainedfoo.go', l:dir)
|
||||||
|
let l:expected = [0, 6, 1, 0]
|
||||||
|
call assert_notequal(l:expected, l:jumpstart)
|
||||||
|
|
||||||
|
call go#def#Jump('', 0)
|
||||||
|
|
||||||
|
let l:start = reltime()
|
||||||
|
while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call assert_equal(l:expectedfilename, bufname("%"))
|
||||||
|
call assert_equal(l:expected, getpos('.'))
|
||||||
|
|
||||||
|
let l:lsplog = getbufline('__GOLSP_LOG__', 1, '$')
|
||||||
|
|
||||||
|
finally
|
||||||
|
call go#config#SetBuildTags('')
|
||||||
|
unlet g:go_def_mode
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_GoplsEnabled_Clear() abort
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_gopls_enabled = 0
|
||||||
|
|
||||||
|
let l:tmp = gotest#write_file('gopls_disabled.go', [
|
||||||
|
\ 'package example',
|
||||||
|
\ '',
|
||||||
|
\ 'func Example() {',
|
||||||
|
\ "\tprintln(" . '"hello, world!")',
|
||||||
|
\ '}',
|
||||||
|
\ ] )
|
||||||
|
|
||||||
|
finally
|
||||||
|
unlet g:go_gopls_enabled
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -25,10 +25,10 @@ endfunction
|
||||||
" the code. Calling it again reruns the tests and shows the last updated
|
" the code. Calling it again reruns the tests and shows the last updated
|
||||||
" coverage.
|
" coverage.
|
||||||
function! go#coverage#Buffer(bang, ...) abort
|
function! go#coverage#Buffer(bang, ...) abort
|
||||||
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
|
|
||||||
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
|
" check if the version of Vim being tested supports matchaddpos()
|
||||||
if !exists("*matchaddpos")
|
if !exists("*matchaddpos")
|
||||||
call go#util#EchoError("GoCoverage is supported with Vim version 7.4-330 or later")
|
call go#util#EchoError("GoCoverage is not supported by your version of Vim.")
|
||||||
return -1
|
return -1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,6 +10,10 @@ function! Test_GoDebugStart_RelativePackage() abort
|
||||||
call s:debug('./debug/debugmain')
|
call s:debug('./debug/debugmain')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! Test_GoDebugStart_RelativePackage_NullModule() abort
|
||||||
|
call s:debug('./debug/debugmain', 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! Test_GoDebugStart_Package() abort
|
function! Test_GoDebugStart_Package() abort
|
||||||
call s:debug('debug/debugmain')
|
call s:debug('debug/debugmain')
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -20,20 +24,21 @@ function! Test_GoDebugStart_Errors() abort
|
||||||
endif
|
endif
|
||||||
|
|
||||||
try
|
try
|
||||||
|
let l:tmp = gotest#load_fixture('debug/compilerror/main.go')
|
||||||
|
|
||||||
let l:expected = [
|
let l:expected = [
|
||||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 0, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': '# debug/compilerror'},
|
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 0, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': '# debug/compilerror'},
|
||||||
\ {'lnum': 6, 'bufnr': 7, 'col': 22, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': ' syntax error: unexpected newline, expecting comma or )'},
|
\ {'lnum': 6, 'bufnr': bufnr('%'), 'col': 22, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': ' syntax error: unexpected newline, expecting comma or )'},
|
||||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 0, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exit status 2'}
|
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 0, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exit status 2'}
|
||||||
\]
|
\]
|
||||||
call setqflist([], 'r')
|
call setqflist([], 'r')
|
||||||
|
|
||||||
let l:tmp = gotest#load_fixture('debug/compilerror/main.go')
|
|
||||||
call assert_false(exists(':GoDebugStop'))
|
call assert_false(exists(':GoDebugStop'))
|
||||||
|
|
||||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
||||||
execute l:cd . ' debug/compilerror'
|
execute l:cd . ' debug/compilerror'
|
||||||
|
|
||||||
call go#debug#Start(0)
|
call go#debug#Start('debug')
|
||||||
|
|
||||||
let l:actual = getqflist()
|
let l:actual = getqflist()
|
||||||
let l:start = reltime()
|
let l:start = reltime()
|
||||||
|
@ -52,14 +57,22 @@ function! Test_GoDebugStart_Errors() abort
|
||||||
endtry
|
endtry
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" s:debug takes 2 optional arguments. The first is a package to debug. The
|
||||||
|
" second is a flag to indicate whether to reset GOPATH after
|
||||||
|
" gotest#load_fixture is called in order to test behavior outside of GOPATH.
|
||||||
function! s:debug(...) abort
|
function! s:debug(...) abort
|
||||||
if !go#util#has_job()
|
if !go#util#has_job()
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
try
|
try
|
||||||
|
let $oldgopath = $GOPATH
|
||||||
let l:tmp = gotest#load_fixture('debug/debugmain/debugmain.go')
|
let l:tmp = gotest#load_fixture('debug/debugmain/debugmain.go')
|
||||||
|
|
||||||
|
if a:0 > 1 && a:2 == 1
|
||||||
|
let $GOPATH = $oldgopath
|
||||||
|
endif
|
||||||
|
|
||||||
call go#debug#Breakpoint(6)
|
call go#debug#Breakpoint(6)
|
||||||
|
|
||||||
call assert_false(exists(':GoDebugStop'))
|
call assert_false(exists(':GoDebugStop'))
|
||||||
|
@ -67,9 +80,9 @@ function! s:debug(...) abort
|
||||||
if a:0 == 0
|
if a:0 == 0
|
||||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
||||||
execute l:cd . ' debug/debugmain'
|
execute l:cd . ' debug/debugmain'
|
||||||
let l:job = go#debug#Start(0)
|
let l:job = go#debug#Start('debug')
|
||||||
else
|
else
|
||||||
let l:job = go#debug#Start(0, a:1)
|
let l:job = go#debug#Start('debug', a:1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:start = reltime()
|
let l:start = reltime()
|
||||||
|
|
|
@ -6,7 +6,7 @@ let s:go_stack = []
|
||||||
let s:go_stack_level = 0
|
let s:go_stack_level = 0
|
||||||
|
|
||||||
function! go#def#Jump(mode, type) abort
|
function! go#def#Jump(mode, type) abort
|
||||||
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
|
let l:fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
|
||||||
|
|
||||||
" so guru right now is slow for some people. previously we were using
|
" so guru right now is slow for some people. previously we were using
|
||||||
" godef which also has it's own quirks. But this issue come up so many
|
" godef which also has it's own quirks. But this issue come up so many
|
||||||
|
@ -66,7 +66,15 @@ function! go#def#Jump(mode, type) abort
|
||||||
let [l:out, l:err] = go#util#ExecInDir(l:cmd)
|
let [l:out, l:err] = go#util#ExecInDir(l:cmd)
|
||||||
endif
|
endif
|
||||||
elseif bin_name == 'gopls'
|
elseif bin_name == 'gopls'
|
||||||
let [l:line, l:col] = getpos('.')[1:2]
|
if !go#config#GoplsEnabled()
|
||||||
|
call go#util#EchoError("go_def_mode is 'gopls', but gopls is disabled")
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
" reset l:fname when using gopls so that the filename will be converted to
|
||||||
|
" a URI correctly on windows.
|
||||||
|
let l:fname = expand('%')
|
||||||
|
let [l:line, l:col] = go#lsp#lsp#Position()
|
||||||
" delegate to gopls, with an empty job object and an exit status of 0
|
" delegate to gopls, with an empty job object and an exit status of 0
|
||||||
" (they're irrelevant for gopls).
|
" (they're irrelevant for gopls).
|
||||||
if a:type
|
if a:type
|
||||||
|
@ -162,9 +170,9 @@ function! go#def#jump_to_declaration(out, mode, bin_name) abort
|
||||||
if filename != fnamemodify(expand("%"), ':p:gs?\\?/?')
|
if filename != fnamemodify(expand("%"), ':p:gs?\\?/?')
|
||||||
" jump to existing buffer if, 1. we have enabled it, 2. the buffer is loaded
|
" jump to existing buffer if, 1. we have enabled it, 2. the buffer is loaded
|
||||||
" and 3. there is buffer window number we switch to
|
" and 3. there is buffer window number we switch to
|
||||||
if go#config#DefReuseBuffer() && bufloaded(filename) != 0 && bufwinnr(filename) != -1
|
if go#config#DefReuseBuffer() && bufwinnr(filename) != -1
|
||||||
" jumpt to existing buffer if it exists
|
" jump to existing buffer if it exists
|
||||||
execute bufwinnr(filename) . 'wincmd w'
|
call win_gotoid(bufwinid(filename))
|
||||||
else
|
else
|
||||||
if &modified
|
if &modified
|
||||||
let cmd = 'hide edit'
|
let cmd = 'hide edit'
|
||||||
|
@ -186,7 +194,13 @@ function! go#def#jump_to_declaration(out, mode, bin_name) abort
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" open the file and jump to line and column
|
" open the file and jump to line and column
|
||||||
exec cmd fnameescape(fnamemodify(filename, ':.'))
|
try
|
||||||
|
exec cmd fnameescape(fnamemodify(filename, ':.'))
|
||||||
|
catch
|
||||||
|
if stridx(v:exception, ':E325:') < 0
|
||||||
|
call go#util#EchoError(v:exception)
|
||||||
|
endif
|
||||||
|
endtry
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
call cursor(line, col)
|
call cursor(line, col)
|
||||||
|
|
|
@ -2,19 +2,21 @@
|
||||||
let s:cpo_save = &cpo
|
let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
func! Test_jump_to_declaration_guru() abort
|
func! Test_jump_to_declaration_guru() abort
|
||||||
try
|
try
|
||||||
let l:filename = 'def/jump.go'
|
let l:filename = 'def/jump.go'
|
||||||
let lnum = 5
|
let l:lnum = 5
|
||||||
let col = 6
|
let l:col = 6
|
||||||
let l:tmp = gotest#load_fixture(l:filename)
|
let l:tmp = gotest#load_fixture(l:filename)
|
||||||
|
|
||||||
let guru_out = printf("%s:%d:%d: defined here as func main", filename, lnum, col)
|
let l:guru_out = printf("%s:%d:%d: defined here as func main", l:filename, l:lnum, l:col)
|
||||||
call go#def#jump_to_declaration(guru_out, "", 'guru')
|
call go#def#jump_to_declaration(l:guru_out, "", 'guru')
|
||||||
|
|
||||||
call assert_equal(filename, bufname("%"))
|
call assert_equal(l:filename, bufname("%"))
|
||||||
call assert_equal(lnum, getcurpos()[1])
|
call assert_equal(l:lnum, getcurpos()[1])
|
||||||
call assert_equal(col, getcurpos()[2])
|
call assert_equal(l:col, getcurpos()[2])
|
||||||
finally
|
finally
|
||||||
call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
endtry
|
endtry
|
||||||
|
@ -22,17 +24,17 @@ endfunc
|
||||||
|
|
||||||
func! Test_jump_to_declaration_godef() abort
|
func! Test_jump_to_declaration_godef() abort
|
||||||
try
|
try
|
||||||
let filename = 'def/jump.go'
|
let l:filename = 'def/jump.go'
|
||||||
let lnum = 5
|
let l:lnum = 5
|
||||||
let col = 6
|
let l:col = 6
|
||||||
let l:tmp = gotest#load_fixture(l:filename)
|
let l:tmp = gotest#load_fixture(l:filename)
|
||||||
|
|
||||||
let godef_out = printf("%s:%d:%d\ndefined here as func main", filename, lnum, col)
|
let l:godef_out = printf("%s:%d:%d\ndefined here as func main", l:filename, l:lnum, l:col)
|
||||||
call go#def#jump_to_declaration(godef_out, "", 'godef')
|
call go#def#jump_to_declaration(godef_out, "", 'godef')
|
||||||
|
|
||||||
call assert_equal(filename, bufname("%"))
|
call assert_equal(l:filename, bufname("%"))
|
||||||
call assert_equal(lnum, getcurpos()[1])
|
call assert_equal(l:lnum, getcurpos()[1])
|
||||||
call assert_equal(col, getcurpos()[2])
|
call assert_equal(l:col, getcurpos()[2])
|
||||||
finally
|
finally
|
||||||
call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
endtry
|
endtry
|
||||||
|
@ -40,33 +42,180 @@ endfunc
|
||||||
|
|
||||||
func! Test_Jump_leaves_lists() abort
|
func! Test_Jump_leaves_lists() abort
|
||||||
try
|
try
|
||||||
let filename = 'def/jump.go'
|
let l:filename = 'def/jump.go'
|
||||||
let l:tmp = gotest#load_fixture(l:filename)
|
let l:tmp = gotest#load_fixture(l:filename)
|
||||||
|
|
||||||
let expected = [{'lnum': 10, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'quux'}]
|
let l:expected = [{'lnum': 10, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'quux'}]
|
||||||
|
|
||||||
call setloclist(winnr(), copy(expected), 'r' )
|
call setloclist(0, copy(l:expected), 'r' )
|
||||||
call setqflist(copy(expected), 'r' )
|
call setqflist(copy(l:expected), 'r' )
|
||||||
|
|
||||||
let l:bufnr = bufnr('%')
|
let l:bufnr = bufnr('%')
|
||||||
call cursor(6, 7)
|
call cursor(6, 7)
|
||||||
|
|
||||||
|
if !go#util#has_job()
|
||||||
|
let g:go_def_mode='godef'
|
||||||
|
endif
|
||||||
call go#def#Jump('', 0)
|
call go#def#Jump('', 0)
|
||||||
|
|
||||||
let start = reltime()
|
if !go#util#has_job()
|
||||||
while bufnr('%') == l:bufnr && reltimefloat(reltime(start)) < 10
|
unlet g:go_def_mode
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:start = reltime()
|
||||||
|
while bufnr('%') == l:bufnr && reltimefloat(reltime(l:start)) < 10
|
||||||
sleep 100m
|
sleep 100m
|
||||||
endwhile
|
endwhile
|
||||||
|
|
||||||
let actual = getloclist(winnr())
|
let l:actual = getloclist(0)
|
||||||
call gotest#assert_quickfix(actual, expected)
|
call gotest#assert_quickfix(l:actual, l:expected)
|
||||||
|
|
||||||
let actual = getqflist()
|
let l:actual = getqflist()
|
||||||
call gotest#assert_quickfix(actual, expected)
|
call gotest#assert_quickfix(l:actual, l:expected)
|
||||||
finally
|
finally
|
||||||
call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func! Test_DefJump_gopls_simple_first() abort
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_def_mode = 'gopls'
|
||||||
|
|
||||||
|
let l:tmp = gotest#write_file('simple/firstposition/firstposition.go', [
|
||||||
|
\ 'package firstposition',
|
||||||
|
\ '',
|
||||||
|
\ 'func Example() {',
|
||||||
|
\ "\tid := " . '"foo"',
|
||||||
|
\ "\tprintln(" . '"id:", id)',
|
||||||
|
\ '}',
|
||||||
|
\ ] )
|
||||||
|
|
||||||
|
let l:expected = [0, 4, 2, 0]
|
||||||
|
|
||||||
|
call assert_notequal(l:expected, getpos('.'))
|
||||||
|
|
||||||
|
call go#def#Jump('', 0)
|
||||||
|
|
||||||
|
let l:start = reltime()
|
||||||
|
while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call assert_equal(l:expected, getpos('.'))
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
unlet g:go_def_mode
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_DefJump_gopls_simple_last() abort
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_def_mode = 'gopls'
|
||||||
|
|
||||||
|
let l:tmp = gotest#write_file('simple/lastposition/lastposition.go', [
|
||||||
|
\ 'package lastposition',
|
||||||
|
\ '',
|
||||||
|
\ 'func Example() {',
|
||||||
|
\ "\tid := " . '"foo"',
|
||||||
|
\ "\tprintln(" . '"id:", id)',
|
||||||
|
\ '}',
|
||||||
|
\ ] )
|
||||||
|
|
||||||
|
let l:expected = [0, 4, 2, 0]
|
||||||
|
|
||||||
|
call assert_notequal(l:expected, getpos('.'))
|
||||||
|
|
||||||
|
call go#def#Jump('', 0)
|
||||||
|
|
||||||
|
let l:start = reltime()
|
||||||
|
while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call assert_equal(l:expected, getpos('.'))
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
unlet g:go_def_mode
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_DefJump_gopls_MultipleCodeUnit_first() abort
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_def_mode = 'gopls'
|
||||||
|
|
||||||
|
let l:tmp = gotest#write_file('multiplecodeunit/firstposition/firstposition.go', [
|
||||||
|
\ 'package firstposition',
|
||||||
|
\ '',
|
||||||
|
\ 'func Example() {',
|
||||||
|
\ "\t𐐀, id := " . '"foo", "bar"',
|
||||||
|
\ "\tprintln(" . '"(𐐀, id):", 𐐀, id)',
|
||||||
|
\ '}',
|
||||||
|
\ ] )
|
||||||
|
|
||||||
|
let l:expected = [0, 4, 8, 0]
|
||||||
|
call assert_notequal(l:expected, getpos('.'))
|
||||||
|
|
||||||
|
call go#def#Jump('', 0)
|
||||||
|
|
||||||
|
let l:start = reltime()
|
||||||
|
while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call assert_equal(l:expected, getpos('.'))
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
unlet g:go_def_mode
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
|
func! Test_DefJump_gopls_MultipleCodeUnit_last() abort
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_def_mode = 'gopls'
|
||||||
|
|
||||||
|
let l:tmp = gotest#write_file('multiplecodeunit/lastposition/lastposition.go', [
|
||||||
|
\ 'package lastposition',
|
||||||
|
\ '',
|
||||||
|
\ 'func Example() {',
|
||||||
|
\ "\t𐐀, id := " . '"foo", "bar"',
|
||||||
|
\ "\tprintln(" . '"(𐐀, id):", 𐐀, id)',
|
||||||
|
\ '}',
|
||||||
|
\ ] )
|
||||||
|
|
||||||
|
let l:expected = [0, 4, 8, 0]
|
||||||
|
call assert_notequal(l:expected, getpos('.'))
|
||||||
|
|
||||||
|
call go#def#Jump('', 0)
|
||||||
|
|
||||||
|
let l:start = reltime()
|
||||||
|
while getpos('.') != l:expected && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call assert_equal(l:expected, getpos('.'))
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
unlet g:go_def_mode
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
|
@ -6,36 +6,25 @@
|
||||||
let s:cpo_save = &cpo
|
let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
let s:buf_nr = -1
|
let s:buf_nr = -1
|
||||||
|
|
||||||
function! go#doc#OpenBrowser(...) abort
|
function! go#doc#OpenBrowser(...) abort
|
||||||
" check if we have gogetdoc as it gives us more and accurate information.
|
if len(a:000) == 0
|
||||||
" Only supported if we have json_decode as it's not worth to parse the plain
|
let [l:out, l:err] = go#lsp#DocLink()
|
||||||
" non-json output of gogetdoc
|
|
||||||
let bin_path = go#path#CheckBinPath('gogetdoc')
|
|
||||||
if !empty(bin_path) && exists('*json_decode')
|
|
||||||
let [l:json_out, l:err] = s:gogetdoc(1)
|
|
||||||
if l:err
|
if l:err
|
||||||
call go#util#EchoError(json_out)
|
call go#util#EchoError(l:out)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let out = json_decode(json_out)
|
if len(l:out) == 0
|
||||||
if type(out) != type({})
|
call go#util#EchoWarning("could not path for doc URL")
|
||||||
call go#util#EchoError("gogetdoc output is malformed")
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let import = out["import"]
|
let l:godoc_url = printf('%s/%s', go#config#DocUrl(), l:out)
|
||||||
let name = out["name"]
|
|
||||||
let decl = out["decl"]
|
|
||||||
|
|
||||||
let godoc_url = go#config#DocUrl()
|
call go#util#OpenBrowser(l:godoc_url)
|
||||||
let godoc_url .= "/" . import
|
|
||||||
if decl !~ "^package"
|
|
||||||
let godoc_url .= "#" . name
|
|
||||||
endif
|
|
||||||
|
|
||||||
call go#util#OpenBrowser(godoc_url)
|
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -48,7 +37,7 @@ function! go#doc#OpenBrowser(...) abort
|
||||||
let exported_name = pkgs[1]
|
let exported_name = pkgs[1]
|
||||||
|
|
||||||
" example url: https://godoc.org/github.com/fatih/set#Set
|
" example url: https://godoc.org/github.com/fatih/set#Set
|
||||||
let godoc_url = go#config#DocUrl() . "/" . pkg . "#" . exported_name
|
let godoc_url = printf('%s/%s#%s', go#config#DocUrl(), pkg, exported_name)
|
||||||
call go#util#OpenBrowser(godoc_url)
|
call go#util#OpenBrowser(godoc_url)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
@ -56,11 +45,8 @@ function! go#doc#Open(newmode, mode, ...) abort
|
||||||
" With argument: run "godoc [arg]".
|
" With argument: run "godoc [arg]".
|
||||||
if len(a:000)
|
if len(a:000)
|
||||||
let [l:out, l:err] = go#util#Exec(['go', 'doc'] + a:000)
|
let [l:out, l:err] = go#util#Exec(['go', 'doc'] + a:000)
|
||||||
else " Without argument: run gogetdoc on cursor position.
|
else " Without argument: use gopls to get documentation
|
||||||
let [l:out, l:err] = s:gogetdoc(0)
|
let [l:out, l:err] = go#lsp#Doc()
|
||||||
if out == -1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if l:err
|
if l:err
|
||||||
|
@ -68,10 +54,62 @@ function! go#doc#Open(newmode, mode, ...) abort
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
call s:GodocView(a:newmode, a:mode, out)
|
call s:GodocView(a:newmode, a:mode, l:out)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:GodocView(newposition, position, content) abort
|
function! s:GodocView(newposition, position, content) abort
|
||||||
|
" popup window
|
||||||
|
if go#config#DocPopupWindow()
|
||||||
|
if exists('*popup_atcursor') && exists('*popup_clear')
|
||||||
|
call popup_clear()
|
||||||
|
|
||||||
|
let borderchars = ['-', '|', '-', '|', '+', '+', '+', '+']
|
||||||
|
if &encoding == "utf-8"
|
||||||
|
let borderchars = ['─', '│', '─', '│', '┌', '┐', '┘', '└']
|
||||||
|
endif
|
||||||
|
call popup_atcursor(split(a:content, '\n'), {
|
||||||
|
\ 'padding': [1, 1, 1, 1],
|
||||||
|
\ 'borderchars': borderchars,
|
||||||
|
\ 'border': [1, 1, 1, 1],
|
||||||
|
\ })
|
||||||
|
elseif has('nvim') && exists('*nvim_open_win')
|
||||||
|
let lines = split(a:content, '\n')
|
||||||
|
let height = 0
|
||||||
|
let width = 0
|
||||||
|
for line in lines
|
||||||
|
let lw = strdisplaywidth(line)
|
||||||
|
if lw > width
|
||||||
|
let width = lw
|
||||||
|
endif
|
||||||
|
let height += 1
|
||||||
|
endfor
|
||||||
|
let width += 1 " right margin
|
||||||
|
let max_height = go#config#DocMaxHeight()
|
||||||
|
if height > max_height
|
||||||
|
let height = max_height
|
||||||
|
endif
|
||||||
|
|
||||||
|
let buf = nvim_create_buf(v:false, v:true)
|
||||||
|
call nvim_buf_set_lines(buf, 0, -1, v:true, lines)
|
||||||
|
let opts = {
|
||||||
|
\ 'relative': 'cursor',
|
||||||
|
\ 'row': 1,
|
||||||
|
\ 'col': 0,
|
||||||
|
\ 'width': width,
|
||||||
|
\ 'height': height,
|
||||||
|
\ 'style': 'minimal',
|
||||||
|
\ }
|
||||||
|
call nvim_open_win(buf, v:true, opts)
|
||||||
|
setlocal nomodified nomodifiable filetype=godoc
|
||||||
|
|
||||||
|
" close easily with CR, Esc and q
|
||||||
|
noremap <buffer> <silent> <CR> :<C-U>close<CR>
|
||||||
|
noremap <buffer> <silent> <Esc> :<C-U>close<CR>
|
||||||
|
noremap <buffer> <silent> q :<C-U>close<CR>
|
||||||
|
endif
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
" reuse existing buffer window if it exists otherwise create a new one
|
" reuse existing buffer window if it exists otherwise create a new one
|
||||||
let is_visible = bufexists(s:buf_nr) && bufwinnr(s:buf_nr) != -1
|
let is_visible = bufexists(s:buf_nr) && bufwinnr(s:buf_nr) != -1
|
||||||
if !bufexists(s:buf_nr)
|
if !bufexists(s:buf_nr)
|
||||||
|
@ -129,23 +167,6 @@ function! s:GodocView(newposition, position, content) abort
|
||||||
nnoremap <buffer> <silent> <Esc>[ <Esc>[
|
nnoremap <buffer> <silent> <Esc>[ <Esc>[
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:gogetdoc(json) abort
|
|
||||||
let l:cmd = [
|
|
||||||
\ 'gogetdoc',
|
|
||||||
\ '-tags', go#config#BuildTags(),
|
|
||||||
\ '-pos', expand("%:p:gs!\\!/!") . ':#' . go#util#OffsetCursor()]
|
|
||||||
if a:json
|
|
||||||
let l:cmd += ['-json']
|
|
||||||
endif
|
|
||||||
|
|
||||||
if &modified
|
|
||||||
let l:cmd += ['-modified']
|
|
||||||
return go#util#Exec(l:cmd, go#util#archive())
|
|
||||||
endif
|
|
||||||
|
|
||||||
return go#util#Exec(l:cmd)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" returns the package and exported name. exported name might be empty.
|
" returns the package and exported name. exported name might be empty.
|
||||||
" ie: fmt and Println
|
" ie: fmt and Println
|
||||||
" ie: github.com/fatih/set and New
|
" ie: github.com/fatih/set and New
|
||||||
|
|
|
@ -62,7 +62,7 @@ func! Test_fillstruct_two_line() abort
|
||||||
\ '\tAddress: "",',
|
\ '\tAddress: "",',
|
||||||
\ '}) }'])
|
\ '}) }'])
|
||||||
finally
|
finally
|
||||||
"call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,30 @@ set cpo&vim
|
||||||
" this and have VimL experience, please look at the function for
|
" this and have VimL experience, please look at the function for
|
||||||
" improvements, patches are welcome :)
|
" improvements, patches are welcome :)
|
||||||
function! go#fmt#Format(withGoimport) abort
|
function! go#fmt#Format(withGoimport) abort
|
||||||
|
let l:bin_name = go#config#FmtCommand()
|
||||||
|
if a:withGoimport == 1
|
||||||
|
let l:mode = go#config#ImportsMode()
|
||||||
|
if l:mode == 'gopls'
|
||||||
|
if !go#config#GoplsEnabled()
|
||||||
|
call go#util#EchoError("go_imports_mode is 'gopls', but gopls is disabled")
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call go#lsp#Imports()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:bin_name = 'goimports'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:bin_name == 'gopls'
|
||||||
|
if !go#config#GoplsEnabled()
|
||||||
|
call go#util#EchoError("go_def_mode is 'gopls', but gopls is disabled")
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call go#lsp#Format()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
if go#config#FmtExperimental()
|
if go#config#FmtExperimental()
|
||||||
" Using winsaveview to save/restore cursor state has the problem of
|
" Using winsaveview to save/restore cursor state has the problem of
|
||||||
" closing folds on save:
|
" closing folds on save:
|
||||||
|
@ -52,20 +76,16 @@ function! go#fmt#Format(withGoimport) abort
|
||||||
let l:tmpname = tr(l:tmpname, '\', '/')
|
let l:tmpname = tr(l:tmpname, '\', '/')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let bin_name = go#config#FmtCommand()
|
|
||||||
if a:withGoimport == 1
|
|
||||||
let bin_name = "goimports"
|
|
||||||
endif
|
|
||||||
|
|
||||||
let current_col = col('.')
|
let current_col = col('.')
|
||||||
let [l:out, l:err] = go#fmt#run(bin_name, l:tmpname, expand('%'))
|
let [l:out, l:err] = go#fmt#run(l:bin_name, l:tmpname, expand('%'))
|
||||||
let diff_offset = len(readfile(l:tmpname)) - line('$')
|
let line_offset = len(readfile(l:tmpname)) - line('$')
|
||||||
|
let l:orig_line = getline('.')
|
||||||
|
|
||||||
if l:err == 0
|
if l:err == 0
|
||||||
call go#fmt#update_file(l:tmpname, expand('%'))
|
call go#fmt#update_file(l:tmpname, expand('%'))
|
||||||
elseif !go#config#FmtFailSilently()
|
elseif !go#config#FmtFailSilently()
|
||||||
let errors = s:parse_errors(expand('%'), out)
|
let l:errors = s:replace_filename(expand('%'), out)
|
||||||
call s:show_errors(errors)
|
call go#fmt#ShowErrors(l:errors)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" We didn't use the temp file, so clean up
|
" We didn't use the temp file, so clean up
|
||||||
|
@ -87,8 +107,10 @@ function! go#fmt#Format(withGoimport) abort
|
||||||
call winrestview(l:curw)
|
call winrestview(l:curw)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" be smart and jump to the line the new statement was added/removed
|
" be smart and jump to the line the new statement was added/removed and
|
||||||
call cursor(line('.') + diff_offset, current_col)
|
" adjust the column within the line
|
||||||
|
let l:lineno = line('.') + line_offset
|
||||||
|
call cursor(l:lineno, current_col + (len(getline(l:lineno)) - len(l:orig_line)))
|
||||||
|
|
||||||
" Syntax highlighting breaks less often.
|
" Syntax highlighting breaks less often.
|
||||||
syntax sync fromstart
|
syntax sync fromstart
|
||||||
|
@ -115,28 +137,12 @@ function! go#fmt#update_file(source, target)
|
||||||
" reload buffer to reflect latest changes
|
" reload buffer to reflect latest changes
|
||||||
silent edit!
|
silent edit!
|
||||||
|
|
||||||
|
call go#lsp#DidChange(expand(a:target, ':p'))
|
||||||
|
|
||||||
let &fileformat = old_fileformat
|
let &fileformat = old_fileformat
|
||||||
let &syntax = &syntax
|
let &syntax = &syntax
|
||||||
|
|
||||||
let l:listtype = go#list#Type("GoFmt")
|
call go#fmt#CleanErrors()
|
||||||
|
|
||||||
" the title information was introduced with 7.4-2200
|
|
||||||
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
|
|
||||||
if has('patch-7.4.2200')
|
|
||||||
" clean up previous list
|
|
||||||
if l:listtype == "quickfix"
|
|
||||||
let l:list_title = getqflist({'title': 1})
|
|
||||||
else
|
|
||||||
let l:list_title = getloclist(0, {'title': 1})
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
" can't check the title, so assume that the list was for go fmt.
|
|
||||||
let l:list_title = {'title': 'Format'}
|
|
||||||
endif
|
|
||||||
|
|
||||||
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
|
|
||||||
call go#list#Clean(l:listtype)
|
|
||||||
endif
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" run runs the gofmt/goimport command for the given source file and returns
|
" run runs the gofmt/goimport command for the given source file and returns
|
||||||
|
@ -169,39 +175,42 @@ function! s:fmt_cmd(bin_name, source, target)
|
||||||
return cmd
|
return cmd
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" parse_errors parses the given errors and returns a list of parsed errors
|
" replace_filename replaces the filename on each line of content with
|
||||||
function! s:parse_errors(filename, content) abort
|
" a:filename.
|
||||||
let splitted = split(a:content, '\n')
|
function! s:replace_filename(filename, content) abort
|
||||||
|
let l:errors = split(a:content, '\n')
|
||||||
|
|
||||||
" list of errors to be put into location list
|
let l:errors = map(l:errors, printf('substitute(v:val, ''^.\{-}:'', ''%s:'', '''')', a:filename))
|
||||||
let errors = []
|
return join(l:errors, "\n")
|
||||||
for line in splitted
|
|
||||||
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
|
|
||||||
if !empty(tokens)
|
|
||||||
call add(errors,{
|
|
||||||
\"filename": a:filename,
|
|
||||||
\"lnum": tokens[2],
|
|
||||||
\"col": tokens[3],
|
|
||||||
\"text": tokens[4],
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return errors
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" show_errors opens a location list and shows the given errors. If the given
|
function! go#fmt#CleanErrors() abort
|
||||||
" errors is empty, it closes the the location list
|
|
||||||
function! s:show_errors(errors) abort
|
|
||||||
let l:listtype = go#list#Type("GoFmt")
|
let l:listtype = go#list#Type("GoFmt")
|
||||||
if !empty(a:errors)
|
|
||||||
call go#list#Populate(l:listtype, a:errors, 'Format')
|
" clean up previous list
|
||||||
echohl Error | echomsg "Gofmt returned error" | echohl None
|
if l:listtype == "quickfix"
|
||||||
|
let l:list_title = getqflist({'title': 1})
|
||||||
|
else
|
||||||
|
let l:list_title = getloclist(0, {'title': 1})
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if has_key(l:list_title, 'title') && (l:list_title['title'] == 'Format' || l:list_title['title'] == 'GoMetaLinterAutoSave')
|
||||||
|
call go#list#Clean(l:listtype)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" show_errors opens a location list and shows the given errors. If errors is
|
||||||
|
" empty, it closes the the location list.
|
||||||
|
function! go#fmt#ShowErrors(errors) abort
|
||||||
|
let l:errorformat = '%f:%l:%c:\ %m'
|
||||||
|
let l:listtype = go#list#Type("GoFmt")
|
||||||
|
|
||||||
|
call go#list#ParseFormat(l:listtype, l:errorformat, a:errors, 'Format', 0)
|
||||||
|
let l:errors = go#list#Get(l:listtype)
|
||||||
|
|
||||||
" this closes the window if there are no errors or it opens
|
" this closes the window if there are no errors or it opens
|
||||||
" it if there is any
|
" it if there are any.
|
||||||
call go#list#Window(l:listtype, len(a:errors))
|
call go#list#Window(l:listtype, len(l:errors))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#fmt#ToggleFmtAutoSave() abort
|
function! go#fmt#ToggleFmtAutoSave() abort
|
||||||
|
|
|
@ -35,7 +35,7 @@ func! Test_update_file() abort
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! Test_goimports() abort
|
func! Test_goimports() abort
|
||||||
let $GOPATH = 'test-fixtures/fmt/'
|
let $GOPATH = printf('%s/%s', fnamemodify(getcwd(), ':p'), 'test-fixtures/fmt')
|
||||||
let actual_file = tempname()
|
let actual_file = tempname()
|
||||||
call writefile(readfile("test-fixtures/fmt/src/imports/goimports.go"), actual_file)
|
call writefile(readfile("test-fixtures/fmt/src/imports/goimports.go"), actual_file)
|
||||||
|
|
||||||
|
|
|
@ -232,11 +232,10 @@ function! go#guru#Describe(selected) abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#guru#DescribeInfo(showstatus) abort
|
function! go#guru#DescribeInfo(showstatus) abort
|
||||||
" json_encode() and friends are introduced with this patch (7.4.1304)
|
|
||||||
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
|
" check if the version of Vim being tested supports json_decode()
|
||||||
" nvim: https://github.com/neovim/neovim/pull/4131
|
|
||||||
if !exists("*json_decode")
|
if !exists("*json_decode")
|
||||||
call go#util#EchoError("requires 'json_decode'. Update your Vim/Neovim version.")
|
call go#util#EchoError("GoDescribeInfo requires 'json_decode'. Update your Vim/Neovim version.")
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -406,43 +405,31 @@ endfunction
|
||||||
" Show all refs to entity denoted by selected identifier
|
" Show all refs to entity denoted by selected identifier
|
||||||
function! go#guru#Referrers(selected) abort
|
function! go#guru#Referrers(selected) abort
|
||||||
let args = {
|
let args = {
|
||||||
\ 'mode': 'referrers',
|
\ 'mode': 'referrers',
|
||||||
\ 'format': 'plain',
|
\ 'format': 'plain',
|
||||||
\ 'selected': a:selected,
|
\ 'selected': a:selected,
|
||||||
\ 'needs_scope': 0,
|
\ 'needs_scope': 0,
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
call s:run_guru(args)
|
call s:run_guru(args)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#guru#SameIds(showstatus) abort
|
function! go#guru#SameIds(showstatus) abort
|
||||||
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
|
" check if the version of Vim being tested supports matchaddpos()
|
||||||
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
|
|
||||||
if !exists("*matchaddpos")
|
if !exists("*matchaddpos")
|
||||||
call go#util#EchoError("GoSameIds requires 'matchaddpos'. Update your Vim/Neovim version.")
|
call go#util#EchoError("GoSameIds requires 'matchaddpos'. Update your Vim/Neovim version.")
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" json_encode() and friends are introduced with this patch (7.4.1304)
|
" check if the version of Vim being tested supports json_decode()
|
||||||
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
|
|
||||||
" nvim: https://github.com/neovim/neovim/pull/4131
|
|
||||||
if !exists("*json_decode")
|
if !exists("*json_decode")
|
||||||
call go#util#EchoError("GoSameIds requires 'json_decode'. Update your Vim/Neovim version.")
|
call go#util#EchoError("GoSameIds requires 'json_decode'. Update your Vim/Neovim version.")
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let args = {
|
let [l:line, l:col] = getpos('.')[1:2]
|
||||||
\ 'mode': 'what',
|
let [l:line, l:col] = go#lsp#lsp#Position(l:line, l:col)
|
||||||
\ 'format': 'json',
|
call go#lsp#SameIDs(0, expand('%:p'), l:line, l:col, funcref('s:same_ids_highlight'))
|
||||||
\ 'selected': -1,
|
|
||||||
\ 'needs_scope': 0,
|
|
||||||
\ 'custom_parse': function('s:same_ids_highlight'),
|
|
||||||
\ }
|
|
||||||
if !a:showstatus
|
|
||||||
let args.disable_progress = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
call s:run_guru(args)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:same_ids_highlight(exit_val, output, mode) abort
|
function! s:same_ids_highlight(exit_val, output, mode) abort
|
||||||
|
@ -482,18 +469,26 @@ function! s:same_ids_highlight(exit_val, output, mode) abort
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let same_ids = result['sameids']
|
let same_ids = result['sameids']
|
||||||
|
|
||||||
" highlight the lines
|
" highlight the lines
|
||||||
|
let l:matches = []
|
||||||
for item in same_ids
|
for item in same_ids
|
||||||
let pos = split(item, ':')
|
let pos = split(item, ':')
|
||||||
call matchaddpos('goSameId', [[str2nr(pos[-2]), str2nr(pos[-1]), str2nr(poslen)]])
|
let l:matches = add(l:matches, [str2nr(pos[-2]), str2nr(pos[-1]), str2nr(poslen)])
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
|
call go#util#HighlightPositions('goSameId', l:matches)
|
||||||
|
|
||||||
if go#config#AutoSameids()
|
if go#config#AutoSameids()
|
||||||
" re-apply SameIds at the current cursor position at the time the buffer
|
" re-apply SameIds at the current cursor position at the time the buffer
|
||||||
" is redisplayed: e.g. :edit, :GoRename, etc.
|
" is redisplayed: e.g. :edit, :GoRename, etc.
|
||||||
augroup vim-go-sameids
|
augroup vim-go-sameids
|
||||||
autocmd! * <buffer>
|
autocmd! * <buffer>
|
||||||
autocmd BufWinEnter <buffer> nested call go#guru#SameIds(0)
|
if has('textprop')
|
||||||
|
autocmd BufReadPost <buffer> nested call go#guru#SameIds(0)
|
||||||
|
else
|
||||||
|
autocmd BufWinEnter <buffer> nested call go#guru#SameIds(0)
|
||||||
|
endif
|
||||||
augroup end
|
augroup end
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -501,15 +496,7 @@ endfunction
|
||||||
" ClearSameIds returns 0 when it removes goSameId groups and non-zero if no
|
" ClearSameIds returns 0 when it removes goSameId groups and non-zero if no
|
||||||
" goSameId groups are found.
|
" goSameId groups are found.
|
||||||
function! go#guru#ClearSameIds() abort
|
function! go#guru#ClearSameIds() abort
|
||||||
let l:cleared = 0
|
let l:cleared = go#util#ClearHighlights('goSameId')
|
||||||
|
|
||||||
let m = getmatches()
|
|
||||||
for item in m
|
|
||||||
if item['group'] == 'goSameId'
|
|
||||||
call matchdelete(item['id'])
|
|
||||||
let l:cleared = 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
if !l:cleared
|
if !l:cleared
|
||||||
return 1
|
return 1
|
||||||
|
@ -534,11 +521,11 @@ function! go#guru#AutoToggleSameIds() abort
|
||||||
call go#util#EchoProgress("sameids auto highlighting disabled")
|
call go#util#EchoProgress("sameids auto highlighting disabled")
|
||||||
call go#guru#ClearSameIds()
|
call go#guru#ClearSameIds()
|
||||||
call go#config#SetAutoSameids(0)
|
call go#config#SetAutoSameids(0)
|
||||||
return
|
else
|
||||||
|
call go#util#EchoSuccess("sameids auto highlighting enabled")
|
||||||
|
call go#config#SetAutoSameids(1)
|
||||||
endif
|
endif
|
||||||
|
call go#auto#update_autocmd()
|
||||||
call go#util#EchoSuccess("sameids auto highlighting enabled")
|
|
||||||
call go#config#SetAutoSameids(1)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
@ -565,11 +552,11 @@ function! s:parse_guru_output(exit_val, output, title) abort
|
||||||
|
|
||||||
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
|
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
|
||||||
let l:listtype = go#list#Type("_guru")
|
let l:listtype = go#list#Type("_guru")
|
||||||
call go#list#ParseFormat(l:listtype, errformat, a:output, a:title)
|
call go#list#ParseFormat(l:listtype, errformat, a:output, a:title, 0)
|
||||||
|
|
||||||
let errors = go#list#Get(l:listtype)
|
let errors = go#list#Get(l:listtype)
|
||||||
call go#list#Window(l:listtype, len(errors))
|
call go#list#Window(l:listtype, len(errors))
|
||||||
endfun
|
endfunction
|
||||||
|
|
||||||
function! go#guru#Scope(...) abort
|
function! go#guru#Scope(...) abort
|
||||||
if a:0
|
if a:0
|
||||||
|
@ -602,11 +589,9 @@ function! go#guru#DescribeBalloon() abort
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" json_encode() and friends are introduced with this patch (7.4.1304)
|
" check if the version of Vim being tested supports json_decode()
|
||||||
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
|
|
||||||
" nvim: https://github.com/neovim/neovim/pull/4131
|
|
||||||
if !exists("*json_decode")
|
if !exists("*json_decode")
|
||||||
call go#util#EchoError("requires 'json_decode'. Update your Vim/Neovim version.")
|
call go#util#EchoError("GoDescribeBalloon requires 'json_decode'. Update your Vim/Neovim version.")
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,325 @@ function! Test_gomodVersion_incompatible_highlight() abort
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
function! Test_numeric_literal_highlight() abort
|
||||||
|
syntax on
|
||||||
|
|
||||||
|
let tests = {
|
||||||
|
\ 'lone zero': {'group': 'goDecimalInt', 'value': '0'},
|
||||||
|
\ 'integer': {'group': 'goDecimalInt', 'value': '1234567890'},
|
||||||
|
\ 'integerGrouped': {'group': 'goDecimalInt', 'value': '1_234_567_890'},
|
||||||
|
\ 'integerErrorLeadingUnderscore': {'group': 'goDecimalError', 'value': '_1234_567_890'},
|
||||||
|
\ 'integerErrorTrailingUnderscore': {'group': 'goDecimalError', 'value': '1_234_567890_'},
|
||||||
|
\ 'integerErrorDoubleUnderscore': {'group': 'goDecimalError', 'value': '1_234__567_890'},
|
||||||
|
\ 'hexadecimal': {'group': 'goHexadecimalInt', 'value': '0x0123456789abdef'},
|
||||||
|
\ 'hexadecimalGrouped': {'group': 'goHexadecimalInt', 'value': '0x012_345_678_9ab_def'},
|
||||||
|
\ 'hexadecimalErrorLeading': {'group': 'goHexadecimalError', 'value': '0xg0123456789abdef'},
|
||||||
|
\ 'hexadecimalErrorTrailing': {'group': 'goHexadecimalError', 'value': '0x0123456789abdefg'},
|
||||||
|
\ 'hexadecimalErrorDoubleUnderscore': {'group': 'goHexadecimalError', 'value': '0x__0123456789abdef'},
|
||||||
|
\ 'hexadecimalErrorTrailingUnderscore': {'group': 'goHexadecimalError', 'value': '0x0123456789abdef_'},
|
||||||
|
\ 'heXadecimal': {'group': 'goHexadecimalInt', 'value': '0X0123456789abdef'},
|
||||||
|
\ 'heXadecimalErrorLeading': {'group': 'goHexadecimalError', 'value': '0Xg0123456789abdef'},
|
||||||
|
\ 'heXadecimalErrorTrailing': {'group': 'goHexadecimalError', 'value': '0X0123456789abdefg'},
|
||||||
|
\ 'octal': {'group': 'goOctalInt', 'value': '01234567'},
|
||||||
|
\ 'octalPrefix': {'group': 'goOctalInt', 'value': '0o1234567'},
|
||||||
|
\ 'octalGrouped': {'group': 'goOctalInt', 'value': '0o1_234_567'},
|
||||||
|
\ 'octalErrorLeading': {'group': 'goOctalError', 'value': '081234567'},
|
||||||
|
\ 'octalErrorTrailing': {'group': 'goOctalError', 'value': '012345678'},
|
||||||
|
\ 'octalErrorDoubleUnderscore': {'group': 'goOctalError', 'value': '0o__1234567'},
|
||||||
|
\ 'octalErrorTrailingUnderscore': {'group': 'goOctalError', 'value': '0o_123456_7_'},
|
||||||
|
\ 'octalErrorTrailingO': {'group': 'goOctalError', 'value': '0o_123456_7o'},
|
||||||
|
\ 'octalErrorTrailingX': {'group': 'goOctalError', 'value': '0o_123456_7x'},
|
||||||
|
\ 'octalErrorTrailingB': {'group': 'goOctalError', 'value': '0o_123456_7b'},
|
||||||
|
\ 'OctalPrefix': {'group': 'goOctalInt', 'value': '0O1234567'},
|
||||||
|
\ 'binaryInt': {'group': 'goBinaryInt', 'value': '0b0101'},
|
||||||
|
\ 'binaryIntGrouped': {'group': 'goBinaryInt', 'value': '0b_01_01'},
|
||||||
|
\ 'binaryErrorLeading': {'group': 'goBinaryError', 'value': '0b20101'},
|
||||||
|
\ 'binaryErrorTrailing': {'group': 'goBinaryError', 'value': '0b01012'},
|
||||||
|
\ 'binaryErrorDoubleUnderscore': {'group': 'goBinaryError', 'value': '0b_01__01'},
|
||||||
|
\ 'binaryOverrideOctal': {'group': 'goBinaryError', 'value': '0b1234567'},
|
||||||
|
\ 'binaryErrorTrailingUnderscore': {'group': 'goBinaryError', 'value': '0b_01_01_'},
|
||||||
|
\ 'BinaryInt': {'group': 'goBinaryInt', 'value': '0B0101'},
|
||||||
|
\ 'BinaryErrorLeading': {'group': 'goBinaryError', 'value': '0B20101'},
|
||||||
|
\ 'BinaryErrorTrailing': {'group': 'goBinaryError', 'value': '0B01012'},
|
||||||
|
\ }
|
||||||
|
|
||||||
|
for kv in items(tests)
|
||||||
|
let l:actual = s:numericHighlightGroupInAssignment(kv[0], kv[1].value)
|
||||||
|
call assert_equal(kv[1].group, l:actual, kv[0])
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_zero_as_index_element() abort
|
||||||
|
syntax on
|
||||||
|
|
||||||
|
let l:actual = s:numericHighlightGroupInSliceElement('zero-element', '0')
|
||||||
|
call assert_equal('goDecimalInt', l:actual)
|
||||||
|
let l:actual = s:numericHighlightGroupInMultidimensionalSliceElement('zero-element', '0')
|
||||||
|
call assert_equal('goDecimalInt', l:actual, 'multi-dimensional')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_zero_as_slice_index() abort
|
||||||
|
syntax on
|
||||||
|
|
||||||
|
let l:actual = s:numericHighlightGroupInSliceIndex('zero-index', '0')
|
||||||
|
call assert_equal('goDecimalInt', l:actual)
|
||||||
|
let l:actual = s:numericHighlightGroupInMultidimensionalSliceIndex('zero-index', '0', '0')
|
||||||
|
|
||||||
|
call assert_equal('goDecimalInt', l:actual, 'multi-dimensional')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_zero_as_start_slicing_slice() abort
|
||||||
|
syntax on
|
||||||
|
|
||||||
|
let l:actual = s:numericHighlightGroupInSliceSlicing('slice-slicing', '0', '1')
|
||||||
|
call assert_equal('goDecimalInt', l:actual)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:numericHighlightGroupInAssignment(testname, value)
|
||||||
|
let l:dir = gotest#write_file(printf('numeric/%s.go', a:testname), [
|
||||||
|
\ 'package numeric',
|
||||||
|
\ '',
|
||||||
|
\ printf("var v = %s\x1f", a:value),
|
||||||
|
\ ])
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
let l:actual = synIDattr(synID(l:pos[1], l:pos[2], 1), 'name')
|
||||||
|
return l:actual
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:numericHighlightGroupInSliceElement(testname, value)
|
||||||
|
let l:dir = gotest#write_file(printf('numeric/slice-element/%s.go', a:testname), [
|
||||||
|
\ 'package numeric',
|
||||||
|
\ '',
|
||||||
|
\ printf("v := []int{\x1f%s}", a:value),
|
||||||
|
\ ])
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
let l:actual = synIDattr(synID(l:pos[1], l:pos[2], 1), 'name')
|
||||||
|
return l:actual
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:numericHighlightGroupInMultidimensionalSliceElement(testname, value)
|
||||||
|
let l:dir = gotest#write_file(printf('numeric/slice-multidimensional-element/%s.go', a:testname), [
|
||||||
|
\ 'package numeric',
|
||||||
|
\ '',
|
||||||
|
\ printf("v := [][]int{{\x1f%s},{%s}}", a:value, a:value),
|
||||||
|
\ ])
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
let l:actual = synIDattr(synID(l:pos[1], l:pos[2], 1), 'name')
|
||||||
|
return l:actual
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:numericHighlightGroupInSliceIndex(testname, value)
|
||||||
|
let l:dir = gotest#write_file(printf('numeric/slice-index/%s.go', a:testname), [
|
||||||
|
\ 'package numeric',
|
||||||
|
\ '',
|
||||||
|
\ 'var sl []int',
|
||||||
|
\ printf("println(sl[\x1f%s])", a:value),
|
||||||
|
\ ])
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
let l:actual = synIDattr(synID(l:pos[1], l:pos[2], 1), 'name')
|
||||||
|
return l:actual
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:numericHighlightGroupInMultidimensionalSliceIndex(testname, first, second)
|
||||||
|
let l:dir = gotest#write_file(printf('numeric/slice-multidimensional-index/%s.go', a:testname), [
|
||||||
|
\ 'package numeric',
|
||||||
|
\ '',
|
||||||
|
\ 'var sl [][]int',
|
||||||
|
\ printf("println(sl[\x1f%s][%s])", a:first, a:second),
|
||||||
|
\ ])
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
let l:actual = synIDattr(synID(l:pos[1], l:pos[2], 1), 'name')
|
||||||
|
return l:actual
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:numericHighlightGroupInSliceSlicing(testname, from, to)
|
||||||
|
let l:dir = gotest#write_file(printf('numeric/slice-slicing/%s.go', a:testname), [
|
||||||
|
\ 'package numeric',
|
||||||
|
\ '',
|
||||||
|
\ 'var sl = []int{1,2}',
|
||||||
|
\ printf("println(sl[\x1f%s:%s])", a:from, a:to),
|
||||||
|
\ ])
|
||||||
|
try
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
let l:actual = synIDattr(synID(l:pos[1], l:pos[2], 1), 'name')
|
||||||
|
return l:actual
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_diagnostic_after_fmt() abort
|
||||||
|
let g:go_fmt_command = 'gofmt'
|
||||||
|
try
|
||||||
|
call s:diagnostic_after_write( [
|
||||||
|
\ 'package main',
|
||||||
|
\ 'import "fmt"',
|
||||||
|
\ '',
|
||||||
|
\ 'func main() {',
|
||||||
|
\ '',
|
||||||
|
\ "\tfmt.Println(\x1fhello)",
|
||||||
|
\ '}',
|
||||||
|
\ ], [])
|
||||||
|
finally
|
||||||
|
unlet g:go_fmt_command
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_diagnostic_after_fmt_change() abort
|
||||||
|
" craft a file that will be changed when its written (gofmt will change it).
|
||||||
|
let g:go_fmt_command = 'gofmt'
|
||||||
|
try
|
||||||
|
call s:diagnostic_after_write( [
|
||||||
|
\ 'package main',
|
||||||
|
\ 'import "fmt"',
|
||||||
|
\ '',
|
||||||
|
\ 'func main() {',
|
||||||
|
\ '',
|
||||||
|
\ "fmt.Println(\x1fhello)",
|
||||||
|
\ '}',
|
||||||
|
\ ], [])
|
||||||
|
finally
|
||||||
|
unlet g:go_fmt_command
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_diagnostic_after_fmt_cleared() abort
|
||||||
|
" craft a file that will be fixed when it is written.
|
||||||
|
let g:go_fmt_command = 'gofmt'
|
||||||
|
try
|
||||||
|
call s:diagnostic_after_write( [
|
||||||
|
\ 'package main',
|
||||||
|
\ 'import "fmt"',
|
||||||
|
\ '',
|
||||||
|
\ 'func main() {',
|
||||||
|
\ '',
|
||||||
|
\ "fmt.Println(\x1fhello)",
|
||||||
|
\ '}',
|
||||||
|
\ ], ['hello := "hello, vim-go"'])
|
||||||
|
finally
|
||||||
|
unlet g:go_fmt_command
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_diagnostic_after_reload() abort
|
||||||
|
let l:dir = gotest#write_file('diagnostic/after-reload.go', [
|
||||||
|
\ 'package main',
|
||||||
|
\ 'import "fmt"',
|
||||||
|
\ '',
|
||||||
|
\ 'func main() {',
|
||||||
|
\ '',
|
||||||
|
\ "\tfmt.Println(\x1fhello)",
|
||||||
|
\ '}',
|
||||||
|
\ ])
|
||||||
|
try
|
||||||
|
call s:check_diagnostics('', 'goDiagnosticError', 'initial')
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
edit
|
||||||
|
call setpos('.', l:pos)
|
||||||
|
call s:check_diagnostics('', 'goDiagnosticError', 'after-reload')
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:diagnostic_after_write(contents, changes) abort
|
||||||
|
syntax on
|
||||||
|
|
||||||
|
let l:dir = gotest#write_file('diagnostic/after-write.go', a:contents)
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
call s:check_diagnostics('', 'goDiagnosticError', 'initial')
|
||||||
|
|
||||||
|
" write a:changes to the previous line and make sure l:actual and
|
||||||
|
" l:expected are set so that they won't accidentally match on the next
|
||||||
|
" check.
|
||||||
|
if len(a:changes) > 0
|
||||||
|
call append(l:pos[1]-1, a:changes)
|
||||||
|
let l:actual = 'goDiagnosticError'
|
||||||
|
let l:expected = ''
|
||||||
|
else
|
||||||
|
let l:actual = ''
|
||||||
|
let l:expected = 'goDiagnosticError'
|
||||||
|
endif
|
||||||
|
|
||||||
|
write
|
||||||
|
|
||||||
|
call s:check_diagnostics(l:actual, l:expected, 'after-write')
|
||||||
|
finally
|
||||||
|
call delete(l:dir, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:check_diagnostics(actual, expected, when)
|
||||||
|
let l:actual = a:actual
|
||||||
|
let l:start = reltime()
|
||||||
|
|
||||||
|
while l:actual != a:expected && reltimefloat(reltime(l:start)) < 10
|
||||||
|
" Get the cursor position on each iteration, because the cursor postion
|
||||||
|
" may change between iterations when go#fmt#GoFmt formats, reloads the
|
||||||
|
" file, and moves the cursor to try to keep it where the user expects it
|
||||||
|
" to be when gofmt modifies the files.
|
||||||
|
let l:pos = getcurpos()
|
||||||
|
if !has('textprop')
|
||||||
|
let l:matches = getmatches()
|
||||||
|
if len(l:matches) == 0
|
||||||
|
let l:actual = ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
for l:m in l:matches
|
||||||
|
let l:matchline = l:m.pos1[0]
|
||||||
|
if len(l:m.pos1) < 2
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
let l:matchcol = get(l:m.pos1, 1, 1)
|
||||||
|
if l:pos[1] == l:matchline && l:pos[2] >= l:matchcol && l:pos[2] <= l:matchcol + l:m.pos1[2]
|
||||||
|
" Ideally, we'd check that the cursor is within the match, but when a
|
||||||
|
" tab is added on the current line, the cursor position within the
|
||||||
|
" line will stay constant while the line itself is shifted over by a
|
||||||
|
" column, so just check the line itself instead of checking a precise
|
||||||
|
" cursor location.
|
||||||
|
" if l:pos[1] == l:matchline
|
||||||
|
let l:actual = l:m.group
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
sleep 100m
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:actual = get(prop_list(l:pos[1]), 0, {'type': ''}).type
|
||||||
|
sleep 100m
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call assert_equal(a:expected, l:actual, a:when)
|
||||||
|
endfunction
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
|
@ -12,7 +12,7 @@ func! Test_impl() abort
|
||||||
call go#impl#Impl('r', 'reader', 'io.Reader')
|
call go#impl#Impl('r', 'reader', 'io.Reader')
|
||||||
call gotest#assert_buffer(1, [
|
call gotest#assert_buffer(1, [
|
||||||
\ 'func (r reader) Read(p []byte) (n int, err error) {',
|
\ 'func (r reader) Read(p []byte) (n int, err error) {',
|
||||||
\ ' panic("not implemented")',
|
\ ' panic("not implemented") // TODO: Implement',
|
||||||
\ '}'])
|
\ '}'])
|
||||||
finally
|
finally
|
||||||
call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
|
@ -33,7 +33,7 @@ func! Test_impl_get() abort
|
||||||
\ 'type reader struct {}',
|
\ 'type reader struct {}',
|
||||||
\ '',
|
\ '',
|
||||||
\ 'func (r *reader) Read(p []byte) (n int, err error) {',
|
\ 'func (r *reader) Read(p []byte) (n int, err error) {',
|
||||||
\ ' panic("not implemented")',
|
\ ' panic("not implemented") // TODO: Implement',
|
||||||
\ '}'])
|
\ '}'])
|
||||||
finally
|
finally
|
||||||
call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
|
|
44
pack/acp/start/vim-go/autoload/go/implements.vim
Normal file
44
pack/acp/start/vim-go/autoload/go/implements.vim
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
function! go#implements#Implements(selected) abort
|
||||||
|
let l:mode = go#config#ImplementsMode()
|
||||||
|
if l:mode == 'guru'
|
||||||
|
call go#guru#Implements(a:selected)
|
||||||
|
return
|
||||||
|
elseif l:mode == 'gopls'
|
||||||
|
if !go#config#GoplsEnabled()
|
||||||
|
call go#util#EchoError("go_implements_mode is 'gopls', but gopls is disabled")
|
||||||
|
endif
|
||||||
|
let [l:line, l:col] = getpos('.')[1:2]
|
||||||
|
let [l:line, l:col] = go#lsp#lsp#Position(l:line, l:col)
|
||||||
|
let l:fname = expand('%:p')
|
||||||
|
call go#lsp#Implements(l:fname, l:line, l:col, funcref('s:parse_output'))
|
||||||
|
return
|
||||||
|
else
|
||||||
|
call go#util#EchoWarning('unknown value for g:go_implements_mode')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" This uses Vim's errorformat to parse the output and put it into a quickfix
|
||||||
|
" or locationlist.
|
||||||
|
function! s:parse_output(exit_val, output, title) abort
|
||||||
|
if a:exit_val
|
||||||
|
call go#util#EchoError(a:output)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let errformat = ",%f:%l:%c:\ %m"
|
||||||
|
let l:listtype = go#list#Type("GoImplements")
|
||||||
|
call go#list#ParseFormat(l:listtype, errformat, a:output, a:title, 0)
|
||||||
|
|
||||||
|
let errors = go#list#Get(l:listtype)
|
||||||
|
call go#list#Window(l:listtype, len(errors))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -82,7 +82,7 @@ function! go#import#SwitchImport(enabled, localname, path, bang) abort
|
||||||
while line <= line("$")
|
while line <= line("$")
|
||||||
let line = line + 1
|
let line = line + 1
|
||||||
let linestr = getline(line)
|
let linestr = getline(line)
|
||||||
let m = matchlist(getline(line), '^\()\|\(\s\+\)\(\S*\s*\)"\(.\+\)"\)')
|
let m = matchlist(getline(line), '^\()\|\(\s\+\)\(\w\+\s\+\)\="\(.\+\)"\)')
|
||||||
if empty(m)
|
if empty(m)
|
||||||
if siteprefix == "" && a:enabled
|
if siteprefix == "" && a:enabled
|
||||||
" must be in the first group
|
" must be in the first group
|
||||||
|
|
35
pack/acp/start/vim-go/autoload/go/import_test.vim
Normal file
35
pack/acp/start/vim-go/autoload/go/import_test.vim
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
func! Test_SwitchImportAddIgnoresCommented()
|
||||||
|
try
|
||||||
|
let l:tmp = gotest#write_file('import/import.go', [
|
||||||
|
\ 'package import',
|
||||||
|
\ '',
|
||||||
|
\ 'import (',
|
||||||
|
\ "\t" . '// "fmt"',
|
||||||
|
\ "\t" . '"io"',
|
||||||
|
\ "\t" . '"ioutil"',
|
||||||
|
\ "\t" . '"os"',
|
||||||
|
\ ')',
|
||||||
|
\ '',
|
||||||
|
\ 'func main() {',
|
||||||
|
\ ' io.Copy(ioutil.Discard, os.Stdin)',
|
||||||
|
\ ' fmt.Println("import the package")',
|
||||||
|
\ '}',
|
||||||
|
\ ])
|
||||||
|
call go#import#SwitchImport(1, '', 'fmt', 0)
|
||||||
|
|
||||||
|
let l:actual = getline(4)
|
||||||
|
call assert_equal("\t" . '"fmt"', l:actual)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -18,20 +18,34 @@ function! s:issuebody() abort
|
||||||
for l in lines
|
for l in lines
|
||||||
let body = add(body, l)
|
let body = add(body, l)
|
||||||
|
|
||||||
if l =~ '^\* Vim version'
|
if l =~ '^<!-- :version'
|
||||||
redir => out
|
let out = execute('version')
|
||||||
silent version
|
|
||||||
redir END
|
|
||||||
let body = extend(body, split(out, "\n")[0:2])
|
let body = extend(body, split(out, "\n")[0:2])
|
||||||
elseif l =~ '^\* Go version'
|
elseif l =~ '^<!-- go version -->'
|
||||||
let [out, err] = go#util#Exec(['go', 'version'])
|
let [out, err] = go#util#Exec(['go', 'version'])
|
||||||
let body = add(body, substitute(l:out, rtrimpat, '', ''))
|
let body = add(body, substitute(l:out, rtrimpat, '', ''))
|
||||||
elseif l =~ '^\* Go environment'
|
elseif l =~ '^<!-- go env -->'
|
||||||
let [out, err] = go#util#Exec(['go', 'env'])
|
let [out, err] = go#util#ExecInDir(['go', 'env'])
|
||||||
|
let body = add(body, substitute(l:out, rtrimpat, '', ''))
|
||||||
|
elseif l=~ '^<!-- gopls version -->'
|
||||||
|
let [out, err] = go#util#Exec(['gopls', 'version'])
|
||||||
let body = add(body, substitute(l:out, rtrimpat, '', ''))
|
let body = add(body, substitute(l:out, rtrimpat, '', ''))
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
|
let body = add(body, "\n#### vim-go configuration:\n<details><summary>vim-go configuration</summary><br><pre>")
|
||||||
|
|
||||||
|
for k in keys(g:)
|
||||||
|
if k =~ '^go_'
|
||||||
|
let body = add(body, 'g:' . k . ' = ' . string(get(g:, k)))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
let body = add(body, '</pre></details>')
|
||||||
|
|
||||||
|
let body = add(body, printf("\n#### filetype detection configuration:\n<details><summary>filetype detection</summary><br><pre>%s", execute('filetype')))
|
||||||
|
let body = add(body, '</pre></details>')
|
||||||
|
|
||||||
return join(body, "\n")
|
return join(body, "\n")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,12 @@ endfunction
|
||||||
" the current window will be the window that was hosting the buffer when
|
" the current window will be the window that was hosting the buffer when
|
||||||
" the job was started. After it returns, the current window will be
|
" the job was started. After it returns, the current window will be
|
||||||
" restored to what it was before the function was called.
|
" restored to what it was before the function was called.
|
||||||
|
" 'preserveerrors':
|
||||||
|
" A function that will be passed one value, the list type. It should
|
||||||
|
" return a boolean value that indicates whether any errors encountered
|
||||||
|
" should be consider additive to the existing set of errors. This is
|
||||||
|
" mostly useful for a set of commands that are run via autocmds.
|
||||||
|
"
|
||||||
" The return value is a dictionary with these keys:
|
" The return value is a dictionary with these keys:
|
||||||
" 'callback':
|
" 'callback':
|
||||||
" A function suitable to be passed as a job callback handler. See
|
" A function suitable to be passed as a job callback handler. See
|
||||||
|
@ -61,7 +66,7 @@ function! go#job#Options(args)
|
||||||
let state = {
|
let state = {
|
||||||
\ 'winid': win_getid(winnr()),
|
\ 'winid': win_getid(winnr()),
|
||||||
\ 'dir': getcwd(),
|
\ 'dir': getcwd(),
|
||||||
\ 'jobdir': fnameescape(expand("%:p:h")),
|
\ 'jobdir': expand("%:p:h"),
|
||||||
\ 'messages': [],
|
\ 'messages': [],
|
||||||
\ 'bang': 0,
|
\ 'bang': 0,
|
||||||
\ 'for': "_job",
|
\ 'for': "_job",
|
||||||
|
@ -69,12 +74,10 @@ function! go#job#Options(args)
|
||||||
\ 'exit_status': 0,
|
\ 'exit_status': 0,
|
||||||
\ 'closed': 0,
|
\ 'closed': 0,
|
||||||
\ 'errorformat': &errorformat,
|
\ 'errorformat': &errorformat,
|
||||||
\ 'statustype' : ''
|
\ 'statustype' : '',
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
if has("patch-8.0.0902") || has('nvim')
|
let cbs.cwd = state.jobdir
|
||||||
let cbs.cwd = state.jobdir
|
|
||||||
endif
|
|
||||||
|
|
||||||
if has_key(a:args, 'bang')
|
if has_key(a:args, 'bang')
|
||||||
let state.bang = a:args.bang
|
let state.bang = a:args.bang
|
||||||
|
@ -92,6 +95,10 @@ function! go#job#Options(args)
|
||||||
let state.errorformat = a:args.errorformat
|
let state.errorformat = a:args.errorformat
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if has_key(a:args, 'preserveerrors')
|
||||||
|
let state.preserveerrors = a:args.preserveerrors
|
||||||
|
endif
|
||||||
|
|
||||||
function state.complete(job, exit_status, data)
|
function state.complete(job, exit_status, data)
|
||||||
if has_key(self, 'custom_complete')
|
if has_key(self, 'custom_complete')
|
||||||
let l:winid = win_getid(winnr())
|
let l:winid = win_getid(winnr())
|
||||||
|
@ -177,16 +184,26 @@ function! go#job#Options(args)
|
||||||
call win_gotoid(self.winid)
|
call win_gotoid(self.winid)
|
||||||
|
|
||||||
let l:listtype = go#list#Type(self.for)
|
let l:listtype = go#list#Type(self.for)
|
||||||
|
|
||||||
|
let l:preserveerrors = 0
|
||||||
|
if has_key(self, 'preserveerrors')
|
||||||
|
let l:preserveerrors = self.preserveerrors(l:listtype)
|
||||||
|
endif
|
||||||
|
|
||||||
if a:exit_status == 0
|
if a:exit_status == 0
|
||||||
call go#list#Clean(l:listtype)
|
if !l:preserveerrors
|
||||||
call win_gotoid(l:winid)
|
call go#list#Clean(l:listtype)
|
||||||
|
call win_gotoid(l:winid)
|
||||||
|
endif
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:listtype = go#list#Type(self.for)
|
let l:listtype = go#list#Type(self.for)
|
||||||
if len(a:data) == 0
|
if len(a:data) == 0
|
||||||
call go#list#Clean(l:listtype)
|
if !l:preserveerrors
|
||||||
call win_gotoid(l:winid)
|
call go#list#Clean(l:listtype)
|
||||||
|
call win_gotoid(l:winid)
|
||||||
|
endif
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -195,8 +212,8 @@ function! go#job#Options(args)
|
||||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
||||||
try
|
try
|
||||||
" parse the errors relative to self.jobdir
|
" parse the errors relative to self.jobdir
|
||||||
execute l:cd self.jobdir
|
execute l:cd fnameescape(self.jobdir)
|
||||||
call go#list#ParseFormat(l:listtype, self.errorformat, out, self.for)
|
call go#list#ParseFormat(l:listtype, self.errorformat, out, self.for, l:preserveerrors)
|
||||||
let errors = go#list#Get(l:listtype)
|
let errors = go#list#Get(l:listtype)
|
||||||
finally
|
finally
|
||||||
execute l:cd fnameescape(self.dir)
|
execute l:cd fnameescape(self.dir)
|
||||||
|
@ -295,11 +312,6 @@ function! go#job#Start(cmd, options)
|
||||||
let l:manualcd = 1
|
let l:manualcd = 1
|
||||||
let dir = getcwd()
|
let dir = getcwd()
|
||||||
execute l:cd fnameescape(filedir)
|
execute l:cd fnameescape(filedir)
|
||||||
elseif !(has("patch-8.0.0902") || has('nvim'))
|
|
||||||
let l:manualcd = 1
|
|
||||||
let l:dir = l:options.cwd
|
|
||||||
execute l:cd fnameescape(l:dir)
|
|
||||||
call remove(l:options, 'cwd')
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if has_key(l:options, '_start')
|
if has_key(l:options, '_start')
|
||||||
|
|
53
pack/acp/start/vim-go/autoload/go/job_test.vim
Normal file
53
pack/acp/start/vim-go/autoload/go/job_test.vim
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
func! Test_JobDirWithSpaces()
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:filename = 'job/dir has spaces/main.go'
|
||||||
|
let l:tmp = gotest#load_fixture(l:filename)
|
||||||
|
exe 'cd ' . fnameescape(l:tmp . '/src/job/dir has spaces')
|
||||||
|
|
||||||
|
" set the compiler type so that the errorformat option will be set
|
||||||
|
" correctly.
|
||||||
|
compiler go
|
||||||
|
|
||||||
|
let expected = [{'lnum': 4, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'undefined: notafunc'}]
|
||||||
|
" clear the quickfix lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
" go build discards any results when it compiles multiple packages. So we
|
||||||
|
" pass the `errors` package just as a placeholder with the current folder
|
||||||
|
" (indicated with '.').
|
||||||
|
let l:cmd = ['go', 'build', '.', 'errors']
|
||||||
|
|
||||||
|
let l:complete = go#promise#New(function('s:complete'), 10000, '')
|
||||||
|
call go#job#Spawn(l:cmd, {
|
||||||
|
\ 'for': 'GoBuild',
|
||||||
|
\ 'complete': l:complete.wrapper,
|
||||||
|
\ 'statustype': 'build'
|
||||||
|
\})
|
||||||
|
|
||||||
|
let l:out = l:complete.await()
|
||||||
|
|
||||||
|
let actual = getqflist()
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, l:expected)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! s:complete(job, exit_code, messages)
|
||||||
|
return a:messages
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -3,30 +3,36 @@ let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
function! go#lint#Gometa(bang, autosave, ...) abort
|
function! go#lint#Gometa(bang, autosave, ...) abort
|
||||||
if a:0 == 0
|
|
||||||
let goargs = [expand('%:p:h')]
|
|
||||||
else
|
|
||||||
let goargs = a:000
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:metalinter = go#config#MetalinterCommand()
|
let l:metalinter = go#config#MetalinterCommand()
|
||||||
|
|
||||||
if l:metalinter == 'gometalinter' || l:metalinter == 'golangci-lint'
|
if a:0 == 0
|
||||||
let cmd = s:metalintercmd(l:metalinter)
|
let l:goargs = [expand('%:p:h')]
|
||||||
|
if l:metalinter == 'gopls'
|
||||||
|
let l:pkg = go#package#ImportPath()
|
||||||
|
if l:pkg == -1
|
||||||
|
call go#util#EchoError('could not determine package name')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:goargs = [l:pkg]
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
let l:goargs = a:000
|
||||||
|
endif
|
||||||
|
|
||||||
|
let cmd = []
|
||||||
|
if l:metalinter == 'golangci-lint'
|
||||||
|
let linters = a:autosave ? go#config#MetalinterAutosaveEnabled() : go#config#MetalinterEnabled()
|
||||||
|
let cmd = s:metalintercmd(l:metalinter, len(linters) != 0)
|
||||||
if empty(cmd)
|
if empty(cmd)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" linters
|
" add linters to cmd
|
||||||
let linters = a:autosave ? go#config#MetalinterAutosaveEnabled() : go#config#MetalinterEnabled()
|
|
||||||
for linter in linters
|
for linter in linters
|
||||||
let cmd += ["--enable=".linter]
|
let cmd += ["--enable=".linter]
|
||||||
endfor
|
endfor
|
||||||
|
elseif l:metalinter != 'gopls'
|
||||||
for linter in go#config#MetalinterDisabled()
|
|
||||||
let cmd += ["--disable=".linter]
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
" the user wants something else, let us use it.
|
" the user wants something else, let us use it.
|
||||||
let cmd = split(go#config#MetalinterCommand(), " ")
|
let cmd = split(go#config#MetalinterCommand(), " ")
|
||||||
endif
|
endif
|
||||||
|
@ -36,15 +42,8 @@ function! go#lint#Gometa(bang, autosave, ...) abort
|
||||||
" will be cleared
|
" will be cleared
|
||||||
redraw
|
redraw
|
||||||
|
|
||||||
if l:metalinter == "gometalinter"
|
if l:metalinter == "golangci-lint"
|
||||||
" Include only messages for the active buffer for autosave.
|
let l:goargs[0] = expand('%:p:h')
|
||||||
let include = [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))]
|
|
||||||
if go#util#has_job()
|
|
||||||
let include = [printf('--include=^%s:.*$', expand('%:p:t'))]
|
|
||||||
endif
|
|
||||||
let cmd += include
|
|
||||||
elseif l:metalinter == "golangci-lint"
|
|
||||||
let goargs[0] = expand('%:p')
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -54,139 +53,288 @@ function! go#lint#Gometa(bang, autosave, ...) abort
|
||||||
let cmd += ["--deadline=" . deadline]
|
let cmd += ["--deadline=" . deadline]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let cmd += goargs
|
let cmd += l:goargs
|
||||||
|
|
||||||
if l:metalinter == "gometalinter"
|
let errformat = s:errorformat(l:metalinter)
|
||||||
" Gometalinter can output one of the two, so we look for both:
|
|
||||||
" <file>:<line>:<column>:<severity>: <message> (<linter>)
|
if l:metalinter == 'gopls'
|
||||||
" <file>:<line>::<severity>: <message> (<linter>)
|
if a:autosave
|
||||||
" This can be defined by the following errorformat:
|
let l:messages = go#lsp#AnalyzeFile(expand('%:p'))
|
||||||
let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m"
|
else
|
||||||
|
let l:import_paths = l:goargs
|
||||||
|
let l:messages = call('go#lsp#Diagnostics', l:import_paths)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:err = len(l:messages)
|
||||||
else
|
else
|
||||||
" Golangci-lint can output the following:
|
if go#util#has_job()
|
||||||
" <file>:<line>:<column>: <message> (<linter>)
|
if a:autosave
|
||||||
" This can be defined by the following errorformat:
|
let l:for = 'GoMetaLinterAutoSave'
|
||||||
let errformat = "%f:%l:%c:\ %m"
|
else
|
||||||
endif
|
let l:for = 'GoMetaLinter'
|
||||||
|
endif
|
||||||
|
|
||||||
if go#util#has_job()
|
call s:lint_job(l:metalinter, {'cmd': cmd, 'statustype': l:metalinter, 'errformat': errformat, 'for': l:for}, a:bang, a:autosave)
|
||||||
call s:lint_job({'cmd': cmd, 'statustype': l:metalinter, 'errformat': errformat}, a:bang, a:autosave)
|
return
|
||||||
return
|
endif
|
||||||
endif
|
|
||||||
|
|
||||||
let [l:out, l:err] = go#util#Exec(cmd)
|
let [l:out, l:err] = go#util#Exec(cmd)
|
||||||
|
let l:messages = split(out, "\n")
|
||||||
|
endif
|
||||||
|
|
||||||
if a:autosave
|
if a:autosave
|
||||||
let l:listtype = go#list#Type("GoMetaLinterAutoSave")
|
let l:listtype = go#list#Type('GoMetaLinterAutoSave')
|
||||||
|
let l:for = 'GoMetaLinterAutoSave'
|
||||||
else
|
else
|
||||||
let l:listtype = go#list#Type("GoMetaLinter")
|
let l:listtype = go#list#Type('GoMetaLinter')
|
||||||
|
let l:for = 'GoMetaLinterAuto'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if l:err == 0
|
if l:err == 0
|
||||||
call go#list#Clean(l:listtype)
|
if !s:preserveerrors(a:autosave, l:listtype)
|
||||||
echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None
|
call go#list#Clean(l:listtype)
|
||||||
|
endif
|
||||||
|
call go#util#EchoSuccess('[metalinter] PASS')
|
||||||
else
|
else
|
||||||
let l:winid = win_getid(winnr())
|
let l:winid = win_getid(winnr())
|
||||||
" Parse and populate our location list
|
" Parse and populate our location list
|
||||||
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter')
|
|
||||||
|
if a:autosave
|
||||||
|
call s:metalinterautosavecomplete(l:metalinter, fnamemodify(expand('%:p'), ":."), 0, 1, l:messages)
|
||||||
|
endif
|
||||||
|
call go#list#ParseFormat(l:listtype, errformat, l:messages, l:for, s:preserveerrors(a:autosave, l:listtype))
|
||||||
|
|
||||||
let errors = go#list#Get(l:listtype)
|
let errors = go#list#Get(l:listtype)
|
||||||
call go#list#Window(l:listtype, len(errors))
|
call go#list#Window(l:listtype, len(errors))
|
||||||
|
|
||||||
if a:autosave || a:bang
|
if a:autosave || a:bang
|
||||||
call win_gotoid(l:winid)
|
call win_gotoid(l:winid)
|
||||||
|
else
|
||||||
|
call go#list#JumpToFirst(l:listtype)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lint#Diagnostics(bang, ...) abort
|
||||||
|
if a:0 == 0
|
||||||
|
let l:pkg = go#package#ImportPath()
|
||||||
|
if l:pkg == -1
|
||||||
|
call go#util#EchoError('could not determine package name')
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
call go#list#JumpToFirst(l:listtype)
|
|
||||||
|
let l:import_paths = [l:pkg]
|
||||||
|
else
|
||||||
|
let l:import_paths = a:000
|
||||||
|
endif
|
||||||
|
|
||||||
|
let errformat = s:errorformat('gopls')
|
||||||
|
|
||||||
|
let l:messages = call('go#lsp#Diagnostics', l:import_paths)
|
||||||
|
|
||||||
|
let l:listtype = go#list#Type("GoDiagnostics")
|
||||||
|
|
||||||
|
if len(l:messages) == 0
|
||||||
|
call go#list#Clean(l:listtype)
|
||||||
|
call go#util#EchoSuccess('[diagnostics] PASS')
|
||||||
|
else
|
||||||
|
" Parse and populate the quickfix list
|
||||||
|
let l:winid = win_getid(winnr())
|
||||||
|
call go#list#ParseFormat(l:listtype, errformat, l:messages, 'GoDiagnostics', 0)
|
||||||
|
|
||||||
|
let errors = go#list#Get(l:listtype)
|
||||||
|
call go#list#Window(l:listtype, len(errors))
|
||||||
|
|
||||||
|
if a:bang
|
||||||
|
call win_gotoid(l:winid)
|
||||||
|
else
|
||||||
|
call go#list#JumpToFirst(l:listtype)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Golint calls 'golint' on the current directory. Any warnings are populated in
|
" Golint calls 'golint' on the current directory. Any warnings are populated in
|
||||||
" the location list
|
" the location list
|
||||||
function! go#lint#Golint(bang, ...) abort
|
function! go#lint#Golint(bang, ...) abort
|
||||||
|
call go#cmd#autowrite()
|
||||||
|
|
||||||
|
let l:type = 'golint'
|
||||||
|
let l:status = {
|
||||||
|
\ 'desc': 'current status',
|
||||||
|
\ 'type': l:type,
|
||||||
|
\ 'state': "started",
|
||||||
|
\ }
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoProgress(printf('[%s] analyzing...', l:type))
|
||||||
|
endif
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
|
|
||||||
if a:0 == 0
|
if a:0 == 0
|
||||||
let [l:out, l:err] = go#util#Exec([go#config#GolintBin(), go#package#ImportPath()])
|
let [l:out, l:err] = go#util#Exec([go#config#GolintBin(), expand('%:p:h')])
|
||||||
else
|
else
|
||||||
let [l:out, l:err] = go#util#Exec([go#config#GolintBin()] + a:000)
|
let [l:out, l:err] = go#util#Exec([go#config#GolintBin()] + a:000)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if empty(l:out)
|
let l:status.state = 'success'
|
||||||
call go#util#EchoSuccess('[lint] PASS')
|
let l:state = 'PASS'
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:winid = win_getid(winnr())
|
|
||||||
let l:listtype = go#list#Type("GoLint")
|
let l:listtype = go#list#Type("GoLint")
|
||||||
call go#list#Parse(l:listtype, l:out, "GoLint")
|
if !empty(l:out)
|
||||||
let l:errors = go#list#Get(l:listtype)
|
let l:status.state = 'failed'
|
||||||
call go#list#Window(l:listtype, len(l:errors))
|
let l:state = 'FAIL'
|
||||||
|
|
||||||
if a:bang
|
let l:winid = win_getid(winnr())
|
||||||
call win_gotoid(l:winid)
|
call go#list#Parse(l:listtype, l:out, "GoLint", 0)
|
||||||
return
|
let l:errors = go#list#Get(l:listtype)
|
||||||
|
call go#list#Window(l:listtype, len(l:errors))
|
||||||
|
|
||||||
|
if a:bang
|
||||||
|
call win_gotoid(l:winid)
|
||||||
|
else
|
||||||
|
call go#list#JumpToFirst(l:listtype)
|
||||||
|
endif
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoError(printf('[%s] %s', l:type, l:state))
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
call go#list#Clean(l:listtype)
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoSuccess(printf('[%s] %s', l:type, l:state))
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
call go#list#JumpToFirst(l:listtype)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Vet calls 'go vet' on the current directory. Any warnings are populated in
|
" Vet calls 'go vet' on the current buffer's directory. Any warnings are
|
||||||
" the location list
|
" populated in the location list
|
||||||
function! go#lint#Vet(bang, ...) abort
|
function! go#lint#Vet(bang, ...) abort
|
||||||
call go#cmd#autowrite()
|
call go#cmd#autowrite()
|
||||||
|
|
||||||
if go#config#EchoCommandInfo()
|
let l:cmd = ['go', 'vet']
|
||||||
call go#util#EchoProgress('calling vet...')
|
|
||||||
|
let buildtags = go#config#BuildTags()
|
||||||
|
if buildtags isnot ''
|
||||||
|
let l:cmd += ['-tags', buildtags]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if a:0 == 0
|
if a:0 == 0
|
||||||
let [l:out, l:err] = go#util#Exec(['go', 'vet', go#package#ImportPath()])
|
let l:import_path = go#package#ImportPath()
|
||||||
|
if l:import_path == -1
|
||||||
|
call go#util#EchoError('could not determine package')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let l:cmd = add(l:cmd, l:import_path)
|
||||||
else
|
else
|
||||||
let [l:out, l:err] = go#util#Exec(['go', 'tool', 'vet'] + a:000)
|
let l:cmd = extend(l:cmd, a:000)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let l:type = 'go vet'
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoProgress(printf('[%s] analyzing...', l:type))
|
||||||
|
endif
|
||||||
|
let l:status = {
|
||||||
|
\ 'desc': 'current status',
|
||||||
|
\ 'type': l:type,
|
||||||
|
\ 'state': "started",
|
||||||
|
\ }
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
|
|
||||||
|
let [l:out, l:err] = go#util#ExecInDir(l:cmd)
|
||||||
|
|
||||||
|
let l:status.state = 'success'
|
||||||
|
let l:state = 'PASS'
|
||||||
|
|
||||||
let l:listtype = go#list#Type("GoVet")
|
let l:listtype = go#list#Type("GoVet")
|
||||||
if l:err != 0
|
if l:err != 0
|
||||||
|
let l:status.state = 'failed'
|
||||||
|
let l:state = 'FAIL'
|
||||||
|
|
||||||
let l:winid = win_getid(winnr())
|
let l:winid = win_getid(winnr())
|
||||||
let errorformat = "%-Gexit status %\\d%\\+," . &errorformat
|
let l:errorformat = "%-Gexit status %\\d%\\+," . &errorformat
|
||||||
call go#list#ParseFormat(l:listtype, l:errorformat, out, "GoVet")
|
let l:dir = go#util#Chdir(expand('%:p:h'))
|
||||||
let errors = go#list#Get(l:listtype)
|
try
|
||||||
call go#list#Window(l:listtype, len(errors))
|
call go#list#ParseFormat(l:listtype, l:errorformat, out, "GoVet", 0)
|
||||||
if !empty(errors) && !a:bang
|
finally
|
||||||
|
call go#util#Chdir(l:dir)
|
||||||
|
endtry
|
||||||
|
let l:errors = go#list#Get(l:listtype)
|
||||||
|
|
||||||
|
if empty(l:errors)
|
||||||
|
call go#util#EchoError(l:out)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
call go#list#Window(l:listtype, len(l:errors))
|
||||||
|
if !empty(l:errors) && !a:bang
|
||||||
call go#list#JumpToFirst(l:listtype)
|
call go#list#JumpToFirst(l:listtype)
|
||||||
else
|
else
|
||||||
call win_gotoid(l:winid)
|
call win_gotoid(l:winid)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoError(printf('[%s] %s', l:type, l:state))
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
call go#list#Clean(l:listtype)
|
call go#list#Clean(l:listtype)
|
||||||
call go#util#EchoSuccess('[vet] PASS')
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoSuccess(printf('[%s] %s', l:type, l:state))
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" ErrCheck calls 'errcheck' for the given packages. Any warnings are populated in
|
" ErrCheck calls 'errcheck' for the given packages. Any warnings are populated in
|
||||||
" the location list
|
" the location list
|
||||||
function! go#lint#Errcheck(bang, ...) abort
|
function! go#lint#Errcheck(bang, ...) abort
|
||||||
if a:0 == 0
|
call go#cmd#autowrite()
|
||||||
let l:import_path = go#package#ImportPath()
|
|
||||||
if import_path == -1
|
let l:cmd = [go#config#ErrcheckBin(), '-abspath']
|
||||||
call go#util#EchoError('package is not inside GOPATH src')
|
|
||||||
return
|
let buildtags = go#config#BuildTags()
|
||||||
endif
|
if buildtags isnot ''
|
||||||
else
|
let l:cmd += ['-tags', buildtags]
|
||||||
let l:import_path = join(a:000, ' ')
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
call go#util#EchoProgress('[errcheck] analysing ...')
|
if a:0 == 0
|
||||||
|
let l:import_path = go#package#ImportPath()
|
||||||
|
if l:import_path == -1
|
||||||
|
call go#util#EchoError('could not determine package')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let l:cmd = add(l:cmd, l:import_path)
|
||||||
|
else
|
||||||
|
let l:cmd = extend(l:cmd, a:000)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:type = 'errcheck'
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoProgress(printf('[%s] analyzing...', l:type))
|
||||||
|
endif
|
||||||
|
let l:status = {
|
||||||
|
\ 'desc': 'current status',
|
||||||
|
\ 'type': l:type,
|
||||||
|
\ 'state': "started",
|
||||||
|
\ }
|
||||||
redraw
|
redraw
|
||||||
|
|
||||||
let [l:out, l:err] = go#util#Exec([go#config#ErrcheckBin(), '-abspath', l:import_path])
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
|
|
||||||
|
let [l:out, l:err] = go#util#ExecInDir(l:cmd)
|
||||||
|
|
||||||
|
let l:status.state = 'success'
|
||||||
|
let l:state = 'PASS'
|
||||||
|
|
||||||
let l:listtype = go#list#Type("GoErrCheck")
|
let l:listtype = go#list#Type("GoErrCheck")
|
||||||
if l:err != 0
|
if l:err != 0
|
||||||
let l:winid = win_getid(winnr())
|
let l:status.state = 'failed'
|
||||||
let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m"
|
let l:state = 'FAIL'
|
||||||
|
|
||||||
" Parse and populate our location list
|
let l:winid = win_getid(winnr())
|
||||||
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'Errcheck')
|
|
||||||
|
if l:err == 1
|
||||||
|
let l:errformat = "%f:%l:%c:\ %m,%f:%l:%c\ %#%m"
|
||||||
|
" Parse and populate our location list
|
||||||
|
call go#list#ParseFormat(l:listtype, l:errformat, split(out, "\n"), 'Errcheck', 0)
|
||||||
|
endif
|
||||||
|
|
||||||
let l:errors = go#list#Get(l:listtype)
|
let l:errors = go#list#Get(l:listtype)
|
||||||
if empty(l:errors)
|
if empty(l:errors)
|
||||||
|
@ -195,18 +343,24 @@ function! go#lint#Errcheck(bang, ...) abort
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if !empty(errors)
|
if !empty(errors)
|
||||||
call go#list#Populate(l:listtype, errors, 'Errcheck')
|
call go#list#Populate(l:listtype, l:errors, 'Errcheck')
|
||||||
call go#list#Window(l:listtype, len(errors))
|
call go#list#Window(l:listtype, len(l:errors))
|
||||||
if !a:bang
|
if !a:bang
|
||||||
call go#list#JumpToFirst(l:listtype)
|
call go#list#JumpToFirst(l:listtype)
|
||||||
else
|
else
|
||||||
call win_gotoid(l:winid)
|
call win_gotoid(l:winid)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoError(printf('[%s] %s', l:type, l:state))
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
call go#list#Clean(l:listtype)
|
call go#list#Clean(l:listtype)
|
||||||
call go#util#EchoSuccess('[errcheck] PASS')
|
if go#config#EchoCommandInfo()
|
||||||
|
call go#util#EchoSuccess(printf('[%s] %s', l:type, l:state))
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
call go#statusline#Update(expand('%:p:h'), l:status)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#lint#ToggleMetaLinterAutoSave() abort
|
function! go#lint#ToggleMetaLinterAutoSave() abort
|
||||||
|
@ -220,16 +374,19 @@ function! go#lint#ToggleMetaLinterAutoSave() abort
|
||||||
call go#util#EchoProgress("auto metalinter enabled")
|
call go#util#EchoProgress("auto metalinter enabled")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:lint_job(args, bang, autosave)
|
function! s:lint_job(metalinter, args, bang, autosave)
|
||||||
let l:opts = {
|
let l:opts = {
|
||||||
\ 'statustype': a:args.statustype,
|
\ 'statustype': a:args.statustype,
|
||||||
\ 'errorformat': a:args.errformat,
|
\ 'errorformat': a:args.errformat,
|
||||||
\ 'for': "GoMetaLinter",
|
\ 'for': 'GoMetaLinter',
|
||||||
\ 'bang': a:bang,
|
\ 'bang': a:bang,
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
if a:autosave
|
if a:autosave
|
||||||
let l:opts.for = "GoMetaLinterAutoSave"
|
let l:opts.for = 'GoMetaLinterAutoSave'
|
||||||
|
" s:metalinterautosavecomplete is really only needed for golangci-lint
|
||||||
|
let l:opts.complete = funcref('s:metalinterautosavecomplete', [a:metalinter, expand('%:p:t')])
|
||||||
|
let l:opts.preserveerrors = funcref('s:preserveerrors', [a:autosave])
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" autowrite is not enabled for jobs
|
" autowrite is not enabled for jobs
|
||||||
|
@ -238,45 +395,72 @@ function! s:lint_job(args, bang, autosave)
|
||||||
call go#job#Spawn(a:args.cmd, l:opts)
|
call go#job#Spawn(a:args.cmd, l:opts)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:metalintercmd(metalinter)
|
function! s:metalintercmd(metalinter, haslinter)
|
||||||
let l:cmd = []
|
let l:cmd = []
|
||||||
let bin_path = go#path#CheckBinPath(a:metalinter)
|
let bin_path = go#path#CheckBinPath(a:metalinter)
|
||||||
if !empty(bin_path)
|
if !empty(bin_path)
|
||||||
if a:metalinter == "gometalinter"
|
if a:metalinter == "golangci-lint"
|
||||||
let l:cmd = s:gometalintercmd(bin_path)
|
let l:cmd = s:golangcilintcmd(bin_path, a:haslinter)
|
||||||
elseif a:metalinter == "golangci-lint"
|
|
||||||
let l:cmd = s:golangcilintcmd(bin_path)
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:gometalintercmd(bin_path)
|
function! s:golangcilintcmd(bin_path, haslinter)
|
||||||
let cmd = [a:bin_path]
|
|
||||||
let cmd += ["--disable-all"]
|
|
||||||
|
|
||||||
" gometalinter has a --tests flag to tell its linters whether to run
|
|
||||||
" against tests. While not all of its linters respect this flag, for those
|
|
||||||
" that do, it means if we don't pass --tests, the linter won't run against
|
|
||||||
" test files. One example of a linter that will not run against tests if
|
|
||||||
" we do not specify this flag is errcheck.
|
|
||||||
let cmd += ["--tests"]
|
|
||||||
return cmd
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:golangcilintcmd(bin_path)
|
|
||||||
let cmd = [a:bin_path]
|
let cmd = [a:bin_path]
|
||||||
let cmd += ["run"]
|
let cmd += ["run"]
|
||||||
let cmd += ["--print-issued-lines=false"]
|
let cmd += ["--print-issued-lines=false"]
|
||||||
let cmd += ["--disable-all"]
|
let cmd += ['--build-tags', go#config#BuildTags()]
|
||||||
" do not use the default exclude patterns, because doing so causes golint
|
" do not use the default exclude patterns, because doing so causes golint
|
||||||
" problems about missing doc strings to be ignored and other things that
|
" problems about missing doc strings to be ignored and other things that
|
||||||
" golint identifies.
|
" golint identifies.
|
||||||
let cmd += ["--exclude-use-default=false"]
|
let cmd += ["--exclude-use-default=false"]
|
||||||
|
|
||||||
|
if a:haslinter
|
||||||
|
let cmd += ["--disable-all"]
|
||||||
|
endif
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! s:metalinterautosavecomplete(metalinter, filepath, job, exit_code, messages)
|
||||||
|
if a:metalinter != 'golangci-lint'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if len(a:messages) == 0
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:idx = len(a:messages) - 1
|
||||||
|
while l:idx >= 0
|
||||||
|
" leave in any messages that report errors about a:filepath or that report
|
||||||
|
" more general problems that prevent golangci-lint from linting
|
||||||
|
" a:filepath.
|
||||||
|
if a:messages[l:idx] !~# '^' . a:filepath . ':' && a:messages[l:idx] !~# '^level='
|
||||||
|
call remove(a:messages, l:idx)
|
||||||
|
endif
|
||||||
|
let l:idx -= 1
|
||||||
|
endwhile
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:errorformat(metalinter) abort
|
||||||
|
if a:metalinter == 'golangci-lint'
|
||||||
|
" Golangci-lint can output the following:
|
||||||
|
" <file>:<line>:<column>: <message> (<linter>)
|
||||||
|
" This can be defined by the following errorformat:
|
||||||
|
return 'level=%tarning\ msg="%m:\ [%f:%l:%c:\ %.%#]",level=%tarning\ msg="%m",level=%trror\ msg="%m:\ [%f:%l:%c:\ %.%#]",level=%trror\ msg="%m",%f:%l:%c:\ %m,%f:%l\ %m'
|
||||||
|
elseif a:metalinter == 'gopls'
|
||||||
|
return '%f:%l:%c:%t:\ %m,%f:%l:%c::\ %m,%f:%l::%t:\ %m'
|
||||||
|
endif
|
||||||
|
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:preserveerrors(autosave, listtype) abort
|
||||||
|
return a:autosave && a:listtype == go#list#Type("GoFmt") && go#config#FmtAutosave() && isdirectory(expand('%:p:h'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
|
@ -2,23 +2,24 @@
|
||||||
let s:cpo_save = &cpo
|
let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
func! Test_Gometa() abort
|
|
||||||
call s:gometa('gometaliner')
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
func! Test_GometaGolangciLint() abort
|
func! Test_GometaGolangciLint() abort
|
||||||
call s:gometa('golangci-lint')
|
call s:gometa('golangci-lint')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! s:gometa(metalinter) abort
|
func! s:gometa(metalinter) abort
|
||||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnamemodify(getcwd(), ':p') . 'test-fixtures/lint')
|
||||||
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
||||||
|
|
||||||
try
|
try
|
||||||
let g:go_metalinter_comand = a:metalinter
|
let g:go_metalinter_command = a:metalinter
|
||||||
let expected = [
|
let expected = [
|
||||||
\ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
|
\ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
|
||||||
\ ]
|
\ ]
|
||||||
|
if a:metalinter == 'golangci-lint'
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 5, 'bufnr': bufnr('%')+5, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function `MissingFooDoc` should have comment or be unexported (golint)'}
|
||||||
|
\ ]
|
||||||
|
endif
|
||||||
|
|
||||||
" clear the quickfix lists
|
" clear the quickfix lists
|
||||||
call setqflist([], 'r')
|
call setqflist([], 'r')
|
||||||
|
@ -36,34 +37,32 @@ func! s:gometa(metalinter) abort
|
||||||
|
|
||||||
call gotest#assert_quickfix(actual, expected)
|
call gotest#assert_quickfix(actual, expected)
|
||||||
finally
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
unlet g:go_metalinter_enabled
|
unlet g:go_metalinter_enabled
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! Test_GometaWithDisabled() abort
|
func! Test_GometaGolangciLint_shadow() abort
|
||||||
call s:gometawithdisabled('gometalinter')
|
call s:gometa_shadow('golangci-lint')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! Test_GometaWithDisabledGolangciLint() abort
|
func! s:gometa_shadow(metalinter) abort
|
||||||
call s:gometawithdisabled('golangci-lint')
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnamemodify(getcwd(), ':p') . 'test-fixtures/lint')
|
||||||
endfunc
|
silent exe 'e ' . $GOPATH . '/src/lint/golangci-lint/problems/shadow/problems.go'
|
||||||
|
|
||||||
func! s:gometawithdisabled(metalinter) abort
|
|
||||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
|
||||||
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
|
||||||
|
|
||||||
try
|
try
|
||||||
let g:go_metalinter_comand = a:metalinter
|
let g:go_metalinter_command = a:metalinter
|
||||||
let expected = [
|
let expected = [
|
||||||
\ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
|
\ {'lnum': 4, 'bufnr': bufnr('%'), 'col': 7, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'module': '', 'text': '[runner] Can''t run linter golint: golint: analysis skipped: errors in package'},
|
||||||
|
\ {'lnum': 4, 'bufnr': bufnr('%'), 'col': 7, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'e', 'module': '', 'text': 'Running error: golint: analysis skipped: errors in package'}
|
||||||
\ ]
|
\ ]
|
||||||
|
|
||||||
" clear the quickfix lists
|
" clear the quickfix lists
|
||||||
call setqflist([], 'r')
|
call setqflist([], 'r')
|
||||||
|
|
||||||
let g:go_metalinter_disabled = ['vet']
|
let g:go_metalinter_enabled = ['golint']
|
||||||
|
|
||||||
call go#lint#Gometa(0, 0, $GOPATH . '/src/foo')
|
call go#lint#Gometa(0, 0)
|
||||||
|
|
||||||
let actual = getqflist()
|
let actual = getqflist()
|
||||||
let start = reltime()
|
let start = reltime()
|
||||||
|
@ -74,58 +73,305 @@ func! s:gometawithdisabled(metalinter) abort
|
||||||
|
|
||||||
call gotest#assert_quickfix(actual, expected)
|
call gotest#assert_quickfix(actual, expected)
|
||||||
finally
|
finally
|
||||||
unlet g:go_metalinter_disabled
|
call call(RestoreGOPATH, [])
|
||||||
|
unlet g:go_metalinter_enabled
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! Test_GometaAutoSave() abort
|
|
||||||
call s:gometaautosave('gometalinter')
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
func! Test_GometaAutoSaveGolangciLint() abort
|
func! Test_GometaAutoSaveGolangciLint() abort
|
||||||
call s:gometaautosave('golangci-lint')
|
call s:gometaautosave('golangci-lint', 0)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! s:gometaautosave(metalinter) abort
|
func! Test_GometaAutoSaveKeepsErrors() abort
|
||||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
call s:gometaautosave('golangci-lint', 1)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! s:gometaautosave(metalinter, withList) abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint')
|
||||||
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
||||||
|
|
||||||
try
|
try
|
||||||
let g:go_metalinter_comand = a:metalinter
|
let g:go_metalinter_command = a:metalinter
|
||||||
let expected = [
|
let l:expected = [
|
||||||
\ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'}
|
\ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'}
|
||||||
\ ]
|
\ ]
|
||||||
|
if a:metalinter == 'golangci-lint'
|
||||||
|
let l:expected = [
|
||||||
|
\ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function `MissingDoc` should have comment or be unexported (golint)'}
|
||||||
|
\ ]
|
||||||
|
endif
|
||||||
|
|
||||||
let winnr = winnr()
|
let l:list = []
|
||||||
|
if a:withList
|
||||||
|
let l:list = [
|
||||||
|
\ {'lnum': 1, 'bufnr': 1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'before metalinter'}
|
||||||
|
\ ]
|
||||||
|
let l:expected = extend(l:list, l:expected)
|
||||||
|
endif
|
||||||
|
|
||||||
" clear the location lists
|
" set the location lists
|
||||||
call setloclist(l:winnr, [], 'r')
|
call setloclist(0, l:list, 'r')
|
||||||
|
|
||||||
let g:go_metalinter_autosave_enabled = ['golint']
|
let g:go_metalinter_autosave_enabled = ['golint']
|
||||||
|
|
||||||
call go#lint#Gometa(0, 1)
|
call go#lint#Gometa(0, 1)
|
||||||
|
|
||||||
let actual = getloclist(l:winnr)
|
let l:actual = getloclist(0)
|
||||||
|
let l:start = reltime()
|
||||||
|
while len(l:actual) != len(l:expected) && reltimefloat(reltime(l:start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let l:actual = getloclist(0)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(l:actual, l:expected)
|
||||||
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
|
unlet g:go_metalinter_autosave_enabled
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_GometaGolangciLint_importabs() abort
|
||||||
|
call s:gometa_importabs('golangci-lint')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! s:gometa_importabs(metalinter) abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnamemodify(getcwd(), ':p') . 'test-fixtures/lint')
|
||||||
|
silent exe 'e ' . $GOPATH . '/src/lint/golangci-lint/problems/importabs/problems.go'
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_metalinter_command = a:metalinter
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 3, 'bufnr': bufnr('%'), 'col': 8, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'module': '', 'text': '[runner] Can''t run linter golint: golint: analysis skipped: errors in package'},
|
||||||
|
\ {'lnum': 3, 'bufnr': bufnr('%'), 'col': 8, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'e', 'module': '', 'text': 'Running error: golint: analysis skipped: errors in package'},
|
||||||
|
\ ]
|
||||||
|
" clear the quickfix lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
let g:go_metalinter_enabled = ['golint']
|
||||||
|
|
||||||
|
call go#lint#Gometa(0, 0)
|
||||||
|
|
||||||
|
let actual = getqflist()
|
||||||
let start = reltime()
|
let start = reltime()
|
||||||
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
sleep 100m
|
sleep 100m
|
||||||
let actual = getloclist(l:winnr)
|
let actual = getqflist()
|
||||||
endwhile
|
endwhile
|
||||||
|
|
||||||
call gotest#assert_quickfix(actual, expected)
|
call gotest#assert_quickfix(actual, expected)
|
||||||
finally
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
|
unlet g:go_metalinter_enabled
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_GometaAutoSaveGolangciLint_importabs() abort
|
||||||
|
call s:gometaautosave_importabs('golangci-lint')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! s:gometaautosave_importabs(metalinter) abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint')
|
||||||
|
silent exe 'e ' . $GOPATH . '/src/lint/golangci-lint/problems/importabs/ok.go'
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_metalinter_command = a:metalinter
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 3, 'bufnr': bufnr('%')+1, 'col': 8, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'module': '', 'text': '[runner] Can''t run linter golint: golint: analysis skipped: errors in package'},
|
||||||
|
\ {'lnum': 3, 'bufnr': bufnr('%')+1, 'col': 8, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'e', 'module': '', 'text': 'Running error: golint: analysis skipped: errors in package'}
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setloclist(0, [], 'r')
|
||||||
|
|
||||||
|
let g:go_metalinter_autosave_enabled = ['golint']
|
||||||
|
|
||||||
|
call go#lint#Gometa(0, 1)
|
||||||
|
|
||||||
|
let actual = getloclist(0)
|
||||||
|
let start = reltime()
|
||||||
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let actual = getloclist(0)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, expected)
|
||||||
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
|
unlet g:go_metalinter_autosave_enabled
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_GometaGolangciLint_multiple() abort
|
||||||
|
call s:gometa_multiple('golangci-lint')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! s:gometa_multiple(metalinter) abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnamemodify(getcwd(), ':p') . 'test-fixtures/lint')
|
||||||
|
silent exe 'e ' . $GOPATH . '/src/lint/golangci-lint/problems/multiple/problems.go'
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_metalinter_command = a:metalinter
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 8, 'bufnr': bufnr('%'), 'col': 7, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'module': '', 'text': '[runner] Can''t run linter golint: golint: analysis skipped: errors in package'},
|
||||||
|
\ {'lnum': 8, 'bufnr': bufnr('%'), 'col': 7, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'e', 'module': '', 'text': 'Running error: golint: analysis skipped: errors in package'},
|
||||||
|
\ ]
|
||||||
|
" clear the quickfix lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
let g:go_metalinter_enabled = ['golint']
|
||||||
|
|
||||||
|
call go#lint#Gometa(0, 0)
|
||||||
|
|
||||||
|
let actual = getqflist()
|
||||||
|
let start = reltime()
|
||||||
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let actual = getqflist()
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, expected)
|
||||||
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
|
unlet g:go_metalinter_enabled
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_GometaAutoSaveGolangciLint_multiple() abort
|
||||||
|
call s:gometaautosave_multiple('golangci-lint')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! s:gometaautosave_multiple(metalinter) abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint')
|
||||||
|
silent exe 'e ' . $GOPATH . '/src/lint/golangci-lint/problems/multiple/problems.go'
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_metalinter_command = a:metalinter
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 8, 'bufnr': bufnr('%'), 'col': 7, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'module': '', 'text': '[runner] Can''t run linter golint: golint: analysis skipped: errors in package'},
|
||||||
|
\ {'lnum': 8, 'bufnr': bufnr('%'), 'col': 7, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'e', 'module': '', 'text': 'Running error: golint: analysis skipped: errors in package'},
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setloclist(0, [], 'r')
|
||||||
|
|
||||||
|
let g:go_metalinter_autosave_enabled = ['golint']
|
||||||
|
|
||||||
|
call go#lint#Gometa(0, 1)
|
||||||
|
|
||||||
|
let actual = getloclist(0)
|
||||||
|
let start = reltime()
|
||||||
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let actual = getloclist(0)
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, expected)
|
||||||
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
unlet g:go_metalinter_autosave_enabled
|
unlet g:go_metalinter_autosave_enabled
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! Test_Vet() abort
|
func! Test_Vet() abort
|
||||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
let l:tmp = gotest#load_fixture('lint/src/vet/vet.go')
|
||||||
silent exe 'e ' . $GOPATH . '/src/vet/vet.go'
|
|
||||||
|
try
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '',
|
||||||
|
\ 'text': 'Printf format %d has arg str of wrong type string'}
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
let winnr = winnr()
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
call go#lint#Vet(1)
|
||||||
|
|
||||||
|
let actual = getqflist()
|
||||||
|
let start = reltime()
|
||||||
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let actual = getqflist()
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, expected)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Vet_subdir() abort
|
||||||
|
let l:tmp = gotest#load_fixture('lint/src/vet/vet.go')
|
||||||
|
|
||||||
|
" go up one directory to easily test that go vet's file paths are handled
|
||||||
|
" correctly when the working directory is not the directory that contains
|
||||||
|
" the file being vetted.
|
||||||
|
call go#util#Chdir('..')
|
||||||
|
|
||||||
|
try
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '',
|
||||||
|
\ 'text': 'Printf format %d has arg str of wrong type string'}
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
let winnr = winnr()
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
call go#lint#Vet(1)
|
||||||
|
|
||||||
|
let actual = getqflist()
|
||||||
|
let start = reltime()
|
||||||
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let actual = getqflist()
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, expected)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Vet_compilererror() abort
|
||||||
|
let l:tmp = gotest#load_fixture('lint/src/vet/compilererror/compilererror.go')
|
||||||
|
|
||||||
|
try
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 6, 'bufnr': bufnr('%'), 'col': 22, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': "missing ',' before newline in argument list (and 1 more errors)"}
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
let winnr = winnr()
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
call go#lint#Vet(1)
|
||||||
|
|
||||||
|
let actual = getqflist()
|
||||||
|
let start = reltime()
|
||||||
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let actual = getqflist()
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, expected)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Lint_GOPATH() abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint')
|
||||||
|
|
||||||
|
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
||||||
compiler go
|
compiler go
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
\ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '',
|
\ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported'},
|
||||||
\ 'text': 'Printf format %d has arg str of wrong type string'}
|
\ {'lnum': 5, 'bufnr': bufnr('%')+7, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function AlsoMissingDoc should have comment or be unexported'}
|
||||||
\ ]
|
\ ]
|
||||||
|
|
||||||
let winnr = winnr()
|
let winnr = winnr()
|
||||||
|
@ -133,7 +379,35 @@ func! Test_Vet() abort
|
||||||
" clear the location lists
|
" clear the location lists
|
||||||
call setqflist([], 'r')
|
call setqflist([], 'r')
|
||||||
|
|
||||||
call go#lint#Vet(1)
|
call go#lint#Golint(1)
|
||||||
|
|
||||||
|
let actual = getqflist()
|
||||||
|
let start = reltime()
|
||||||
|
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||||
|
sleep 100m
|
||||||
|
let actual = getqflist()
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(actual, expected)
|
||||||
|
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Lint_NullModule() abort
|
||||||
|
silent exe 'e ' . fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint/src/lint/lint.go'
|
||||||
|
compiler go
|
||||||
|
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported'},
|
||||||
|
\ {'lnum': 5, 'bufnr': bufnr('%')+7, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'exported function AlsoMissingDoc should have comment or be unexported'}
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
let winnr = winnr()
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
call go#lint#Golint(1)
|
||||||
|
|
||||||
let actual = getqflist()
|
let actual = getqflist()
|
||||||
let start = reltime()
|
let start = reltime()
|
||||||
|
@ -145,6 +419,70 @@ func! Test_Vet() abort
|
||||||
call gotest#assert_quickfix(actual, expected)
|
call gotest#assert_quickfix(actual, expected)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Errcheck() abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnamemodify(getcwd(), ':p') . 'test-fixtures/lint')
|
||||||
|
silent exe 'e ' . $GOPATH . '/src/errcheck/errcheck.go'
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:bufnr = bufnr('')
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 9, 'bufnr': bufnr(''), 'col': 9, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': ":\tio.Copy(os.Stdout, os.Stdin)"},
|
||||||
|
\ {'lnum': 10, 'bufnr': bufnr('')+1, 'col': 9, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': ":\tio.Copy(os.Stdout, os.Stdin)"},
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
call go#lint#Errcheck(1)
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(getqflist(), expected)
|
||||||
|
call assert_equal(l:bufnr, bufnr(''))
|
||||||
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Errcheck_options() abort
|
||||||
|
let RestoreGOPATH = go#util#SetEnv('GOPATH', fnamemodify(getcwd(), ':p') . 'test-fixtures/lint')
|
||||||
|
silent exe 'e ' . $GOPATH . '/src/errcheck/errcheck.go'
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:bufnr = bufnr('')
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 9, 'bufnr': bufnr(''), 'col': 9, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': ":\tio.Copy(os.Stdout, os.Stdin)"},
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
call go#lint#Errcheck(1, '-ignoretests')
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(getqflist(), expected)
|
||||||
|
call assert_equal(l:bufnr, bufnr(''))
|
||||||
|
finally
|
||||||
|
call call(RestoreGOPATH, [])
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Errcheck_compilererror() abort
|
||||||
|
let l:tmp = gotest#load_fixture('lint/src/errcheck/compilererror/compilererror.go')
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:bufnr = bufnr('')
|
||||||
|
let expected = []
|
||||||
|
|
||||||
|
" clear the location lists
|
||||||
|
call setqflist([], 'r')
|
||||||
|
|
||||||
|
call go#lint#Errcheck(1)
|
||||||
|
|
||||||
|
call gotest#assert_quickfix(getqflist(), expected)
|
||||||
|
call assert_equal(l:bufnr, bufnr(''))
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
|
@ -49,26 +49,23 @@ endfunction
|
||||||
function! go#list#Populate(listtype, items, title) abort
|
function! go#list#Populate(listtype, items, title) abort
|
||||||
if a:listtype == "locationlist"
|
if a:listtype == "locationlist"
|
||||||
call setloclist(0, a:items, 'r')
|
call setloclist(0, a:items, 'r')
|
||||||
|
call setloclist(0, [], 'a', {'title': a:title})
|
||||||
" The last argument ({what}) is introduced with 7.4.2200:
|
|
||||||
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
|
|
||||||
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
|
|
||||||
else
|
else
|
||||||
call setqflist(a:items, 'r')
|
call setqflist(a:items, 'r')
|
||||||
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
|
call setqflist([], 'a', {'title': a:title})
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Parse parses the given items based on the specified errorformat and
|
" Parse parses the given items based on the specified errorformat and
|
||||||
" populates the list.
|
" populates the list.
|
||||||
function! go#list#ParseFormat(listtype, errformat, items, title) abort
|
function! go#list#ParseFormat(listtype, errformat, items, title, add) abort
|
||||||
" backup users errorformat, will be restored once we are finished
|
" backup users errorformat, will be restored once we are finished
|
||||||
let old_errorformat = &errorformat
|
let old_errorformat = &errorformat
|
||||||
|
|
||||||
" parse and populate the location list
|
" parse and populate the location list
|
||||||
let &errorformat = a:errformat
|
let &errorformat = a:errformat
|
||||||
try
|
try
|
||||||
call go#list#Parse(a:listtype, a:items, a:title)
|
call go#list#Parse(a:listtype, a:items, a:title, a:add)
|
||||||
finally
|
finally
|
||||||
"restore back
|
"restore back
|
||||||
let &errorformat = old_errorformat
|
let &errorformat = old_errorformat
|
||||||
|
@ -77,13 +74,26 @@ endfunction
|
||||||
|
|
||||||
" Parse parses the given items based on the global errorformat and
|
" Parse parses the given items based on the global errorformat and
|
||||||
" populates the list.
|
" populates the list.
|
||||||
function! go#list#Parse(listtype, items, title) abort
|
function! go#list#Parse(listtype, items, title, add) abort
|
||||||
|
let l:list = []
|
||||||
|
if a:add
|
||||||
|
let l:list = go#list#Get(a:listtype)
|
||||||
|
endif
|
||||||
|
|
||||||
if a:listtype == "locationlist"
|
if a:listtype == "locationlist"
|
||||||
lgetexpr a:items
|
if a:add
|
||||||
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
|
laddexpr a:items
|
||||||
|
else
|
||||||
|
lgetexpr a:items
|
||||||
|
endif
|
||||||
|
call setloclist(0, [], 'a', {'title': a:title})
|
||||||
else
|
else
|
||||||
cgetexpr a:items
|
if a:add
|
||||||
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
|
caddexpr a:items
|
||||||
|
else
|
||||||
|
cgetexpr a:items
|
||||||
|
endif
|
||||||
|
call setqflist([], 'a', {'title': a:title})
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
@ -138,6 +148,7 @@ endfunction
|
||||||
" in g:go_list_type_commands.
|
" in g:go_list_type_commands.
|
||||||
let s:default_list_type_commands = {
|
let s:default_list_type_commands = {
|
||||||
\ "GoBuild": "quickfix",
|
\ "GoBuild": "quickfix",
|
||||||
|
\ "GoDiagnostics": "quickfix",
|
||||||
\ "GoDebug": "quickfix",
|
\ "GoDebug": "quickfix",
|
||||||
\ "GoErrCheck": "quickfix",
|
\ "GoErrCheck": "quickfix",
|
||||||
\ "GoFmt": "locationlist",
|
\ "GoFmt": "locationlist",
|
||||||
|
@ -152,6 +163,8 @@ let s:default_list_type_commands = {
|
||||||
\ "GoRun": "quickfix",
|
\ "GoRun": "quickfix",
|
||||||
\ "GoTest": "quickfix",
|
\ "GoTest": "quickfix",
|
||||||
\ "GoVet": "quickfix",
|
\ "GoVet": "quickfix",
|
||||||
|
\ "GoReferrers": "locationlist",
|
||||||
|
\ "GoImplements": "locationlist",
|
||||||
\ "_guru": "locationlist",
|
\ "_guru": "locationlist",
|
||||||
\ "_term": "locationlist",
|
\ "_term": "locationlist",
|
||||||
\ "_job": "locationlist",
|
\ "_job": "locationlist",
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,7 +28,7 @@ let s:Event = 23
|
||||||
let s:Operator = 24
|
let s:Operator = 24
|
||||||
let s:TypeParameter = 25
|
let s:TypeParameter = 25
|
||||||
|
|
||||||
function! go#lsp#completionitemkind#Vim(kind)
|
function! go#lsp#completionitemkind#Vim(kind) abort
|
||||||
if a:kind == s:Method || a:kind == s:Function || a:kind == s:Constructor
|
if a:kind == s:Method || a:kind == s:Function || a:kind == s:Constructor
|
||||||
return 'f'
|
return 'f'
|
||||||
elseif a:kind == s:Variable || a:kind == s:Constant
|
elseif a:kind == s:Variable || a:kind == s:Constant
|
||||||
|
@ -40,6 +40,22 @@ function! go#lsp#completionitemkind#Vim(kind)
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#completionitemkind#IsFunction(kind) abort
|
||||||
|
if a:kind == s:Function
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#completionitemkind#IsMethod(kind) abort
|
||||||
|
if a:kind == s:Method
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
72
pack/acp/start/vim-go/autoload/go/lsp/lsp.vim
Normal file
72
pack/acp/start/vim-go/autoload/go/lsp/lsp.vim
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
" go#lsp#lsp#Position returns the LSP text position. If no arguments are
|
||||||
|
" provided, the cursor position is assumed. Otherwise, there should be two
|
||||||
|
" arguments: the line and the column.
|
||||||
|
function! go#lsp#lsp#Position(...)
|
||||||
|
if a:0 < 2
|
||||||
|
let [l:line, l:col] = getpos('.')[1:2]
|
||||||
|
else
|
||||||
|
let l:line = a:1
|
||||||
|
let l:col = a:2
|
||||||
|
endif
|
||||||
|
let l:content = getline(l:line)
|
||||||
|
|
||||||
|
" LSP uses 0-based lines.
|
||||||
|
return [l:line - 1, s:character(l:line, l:col-1)]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:strlen(str) abort
|
||||||
|
let l:runes = split(a:str, '\zs')
|
||||||
|
return len(l:runes) + len(filter(l:runes, 'char2nr(v:val)>=0x10000'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:character(line, col) abort
|
||||||
|
return s:strlen(getline(a:line)[:col([a:line, a:col - 1])])
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" go#lsp#PositionOf returns len(content[0:units]) where units is utf-16 code
|
||||||
|
" units. This is mostly useful for converting LSP text position to vim
|
||||||
|
" position.
|
||||||
|
function! go#lsp#lsp#PositionOf(content, units, ...) abort
|
||||||
|
if a:units == 0
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:remaining = a:units
|
||||||
|
let l:str = ''
|
||||||
|
for l:rune in split(a:content, '\zs')
|
||||||
|
if l:remaining < 0
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
let l:remaining -= 1
|
||||||
|
if char2nr(l:rune) >= 0x10000
|
||||||
|
let l:remaining -= 1
|
||||||
|
endif
|
||||||
|
let l:str = l:str . l:rune
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return len(l:str)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#lsp#SeverityToErrorType(severity) abort
|
||||||
|
if a:severity == 1
|
||||||
|
return 'E'
|
||||||
|
elseif a:severity == 2
|
||||||
|
return 'W'
|
||||||
|
elseif a:severity == 3
|
||||||
|
return 'I'
|
||||||
|
elseif a:severity == 4
|
||||||
|
return 'I'
|
||||||
|
endif
|
||||||
|
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
32
pack/acp/start/vim-go/autoload/go/lsp/lsp_test.vim
Normal file
32
pack/acp/start/vim-go/autoload/go/lsp/lsp_test.vim
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
function! Test_PositionOf_Simple()
|
||||||
|
let l:actual = go#lsp#lsp#PositionOf("just ascii", 3)
|
||||||
|
call assert_equal(4, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
|
function! Test_PositionOf_MultiByte()
|
||||||
|
" ⌘ is U+2318, which encodes to three bytes in utf-8 and 1 code unit in
|
||||||
|
" utf-16.
|
||||||
|
let l:actual = go#lsp#lsp#PositionOf("⌘⌘ foo", 3)
|
||||||
|
call assert_equal(8, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
function! Test_PositionOf_MultipleCodeUnit()
|
||||||
|
" 𐐀 is U+10400, which encodes to 4 bytes in utf-8 and 2 code units in
|
||||||
|
" utf-16.
|
||||||
|
let l:actual = go#lsp#lsp#PositionOf("𐐀 bar", 3)
|
||||||
|
call assert_equal(6, l:actual)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -10,17 +10,100 @@ function! go#lsp#message#Initialize(wd) abort
|
||||||
\ 'processId': getpid(),
|
\ 'processId': getpid(),
|
||||||
\ 'rootUri': go#path#ToURI(a:wd),
|
\ 'rootUri': go#path#ToURI(a:wd),
|
||||||
\ 'capabilities': {
|
\ 'capabilities': {
|
||||||
\ 'workspace': {},
|
\ 'workspace': {
|
||||||
|
\ 'workspaceFolders': v:true,
|
||||||
|
\ 'didChangeConfiguration': {
|
||||||
|
\ 'dynamicRegistration': v:true,
|
||||||
|
\ },
|
||||||
|
\ 'configuration': v:true,
|
||||||
|
\ },
|
||||||
\ 'textDocument': {
|
\ 'textDocument': {
|
||||||
\ 'hover': {
|
\ 'hover': {
|
||||||
\ 'contentFormat': ['plaintext'],
|
\ 'contentFormat': ['plaintext'],
|
||||||
\ },
|
\ },
|
||||||
|
\ 'completion': {
|
||||||
|
\ 'completionItem': {
|
||||||
|
\ 'snippetSupport': go#config#GoplsUsePlaceholders() ? v:true : v:false,
|
||||||
|
\ },
|
||||||
|
\ },
|
||||||
|
\ 'codeAction': {
|
||||||
|
\ 'codeActionLiteralSupport': {
|
||||||
|
\ 'codeActionKind': {
|
||||||
|
\ 'valueSet': ['source.organizeImports'],
|
||||||
|
\ },
|
||||||
|
\ },
|
||||||
|
\ },
|
||||||
\ }
|
\ }
|
||||||
\ }
|
\ },
|
||||||
|
\ 'workspaceFolders': [s:workspaceFolder(0, a:wd)],
|
||||||
\ }
|
\ }
|
||||||
\ }
|
\ }
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#Initialized() abort
|
||||||
|
return {
|
||||||
|
\ 'notification': 1,
|
||||||
|
\ 'method': 'initialized',
|
||||||
|
\ 'params': {},
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#Shutdown() abort
|
||||||
|
return {
|
||||||
|
\ 'notification': 0,
|
||||||
|
\ 'method': 'shutdown',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#Format(file) abort
|
||||||
|
return {
|
||||||
|
\ 'notification': 0,
|
||||||
|
\ 'method': 'textDocument/formatting',
|
||||||
|
\ 'params': {
|
||||||
|
\ 'textDocument': {
|
||||||
|
\ 'uri': go#path#ToURI(a:file)
|
||||||
|
\ },
|
||||||
|
\ 'options': {
|
||||||
|
\ 'insertSpaces': v:false,
|
||||||
|
\ },
|
||||||
|
\ }
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#CodeActionImports(file) abort
|
||||||
|
return s:codeAction('source.organizeImports', a:file)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:codeAction(name, file) abort
|
||||||
|
return {
|
||||||
|
\ 'notification': 0,
|
||||||
|
\ 'method': 'textDocument/codeAction',
|
||||||
|
\ 'params': {
|
||||||
|
\ 'textDocument': {
|
||||||
|
\ 'uri': go#path#ToURI(a:file)
|
||||||
|
\ },
|
||||||
|
\ 'range': {
|
||||||
|
\ 'start': {'line': 0, 'character': 0},
|
||||||
|
\ 'end': {'line': line('$'), 'character': 0},
|
||||||
|
\ },
|
||||||
|
\ 'context': {
|
||||||
|
\ 'only': [a:name],
|
||||||
|
\ },
|
||||||
|
\ }
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#Exit() abort
|
||||||
|
return {
|
||||||
|
\ 'notification': 1,
|
||||||
|
\ 'method': 'exit',
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#WorkspaceFoldersResult(dirs) abort
|
||||||
|
return map(copy(a:dirs), function('s:workspaceFolder', []))
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#lsp#message#Definition(file, line, col) abort
|
function! go#lsp#message#Definition(file, line, col) abort
|
||||||
return {
|
return {
|
||||||
\ 'notification': 0,
|
\ 'notification': 0,
|
||||||
|
@ -47,7 +130,20 @@ function! go#lsp#message#TypeDefinition(file, line, col) abort
|
||||||
\ }
|
\ }
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#lsp#message#DidOpen(file, content) abort
|
function! go#lsp#message#Implementation(file, line, col) abort
|
||||||
|
return {
|
||||||
|
\ 'notification': 0,
|
||||||
|
\ 'method': 'textDocument/implementation',
|
||||||
|
\ 'params': {
|
||||||
|
\ 'textDocument': {
|
||||||
|
\ 'uri': go#path#ToURI(a:file)
|
||||||
|
\ },
|
||||||
|
\ 'position': s:position(a:line, a:col)
|
||||||
|
\ }
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#DidOpen(file, content, version) abort
|
||||||
return {
|
return {
|
||||||
\ 'notification': 1,
|
\ 'notification': 1,
|
||||||
\ 'method': 'textDocument/didOpen',
|
\ 'method': 'textDocument/didOpen',
|
||||||
|
@ -56,18 +152,20 @@ function! go#lsp#message#DidOpen(file, content) abort
|
||||||
\ 'uri': go#path#ToURI(a:file),
|
\ 'uri': go#path#ToURI(a:file),
|
||||||
\ 'languageId': 'go',
|
\ 'languageId': 'go',
|
||||||
\ 'text': a:content,
|
\ 'text': a:content,
|
||||||
|
\ 'version': a:version,
|
||||||
\ }
|
\ }
|
||||||
\ }
|
\ }
|
||||||
\ }
|
\ }
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! go#lsp#message#DidChange(file, content) abort
|
function! go#lsp#message#DidChange(file, content, version) abort
|
||||||
return {
|
return {
|
||||||
\ 'notification': 1,
|
\ 'notification': 1,
|
||||||
\ 'method': 'textDocument/didChange',
|
\ 'method': 'textDocument/didChange',
|
||||||
\ 'params': {
|
\ 'params': {
|
||||||
\ 'textDocument': {
|
\ 'textDocument': {
|
||||||
\ 'uri': go#path#ToURI(a:file),
|
\ 'uri': go#path#ToURI(a:file),
|
||||||
|
\ 'version': a:version,
|
||||||
\ },
|
\ },
|
||||||
\ 'contentChanges': [
|
\ 'contentChanges': [
|
||||||
\ {
|
\ {
|
||||||
|
@ -103,6 +201,22 @@ function! go#lsp#message#Completion(file, line, col) abort
|
||||||
\ }
|
\ }
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#References(file, line, col) abort
|
||||||
|
return {
|
||||||
|
\ 'notification': 0,
|
||||||
|
\ 'method': 'textDocument/references',
|
||||||
|
\ 'params': {
|
||||||
|
\ 'textDocument': {
|
||||||
|
\ 'uri': go#path#ToURI(a:file)
|
||||||
|
\ },
|
||||||
|
\ 'position': s:position(a:line, a:col),
|
||||||
|
\ 'context': {
|
||||||
|
\ 'includeDeclaration': v:true,
|
||||||
|
\ },
|
||||||
|
\ }
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#lsp#message#Hover(file, line, col) abort
|
function! go#lsp#message#Hover(file, line, col) abort
|
||||||
return {
|
return {
|
||||||
\ 'notification': 0,
|
\ 'notification': 0,
|
||||||
|
@ -116,8 +230,120 @@ function! go#lsp#message#Hover(file, line, col) abort
|
||||||
\ }
|
\ }
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#ChangeWorkspaceFolders(add, remove) abort
|
||||||
|
let l:addDirs = map(copy(a:add), function('s:workspaceFolder', []))
|
||||||
|
let l:removeDirs = map(copy(a:remove), function('s:workspaceFolder', []))
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'notification': 1,
|
||||||
|
\ 'method': 'workspace/didChangeWorkspaceFolders',
|
||||||
|
\ 'params': {
|
||||||
|
\ 'event': {
|
||||||
|
\ 'removed': l:removeDirs,
|
||||||
|
\ 'added': l:addDirs,
|
||||||
|
\ },
|
||||||
|
\ }
|
||||||
|
\ }
|
||||||
|
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#lsp#message#ConfigurationResult(items) abort
|
||||||
|
let l:result = []
|
||||||
|
|
||||||
|
" results must be in the same order as the items
|
||||||
|
for l:item in a:items
|
||||||
|
let l:config = {
|
||||||
|
\ 'buildFlags': [],
|
||||||
|
\ 'hoverKind': 'Structured',
|
||||||
|
\ }
|
||||||
|
let l:buildtags = go#config#BuildTags()
|
||||||
|
if buildtags isnot ''
|
||||||
|
let l:config.buildFlags = extend(l:config.buildFlags, ['-tags', go#config#BuildTags()])
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:deepCompletion = go#config#GoplsDeepCompletion()
|
||||||
|
let l:matcher = go#config#GoplsMatcher()
|
||||||
|
let l:completeUnimported = go#config#GoplsCompleteUnimported()
|
||||||
|
let l:staticcheck = go#config#GoplsStaticCheck()
|
||||||
|
let l:usePlaceholder = go#config#GoplsUsePlaceholders()
|
||||||
|
let l:tempModfile = go#config#GoplsTempModfile()
|
||||||
|
let l:analyses = go#config#GoplsAnalyses()
|
||||||
|
let l:local = go#config#GoplsLocal()
|
||||||
|
let l:gofumpt = go#config#GoplsGofumpt()
|
||||||
|
let l:settings = go#config#GoplsSettings()
|
||||||
|
|
||||||
|
if l:deepCompletion isnot v:null
|
||||||
|
if l:deepCompletion
|
||||||
|
let l:config.deepCompletion = v:true
|
||||||
|
else
|
||||||
|
let l:config.deepCompletion = v:false
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:matcher isnot v:null
|
||||||
|
let l:config.matcher = l:matcher
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:completeUnimported isnot v:null
|
||||||
|
if l:completeUnimported
|
||||||
|
let l:config.completeUnimported = v:true
|
||||||
|
else
|
||||||
|
let l:config.completeUnimported = v:false
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:staticcheck isnot v:null
|
||||||
|
if l:staticcheck
|
||||||
|
let l:config.staticcheck = v:true
|
||||||
|
else
|
||||||
|
let l:config.staticcheck = v:false
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:usePlaceholder isnot v:null
|
||||||
|
if l:usePlaceholder
|
||||||
|
let l:config.usePlaceholders = v:true
|
||||||
|
else
|
||||||
|
let l:config.usePlaceholders = v:false
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:tempModfile isnot v:null
|
||||||
|
if l:tempModfile
|
||||||
|
let l:config.tempModfile = v:true
|
||||||
|
else
|
||||||
|
let l:config.tempModfile = v:false
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:analyses isnot v:null
|
||||||
|
let l:config.analyses = l:analyses
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:local isnot v:null
|
||||||
|
let l:config.local = l:local
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:gofumpt isnot v:null
|
||||||
|
let l:config.gofumpt = l:gofumpt
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:settings isnot v:null
|
||||||
|
let l:config = extend(l:config, l:settings, 'keep')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:result = add(l:result, l:config)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:result
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function s:workspaceFolder(key, val) abort
|
||||||
|
return {'uri': go#path#ToURI(a:val), 'name': a:val}
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! s:position(line, col) abort
|
function! s:position(line, col) abort
|
||||||
return {'line': a:line - 1, 'character': a:col-1}
|
return {'line': a:line, 'character': a:col}
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
|
|
97
pack/acp/start/vim-go/autoload/go/lsp_test.vim
Normal file
97
pack/acp/start/vim-go/autoload/go/lsp_test.vim
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
function! Test_GetSimpleTextPosition()
|
||||||
|
call s:getinfo('lsp text position should align with cursor position after ascii only', 'ascii')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_GetMultiByteTextPosition()
|
||||||
|
call s:getinfo('lsp text position should align with cursor position after two place of interest symbols ⌘⌘', 'multi-byte')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Test_GetMultipleCodeUnitTextPosition()
|
||||||
|
call s:getinfo('lsp text position should align with cursor position after Deseret Capital Letter Long I 𐐀', 'multi-code-units')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:getinfo(str, name)
|
||||||
|
if !go#util#has_job()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let g:go_info_mode = 'gopls'
|
||||||
|
|
||||||
|
let l:tmp = gotest#write_file(a:name . '/position/position.go', [
|
||||||
|
\ 'package position',
|
||||||
|
\ '',
|
||||||
|
\ 'func Example() {',
|
||||||
|
\ "\tid := " . '"foo"',
|
||||||
|
\ "\tprintln(" .'"' . a:str . '", id)',
|
||||||
|
\ '}',
|
||||||
|
\ ] )
|
||||||
|
|
||||||
|
let l:expected = 'var id string'
|
||||||
|
let l:actual = go#lsp#GetInfo()
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
unlet g:go_info_mode
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
func! Test_Format() abort
|
||||||
|
try
|
||||||
|
let expected = join(readfile("test-fixtures/lsp/fmt/format_golden.go"), "\n")
|
||||||
|
let l:tmp = gotest#load_fixture('lsp/fmt/format.go')
|
||||||
|
|
||||||
|
call go#lsp#Format()
|
||||||
|
|
||||||
|
" this should now contain the formatted code
|
||||||
|
let actual = join(go#util#GetLines(), "\n")
|
||||||
|
|
||||||
|
call assert_equal(expected, actual)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Format_SingleNewline() abort
|
||||||
|
try
|
||||||
|
let expected = join(readfile("test-fixtures/lsp/fmt/format_golden.go"), "\n")
|
||||||
|
let l:tmp = gotest#load_fixture('lsp/fmt/newline.go')
|
||||||
|
|
||||||
|
call go#lsp#Format()
|
||||||
|
|
||||||
|
" this should now contain the formatted code
|
||||||
|
let actual = join(go#util#GetLines(), "\n")
|
||||||
|
|
||||||
|
call assert_equal(expected, actual)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Imports() abort
|
||||||
|
try
|
||||||
|
let expected = join(readfile("test-fixtures/lsp/imports/imports_golden.go"), "\n")
|
||||||
|
let l:tmp = gotest#load_fixture('lsp/imports/imports.go')
|
||||||
|
|
||||||
|
call go#lsp#Imports()
|
||||||
|
|
||||||
|
" this should now contain the expected imports code
|
||||||
|
let actual = join(go#util#GetLines(), "\n")
|
||||||
|
|
||||||
|
call assert_equal(expected, actual)
|
||||||
|
finally
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -7,11 +7,15 @@ let s:go_major_version = ""
|
||||||
function! go#mod#Format() abort
|
function! go#mod#Format() abort
|
||||||
" go mod only exists in `v1.11`
|
" go mod only exists in `v1.11`
|
||||||
if empty(s:go_major_version)
|
if empty(s:go_major_version)
|
||||||
let tokens = matchlist(go#util#System("go version"), '\d\+.\(\d\+\)\(\.\d\+\)\? ')
|
let tokens = matchlist(go#util#Exec(['go', 'version']), '\d\+.\(\d\+\)\(\.\d\+\)\? ')
|
||||||
let s:go_major_version = str2nr(tokens[1])
|
if len(tokens) > 0
|
||||||
|
let s:go_major_version = str2nr(tokens[1])
|
||||||
|
else
|
||||||
|
let s:go_major_version = ""
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if s:go_major_version < "11"
|
if !empty(s:go_major_version) && s:go_major_version < "11"
|
||||||
call go#util#EchoError("Go v1.11 is required to format go.mod file")
|
call go#util#EchoError("Go v1.11 is required to format go.mod file")
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
@ -79,18 +83,11 @@ function! go#mod#update_file(source, target)
|
||||||
|
|
||||||
let l:listtype = go#list#Type("GoModFmt")
|
let l:listtype = go#list#Type("GoModFmt")
|
||||||
|
|
||||||
" the title information was introduced with 7.4-2200
|
" clean up previous list
|
||||||
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
|
if l:listtype == "quickfix"
|
||||||
if has('patch-7.4.2200')
|
let l:list_title = getqflist({'title': 1})
|
||||||
" clean up previous list
|
|
||||||
if l:listtype == "quickfix"
|
|
||||||
let l:list_title = getqflist({'title': 1})
|
|
||||||
else
|
|
||||||
let l:list_title = getloclist(0, {'title': 1})
|
|
||||||
endif
|
|
||||||
else
|
else
|
||||||
" can't check the title, so assume that the list was for go fmt.
|
let l:list_title = getloclist(0, {'title': 1})
|
||||||
let l:list_title = {'title': 'Format'}
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
|
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
|
||||||
|
|
|
@ -39,7 +39,7 @@ function! s:paths() abort
|
||||||
if executable('go')
|
if executable('go')
|
||||||
let s:goroot = go#util#env("goroot")
|
let s:goroot = go#util#env("goroot")
|
||||||
if go#util#ShellError() != 0
|
if go#util#ShellError() != 0
|
||||||
echomsg '''go env GOROOT'' failed'
|
call go#util#EchoError('`go env GOROOT` failed')
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
let s:goroot = $GOROOT
|
let s:goroot = $GOROOT
|
||||||
|
@ -82,6 +82,10 @@ function! s:vendordirs() abort
|
||||||
if l:err != 0
|
if l:err != 0
|
||||||
return []
|
return []
|
||||||
endif
|
endif
|
||||||
|
if empty(l:root)
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
|
||||||
let l:root = split(l:root, '\n')[0] . go#util#PathSep() . 'src'
|
let l:root = split(l:root, '\n')[0] . go#util#PathSep() . 'src'
|
||||||
|
|
||||||
let [l:dir, l:err] = go#util#ExecInDir(['go', 'list', '-f', '{{.Dir}}'])
|
let [l:dir, l:err] = go#util#ExecInDir(['go', 'list', '-f', '{{.Dir}}'])
|
||||||
|
@ -111,55 +115,77 @@ function! s:vendordirs() abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let s:import_paths = {}
|
let s:import_paths = {}
|
||||||
" ImportPath returns the import path of the package for current buffer.
|
" ImportPath returns the import path of the package for current buffer. It
|
||||||
|
" returns -1 if the import path cannot be determined.
|
||||||
function! go#package#ImportPath() abort
|
function! go#package#ImportPath() abort
|
||||||
let dir = expand("%:p:h")
|
let l:dir = expand("%:p:h")
|
||||||
if has_key(s:import_paths, dir)
|
if has_key(s:import_paths, dir)
|
||||||
return s:import_paths[dir]
|
return s:import_paths[l:dir]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let [l:out, l:err] = go#util#ExecInDir(['go', 'list'])
|
let l:importpath = go#package#FromPath(l:dir)
|
||||||
if l:err != 0
|
if type(l:importpath) == type(0)
|
||||||
return -1
|
return -1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:importpath = split(out, '\n')[0]
|
let s:import_paths[l:dir] = l:importpath
|
||||||
|
|
||||||
" go list returns '_CURRENTDIRECTORY' if the directory is not inside GOPATH.
|
|
||||||
" Check it and retun an error if that is the case
|
|
||||||
if l:importpath[0] ==# '_'
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
let s:import_paths[dir] = l:importpath
|
|
||||||
|
|
||||||
return l:importpath
|
return l:importpath
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" go#package#FromPath returns the import path of arg. -1 is returned when arg
|
||||||
" FromPath returns the import path of arg.
|
" does not specify a package. -2 is returned when arg is a relative path
|
||||||
|
" outside of GOPATH, not in a module, and not below the current working
|
||||||
|
" directory. A relative path is returned when in a null module at or below the
|
||||||
|
" current working directory..
|
||||||
function! go#package#FromPath(arg) abort
|
function! go#package#FromPath(arg) abort
|
||||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
||||||
let l:dir = getcwd()
|
let l:dir = getcwd()
|
||||||
|
|
||||||
let l:path = a:arg
|
let l:path = fnamemodify(a:arg, ':p')
|
||||||
if !isdirectory(l:path)
|
if !isdirectory(l:path)
|
||||||
let l:path = fnamemodify(l:path, ':h')
|
let l:path = fnamemodify(l:path, ':h')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
execute l:cd fnameescape(l:path)
|
execute l:cd fnameescape(l:path)
|
||||||
let [l:out, l:err] = go#util#Exec(['go', 'list'])
|
try
|
||||||
execute l:cd fnameescape(l:dir)
|
if glob("*.go") == ""
|
||||||
if l:err != 0
|
" There's no Go code in this directory. We might be in a module directory
|
||||||
return -1
|
" which doesn't have any code at this level. To avoid `go list` making a
|
||||||
endif
|
" bunch of HTTP requests to fetch dependencies, short-circuit `go list`
|
||||||
|
" and return -1 immediately.
|
||||||
|
if !empty(s:module())
|
||||||
|
return -1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let [l:out, l:err] = go#util#Exec(['go', 'list'])
|
||||||
|
if l:err != 0
|
||||||
|
return -1
|
||||||
|
endif
|
||||||
|
|
||||||
let l:importpath = split(l:out, '\n')[0]
|
let l:importpath = split(l:out, '\n')[0]
|
||||||
|
finally
|
||||||
|
execute l:cd fnameescape(l:dir)
|
||||||
|
endtry
|
||||||
|
|
||||||
" go list returns '_CURRENTDIRECTORY' if the directory is not inside GOPATH.
|
" go list returns '_CURRENTDIRECTORY' if the directory is in a null module
|
||||||
" Check it and retun an error if that is the case
|
" (i.e. neither in GOPATH nor in a module). Return a relative import path
|
||||||
|
" if possible or an error if that is the case.
|
||||||
if l:importpath[0] ==# '_'
|
if l:importpath[0] ==# '_'
|
||||||
return -1
|
let l:relativeimportpath = fnamemodify(l:importpath[1:], ':.')
|
||||||
|
if go#util#IsWin()
|
||||||
|
let l:relativeimportpath = substitute(l:relativeimportpath, '\\', '/', 'g')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:relativeimportpath == l:importpath[1:]
|
||||||
|
return '.'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:relativeimportpath[0] == '/'
|
||||||
|
return -2
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:importpath= printf('./%s', l:relativeimportpath)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return l:importpath
|
return l:importpath
|
||||||
|
@ -206,10 +232,17 @@ function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort
|
||||||
|
|
||||||
let vendordirs = s:vendordirs()
|
let vendordirs = s:vendordirs()
|
||||||
|
|
||||||
|
let l:modcache = go#util#env('gomodcache')
|
||||||
|
|
||||||
let ret = {}
|
let ret = {}
|
||||||
for dir in dirs
|
for dir in dirs
|
||||||
" this may expand to multiple lines
|
" this may expand to multiple lines
|
||||||
let root = split(expand(dir . '/pkg/' . s:goos . '_' . s:goarch), "\n")
|
let root = split(expand(dir . '/pkg/' . s:goos . '_' . s:goarch), "\n")
|
||||||
|
if l:modcache != ''
|
||||||
|
let root = add(root, l:modcache)
|
||||||
|
else
|
||||||
|
let root = add(root, expand(dir . '/pkg/mod'))
|
||||||
|
endif
|
||||||
let root = add(root, expand(dir . '/src'), )
|
let root = add(root, expand(dir . '/src'), )
|
||||||
let root = extend(root, vendordirs)
|
let root = extend(root, vendordirs)
|
||||||
let root = add(root, module)
|
let root = add(root, module)
|
||||||
|
@ -234,9 +267,8 @@ function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort
|
||||||
let glob = module.dir
|
let glob = module.dir
|
||||||
endif
|
endif
|
||||||
elseif stridx(module.path, a:ArgLead) == 0 && stridx(module.path, '/', len(a:ArgLead)) < 0
|
elseif stridx(module.path, a:ArgLead) == 0 && stridx(module.path, '/', len(a:ArgLead)) < 0
|
||||||
" use the module directory when a:ArgLead is contained in
|
" use the module directory when module.path begins wih a:ArgLead and
|
||||||
" module.path and module.path does not have any path segments after
|
" module.path does not have any path segments after a:ArgLead.
|
||||||
" a:ArgLead.
|
|
||||||
let glob = module.dir
|
let glob = module.dir
|
||||||
else
|
else
|
||||||
continue
|
continue
|
||||||
|
@ -251,6 +283,11 @@ function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort
|
||||||
if fnamemodify(candidate, ':t') == 'vendor'
|
if fnamemodify(candidate, ':t') == 'vendor'
|
||||||
continue
|
continue
|
||||||
endif
|
endif
|
||||||
|
" if path contains version info, strip it out
|
||||||
|
let vidx = strridx(candidate, '@')
|
||||||
|
if vidx >= 0
|
||||||
|
let candidate = strpart(candidate, 0, vidx)
|
||||||
|
endif
|
||||||
let candidate .= '/'
|
let candidate .= '/'
|
||||||
elseif candidate !~ '\.a$'
|
elseif candidate !~ '\.a$'
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -28,11 +28,11 @@ function! go#path#GoPath(...) abort
|
||||||
let s:initial_go_path = ""
|
let s:initial_go_path = ""
|
||||||
endif
|
endif
|
||||||
|
|
||||||
echon "vim-go: " | echohl Function | echon "GOPATH restored to ". $GOPATH | echohl None
|
call go#util#EchoInfo("GOPATH restored to ". $GOPATH)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
echon "vim-go: " | echohl Function | echon "GOPATH changed to ". a:1 | echohl None
|
call go#util#EchoInfo("GOPATH changed to ". a:1)
|
||||||
let s:initial_go_path = $GOPATH
|
let s:initial_go_path = $GOPATH
|
||||||
let $GOPATH = a:1
|
let $GOPATH = a:1
|
||||||
endfunction
|
endfunction
|
||||||
|
|
|
@ -4,7 +4,7 @@ set cpo&vim
|
||||||
|
|
||||||
function! go#play#Share(count, line1, line2) abort
|
function! go#play#Share(count, line1, line2) abort
|
||||||
if !executable('curl')
|
if !executable('curl')
|
||||||
echohl ErrorMsg | echomsg "vim-go: require 'curl' command" | echohl None
|
call go#util#EchoError('cannot share: curl cannot be found')
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -20,8 +20,7 @@ function! go#play#Share(count, line1, line2) abort
|
||||||
call delete(share_file)
|
call delete(share_file)
|
||||||
|
|
||||||
if l:err != 0
|
if l:err != 0
|
||||||
echom 'A error has occurred. Run this command to see what the problem is:'
|
call go#util#EchoError(['A error has occurred. Run this command to see what the problem is:', go#util#Shelljoin(l:cmd)])
|
||||||
echom go#util#Shelljoin(l:cmd)
|
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ function! go#play#Share(count, line1, line2) abort
|
||||||
call go#util#OpenBrowser(url)
|
call go#util#OpenBrowser(url)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
echo "vim-go: snippet uploaded: ".url
|
call go#util#EchoInfo('snippet uploaded: ' . url)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
|
58
pack/acp/start/vim-go/autoload/go/promise.vim
Normal file
58
pack/acp/start/vim-go/autoload/go/promise.vim
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
" New returns a promise. A promise's primary purpose is to make async jobs
|
||||||
|
" synchronous by awaiting fn.
|
||||||
|
"
|
||||||
|
" A promise is a dictionary with two keys:
|
||||||
|
" 'wrapper':
|
||||||
|
" A function that wraps fn. It can be used in place of fn.
|
||||||
|
" 'await':
|
||||||
|
" A function that waits for wrapper to be called and returns the value
|
||||||
|
" returned by fn. Returns default if timeout expires.
|
||||||
|
function! go#promise#New(fn, timeout, default) abort
|
||||||
|
let l:state = {}
|
||||||
|
|
||||||
|
" explicitly bind to state so that within l:promise's methods, self will
|
||||||
|
" always refer to state. See :help Partial for more information.
|
||||||
|
return {
|
||||||
|
\ 'wrapper': function('s:wrapper', [a:fn, a:default], l:state),
|
||||||
|
\ 'await': function('s:await', [a:timeout, a:default], l:state),
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:wrapper(fn, default, ...) dict
|
||||||
|
try
|
||||||
|
let self.retval = call(a:fn, a:000)
|
||||||
|
catch
|
||||||
|
let self.retval = substitute(v:exception, '^Vim', '', '')
|
||||||
|
let self.exception = 1
|
||||||
|
endtry
|
||||||
|
return self.retval
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:await(timeout, default) dict
|
||||||
|
let l:timer = timer_start(a:timeout, function('s:setretval', [a:default], self))
|
||||||
|
while !has_key(self, 'retval')
|
||||||
|
sleep 50m
|
||||||
|
endwhile
|
||||||
|
call timer_stop(l:timer)
|
||||||
|
|
||||||
|
if get(self, 'exception', 0)
|
||||||
|
throw self.retval
|
||||||
|
endif
|
||||||
|
return self.retval
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:setretval(val, timer) dict
|
||||||
|
let self.retval = a:val
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
41
pack/acp/start/vim-go/autoload/go/promise_test.vim
Normal file
41
pack/acp/start/vim-go/autoload/go/promise_test.vim
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
func! Test_PromiseNew() abort
|
||||||
|
let l:sut = go#promise#New(function('s:work', []), 100, -1)
|
||||||
|
call assert_true(has_key(l:sut, 'wrapper'))
|
||||||
|
call assert_true(has_key(l:sut, 'await'))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_PromiseAwait() abort
|
||||||
|
let l:expected = 1
|
||||||
|
let l:default = -1
|
||||||
|
let l:sut = go#promise#New(function('s:work', [l:expected]), 100, l:default)
|
||||||
|
|
||||||
|
call timer_start(10, l:sut.wrapper)
|
||||||
|
|
||||||
|
let l:actual = call(l:sut.await, [])
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_PromiseAwait_Timeout() abort
|
||||||
|
let l:desired = 1
|
||||||
|
let l:expected = -1
|
||||||
|
let l:sut = go#promise#New(function('s:work', [l:desired]), 10, l:expected)
|
||||||
|
|
||||||
|
call timer_start(100, l:sut.wrapper)
|
||||||
|
|
||||||
|
let l:actual = call(l:sut.await, [])
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! s:work(val, timer)
|
||||||
|
return a:val
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
43
pack/acp/start/vim-go/autoload/go/referrers.vim
Normal file
43
pack/acp/start/vim-go/autoload/go/referrers.vim
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
function! go#referrers#Referrers(selected) abort
|
||||||
|
let l:mode = go#config#ReferrersMode()
|
||||||
|
if l:mode == 'guru'
|
||||||
|
call go#guru#Referrers(a:selected)
|
||||||
|
return
|
||||||
|
elseif l:mode == 'gopls'
|
||||||
|
if !go#config#GoplsEnabled()
|
||||||
|
call go#util#EchoError("go_referrers_mode is 'gopls', but gopls is disabled")
|
||||||
|
endif
|
||||||
|
let [l:line, l:col] = getpos('.')[1:2]
|
||||||
|
let [l:line, l:col] = go#lsp#lsp#Position(l:line, l:col)
|
||||||
|
let l:fname = expand('%:p')
|
||||||
|
call go#lsp#Referrers(l:fname, l:line, l:col, funcref('s:parse_output'))
|
||||||
|
return
|
||||||
|
else
|
||||||
|
call go#util#EchoWarning('unknown value for g:go_referrers_mode')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" This uses Vim's errorformat to parse the output and put it into a quickfix
|
||||||
|
" or locationlist.
|
||||||
|
function! s:parse_output(exit_val, output, title) abort
|
||||||
|
if a:exit_val
|
||||||
|
call go#util#EchoError(a:output)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let errformat = ",%f:%l:%c:\ %m"
|
||||||
|
let l:listtype = go#list#Type("GoReferrers")
|
||||||
|
call go#list#ParseFormat(l:listtype, errformat, a:output, a:title, 0)
|
||||||
|
|
||||||
|
let errors = go#list#Get(l:listtype)
|
||||||
|
call go#list#Window(l:listtype, len(errors))
|
||||||
|
endfunction
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -20,8 +20,10 @@ function! go#rename#Rename(bang, ...) abort
|
||||||
let to_identifier = a:1
|
let to_identifier = a:1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let l:bin = go#config#RenameCommand()
|
||||||
|
|
||||||
" return with a warning if the bin doesn't exist
|
" return with a warning if the bin doesn't exist
|
||||||
let bin_path = go#path#CheckBinPath(go#config#GorenameBin())
|
let bin_path = go#path#CheckBinPath(l:bin)
|
||||||
if empty(bin_path)
|
if empty(bin_path)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
@ -29,7 +31,18 @@ function! go#rename#Rename(bang, ...) abort
|
||||||
let fname = expand('%:p')
|
let fname = expand('%:p')
|
||||||
let pos = go#util#OffsetCursor()
|
let pos = go#util#OffsetCursor()
|
||||||
let offset = printf('%s:#%d', fname, pos)
|
let offset = printf('%s:#%d', fname, pos)
|
||||||
let cmd = [bin_path, "-offset", offset, "-to", to_identifier, '-tags', go#config#BuildTags()]
|
|
||||||
|
let args = []
|
||||||
|
if l:bin == 'gorename'
|
||||||
|
let l:args = extend(l:args, ['-tags', go#config#BuildTags(), '-offset', offset, '-to', to_identifier])
|
||||||
|
elseif l:bin == 'gopls'
|
||||||
|
" TODO(bc): use -tags when gopls supports it
|
||||||
|
let l:args = extend(l:args, ['rename', '-w', l:offset, to_identifier])
|
||||||
|
else
|
||||||
|
call go#util#EchoWarning('unexpected rename command')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:cmd = extend([l:bin_path], l:args)
|
||||||
|
|
||||||
if go#util#has_job()
|
if go#util#has_job()
|
||||||
call s:rename_job({
|
call s:rename_job({
|
||||||
|
@ -39,7 +52,12 @@ function! go#rename#Rename(bang, ...) abort
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let [l:out, l:err] = go#util#ExecInDir(l:cmd)
|
let l:wd = go#util#ModuleRoot()
|
||||||
|
if l:wd == -1
|
||||||
|
let l:wd = expand("%:p:h")
|
||||||
|
endif
|
||||||
|
|
||||||
|
let [l:out, l:err] = go#util#ExecInWorkDir(l:cmd, l:wd)
|
||||||
call s:parse_errors(l:err, a:bang, split(l:out, '\n'))
|
call s:parse_errors(l:err, a:bang, split(l:out, '\n'))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
@ -54,6 +72,11 @@ function s:rename_job(args)
|
||||||
call go#cmd#autowrite()
|
call go#cmd#autowrite()
|
||||||
let l:cbs = go#job#Options(l:job_opts)
|
let l:cbs = go#job#Options(l:job_opts)
|
||||||
|
|
||||||
|
let l:wd = go#util#ModuleRoot()
|
||||||
|
if l:wd != -1
|
||||||
|
let l:cbs.cwd = l:wd
|
||||||
|
endif
|
||||||
|
|
||||||
" wrap l:cbs.exit_cb in s:exit_cb.
|
" wrap l:cbs.exit_cb in s:exit_cb.
|
||||||
let l:cbs.exit_cb = funcref('s:exit_cb', [l:cbs.exit_cb])
|
let l:cbs.exit_cb = funcref('s:exit_cb', [l:cbs.exit_cb])
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,8 @@ let s:last_status = ""
|
||||||
" if not it returns an empty string. This function should be plugged directly
|
" if not it returns an empty string. This function should be plugged directly
|
||||||
" into the statusline.
|
" into the statusline.
|
||||||
function! go#statusline#Show() abort
|
function! go#statusline#Show() abort
|
||||||
" lazy initialiation of the cleaner
|
" lazy initialization of the cleaner
|
||||||
if !s:timer_id
|
if !s:timer_id
|
||||||
" clean every 60 seconds all statuses
|
|
||||||
let interval = go#config#StatuslineDuration()
|
let interval = go#config#StatuslineDuration()
|
||||||
let s:timer_id = timer_start(interval, function('go#statusline#Clear'), {'repeat': -1})
|
let s:timer_id = timer_start(interval, function('go#statusline#Clear'), {'repeat': -1})
|
||||||
endif
|
endif
|
||||||
|
@ -57,9 +56,9 @@ function! go#statusline#Show() abort
|
||||||
|
|
||||||
" only update highlight if status has changed.
|
" only update highlight if status has changed.
|
||||||
if status_text != s:last_status
|
if status_text != s:last_status
|
||||||
if status.state =~ "success" || status.state =~ "finished" || status.state =~ "pass"
|
if status.state =~ "success" || status.state =~ "finished" || status.state =~ "pass" || status.state =~ 'initialized'
|
||||||
hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22 guibg=#5fd700 guifg=#005f00
|
hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22 guibg=#5fd700 guifg=#005f00
|
||||||
elseif status.state =~ "started" || status.state =~ "analysing" || status.state =~ "compiling"
|
elseif status.state =~ "started" || status.state =~ "analysing" || status.state =~ "compiling" || status.state =~ 'initializing'
|
||||||
hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 guibg=#ff8700 guifg=#870000
|
hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 guibg=#ff8700 guifg=#870000
|
||||||
elseif status.state =~ "failed"
|
elseif status.state =~ "failed"
|
||||||
hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52 guibg=#ff0000 guifg=#5f0000
|
hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52 guibg=#ff0000 guifg=#5f0000
|
||||||
|
@ -83,10 +82,11 @@ function! go#statusline#Update(status_dir, status) abort
|
||||||
" before we stop the timer, check if we have any previous jobs to be cleaned
|
" before we stop the timer, check if we have any previous jobs to be cleaned
|
||||||
" up. Otherwise every job will reset the timer when this function is called
|
" up. Otherwise every job will reset the timer when this function is called
|
||||||
" and thus old jobs will never be cleaned
|
" and thus old jobs will never be cleaned
|
||||||
call go#statusline#Clear(0)
|
call s:clear()
|
||||||
|
|
||||||
" also reset the timer, so the user has time to see it in the statusline.
|
" also reset the timer, so the user has time to see it in the statusline.
|
||||||
" Setting the timer_id to 0 will trigger a new cleaner routine.
|
" Setting the timer_id to 0 will cause a new timer to be created the next
|
||||||
|
" time the go#statusline#Show() is called.
|
||||||
call timer_stop(s:timer_id)
|
call timer_stop(s:timer_id)
|
||||||
let s:timer_id = 0
|
let s:timer_id = 0
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -94,6 +94,10 @@ endfunction
|
||||||
" Clear clears all currently stored statusline data. The timer_id argument is
|
" Clear clears all currently stored statusline data. The timer_id argument is
|
||||||
" just a placeholder so we can pass it to a timer_start() function if needed.
|
" just a placeholder so we can pass it to a timer_start() function if needed.
|
||||||
function! go#statusline#Clear(timer_id) abort
|
function! go#statusline#Clear(timer_id) abort
|
||||||
|
call s:clear()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:clear()
|
||||||
for [status_dir, status] in items(s:statuses)
|
for [status_dir, status] in items(s:statuses)
|
||||||
let elapsed_time = reltimestr(reltime(status.created_at))
|
let elapsed_time = reltimestr(reltime(status.created_at))
|
||||||
" strip whitespace
|
" strip whitespace
|
||||||
|
|
|
@ -98,7 +98,7 @@ func s:write_out(out) abort
|
||||||
if has_key(result, 'errors')
|
if has_key(result, 'errors')
|
||||||
let l:winnr = winnr()
|
let l:winnr = winnr()
|
||||||
let l:listtype = go#list#Type("GoModifyTags")
|
let l:listtype = go#list#Type("GoModifyTags")
|
||||||
call go#list#ParseFormat(l:listtype, "%f:%l:%c:%m", result['errors'], "gomodifytags")
|
call go#list#ParseFormat(l:listtype, "%f:%l:%c:%m", result['errors'], "gomodifytags", 0)
|
||||||
call go#list#Window(l:listtype, len(result['errors']))
|
call go#list#Window(l:listtype, len(result['errors']))
|
||||||
|
|
||||||
"prevent jumping to quickfix list
|
"prevent jumping to quickfix list
|
||||||
|
@ -124,6 +124,7 @@ func s:create_cmd(args) abort
|
||||||
let l:mode = a:args.mode
|
let l:mode = a:args.mode
|
||||||
let l:cmd_args = a:args.cmd_args
|
let l:cmd_args = a:args.cmd_args
|
||||||
let l:modifytags_transform = go#config#AddtagsTransform()
|
let l:modifytags_transform = go#config#AddtagsTransform()
|
||||||
|
let l:modifytags_skip_unexported = go#config#AddtagsSkipUnexported()
|
||||||
|
|
||||||
" start constructing the command
|
" start constructing the command
|
||||||
let cmd = [bin_path]
|
let cmd = [bin_path]
|
||||||
|
@ -131,6 +132,10 @@ func s:create_cmd(args) abort
|
||||||
call extend(cmd, ["-file", a:args.fname])
|
call extend(cmd, ["-file", a:args.fname])
|
||||||
call extend(cmd, ["-transform", l:modifytags_transform])
|
call extend(cmd, ["-transform", l:modifytags_transform])
|
||||||
|
|
||||||
|
if l:modifytags_skip_unexported
|
||||||
|
call extend(cmd, ["-skip-unexported"])
|
||||||
|
endif
|
||||||
|
|
||||||
if has_key(a:args, "modified")
|
if has_key(a:args, "modified")
|
||||||
call add(cmd, "-modified")
|
call add(cmd, "-modified")
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -24,8 +24,13 @@ function! go#template#create() abort
|
||||||
else
|
else
|
||||||
let l:template_file = go#config#TemplateFile()
|
let l:template_file = go#config#TemplateFile()
|
||||||
endif
|
endif
|
||||||
let l:template_path = go#util#Join(l:root_dir, "templates", l:template_file)
|
" If template_file is an absolute path, use it as-is. This is to support
|
||||||
silent exe 'keepalt 0r ' . fnameescape(l:template_path)
|
" overrides pointing to templates outside of the vim-go plugin dir
|
||||||
|
if fnamemodify(l:template_file, ':p') != l:template_file
|
||||||
|
let l:template_file = go#util#Join(l:root_dir, "templates", l:template_file)
|
||||||
|
endif
|
||||||
|
|
||||||
|
silent exe 'keepalt 0r ' . fnameescape(l:template_file)
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
let l:content = printf("package %s", l:package_name)
|
let l:content = printf("package %s", l:package_name)
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
let s:cpo_save = &cpo
|
let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
|
let s:bufnameprefix = 'goterm://'
|
||||||
|
|
||||||
" new creates a new terminal with the given command. Mode is set based on the
|
" new creates a new terminal with the given command. Mode is set based on the
|
||||||
" global variable g:go_term_mode, which is by default set to :vsplit
|
" global variable g:go_term_mode, which is by default set to :vsplit
|
||||||
function! go#term#new(bang, cmd, errorformat) abort
|
function! go#term#new(bang, cmd, errorformat) abort
|
||||||
|
@ -15,6 +17,10 @@ function! go#term#newmode(bang, cmd, errorformat, mode) abort
|
||||||
let l:mode = go#config#TermMode()
|
let l:mode = go#config#TermMode()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if go#config#TermReuse()
|
||||||
|
call s:closeterm()
|
||||||
|
endif
|
||||||
|
|
||||||
let l:state = {
|
let l:state = {
|
||||||
\ 'cmd': a:cmd,
|
\ 'cmd': a:cmd,
|
||||||
\ 'bang' : a:bang,
|
\ 'bang' : a:bang,
|
||||||
|
@ -24,55 +30,96 @@ function! go#term#newmode(bang, cmd, errorformat, mode) abort
|
||||||
\ 'errorformat': a:errorformat,
|
\ 'errorformat': a:errorformat,
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
" execute go build in the files directory
|
" execute the command in the current file's directory
|
||||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
let l:dir = go#util#Chdir(expand('%:p:h'))
|
||||||
let l:dir = getcwd()
|
|
||||||
|
|
||||||
execute l:cd . fnameescape(expand("%:p:h"))
|
|
||||||
|
|
||||||
execute l:mode . ' __go_term__'
|
execute l:mode . ' __go_term__'
|
||||||
|
|
||||||
setlocal filetype=goterm
|
setlocal filetype=goterm
|
||||||
setlocal bufhidden=delete
|
setlocal bufhidden=delete
|
||||||
setlocal winfixheight
|
setlocal winfixheight
|
||||||
|
" TODO(bc)?: setlocal winfixwidth
|
||||||
setlocal noswapfile
|
setlocal noswapfile
|
||||||
setlocal nobuflisted
|
setlocal nobuflisted
|
||||||
|
|
||||||
" explicitly bind callbacks to state so that within them, self will always
|
" setup job for nvim
|
||||||
" refer to state. See :help Partial for more information.
|
if has('nvim')
|
||||||
"
|
" explicitly bind callbacks to state so that within them, self will always
|
||||||
" Don't set an on_stderr, because it will be passed the same data as
|
" refer to state. See :help Partial for more information.
|
||||||
" on_stdout. See https://github.com/neovim/neovim/issues/2836
|
"
|
||||||
let l:job = {
|
" Don't set an on_stderr, because it will be passed the same data as
|
||||||
\ 'on_stdout': function('s:on_stdout', [], state),
|
" on_stdout. See https://github.com/neovim/neovim/issues/2836
|
||||||
\ 'on_exit' : function('s:on_exit', [], state),
|
let l:job = {
|
||||||
\ }
|
\ 'on_stdout': function('s:on_stdout', [], state),
|
||||||
|
\ 'on_exit' : function('s:on_exit', [], state),
|
||||||
|
\ }
|
||||||
|
let l:state.id = termopen(a:cmd, l:job)
|
||||||
|
let l:state.termwinid = win_getid(winnr())
|
||||||
|
let s:lasttermwinid = l:state.termwinid
|
||||||
|
call go#util#Chdir(l:dir)
|
||||||
|
|
||||||
let l:state.id = termopen(a:cmd, l:job)
|
" resize new term if needed.
|
||||||
let l:state.termwinid = win_getid(winnr())
|
let l:height = go#config#TermHeight()
|
||||||
|
let l:width = go#config#TermWidth()
|
||||||
|
|
||||||
execute l:cd . fnameescape(l:dir)
|
" Adjust the window width or height depending on whether it's a vertical or
|
||||||
|
" horizontal split.
|
||||||
|
if l:mode =~ "vertical" || l:mode =~ "vsplit" || l:mode =~ "vnew"
|
||||||
|
exe 'vertical resize ' . l:width
|
||||||
|
elseif mode =~ "split" || mode =~ "new"
|
||||||
|
exe 'resize ' . l:height
|
||||||
|
endif
|
||||||
|
" we also need to resize the pty, so there you go...
|
||||||
|
call jobresize(l:state.id, l:width, l:height)
|
||||||
|
|
||||||
" resize new term if needed.
|
" setup term for vim8
|
||||||
let l:height = go#config#TermHeight()
|
elseif has('terminal')
|
||||||
let l:width = go#config#TermWidth()
|
" Not great randomness, but "good enough" for our purpose here.
|
||||||
|
let l:rnd = sha256(printf('%s%s', reltimestr(reltime()), fnamemodify(bufname(''), ":p")))
|
||||||
|
let l:termname = printf("%s%s", s:bufnameprefix, l:rnd)
|
||||||
|
|
||||||
" Adjust the window width or height depending on whether it's a vertical or
|
let l:term = {
|
||||||
" horizontal split.
|
\ 'out_cb': function('s:out_cb', [], state),
|
||||||
if l:mode =~ "vertical" || l:mode =~ "vsplit" || l:mode =~ "vnew"
|
\ 'exit_cb' : function('s:exit_cb', [], state),
|
||||||
exe 'vertical resize ' . l:width
|
\ 'curwin': 1,
|
||||||
elseif mode =~ "split" || mode =~ "new"
|
\ 'term_name': l:termname,
|
||||||
exe 'resize ' . l:height
|
\ }
|
||||||
|
|
||||||
|
if l:mode =~ "vertical" || l:mode =~ "vsplit" || l:mode =~ "vnew"
|
||||||
|
let l:term["vertical"] = l:mode
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:state.id = term_start(a:cmd, l:term)
|
||||||
|
let l:state.termwinid = win_getid(bufwinnr(l:state.id))
|
||||||
|
let s:lasttermwinid = l:state.termwinid
|
||||||
|
call go#util#Chdir(l:dir)
|
||||||
|
|
||||||
|
" resize new term if needed.
|
||||||
|
let l:height = go#config#TermHeight()
|
||||||
|
let l:width = go#config#TermWidth()
|
||||||
|
|
||||||
|
" Adjust the window width or height depending on whether it's a vertical or
|
||||||
|
" horizontal split.
|
||||||
|
if l:mode =~ "vertical" || l:mode =~ "vsplit" || l:mode =~ "vnew"
|
||||||
|
exe 'vertical resize ' . l:width
|
||||||
|
elseif mode =~ "split" || mode =~ "new"
|
||||||
|
exe 'resize ' . l:height
|
||||||
|
endif
|
||||||
|
"if exists(*term_setsize)
|
||||||
|
"call term_setsize(l:state.id, l:height, l:width)
|
||||||
|
"endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" we also need to resize the pty, so there you go...
|
|
||||||
call jobresize(l:state.id, l:width, l:height)
|
|
||||||
|
|
||||||
call win_gotoid(l:state.winid)
|
call win_gotoid(l:state.winid)
|
||||||
|
|
||||||
return l:state.id
|
return l:state.id
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" out_cb continually concat's the self.stdout_buf on recv of stdout
|
||||||
|
" and sets self.stdout to the new-lined split content in self.stdout_buf
|
||||||
|
func! s:out_cb(channel, msg) dict abort
|
||||||
|
let self.stdout_buf = self.stdout_buf . a:msg
|
||||||
|
let self.stdout = split(self.stdout_buf, '\n')
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! s:on_stdout(job_id, data, event) dict abort
|
function! s:on_stdout(job_id, data, event) dict abort
|
||||||
" A single empty string means EOF was reached. The first item will never be
|
" A single empty string means EOF was reached. The first item will never be
|
||||||
" the empty string except for when it's the only item and is signaling that
|
" the empty string except for when it's the only item and is signaling that
|
||||||
|
@ -95,9 +142,21 @@ function! s:on_stdout(job_id, data, event) dict abort
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" vim8 exit callback
|
||||||
|
function! s:exit_cb(job_id, exit_status) dict abort
|
||||||
|
call s:handle_exit(a:job_id, a:exit_status, self)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" nvim exit callback
|
||||||
function! s:on_exit(job_id, exit_status, event) dict abort
|
function! s:on_exit(job_id, exit_status, event) dict abort
|
||||||
|
call s:handle_exit(a:job_id, a:exit_status, self)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" handle_exit implements both vim8 and nvim exit callbacks
|
||||||
|
func s:handle_exit(job_id, exit_status, state) abort
|
||||||
let l:winid = win_getid(winnr())
|
let l:winid = win_getid(winnr())
|
||||||
call win_gotoid(self.winid)
|
call win_gotoid(a:state.winid)
|
||||||
|
|
||||||
let l:listtype = go#list#Type("_term")
|
let l:listtype = go#list#Type("_term")
|
||||||
|
|
||||||
if a:exit_status == 0
|
if a:exit_status == 0
|
||||||
|
@ -106,40 +165,106 @@ function! s:on_exit(job_id, exit_status, event) dict abort
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
call win_gotoid(self.winid)
|
let l:bufdir = expand('%:p:h')
|
||||||
|
if !isdirectory(l:bufdir)
|
||||||
|
call go#util#EchoWarning('terminal job failure not processed, because the job''s working directory no longer exists')
|
||||||
|
call win_gotoid(l:winid)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
let l:title = self.cmd
|
" change to directory where the command was run. If we do not do this the
|
||||||
|
" quickfix items will have the incorrect paths.
|
||||||
|
" see: https://github.com/fatih/vim-go/issues/2400
|
||||||
|
let l:dir = go#util#Chdir(l:bufdir)
|
||||||
|
|
||||||
|
let l:title = a:state.cmd
|
||||||
if type(l:title) == v:t_list
|
if type(l:title) == v:t_list
|
||||||
let l:title = join(self.cmd)
|
let l:title = join(a:state.cmd)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:i = 0
|
let l:i = 0
|
||||||
while l:i < len(self.stdout)
|
while l:i < len(a:state.stdout)
|
||||||
let self.stdout[l:i] = substitute(self.stdout[l:i], "\r$", '', 'g')
|
let a:state.stdout[l:i] = substitute(a:state.stdout[l:i], "\r$", '', 'g')
|
||||||
let l:i += 1
|
let l:i += 1
|
||||||
endwhile
|
endwhile
|
||||||
|
|
||||||
call go#list#ParseFormat(l:listtype, self.errorformat, self.stdout, l:title)
|
call go#list#ParseFormat(l:listtype, a:state.errorformat, a:state.stdout, l:title, 0)
|
||||||
let l:errors = go#list#Get(l:listtype)
|
let l:errors = go#list#Get(l:listtype)
|
||||||
call go#list#Window(l:listtype, len(l:errors))
|
call go#list#Window(l:listtype, len(l:errors))
|
||||||
|
|
||||||
|
" close terminal; we don't need it anymore
|
||||||
|
if go#config#TermCloseOnExit()
|
||||||
|
call win_gotoid(a:state.termwinid)
|
||||||
|
close!
|
||||||
|
endif
|
||||||
|
|
||||||
if empty(l:errors)
|
if empty(l:errors)
|
||||||
call go#util#EchoError( '[' . l:title . '] ' . "FAIL")
|
call go#util#EchoError( '[' . l:title . '] ' . "FAIL")
|
||||||
|
call go#util#Chdir(l:dir)
|
||||||
call win_gotoid(l:winid)
|
call win_gotoid(l:winid)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" close terminal; we don't need it anymore
|
if a:state.bang
|
||||||
call win_gotoid(self.termwinid)
|
call go#util#Chdir(l:dir)
|
||||||
close!
|
|
||||||
|
|
||||||
if self.bang
|
|
||||||
call win_gotoid(l:winid)
|
call win_gotoid(l:winid)
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
call win_gotoid(self.winid)
|
call win_gotoid(a:state.winid)
|
||||||
call go#list#JumpToFirst(l:listtype)
|
call go#list#JumpToFirst(l:listtype)
|
||||||
|
|
||||||
|
" change back to original working directory
|
||||||
|
call go#util#Chdir(l:dir)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#term#ToggleCloseOnExit() abort
|
||||||
|
if go#config#TermCloseOnExit()
|
||||||
|
call go#config#SetTermCloseOnExit(0)
|
||||||
|
call go#util#EchoProgress("term close on exit disabled")
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
call go#config#SetTermCloseOnExit(1)
|
||||||
|
call go#util#EchoProgress("term close on exit enabled")
|
||||||
|
return
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:closeterm()
|
||||||
|
if !exists('s:lasttermwinid')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:termwinid = s:lasttermwinid
|
||||||
|
unlet s:lasttermwinid
|
||||||
|
let l:info = getwininfo(l:termwinid)
|
||||||
|
if empty(l:info)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:info = l:info[0]
|
||||||
|
|
||||||
|
if !get(l:info, 'terminal', 0) is 1
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has('nvim')
|
||||||
|
if 'goterm' == nvim_buf_get_option(nvim_win_get_buf(l:termwinid), 'filetype')
|
||||||
|
call nvim_win_close(l:termwinid, v:true)
|
||||||
|
endif
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if stridx(bufname(winbufnr(l:termwinid)), s:bufnameprefix, 0) == 0
|
||||||
|
let l:winid = win_getid()
|
||||||
|
call win_gotoid(l:termwinid)
|
||||||
|
close!
|
||||||
|
call win_gotoid(l:winid)
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
call go#util#EchoError(printf("vim-go: %s", v:exception))
|
||||||
|
endtry
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
|
|
|
@ -3,7 +3,7 @@ let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
func! Test_GoTermNewMode()
|
func! Test_GoTermNewMode()
|
||||||
if !has('nvim')
|
if !(has('nvim') || has('terminal'))
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -22,12 +22,13 @@ func! Test_GoTermNewMode()
|
||||||
call assert_equal(actual, l:expected)
|
call assert_equal(actual, l:expected)
|
||||||
|
|
||||||
finally
|
finally
|
||||||
|
sleep 50m
|
||||||
call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! Test_GoTermNewMode_SplitRight()
|
func! Test_GoTermNewMode_SplitRight()
|
||||||
if !has('nvim')
|
if !(has('nvim') || has('terminal'))
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -46,11 +47,46 @@ func! Test_GoTermNewMode_SplitRight()
|
||||||
call assert_equal(actual, l:expected)
|
call assert_equal(actual, l:expected)
|
||||||
|
|
||||||
finally
|
finally
|
||||||
|
sleep 50m
|
||||||
call delete(l:tmp, 'rf')
|
call delete(l:tmp, 'rf')
|
||||||
set nosplitright
|
set nosplitright
|
||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func! Test_GoTermReuse()
|
||||||
|
if !(has('nvim') || has('terminal'))
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
try
|
||||||
|
let l:filename = 'term/term.go'
|
||||||
|
let l:tmp = gotest#load_fixture(l:filename)
|
||||||
|
exe 'cd ' . l:tmp . '/src/term'
|
||||||
|
|
||||||
|
let expected = expand('%:p')
|
||||||
|
|
||||||
|
let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
|
||||||
|
|
||||||
|
set nosplitright
|
||||||
|
|
||||||
|
let g:go_term_reuse = 1
|
||||||
|
call go#term#new(0, cmd, &errorformat)
|
||||||
|
let actual = expand('%:p')
|
||||||
|
call assert_equal(actual, l:expected)
|
||||||
|
call assert_equal(3, len(getwininfo()))
|
||||||
|
|
||||||
|
call go#term#new(0, cmd, &errorformat)
|
||||||
|
let actual = expand('%:p')
|
||||||
|
call assert_equal(actual, l:expected)
|
||||||
|
|
||||||
|
call assert_equal(3, len(getwininfo()))
|
||||||
|
finally
|
||||||
|
sleep 50m
|
||||||
|
unlet g:go_term_reuse
|
||||||
|
call delete(l:tmp, 'rf')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
func Example() {
|
||||||
|
foo()
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
// +build constrained
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
// foo is constrained and this comment exists to make the line numbers different than foo.go
|
||||||
|
func foo() {
|
||||||
|
println("foo")
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// +build !constrained
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
func foo() {
|
||||||
|
println("foo")
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
module config
|
||||||
|
|
||||||
|
go 1.13
|
|
@ -1,13 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Foo(log *logging.TestLogger) {
|
|
||||||
log.Debug("vim-go")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("vim-go")
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
logging "gh.com/gi/foo-logging"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Foo(log *logging.TestLogger) {
|
|
||||||
log.Debug("vim-go")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("vim-go")
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package logging
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type TestLogger struct {
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *TestLogger) Debug(msg string) {
|
|
||||||
fmt.Println(msg)
|
|
||||||
fmt.Println(l.Value)
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
../imports/
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
notafunc()
|
||||||
|
println("vim-go")
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("vim-go"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package errcheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func foo() {
|
||||||
|
io.Copy(os.Stdout, os.Stdin)
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package errcheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFoo(t *testing.T) {
|
||||||
|
io.Copy(os.Stdout, os.Stdin)
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package lint
|
||||||
|
|
||||||
|
func baz() {}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package problems
|
||||||
|
|
||||||
|
func bar() {}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package problems
|
||||||
|
|
||||||
|
import "/quux"
|
||||||
|
|
||||||
|
func baz() {}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package problems
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mySleep(time int) {
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package problems
|
||||||
|
|
||||||
|
func mySleep(time int) {
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("vim-go"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("vim-go")
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("vim-go")
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
func main() {
|
||||||
|
fmt.Println("vim-go")
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
io.Copy(ioutil.Discard, os.Stdin)
|
||||||
|
fmt.Println("vim-go")
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
io.Copy(ioutil.Discard, os.Stdin)
|
||||||
|
fmt.Println("vim-go")
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleHelloWorld() {
|
||||||
|
fmt.Println("Hello, World")
|
||||||
|
// Output: What's shakin
|
||||||
|
}
|
|
@ -6,7 +6,10 @@ set cpo&vim
|
||||||
" compile the tests instead of running them (useful to catch errors in the
|
" compile the tests instead of running them (useful to catch errors in the
|
||||||
" test files). Any other argument is appended to the final `go test` command.
|
" test files). Any other argument is appended to the final `go test` command.
|
||||||
function! go#test#Test(bang, compile, ...) abort
|
function! go#test#Test(bang, compile, ...) abort
|
||||||
let args = ["test", '-tags', go#config#BuildTags()]
|
let args = ["test"]
|
||||||
|
if len(go#config#BuildTags()) > 0
|
||||||
|
call extend(args, ["-tags", go#config#BuildTags()])
|
||||||
|
endif
|
||||||
|
|
||||||
" don't run the test, only compile it. Useful to capture and fix errors.
|
" don't run the test, only compile it. Useful to capture and fix errors.
|
||||||
if a:compile
|
if a:compile
|
||||||
|
@ -32,6 +35,7 @@ function! go#test#Test(bang, compile, ...) abort
|
||||||
|
|
||||||
if go#config#TermEnabled()
|
if go#config#TermEnabled()
|
||||||
call go#term#new(a:bang, ["go"] + args, s:errorformat())
|
call go#term#new(a:bang, ["go"] + args, s:errorformat())
|
||||||
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if go#util#has_job()
|
if go#util#has_job()
|
||||||
|
@ -76,7 +80,7 @@ function! go#test#Test(bang, compile, ...) abort
|
||||||
|
|
||||||
if l:err != 0
|
if l:err != 0
|
||||||
let l:winid = win_getid(winnr())
|
let l:winid = win_getid(winnr())
|
||||||
call go#list#ParseFormat(l:listtype, s:errorformat(), split(out, '\n'), l:cmd)
|
call go#list#ParseFormat(l:listtype, s:errorformat(), split(out, '\n'), l:cmd, 0)
|
||||||
let errors = go#list#Get(l:listtype)
|
let errors = go#list#Get(l:listtype)
|
||||||
call go#list#Window(l:listtype, len(errors))
|
call go#list#Window(l:listtype, len(errors))
|
||||||
if empty(errors)
|
if empty(errors)
|
||||||
|
@ -166,9 +170,17 @@ function! s:errorformat() abort
|
||||||
let format .= ",%-G" . indent . "%#--- PASS: %.%#"
|
let format .= ",%-G" . indent . "%#--- PASS: %.%#"
|
||||||
|
|
||||||
" Match failure lines.
|
" Match failure lines.
|
||||||
"
|
|
||||||
|
" Example failures start with '--- FAIL: ', followed by the example name
|
||||||
|
" followed by a space , followed by the duration of the example in
|
||||||
|
" parantheses. They aren't nested, though, so don't check for indentation.
|
||||||
|
" The errors from them also aren't indented and don't report file location
|
||||||
|
" or line numbers, so those won't show up. This will at least let the user
|
||||||
|
" know which example failed, though.
|
||||||
|
let format .= ',%G--- FAIL: %\\%(Example%\\)%\\@=%m (%.%#)'
|
||||||
|
|
||||||
" Test failures start with '--- FAIL: ', followed by the test name followed
|
" Test failures start with '--- FAIL: ', followed by the test name followed
|
||||||
" by a space the duration of the test in parentheses
|
" by a space, followed by the duration of the test in parentheses.
|
||||||
"
|
"
|
||||||
" e.g.:
|
" e.g.:
|
||||||
" '--- FAIL: TestSomething (0.00s)'
|
" '--- FAIL: TestSomething (0.00s)'
|
||||||
|
@ -207,6 +219,14 @@ function! s:errorformat() abort
|
||||||
let format .= ",%G" . indent . "%#%\\t%\\{2}%m"
|
let format .= ",%G" . indent . "%#%\\t%\\{2}%m"
|
||||||
" }}}1
|
" }}}1
|
||||||
|
|
||||||
|
" Go 1.14 test verbose output {{{1
|
||||||
|
" Match test output lines similarly to Go 1.11 test output lines, but they
|
||||||
|
" have the test name followed by a colon before the filename when run with
|
||||||
|
" the -v flag.
|
||||||
|
let format .= ",%A" . indent . "%\\+%[%^:]%\\+: %f:%l: %m"
|
||||||
|
let format .= ",%A" . indent . "%\\+%[%^:]%\\+: %f:%l: "
|
||||||
|
" }}}1
|
||||||
|
|
||||||
" Go 1.11 test output {{{1
|
" Go 1.11 test output {{{1
|
||||||
" Match test output lines similarly to Go 1.10 test output lines, but they
|
" Match test output lines similarly to Go 1.10 test output lines, but they
|
||||||
" use an indent level where the Go 1.10 test output uses tabs, so they'll
|
" use an indent level where the Go 1.10 test output uses tabs, so they'll
|
||||||
|
|
|
@ -66,9 +66,9 @@ endfunc
|
||||||
func! Test_GoTestShowName() abort
|
func! Test_GoTestShowName() abort
|
||||||
let expected = [
|
let expected = [
|
||||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'},
|
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'},
|
||||||
\ {'lnum': 6, 'bufnr': 7, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'},
|
\ {'lnum': 6, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'},
|
||||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'},
|
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'},
|
||||||
\ {'lnum': 9, 'bufnr': 7, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'},
|
\ {'lnum': 9, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'},
|
||||||
\ ]
|
\ ]
|
||||||
|
|
||||||
let g:go_test_show_name=1
|
let g:go_test_show_name=1
|
||||||
|
@ -78,20 +78,27 @@ endfunc
|
||||||
|
|
||||||
func! Test_GoTestVet() abort
|
func! Test_GoTestVet() abort
|
||||||
let expected = [
|
let expected = [
|
||||||
\ {'lnum': 6, 'bufnr': 10, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'},
|
\ {'lnum': 6, 'bufnr': 11, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'},
|
||||||
\ ]
|
\ ]
|
||||||
call s:test('veterror/veterror.go', expected)
|
call s:test('veterror/veterror.go', expected)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func! Test_GoTestTestCompilerError() abort
|
func! Test_GoTestTestCompilerError() abort
|
||||||
let expected = [
|
let expected = [
|
||||||
\ {'lnum': 10, 'bufnr': 8, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'},
|
\ {'lnum': 10, 'bufnr': 9, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'},
|
||||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'struct {} does not implement io.Reader (missing Read method)'}
|
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'struct {} does not implement io.Reader (missing Read method)'}
|
||||||
\ ]
|
\ ]
|
||||||
|
|
||||||
call s:test('testcompilerror/testcompilerror_test.go', expected)
|
call s:test('testcompilerror/testcompilerror_test.go', expected)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func! Test_GoTestExample() abort
|
||||||
|
let expected = [
|
||||||
|
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'ExampleHelloWorld'}
|
||||||
|
\ ]
|
||||||
|
call s:test('example/example_test.go', expected)
|
||||||
|
endfunc
|
||||||
|
|
||||||
func! s:test(file, expected, ...) abort
|
func! s:test(file, expected, ...) abort
|
||||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/test'
|
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/test'
|
||||||
silent exe 'e ' . $GOPATH . '/src/' . a:file
|
silent exe 'e ' . $GOPATH . '/src/' . a:file
|
||||||
|
|
|
@ -82,14 +82,16 @@ endfunction
|
||||||
|
|
||||||
function! go#tool#Info(showstatus) abort
|
function! go#tool#Info(showstatus) abort
|
||||||
let l:mode = go#config#InfoMode()
|
let l:mode = go#config#InfoMode()
|
||||||
if l:mode == 'gocode'
|
if l:mode == 'guru'
|
||||||
call go#complete#Info(a:showstatus)
|
|
||||||
elseif l:mode == 'guru'
|
|
||||||
call go#guru#DescribeInfo(a:showstatus)
|
call go#guru#DescribeInfo(a:showstatus)
|
||||||
elseif l:mode == 'gopls'
|
elseif l:mode == 'gopls'
|
||||||
|
if !go#config#GoplsEnabled()
|
||||||
|
call go#util#EchoError("go_info_mode is 'gopls', but gopls is disabled")
|
||||||
|
return
|
||||||
|
endif
|
||||||
call go#lsp#Info(a:showstatus)
|
call go#lsp#Info(a:showstatus)
|
||||||
else
|
else
|
||||||
call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru, gopls]')
|
call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [guru, gopls]')
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
@ -115,7 +117,15 @@ endfunction
|
||||||
|
|
||||||
function! go#tool#DescribeBalloon()
|
function! go#tool#DescribeBalloon()
|
||||||
let l:fname = fnamemodify(bufname(v:beval_bufnr), ':p')
|
let l:fname = fnamemodify(bufname(v:beval_bufnr), ':p')
|
||||||
call go#lsp#Hover(l:fname, v:beval_lnum, v:beval_col, funcref('s:balloon', []))
|
|
||||||
|
let l:winid = win_getid()
|
||||||
|
|
||||||
|
call win_gotoid(bufwinid(v:beval_bufnr))
|
||||||
|
|
||||||
|
let [l:line, l:col] = go#lsp#lsp#Position(v:beval_lnum, v:beval_col)
|
||||||
|
call go#lsp#Hover(l:fname, l:line, l:col, funcref('s:balloon', []))
|
||||||
|
|
||||||
|
call win_gotoid(l:winid)
|
||||||
return ''
|
return ''
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ function! s:encode(value, unreserved)
|
||||||
return substitute(
|
return substitute(
|
||||||
\ a:value,
|
\ a:value,
|
||||||
\ a:unreserved,
|
\ a:unreserved,
|
||||||
\ '\="%".printf(''%02X'', char2nr(submatch(0)))',
|
\ '\=s:encodechar(submatch(0))',
|
||||||
\ 'g'
|
\ 'g'
|
||||||
\)
|
\)
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -27,10 +27,27 @@ function! go#uri#Decode(value) abort
|
||||||
return substitute(
|
return substitute(
|
||||||
\ a:value,
|
\ a:value,
|
||||||
\ '%\(\x\x\)',
|
\ '%\(\x\x\)',
|
||||||
\ '\=nr2char(''0X'' . submatch(1))',
|
\ '\=s:decodehex(submatch(1))',
|
||||||
\ 'g'
|
\ 'g'
|
||||||
\)
|
\)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! s:encodechar(value)
|
||||||
|
let l:idx = 0
|
||||||
|
let l:encoded = ''
|
||||||
|
while l:idx < strlen(a:value)
|
||||||
|
let l:byte = strpart(a:value, l:idx, 1)
|
||||||
|
let l:encoded = printf('%s%%%02X', l:encoded, char2nr(l:byte))
|
||||||
|
let l:idx += 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return l:encoded
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:decodehex(value)
|
||||||
|
return eval(printf('"\x%s"', a:value))
|
||||||
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
56
pack/acp/start/vim-go/autoload/go/uri_test.vim
Normal file
56
pack/acp/start/vim-go/autoload/go/uri_test.vim
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
func! Test_EncodePath_simple() abort
|
||||||
|
let l:uri = '/simple/foo'
|
||||||
|
let l:expected = '/simple/foo'
|
||||||
|
|
||||||
|
let l:actual = go#uri#EncodePath(l:uri)
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_EncodePath_multibyte() abort
|
||||||
|
let l:uri = '/multi-byte/⌘⌘'
|
||||||
|
let l:expected = '/multi-byte/%E2%8C%98%E2%8C%98'
|
||||||
|
|
||||||
|
let l:actual = go#uri#EncodePath(l:uri)
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Decode_simple() abort
|
||||||
|
let l:uri = '/simple/foo'
|
||||||
|
let l:expected = '/simple/foo'
|
||||||
|
|
||||||
|
let l:actual = go#uri#Decode(l:uri)
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Decode_multibyte() abort
|
||||||
|
let l:uri = '/multi-byte/%E2%8C%98%E2%8C%98'
|
||||||
|
let l:expected = '/multi-byte/⌘⌘'
|
||||||
|
let l:actual = go#uri#Decode(l:uri)
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Roundtrip_simple() abort
|
||||||
|
let l:expected = '/simple/foo'
|
||||||
|
|
||||||
|
let l:actual = go#uri#Decode(go#uri#EncodePath(l:expected))
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Test_Roundtrip_multibyte() abort
|
||||||
|
let l:expected = '/multi-byte/⌘⌘'
|
||||||
|
|
||||||
|
let l:actual = go#uri#Decode(go#uri#EncodePath(l:expected))
|
||||||
|
call assert_equal(l:expected, l:actual)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" restore Vi compatibility settings
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
|
||||||
|
" vim: sw=2 ts=2 et
|
|
@ -36,15 +36,9 @@ function! go#util#Join(...) abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" IsWin returns 1 if current OS is Windows or 0 otherwise
|
" IsWin returns 1 if current OS is Windows or 0 otherwise
|
||||||
|
" Note that has('win32') is always 1 when has('win64') is 1, so has('win32') is enough.
|
||||||
function! go#util#IsWin() abort
|
function! go#util#IsWin() abort
|
||||||
let win = ['win16', 'win32', 'win64', 'win95']
|
return has('win32')
|
||||||
for w in win
|
|
||||||
if (has(w))
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return 0
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" IsMac returns 1 if current OS is macOS or 0 otherwise.
|
" IsMac returns 1 if current OS is macOS or 0 otherwise.
|
||||||
|
@ -68,18 +62,7 @@ endfunction
|
||||||
" The (optional) first parameter can be added to indicate the 'cwd' or 'env'
|
" The (optional) first parameter can be added to indicate the 'cwd' or 'env'
|
||||||
" parameters will be used, which wasn't added until a later version.
|
" parameters will be used, which wasn't added until a later version.
|
||||||
function! go#util#has_job(...) abort
|
function! go#util#has_job(...) abort
|
||||||
if has('nvim')
|
return has('job') || has('nvim')
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
" cwd and env parameters to job_start was added in this version.
|
|
||||||
if a:0 > 0 && a:1 is 1
|
|
||||||
return has('job') && has("patch-8.0.0902")
|
|
||||||
endif
|
|
||||||
|
|
||||||
" job was introduced in 7.4.xxx however there are multiple bug fixes and one
|
|
||||||
" of the latest is 8.0.0087 which is required for a stable async API.
|
|
||||||
return has('job') && has("patch-8.0.0087")
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let s:env_cache = {}
|
let s:env_cache = {}
|
||||||
|
@ -137,9 +120,39 @@ function! go#util#gomod() abort
|
||||||
return substitute(s:exec(['go', 'env', 'GOMOD'])[0], '\n', '', 'g')
|
return substitute(s:exec(['go', 'env', 'GOMOD'])[0], '\n', '', 'g')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" gomodcache returns 'go env GOMODCACHE'. Instead use 'go#util#env("gomodcache")'
|
||||||
|
function! go#util#gomodcache() abort
|
||||||
|
return substitute(s:exec(['go', 'env', 'GOMODCACHE'])[0], '\n', '', 'g')
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! go#util#osarch() abort
|
" hostosarch returns the OS and ARCH values that the go binary is intended for.
|
||||||
return go#util#env("goos") . '_' . go#util#env("goarch")
|
function! go#util#hostosarch() abort
|
||||||
|
let [l:hostos, l:err] = s:exec(['go', 'env', 'GOHOSTOS'])
|
||||||
|
let [l:hostarch, l:err] = s:exec(['go', 'env', 'GOHOSTARCH'])
|
||||||
|
return [substitute(l:hostos, '\n', '', 'g'), substitute(l:hostarch, '\n', '', 'g')]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" go#util#ModuleRoot returns the root directory of the module of the current
|
||||||
|
" buffer.
|
||||||
|
function! go#util#ModuleRoot() abort
|
||||||
|
let [l:out, l:err] = go#util#ExecInDir(['go', 'env', 'GOMOD'])
|
||||||
|
if l:err != 0
|
||||||
|
return -1
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:module = split(l:out, '\n', 1)[0]
|
||||||
|
|
||||||
|
" When run with `GO111MODULE=on and not in a module directory, the module will be reported as /dev/null.
|
||||||
|
let l:fakeModule = '/dev/null'
|
||||||
|
if go#util#IsWin()
|
||||||
|
let l:fakeModule = 'NUL'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if l:fakeModule == l:module
|
||||||
|
return expand('%:p:h')
|
||||||
|
endif
|
||||||
|
|
||||||
|
return resolve(fnamemodify(l:module, ':p:h'))
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Run a shell command.
|
" Run a shell command.
|
||||||
|
@ -157,6 +170,13 @@ function! s:system(cmd, ...) abort
|
||||||
set shell=/bin/sh shellredir=>%s\ 2>&1 shellcmdflag=-c
|
set shell=/bin/sh shellredir=>%s\ 2>&1 shellcmdflag=-c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if go#util#IsWin()
|
||||||
|
if executable($COMSPEC)
|
||||||
|
let &shell = $COMSPEC
|
||||||
|
set shellcmdflag=/C
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
try
|
try
|
||||||
return call('system', [a:cmd] + a:000)
|
return call('system', [a:cmd] + a:000)
|
||||||
finally
|
finally
|
||||||
|
@ -196,18 +216,25 @@ function! go#util#Exec(cmd, ...) abort
|
||||||
return call('s:exec', [[l:bin] + a:cmd[1:]] + a:000)
|
return call('s:exec', [[l:bin] + a:cmd[1:]] + a:000)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" ExecInDir will execute cmd with the working directory set to the current
|
||||||
|
" buffer's directory.
|
||||||
function! go#util#ExecInDir(cmd, ...) abort
|
function! go#util#ExecInDir(cmd, ...) abort
|
||||||
if !isdirectory(expand("%:p:h"))
|
let l:wd = expand('%:p:h')
|
||||||
|
return call('go#util#ExecInWorkDir', [a:cmd, l:wd] + a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" ExecInWorkDir will execute cmd with the working diretory set to wd. Additional arguments will be passed
|
||||||
|
" to cmd.
|
||||||
|
function! go#util#ExecInWorkDir(cmd, wd, ...) abort
|
||||||
|
if !isdirectory(a:wd)
|
||||||
return ['', 1]
|
return ['', 1]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
let l:dir = go#util#Chdir(a:wd)
|
||||||
let dir = getcwd()
|
|
||||||
try
|
try
|
||||||
execute cd . fnameescape(expand("%:p:h"))
|
|
||||||
let [l:out, l:err] = call('go#util#Exec', [a:cmd] + a:000)
|
let [l:out, l:err] = call('go#util#Exec', [a:cmd] + a:000)
|
||||||
finally
|
finally
|
||||||
execute cd . fnameescape(l:dir)
|
call go#util#Chdir(l:dir)
|
||||||
endtry
|
endtry
|
||||||
return [l:out, l:err]
|
return [l:out, l:err]
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -446,7 +473,7 @@ function! go#util#tempdir(prefix) abort
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Not great randomness, but "good enough" for our purpose here.
|
" Not great randomness, but "good enough" for our purpose here.
|
||||||
let l:rnd = sha256(printf('%s%s', localtime(), fnamemodify(bufname(''), ":p")))
|
let l:rnd = sha256(printf('%s%s', reltimestr(reltime()), fnamemodify(bufname(''), ":p")))
|
||||||
let l:tmp = printf("%s/%s%s", l:dir, a:prefix, l:rnd)
|
let l:tmp = printf("%s/%s%s", l:dir, a:prefix, l:rnd)
|
||||||
call mkdir(l:tmp, 'p', 0700)
|
call mkdir(l:tmp, 'p', 0700)
|
||||||
return l:tmp
|
return l:tmp
|
||||||
|
@ -519,6 +546,170 @@ function! go#util#ShowInfo(info)
|
||||||
echo "vim-go: " | echohl Function | echon a:info | echohl None
|
echo "vim-go: " | echohl Function | echon a:info | echohl None
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" go#util#SetEnv takes the name of an environment variable and what its value
|
||||||
|
" should be and returns a function that will restore it to its original value.
|
||||||
|
function! go#util#SetEnv(name, value) abort
|
||||||
|
let l:state = {}
|
||||||
|
|
||||||
|
if len(a:name) == 0
|
||||||
|
return function('s:noop', [], l:state)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:remove = 0
|
||||||
|
if exists('$' . a:name)
|
||||||
|
let l:oldvalue = eval('$' . a:name)
|
||||||
|
else
|
||||||
|
let l:remove = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
" wrap the value in single quotes so that it will work on windows when there
|
||||||
|
" are backslashes present in the value (e.g. $PATH).
|
||||||
|
call execute('let $' . a:name . " = '" . a:value . "'")
|
||||||
|
|
||||||
|
if l:remove
|
||||||
|
return function('s:unset', [a:name], l:state)
|
||||||
|
endif
|
||||||
|
|
||||||
|
return function('go#util#SetEnv', [a:name, l:oldvalue], l:state)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#util#ClearHighlights(group) abort
|
||||||
|
if has('textprop')
|
||||||
|
" the property type may not exist when syntax highlighting is not enabled.
|
||||||
|
if empty(prop_type_get(a:group))
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
if !has('patch-8.1.1035')
|
||||||
|
return prop_remove({'type': a:group, 'all': 1}, 1, line('$'))
|
||||||
|
endif
|
||||||
|
return prop_remove({'type': a:group, 'all': 1})
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists("*matchaddpos")
|
||||||
|
return s:clear_group_from_matches(a:group)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:clear_group_from_matches(group) abort
|
||||||
|
let l:cleared = 0
|
||||||
|
|
||||||
|
let m = getmatches()
|
||||||
|
for item in m
|
||||||
|
if item['group'] == a:group
|
||||||
|
call matchdelete(item['id'])
|
||||||
|
let l:cleared = 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return l:cleared
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:unset(name) abort
|
||||||
|
try
|
||||||
|
" unlet $VAR was introducted in Vim 8.0.1832, which is newer than the
|
||||||
|
" minimal version that vim-go supports. Set the environment variable to
|
||||||
|
" the empty string in that case. It's not perfect, but it will work fine
|
||||||
|
" for most things, and is really the best alternative that's available.
|
||||||
|
if !has('patch-8.0.1832')
|
||||||
|
call go#util#SetEnv(a:name, '')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
call execute('unlet $' . a:name)
|
||||||
|
catch
|
||||||
|
call go#util#EchoError(printf('could not unset $%s: %s', a:name, v:exception))
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:noop(...) abort dict
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" go#util#HighlightPositions highlights using text properties if possible and
|
||||||
|
" falls back to matchaddpos() if necessary. It works around matchaddpos()'s
|
||||||
|
" limit of only 8 positions per call by calling matchaddpos() with no more
|
||||||
|
" than 8 positions per call.
|
||||||
|
"
|
||||||
|
" pos should be a list of 3 element lists. The lists should be [line, col,
|
||||||
|
" length] as used by matchaddpos().
|
||||||
|
function! go#util#HighlightPositions(group, pos) abort
|
||||||
|
if has('textprop')
|
||||||
|
for l:pos in a:pos
|
||||||
|
" use a single line prop by default
|
||||||
|
let l:prop = {'type': a:group, 'length': l:pos[2]}
|
||||||
|
|
||||||
|
let l:line = getline(l:pos[0])
|
||||||
|
|
||||||
|
" l:max is the 1-based index within the buffer of the first character after l:pos.
|
||||||
|
let l:max = line2byte(l:pos[0]) + l:pos[1] + l:pos[2] - 1
|
||||||
|
if has('patch-8.2.115')
|
||||||
|
" Use byte2line as long as 8.2.115 (which resolved
|
||||||
|
" https://github.com/vim/vim/issues/5334) is available.
|
||||||
|
let l:end_lnum = byte2line(l:max)
|
||||||
|
|
||||||
|
" specify end line and column if needed.
|
||||||
|
if l:pos[0] != l:end_lnum
|
||||||
|
let l:end_col = l:max - line2byte(l:end_lnum)
|
||||||
|
let l:prop = {'type': a:group, 'end_lnum': l:end_lnum, 'end_col': l:end_col}
|
||||||
|
endif
|
||||||
|
elseif l:pos[1] + l:pos[2] - 1 > len(l:line)
|
||||||
|
let l:end_lnum = l:pos[0]
|
||||||
|
while line2byte(l:end_lnum+1) < l:max
|
||||||
|
let l:end_lnum += 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
" l:end_col is the full length - the byte position of l:end_lnum +
|
||||||
|
" the number of newlines (number of newlines is l:end_lnum -
|
||||||
|
" l:pos[0].
|
||||||
|
let l:end_col = l:max - line2byte(l:end_lnum) + l:end_lnum - l:pos[0]
|
||||||
|
let l:prop = {'type': a:group, 'end_lnum': l:end_lnum, 'end_col': l:end_col}
|
||||||
|
endif
|
||||||
|
try
|
||||||
|
call prop_add(l:pos[0], l:pos[1], l:prop)
|
||||||
|
catch
|
||||||
|
" Swallow any exceptions encountered while trying to add the property
|
||||||
|
" Due to the asynchronous nature, it's possible that the buffer has
|
||||||
|
" changed since the buffer was analyzed and that the specified
|
||||||
|
" position is no longer valid.
|
||||||
|
endtry
|
||||||
|
endfor
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists('*matchaddpos')
|
||||||
|
return s:matchaddpos(a:group, a:pos)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" s:matchaddpos works around matchaddpos()'s limit of only 8 positions per
|
||||||
|
" call by calling matchaddpos() with no more than 8 positions per call.
|
||||||
|
function! s:matchaddpos(group, pos) abort
|
||||||
|
let l:partitions = []
|
||||||
|
let l:partitionsIdx = 0
|
||||||
|
let l:posIdx = 0
|
||||||
|
for l:pos in a:pos
|
||||||
|
if l:posIdx % 8 == 0
|
||||||
|
let l:partitions = add(l:partitions, [])
|
||||||
|
let l:partitionsIdx = len(l:partitions) - 1
|
||||||
|
endif
|
||||||
|
let l:partitions[l:partitionsIdx] = add(l:partitions[l:partitionsIdx], l:pos)
|
||||||
|
let l:posIdx = l:posIdx + 1
|
||||||
|
endfor
|
||||||
|
|
||||||
|
for l:positions in l:partitions
|
||||||
|
call matchaddpos(a:group, l:positions)
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! go#util#Chdir(dir) abort
|
||||||
|
if !exists('*chdir')
|
||||||
|
let l:olddir = getcwd()
|
||||||
|
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||||
|
execute cd . fnameescape(a:dir)
|
||||||
|
return l:olddir
|
||||||
|
endif
|
||||||
|
return chdir(a:dir)
|
||||||
|
endfunction
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
let &cpo = s:cpo_save
|
let &cpo = s:cpo_save
|
||||||
unlet s:cpo_save
|
unlet s:cpo_save
|
||||||
|
|
|
@ -18,16 +18,23 @@ fun! gotest#write_file(path, contents) abort
|
||||||
|
|
||||||
call mkdir(fnamemodify(l:full_path, ':h'), 'p')
|
call mkdir(fnamemodify(l:full_path, ':h'), 'p')
|
||||||
call writefile(a:contents, l:full_path)
|
call writefile(a:contents, l:full_path)
|
||||||
exe 'cd ' . l:dir . '/src'
|
call go#util#Chdir(l:dir . '/src')
|
||||||
|
|
||||||
silent exe 'e! ' . a:path
|
silent exe 'e! ' . a:path
|
||||||
|
|
||||||
" Set cursor.
|
" Set cursor.
|
||||||
let l:lnum = 1
|
let l:lnum = 1
|
||||||
for l:line in a:contents
|
for l:line in a:contents
|
||||||
let l:m = match(l:line, "\x1f")
|
let l:m = stridx(l:line, "\x1f")
|
||||||
if l:m > -1
|
if l:m > -1
|
||||||
call setpos('.', [0, l:lnum, l:m, 0])
|
let l:byte = line2byte(l:lnum) + l:m
|
||||||
|
exe 'goto '. l:byte
|
||||||
call setline('.', substitute(getline('.'), "\x1f", '', ''))
|
call setline('.', substitute(getline('.'), "\x1f", '', ''))
|
||||||
|
silent noautocmd w!
|
||||||
|
|
||||||
|
call go#lsp#DidClose(expand('%:p'))
|
||||||
|
call go#lsp#DidOpen(expand('%:p'))
|
||||||
|
|
||||||
break
|
break
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -42,15 +49,21 @@ endfun
|
||||||
" The file will be copied to a new GOPATH-compliant temporary directory and
|
" The file will be copied to a new GOPATH-compliant temporary directory and
|
||||||
" loaded as the current buffer.
|
" loaded as the current buffer.
|
||||||
fun! gotest#load_fixture(path) abort
|
fun! gotest#load_fixture(path) abort
|
||||||
|
if go#util#has_job()
|
||||||
|
call go#lsp#CleanWorkspaces()
|
||||||
|
endif
|
||||||
let l:dir = go#util#tempdir("vim-go-test/testrun/")
|
let l:dir = go#util#tempdir("vim-go-test/testrun/")
|
||||||
let $GOPATH .= ':' . l:dir
|
let $GOPATH .= ':' . l:dir
|
||||||
let l:full_path = l:dir . '/src/' . a:path
|
let l:full_path = l:dir . '/src/' . a:path
|
||||||
|
|
||||||
call mkdir(fnamemodify(l:full_path, ':h'), 'p')
|
call mkdir(fnamemodify(l:full_path, ':h'), 'p')
|
||||||
exe 'cd ' . l:dir . '/src'
|
call go#util#Chdir(l:dir . '/src')
|
||||||
silent exe 'noautocmd e ' . a:path
|
silent exe 'noautocmd e! ' . a:path
|
||||||
silent exe printf('read %s/test-fixtures/%s', g:vim_go_root, a:path)
|
silent exe printf('read %s/test-fixtures/%s', g:vim_go_root, a:path)
|
||||||
silent noautocmd w!
|
silent noautocmd w!
|
||||||
|
if go#util#has_job()
|
||||||
|
call go#lsp#AddWorkspaceDirectory(fnamemodify(l:full_path, ':p:h'))
|
||||||
|
endif
|
||||||
|
|
||||||
return l:dir
|
return l:dir
|
||||||
endfun
|
endfun
|
||||||
|
@ -109,26 +122,29 @@ endfun
|
||||||
func! gotest#assert_quickfix(got, want) abort
|
func! gotest#assert_quickfix(got, want) abort
|
||||||
call assert_equal(len(a:want), len(a:got), "number of errors")
|
call assert_equal(len(a:want), len(a:got), "number of errors")
|
||||||
if len(a:want) != len(a:got)
|
if len(a:want) != len(a:got)
|
||||||
call assert_equal(a:want, a:got)
|
return assert_equal(a:want, a:got)
|
||||||
return
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let l:retval = 0
|
||||||
let i = 0
|
let i = 0
|
||||||
|
|
||||||
while i < len(a:want)
|
while i < len(a:want)
|
||||||
let want_item = a:want[i]
|
let want_item = a:want[i]
|
||||||
let got_item = a:got[i]
|
let got_item = a:got[i]
|
||||||
let i += 1
|
let i += 1
|
||||||
|
|
||||||
call assert_equal(want_item.bufnr, got_item.bufnr, "bufnr")
|
let l:retval = assert_equal(want_item.bufnr, got_item.bufnr, "bufnr") || l:retval
|
||||||
call assert_equal(want_item.lnum, got_item.lnum, "lnum")
|
let l:retval = assert_equal(want_item.lnum, got_item.lnum, "lnum") || l:retval
|
||||||
call assert_equal(want_item.col, got_item.col, "col")
|
let l:retval = assert_equal(want_item.col, got_item.col, "col") || l:retval
|
||||||
call assert_equal(want_item.vcol, got_item.vcol, "vcol")
|
let l:retval = assert_equal(want_item.vcol, got_item.vcol, "vcol") || l:retval
|
||||||
call assert_equal(want_item.nr, got_item.nr, "nr")
|
let l:retval = assert_equal(want_item.nr, got_item.nr, "nr") || l:retval
|
||||||
call assert_equal(want_item.pattern, got_item.pattern, "pattern")
|
let l:retval = assert_equal(want_item.pattern, got_item.pattern, "pattern") || l:retval
|
||||||
call assert_equal(want_item.text, got_item.text, "text")
|
let l:retval = assert_equal(want_item.text, got_item.text, "text") || l:retval
|
||||||
call assert_equal(want_item.type, got_item.type, "type")
|
let l:retval = assert_equal(want_item.type, got_item.type, "type") || l:retval
|
||||||
call assert_equal(want_item.valid, got_item.valid, "valid")
|
let l:retval = assert_equal(want_item.valid, got_item.valid, "valid") || l:retval
|
||||||
endwhile
|
endwhile
|
||||||
|
|
||||||
|
return l:retval
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" restore Vi compatibility settings
|
" restore Vi compatibility settings
|
||||||
|
|
|
@ -31,14 +31,13 @@ endif
|
||||||
" use a different output, for those we define them directly and modify the
|
" use a different output, for those we define them directly and modify the
|
||||||
" errorformat ourselves. More information at:
|
" errorformat ourselves. More information at:
|
||||||
" http://vimdoc.sourceforge.net/htmldoc/quickfix.html#errorformat
|
" http://vimdoc.sourceforge.net/htmldoc/quickfix.html#errorformat
|
||||||
CompilerSet errorformat =%-G#\ %.%# " Ignore lines beginning with '#' ('# command-line-arguments' line sometimes appears?)
|
CompilerSet errorformat =%-G#\ %.%# " Ignore lines beginning with '#' ('# command-line-arguments' line sometimes appears?)
|
||||||
CompilerSet errorformat+=%-G%.%#panic:\ %m " Ignore lines containing 'panic: message'
|
CompilerSet errorformat+=%-G%.%#panic:\ %m " Ignore lines containing 'panic: message'
|
||||||
CompilerSet errorformat+=%Ecan\'t\ load\ package:\ %m " Start of multiline error string is 'can\'t load package'
|
CompilerSet errorformat+=%Ecan\'t\ load\ package:\ %m " Start of multiline error string is 'can\'t load package'
|
||||||
CompilerSet errorformat+=%A%f:%l:%c:\ %m " Start of multiline unspecified string is 'filename:linenumber:columnnumber:'
|
CompilerSet errorformat+=%A%\\%%(%[%^:]%\\+:\ %\\)%\\?%f:%l:%c:\ %m " Start of multiline unspecified string is 'filename:linenumber:columnnumber:'
|
||||||
CompilerSet errorformat+=%A%f:%l:\ %m " Start of multiline unspecified string is 'filename:linenumber:'
|
CompilerSet errorformat+=%A%\\%%(%[%^:]%\\+:\ %\\)%\\?%f:%l:\ %m " Start of multiline unspecified string is 'filename:linenumber:'
|
||||||
CompilerSet errorformat+=%C%*\\s%m " Continuation of multiline error message is indented
|
CompilerSet errorformat+=%C%*\\s%m " Continuation of multiline error message is indented
|
||||||
CompilerSet errorformat+=%-G%.%# " All lines not matching any of the above patterns are ignored
|
CompilerSet errorformat+=%-G%.%# " All lines not matching any of the above patterns are ignored
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
let &cpo = s:save_cpo
|
||||||
unlet s:save_cpo
|
unlet s:save_cpo
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,8 +13,8 @@ let b:did_ftplugin = 1
|
||||||
let s:cpo_save = &cpo
|
let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
let b:undo_ftplugin = "setl fo< com< cms<
|
let b:undo_ftplugin = "setl fo< com< cms<"
|
||||||
\ | exe 'au! vim-go-buffer * <buffer>'"
|
\ . "| exe 'au! vim-go-buffer * <buffer>'"
|
||||||
|
|
||||||
setlocal formatoptions-=t
|
setlocal formatoptions-=t
|
||||||
|
|
||||||
|
@ -25,10 +25,9 @@ setlocal noexpandtab
|
||||||
|
|
||||||
compiler go
|
compiler go
|
||||||
|
|
||||||
" Set autocompletion
|
if go#config#CodeCompletionEnabled()
|
||||||
setlocal omnifunc=go#complete#Complete
|
" Set autocompletion
|
||||||
if !go#util#has_job()
|
setlocal omnifunc=go#complete#Complete
|
||||||
setlocal omnifunc=go#complete#GocodeComplete
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get(g:, "go_doc_keywordprg_enabled", 1)
|
if get(g:, "go_doc_keywordprg_enabled", 1)
|
||||||
|
@ -72,43 +71,59 @@ if get(g:, "go_textobj_enabled", 1)
|
||||||
xnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('v', 'prev')<cr>
|
xnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('v', 'prev')<cr>
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if go#config#AutoTypeInfo() || go#config#AutoSameids()
|
|
||||||
let &l:updatetime= get(g:, "go_updatetime", 800)
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Autocommands
|
" Autocommands
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
"
|
"
|
||||||
augroup vim-go-buffer
|
augroup vim-go-buffer
|
||||||
autocmd! * <buffer>
|
autocmd! * <buffer>
|
||||||
|
|
||||||
" The file is registered (textDocument/DidOpen) with gopls in in
|
" The file is registered (textDocument/DidOpen) with gopls in plugin/go.vim
|
||||||
" plugin/go.vim on the FileType event.
|
" on the FileType event.
|
||||||
" TODO(bc): handle all the other events that may be of interest to gopls,
|
|
||||||
" too (e.g. BufFilePost , CursorHold , CursorHoldI, FileReadPost,
|
|
||||||
" StdinReadPre, BufWritePost, TextChange, TextChangedI)
|
|
||||||
if go#util#has_job()
|
if go#util#has_job()
|
||||||
autocmd BufWritePost <buffer> call go#lsp#DidChange(expand('<afile>:p'))
|
autocmd BufWritePost,FileChangedShellPost <buffer> call go#lsp#DidChange(expand('<afile>:p'))
|
||||||
autocmd FileChangedShell <buffer> call go#lsp#DidChange(expand('<afile>:p'))
|
|
||||||
autocmd BufDelete <buffer> call go#lsp#DidClose(expand('<afile>:p'))
|
autocmd BufDelete <buffer> call go#lsp#DidClose(expand('<afile>:p'))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
autocmd CursorHold <buffer> call go#auto#auto_type_info()
|
" send the textDocument/didChange notification when idle. go#lsp#DidChange
|
||||||
autocmd CursorHold <buffer> call go#auto#auto_sameids()
|
" will not send an event if the buffer hasn't changed since the last
|
||||||
|
" notification.
|
||||||
|
autocmd CursorHold,CursorHoldI <buffer> call go#lsp#DidChange(expand('<afile>:p'))
|
||||||
|
|
||||||
|
autocmd BufEnter,CursorHold <buffer> call go#auto#update_autocmd()
|
||||||
|
|
||||||
" Echo the identifier information when completion is done. Useful to see
|
" Echo the identifier information when completion is done. Useful to see
|
||||||
" the signature of a function, etc...
|
" the signature of a function, etc...
|
||||||
if exists('##CompleteDone')
|
if exists('##CompleteDone')
|
||||||
autocmd CompleteDone <buffer> call go#auto#echo_go_info()
|
autocmd CompleteDone <buffer> call go#auto#complete_done()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
autocmd BufWritePre <buffer> call go#auto#fmt_autosave()
|
autocmd BufWritePre <buffer> call go#auto#fmt_autosave()
|
||||||
autocmd BufWritePost <buffer> call go#auto#metalinter_autosave()
|
autocmd BufWritePost <buffer> call go#auto#metalinter_autosave()
|
||||||
|
|
||||||
" clear SameIds when the buffer is unloaded so that loading another buffer
|
if !has('textprop')
|
||||||
" in the same window doesn't highlight the most recently matched
|
"TODO(bc): how to clear sameids and diagnostics when a non-go buffer is
|
||||||
" identifier's positions.
|
" loaded into a window and the previously loaded buffer is still loaded in
|
||||||
autocmd BufWinEnter <buffer> call go#guru#ClearSameIds()
|
" another window?
|
||||||
|
|
||||||
|
" TODO(bc): only clear when the new buffer isn't the old buffer
|
||||||
|
|
||||||
|
" clear SameIds when the buffer is unloaded from its last window so that
|
||||||
|
" loading another buffer (especially of a different filetype) in the same
|
||||||
|
" window doesn't highlight the most recently matched identifier's positions.
|
||||||
|
autocmd BufWinLeave <buffer> call go#guru#ClearSameIds()
|
||||||
|
" clear SameIds when a new buffer is loaded in the window so that the
|
||||||
|
" previous buffer's highlighting isn't used.
|
||||||
|
autocmd BufWinEnter <buffer> call go#guru#ClearSameIds()
|
||||||
|
|
||||||
|
" clear diagnostics when the buffer is unloaded from its last window so that
|
||||||
|
" loading another buffer (especially of a different filetype) in the same
|
||||||
|
" window doesn't highlight the previously loaded buffer's diagnostics.
|
||||||
|
autocmd BufWinLeave <buffer> call go#lsp#ClearDiagnosticHighlights()
|
||||||
|
" clear diagnostics when a new buffer is loaded in the window so that the
|
||||||
|
" previous buffer's diagnostics aren't used.
|
||||||
|
"autocmd BufWinEnter <buffer> call go#lsp#ClearDiagnosticHighlights()
|
||||||
|
endif
|
||||||
|
|
||||||
autocmd BufEnter <buffer>
|
autocmd BufEnter <buffer>
|
||||||
\ if go#config#AutodetectGopath() && !exists('b:old_gopath')
|
\ if go#config#AutodetectGopath() && !exists('b:old_gopath')
|
||||||
|
|
|
@ -3,7 +3,7 @@ command! -nargs=? -complete=customlist,go#rename#Complete GoRename call go#renam
|
||||||
|
|
||||||
" -- guru
|
" -- guru
|
||||||
command! -nargs=* -complete=customlist,go#package#Complete GoGuruScope call go#guru#Scope(<f-args>)
|
command! -nargs=* -complete=customlist,go#package#Complete GoGuruScope call go#guru#Scope(<f-args>)
|
||||||
command! -range=% GoImplements call go#guru#Implements(<count>)
|
command! -range=% GoImplements call go#implements#Implements(<count>)
|
||||||
command! -range=% GoPointsTo call go#guru#PointsTo(<count>)
|
command! -range=% GoPointsTo call go#guru#PointsTo(<count>)
|
||||||
command! -range=% GoWhicherrs call go#guru#Whicherrs(<count>)
|
command! -range=% GoWhicherrs call go#guru#Whicherrs(<count>)
|
||||||
command! -range=% GoCallees call go#guru#Callees(<count>)
|
command! -range=% GoCallees call go#guru#Callees(<count>)
|
||||||
|
@ -12,7 +12,7 @@ command! -range=% GoCallers call go#guru#Callers(<count>)
|
||||||
command! -range=% GoCallstack call go#guru#Callstack(<count>)
|
command! -range=% GoCallstack call go#guru#Callstack(<count>)
|
||||||
command! -range=% GoFreevars call go#guru#Freevars(<count>)
|
command! -range=% GoFreevars call go#guru#Freevars(<count>)
|
||||||
command! -range=% GoChannelPeers call go#guru#ChannelPeers(<count>)
|
command! -range=% GoChannelPeers call go#guru#ChannelPeers(<count>)
|
||||||
command! -range=% GoReferrers call go#guru#Referrers(<count>)
|
command! -range=% GoReferrers call go#referrers#Referrers(<count>)
|
||||||
|
|
||||||
command! -range=0 GoSameIds call go#guru#SameIds(1)
|
command! -range=0 GoSameIds call go#guru#SameIds(1)
|
||||||
command! -range=0 GoSameIdsClear call go#guru#ClearSameIds()
|
command! -range=0 GoSameIdsClear call go#guru#ClearSameIds()
|
||||||
|
@ -105,8 +105,9 @@ command! -nargs=0 GoFillStruct call go#fillstruct#FillStruct()
|
||||||
|
|
||||||
" -- debug
|
" -- debug
|
||||||
if !exists(':GoDebugStart')
|
if !exists(':GoDebugStart')
|
||||||
command! -nargs=* -complete=customlist,go#package#Complete GoDebugStart call go#debug#Start(0, <f-args>)
|
command! -nargs=* -complete=customlist,go#package#Complete GoDebugStart call go#debug#Start('debug', <f-args>)
|
||||||
command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start(1, <f-args>)
|
command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start('test', <f-args>)
|
||||||
|
command! -nargs=1 GoDebugAttach call go#debug#Start('attach', <f-args>)
|
||||||
command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint(<f-args>)
|
command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint(<f-args>)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -116,4 +117,12 @@ command! -nargs=0 GoReportGitHubIssue call go#issue#New()
|
||||||
" -- iferr
|
" -- iferr
|
||||||
command! -nargs=0 GoIfErr call go#iferr#Generate()
|
command! -nargs=0 GoIfErr call go#iferr#Generate()
|
||||||
|
|
||||||
|
" -- lsp
|
||||||
|
command! -nargs=+ -complete=dir GoAddWorkspace call go#lsp#AddWorkspaceDirectory(<f-args>)
|
||||||
|
command! -nargs=0 GoLSPDebugBrowser call go#lsp#DebugBrowser()
|
||||||
|
command! -nargs=* -bang GoDiagnostics call go#lint#Diagnostics(<bang>0, <f-args>)
|
||||||
|
|
||||||
|
" -- term
|
||||||
|
command! GoToggleTermCloseOnExit call go#term#ToggleCloseOnExit()
|
||||||
|
|
||||||
" vim: sw=2 ts=2 et
|
" vim: sw=2 ts=2 et
|
||||||
|
|
|
@ -11,7 +11,7 @@ endif
|
||||||
" Some handy plug mappings
|
" Some handy plug mappings
|
||||||
nnoremap <silent> <Plug>(go-run) :<C-u>call go#cmd#Run(!g:go_jump_to_error)<CR>
|
nnoremap <silent> <Plug>(go-run) :<C-u>call go#cmd#Run(!g:go_jump_to_error)<CR>
|
||||||
|
|
||||||
if has("nvim")
|
if has("nvim") || has("terminal")
|
||||||
nnoremap <silent> <Plug>(go-run-vertical) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'vsplit', [])<CR>
|
nnoremap <silent> <Plug>(go-run-vertical) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'vsplit', [])<CR>
|
||||||
nnoremap <silent> <Plug>(go-run-split) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'split', [])<CR>
|
nnoremap <silent> <Plug>(go-run-split) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'split', [])<CR>
|
||||||
nnoremap <silent> <Plug>(go-run-tab) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'tabe', [])<CR>
|
nnoremap <silent> <Plug>(go-run-tab) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'tabe', [])<CR>
|
||||||
|
@ -35,14 +35,14 @@ nnoremap <silent> <Plug>(go-info) :<C-u>call go#tool#Info(1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-import) :<C-u>call go#import#SwitchImport(1, '', expand('<cword>'), '')<CR>
|
nnoremap <silent> <Plug>(go-import) :<C-u>call go#import#SwitchImport(1, '', expand('<cword>'), '')<CR>
|
||||||
nnoremap <silent> <Plug>(go-imports) :<C-u>call go#fmt#Format(1)<CR>
|
nnoremap <silent> <Plug>(go-imports) :<C-u>call go#fmt#Format(1)<CR>
|
||||||
|
|
||||||
nnoremap <silent> <Plug>(go-implements) :<C-u>call go#guru#Implements(-1)<CR>
|
nnoremap <silent> <Plug>(go-implements) :<C-u>call go#implements#Implements(-1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-callees) :<C-u>call go#guru#Callees(-1)<CR>
|
nnoremap <silent> <Plug>(go-callees) :<C-u>call go#guru#Callees(-1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-callers) :<C-u>call go#guru#Callers(-1)<CR>
|
nnoremap <silent> <Plug>(go-callers) :<C-u>call go#guru#Callers(-1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-describe) :<C-u>call go#guru#Describe(-1)<CR>
|
nnoremap <silent> <Plug>(go-describe) :<C-u>call go#guru#Describe(-1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-callstack) :<C-u>call go#guru#Callstack(-1)<CR>
|
nnoremap <silent> <Plug>(go-callstack) :<C-u>call go#guru#Callstack(-1)<CR>
|
||||||
xnoremap <silent> <Plug>(go-freevars) :<C-u>call go#guru#Freevars(0)<CR>
|
xnoremap <silent> <Plug>(go-freevars) :<C-u>call go#guru#Freevars(0)<CR>
|
||||||
nnoremap <silent> <Plug>(go-channelpeers) :<C-u>call go#guru#ChannelPeers(-1)<CR>
|
nnoremap <silent> <Plug>(go-channelpeers) :<C-u>call go#guru#ChannelPeers(-1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-referrers) :<C-u>call go#guru#Referrers(-1)<CR>
|
nnoremap <silent> <Plug>(go-referrers) :<C-u>call go#referrers#Referrers(-1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-sameids) :<C-u>call go#guru#SameIds(1)<CR>
|
nnoremap <silent> <Plug>(go-sameids) :<C-u>call go#guru#SameIds(1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-pointsto) :<C-u>call go#guru#PointsTo(-1)<CR>
|
nnoremap <silent> <Plug>(go-pointsto) :<C-u>call go#guru#PointsTo(-1)<CR>
|
||||||
nnoremap <silent> <Plug>(go-whicherrs) :<C-u>call go#guru#Whicherrs(-1)<CR>
|
nnoremap <silent> <Plug>(go-whicherrs) :<C-u>call go#guru#Whicherrs(-1)<CR>
|
||||||
|
@ -83,4 +83,6 @@ nnoremap <silent> <Plug>(go-alternate-split) :<C-u>call go#alternate#Switch(0, "
|
||||||
|
|
||||||
nnoremap <silent> <Plug>(go-iferr) :<C-u>call go#iferr#Generate()<CR>
|
nnoremap <silent> <Plug>(go-iferr) :<C-u>call go#iferr#Generate()<CR>
|
||||||
|
|
||||||
|
nnoremap <silent> <Plug>(go-diagnostics) :<C-u>call go#lint#Diagnostics(!g:go_jump_to_error)<CR>
|
||||||
|
|
||||||
" vim: sw=2 ts=2 et
|
" vim: sw=2 ts=2 et
|
||||||
|
|
|
@ -52,19 +52,11 @@ endfunction
|
||||||
|
|
||||||
|
|
||||||
let s:engine = go#config#SnippetEngine()
|
let s:engine = go#config#SnippetEngine()
|
||||||
if s:engine is? "automatic"
|
if s:engine is? 'ultisnips'
|
||||||
if get(g:, 'did_plugin_ultisnips') is 1
|
|
||||||
call s:GoUltiSnips()
|
|
||||||
elseif get(g:, 'loaded_neosnippet') is 1
|
|
||||||
call s:GoNeosnippet()
|
|
||||||
elseif get(g:, 'loaded_minisnip') is 1
|
|
||||||
call s:GoMinisnip()
|
|
||||||
endif
|
|
||||||
elseif s:engine is? "ultisnips"
|
|
||||||
call s:GoUltiSnips()
|
call s:GoUltiSnips()
|
||||||
elseif s:engine is? "neosnippet"
|
elseif s:engine is? 'neosnippet'
|
||||||
call s:GoNeosnippet()
|
call s:GoNeosnippet()
|
||||||
elseif s:engine is? "minisnip"
|
elseif s:engine is? 'minisnip'
|
||||||
call s:GoMinisnip()
|
call s:GoMinisnip()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -144,20 +144,42 @@ else {
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
# if inline error
|
# if inline error
|
||||||
snippet ife "If with inline erro"
|
snippet ife "If with inline error"
|
||||||
if err := ${1:condition}; err != nil {
|
if err := ${1:condition}; err != nil {
|
||||||
${0:${VISUAL}}
|
${0:${VISUAL}}
|
||||||
}
|
}
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
snippet ew "errors.Wrap"
|
||||||
|
errors.Wrap(${1:err}, "${2:message}")
|
||||||
|
endsnippet
|
||||||
|
|
||||||
|
snippet ewf "errors.Wrapf"
|
||||||
|
errors.Wrapf(${1:err}, "${2:message %v}", ${3:args...})
|
||||||
|
endsnippet
|
||||||
|
|
||||||
# error snippet
|
# error snippet
|
||||||
snippet errn "Error return " !b
|
snippet errn "Error return" !b
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
${0}
|
${0}
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
snippet errnw "Error return wrap" !b
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "${1:message}")
|
||||||
|
}
|
||||||
|
${0}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
|
snippet errnwf "Error return wrapf" !b
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "${1:message %v}", ${2:args...})
|
||||||
|
}
|
||||||
|
${0}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
# error log snippet
|
# error log snippet
|
||||||
snippet errl "Error with log.Fatal(err)" !b
|
snippet errl "Error with log.Fatal(err)" !b
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -174,6 +196,20 @@ if err != nil {
|
||||||
${0}
|
${0}
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
snippet errn,w "Error return wrap with two return values" !b
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "${1:message}")
|
||||||
|
}
|
||||||
|
${0}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
|
snippet errn,wf "Error return wrapf with two return values" !b
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "${1:message %v}", ${2:args...})
|
||||||
|
}
|
||||||
|
${0}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
# error panic
|
# error panic
|
||||||
snippet errp "Error panic" !b
|
snippet errp "Error panic" !b
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -235,6 +271,20 @@ for ${2:k}, ${3:v} := range ${1} {
|
||||||
}
|
}
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
snippet forsel "for select"
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case ${2:${1:result} := }<- ${3:channel}:
|
||||||
|
${0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
|
snippet selc "select case" !b
|
||||||
|
case ${1:${2:var} := }<-${3:channel}:
|
||||||
|
${0}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
# function
|
# function
|
||||||
snippet func "func Function(...) [error] { ... }"
|
snippet func "func Function(...) [error] { ... }"
|
||||||
func ${1:name}(${2:params})${3/(.+)/ /}`!p opening_par(snip, 3)`$3`!p closing_par(snip, 3)` {
|
func ${1:name}(${2:params})${3/(.+)/ /}`!p opening_par(snip, 3)`$3`!p closing_par(snip, 3)` {
|
||||||
|
@ -244,7 +294,12 @@ endsnippet
|
||||||
|
|
||||||
# Fmt Printf debug
|
# Fmt Printf debug
|
||||||
snippet ff "fmt.Printf(...)"
|
snippet ff "fmt.Printf(...)"
|
||||||
fmt.Printf("${1:${VISUAL}} = %+v\n", $1)
|
fmt.Printf("$1 = %+v\n", ${1:${VISUAL}})
|
||||||
|
endsnippet
|
||||||
|
|
||||||
|
# Fmt Printf debug with hash
|
||||||
|
snippet ffh "fmt.Printf(#...) hash"
|
||||||
|
fmt.Printf("$1 = %#v\n", ${1:${VISUAL}})
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
# Fmt Println debug
|
# Fmt Println debug
|
||||||
|
@ -257,6 +312,18 @@ snippet fe "fmt.Errorf(...)"
|
||||||
fmt.Errorf("${1:${VISUAL}}")
|
fmt.Errorf("${1:${VISUAL}}")
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
# Fmt Errorf wrap
|
||||||
|
snippet few "fmt.Errorf(%w, err)"
|
||||||
|
fmt.Errorf("${1:message}: %w", ${2:${VISUAL:err}})
|
||||||
|
endsnippet
|
||||||
|
|
||||||
|
# Fmt Errorf wrap and return
|
||||||
|
snippet errnfw "Error return fmt.Errorf(%w, err)" !b
|
||||||
|
if ${1:${VISUAL:err}} != nil {
|
||||||
|
return fmt.Errorf("${2:message}: %w", $1)
|
||||||
|
}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
# log printf
|
# log printf
|
||||||
snippet lf "log.Printf(...)"
|
snippet lf "log.Printf(...)"
|
||||||
log.Printf("${1:${VISUAL}} = %+v\n", $1)
|
log.Printf("${1:${VISUAL}} = %+v\n", $1)
|
||||||
|
@ -326,7 +393,7 @@ endsnippet
|
||||||
# struct
|
# struct
|
||||||
snippet st "type T struct { ... }"
|
snippet st "type T struct { ... }"
|
||||||
type ${1:Type} struct {
|
type ${1:Type} struct {
|
||||||
${0}
|
${0}
|
||||||
}
|
}
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
@ -338,6 +405,12 @@ case ${2:value1}:
|
||||||
}
|
}
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
snippet tswitch "type switch x { ... }"
|
||||||
|
switch ${2:$1 := }${1:v}.(type) {
|
||||||
|
${0}
|
||||||
|
}
|
||||||
|
endsnippet
|
||||||
|
|
||||||
# sprintf
|
# sprintf
|
||||||
snippet sp "fmt.Sprintf(...)"
|
snippet sp "fmt.Sprintf(...)"
|
||||||
fmt.Sprintf("%${1:s}", ${2:var})
|
fmt.Sprintf("%${1:s}", ${2:var})
|
||||||
|
@ -385,7 +458,7 @@ for _, tt := range tests {
|
||||||
endsnippet
|
endsnippet
|
||||||
|
|
||||||
|
|
||||||
snippet hf "http.HandlerFunc" !b
|
snippet hf "http.HandlerFunc"
|
||||||
func ${1:handler}(w http.ResponseWriter, r *http.Request) {
|
func ${1:handler}(w http.ResponseWriter, r *http.Request) {
|
||||||
${0:fmt.Fprintf(w, "hello world")}
|
${0:fmt.Fprintf(w, "hello world")}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,30 +9,22 @@ let s:cpo_save = &cpo
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
function! s:checkVersion() abort
|
function! s:checkVersion() abort
|
||||||
" Not using the has('patch-7.4.2009') syntax because that wasn't added until
|
|
||||||
" 7.4.237, and we want to be sure this works for everyone (this is also why
|
|
||||||
" we're not using utils#EchoError()).
|
|
||||||
"
|
|
||||||
" Version 7.4.2009 was chosen because that's greater than what the most recent Ubuntu LTS
|
|
||||||
" release (16.04) uses and has a couple of features we need (e.g. execute()
|
|
||||||
" and :message clear).
|
|
||||||
|
|
||||||
let l:unsupported = 0
|
let l:unsupported = 0
|
||||||
if go#config#VersionWarning() != 0
|
if go#config#VersionWarning() != 0
|
||||||
if has('nvim')
|
if has('nvim')
|
||||||
let l:unsupported = !has('nvim-0.3.1')
|
let l:unsupported = !has('nvim-0.4.0')
|
||||||
else
|
else
|
||||||
let l:unsupported = (v:version < 704 || (v:version == 704 && !has('patch2009')))
|
let l:unsupported = !has('patch-8.0.1453')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if l:unsupported == 1
|
if l:unsupported == 1
|
||||||
echohl Error
|
echohl Error
|
||||||
echom "vim-go requires Vim 7.4.2009 or Neovim 0.3.1, but you're using an older version."
|
echom "vim-go requires at least Vim 8.0.1453 or Neovim 0.4.0, but you're using an older version."
|
||||||
echom "Please update your Vim for the best vim-go experience."
|
echom "Please update your Vim for the best vim-go experience."
|
||||||
echom "If you really want to continue you can set this to make the error go away:"
|
echom "If you really want to continue you can set this to make the error go away:"
|
||||||
echom " let g:go_version_warning = 0"
|
echom " let g:go_version_warning = 0"
|
||||||
echom "Note that some features may error out or behave incorrectly."
|
echom "Note that some features may error out or behave incorrectly."
|
||||||
echom "Please do not report bugs unless you're using Vim 7.4.2009 or newer or Neovim 0.3.1."
|
echom "Please do not report bugs unless you're using at least Vim 8.0.1453 or Neovim 0.4.0."
|
||||||
echohl None
|
echohl None
|
||||||
|
|
||||||
" Make sure people see this.
|
" Make sure people see this.
|
||||||
|
@ -45,28 +37,26 @@ call s:checkVersion()
|
||||||
|
|
||||||
" these packages are used by vim-go and can be automatically installed if
|
" these packages are used by vim-go and can be automatically installed if
|
||||||
" needed by the user with GoInstallBinaries.
|
" needed by the user with GoInstallBinaries.
|
||||||
|
|
||||||
|
" NOTE(bc): varying the binary name and the tail of the import path does not yet work in module aware mode.
|
||||||
let s:packages = {
|
let s:packages = {
|
||||||
\ 'asmfmt': ['github.com/klauspost/asmfmt/cmd/asmfmt'],
|
\ 'asmfmt': ['github.com/klauspost/asmfmt/cmd/asmfmt@master'],
|
||||||
\ 'dlv': ['github.com/go-delve/delve/cmd/dlv'],
|
\ 'dlv': ['github.com/go-delve/delve/cmd/dlv@master'],
|
||||||
\ 'errcheck': ['github.com/kisielk/errcheck'],
|
\ 'errcheck': ['github.com/kisielk/errcheck@master'],
|
||||||
\ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct'],
|
\ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct@master'],
|
||||||
\ 'gocode': ['github.com/mdempsky/gocode', {'windows': ['-ldflags', '-H=windowsgui']}],
|
\ 'godef': ['github.com/rogpeppe/godef@master'],
|
||||||
\ 'gocode-gomod': ['github.com/stamblerre/gocode'],
|
\ 'goimports': ['golang.org/x/tools/cmd/goimports@master'],
|
||||||
\ 'godef': ['github.com/rogpeppe/godef'],
|
\ 'golint': ['golang.org/x/lint/golint@master'],
|
||||||
\ 'gogetdoc': ['github.com/zmb3/gogetdoc'],
|
\ 'gopls': ['golang.org/x/tools/gopls@latest', {}, {'after': function('go#lsp#Restart', [])}],
|
||||||
\ 'goimports': ['golang.org/x/tools/cmd/goimports'],
|
\ 'golangci-lint': ['github.com/golangci/golangci-lint/cmd/golangci-lint@master'],
|
||||||
\ 'golint': ['golang.org/x/lint/golint'],
|
\ 'gomodifytags': ['github.com/fatih/gomodifytags@master'],
|
||||||
\ 'gopls': ['golang.org/x/tools/cmd/gopls'],
|
\ 'gorename': ['golang.org/x/tools/cmd/gorename@master'],
|
||||||
\ 'gometalinter': ['github.com/alecthomas/gometalinter'],
|
\ 'gotags': ['github.com/jstemmer/gotags@master'],
|
||||||
\ 'golangci-lint': ['github.com/golangci/golangci-lint/cmd/golangci-lint'],
|
\ 'guru': ['golang.org/x/tools/cmd/guru@master'],
|
||||||
\ 'gomodifytags': ['github.com/fatih/gomodifytags'],
|
\ 'impl': ['github.com/josharian/impl@master'],
|
||||||
\ 'gorename': ['golang.org/x/tools/cmd/gorename'],
|
\ 'keyify': ['honnef.co/go/tools/cmd/keyify@master'],
|
||||||
\ 'gotags': ['github.com/jstemmer/gotags'],
|
\ 'motion': ['github.com/fatih/motion@master'],
|
||||||
\ 'guru': ['golang.org/x/tools/cmd/guru'],
|
\ 'iferr': ['github.com/koron/iferr@master'],
|
||||||
\ 'impl': ['github.com/josharian/impl'],
|
|
||||||
\ 'keyify': ['honnef.co/go/tools/cmd/keyify'],
|
|
||||||
\ 'motion': ['github.com/fatih/motion'],
|
|
||||||
\ 'iferr': ['github.com/koron/iferr'],
|
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
" These commands are available on any filetypes
|
" These commands are available on any filetypes
|
||||||
|
@ -90,22 +80,21 @@ function! s:GoInstallBinaries(updateBinaries, ...)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if go#path#Default() == ""
|
if go#path#Default() == ""
|
||||||
echohl Error
|
call go#util#EchoError('$GOPATH is not set and `go env GOPATH` returns empty')
|
||||||
echomsg "vim.go: $GOPATH is not set and 'go env GOPATH' returns empty"
|
|
||||||
echohl None
|
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let go_bin_path = go#path#BinPath()
|
let go_bin_path = go#path#BinPath()
|
||||||
|
|
||||||
" change $GOBIN so go get can automatically install to it
|
let [l:goos, l:goarch] = go#util#hostosarch()
|
||||||
let $GOBIN = go_bin_path
|
let Restore_goos = go#util#SetEnv('GOOS', l:goos)
|
||||||
|
let Restore_goarch = go#util#SetEnv('GOARCH', l:goarch)
|
||||||
|
|
||||||
" old_path is used to restore users own path
|
" change $GOBIN so go get can automatically install to it
|
||||||
let old_path = $PATH
|
let Restore_gobin = go#util#SetEnv('GOBIN', go_bin_path)
|
||||||
|
|
||||||
" vim's executable path is looking in PATH so add our go_bin path to it
|
" vim's executable path is looking in PATH so add our go_bin path to it
|
||||||
let $PATH = go_bin_path . go#util#PathListSep() . $PATH
|
let Restore_path = go#util#SetEnv('PATH', go_bin_path . go#util#PathListSep() . $PATH)
|
||||||
|
|
||||||
" when shellslash is set on MS-* systems, shellescape puts single quotes
|
" when shellslash is set on MS-* systems, shellescape puts single quotes
|
||||||
" around the output string. cmd on Windows does not handle single quotes
|
" around the output string. cmd on Windows does not handle single quotes
|
||||||
|
@ -117,10 +106,7 @@ function! s:GoInstallBinaries(updateBinaries, ...)
|
||||||
set noshellslash
|
set noshellslash
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:dl_cmd = ['go', 'get', '-v', '-d']
|
let l:get_base_cmd = ['go', 'get', '-v']
|
||||||
if get(g:, "go_get_update", 1) != 0
|
|
||||||
let l:dl_cmd += ['-u']
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Filter packages from arguments (if any).
|
" Filter packages from arguments (if any).
|
||||||
let l:packages = {}
|
let l:packages = {}
|
||||||
|
@ -142,50 +128,103 @@ function! s:GoInstallBinaries(updateBinaries, ...)
|
||||||
let l:platform = 'windows'
|
let l:platform = 'windows'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
for [binary, pkg] in items(l:packages)
|
let l:oldmore = &more
|
||||||
let l:importPath = pkg[0]
|
let &more = 0
|
||||||
|
|
||||||
let l:run_cmd = copy(l:dl_cmd)
|
for [l:binary, l:pkg] in items(l:packages)
|
||||||
if len(l:pkg) > 1 && get(l:pkg[1], l:platform, '') isnot ''
|
let l:importPath = l:pkg[0]
|
||||||
let l:run_cmd += get(l:pkg[1], l:platform, '')
|
|
||||||
endif
|
|
||||||
|
|
||||||
let bin_setting_name = "go_" . binary . "_bin"
|
" TODO(bc): how to support this with modules? Do we have to clone and then
|
||||||
|
" install manually? Probably not. I suspect that we can just use GOPATH
|
||||||
|
" mode and then do the legacy method.
|
||||||
|
let bin_setting_name = "go_" . l:binary . "_bin"
|
||||||
|
|
||||||
if exists("g:{bin_setting_name}")
|
if exists("g:{bin_setting_name}")
|
||||||
let bin = g:{bin_setting_name}
|
let bin = g:{bin_setting_name}
|
||||||
else
|
else
|
||||||
if go#util#IsWin()
|
if go#util#IsWin()
|
||||||
let bin = binary . '.exe'
|
let bin = l:binary . '.exe'
|
||||||
else
|
else
|
||||||
let bin = binary
|
let bin = l:binary
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if !executable(bin) || a:updateBinaries == 1
|
if !executable(bin) || a:updateBinaries == 1
|
||||||
if a:updateBinaries == 1
|
if a:updateBinaries == 1
|
||||||
echo "vim-go: Updating " . binary . ". Reinstalling ". importPath . " to folder " . go_bin_path
|
echo "vim-go: Updating " . l:binary . ". Reinstalling ". importPath . " to folder " . go_bin_path
|
||||||
else
|
else
|
||||||
echo "vim-go: ". binary ." not found. Installing ". importPath . " to folder " . go_bin_path
|
echo "vim-go: ". l:binary ." not found. Installing ". importPath . " to folder " . go_bin_path
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" first download the binary
|
if l:importPath =~ "@"
|
||||||
let [l:out, l:err] = go#util#Exec(l:run_cmd + [l:importPath])
|
let Restore_modules = go#util#SetEnv('GO111MODULE', 'on')
|
||||||
if l:err
|
let l:tmpdir = go#util#tempdir('vim-go')
|
||||||
echom "Error downloading " . l:importPath . ": " . l:out
|
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||||
|
let l:dir = getcwd()
|
||||||
|
try
|
||||||
|
execute l:cd . fnameescape(l:tmpdir)
|
||||||
|
let l:get_cmd = copy(l:get_base_cmd)
|
||||||
|
|
||||||
|
if len(l:pkg) > 1 && get(l:pkg[1], l:platform, []) isnot []
|
||||||
|
let l:get_cmd += get(l:pkg[1], l:platform, [])
|
||||||
|
endif
|
||||||
|
|
||||||
|
" TODO(bc): how to install the bin to a different name than the
|
||||||
|
" binary path? go get does not support -o
|
||||||
|
" let l:get_cmd += ['-o', printf('%s%s%s', go_bin_path, go#util#PathSep(), bin)]
|
||||||
|
|
||||||
|
let [l:out, l:err] = go#util#Exec(l:get_cmd + [l:importPath])
|
||||||
|
if l:err
|
||||||
|
call go#util#EchoError(printf('Error installing %s: %s', l:importPath, l:out))
|
||||||
|
endif
|
||||||
|
|
||||||
|
call call(Restore_modules, [])
|
||||||
|
finally
|
||||||
|
execute l:cd . fnameescape(l:dir)
|
||||||
|
endtry
|
||||||
|
call call(Restore_modules, [])
|
||||||
|
else
|
||||||
|
let l:get_cmd = copy(l:get_base_cmd)
|
||||||
|
let l:get_cmd += ['-d']
|
||||||
|
if get(g:, "go_get_update", 1) != 0
|
||||||
|
let l:get_cmd += ['-u']
|
||||||
|
endif
|
||||||
|
|
||||||
|
let Restore_modules = go#util#SetEnv('GO111MODULE', 'off')
|
||||||
|
|
||||||
|
" first download the binary
|
||||||
|
let [l:out, l:err] = go#util#Exec(l:get_cmd + [l:importPath])
|
||||||
|
if l:err
|
||||||
|
call go#util#EchoError(printf('Error downloading %s: %s', l:importPath, l:out))
|
||||||
|
endif
|
||||||
|
|
||||||
|
" and then build and install it
|
||||||
|
let l:build_cmd = ['go', 'build']
|
||||||
|
if len(l:pkg) > 1 && get(l:pkg[1], l:platform, []) isnot []
|
||||||
|
let l:build_cmd += get(l:pkg[1], l:platform, [])
|
||||||
|
endif
|
||||||
|
let l:build_cmd += ['-o', printf('%s%s%s', go_bin_path, go#util#PathSep(), bin), l:importPath]
|
||||||
|
|
||||||
|
let [l:out, l:err] = go#util#Exec(l:build_cmd)
|
||||||
|
if l:err
|
||||||
|
call go#util#EchoError(printf('Error installing %s: %s', l:importPath, l:out))
|
||||||
|
endif
|
||||||
|
|
||||||
|
call call(Restore_modules, [])
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" and then build and install it
|
if len(l:pkg) > 2
|
||||||
let l:build_cmd = ['go', 'build', '-o', go_bin_path . go#util#PathSep() . bin, l:importPath]
|
call call(get(l:pkg[2], 'after', function('s:noop', [])), [])
|
||||||
let [l:out, l:err] = go#util#Exec(l:build_cmd)
|
|
||||||
if l:err
|
|
||||||
echom "Error installing " . l:importPath . ": " . l:out
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
" restore back!
|
" restore back!
|
||||||
let $PATH = old_path
|
call call(Restore_path, [])
|
||||||
|
call call(Restore_gobin, [])
|
||||||
|
call call(Restore_goarch, [])
|
||||||
|
call call(Restore_goos, [])
|
||||||
|
|
||||||
if resetshellslash
|
if resetshellslash
|
||||||
set shellslash
|
set shellslash
|
||||||
endif
|
endif
|
||||||
|
@ -195,18 +234,20 @@ function! s:GoInstallBinaries(updateBinaries, ...)
|
||||||
else
|
else
|
||||||
call go#util#EchoInfo('installing finished!')
|
call go#util#EchoInfo('installing finished!')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let &more = l:oldmore
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" CheckBinaries checks if the necessary binaries to install the Go tool
|
" CheckBinaries checks if the necessary binaries to install the Go tool
|
||||||
" commands are available.
|
" commands are available.
|
||||||
function! s:CheckBinaries()
|
function! s:CheckBinaries()
|
||||||
if !executable('go')
|
if !executable('go')
|
||||||
echohl Error | echomsg "vim-go: go executable not found." | echohl None
|
call go#util#EchoError('go executable not found.')
|
||||||
return -1
|
return -1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if !executable('git')
|
if !executable('git')
|
||||||
echohl Error | echomsg "vim-go: git executable not found." | echohl None
|
call go#util#EchoError('git executable not found.')
|
||||||
return -1
|
return -1
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
@ -239,7 +280,15 @@ function! s:register()
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let l:RestoreGopath = function('s:noop')
|
||||||
|
if go#config#AutodetectGopath()
|
||||||
|
let l:RestoreGopath = go#util#SetEnv('GOPATH', go#path#Detect())
|
||||||
|
endif
|
||||||
call go#lsp#DidOpen(expand('<afile>:p'))
|
call go#lsp#DidOpen(expand('<afile>:p'))
|
||||||
|
call call(l:RestoreGopath, [])
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:noop(...) abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
augroup vim-go
|
augroup vim-go
|
||||||
|
|
2
pack/acp/start/vim-go/scripts/bench-syntax
Normal file → Executable file
2
pack/acp/start/vim-go/scripts/bench-syntax
Normal file → Executable file
|
@ -13,7 +13,7 @@ cd "$vimgodir"
|
||||||
|
|
||||||
if [ -z "${1:-}" ]; then
|
if [ -z "${1:-}" ]; then
|
||||||
echo "unknown version: '${1:-}'"
|
echo "unknown version: '${1:-}'"
|
||||||
echo "First argument must be 'vim-7.4', 'vim-8.0', or 'nvim'."
|
echo "First argument must be 'vim-8.0' or 'nvim'."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
2
pack/acp/start/vim-go/scripts/docker-test
Normal file → Executable file
2
pack/acp/start/vim-go/scripts/docker-test
Normal file → Executable file
|
@ -10,6 +10,6 @@ cd "$vimgodir"
|
||||||
docker build --tag vim-go-test .
|
docker build --tag vim-go-test .
|
||||||
# seccomp=confined is required for dlv to run in a container, hence it's
|
# seccomp=confined is required for dlv to run in a container, hence it's
|
||||||
# required for vim-go's debug tests.
|
# required for vim-go's debug tests.
|
||||||
docker run --rm --security-opt="seccomp=unconfined" vim-go-test
|
docker run -e VIMS --rm --security-opt="seccomp=unconfined" vim-go-test
|
||||||
|
|
||||||
# vim:ts=2:sts=2:sw=2:et
|
# vim:ts=2:sts=2:sw=2:et
|
||||||
|
|
35
pack/acp/start/vim-go/scripts/install-tools
Executable file
35
pack/acp/start/vim-go/scripts/install-tools
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Install and setup a Vim or Neovim for running tests.
|
||||||
|
# This should work on both GitHub Actions and people's desktop computers, and
|
||||||
|
# be 100% independent from any system installed Vim.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euC
|
||||||
|
|
||||||
|
vimgodir=$(cd -P "$(dirname "$0")/.." > /dev/null && pwd)
|
||||||
|
cd "$vimgodir"
|
||||||
|
|
||||||
|
vim=${1:-}
|
||||||
|
|
||||||
|
installdir="/tmp/vim-go-test/$1-install"
|
||||||
|
|
||||||
|
# Make sure all Go tools and other dependencies are installed.
|
||||||
|
echo "Installing Go binaries"
|
||||||
|
export GOPATH=$installdir
|
||||||
|
export GO111MODULE=off
|
||||||
|
export PATH=${GOPATH}/bin:$PATH
|
||||||
|
"$vimgodir/scripts/run-vim" $vim +':silent :GoUpdateBinaries' +':qa'
|
||||||
|
|
||||||
|
echo "Installing lint tools"
|
||||||
|
(
|
||||||
|
mkdir -p "$installdir/share/vim/vimgo/pack/vim-go/start/"
|
||||||
|
cd "$installdir/share/vim/vimgo/pack/vim-go/start/"
|
||||||
|
[ -d "vim-vimhelplint" ] || git clone --depth 1 --quiet https://github.com/machakann/vim-vimhelplint
|
||||||
|
[ -d "vim-vimlparser" ] || git clone --depth 1 --quiet https://github.com/ynkdir/vim-vimlparser
|
||||||
|
[ -d "vim-vimlint" ] || git clone --depth 1 --quiet https://github.com/syngan/vim-vimlint
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "vim-go tools installed to: $installdir/share/vim/vimgo/pack/vim-go/start"
|
||||||
|
|
||||||
|
# vim:ts=2:sts=2:sw=2:et
|
44
pack/acp/start/vim-go/scripts/install-vim
Normal file → Executable file
44
pack/acp/start/vim-go/scripts/install-vim
Normal file → Executable file
|
@ -1,8 +1,8 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Install and setup a Vim or Neovim for running tests.
|
# Install and setup a Vim or Neovim for running tests.
|
||||||
# This should work on both Travis and people's desktop computers, and be 100%
|
# This should work on both GitHub Actions and people's desktop computers, and
|
||||||
# independent from any system installed Vim.
|
# be 100% independent from any system installed Vim.
|
||||||
#
|
#
|
||||||
# It will echo the full path to a Vim binary, e.g.:
|
# It will echo the full path to a Vim binary, e.g.:
|
||||||
# /some/path/src/vim
|
# /some/path/src/vim
|
||||||
|
@ -15,28 +15,32 @@ cd "$vimgodir"
|
||||||
vim=${1:-}
|
vim=${1:-}
|
||||||
|
|
||||||
case "$vim" in
|
case "$vim" in
|
||||||
"vim-7.4")
|
"vim-8.0")
|
||||||
tag="v7.4.2009"
|
# This follows the version in Ubuntu LTS. Vim's master branch isn't always
|
||||||
|
# stable, and we don't want to have the build fail because Vim introduced a
|
||||||
|
# bug.
|
||||||
|
tag="v8.0.1453"
|
||||||
giturl="https://github.com/vim/vim"
|
giturl="https://github.com/vim/vim"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"vim-8.0")
|
"vim-8.2")
|
||||||
# This follows the version in Arch Linux. Vim's master branch isn't always
|
# This is the version that's installed by homebrew currently. It doesn't
|
||||||
# stable, and we don't want to have the build fail because Vim introduced a
|
# have to stay up to date with homebrew, and is only chosen here because
|
||||||
# bug.
|
# that's what homebrew was using at the the time and we need a version to
|
||||||
tag="v8.0.1542"
|
# vimlint with.
|
||||||
|
tag="v8.2.0200"
|
||||||
giturl="https://github.com/vim/vim"
|
giturl="https://github.com/vim/vim"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"nvim")
|
"nvim")
|
||||||
# Use latest stable version.
|
# Use latest stable version.
|
||||||
tag="v0.3.1"
|
tag="v0.4.0"
|
||||||
giturl="https://github.com/neovim/neovim"
|
giturl="https://github.com/neovim/neovim"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "unknown version: '${1:-}'"
|
echo "unknown version: '${1:-}'"
|
||||||
echo "First argument must be 'vim-7.4', 'vim-8.0', or 'nvim'."
|
echo "First argument must be 'vim-8.0', vim-8.2, or 'nvim'."
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -62,7 +66,7 @@ cd "$srcdir"
|
||||||
if [ "$1" = "nvim" ]; then
|
if [ "$1" = "nvim" ]; then
|
||||||
|
|
||||||
# TODO: Use macOS binaries on macOS
|
# TODO: Use macOS binaries on macOS
|
||||||
curl -Ls https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz |
|
curl -Ls https://github.com/neovim/neovim/releases/download/$tag/nvim-linux64.tar.gz |
|
||||||
tar xzf - -C /tmp/vim-go-test/
|
tar xzf - -C /tmp/vim-go-test/
|
||||||
mv /tmp/vim-go-test/nvim-linux64 /tmp/vim-go-test/nvim-install
|
mv /tmp/vim-go-test/nvim-linux64 /tmp/vim-go-test/nvim-install
|
||||||
mkdir -p "$installdir/share/nvim/runtime/pack/vim-go/start"
|
mkdir -p "$installdir/share/nvim/runtime/pack/vim-go/start"
|
||||||
|
@ -88,22 +92,6 @@ else
|
||||||
ln -s "$vimgodir" "$installdir/share/vim/vimgo/pack/vim-go/start/vim-go"
|
ln -s "$vimgodir" "$installdir/share/vim/vimgo/pack/vim-go/start/vim-go"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure all Go tools and other dependencies are installed.
|
|
||||||
echo "Installing Go binaries"
|
|
||||||
export GOPATH=$installdir
|
|
||||||
export GO111MODULE=off
|
|
||||||
export PATH=${GOPATH}/bin:$PATH
|
|
||||||
"$vimgodir/scripts/run-vim" $vim +':silent :GoUpdateBinaries' +':qa'
|
|
||||||
|
|
||||||
echo "Installing lint tools"
|
|
||||||
(
|
|
||||||
mkdir -p "$installdir/share/vim/vimgo/pack/vim-go/start/"
|
|
||||||
cd "$installdir/share/vim/vimgo/pack/vim-go/start/"
|
|
||||||
[ -d "vim-vimhelplint" ] || git clone --depth 1 --quiet https://github.com/machakann/vim-vimhelplint
|
|
||||||
[ -d "vim-vimlparser" ] || git clone --depth 1 --quiet https://github.com/ynkdir/vim-vimlparser
|
|
||||||
[ -d "vim-vimlint" ] || git clone --depth 1 --quiet https://github.com/syngan/vim-vimlint
|
|
||||||
)
|
|
||||||
|
|
||||||
# Don't really need source after successful install.
|
# Don't really need source after successful install.
|
||||||
rm -rf "$srcdir"
|
rm -rf "$srcdir"
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue