diff --git a/vim/bundle/vim-go/.github/CONTRIBUTING.md b/vim/bundle/vim-go/.github/CONTRIBUTING.md new file mode 100644 index 0000000..450f959 --- /dev/null +++ b/vim/bundle/vim-go/.github/CONTRIBUTING.md @@ -0,0 +1,9 @@ +Thanks for improving vim-go! Before you dive in please read the following: + +1. Please read our + [FAQ](https://github.com/fatih/vim-go/wiki/FAQ-Troubleshooting), it might + have answers for your problem +2. If you add a new feature please don't forget to update the documentation: + [doc/vim-go.txt](https://github.com/fatih/vim-go/blob/master/doc/vim-go.txt) +3. If it's a breaking change or exceed +100 lines please open an issue first + and describe the changes you want to make. diff --git a/vim/bundle/vim-go/.github/ISSUE_TEMPLATE.md b/vim/bundle/vim-go/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..e6b5f20 --- /dev/null +++ b/vim/bundle/vim-go/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,25 @@ +### Behavior + +Write here what's happening and what you're expecting instead of... + +### Steps to reproduce: + +Please create a reproducible case of your problem. If this step is +not provided, the issue will be **closed** + +Re produce it with a minimal `vimrc` with all plugins disabled and +only `vim-go` enabled: + +1. +2. +3. + +### Configuration + +Add here your current configuration and additional information that might be +useful, such as: + +* `vimrc` you used to reproduce +* vim version: +* vim-go version: +* go version: diff --git a/vim/bundle/vim-go/.gitignore b/vim/bundle/vim-go/.gitignore new file mode 100644 index 0000000..4449737 --- /dev/null +++ b/vim/bundle/vim-go/.gitignore @@ -0,0 +1,6 @@ +doc/tags +.DS_Store + +# Test specific files +FAILED +test.log diff --git a/vim/bundle/vim-go/.travis.yml b/vim/bundle/vim-go/.travis.yml new file mode 100644 index 0000000..d05b23e --- /dev/null +++ b/vim/bundle/vim-go/.travis.yml @@ -0,0 +1,21 @@ +language: go + +env: + global: + - DEPS=$HOME/deps + - PATH=$DEPS/bin:$PATH + - PATCH="v8.0.0134" + +install: | + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + + # check out if we can pre-compiled Vim releases somehow, + git clone --branch $PATCH --depth 1 https://github.com/vim/vim + cd vim + ./configure --prefix=$DEPS --with-features=huge --disable-gui + make + make install + cd - + +script: ./scripts/test.sh diff --git a/vim/bundle/vim-go/CHANGELOG.md b/vim/bundle/vim-go/CHANGELOG.md new file mode 100644 index 0000000..2db6358 --- /dev/null +++ b/vim/bundle/vim-go/CHANGELOG.md @@ -0,0 +1,418 @@ +## unplanned + +IMPROVEMENTS + +* :GoMetaLinter can now exclude linters with the new `g:go_metalinter_excludes` option [gh-1253] + +BUG FIXES: + +* job: fix race between channel close and job exit [gh-1247] + +## 1.12 - (March 29, 2017) + +FEATURES: + +* New `:GoAddTags` and `:GoRemoveTags` command based on the tool + [gomodifytags](https://github.com/fatih/gomodifytags). This fixes many old + bugs that were due prior regexp based implementation. For the usage please + read the docs and checkout the demo at: + https://github.com/fatih/vim-go/pull/1204 [gh-1204] +* Add new `errl` snippet that expands to [gh-1185]: + +``` +if err != nil { + log.Fatal(err) +} +``` +* New `:GoBuildTags` command to change build tags for tools such as `guru`, + `gorename`, etc ... There is also a new setting called `g:go_build_tags` + [gh-1232] + +IMPROVEMENTS: + +* vim-go works now even if GOPATH is not set (starting with Go 1.8) [gh-1248] +* Lowercase `` in mappings examples for consistent documentation across the README [gh-1192] +* All of files should be written in utf-8 if the file will be passed to external command. [gh-1184] +* `:GoAddTags` is now able to add options to existing tags with the syntax + `:GoAddTags key,option`, i.e: `:GoAddTags json,omitempty` [gh-985] +* Document 'noshowmode' requirement for echo_go_info [gh-1197] +* Improve godoc view for vertical splits [gh-1195] +* Set GOPATH for both possible go guru execution paths (sync and async) [gh-1193] +* Improve docs for :GoDef usage [gh-1242] +* Highlight trimming syntax for Go templates [gh-1235] + +BUG FIXES: + +* Honor `g:go_echo_command_info` when dispatching builds in neovim [gh-1176] +* Fix `:GoBuild` error in neovim due to invalid jobcontrol handler function + signatures (`s:on_stdout`, `s:on_stderr`)[gh-1176] +* Update statusline before and after `go#jobcontrol#Spawn` command is executed [gh-1176] +* Correctly report the value of the 'g:go_guru_tags' variable [gh-1177] +* Ensure no trailing `:` exist in GOPATH detection if initial GOPATH is not set [gh-1194] +* Fix `:GoAddTags` to allow modifying existing comments [gh-984] +* Fix `:GoAddTags` to work with nested structs [gh-990] +* Fix `:GoAddTags` adding tags twice for existing tags [gh-1064] +* Fix `:GoAddTags` not working for fiels of types `interface{}` [gh-1091] +* Fix `:GoAddTags` not working for fields with one line comments [gh-1181] +* Fix `:GoAddTags` not working if any field comment would contain `{}` [gh-1189] +* Respect go_fmt_options when running goimports [gh-1211] +* Set the filename in the location-list when there is an error with :GoFmt [gh-1199] +* Fix `:GoInstall` to accept additional arguments if async mode was enabled [gh-1246] + +BACKWARDS INCOMPATIBILITIES: + +* The command `:GoGuruTags` is removed in favour of the new command + `:GoBuildTags`. This command will be used now not just for `guru`, also for + all new commands such as `gorename` [gh-1232] +* The setting `g:go_guru_tags` is removed in favour of the new setting + `g:go_build_tags` [gh-1232] + + +## 1.11 - (January 9, 2017) + +FEATURES: + +* Travis test integration has been added. Now any file that is added as `_test.vim` will be automatically tested in for every Pull Request (just like how we add tests to Go with `_test.go`). Going forward this will tremendously increase the stability and decrease the maintenance burden of vim-go. [gh-1157] +* Add new `g:go_updatetime` setting to change the default updatetime (which was hardcoded previously) [gh-1055] +* Add new `g:go_template_use_pkg` setting to enable to use cwd as package name instead of basic template file [gh-1124] + +IMPROVEMENTS: + +* Add `statusline` support for `:GoMetaLinter` [gh-1120] +* Quickfix and Location lists contain now a descriptive title (requires at least Vim `7.4.2200`)[gh-1004] +* Check `go env GOPATH` as well for `:GoInstallBinaries` as Go has now a default path for GOPATH ("~/go")starting with 1.8 [gh-1152] +* `:GoDocBrowser` now also works on import paths [gh-1174] + +BUG FIXES: + +* Always use full path to detect packages to be shown in statusline [gh-1121] +* Use `echom` to persist errors in case of multiple echos [gh-1122] +* Fix a race condition where a quickfix window was not closed if a job has succeeded [gh-1123] +* Do not expand coverage arguments for non job execution of `:GoCoverage` [gh-1127] +* `:GoCoverage` doesn't mess up custom syntax anymore [gh-1128] +* Disable autoformat for `asm` files as they might be non Go ASM format [gh-1141] +* Fix indentation broken when using a action with a minus sign like `{{-` [gh-1143] +* Fix breaking Neovim change of passing less arguments to callbacks [gh-1145] +* Fix `guru` commands if custom build tags were set [gh-1136] +* Fix referencing a non defined variable for async commands when bang (!) was used +* Fix `:GoDef` failing for a modified buffer if `hidden` was not set [gh-1132] +* Fix `:GoDefStack` to allow popping from jump list when buffer is modified [gh-1133] +* Improve internal defining of functions and referencing them for async operations [gh-1155] +* Fix `:GoMetaLinter` failing if `go_metalinter_command` is set. [gh-1160] +* Fix `:GoMetaLinter`'s `go_metalinter_deadline` setting for async mode [gh-1146] + +BACKWARDS INCOMPATIBILITIES: + +* The following syntax options are now disabled by default. If you're using them be sure to set them in your .vimrc [gh-1167] + +```viml +g:go_highlight_array_whitespace_error +g:go_highlight_chan_whitespace_error +g:go_highlight_extra_types +g:go_highlight_space_tab_error +g:go_highlight_trailing_whitespace_error +``` + + + +## 1.10 (November 24, 2016) + +FEATURES: + +* **Vim 8.0 support!** This is the initial version to add Vim 8.0 based support to + all basic commands (check out below for more information). With time we'll + going to extend it to other commands. All the features are only enabled if + you have at least Vim 8.0.0087. Backwards compatible with Vim 7.4.x. + If you see any problems, please open an issue. + +* We have now a [logo for vim-go](https://github.com/fatih/vim-go/blob/master/assets/vim-go.png)! Thanks to @egonelbre for his work on this. +* `:GoBuild`, `:GoTest`, `:GoTestCompile`, `:GoInstall` commands are now fully + async. Async means it doesn't block your UI anymore. If the command finished + it echoes the status. For a better experience use the statusline information + (more info below) + +* `:GoCoverage` and `:GoCoverageBrowser` commands are fully async. +* `:GoDef` is fully async if `guru` is used as command. +* `:GoRename` is fully async . + +* `:GoMetaLinter` is fully asnyc. Also works with the current autosave linting + feature. As a reminder, to enable auto linting on save either call + `:GoMetaLinterAutoSaveToggle` (temporary) or add `let + g:go_metalinter_autosave = 1` (persistent) to your virmc). + +* All `guru` commands run asynchronously if Vim 8.0 is being used. Current + Commands: + * GoImplements + * GoWhicherrs + * GoCallees + * GoDescribe + * GoCallers + * GoCallstack + * GoFreevars + * GoChannelPeers + * GoReferrers + +* `:GoSameIds` also runs asynchronously. This makes it useful especially for + auto sameids mode. In this mode it constantly evaluates the identifier under the + cursor whenever it's in hold position and then calls :GoSameIds. As a + reminder, to enable auto info either call `:GoSameIdsAutoToggle`(temporary) + or add `let g:go_auto_sameids = 1` (persistent) to your vimrc. + +* `:GoInfo` is now non blocking and works in async mode if `guru` is used in + `g:go_info_mode`. This makes it useful especially for autoinfo mode. In this + mode it constantly evaluates the identifier under the cursor whenever it's in + hold position and then calls :GoInfo. As a reminder, to enable auto info + either call `:GoAutoTypeInfoToggle`(temporary) or add `let + g:go_auto_type_info = 1` (persistent) to your vimrc. To use `guru` instead of + `gocode` add following to your vimrc: `let g:go_info_mode = 'guru'` + + The `guru` is more accurate and reliabed due the usage of `guru` describe. It + doesn't rely on `pkg/` folder like `gocode` does. However it's slower than + `gocode` as there is no caching mechanism in `guru` yet. + +* **New**: Statusline function: `go#statusline#Show()` which can be plugged into + the statusline bar. Works only with vim 8.0. It shows all asynchronously + called functions status real time. Checkout it in action: + https://twitter.com/fatih/status/800473735467847680. To enable it add the + following to your `vimrc`. If you use lightline, airline, .. check out their + respective documentation on how to add a custom function: + +```viml +" go command status (requires vim-go) +set statusline+=%#goStatuslineColor# +set statusline+=%{go#statusline#Show()} +set statusline+=%* +``` + +IMPROVEMENTS: + +* **:GoDocBrowser** is now capable to to understand the identifier under the cursor (just like :GoDoc) +* Function calls are now highlighted as well when `g:go_highlight_functions` is enabled [gh-1048] +* Add completion support for un-imported packages. This allows to complete even + if the package is not imported. By default it's disabled, enable by adding + `let g:go_gocode_unimported_packages = 1` [gh-1084] +* Tools that embeds GOROOT into their binaries do not work when people update + their Go version and the GOROOT contains the vesion as part of their path + (i.e: `/usr/local/Cellar/go/1.7.2/libexec`, [more + info](https://blog.filippo.io/stale-goroot-and-gorebuild/)) . This is now + fixed by introducing automatic GOROOT set/unset before each tool invoke. + [gh-954] +* Added new setting `g:go_echo_go_info` to enable/disable printing identifier + information when completion is done [gh-1101] +* Added new `go_echo_command_info` setting is added, which is enabled by + default. It's just a switch for disabling messages of commands, such as + `:GoBuild`, `:GoTest`, etc.. Useful to *disable* if `go#statusline#Show()` is + being used in Statusline, to prevent to see duplicates notifications. +* goSameId highlighting is now linked to `Search`, which is much more clear as + it changes according to the users colorscheme +* Add plug mapping `(go-lint)` for :GoLint [gh-1089] + + +BUG FIXES: + +* Change back nil and iota highlighting color to the old type [gh-1049] +* Fix passing arguments to `:GoBuild` while using NeoVim [gh-1062] +* Do not open a split if `:GoDef` is used on a modified file [gh-1083] +* Highlight nested structs correctly [gh-1075] +* Highlight builtin functions correctly if `g:go_highlight_functions` is enabled [gh-1070] +* Fix `:GoSameIds` highlighting if a new buffer is opened in the same window [gh-1067] +* Internal: add `abort` to all vim function to return in case of errors [gh-1100] +* Fix `:GoCoverage` to be executed if working dir is not inside the test dir [gh-1033] + +BACKWARDS INCOMPATIBILITIES: + +* remove vim-dispatch and vimproc.vim support. vim 8.0 has now the necessary + API to invoke async jobs and timers. Going forward we should use those. Also + this will remove the burden to maintain compatibility with those plugins. + +* `go#jobcontrol#Statusline()` is removed in favor of the new, global and + extensible `go#statusline#Show()` + +## 1.9 (September 13, 2016) + +IMPROVEMENTS: + +* **guru** uses now the `-modified` flag, which allows us use guru on modified + buffers as well. This affects all commands where `guru` is used. Such as + `:GoDef`, `:GoReferrers`, etc.. [gh-944] +* **:GoDoc** uses now the `-modified` flag under the hood (for `gogetdoc), which allows us to get documentation for the identifier under the cursor ina modified buffer. [gh-1014] +* Cleanup and improve documentation [gh-987] +* Add new `g:go_gocode_socket_type` setting to change the underlying socket type passed to `gocode`. Usefull to fallback to `tcp` on cases such as Bash on Windows [gh-1000] +* `:GoSameIds` is now automatically re-evaluated in cases of buffer reloads (such as `:GoRename`) [gh-998] +* Improve docs about `go_auto_sameids` [gh-1017] +* Improve error message by printing the full path if an incompatible `goimports` is being used [gh-1006] +* `iota` and `nil` are now highlighted correctly and are not treated as booleans [gh-1030] + +BUG FIXES: + +* Fix system calls on Windows [gh-988] +* Fix :GoSameIds and :GoCoverage for light background and after changing color schemes [gh-983] +* Fix TagBar and `GoCallers` for Windows user [gh-999] +* Set updatetime for for `auto_sameids` feature as well [gh-1016] +* Update docs about missing `go_highlight_generate_tags` setting [gh-1023] +* Fix updating the jumplist if `:GoDef` is used [gh-1029] +* Fix highlighting literal percent sign (`%%`) in strings [gh-1011] +* Fix highlighting of nested fields [gh-1007] +* Fix checking for `exepath` feature for the upcoming vim 8.0 release [gh-1046] + +BACKWARDS INCOMPATIBILITIES: + +* Rename `GoMetalinterAutoSaveToggle` to `GoMetaLinterAutoSaveToggle` to make it compatible with the existing `:GoMetaLinter` command [gh-1020] + +## 1.8 (July 31, 2016) + +FEATURES: +* New **`:GoAddTags`** command that adds field tags for the fields of a struct automatically based on the field names. Checkout the demo to see it in action: https://twitter.com/fatih/status/759822857773907968 [gh-971] +* The snippet expansion `json` is now much more smarter. It pre populates the placeholder according to the first word and it also applies `snake_case` or `camelCase` conversion. Together with `:GoAddTags` it gives `vim-go` users flexible ways of populating a field tag. Checkout the demo to see it in action: https://twitter.com/fatih/status/754477622042689536 [gh-927] +* New **`:GoSameIds`** command. When called highlights all same identifiers in the current file. Can be also enabled to highlight identifiers automatically (with `:GoSameIdsAutoToggle` or `g:go_auto_sameids`). Checkout the demo to see it in action: https://twitter.com/fatih/status/753673709278339072. [gh-936] +* New **`:GoWhicherrs`** command. It shows all possible values of the selected error variable. [gh-948] +* Add new `errp` snippet to expand an `if err != nil { panic() }` clause [gh-926] +* If you open a new buffer with a Go filename it get automatically populated based on the directory. If there are no Go files a simple main package is created, otherwise the file will include the package declaration line based on the package in the current directory. Checkout the demo to see it in action: https://twitter.com/fatih/status/748333086643994624. This is enabled by default. Can be disabled with `let g:go_template_autocreate = 0`. You can use your own template with `let g:go_template_file = "foo.go"` and putting the file under the `templates/` folder. [gh-918] +* Added new toggle commands to enable/disable feature that run for your + automatic. For example if you have `let g:go_auto_type_info = 1` enabled, you + can now easily enable/disable it on the fly. Support added with the following + commands: `:GoAutoTypeInfoToggle`, `:GoFmtAutoSaveToggle`, + `:GoAsmFmtAutoSaveToggle`, `:GoMetalinterAutoSaveToggle`, + `:GoTemplateAutoCreateToggle` [gh-945] + + +IMPROVEMENTS: +* `:GoDoc` accepts arguments now which are passed directly to `godoc`. So usages like `:GoDoc flag` works again (it was changed in previous versions [gh-894] +* `:GoDef` works now for modified files as well [gh-910] +* Internal: pass filename to the `--srcdir` flag to enable upcoming `goimports` features [gh-957] +* Internal: fix indentations on all files to **2-spaces/no tabs**. This is now the default vim-go style across all VimL files [gh-915] +* Internal: autocmd settings can be now dynamically enabled/disabled [gh-939] +* Internal: automatically detect `GOPATH` for :GoInstall [gh-980] +* Internal: shell executions uses now by default `sh` and then resets it back to the user preference. [gh-967] +* Syntax: improved syntax highglighting performance for methods, fields, structs and interface type declarations [gh-917] +* Syntax: moved `:GoCoverage` highlight definition into go's syntax file for more customizability [gh-962] + + +BUG FIXES: + +* Escape `#` characters when opening URL's, as it's handled as alternative file in vim [gh-895] +* Fix typos in `doc/vim-go.txt` about usages of syntax highglightings [gh-897] +* Fix `:GoCoverage` not running for Neovim [gh-899] +* Fix `:GoFmt` not picking up `-srcdir` if the command was set to use `goimports` [gh-904] +* Fix `:GoTestCompile` to not leave behind artifacts if the cwd and the test files's directory do not match [gh-909] +* Fix `:GoDocBrowser` to not fail if godoc doesn't exist [gh-920] +* Fix `:GoFmt` to not change the permissions of saved file. Now original file permissions are restored [gh-922] + +BACKWARDS INCOMPATIBILITIES: + +* `g:go_highlight_structs` and `g:go_highlight_interface` are removed in favor of `g:go_highlight_types` [gh-917] + + +## 1.7.1 (June 7, 2016) + +BUG FIXES: +* Fixed typo in `syntax/go.vim` file from `go:go_highlight_fields` to `g:go_highlight_fields` + +## 1.7 (June 7, 2016) + +FEATURES: + +* New **`:GoImpl`** command that generates method stubs for implementing an interface. Checkout the [demo](https://twitter.com/fatih/status/729991365581545472) to see how it works. [gh-846] +* `godef` support is added back as an optional setting. By default `:GoDef` still uses `guru`, but can be changed to `godef` by adding the option: `let g:go_def_mode = 'godef'` [gh-888] +* New `` and `]>` shortcuts to split current window and jumpt to the identifier under cursor. [gh-838] +* New syntax setting" `g:go_highlight_fields` that highlights struct field references [gh-854] + +IMPROVEMENTS: + +* Invoking `:GoRename` now reloads all files to reflect new changes automatically [gh-855] +* Calling `:GoTestCompile` does not create any temporary binary file anymore [gh-879] +* Enable passing the `-tags` flag to `:GoDef`. Now you can pass build tags to `:GoDef` via `:GoGuruTags` or `g:go_guru_tags` +* Internal refactoring to use custom `system()` function that wraps both the standard `system()` call and `vimproc`. Now all system calls will take advantage and will use `vimproc` if installed. [gh-801] +* Completion enables now `gocode`'s `autobuild` and `propose-builtins` flags automatically. With these settings packages will be automatically build to get the freshest completion candidates and builtin keywords will be showed as well. By defaults these settings are enabled. Settings can be disabled/enabled via `g:go_gocode_autobuild` and `g:go_gocode_propose_builtins`. [gh-815] +* Added new `http.HandlerFunc` snippets with `hf` and `hhf` shortcuts [gh-816] +* Added new `Example` and `Benchmark` snippets with `example` and `benchmark` shortcuts [gh-836] +* Search tool binaries first in `GOBIN` and then in `PATH` as most of vim-go users installs it to `GOBIN` mostly [gh-823] +* Improve `guru` based commands by providing automatically detected GOPATHS, such as `gb`, `godep` to be used if possible [gh-861] +* Add `(go-imports)` mapping to make it assignable to other keys [gh-878] +* Increase compatibility with tcsh [gh-869] +* Improve `:GoInstallBinaries` for GOPATH's which don't have packages that work well with `go get -u`. We have a new `g:go_get_update` setting to disable it. By default it's enabled. [gh-883] + + + +BUG FIXES: +* Fix `(go-freevars)` plug mapping to work as in visual mode instead of noncompatible normal mode [gh-832] +* Commands based on guru now shows a more meaningful error message instead of just showing the exit status (-1) +* Fix `:GoCoverage` accidently enabling syntax highlighting for users who don't use syntax (i.e syntax off) [gh-827] +* Fix `:GoCoverage` colors to work for xterm as well [gh-863] +* Fix commenting out block of texts for Go templates (filetype gothtmltmpl) [gh-813] +* Fix `:GoImplements` failing because of an empty scope definition. Now we default to current package to make it usable. +* Fix `:GoPlay` posting to non HTTPS url. [gh-847] +* Fix escaping the filenames for lint and motion commands [gh-862] +* Fix escaping the filename to `:GoDef` completely for tcsh [gh-868] +* Fix showing SUCCESS for `go test` related commands if no test files are available [gh-859] + + + +## 1.6 (April 25, 2016) + +FEATURES: + +* New `CHANGELOG.md` file (which you're reading now). This will make it easier + for me to track changes and release versions +* **`:GoCoverage`** is now highlighting the current source file for + covered/uncovered lines. If called again it runs the tests and updates the + annotation. Use `:GoCoverageClear` to clear the coverage annotation. + This is a pretty good addition to vim-go and I suggest to check out the gif + that shows it in action: https://twitter.com/fatih/status/716722650383564800 + [gh-786] +* **`:GoCoverageToggle`** just like `:GoCoverage` but acts as a toggle. If run + again it clears the annotation. +* **`:GoCoverageBrowser`** opens a new annotated HTML page. This is the old + `:GoCoverage` behavior [gh-786] +* **`:GoDoc`** uses now [gogetdoc](https://github.com/zmb3/gogetdoc) to + lookup and display the comment documentation for the identifier under the + cursor. This is more superior as it support looking up dot imports, named + imports and imports where package name and file name are different [gh-782] +* **`guru support`**: `oracle` is replaced by the new tool `guru`. `oracle.vim` + is therefore renamed to `guru.vim`. I've also refactored the code to make it + much more easier to maintain and add additional features in future (such as + upcoming JSON decoding). vim-go is now fully compatible with `guru`. Please + be sure you have installed `guru`. You can easily do it with + `:GoInstallBinaries`. +* **`:GoDef`** uses now `guru definition` under the hood instead of `godef`. + This fixes the following issues: 1. dot imports 2. vendor imports 3. folder + != package name imports. The tool `godef` is also deprecated and not used + anymore. +* **`:GoDef`** does have now history of the call stack. This means you can + easily jump back to your last entry. This can be done with the new command + `:GoDefPop` or the mapping `CTRL-t`. To see the stack and jump between entries + you can use the new command `:GoDefStack`, which shows the list of all stack + entries. To reset the stack list anytime you can call `:GoDefStackClear` + [gh-776] + +IMPROVEMENTS: + +* **`:GoCoverage`** is executed asynchronously when used within Neovim [gh-686] +* **`:GoTestFunc`** supports now testable examples [gh-794] +* **`:GoDef`** can jump to existing buffers instead of opening a new window + (split, vsplit or tab). By default it's disabled to not break the old + behavior, can be enabled with `let g:go_def_reuse_buffer = 1` + +BUG FIXES: + +* Fix not showing documentation for dot, named and package/file name being different imports [gh-332] +* Term mode: fix closing location list if result is successful after a failed attempt [gh-768] +* Syntax: fix gotexttmpl identifier highlighting [gh-778] +* Doc: fix wrong wording for `go-run` mapping. It's for the whole main package, + not for the current file + +BACKWARDS INCOMPATIBILITIES: + +* `:GoDef` doesn't accept any identifier as an argument. This is not suported + via `guru definition` and also was not widely used either. Also with this, we + significantly simplified the existing def.vim code +* `:GoOracleScope` and `:GoOracleTags` are deprecated in favor of + `:GoGuruScope` and `:GoGuruTags`. Also `g:go_oracle_scope` is renamed to + `g:go_guru_scope` +* `g:go_guru_scope` accepts a variable in type of `list` instead of `string`. + i.g: `let g:go_guru_scope = ["github.com/fatih/structs", "golang.org/x/tools/..."]` + + +## Previous releases + +Previous changelogs can be found here: https://github.com/fatih/vim-go/releases diff --git a/vim/bundle/vim-go/LICENSE b/vim/bundle/vim-go/LICENSE new file mode 100644 index 0000000..d9493d4 --- /dev/null +++ b/vim/bundle/vim-go/LICENSE @@ -0,0 +1,60 @@ +Copyright (c) 2015, Fatih Arslan +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of vim-go nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This software includes some portions from Go. Go is used under the terms of the +BSD like license. + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The Go gopher was designed by Renee French. http://reneefrench.blogspot.com/ The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details: https://blog.golang.org/gopher diff --git a/vim/bundle/vim-go/Makefile b/vim/bundle/vim-go/Makefile new file mode 100644 index 0000000..20b296d --- /dev/null +++ b/vim/bundle/vim-go/Makefile @@ -0,0 +1,7 @@ +all: test + +test: + @echo "==> Running tests" + @./scripts/test.sh + +.PHONY: all test diff --git a/vim/bundle/vim-go/README.md b/vim/bundle/vim-go/README.md new file mode 100644 index 0000000..7fdd1c9 --- /dev/null +++ b/vim/bundle/vim-go/README.md @@ -0,0 +1,67 @@ +# 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 logo +

+ +## Features + +This plugin adds Go language support for Vim, with the following main features: + +* Build with `:GoBuild`, install with `:GoInstall` or test + with `:GoTest` (run single tests via `:GoTestFunc`) +* Show test coverage with `:GoCoverage` or in browser with `:GoCoverageBrowser` +* Goto definition with `:GoDef` +* Quick jump to declarations with `:GoDecls` or `:GoDeclsDir` +* Show documentation with `:GoDoc` inside or in browser with `:GoDocBrowser` +* Quickly execute your current file/files with `:GoRun` +* Advanced source analysis tools utilizing guru, such as `:GoImplements`, + `:GoCallees`, and `:GoReferrers` +* Change or display `GOPATH` with `:GoPath` +* Multiple 3rd linter support with `:GoMetaLinter` +* Renaming identifiers with `:GoRename` +* Share your code to [play.golang.org](http://play.golang.org) with `:GoPlay` +* Switch between `*.go` and `*_test.go` code with `:GoAlternate` +* Add/Remove tags on struct fields with `:GoAddTags` +* Add import paths via `:GoImport` or remove them with `:GoDrop` +* Custom vim text objects such as `a function (af)` or `inner function (if)` +* ... and many more! Please see [doc/vim-go.txt](doc/vim-go.txt) for more information. + + +## Install + +Master branch is a **development** branch. Please use with caution. +I recommend to use the [**latest stable release**](https://github.com/fatih/vim-go/releases/latest) + +Vim-go follows the standard runtime path structure. Below are some helper lines +for popular package managers: + +* [Pathogen](https://github.com/tpope/vim-pathogen) + * `git clone https://github.com/fatih/vim-go.git ~/.vim/bundle/vim-go` +* [vim-plug](https://github.com/junegunn/vim-plug) + * `Plug 'fatih/vim-go'` +* [Vim packages](http://vimhelp.appspot.com/repeat.txt.html#packages) + * `git clone https://github.com/fatih/vim-go.git ~/.vim/pack/plugins/start/vim-go` + +After installing, please install all necessary binaries. We have a handy +command for it: + +``` +:GoInstallBinaries +``` + +for more information please check out the [documentation](doc/vim-go.txt) + +## Usage + +Official documentation can be found under [doc/vim-go.txt](doc/vim-go.txt). You can display it from within Vim with: + +``` +:help vim-go +``` +We also have an [official vim-go +tutorial](https://github.com/fatih/vim-go-tutorial). + +## License + +The BSD 3-Clause License - see [`LICENSE`](LICENSE) for more details diff --git a/vim/bundle/vim-go/addon-info.json b/vim/bundle/vim-go/addon-info.json new file mode 100644 index 0000000..145d961 --- /dev/null +++ b/vim/bundle/vim-go/addon-info.json @@ -0,0 +1,6 @@ +{ + "name": "vim-go", + "description": "Full featured Go (golang) support for Vim.", + "author": "Fatih Arslan ", + "repository" : {"type": "git", "url": "https://github.com/fatih/vim-go.git"} +} diff --git a/vim/bundle/vim-go/assets/screenshot.png b/vim/bundle/vim-go/assets/screenshot.png new file mode 100644 index 0000000..8b2923d Binary files /dev/null and b/vim/bundle/vim-go/assets/screenshot.png differ diff --git a/vim/bundle/vim-go/assets/vim-go.png b/vim/bundle/vim-go/assets/vim-go.png new file mode 100644 index 0000000..cb26e2c Binary files /dev/null and b/vim/bundle/vim-go/assets/vim-go.png differ diff --git a/vim/bundle/vim-go/assets/vim-go.svg b/vim/bundle/vim-go/assets/vim-go.svg new file mode 100644 index 0000000..8471db5 --- /dev/null +++ b/vim/bundle/vim-go/assets/vim-go.svg @@ -0,0 +1,821 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vim/bundle/vim-go/autoload/ctrlp/decls.vim b/vim/bundle/vim-go/autoload/ctrlp/decls.vim new file mode 100644 index 0000000..e742676 --- /dev/null +++ b/vim/bundle/vim-go/autoload/ctrlp/decls.vim @@ -0,0 +1,159 @@ +let s:go_decls_var = { + \ 'init': 'ctrlp#decls#init()', + \ 'exit': 'ctrlp#decls#exit()', + \ 'enter': 'ctrlp#decls#enter()', + \ 'accept': 'ctrlp#decls#accept', + \ 'lname': 'declarations', + \ 'sname': 'decls', + \ 'type': 'tabs', + \} + +if exists('g:ctrlp_ext_vars') && !empty(g:ctrlp_ext_vars) + let g:ctrlp_ext_vars = add(g:ctrlp_ext_vars, s:go_decls_var) +else + let g:ctrlp_ext_vars = [s:go_decls_var] +endif + +function! ctrlp#decls#init() abort + cal s:enable_syntax() + return s:decls +endfunction + +function! ctrlp#decls#exit() abort + unlet! s:decls s:current_dir s:target +endfunction + +" The action to perform on the selected string +" Arguments: +" a:mode the mode that has been chosen by pressing or +" the values are 'e', 'v', 't' and 'h', respectively +" a:str the selected string +function! ctrlp#decls#accept(mode, str) abort + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + " we jump to the file directory so we can get the fullpath via fnamemodify + " below + execute cd . s:current_dir + + let vals = matchlist(a:str, '|\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)|') + + " i.e: main.go + let filename = vals[1] + let line = vals[2] + let col = vals[3] + + " i.e: /Users/fatih/vim-go/main.go + let filepath = fnamemodify(filename, ":p") + + " acceptile is a very versatile method, + call ctrlp#acceptfile(a:mode, filepath) + call cursor(line, col) + silent! norm! zvzz + finally + "jump back to old dir + execute cd . fnameescape(dir) + endtry +endfunction + +function! ctrlp#decls#enter() abort + let s:current_dir = fnameescape(expand('%:p:h')) + let s:decls = [] + + let bin_path = go#path#CheckBinPath('motion') + if empty(bin_path) + return + endif + let command = printf("%s -format vim -mode decls", bin_path) + let command .= " -include ". get(g:, "go_decls_includes", "func,type") + + call go#cmd#autowrite() + + if s:mode == 0 + " current file mode + let fname = expand("%:p") + if exists('s:target') + let fname = s:target + endif + + let command .= printf(" -file %s", fname) + else + " all functions mode + let dir = expand("%:p:h") + if exists('s:target') + let dir = s:target + endif + + let command .= printf(" -dir %s", dir) + endif + + let out = go#util#System(command) + if go#util#ShellError() != 0 + call go#util#EchoError(out) + return + endif + + if exists("l:tmpname") + call delete(l:tmpname) + endif + + let result = eval(out) + if type(result) != 4 || !has_key(result, 'decls') + return + endif + + let decls = result.decls + + " find the maximum function name + let max_len = 0 + for decl in decls + if len(decl.ident)> max_len + let max_len = len(decl.ident) + endif + endfor + + for decl in decls + " paddings + let space = " " + for i in range(max_len - len(decl.ident)) + let space .= " " + endfor + + call add(s:decls, printf("%s\t%s |%s:%s:%s|\t%s", + \ decl.ident . space, + \ decl.keyword, + \ fnamemodify(decl.filename, ":t"), + \ decl.line, + \ decl.col, + \ decl.full, + \)) + endfor +endfunc + +function! s:enable_syntax() abort + if !(has('syntax') && exists('g:syntax_on')) + return + endif + + syntax match CtrlPIdent '\zs\h\+\ze\s' + syntax match CtrlPKeyword '\zs[^\t|]\+\ze|[^|]\+:\d\+:\d\+|' + syntax match CtrlPFilename '|\zs[^|]\+:\d\+:\d\+\ze|' + syntax match CtrlPSignature '\zs\t.*\ze$' contains=CtrlPKeyWord,CtrlPFilename + + highlight link CtrlPIdent Function + highlight link CtrlPKeyword Keyword + highlight link CtrlPFilename SpecialComment + highlight link CtrlPSignature Comment +endfunction + +let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) + +function! ctrlp#decls#cmd(mode, ...) abort + let s:mode = a:mode + if a:0 && !empty(a:1) + let s:target = a:1 + endif + return s:id +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/alternate.vim b/vim/bundle/vim-go/autoload/go/alternate.vim new file mode 100644 index 0000000..f2cb210 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/alternate.vim @@ -0,0 +1,32 @@ +" By default use edit (current buffer view) to switch +if !exists("g:go_alternate_mode") + let g:go_alternate_mode = "edit" +endif + +" Test alternates between the implementation of code and the test code. +function! go#alternate#Switch(bang, cmd) abort + let file = expand('%') + if empty(file) + call go#util#EchoError("no buffer name") + return + elseif file =~# '^\f\+_test\.go$' + let l:root = split(file, '_test.go$')[0] + let l:alt_file = l:root . ".go" + elseif file =~# '^\f\+\.go$' + let l:root = split(file, ".go$")[0] + let l:alt_file = l:root . '_test.go' + else + call go#util#EchoError("not a go file") + return + endif + if !filereadable(alt_file) && !bufexists(alt_file) && !a:bang + call go#util#EchoError("couldn't find ".alt_file) + return + elseif empty(a:cmd) + execute ":" . g:go_alternate_mode . " " . alt_file + else + execute ":" . a:cmd . " " . alt_file + endif +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/asmfmt.vim b/vim/bundle/vim-go/autoload/go/asmfmt.vim new file mode 100644 index 0000000..cc8acd3 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/asmfmt.vim @@ -0,0 +1,69 @@ +" asmfmt.vim: Vim command to format Go asm files with asmfmt +" (github.com/klauspost/asmfmt). +" +" This filetype plugin adds new commands for asm buffers: +" +" :Fmt +" +" Filter the current asm buffer through asmfmt. +" It tries to preserve cursor position and avoids +" replacing the buffer with stderr output. +" +" Options: +" +" g:go_asmfmt_autosave [default=0] +" +" Flag to automatically call :Fmt when file is saved. + +let s:got_fmt_error = 0 + +" This is a trimmed-down version of the logic in fmt.vim. + +function! go#asmfmt#Format() abort + " Save state. + let l:curw = winsaveview() + + " Write the current buffer to a tempfile. + let l:tmpname = tempname() + call writefile(go#util#GetLines(), l:tmpname) + + " Run asmfmt. + let path = go#path#CheckBinPath("asmfmt") + if empty(path) + return + endif + let out = go#util#System(path . ' -w ' . l:tmpname) + + " If there's no error, replace the current file with the output. + if go#util#ShellError() == 0 + " Remove undo point caused by BufWritePre. + try | silent undojoin | catch | endtry + + " Replace the current file with the temp file; then reload the buffer. + let old_fileformat = &fileformat + " save old file permissions + let original_fperm = getfperm(expand('%')) + call rename(l:tmpname, expand('%')) + " restore old file permissions + call setfperm(expand('%'), original_fperm) + silent edit! + let &fileformat = old_fileformat + let &syntax = &syntax + endif + + " Restore the cursor/window positions. + call winrestview(l:curw) +endfunction + +function! go#asmfmt#ToggleAsmFmtAutoSave() abort + if get(g:, "go_asmfmt_autosave", 0) + let g:go_asmfmt_autosave = 1 + call go#util#EchoProgress("auto asmfmt enabled") + return + end + + let g:go_asmfmt_autosave = 0 + call go#util#EchoProgress("auto asmfmt disabled") +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/cmd.vim b/vim/bundle/vim-go/autoload/go/cmd.vim new file mode 100644 index 0000000..ec7d44c --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/cmd.vim @@ -0,0 +1,488 @@ +function! go#cmd#autowrite() abort + if &autowrite == 1 + silent! wall + endif +endfunction + +" Build builds the source code without producting any output binary. We live in +" an editor so the best is to build it to catch errors and fix them. By +" default it tries to call simply 'go build', but it first tries to get all +" dependent files for the current folder and passes it to go build. +function! go#cmd#Build(bang, ...) abort + " expand all wildcards(i.e: '%' to the current file name) + let goargs = map(copy(a:000), "expand(v:val)") + + " escape all shell arguments before we pass it to make + if !has('nvim') + let goargs = go#util#Shelllist(goargs, 1) + endif + " create our command arguments. go build discards any results when it + " compiles multiple packages. So we pass the `errors` package just as an + " placeholder with the current folder (indicated with '.') + let args = ["build"] + goargs + [".", "errors"] + + if go#util#has_job() + if get(g:, 'go_echo_command_info', 1) + call go#util#EchoProgress("building dispatched ...") + endif + + call s:cmd_job({ + \ 'cmd': ['go'] + args, + \ 'bang': a:bang, + \}) + return + elseif has('nvim') + if get(g:, 'go_echo_command_info', 1) + call go#util#EchoProgress("building dispatched ...") + endif + + " if we have nvim, call it asynchronously and return early ;) + call go#jobcontrol#Spawn(a:bang, "build", args) + return + endif + + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + let default_makeprg = &makeprg + let &makeprg = "go " . join(args, ' ') + + let l:listtype = go#list#Type("quickfix") + " execute make inside the source folder so we can parse the errors + " correctly + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd . fnameescape(expand("%:p:h")) + if l:listtype == "locationlist" + silent! exe 'lmake!' + else + silent! exe 'make!' + endif + redraw! + finally + execute cd . fnameescape(dir) + endtry + + let errors = go#list#Get(l:listtype) + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) && !a:bang + call go#list#JumpToFirst(l:listtype) + else + call go#util#EchoSuccess("[build] SUCCESS") + endif + + let &makeprg = default_makeprg + let $GOPATH = old_gopath +endfunction + + +" BuildTags sets or shows the current build tags used for tools +function! go#cmd#BuildTags(bang, ...) abort + if a:0 + if a:0 == 1 && a:1 == '""' + unlet g:go_build_tags + call go#util#EchoSuccess("build tags are cleared") + else + let g:go_build_tags = a:1 + call go#util#EchoSuccess("build tags are changed to: ". a:1) + endif + + return + endif + + if !exists('g:go_build_tags') + call go#util#EchoSuccess("build tags are not set") + else + call go#util#EchoSuccess("current build tags: ". g:go_build_tags) + endif +endfunction + + +" Run runs the current file (and their dependencies if any) in a new terminal. +function! go#cmd#RunTerm(bang, mode, files) abort + if empty(a:files) + let cmd = "go run ". go#util#Shelljoin(go#tool#Files()) + else + let cmd = "go run ". go#util#Shelljoin(map(copy(a:files), "expand(v:val)"), 1) + endif + call go#term#newmode(a:bang, cmd, a:mode) +endfunction + +" Run runs the current file (and their dependencies if any) and outputs it. +" This is intented to test small programs and play with them. It's not +" suitable for long running apps, because vim is blocking by default and +" calling long running apps will block the whole UI. +function! go#cmd#Run(bang, ...) abort + if has('nvim') + call go#cmd#RunTerm(a:bang, '', a:000) + return + endif + + if go#util#has_job() + " NOTE(arslan): 'term': 'open' case is not implement for +jobs. This means + " executions waiting for stdin will not work. That's why we don't do + " anything. Once this is implemented we're going to make :GoRun async + endif + + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + if go#util#IsWin() + exec '!go run ' . go#util#Shelljoin(go#tool#Files()) + if v:shell_error + redraws! | echon "vim-go: [run] " | echohl ErrorMsg | echon "FAILED"| echohl None + else + redraws! | echon "vim-go: [run] " | echohl Function | echon "SUCCESS"| echohl None + endif + + let $GOPATH = old_gopath + return + endif + + " :make expands '%' and '#' wildcards, so they must also be escaped + let default_makeprg = &makeprg + if a:0 == 0 + let &makeprg = 'go run ' . go#util#Shelljoin(go#tool#Files(), 1) + else + let &makeprg = "go run " . go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1) + endif + + let l:listtype = go#list#Type("quickfix") + + if l:listtype == "locationlist" + exe 'lmake!' + else + exe 'make!' + endif + + let items = go#list#Get(l:listtype) + let errors = go#tool#FilterValids(items) + + call go#list#Populate(l:listtype, errors, &makeprg) + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) && !a:bang + call go#list#JumpToFirst(l:listtype) + endif + + let $GOPATH = old_gopath + let &makeprg = default_makeprg +endfunction + +" Install installs the package by simple calling 'go install'. If any argument +" is given(which are passed directly to 'go install') it tries to install +" those packages. Errors are populated in the location window. +function! go#cmd#Install(bang, ...) abort + " use vim's job functionality to call it asynchronously + if go#util#has_job() + " expand all wildcards(i.e: '%' to the current file name) + let goargs = map(copy(a:000), "expand(v:val)") + + if get(g:, 'go_echo_command_info', 1) + call go#util#EchoProgress("installing dispatched ...") + endif + + call s:cmd_job({ + \ 'cmd': ['go', 'install'] + goargs, + \ 'bang': a:bang, + \}) + return + endif + + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + let default_makeprg = &makeprg + + " :make expands '%' and '#' wildcards, so they must also be escaped + let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1) + let &makeprg = "go install " . goargs + + let l:listtype = go#list#Type("quickfix") + " execute make inside the source folder so we can parse the errors + " correctly + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd . fnameescape(expand("%:p:h")) + if l:listtype == "locationlist" + silent! exe 'lmake!' + else + silent! exe 'make!' + endif + redraw! + finally + execute cd . fnameescape(dir) + endtry + + let errors = go#list#Get(l:listtype) + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) && !a:bang + call go#list#JumpToFirst(l:listtype) + else + call go#util#EchoSuccess("installed to ". go#path#Detect()) + endif + + let $GOPATH = old_gopath + let &makeprg = default_makeprg +endfunction + +" Test runs `go test` in the current directory. If compile is true, it'll +" compile the tests instead of running them (useful to catch errors in the +" test files). Any other argument is appendend to the final `go test` command +function! go#cmd#Test(bang, compile, ...) abort + let args = ["test"] + + " don't run the test, only compile it. Useful to capture and fix errors. + if a:compile + let compile_file = "vim-go-test-compile" + call extend(args, ["-c", "-o", compile_file]) + endif + + if a:0 + let goargs = a:000 + + " do not expand for coverage mode as we're passing the arg ourself + if a:1 != '-coverprofile' + " expand all wildcards(i.e: '%' to the current file name) + let goargs = map(copy(a:000), "expand(v:val)") + endif + + if !(has('nvim') || go#util#has_job()) + let goargs = go#util#Shelllist(goargs, 1) + endif + + call extend(args, goargs, 1) + else + " only add this if no custom flags are passed + let timeout = get(g:, 'go_test_timeout', '10s') + call add(args, printf("-timeout=%s", timeout)) + endif + + if get(g:, 'go_echo_command_info', 1) + if a:compile + echon "vim-go: " | echohl Identifier | echon "compiling tests ..." | echohl None + else + echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None + endif + endif + + if go#util#has_job() + " use vim's job functionality to call it asynchronously + let job_args = { + \ 'cmd': ['go'] + args, + \ 'bang': a:bang, + \ } + + if a:compile + let job_args['custom_cb'] = function('s:test_compile', [compile_file]) + endif + + call s:cmd_job(job_args) + return + elseif has('nvim') + " use nvims's job functionality + if get(g:, 'go_term_enabled', 0) + let id = go#term#new(a:bang, ["go"] + args) + else + let id = go#jobcontrol#Spawn(a:bang, "test", args) + endif + + if a:compile + call go#jobcontrol#AddHandler(function('s:test_compile_handler')) + let s:test_compile_handlers[id] = compile_file + endif + return id + endif + + call go#cmd#autowrite() + redraw + + let command = "go " . join(args, ' ') + let out = go#tool#ExecuteInDir(command) + + let l:listtype = "quickfix" + + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + execute cd fnameescape(expand("%:p:h")) + + if a:compile + call delete(compile_file) + endif + + if go#util#ShellError() != 0 + let errors = go#tool#ParseErrors(split(out, '\n')) + let errors = go#tool#FilterValids(errors) + + call go#list#Populate(l:listtype, errors, command) + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) && !a:bang + call go#list#JumpToFirst(l:listtype) + elseif empty(errors) + " failed to parse errors, output the original content + call go#util#EchoError(out) + endif + echon "vim-go: " | echohl ErrorMsg | echon "[test] FAIL" | echohl None + else + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + + if a:compile + echon "vim-go: " | echohl Function | echon "[test] SUCCESS" | echohl None + else + echon "vim-go: " | echohl Function | echon "[test] PASS" | echohl None + endif + endif + execute cd . fnameescape(dir) +endfunction + +" Testfunc runs a single test that surrounds the current cursor position. +" Arguments are passed to the `go test` command. +function! go#cmd#TestFunc(bang, ...) abort + " search flags legend (used only) + " 'b' search backward instead of forward + " 'c' accept a match at the cursor position + " 'n' do Not move the cursor + " 'W' don't wrap around the end of the file + " + " for the full list + " :help search + let test = search('func \(Test\|Example\)', "bcnW") + + if test == 0 + echo "vim-go: [test] no test found immediate to cursor" + return + end + + let line = getline(test) + let name = split(split(line, " ")[1], "(")[0] + let args = [a:bang, 0, "-run", name . "$"] + + if a:0 + call extend(args, a:000) + endif + + call call('go#cmd#Test', args) +endfunction + +" Generate runs 'go generate' in similar fashion to go#cmd#Build() +function! go#cmd#Generate(bang, ...) abort + let default_makeprg = &makeprg + + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + " :make expands '%' and '#' wildcards, so they must also be escaped + let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1) + if go#util#ShellError() != 0 + let &makeprg = "go generate " . goargs + else + let gofiles = go#util#Shelljoin(go#tool#Files(), 1) + let &makeprg = "go generate " . goargs . ' ' . gofiles + endif + + let l:listtype = go#list#Type("quickfix") + + echon "vim-go: " | echohl Identifier | echon "generating ..."| echohl None + if l:listtype == "locationlist" + silent! exe 'lmake!' + else + silent! exe 'make!' + endif + redraw! + + let errors = go#list#Get(l:listtype) + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) + if !a:bang + call go#list#JumpToFirst(l:listtype) + endif + else + redraws! | echon "vim-go: " | echohl Function | echon "[generate] SUCCESS"| echohl None + endif + + let &makeprg = default_makeprg + let $GOPATH = old_gopath +endfunction + +" --------------------- +" | Vim job callbacks | +" --------------------- + +function s:cmd_job(args) abort + let status_dir = expand('%:p:h') + let started_at = reltime() + + call go#statusline#Update(status_dir, { + \ 'desc': "current status", + \ 'type': a:args.cmd[1], + \ 'state': "started", + \}) + + " autowrite is not enabled for jobs + call go#cmd#autowrite() + + function! s:error_info_cb(job, exit_status, data) closure abort + let status = { + \ 'desc': 'last status', + \ 'type': a:args.cmd[1], + \ 'state': "success", + \ } + + if a:exit_status + let status.state = "failed" + endif + + let elapsed_time = reltimestr(reltime(started_at)) + " strip whitespace + let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') + let status.state .= printf(" (%ss)", elapsed_time) + + call go#statusline#Update(status_dir, status) + endfunction + + let a:args.error_info_cb = funcref('s:error_info_cb') + let callbacks = go#job#Spawn(a:args) + + let start_options = { + \ 'callback': callbacks.callback, + \ 'exit_cb': callbacks.exit_cb, + \ } + + " modify GOPATH if needed + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + " pre start + let dir = getcwd() + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let jobdir = fnameescape(expand("%:p:h")) + execute cd . jobdir + + call job_start(a:args.cmd, start_options) + + " post start + execute cd . fnameescape(dir) + let $GOPATH = old_gopath +endfunction + + +" test_compile is called when a GoTestCompile call is finished +function! s:test_compile(test_file, job, exit_status, data) abort + call delete(a:test_file) +endfunction + +" ----------------------- +" | Neovim job handlers | +" ----------------------- +let s:test_compile_handlers = {} + +function! s:test_compile_handler(job, exit_status, data) abort + if !has_key(s:test_compile_handlers, a:job.id) + return + endif + let l:compile_file = s:test_compile_handlers[a:job.id] + call delete(l:compile_file) + unlet s:test_compile_handlers[a:job.id] +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/complete.vim b/vim/bundle/vim-go/autoload/go/complete.vim new file mode 100644 index 0000000..a5d0ec1 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/complete.vim @@ -0,0 +1,172 @@ +let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix' + +function! s:gocodeCurrentBuffer() abort + let file = tempname() + call writefile(go#util#GetLines(), file) + return file +endfunction + +function! s:gocodeCommand(cmd, preargs, args) abort + for i in range(0, len(a:args) - 1) + let a:args[i] = go#util#Shellescape(a:args[i]) + endfor + for i in range(0, len(a:preargs) - 1) + let a:preargs[i] = go#util#Shellescape(a:preargs[i]) + endfor + + let bin_path = go#path#CheckBinPath("gocode") + if empty(bin_path) + return + endif + + " we might hit cache problems, as gocode doesn't handle well different + " GOPATHS: https://github.com/nsf/gocode/issues/239 + let old_gopath = $GOPATH + let old_goroot = $GOROOT + let $GOPATH = go#path#Detect() + let $GOROOT = go#util#env("goroot") + + let socket_type = get(g:, 'go_gocode_socket_type', s:sock_type) + let cmd = printf('%s -sock %s %s %s %s', + \ go#util#Shellescape(bin_path), + \ socket_type, + \ join(a:preargs), + \ go#util#Shellescape(a:cmd), + \ join(a:args) + \ ) + + let result = go#util#System(cmd) + let $GOPATH = old_gopath + let $GOROOT = old_goroot + + if go#util#ShellError() != 0 + return "[\"0\", []]" + else + if &encoding != 'utf-8' + let result = iconv(result, 'utf-8', &encoding) + endif + return result + endif +endfunction + +function! s:gocodeCurrentBufferOpt(filename) abort + return '-in=' . a:filename +endfunction + +let s:optionsEnabled = 0 +function! s:gocodeEnableOptions() abort + if s:optionsEnabled + return + endif + + let bin_path = go#path#CheckBinPath("gocode") + if empty(bin_path) + return + endif + + let s:optionsEnabled = 1 + + call go#util#System(printf('%s set propose-builtins %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_propose_builtins', 1)))) + call go#util#System(printf('%s set autobuild %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_autobuild', 1)))) + call go#util#System(printf('%s set unimported-packages %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_unimported_packages', 0)))) +endfunction + +function! s:toBool(val) abort + if a:val | return 'true ' | else | return 'false' | endif +endfunction + +function! s:gocodeAutocomplete() abort + call s:gocodeEnableOptions() + + let filename = s:gocodeCurrentBuffer() + let result = s:gocodeCommand('autocomplete', + \ [s:gocodeCurrentBufferOpt(filename), '-f=vim'], + \ [expand('%:p'), go#util#OffsetCursor()]) + call delete(filename) + return result +endfunction + +function! go#complete#GetInfo() abort + let offset = go#util#OffsetCursor()+1 + let filename = s:gocodeCurrentBuffer() + let result = s:gocodeCommand('autocomplete', + \ [s:gocodeCurrentBufferOpt(filename), '-f=godit'], + \ [expand('%:p'), offset]) + call delete(filename) + + " first line is: Charcount,,NumberOfCandidates, i.e: 8,,1 + " following lines are candiates, i.e: func foo(name string),,foo( + let out = split(result, '\n') + + " no candidates are found + if len(out) == 1 + return "" + endif + + " only one candiate is found + if len(out) == 2 + return split(out[1], ',,')[0] + endif + + " to many candidates are available, pick one that maches the word under the + " cursor + let infos = [] + for info in out[1:] + call add(infos, split(info, ',,')[0]) + endfor + + let wordMatch = '\<' . expand("") . '\>' + " escape single quotes in wordMatch before passing it to filter + let wordMatch = substitute(wordMatch, "'", "''", "g") + let filtered = filter(infos, "v:val =~ '".wordMatch."'") + + if len(filtered) == 1 + return filtered[0] + endif + + return "" +endfunction + +function! go#complete#Info(auto) abort + " auto is true if we were called by g:go_auto_type_info's autocmd + let result = go#complete#GetInfo() + if !empty(result) + " if auto, and the result is a PANIC by gocode, hide it + if a:auto && result ==# 'PANIC PANIC PANIC' | return | endif + echo "vim-go: " | echohl Function | echon result | echohl None + endif +endfunction + +function! s:trim_bracket(val) abort + let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '') + return a:val +endfunction + +function! go#complete#Complete(findstart, base) abort + "findstart = 1 when we need to get the text length + if a:findstart == 1 + execute "silent let g:gocomplete_completions = " . s:gocodeAutocomplete() + return col('.') - g:gocomplete_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(g:gocomplete_completions[1]), 's:trim_bracket(v:val)') + endif + return g:gocomplete_completions[1] + endif +endf + +function! go#complete#ToggleAutoTypeInfo() abort + if get(g:, "go_auto_type_info", 0) + let g:go_auto_type_info = 0 + call go#util#EchoProgress("auto type info disabled") + return + end + + let g:go_auto_type_info = 1 + call go#util#EchoProgress("auto type info enabled") +endfunction + + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/coverage.vim b/vim/bundle/vim-go/autoload/go/coverage.vim new file mode 100644 index 0000000..fd2bb76 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/coverage.vim @@ -0,0 +1,371 @@ +let s:toggle = 0 + +" Buffer creates a new cover profile with 'go test -coverprofile' and changes +" the current buffers highlighting to show covered and uncovered sections of +" the code. If run again it clears the annotation. +function! go#coverage#BufferToggle(bang, ...) abort + if s:toggle + call go#coverage#Clear() + return + endif + + if a:0 == 0 + return call(function('go#coverage#Buffer'), [a:bang]) + endif + + return call(function('go#coverage#Buffer'), [a:bang] + a:000) +endfunction + +" Buffer creates a new cover profile with 'go test -coverprofile' and changes +" teh current buffers highlighting to show covered and uncovered sections of +" the code. Calling it again reruns the tests and shows the last updated +" coverage. +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 + if !exists("*matchaddpos") + call go#util#EchoError("GoCoverage is supported with Vim version 7.4-330 or later") + return -1 + endif + + " check if there is any test file, if not we just return + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd . fnameescape(expand("%:p:h")) + if empty(glob("*_test.go")) + call go#util#EchoError("no test files available") + return + endif + finally + execute cd . fnameescape(dir) + endtry + + let s:toggle = 1 + let l:tmpname = tempname() + + if go#util#has_job() + call s:coverage_job({ + \ 'cmd': ['go', 'test', '-coverprofile', l:tmpname], + \ 'custom_cb': function('s:coverage_callback', [l:tmpname]), + \ 'bang': a:bang, + \ }) + return + endif + + let args = [a:bang, 0, "-coverprofile", l:tmpname] + if a:0 + call extend(args, a:000) + endif + + let disabled_term = 0 + if get(g:, 'go_term_enabled') + let disabled_term = 1 + let g:go_term_enabled = 0 + endif + + let id = call('go#cmd#Test', args) + + if disabled_term + let g:go_term_enabled = 1 + endif + + if has('nvim') + call go#jobcontrol#AddHandler(function('s:coverage_handler')) + let s:coverage_handler_jobs[id] = l:tmpname + return + endif + + if go#util#ShellError() == 0 + call go#coverage#overlay(l:tmpname) + endif + + call delete(l:tmpname) +endfunction + +" Clear clears and resets the buffer annotation matches +function! go#coverage#Clear() abort + call clearmatches() + + if exists("s:toggle") | let s:toggle = 0 | endif + + " remove the autocmd we defined + if exists("#BufWinLeave#") + autocmd! BufWinLeave + endif +endfunction + +" Browser creates a new cover profile with 'go test -coverprofile' and opens +" a new HTML coverage page from that profile in a new browser +function! go#coverage#Browser(bang, ...) abort + let l:tmpname = tempname() + if go#util#has_job() + call s:coverage_job({ + \ 'cmd': ['go', 'test', '-coverprofile', l:tmpname], + \ 'custom_cb': function('s:coverage_browser_callback', [l:tmpname]), + \ 'bang': a:bang, + \ }) + return + endif + + let args = [a:bang, 0, "-coverprofile", l:tmpname] + if a:0 + call extend(args, a:000) + endif + + let id = call('go#cmd#Test', args) + if has('nvim') + call go#jobcontrol#AddHandler(function('s:coverage_browser_handler')) + let s:coverage_browser_handler_jobs[id] = l:tmpname + return + endif + + + if go#util#ShellError() == 0 + let openHTML = 'go tool cover -html='.l:tmpname + call go#tool#ExecuteInDir(openHTML) + endif + + call delete(l:tmpname) +endfunction + +" Parses a single line from the cover file generated via go test -coverprofile +" and returns a single coverage profile block. +function! go#coverage#parsegocoverline(line) abort + " file:startline.col,endline.col numstmt count + let mx = '\([^:]\+\):\(\d\+\)\.\(\d\+\),\(\d\+\)\.\(\d\+\)\s\(\d\+\)\s\(\d\+\)' + let tokens = matchlist(a:line, mx) + let ret = {} + let ret.file = tokens[1] + let ret.startline = str2nr(tokens[2]) + let ret.startcol = str2nr(tokens[3]) + let ret.endline = str2nr(tokens[4]) + let ret.endcol = str2nr(tokens[5]) + let ret.numstmt = tokens[6] + let ret.cnt = tokens[7] + return ret +endfunction + +" Generates matches to be added to matchaddpos for the given coverage profile +" block +function! go#coverage#genmatch(cov) abort + let color = 'goCoverageCovered' + if a:cov.cnt == 0 + let color = 'goCoverageUncover' + endif + + let matches = [] + + " if start and end are the same, also specify the byte length + " example: foo.go:92.2,92.65 1 0 + if a:cov.startline == a:cov.endline + call add(matches, { + \ 'group': color, + \ 'pos': [[a:cov.startline, a:cov.startcol, a:cov.endcol - a:cov.startcol]], + \ 'priority': 2, + \ }) + return matches + endif + + " add start columns. Because we don't know the length of the of + " the line, we assume it is at maximum 200 bytes. I know this is hacky, + " but that's only way of fixing the issue + call add(matches, { + \ 'group': color, + \ 'pos': [[a:cov.startline, a:cov.startcol, 200]], + \ 'priority': 2, + \ }) + + " and then the remaining lines + let start_line = a:cov.startline + while start_line < a:cov.endline + let start_line += 1 + call add(matches, { + \ 'group': color, + \ 'pos': [[start_line]], + \ 'priority': 2, + \ }) + endwhile + + " finally end columns + call add(matches, { + \ 'group': color, + \ 'pos': [[a:cov.endline, a:cov.endcol-1]], + \ 'priority': 2, + \ }) + + return matches +endfunction + +" Reads the given coverprofile file and annotates the current buffer +function! go#coverage#overlay(file) abort + if !filereadable(a:file) + return + endif + let lines = readfile(a:file) + + " cover mode, by default it's 'set'. Just here for debugging purposes + let mode = lines[0] + + " contains matches for matchaddpos() + let matches = [] + + " first mark all lines as goCoverageNormalText. We use a custom group to not + " interfere with other buffers highlightings. Because the priority is + " lower than the cover and uncover matches, it'll be overriden. + let cnt = 1 + while cnt <= line('$') + call add(matches, {'group': 'goCoverageNormalText', 'pos': [cnt], 'priority': 1}) + let cnt += 1 + endwhile + + let fname = expand('%') + + " when called for a _test.go file, run the coverage for the actuall file + " file + if fname =~# '^\f\+_test\.go$' + let l:root = split(fname, '_test.go$')[0] + let fname = l:root . ".go" + + if !filereadable(fname) + call go#util#EchoError("couldn't find ".fname) + return + endif + + " open the alternate file to show the coverage + exe ":edit ". fnamemodify(fname, ":p") + endif + + " cov.file includes only the filename itself, without full path + let fname = fnamemodify(fname, ":t") + + for line in lines[1:] + let cov = go#coverage#parsegocoverline(line) + + " TODO(arslan): for now only include the coverage for the current + " buffer + if fname != fnamemodify(cov.file, ':t') + continue + endif + + call extend(matches, go#coverage#genmatch(cov)) + endfor + + " clear the matches if we leave the buffer + autocmd BufWinLeave call go#coverage#Clear() + + for m in matches + call matchaddpos(m.group, m.pos) + endfor +endfunction + + +" --------------------- +" | Vim job callbacks | +" --------------------- +" +function s:coverage_job(args) + " autowrite is not enabled for jobs + call go#cmd#autowrite() + + let status_dir = expand('%:p:h') + function! s:error_info_cb(job, exit_status, data) closure + let status = { + \ 'desc': 'last status', + \ 'type': "coverage", + \ 'state': "finished", + \ } + + if a:exit_status + let status.state = "failed" + endif + + call go#statusline#Update(status_dir, status) + endfunction + + let a:args.error_info_cb = funcref('s:error_info_cb') + let callbacks = go#job#Spawn(a:args) + + let start_options = { + \ 'callback': callbacks.callback, + \ 'exit_cb': callbacks.exit_cb, + \ } + + " modify GOPATH if needed + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + " pre start + let dir = getcwd() + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let jobdir = fnameescape(expand("%:p:h")) + execute cd . jobdir + + call go#statusline#Update(status_dir, { + \ 'desc': "current status", + \ 'type': "coverage", + \ 'state': "started", + \}) + + call job_start(a:args.cmd, start_options) + + " post start + execute cd . fnameescape(dir) + let $GOPATH = old_gopath +endfunction + +" coverage_callback is called when the coverage execution is finished +function! s:coverage_callback(coverfile, job, exit_status, data) + if a:exit_status == 0 + call go#coverage#overlay(a:coverfile) + endif + + call delete(a:coverfile) +endfunction + +function! s:coverage_browser_callback(coverfile, job, exit_status, data) + if a:exit_status == 0 + let openHTML = 'go tool cover -html='.a:coverfile + call go#tool#ExecuteInDir(openHTML) + endif + + call delete(a:coverfile) +endfunction + +" ----------------------- +" | Neovim job handlers | +" ----------------------- + +let s:coverage_handler_jobs = {} +let s:coverage_browser_handler_jobs = {} + +function! s:coverage_handler(job, exit_status, data) abort + if !has_key(s:coverage_handler_jobs, a:job.id) + return + endif + let l:tmpname = s:coverage_handler_jobs[a:job.id] + if a:exit_status == 0 + call go#coverage#overlay(l:tmpname) + endif + + call delete(l:tmpname) + unlet s:coverage_handler_jobs[a:job.id] +endfunction + +function! s:coverage_browser_handler(job, exit_status, data) abort + if !has_key(s:coverage_browser_handler_jobs, a:job.id) + return + endif + + let l:tmpname = s:coverage_browser_handler_jobs[a:job.id] + if a:exit_status == 0 + let openHTML = 'go tool cover -html='.l:tmpname + call go#tool#ExecuteInDir(openHTML) + endif + + call delete(l:tmpname) + unlet s:coverage_browser_handler_jobs[a:job.id] +endfunction + + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/def.vim b/vim/bundle/vim-go/autoload/go/def.vim new file mode 100644 index 0000000..2f73cee --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/def.vim @@ -0,0 +1,319 @@ +let s:go_stack = [] +let s:go_stack_level = 0 + +function! go#def#Jump(mode) abort + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') + + " 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 + " times I've decided to support both. By default we still use guru as it + " covers all edge cases, but now anyone can switch to godef if they wish + let bin_name = get(g:, 'go_def_mode', 'guru') + if bin_name == 'godef' + if &modified + " Write current unsaved buffer to a temp file and use the modified content + let l:tmpname = tempname() + call writefile(go#util#GetLines(), l:tmpname) + let fname = l:tmpname + endif + + let bin_path = go#path#CheckBinPath("godef") + if empty(bin_path) + let $GOPATH = old_gopath + return + endif + let command = printf("%s -f=%s -o=%s -t", bin_path, fname, go#util#OffsetCursor()) + let out = go#util#System(command) + if exists("l:tmpname") + call delete(l:tmpname) + endif + elseif bin_name == 'guru' + let bin_path = go#path#CheckBinPath("guru") + if empty(bin_path) + let $GOPATH = old_gopath + return + endif + + let cmd = [bin_path] + let stdin_content = "" + + if &modified + let content = join(go#util#GetLines(), "\n") + let stdin_content = fname . "\n" . strlen(content) . "\n" . content + call add(cmd, "-modified") + endif + + if exists('g:go_guru_tags') + let tags = get(g:, 'go_guru_tags') + call extend(cmd, ["-tags", tags]) + endif + + let fname = fname.':#'.go#util#OffsetCursor() + call extend(cmd, ["definition", fname]) + + if go#util#has_job() + let l:spawn_args = { + \ 'cmd': cmd, + \ 'custom_cb': function('s:jump_to_declaration_cb', [a:mode, bin_name]), + \ } + + if &modified + let l:spawn_args.input = stdin_content + endif + + call go#util#EchoProgress("searching declaration ...") + + call s:def_job(spawn_args) + return + endif + + let command = join(cmd, " ") + if &modified + let out = go#util#System(command, stdin_content) + else + let out = go#util#System(command) + endif + else + call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru]') + return + endif + + if go#util#ShellError() != 0 + call go#util#EchoError(out) + return + endif + + call go#def#jump_to_declaration(out, a:mode, bin_name) + let $GOPATH = old_gopath +endfunction + +function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort + if a:exit_status != 0 + return + endif + + call go#def#jump_to_declaration(a:data[0], a:mode, a:bin_name) +endfunction + +function! go#def#jump_to_declaration(out, mode, bin_name) abort + let final_out = a:out + if a:bin_name == "godef" + " append the type information to the same line so our we can parse it. + " This makes it compatible with guru output. + let final_out = join(split(a:out, '\n'), ':') + endif + + " strip line ending + let out = split(final_out, go#util#LineEnding())[0] + if go#util#IsWin() + let parts = split(out, '\(^[a-zA-Z]\)\@,:navigate :jump ,q:exit'] + + let i = 0 + while i < len(s:go_stack) + let entry = s:go_stack[i] + let prefix = "" + + if i == s:go_stack_level + let prefix = ">" + else + let prefix = " " + endif + + call add(stackOut, printf("%s %d %s|%d col %d|%s", + \ prefix, i+1, entry["file"], entry["line"], entry["col"], entry["ident"])) + let i += 1 + endwhile + + if s:go_stack_level == i + call add(stackOut, "> ") + endif + + call go#ui#OpenWindow("GoDef Stack", stackOut, "godefstack") + + noremap :call go#def#SelectStackEntry() + noremap :call go#ui#CloseWindow() + noremap q :call go#ui#CloseWindow() +endfunction + +function! go#def#StackClear(...) abort + let s:go_stack = [] + let s:go_stack_level = 0 +endfunction + +function! go#def#StackPop(...) abort + if len(s:go_stack) == 0 + call go#util#EchoError("godef stack empty") + return + endif + + if s:go_stack_level == 0 + call go#util#EchoError("at bottom of the godef stack") + return + endif + + if !len(a:000) + let numPop = 1 + else + let numPop = a:1 + endif + + let newLevel = str2nr(s:go_stack_level) - str2nr(numPop) + call go#def#Stack(newLevel + 1) +endfunction + +function! go#def#Stack(...) abort + if len(s:go_stack) == 0 + call go#util#EchoError("godef stack empty") + return + endif + + if !len(a:000) + " Display interactive stack + call go#def#StackUI() + return + else + let jumpTarget = a:1 + endif + + if jumpTarget !~ '^\d\+$' + if jumpTarget !~ '^\s*$' + call go#util#EchoError("location must be a number") + endif + return + endif + + let jumpTarget = str2nr(jumpTarget) - 1 + + if jumpTarget >= 0 && jumpTarget < len(s:go_stack) + let s:go_stack_level = jumpTarget + let target = s:go_stack[s:go_stack_level] + + " jump + if expand('%:p') != target["file"] + if &modified + exec 'hide edit' target["file"] + else + exec 'edit' target["file"] + endif + endif + call cursor(target["line"], target["col"]) + normal! zz + else + call go#util#EchoError("invalid location. Try :GoDefStack to see the list of valid entries") + endif +endfunction + +function s:def_job(args) abort + function! s:error_info_cb(job, exit_status, data) closure + " do not print anything during async definition search&jump + endfunction + + let a:args.error_info_cb = funcref('s:error_info_cb') + let callbacks = go#job#Spawn(a:args) + + let start_options = { + \ 'callback': callbacks.callback, + \ 'exit_cb': callbacks.exit_cb, + \ } + + if &modified + let l:tmpname = tempname() + call writefile(split(a:args.input, "\n"), l:tmpname, "b") + let l:start_options.in_io = "file" + let l:start_options.in_name = l:tmpname + endif + + call job_start(a:args.cmd, start_options) +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/def_test.vim b/vim/bundle/vim-go/autoload/go/def_test.vim new file mode 100644 index 0000000..a5ed24f --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/def_test.vim @@ -0,0 +1,32 @@ +func Test_jump_to_declaration_guru() + let file_name = "test-fixtures/def/jump.go" + let lnum = 5 + let col = 6 + + let out = printf("%s:%d:%d: defined here as func main", file_name, lnum, col) + let bin_name = "guru" + + call go#def#jump_to_declaration(out, "", bin_name) + + call assert_equal(file_name, bufname("%")) + call assert_equal(lnum, getcurpos()[1]) + call assert_equal(col, getcurpos()[2]) +endfunc + +func Test_jump_to_declaration_godef() + let file_name = "test-fixtures/def/jump.go" + let lnum = 5 + let col = 6 + + " note that the output of godef has two lines + let out = printf("%s:%d:%d\ndefined here as func main", file_name, lnum, col) + let bin_name = "godef" + + call go#def#jump_to_declaration(out, "", bin_name) + + call assert_equal(file_name, bufname("%")) + call assert_equal(lnum, getcurpos()[1]) + call assert_equal(col, getcurpos()[2]) +endfunc + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/doc.vim b/vim/bundle/vim-go/autoload/go/doc.vim new file mode 100644 index 0000000..4ad28d8 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/doc.vim @@ -0,0 +1,224 @@ +" Copyright 2011 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. + +let s:buf_nr = -1 + +if !exists("g:go_doc_command") + let g:go_doc_command = "godoc" +endif + +if !exists("g:go_doc_options") + let g:go_doc_options = "" +endif + +function! go#doc#OpenBrowser(...) abort + " check if we have gogetdoc as it gives us more and accurate information. + " Only supported if we have json_decode as it's not worth to parse the plain + " non-json output of gogetdoc + let bin_path = go#path#CheckBinPath('gogetdoc') + if !empty(bin_path) && exists('*json_decode') + let json_out = s:gogetdoc(1) + if go#util#ShellError() != 0 + call go#util#EchoError(json_out) + return + endif + + let out = json_decode(json_out) + if type(out) != type({}) + call go#util#EchoError("gogetdoc output is malformed") + endif + + let import = out["import"] + let name = out["name"] + let decl = out["decl"] + + let godoc_url = "https://godoc.org/" . import + if decl !~ "^package" + let godoc_url .= "#" . name + endif + + echo godoc_url + + call go#tool#OpenBrowser(godoc_url) + return + endif + + let pkgs = s:godocWord(a:000) + if empty(pkgs) + return + endif + + let pkg = pkgs[0] + let exported_name = pkgs[1] + + " example url: https://godoc.org/github.com/fatih/set#Set + let godoc_url = "https://godoc.org/" . pkg . "#" . exported_name + call go#tool#OpenBrowser(godoc_url) +endfunction + +function! go#doc#Open(newmode, mode, ...) abort + if len(a:000) + " check if we have 'godoc' and use it automatically + let bin_path = go#path#CheckBinPath('godoc') + if empty(bin_path) + return + endif + + let command = printf("%s %s", bin_path, join(a:000, ' ')) + let out = go#util#System(command) + else + let out = s:gogetdoc(0) + endif + + if go#util#ShellError() != 0 + call go#util#EchoError(out) + return + endif + + call s:GodocView(a:newmode, a:mode, out) +endfunction + +function! s:GodocView(newposition, position, content) abort + " reuse existing buffer window if it exists otherwise create a new one + if !bufexists(s:buf_nr) + execute a:newposition + sil file `="[Godoc]"` + let s:buf_nr = bufnr('%') + elseif bufwinnr(s:buf_nr) == -1 + execute a:position + execute s:buf_nr . 'buffer' + elseif bufwinnr(s:buf_nr) != bufwinnr('%') + execute bufwinnr(s:buf_nr) . 'wincmd w' + endif + + if a:position == "split" + " cap buffer height to 20, but resize it for smaller contents + let max_height = 20 + let content_height = len(split(a:content, "\n")) + if content_height > max_height + exe 'resize ' . max_height + else + exe 'resize ' . content_height + endif + else + " set a sane maximum width for vertical splits. In this case the minimum + " that fits the godoc for package http without extra linebreaks and line + " numbers on + exe 'vertical resize 84' + endif + + setlocal filetype=godoc + setlocal bufhidden=delete + setlocal buftype=nofile + setlocal noswapfile + setlocal nobuflisted + setlocal nocursorline + setlocal nocursorcolumn + setlocal iskeyword+=: + setlocal iskeyword-=- + + setlocal modifiable + %delete _ + call append(0, split(a:content, "\n")) + sil $delete _ + setlocal nomodifiable + sil normal! gg + + " close easily with or enter + noremap :close + noremap :close +endfunction + +function! s:gogetdoc(json) abort + " check if we have 'gogetdoc' and use it automatically + let bin_path = go#path#CheckBinPath('gogetdoc') + if empty(bin_path) + return -1 + endif + + let cmd = [bin_path] + + let offset = go#util#OffsetCursor() + let fname = expand("%:p:gs!\\!/!") + let pos = shellescape(fname.':#'.offset) + + let cmd += ["-pos", pos] + if a:json + let cmd += ["-json"] + endif + + let command = join(cmd, " ") + + if &modified + " gogetdoc supports the same archive format as guru for dealing with + " modified buffers. + " use the -modified flag + " write each archive entry on stdin as: + " filename followed by newline + " file size followed by newline + " file contents + let in = "" + let content = join(go#util#GetLines(), "\n") + let in = fname . "\n" . strlen(content) . "\n" . content + let command .= " -modified" + let out = go#util#System(command, in) + else + let out = go#util#System(command) + endif + + return out +endfunction + +" returns the package and exported name. exported name might be empty. +" ie: fmt and Println +" ie: github.com/fatih/set and New +function! s:godocWord(args) abort + if !executable('godoc') + let msg = "godoc command not found." + let msg .= " install with: go get golang.org/x/tools/cmd/godoc" + call go#util#EchoWarning(msg) + return [] + endif + + if !len(a:args) + let oldiskeyword = &iskeyword + setlocal iskeyword+=. + let word = expand('') + let &iskeyword = oldiskeyword + let word = substitute(word, '[^a-zA-Z0-9\\/._~-]', '', 'g') + let words = split(word, '\.\ze[^./]\+$') + else + let words = a:args + endif + + if !len(words) + return [] + endif + + let pkg = words[0] + if len(words) == 1 + let exported_name = "" + else + let exported_name = words[1] + endif + + let packages = go#tool#Imports() + + if has_key(packages, pkg) + let pkg = packages[pkg] + endif + + return [pkg, exported_name] +endfunction + +function! s:godocNotFound(content) abort + if len(a:content) == 0 + return 1 + endif + + return a:content =~# '^.*: no such file or directory\n$' +endfunction + + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/fmt.vim b/vim/bundle/vim-go/autoload/go/fmt.vim new file mode 100644 index 0000000..edddb4b --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/fmt.vim @@ -0,0 +1,247 @@ +" Copyright 2011 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. +" +" fmt.vim: Vim command to format Go files with gofmt (and gofmt compatible +" toorls, such as goimports). + +if !exists("g:go_fmt_command") + let g:go_fmt_command = "gofmt" +endif + +if !exists("g:go_goimports_bin") + let g:go_goimports_bin = "goimports" +endif + +if !exists('g:go_fmt_fail_silently') + let g:go_fmt_fail_silently = 0 +endif + +if !exists('g:go_fmt_options') + let g:go_fmt_options = '' +endif + +if !exists("g:go_fmt_experimental") + let g:go_fmt_experimental = 0 +endif + +" we have those problems : +" http://stackoverflow.com/questions/12741977/prevent-vim-from-updating-its-undo-tree +" http://stackoverflow.com/questions/18532692/golang-formatter-and-vim-how-to-destroy-history-record?rq=1 +" +" The below function is an improved version that aims to fix all problems. +" it doesn't undo changes and break undo history. If you are here reading +" this and have VimL experience, please look at the function for +" improvements, patches are welcome :) +function! go#fmt#Format(withGoimport) abort + if g:go_fmt_experimental == 1 + " Using winsaveview to save/restore cursor state has the problem of + " closing folds on save: + " https://github.com/fatih/vim-go/issues/502 + " One fix is to use mkview instead. Unfortunately, this sometimes causes + " other bad side effects: + " https://github.com/fatih/vim-go/issues/728 + " and still closes all folds if foldlevel>0: + " https://github.com/fatih/vim-go/issues/732 + let l:curw = {} + try + mkview! + catch + let l:curw = winsaveview() + endtry + + " save our undo file to be restored after we are done. This is needed to + " prevent an additional undo jump due to BufWritePre auto command and also + " restore 'redo' history because it's getting being destroyed every + " BufWritePre + let tmpundofile = tempname() + exe 'wundo! ' . tmpundofile + else + " Save cursor position and many other things. + let l:curw = winsaveview() + endif + + " Write current unsaved buffer to a temp file + let l:tmpname = tempname() + call writefile(go#util#GetLines(), l:tmpname) + if go#util#IsWin() + let l:tmpname = tr(l:tmpname, '\', '/') + endif + + let bin_name = g:go_fmt_command + if a:withGoimport == 1 + let bin_name = g:go_goimports_bin + endif + + let out = go#fmt#run(bin_name, l:tmpname, expand('%')) + if go#util#ShellError() == 0 + call go#fmt#update_file(l:tmpname, expand('%')) + elseif g:go_fmt_fail_silently == 0 + let errors = s:parse_errors(expand('%'), out) + call s:show_errors(errors) + endif + + " We didn't use the temp file, so clean up + call delete(l:tmpname) + + if g:go_fmt_experimental == 1 + " restore our undo history + silent! exe 'rundo ' . tmpundofile + call delete(tmpundofile) + + " Restore our cursor/windows positions, folds, etc. + if empty(l:curw) + silent! loadview + else + call winrestview(l:curw) + endif + else + " Restore our cursor/windows positions. + call winrestview(l:curw) + endif +endfunction + +" update_file updates the target file with the given formatted source +function! go#fmt#update_file(source, target) + " remove undo point caused via BufWritePre + try | silent undojoin | catch | endtry + + let old_fileformat = &fileformat + if exists("*getfperm") + " save file permissions + let original_fperm = getfperm(a:target) + endif + + call rename(a:source, a:target) + + " restore file permissions + if exists("*setfperm") && original_fperm != '' + call setfperm(a:target , original_fperm) + endif + + " reload buffer to reflect latest changes + silent! edit! + + let &fileformat = old_fileformat + let &syntax = &syntax + + " clean up previous location list + let l:listtype = "locationlist" + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) +endfunction + +" run runs the gofmt/goimport command for the given source file and returns +" the the output of the executed command. Target is the real file to be +" formated. +function! go#fmt#run(bin_name, source, target) + let cmd = s:fmt_cmd(a:bin_name, a:source, a:target) + if empty(cmd) + return + endif + + if cmd[0] == "goimports" + " change GOPATH too, so goimports can pick up the correct library + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + endif + + let command = join(cmd, " ") + + " execute our command... + let out = go#util#System(command) + + if cmd[0] == "goimports" + let $GOPATH = old_gopath + endif + + return out +endfunction + +" fmt_cmd returns a dict that contains the command to execute gofmt (or +" goimports). args is dict with +function! s:fmt_cmd(bin_name, source, target) + " check if the user has installed command binary. + " For example if it's goimports, let us check if it's installed, + " if not the user get's a warning via go#path#CheckBinPath() + let bin_path = go#path#CheckBinPath(a:bin_name) + if empty(bin_path) + return [] + endif + + " start constructing the command + let cmd = [bin_path] + call add(cmd, "-w") + call extend(cmd, split(g:go_fmt_options, " ")) + + if a:bin_name == "goimports" + " lazy check if goimports support `-srcdir`. We should eventually remove + " this in the future + if !exists('b:goimports_vendor_compatible') + let out = go#util#System(bin_path . " --help") + if out !~ "-srcdir" + call go#util#EchoWarning(printf("vim-go: goimports (%s) does not support srcdir. Update with: :GoUpdateBinaries", , bin_path)) + else + let b:goimports_vendor_compatible = 1 + endif + endif + + if exists('b:goimports_vendor_compatible') && b:goimports_vendor_compatible + let ssl_save = &shellslash + set noshellslash + call extend(cmd, ["-srcdir", shellescape(fnamemodify(a:target, ":p"))]) + let &shellslash = ssl_save + endif + endif + + call add(cmd, a:source) + return cmd +endfunction + +" parse_errors parses the given errors and returns a list of parsed errors +function! s:parse_errors(filename, content) abort + let splitted = split(a:content, '\n') + + " list of errors to be put into location list + let errors = [] + 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 + +" show_errors opens a location list and shows the given errors. If the given +" errors is empty, it closes the the location list +function! s:show_errors(errors) abort + let l:listtype = "locationlist" + if !empty(a:errors) + call go#list#Populate(l:listtype, a:errors, 'Format') + echohl Error | echomsg "Gofmt returned error" | echohl None + endif + + " this closes the window if there are no errors or it opens + " it if there is any + call go#list#Window(l:listtype, len(a:errors)) +endfunction + +function! go#fmt#ToggleFmtAutoSave() abort + if get(g:, "go_fmt_autosave", 1) + let g:go_fmt_autosave = 0 + call go#util#EchoProgress("auto fmt disabled") + return + end + + let g:go_fmt_autosave = 1 + call go#util#EchoProgress("auto fmt enabled") +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/fmt_test.vim b/vim/bundle/vim-go/autoload/go/fmt_test.vim new file mode 100644 index 0000000..0de2933 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/fmt_test.vim @@ -0,0 +1,31 @@ +func Test_run_fmt() + let actual_file = tempname() + call writefile(readfile("test-fixtures/fmt/hello.go"), actual_file) + + let expected = join(readfile("test-fixtures/fmt/hello_golden.go"), "\n") + + " run our code + call go#fmt#run("gofmt", actual_file, "test-fixtures/fmt/hello.go") + + " this should now contain the formatted code + let actual = join(readfile(actual_file), "\n") + + call assert_equal(expected, actual) +endfunc + +func Test_update_file() + let expected = join(readfile("test-fixtures/fmt/hello_golden.go"), "\n") + let source_file = tempname() + call writefile(readfile("test-fixtures/fmt/hello_golden.go"), source_file) + + let target_file = tempname() + call writefile([""], target_file) + + " update_file now + call go#fmt#update_file(source_file, target_file) + + " this should now contain the formatted code + let actual = join(readfile(target_file), "\n") + + call assert_equal(expected, actual) +endfunc diff --git a/vim/bundle/vim-go/autoload/go/guru.vim b/vim/bundle/vim-go/autoload/go/guru.vim new file mode 100644 index 0000000..5cff49d --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/guru.vim @@ -0,0 +1,614 @@ +" guru.vim -- Vim integration for the Go guru. + +" guru_cmd returns a dict that contains the command to execute guru. args +" is dict with following options: +" mode : guru mode, such as 'implements' +" format : output format, either 'plain' or 'json' +" needs_scope : if 1, adds the current package to the scope +" selected : if 1, means it's a range of selection, otherwise it picks up the +" offset under the cursor +" example output: +" {'cmd' : ['guru', '-json', 'implements', 'demo/demo.go:#66']} +function! s:guru_cmd(args) range abort + let mode = a:args.mode + let format = a:args.format + let needs_scope = a:args.needs_scope + let selected = a:args.selected + + let result = {} + let dirname = expand('%:p:h') + let pkg = go#package#ImportPath(dirname) + + " this is important, check it! + if pkg == -1 && needs_scope + return {'err': "current directory is not inside of a valid GOPATH"} + endif + + "return with a warning if the binary doesn't exist + let bin_path = go#path#CheckBinPath("guru") + if empty(bin_path) + return {'err': "bin path not found"} + endif + + " start constructing the command + let cmd = [bin_path] + + let filename = fnamemodify(expand("%"), ':p:gs?\\?/?') + if &modified + let content = join(go#util#GetLines(), "\n") + let result.stdin_content = filename . "\n" . strlen(content) . "\n" . content + call add(cmd, "-modified") + endif + + " enable outputting in json format + if format == "json" + call add(cmd, "-json") + endif + + " check for any tags + if exists('g:go_build_tags') + let tags = get(g:, 'go_build_tags') + call extend(cmd, ["-tags", tags]) + let result.tags = tags + endif + + " some modes require scope to be defined (such as callers). For these we + " choose a sensible setting, which is using the current file's package + let scopes = [] + if needs_scope + let scopes = [pkg] + endif + + " check for any user defined scope setting. users can define the scope, + " in package pattern form. examples: + " golang.org/x/tools/cmd/guru # a single package + " golang.org/x/tools/... # all packages beneath dir + " ... # the entire workspace. + if exists('g:go_guru_scope') + " check that the setting is of type list + if type(get(g:, 'go_guru_scope')) != type([]) + return {'err' : "go_guru_scope should of type list"} + endif + + let scopes = get(g:, 'go_guru_scope') + endif + + " now add the scope to our command if there is any + if !empty(scopes) + " strip trailing slashes for each path in scoped. bug: + " https://github.com/golang/go/issues/14584 + let scopes = go#util#StripTrailingSlash(scopes) + + " create shell-safe entries of the list + if !go#util#has_job() | let scopes = go#util#Shelllist(scopes) | endif + + " guru expect a comma-separated list of patterns, construct it + let l:scope = join(scopes, ",") + let result.scope = l:scope + call extend(cmd, ["-scope", l:scope]) + endif + + let pos = printf("#%s", go#util#OffsetCursor()) + if selected != -1 + " means we have a range, get it + let pos1 = go#util#Offset(line("'<"), col("'<")) + let pos2 = go#util#Offset(line("'>"), col("'>")) + let pos = printf("#%s,#%s", pos1, pos2) + endif + + let filename .= ':'.pos + call extend(cmd, [mode, filename]) + + let result.cmd = cmd + return result +endfunction + +" sync_guru runs guru in sync mode with the given arguments +function! s:sync_guru(args) abort + let result = s:guru_cmd(a:args) + if has_key(result, 'err') + call go#util#EchoError(result.err) + return -1 + endif + + if !has_key(a:args, 'disable_progress') + if a:args.needs_scope + call go#util#EchoProgress("analysing with scope ". result.scope . " ...") + elseif a:args.mode !=# 'what' + " the query might take time, let us give some feedback + call go#util#EchoProgress("analysing ...") + endif + endif + + + " run, forrest run!!! + let command = join(result.cmd, " ") + if has_key(result, 'stdin_content') + let out = go#util#System(command, result.stdin_content) + else + let out = go#util#System(command) + endif + + if has_key(a:args, 'custom_parse') + call a:args.custom_parse(go#util#ShellError(), out) + else + call s:parse_guru_output(go#util#ShellError(), out, a:args.mode) + endif + + return out +endfunc + +" async_guru runs guru in async mode with the given arguments +function! s:async_guru(args) abort + let result = s:guru_cmd(a:args) + if has_key(result, 'err') + call go#util#EchoError(result.err) + return + endif + + let status_dir = expand('%:p:h') + let statusline_type = printf("%s", a:args.mode) + + if !has_key(a:args, 'disable_progress') + if a:args.needs_scope + call go#util#EchoProgress("analysing with scope ". result.scope . " ...") + endif + endif + + let messages = [] + function! s:callback(chan, msg) closure + call add(messages, a:msg) + endfunction + + function! s:exit_cb(job, exitval) closure + let out = join(messages, "\n") + + let status = { + \ 'desc': 'last status', + \ 'type': statusline_type, + \ 'state': "finished", + \ } + + if a:exitval + let status.state = "failed" + endif + + call go#statusline#Update(status_dir, status) + + if has_key(a:args, 'custom_parse') + call a:args.custom_parse(a:exitval, out) + else + call s:parse_guru_output(a:exitval, out, a:args.mode) + endif + endfunction + + let start_options = { + \ 'callback': funcref("s:callback"), + \ 'exit_cb': funcref("s:exit_cb"), + \ } + + if has_key(result, 'stdin_content') + let l:tmpname = tempname() + call writefile(split(result.stdin_content, "\n"), l:tmpname, "b") + let l:start_options.in_io = "file" + let l:start_options.in_name = l:tmpname + endif + + call go#statusline#Update(status_dir, { + \ 'desc': "current status", + \ 'type': statusline_type, + \ 'state': "analysing", + \}) + + return job_start(result.cmd, start_options) +endfunc + +" run_guru runs the given guru argument +function! s:run_guru(args) abort + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + if go#util#has_job() + let res = s:async_guru(a:args) + else + let res = s:sync_guru(a:args) + endif + + let $GOPATH = old_gopath + + return res +endfunction + +" Show 'implements' relation for selected package +function! go#guru#Implements(selected) abort + let args = { + \ 'mode': 'implements', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 1, + \ } + + call s:run_guru(args) +endfunction + +" Report the possible constants, global variables, and concrete types that may +" appear in a value of type error +function! go#guru#Whicherrs(selected) abort + let args = { + \ 'mode': 'whicherrs', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 1, + \ } + + + " TODO(arslan): handle empty case for both sync/async + " if empty(out.out) + " call go#util#EchoSuccess("no error variables found. Try to change the scope with :GoGuruScope") + " return + " endif + call s:run_guru(args) +endfunction + +" Describe selected syntax: definition, methods, etc +function! go#guru#Describe(selected) abort + let args = { + \ 'mode': 'describe', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 1, + \ } + + call s:run_guru(args) +endfunction + +function! go#guru#DescribeInfo() abort + " json_encode() and friends are introduced with this patch (7.4.1304) + " vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ + " nvim: https://github.com/neovim/neovim/pull/4131 + if !exists("*json_decode") + call go#util#EchoError("requires 'json_decode'. Update your Vim/Neovim version.") + return + endif + + function! s:info(exit_val, output) + if a:exit_val != 0 + return + endif + + if a:output[0] !=# '{' + return + endif + + if empty(a:output) || type(a:output) != type("") + return + endif + + let result = json_decode(a:output) + if type(result) != type({}) + call go#util#EchoError(printf("malformed output from guru: %s", a:output)) + return + endif + + if !has_key(result, 'detail') + " if there is no detail check if there is a description and print it + if has_key(result, "desc") + call go#util#EchoInfo(result["desc"]) + return + endif + + call go#util#EchoError("detail key is missing. Please open a bug report on vim-go repo.") + return + endif + + let detail = result['detail'] + let info = "" + + " guru gives different information based on the detail mode. Let try to + " extract the most useful information + + if detail == "value" + if !has_key(result, 'value') + call go#util#EchoError("value key is missing. Please open a bug report on vim-go repo.") + return + endif + + let val = result["value"] + if !has_key(val, 'type') + call go#util#EchoError("type key is missing (value.type). Please open a bug report on vim-go repo.") + return + endif + + let info = val["type"] + elseif detail == "type" + if !has_key(result, 'type') + call go#util#EchoError("type key is missing. Please open a bug report on vim-go repo.") + return + endif + + let type = result["type"] + if !has_key(type, 'type') + call go#util#EchoError("type key is missing (type.type). Please open a bug report on vim-go repo.") + return + endif + + let info = type["type"] + elseif detail == "package" + if !has_key(result, 'package') + call go#util#EchoError("package key is missing. Please open a bug report on vim-go repo.") + return + endif + + let package = result["package"] + if !has_key(package, 'path') + call go#util#EchoError("path key is missing (package.path). Please open a bug report on vim-go repo.") + return + endif + + let info = printf("package %s", package["path"]) + elseif detail == "unknown" + let info = result["desc"] + else + call go#util#EchoError(printf("unknown detail mode found '%s'. Please open a bug report on vim-go repo", detail)) + return + endif + + call go#util#EchoInfo(info) + endfunction + + let args = { + \ 'mode': 'describe', + \ 'format': 'json', + \ 'selected': -1, + \ 'needs_scope': 1, + \ 'custom_parse': function('s:info'), + \ 'disable_progress': 1, + \ } + + call s:run_guru(args) +endfunction + +" Show possible targets of selected function call +function! go#guru#Callees(selected) abort + let args = { + \ 'mode': 'callees', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 1, + \ } + + call s:run_guru(args) +endfunction + +" Show possible callers of selected function +function! go#guru#Callers(selected) abort + let args = { + \ 'mode': 'callers', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 1, + \ } + + call s:run_guru(args) +endfunction + +" Show path from callgraph root to selected function +function! go#guru#Callstack(selected) abort + let args = { + \ 'mode': 'callstack', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 1, + \ } + + call s:run_guru(args) +endfunction + +" Show free variables of selection +function! go#guru#Freevars(selected) abort + " Freevars requires a selection + if a:selected == -1 + call go#util#EchoError("GoFreevars requires a selection (range) of code") + return + endif + + let args = { + \ 'mode': 'freevars', + \ 'format': 'plain', + \ 'selected': 1, + \ 'needs_scope': 0, + \ } + + call s:run_guru(args) +endfunction + +" Show send/receive corresponding to selected channel op +function! go#guru#ChannelPeers(selected) abort + let args = { + \ 'mode': 'peers', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 1, + \ } + + call s:run_guru(args) +endfunction + +" Show all refs to entity denoted by selected identifier +function! go#guru#Referrers(selected) abort + let args = { + \ 'mode': 'referrers', + \ 'format': 'plain', + \ 'selected': a:selected, + \ 'needs_scope': 0, + \ } + + call s:run_guru(args) +endfunction + +function! go#guru#SameIdsTimer() abort + call timer_start(200, function('go#guru#SameIds'), {'repeat': -1}) +endfunction + +function! go#guru#SameIds() 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 + if !exists("*matchaddpos") + call go#util#EchoError("GoSameIds requires 'matchaddpos'. Update your Vim/Neovim version.") + return + endif + + " json_encode() and friends are introduced with this patch (7.4.1304) + " vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ + " nvim: https://github.com/neovim/neovim/pull/4131 + if !exists("*json_decode") + call go#util#EchoError("GoSameIds requires 'json_decode'. Update your Vim/Neovim version.") + return + endif + + let args = { + \ 'mode': 'what', + \ 'format': 'json', + \ 'selected': -1, + \ 'needs_scope': 0, + \ 'custom_parse': function('s:same_ids_highlight'), + \ } + + call s:run_guru(args) +endfunction + +function! s:same_ids_highlight(exit_val, output) abort + call go#guru#ClearSameIds() " run after calling guru to reduce flicker. + + if a:output[0] !=# '{' + if !get(g:, 'go_auto_sameids', 0) + call go#util#EchoError(a:output) + endif + return + endif + + let result = json_decode(a:output) + if type(result) != type({}) && !get(g:, 'go_auto_sameids', 0) + call go#util#EchoError("malformed output from guru") + return + endif + + if !has_key(result, 'sameids') + if !get(g:, 'go_auto_sameids', 0) + call go#util#EchoError("no same_ids founds for the given identifier") + endif + return + endif + + let poslen = 0 + for enclosing in result['enclosing'] + if enclosing['desc'] == 'identifier' + let poslen = enclosing['end'] - enclosing['start'] + break + endif + endfor + + " return when there's no identifier to highlight. + if poslen == 0 + return + endif + + let same_ids = result['sameids'] + " highlight the lines + for item in same_ids + let pos = split(item, ':') + call matchaddpos('goSameId', [[str2nr(pos[-2]), str2nr(pos[-1]), str2nr(poslen)]]) + endfor + + if get(g:, "go_auto_sameids", 0) + " re-apply SameIds at the current cursor position at the time the buffer + " is redisplayed: e.g. :edit, :GoRename, etc. + autocmd BufWinEnter nested call go#guru#SameIds() + endif +endfunction + +function! go#guru#ClearSameIds() abort + let m = getmatches() + for item in m + if item['group'] == 'goSameId' + call matchdelete(item['id']) + endif + endfor + + " remove the autocmds we defined + if exists("#BufWinEnter#") + autocmd! BufWinEnter + endif +endfunction + +function! go#guru#ToggleSameIds() abort + if len(getmatches()) != 0 + call go#guru#ClearSameIds() + else + call go#guru#SameIds() + endif +endfunction + +function! go#guru#AutoToogleSameIds() abort + if get(g:, "go_auto_sameids", 0) + call go#util#EchoProgress("sameids auto highlighting disabled") + call go#guru#ClearSameIds() + let g:go_auto_sameids = 0 + return + endif + + call go#util#EchoSuccess("sameids auto highlighting enabled") + let g:go_auto_sameids = 1 +endfunction + + +"""""""""""""""""""""""""""""""""""""""" +"" HELPER FUNCTIONS +"""""""""""""""""""""""""""""""""""""""" + +" This uses Vim's errorformat to parse the output from Guru's 'plain output +" and put it into location list. I believe using errorformat is much more +" easier to use. If we need more power we can always switch back to parse it +" via regex. Match two possible styles of errorformats: +" +" 'file:line.col-line2.col2: message' +" 'file:line:col: message' +" +" We discard line2 and col2 for the first errorformat, because it's not +" useful and location only has the ability to show one line and column +" number +function! s:parse_guru_output(exit_val, output, title) abort + if a:exit_val + call go#util#EchoError(a:output) + return + endif + + let old_errorformat = &errorformat + let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m" + call go#list#ParseFormat("locationlist", errformat, a:output, a:title) + let &errorformat = old_errorformat + + let errors = go#list#Get("locationlist") + call go#list#Window("locationlist", len(errors)) +endfun + +function! go#guru#Scope(...) abort + if a:0 + if a:0 == 1 && a:1 == '""' + unlet g:go_guru_scope + call go#util#EchoSuccess("guru scope is cleared") + else + let g:go_guru_scope = a:000 + call go#util#EchoSuccess("guru scope changed to: ". join(a:000, ",")) + endif + + return + endif + + if !exists('g:go_guru_scope') + call go#util#EchoError("guru scope is not set") + else + call go#util#EchoSuccess("current guru scope: ". join(g:go_guru_scope, ",")) + endif +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/impl.vim b/vim/bundle/vim-go/autoload/go/impl.vim new file mode 100644 index 0000000..a4b696d --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/impl.vim @@ -0,0 +1,126 @@ +function! go#impl#Impl(...) abort + let binpath = go#path#CheckBinPath('impl') + if empty(binpath) + return + endif + + let recv = "" + let iface = "" + + if a:0 == 0 + " user didn't passed anything, just called ':GoImpl' + let receiveType = expand("") + let recv = printf("%s *%s", tolower(receiveType)[0], receiveType) + let iface = input("vim-go: generating method stubs for interface: ") + redraw! + if empty(iface) + call go#util#EchoError('usage: interface type is not provided') + return + endif + elseif a:0 == 1 + " we assume the user only passed the interface type, + " i.e: ':GoImpl io.Writer' + let receiveType = expand("") + let recv = printf("%s *%s", tolower(receiveType)[0], receiveType) + let iface = a:1 + elseif a:0 > 2 + " user passed receiver and interface type both, + " i.e: 'GoImpl f *Foo io.Writer' + let recv = join(a:000[:-2], ' ') + let iface = a:000[-1] + else + call go#util#EchoError('usage: GoImpl {receiver} {interface}') + return + endif + + let result = go#util#System(printf("%s '%s' '%s'", binpath, recv, iface)) + if go#util#ShellError() != 0 + call go#util#EchoError(result) + return + endif + + if result ==# '' + return + end + + let pos = getpos('.') + put ='' + put =result + call setpos('.', pos) +endfunction + +if exists('*uniq') + function! s:uniq(list) + return uniq(a:list) + endfunction +else + " Note: Believe that the list is sorted + function! s:uniq(list) + let i = len(a:list) - 1 + while 0 < i + if a:list[i-1] ==# a:list[i] + call remove(a:list, i) + let i -= 2 + else + let i -= 1 + endif + endwhile + return a:list + endfunction +endif + +function! s:root_dirs() abort + let dirs = [] + let root = go#util#goroot() + if root !=# '' && isdirectory(root) + call add(dirs, root) + endif + + let paths = map(split(go#util#gopath(), go#util#PathListSep()), "substitute(v:val, '\\\\', '/', 'g')") + if go#util#ShellError() + return [] + endif + + if !empty(filter(paths, 'isdirectory(v:val)')) + call extend(dirs, paths) + endif + + return dirs +endfunction + +function! s:go_packages(dirs) abort + let pkgs = [] + for d in a:dirs + let pkg_root = expand(d . '/pkg/' . go#util#osarch()) + call extend(pkgs, split(globpath(pkg_root, '**/*.a', 1), "\n")) + endfor + return map(pkgs, "fnamemodify(v:val, ':t:r')") +endfunction + +function! s:interface_list(pkg) abort + let contents = split(go#util#System('go doc ' . a:pkg), "\n") + if go#util#ShellError() + return [] + endif + + call filter(contents, 'v:val =~# ''^type\s\+\h\w*\s\+interface''') + return map(contents, 'a:pkg . "." . matchstr(v:val, ''^type\s\+\zs\h\w*\ze\s\+interface'')') +endfunction + +" Complete package and interface for {interface} +function! go#impl#Complete(arglead, cmdline, cursorpos) abort + let words = split(a:cmdline, '\s\+', 1) + if words[-1] ==# '' + return s:uniq(sort(s:go_packages(s:root_dirs()))) + elseif words[-1] =~# '^\h\w*$' + return s:uniq(sort(filter(s:go_packages(s:root_dirs()), 'stridx(v:val, words[-1]) == 0'))) + elseif words[-1] =~# '^\h\w*\.\%(\h\w*\)\=$' + let [pkg, interface] = split(words[-1], '\.', 1) + echomsg pkg + return s:uniq(sort(filter(s:interface_list(pkg), 'v:val =~? words[-1]'))) + else + return [] + endif +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/import.vim b/vim/bundle/vim-go/autoload/go/import.vim new file mode 100644 index 0000000..8d9e8d4 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/import.vim @@ -0,0 +1,213 @@ +" Copyright 2011 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. +" +" Check out the docs for more information at /doc/vim-go.txt +" +function! go#import#SwitchImport(enabled, localname, path, bang) abort + let view = winsaveview() + let path = substitute(a:path, '^\s*\(.\{-}\)\s*$', '\1', '') + + " Quotes are not necessary, so remove them if provided. + if path[0] == '"' + let path = strpart(path, 1) + endif + if path[len(path)-1] == '"' + let path = strpart(path, 0, len(path) - 1) + endif + + " if given a trailing slash, eg. `github.com/user/pkg/`, remove it + if path[len(path)-1] == '/' + let path = strpart(path, 0, len(path) - 1) + endif + + if path == '' + call s:Error('Import path not provided') + return + endif + + if a:bang == "!" + let out = go#util#System("go get -u -v ".shellescape(path)) + if go#util#ShellError() != 0 + call s:Error("Can't find import: " . path . ":" . out) + endif + endif + let exists = go#tool#Exists(path) + if exists == -1 + call s:Error("Can't find import: " . path) + return + endif + + " Extract any site prefix (e.g. github.com/). + " If other imports with the same prefix are grouped separately, + " we will add this new import with them. + " Only up to and including the first slash is used. + let siteprefix = matchstr(path, "^[^/]*/") + + let qpath = '"' . path . '"' + if a:localname != '' + let qlocalpath = a:localname . ' ' . qpath + else + let qlocalpath = qpath + endif + let indentstr = 0 + let packageline = -1 " Position of package name statement + let appendline = -1 " Position to introduce new import + let deleteline = -1 " Position of line with existing import + let linesdelta = 0 " Lines added/removed + + " Find proper place to add/remove import. + let line = 0 + while line <= line('$') + let linestr = getline(line) + + if linestr =~# '^package\s' + let packageline = line + let appendline = line + + elseif linestr =~# '^import\s\+(' + let appendstr = qlocalpath + let indentstr = 1 + let appendline = line + let firstblank = -1 + let lastprefix = "" + while line <= line("$") + let line = line + 1 + let linestr = getline(line) + let m = matchlist(getline(line), '^\()\|\(\s\+\)\(\S*\s*\)"\(.\+\)"\)') + if empty(m) + if siteprefix == "" && a:enabled + " must be in the first group + break + endif + " record this position, but keep looking + if firstblank < 0 + let firstblank = line + endif + continue + endif + if m[1] == ')' + " if there's no match, add it to the first group + if appendline < 0 && firstblank >= 0 + let appendline = firstblank + endif + break + endif + let lastprefix = matchstr(m[4], "^[^/]*/") + if a:localname != '' && m[3] != '' + let qlocalpath = printf('%-' . (len(m[3])-1) . 's %s', a:localname, qpath) + endif + let appendstr = m[2] . qlocalpath + let indentstr = 0 + if m[4] == path + let appendline = -1 + let deleteline = line + break + elseif m[4] < path + " don't set candidate position if we have a site prefix, + " we've passed a blank line, and this doesn't share the same + " site prefix. + if siteprefix == "" || firstblank < 0 || match(m[4], "^" . siteprefix) >= 0 + let appendline = line + endif + elseif siteprefix != "" && match(m[4], "^" . siteprefix) >= 0 + " first entry of site group + let appendline = line - 1 + break + endif + endwhile + break + + elseif linestr =~# '^import ' + if appendline == packageline + let appendstr = 'import ' . qlocalpath + let appendline = line - 1 + endif + let m = matchlist(linestr, '^import\(\s\+\)\(\S*\s*\)"\(.\+\)"') + if !empty(m) + if m[3] == path + let appendline = -1 + let deleteline = line + break + endif + if m[3] < path + let appendline = line + endif + if a:localname != '' && m[2] != '' + let qlocalpath = printf("%s %" . len(m[2])-1 . "s", a:localname, qpath) + endif + let appendstr = 'import' . m[1] . qlocalpath + endif + + elseif linestr =~# '^\(var\|const\|type\|func\)\>' + break + + endif + let line = line + 1 + endwhile + + " Append or remove the package import, as requested. + if a:enabled + if deleteline != -1 + call s:Error(qpath . ' already being imported') + elseif appendline == -1 + call s:Error('No package line found') + else + if appendline == packageline + call append(appendline + 0, '') + call append(appendline + 1, 'import (') + call append(appendline + 2, ')') + let appendline += 2 + let linesdelta += 3 + let appendstr = qlocalpath + let indentstr = 1 + endif + call append(appendline, appendstr) + execute appendline + 1 + if indentstr + execute 'normal! >>' + endif + let linesdelta += 1 + endif + else + if deleteline == -1 + call s:Error(qpath . ' not being imported') + else + execute deleteline . 'd' + let linesdelta -= 1 + + if getline(deleteline-1) =~# '^import\s\+(' && getline(deleteline) =~# '^)' + " Delete empty import block + let deleteline -= 1 + execute deleteline . "d" + execute deleteline . "d" + let linesdelta -= 2 + endif + + if getline(deleteline) == '' && getline(deleteline - 1) == '' + " Delete spacing for removed line too. + execute deleteline . "d" + let linesdelta -= 1 + endif + endif + endif + + " Adjust view for any changes. + let view.lnum += linesdelta + let view.topline += linesdelta + if view.topline < 0 + let view.topline = 0 + endif + + " Put buffer back where it was. + call winrestview(view) + +endfunction + + +function! s:Error(s) abort + echohl Error | echo a:s | echohl None +endfunction + + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/job.vim b/vim/bundle/vim-go/autoload/go/job.vim new file mode 100644 index 0000000..6fb03af --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/job.vim @@ -0,0 +1,98 @@ +" Spawn returns callbacks to be used with job_start. It's abstracted to be +" used with various go command, such as build, test, install, etc.. This avoid +" us to write the same callback over and over for some commands. It's fully +" customizable so each command can change it to it's own logic. +function go#job#Spawn(args) + let cbs = { + \ 'winnr': winnr(), + \ 'dir': getcwd(), + \ 'jobdir': fnameescape(expand("%:p:h")), + \ 'messages': [], + \ 'args': a:args.cmd, + \ 'bang': 0, + \ } + + if has_key(a:args, 'bang') + let cbs.bang = a:args.bang + endif + + " add final callback to be called if async job is finished + " The signature should be in form: func(job, exit_status, messages) + if has_key(a:args, 'custom_cb') + let cbs.custom_cb = a:args.custom_cb + endif + + if has_key(a:args, 'error_info_cb') + let cbs.error_info_cb = a:args.error_info_cb + endif + + function cbs.callback(chan, msg) dict + call add(self.messages, a:msg) + endfunction + + function cbs.exit_cb(job, exitval) dict + if has_key(self, 'custom_cb') + call self.custom_cb(a:job, a:exitval, self.messages) + endif + + if has_key(self, 'error_info_cb') + call self.error_info_cb(a:job, a:exitval, self.messages) + endif + + if get(g:, 'go_echo_command_info', 1) + if a:exitval == 0 + call go#util#EchoSuccess("SUCCESS") + else + call go#util#EchoError("FAILED") + endif + endif + + let l:listtype = go#list#Type("quickfix") + if a:exitval == 0 + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + return + endif + + call self.show_errors(l:listtype) + endfunction + + function cbs.show_errors(listtype) dict + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + try + execute cd self.jobdir + let errors = go#tool#ParseErrors(self.messages) + let errors = go#tool#FilterValids(errors) + finally + execute cd . fnameescape(self.dir) + endtry + + if !len(errors) + " failed to parse errors, output the original content + call go#util#EchoError(join(self.messages, " ")) + call go#util#EchoError(self.dir) + return + endif + + if self.winnr == winnr() + call go#list#Populate(a:listtype, errors, join(self.args)) + call go#list#Window(a:listtype, len(errors)) + if !empty(errors) && !self.bang + call go#list#JumpToFirst(a:listtype) + endif + endif + endfunction + + " override callback handler if user provided it + if has_key(a:args, 'callback') + let cbs.callback = a:args.callback + endif + + " override exit callback handler if user provided it + if has_key(a:args, 'exit_cb') + let cbs.exit_cb = a:args.exit_cb + endif + + return cbs +endfunction +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/jobcontrol.vim b/vim/bundle/vim-go/autoload/go/jobcontrol.vim new file mode 100644 index 0000000..d914cb8 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/jobcontrol.vim @@ -0,0 +1,197 @@ +" s:jobs is a global reference to all jobs started with Spawn() or with the +" internal function s:spawn +let s:jobs = {} + +" s:handlers is a global event handlers for all jobs started with Spawn() or +" with the internal function s:spawn +let s:handlers = {} + +" Spawn is a wrapper around s:spawn. It can be executed by other files and +" scripts if needed. Desc defines the description for printing the status +" during the job execution (useful for statusline integration). +function! go#jobcontrol#Spawn(bang, desc, args) abort + " autowrite is not enabled for jobs + call go#cmd#autowrite() + + let job = s:spawn(a:bang, a:desc, a:args) + return job.id +endfunction + +" AddHandler adds a on_exit callback handler and returns the id. +function! go#jobcontrol#AddHandler(handler) abort + let i = len(s:handlers) + while has_key(s:handlers, string(i)) + let i += 1 + break + endwhile + let s:handlers[string(i)] = a:handler + return string(i) +endfunction + +" RemoveHandler removes a callback handler by id. +function! go#jobcontrol#RemoveHandler(id) abort + unlet s:handlers[a:id] +endfunction + +" spawn spawns a go subcommand with the name and arguments with jobstart. Once +" a job is started a reference will be stored inside s:jobs. spawn changes the +" GOPATH when g:go_autodetect_gopath is enabled. The job is started inside the +" current files folder. +function! s:spawn(bang, desc, args) abort + let status_type = a:args[0] + let status_dir = expand('%:p:h') + let started_at = reltime() + + call go#statusline#Update(status_dir, { + \ 'desc': "current status", + \ 'type': status_type, + \ 'state': "started", + \}) + + let job = { + \ 'desc': a:desc, + \ 'bang': a:bang, + \ 'winnr': winnr(), + \ 'importpath': go#package#ImportPath(expand('%:p:h')), + \ 'state': "RUNNING", + \ 'stderr' : [], + \ 'stdout' : [], + \ 'on_stdout': function('s:on_stdout'), + \ 'on_stderr': function('s:on_stderr'), + \ 'on_exit' : function('s:on_exit'), + \ 'status_type' : status_type, + \ 'status_dir' : status_dir, + \ 'started_at' : started_at, + \ } + + " modify GOPATH if needed + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + " execute go build in the files directory + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + + " cleanup previous jobs for this file + for jb in values(s:jobs) + if jb.importpath == job.importpath + unlet s:jobs[jb.id] + endif + endfor + + let dir = getcwd() + let jobdir = fnameescape(expand("%:p:h")) + execute cd . jobdir + + " append the subcommand, such as 'build' + let argv = ['go'] + a:args + + " run, forrest, run! + let id = jobstart(argv, job) + let job.id = id + let job.dir = jobdir + let s:jobs[id] = job + + execute cd . fnameescape(dir) + + " restore back GOPATH + let $GOPATH = old_gopath + + return job +endfunction + +" on_exit is the exit handler for jobstart(). It handles cleaning up the job +" references and also displaying errors in the quickfix window collected by +" on_stderr handler. If there are no errors and a quickfix window is open, +" it'll be closed. +function! s:on_exit(job_id, exit_status, event) dict abort + let status = { + \ 'desc': 'last status', + \ 'type': self.status_type, + \ 'state': "success", + \ } + + if a:exit_status + let status.state = "failed" + endif + + let elapsed_time = reltimestr(reltime(self.started_at)) + " strip whitespace + let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') + let status.state .= printf(" (%ss)", elapsed_time) + + call go#statusline#Update(self.status_dir, status) + + let std_combined = self.stderr + self.stdout + + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + execute cd self.dir + + call s:callback_handlers_on_exit(s:jobs[a:job_id], a:exit_status, std_combined) + + let l:listtype = go#list#Type("quickfix") + if a:exit_status == 0 + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + + let self.state = "SUCCESS" + + if get(g:, 'go_echo_command_info', 1) + call go#util#EchoSuccess("[" . self.status_type . "] SUCCESS") + endif + + execute cd . fnameescape(dir) + return + endif + + let self.state = "FAILED" + + if get(g:, 'go_echo_command_info', 1) + call go#util#EchoError("[" . self.status_type . "] FAILED") + endif + + let errors = go#tool#ParseErrors(std_combined) + let errors = go#tool#FilterValids(errors) + + execute cd . fnameescape(dir) + + if !len(errors) + " failed to parse errors, output the original content + call go#util#EchoError(std_combined[0]) + return + endif + + " if we are still in the same windows show the list + if self.winnr == winnr() + call go#list#Populate(l:listtype, errors, self.desc) + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) && !self.bang + call go#list#JumpToFirst(l:listtype) + endif + endif +endfunction + +" callback_handlers_on_exit runs all handlers for job on exit event. +function! s:callback_handlers_on_exit(job, exit_status, data) abort + if empty(s:handlers) + return + endif + + for s:handler in values(s:handlers) + call s:handler(a:job, a:exit_status, a:data) + endfor +endfunction + +" on_stdout is the stdout handler for jobstart(). It collects the output of +" stderr and stores them to the jobs internal stdout list. +function! s:on_stdout(job_id, data, event) dict abort + call extend(self.stdout, a:data) +endfunction + +" on_stderr is the stderr handler for jobstart(). It collects the output of +" stderr and stores them to the jobs internal stderr list. +function! s:on_stderr(job_id, data, event) dict abort + call extend(self.stderr, a:data) +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/lint.vim b/vim/bundle/vim-go/autoload/go/lint.vim new file mode 100644 index 0000000..cbc7b33 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/lint.vim @@ -0,0 +1,311 @@ +if !exists("g:go_metalinter_command") + let g:go_metalinter_command = "" +endif + +if !exists("g:go_metalinter_autosave_enabled") + let g:go_metalinter_autosave_enabled = ['vet', 'golint'] +endif + +if !exists("g:go_metalinter_enabled") + let g:go_metalinter_enabled = ['vet', 'golint', 'errcheck'] +endif + +if !exists("g:go_metalinter_excludes") + let g:go_metalinter_excludes = [] +endif + +if !exists("g:go_golint_bin") + let g:go_golint_bin = "golint" +endif + +if !exists("g:go_errcheck_bin") + let g:go_errcheck_bin = "errcheck" +endif + +function! go#lint#Gometa(autosave, ...) abort + if a:0 == 0 + let goargs = shellescape(expand('%:p:h')) + else + let goargs = go#util#Shelljoin(a:000) + endif + + let bin_path = go#path#CheckBinPath("gometalinter") + if empty(bin_path) + return + endif + + let cmd = [bin_path] + let cmd += ["--disable-all"] + + if a:autosave || empty(g:go_metalinter_command) + " linters + let linters = a:autosave ? g:go_metalinter_autosave_enabled : g:go_metalinter_enabled + for linter in linters + let cmd += ["--enable=".linter] + endfor + + for exclude in g:go_metalinter_excludes + let cmd += ["--exclude=".exclude] + endfor + + " path + let cmd += [expand('%:p:h')] + else + " the user wants something else, let us use it. + let cmd += split(g:go_metalinter_command, " ") + endif + + " gometalinter has a default deadline of 5 seconds. + " + " For async mode (s:lint_job), we want to override the default deadline only + " if we have a deadline configured. + " + " For sync mode (go#tool#ExecuteInDir), always explicitly pass the 5 seconds + " deadline if there is no other deadline configured. If a deadline is + " configured, then use it. + + " Call gometalinter asynchronously. + if go#util#has_job() && has('lambda') + let deadline = get(g:, 'go_metalinter_deadline', 0) + if deadline != 0 + let cmd += ["--deadline=" . deadline] + endif + + call s:lint_job({'cmd': cmd}) + return + endif + + " We're calling gometalinter synchronously. + + let cmd += ["--deadline=" . get(g:, 'go_metalinter_deadline', "5s")] + + if a:autosave + " include only messages for the active buffer + let cmd += ["--include='^" . expand('%:p') . ".*$'"] + endif + + + let meta_command = join(cmd, " ") + + let out = go#tool#ExecuteInDir(meta_command) + + let l:listtype = "quickfix" + if go#util#ShellError() == 0 + redraw | echo + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None + else + " GoMetaLinter can output one of the two, so we look for both: + " ::[]: () + " ::: () + " This can be defined by the following errorformat: + let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m" + + " Parse and populate our location list + call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter') + + let errors = go#list#Get(l:listtype) + call go#list#Window(l:listtype, len(errors)) + + if !a:autosave + call go#list#JumpToFirst(l:listtype) + endif + endif +endfunction + +" Golint calls 'golint' on the current directory. Any warnings are populated in +" the location list +function! go#lint#Golint(...) abort + let bin_path = go#path#CheckBinPath(g:go_golint_bin) + if empty(bin_path) + return + endif + + if a:0 == 0 + let goargs = shellescape(expand('%')) + else + let goargs = go#util#Shelljoin(a:000) + endif + + let out = go#util#System(bin_path . " " . goargs) + if empty(out) + echon "vim-go: " | echohl Function | echon "[lint] PASS" | echohl None + return + endif + + let l:listtype = "quickfix" + call go#list#Parse(l:listtype, out) + let errors = go#list#Get(l:listtype) + call go#list#Window(l:listtype, len(errors)) + call go#list#JumpToFirst(l:listtype) +endfunction + +" Vet calls 'go vet' on the current directory. Any warnings are populated in +" the location list +function! go#lint#Vet(bang, ...) abort + call go#cmd#autowrite() + echon "vim-go: " | echohl Identifier | echon "calling vet..." | echohl None + if a:0 == 0 + let out = go#tool#ExecuteInDir('go vet') + else + let out = go#tool#ExecuteInDir('go tool vet ' . go#util#Shelljoin(a:000)) + endif + + let l:listtype = "quickfix" + if go#util#ShellError() != 0 + let errors = go#tool#ParseErrors(split(out, '\n')) + call go#list#Populate(l:listtype, errors, 'Vet') + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) && !a:bang + call go#list#JumpToFirst(l:listtype) + endif + echon "vim-go: " | echohl ErrorMsg | echon "[vet] FAIL" | echohl None + else + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + redraw | echon "vim-go: " | echohl Function | echon "[vet] PASS" | echohl None + endif +endfunction + +" ErrCheck calls 'errcheck' for the given packages. Any warnings are populated in +" the location list +function! go#lint#Errcheck(...) abort + if a:0 == 0 + let goargs = go#package#ImportPath(expand('%:p:h')) + if goargs == -1 + echohl Error | echomsg "vim-go: package is not inside GOPATH src" | echohl None + return + endif + else + let goargs = go#util#Shelljoin(a:000) + endif + + let bin_path = go#path#CheckBinPath(g:go_errcheck_bin) + if empty(bin_path) + return + endif + + echon "vim-go: " | echohl Identifier | echon "errcheck analysing ..." | echohl None + redraw + + let command = bin_path . ' -abspath ' . goargs + let out = go#tool#ExecuteInDir(command) + + let l:listtype = "quickfix" + if go#util#ShellError() != 0 + let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m" + + " Parse and populate our location list + call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'Errcheck') + + let errors = go#list#Get(l:listtype) + + if empty(errors) + echohl Error | echomsg "GoErrCheck returned error" | echohl None + echo out + return + endif + + if !empty(errors) + call go#list#Populate(l:listtype, errors, 'Errcheck') + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) + call go#list#JumpToFirst(l:listtype) + endif + endif + else + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + echon "vim-go: " | echohl Function | echon "[errcheck] PASS" | echohl None + endif + +endfunction + +function! go#lint#ToggleMetaLinterAutoSave() abort + if get(g:, "go_metalinter_autosave", 0) + let g:go_metalinter_autosave = 0 + call go#util#EchoProgress("auto metalinter disabled") + return + end + + let g:go_metalinter_autosave = 1 + call go#util#EchoProgress("auto metalinter enabled") +endfunction + +function s:lint_job(args) + let status_dir = expand('%:p:h') + let started_at = reltime() + + call go#statusline#Update(status_dir, { + \ 'desc': "current status", + \ 'type': "gometalinter", + \ 'state': "analysing", + \}) + + " autowrite is not enabled for jobs + call go#cmd#autowrite() + + let l:listtype = go#list#Type("quickfix") + let l:errformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m' + + function! s:callback(chan, msg) closure + let old_errorformat = &errorformat + let &errorformat = l:errformat + caddexpr a:msg + let &errorformat = old_errorformat + + " TODO(arslan): cursor still jumps to first error even If I don't want + " it. Seems like there is a regression somewhere, but not sure where. + copen + endfunction + + function! s:exit_cb(job, exitval) closure + let status = { + \ 'desc': 'last status', + \ 'type': "gometaliner", + \ 'state': "finished", + \ } + + if a:exitval + let status.state = "failed" + endif + + let elapsed_time = reltimestr(reltime(started_at)) + " strip whitespace + let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') + let status.state .= printf(" (%ss)", elapsed_time) + + call go#statusline#Update(status_dir, status) + + let errors = go#list#Get(l:listtype) + if empty(errors) + call go#list#Window(l:listtype, len(errors)) + elseif has("patch-7.4.2200") + if l:listtype == 'quickfix' + call setqflist([], 'a', {'title': 'GoMetaLinter'}) + else + call setloclist(0, [], 'a', {'title': 'GoMetaLinter'}) + endif + endif + + if get(g:, 'go_echo_command_info', 1) + call go#util#EchoSuccess("linting finished") + endif + endfunction + + let start_options = { + \ 'callback': funcref("s:callback"), + \ 'exit_cb': funcref("s:exit_cb"), + \ } + + call job_start(a:args.cmd, start_options) + + call go#list#Clean(l:listtype) + + if get(g:, 'go_echo_command_info', 1) + call go#util#EchoProgress("linting started ...") + endif +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/list.vim b/vim/bundle/vim-go/autoload/go/list.vim new file mode 100644 index 0000000..dbd1e25 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/list.vim @@ -0,0 +1,133 @@ +if !exists("g:go_list_type") + let g:go_list_type = "" +endif + +" Window opens the list with the given height up to 10 lines maximum. +" Otherwise g:go_loclist_height is used. If no or zero height is given it +" closes the window +function! go#list#Window(listtype, ...) abort + let l:listtype = go#list#Type(a:listtype) + " we don't use lwindow to close the location list as we need also the + " ability to resize the window. So, we are going to use lopen and lclose + " for a better user experience. If the number of errors in a current + " location list increases/decreases, cwindow will not resize when a new + " updated height is passed. lopen in the other hand resizes the screen. + if !a:0 || a:1 == 0 + if l:listtype == "locationlist" + lclose + else + cclose + endif + return + endif + + let height = get(g:, "go_list_height", 0) + if height == 0 + " prevent creating a large location height for a large set of numbers + if a:1 > 10 + let height = 10 + else + let height = a:1 + endif + endif + + if l:listtype == "locationlist" + exe 'lopen ' . height + else + exe 'copen ' . height + endif +endfunction + + +" Get returns the current list of items from the location list +function! go#list#Get(listtype) abort + let l:listtype = go#list#Type(a:listtype) + if l:listtype == "locationlist" + return getloclist(0) + else + return getqflist() + endif +endfunction + +" Populate populate the location list with the given items +function! go#list#Populate(listtype, items, title) abort + let l:listtype = go#list#Type(a:listtype) + if l:listtype == "locationlist" + call setloclist(0, a:items, 'r') + + " 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 + call setqflist(a:items, 'r') + if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif + endif +endfunction + +function! go#list#PopulateWin(winnr, items) abort + call setloclist(a:winnr, a:items, 'r') +endfunction + +" Parse parses the given items based on the specified errorformat nad +" populates the location list. +function! go#list#ParseFormat(listtype, errformat, items, title) abort + let l:listtype = go#list#Type(a:listtype) + " backup users errorformat, will be restored once we are finished + let old_errorformat = &errorformat + + " parse and populate the location list + let &errorformat = a:errformat + if l:listtype == "locationlist" + lgetexpr a:items + if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif + else + cgetexpr a:items + if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif + endif + + "restore back + let &errorformat = old_errorformat +endfunction + +" Parse parses the given items based on the global errorformat and +" populates the location list. +function! go#list#Parse(listtype, items) abort + let l:listtype = go#list#Type(a:listtype) + if l:listtype == "locationlist" + lgetexpr a:items + else + cgetexpr a:items + endif +endfunction + +" JumpToFirst jumps to the first item in the location list +function! go#list#JumpToFirst(listtype) abort + let l:listtype = go#list#Type(a:listtype) + if l:listtype == "locationlist" + ll 1 + else + cc 1 + endif +endfunction + +" Clean cleans the location list +function! go#list#Clean(listtype) abort + let l:listtype = go#list#Type(a:listtype) + if l:listtype == "locationlist" + lex [] + else + cex [] + endif +endfunction + +function! go#list#Type(listtype) abort + if g:go_list_type == "locationlist" + return "locationlist" + elseif g:go_list_type == "quickfix" + return "quickfix" + else + return a:listtype + endif +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/package.vim b/vim/bundle/vim-go/autoload/go/package.vim new file mode 100644 index 0000000..b12c7b7 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/package.vim @@ -0,0 +1,165 @@ +" Copyright 2011 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. +" +" This file provides a utility function that performs auto-completion of +" package names, for use by other commands. + +let s:goos = $GOOS +let s:goarch = $GOARCH + +if len(s:goos) == 0 + if exists('g:golang_goos') + let s:goos = g:golang_goos + elseif has('win32') || has('win64') + let s:goos = 'windows' + elseif has('macunix') + let s:goos = 'darwin' + else + let s:goos = '*' + endif +endif + +if len(s:goarch) == 0 + if exists('g:golang_goarch') + let s:goarch = g:golang_goarch + else + let s:goarch = '*' + endif +endif + +function! go#package#Paths() abort + let dirs = [] + + if !exists("s:goroot") + if executable('go') + let s:goroot = go#util#goroot() + if go#util#ShellError() != 0 + echomsg '''go env GOROOT'' failed' + endif + else + let s:goroot = $GOROOT + endif + endif + + if len(s:goroot) != 0 && isdirectory(s:goroot) + let dirs += [s:goroot] + endif + + let workspaces = split(go#path#Detect(), go#util#PathListSep()) + if workspaces != [] + let dirs += workspaces + endif + + return dirs +endfunction + +function! go#package#ImportPath(arg) abort + let path = fnamemodify(resolve(a:arg), ':p') + let dirs = go#package#Paths() + + for dir in dirs + if len(dir) && matchstr(escape(path, '\/'), escape(dir, '\/')) == 0 + let workspace = dir + endif + endfor + + if !exists('workspace') + return -1 + endif + + if go#util#IsWin() + let srcdir = substitute(workspace . '\src\', '//', '/', '') + return path[len(srcdir):] + else + let srcdir = substitute(workspace . '/src/', '//', '/', '') + return substitute(path, srcdir, '', '') + endif +endfunction + +function! go#package#FromPath(arg) abort + let path = fnamemodify(resolve(a:arg), ':p') + let dirs = go#package#Paths() + + for dir in dirs + if len(dir) && match(path, dir) == 0 + let workspace = dir + endif + endfor + + if !exists('workspace') + return -1 + endif + + if isdirectory(path) + return substitute(path, workspace . 'src/', '', '') + else + return substitute(substitute(path, workspace . 'src/', '', ''), + \ '/' . fnamemodify(path, ':t'), '', '') + endif +endfunction + +function! go#package#CompleteMembers(package, member) abort + silent! let content = go#util#System('godoc ' . a:package) + if go#util#ShellError() || !len(content) + return [] + endif + let lines = filter(split(content, "\n"),"v:val !~ '^\\s\\+$'") + try + let mx1 = '^\s\+\(\S+\)\s\+=\s\+.*' + let mx2 = '^\%(const\|var\|type\|func\) \([A-Z][^ (]\+\).*' + let candidates = map(filter(copy(lines), 'v:val =~ mx1'), + \ 'substitute(v:val, mx1, "\\1", "")') + \ + map(filter(copy(lines), 'v:val =~ mx2'), + \ 'substitute(v:val, mx2, "\\1", "")') + return filter(candidates, '!stridx(v:val, a:member)') + catch + return [] + endtry +endfunction + +function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort + let words = split(a:CmdLine, '\s\+', 1) + + " do not complete package members for these commands + let neglect_commands = ["GoImportAs", "GoGuruScope"] + + if len(words) > 2 && index(neglect_commands, words[0]) == -1 + " Complete package members + return go#package#CompleteMembers(words[1], words[2]) + endif + + let dirs = go#package#Paths() + + if len(dirs) == 0 + " should not happen + return [] + endif + + let ret = {} + for dir in dirs + " this may expand to multiple lines + let root = split(expand(dir . '/pkg/' . s:goos . '_' . s:goarch), "\n") + call add(root, expand(dir . '/src')) + for r in root + for i in split(globpath(r, a:ArgLead.'*'), "\n") + if isdirectory(i) + let i .= '/' + elseif i !~ '\.a$' + continue + endif + let i = substitute(substitute(i[len(r)+1:], '[\\]', '/', 'g'), + \ '\.a$', '', 'g') + + " without this the result can have duplicates in form of + " 'encoding/json' and '/encoding/json/' + let i = go#util#StripPathSep(i) + + let ret[i] = i + endfor + endfor + endfor + return sort(keys(ret)) +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/path.vim b/vim/bundle/vim-go/autoload/go/path.vim new file mode 100644 index 0000000..5c1acd9 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/path.vim @@ -0,0 +1,185 @@ +" initial_go_path is used to store the initial GOPATH that was set when Vim +" was started. It's used with :GoPathClear to restore the GOPATH when the user +" changed it explicitly via :GoPath. Initially it's empty. It's being set when +" :GoPath is used +let s:initial_go_path = "" + +" GoPath sets or returns the current GOPATH. If no arguments are passed it +" echoes the current GOPATH, if an argument is passed it replaces the current +" GOPATH with it. If two double quotes are passed (the empty string in go), +" it'll clear the GOPATH and will restore to the initial GOPATH. +function! go#path#GoPath(...) abort + " no argument, show GOPATH + if len(a:000) == 0 + echo go#path#Detect() + return + endif + + " we have an argument, replace GOPATH + " clears the current manually set GOPATH and restores it to the + " initial GOPATH, which was set when Vim was started. + if len(a:000) == 1 && a:1 == '""' + if !empty(s:initial_go_path) + let $GOPATH = s:initial_go_path + let s:initial_go_path = "" + endif + + echon "vim-go: " | echohl Function | echon "GOPATH restored to ". $GOPATH | echohl None + return + endif + + echon "vim-go: " | echohl Function | echon "GOPATH changed to ". a:1 | echohl None + let s:initial_go_path = $GOPATH + let $GOPATH = a:1 +endfunction + +" Default returns the default GOPATH. If there is a single GOPATH it returns +" it. For multiple GOPATHS separated with a the OS specific separator, only +" the first one is returned. If GOPATH is not set, it uses the default GOPATH +" set starting with GO 1.8. This GOPATH can be retrieved via 'go env GOPATH' +function! go#path#Default() abort + if $GOPATH == "" + " use default GOPATH via go env + return go#util#gopath() + endif + + let go_paths = split($GOPATH, go#util#PathListSep()) + if len(go_paths) == 1 + return $GOPATH + endif + + return go_paths[0] +endfunction + +" HasPath checks whether the given path exists in GOPATH environment variable +" or not +function! go#path#HasPath(path) abort + let go_paths = split(go#path#Default(), go#util#PathListSep()) + let last_char = strlen(a:path) - 1 + + " check cases of '/foo/bar/' and '/foo/bar' + if a:path[last_char] == go#util#PathSep() + let withSep = a:path + let noSep = strpart(a:path, 0, last_char) + else + let withSep = a:path . go#util#PathSep() + let noSep = a:path + endif + + let hasA = index(go_paths, withSep) != -1 + let hasB = index(go_paths, noSep) != -1 + return hasA || hasB +endfunction + +" Detect returns the current GOPATH. If a package manager is used, such as +" Godeps, GB, it will modify the GOPATH so those directories take precedence +" over the current GOPATH. It also detects diretories whose are outside +" GOPATH. +function! go#path#Detect() abort + let gopath = go#path#Default() + + " don't lookup for godeps if autodetect is disabled. + if !get(g:, "go_autodetect_gopath", 1) + return gopath + endif + + let current_dir = fnameescape(expand('%:p:h')) + + " TODO(arslan): this should be changed so folders or files should be + " fetched from a customizable list. The user should define any new package + " management tool by it's own. + + " src folder outside $GOPATH + let src_root = finddir("src", current_dir .";") + if !empty(src_root) + let src_path = fnamemodify(src_root, ':p:h:h') . go#util#PathSep() + + " gb vendor plugin + " (https://github.com/constabulary/gb/tree/master/cmd/gb-vendor) + let gb_vendor_root = src_path . "vendor" . go#util#PathSep() + if isdirectory(gb_vendor_root) && !go#path#HasPath(gb_vendor_root) + let gopath = gb_vendor_root . go#util#PathListSep() . gopath + endif + + if !go#path#HasPath(src_path) + let gopath = src_path . go#util#PathListSep() . gopath + endif + endif + + " Godeps + let godeps_root = finddir("Godeps", current_dir .";") + if !empty(godeps_root) + let godeps_path = join([fnamemodify(godeps_root, ':p:h:h'), "Godeps", "_workspace" ], go#util#PathSep()) + + if !go#path#HasPath(godeps_path) + let gopath = godeps_path . go#util#PathListSep() . gopath + endif + endif + + " Fix up the case where initial $GOPATH is empty, + " and we end up with a trailing : + let gopath = substitute(gopath, ":$", "", "") + return gopath +endfunction + + +" BinPath returns the binary path of installed go tools. +function! go#path#BinPath() abort + let bin_path = "" + + " check if our global custom path is set, if not check if $GOBIN is set so + " we can use it, otherwise use default GOPATH + if exists("g:go_bin_path") + let bin_path = g:go_bin_path + elseif $GOBIN != "" + let bin_path = $GOBIN + else + " GOPATH (user set or default GO) + let bin_path = expand(go#path#Default() . "/bin/") + endif + + return bin_path +endfunction + +" CheckBinPath checks whether the given binary exists or not and returns the +" path of the binary. It returns an empty string doesn't exists. +function! go#path#CheckBinPath(binpath) abort + " remove whitespaces if user applied something like 'goimports ' + let binpath = substitute(a:binpath, '^\s*\(.\{-}\)\s*$', '\1', '') + " save off original path + let old_path = $PATH + + " check if we have an appropriate bin_path + let go_bin_path = go#path#BinPath() + if !empty(go_bin_path) + " append our GOBIN and GOPATH paths and be sure they can be found there... + " let us search in our GOBIN and GOPATH paths + let $PATH = go_bin_path . go#util#PathListSep() . $PATH + endif + + " if it's in PATH just return it + if executable(binpath) + if exists('*exepath') + let binpath = exepath(binpath) + endif + let $PATH = old_path + return binpath + endif + + " just get the basename + let basename = fnamemodify(binpath, ":t") + if !executable(basename) + + call go#util#EchoError(printf("could not find '%s'. Run :GoInstallBinaries to fix it", basename)) + + " restore back! + let $PATH = old_path + return "" + endif + + let $PATH = old_path + + return go_bin_path . go#util#PathSep() . basename +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/play.vim b/vim/bundle/vim-go/autoload/go/play.vim new file mode 100644 index 0000000..4674d5b --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/play.vim @@ -0,0 +1,93 @@ +if !exists("g:go_play_open_browser") + let g:go_play_open_browser = 1 +endif + + +function! go#play#Share(count, line1, line2) abort + if !executable('curl') + echohl ErrorMsg | echomsg "vim-go: require 'curl' command" | echohl None + return + endif + + let content = join(getline(a:line1, a:line2), "\n") + let share_file = tempname() + call writefile(split(content, "\n"), share_file, "b") + + let command = "curl -s -X POST https://play.golang.org/share --data-binary '@".share_file."'" + let snippet_id = go#util#System(command) + + " we can remove the temp file because it's now posted. + call delete(share_file) + + if go#util#ShellError() != 0 + echo 'A error has occured. Run this command to see what the problem is:' + echo command + return + endif + + let url = "http://play.golang.org/p/".snippet_id + + " copy to clipboard + if has('unix') && !has('xterm_clipboard') && !has('clipboard') + let @" = url + else + let @+ = url + endif + + if g:go_play_open_browser != 0 + call go#tool#OpenBrowser(url) + endif + + echo "vim-go: snippet uploaded: ".url +endfunction + + +function! s:get_visual_content() abort + let save_regcont = @" + let save_regtype = getregtype('"') + silent! normal! gvy + let content = @" + call setreg('"', save_regcont, save_regtype) + return content +endfunction + +" modified version of +" http://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript +" another function that returns the content of visual selection, it's not used +" but might be useful in the future +function! s:get_visual_selection() abort + let [lnum1, col1] = getpos("'<")[1:2] + let [lnum2, col2] = getpos("'>")[1:2] + + " check if the the visual mode is used before + if lnum1 == 0 || lnum2 == 0 || col1 == 0 || col2 == 0 + return + endif + + let lines = getline(lnum1, lnum2) + let lines[-1] = lines[-1][: col2 - (&selection == 'inclusive' ? 1 : 2)] + let lines[0] = lines[0][col1 - 1:] + return join(lines, "\n") +endfunction + +" following two functions are from: https://github.com/mattn/gist-vim +" thanks @mattn +function! s:get_browser_command() abort + let go_play_browser_command = get(g:, 'go_play_browser_command', '') + if go_play_browser_command == '' + if has('win32') || has('win64') + let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%' + elseif has('mac') || has('macunix') || has('gui_macvim') || go#util#System('uname') =~? '^darwin' + let go_play_browser_command = 'open %URL%' + elseif executable('xdg-open') + let go_play_browser_command = 'xdg-open %URL%' + elseif executable('firefox') + let go_play_browser_command = 'firefox %URL% &' + else + let go_play_browser_command = '' + endif + endif + return go_play_browser_command +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/rename.vim b/vim/bundle/vim-go/autoload/go/rename.vim new file mode 100644 index 0000000..3ca47d5 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/rename.vim @@ -0,0 +1,149 @@ +if !exists("g:go_gorename_bin") + let g:go_gorename_bin = "gorename" +endif + +if !exists("g:go_gorename_prefill") + let g:go_gorename_prefill = 1 +endif + +function! go#rename#Rename(bang, ...) abort + let to_identifier = "" + if a:0 == 0 + let from = expand("") + let ask = printf("vim-go: rename '%s' to: ", from) + if g:go_gorename_prefill + let to_identifier = input(ask, from) + else + let to_identifier = input(ask) + endif + redraw! + if empty(to_identifier) + return + endif + else + let to_identifier = a:1 + endif + + "return with a warning if the bin doesn't exist + let bin_path = go#path#CheckBinPath(g:go_gorename_bin) + if empty(bin_path) + return + endif + + let fname = expand('%:p') + let pos = go#util#OffsetCursor() + let offset = printf('%s:#%d', fname, pos) + + " no need to escape for job call + let bin_path = go#util#has_job() ? bin_path : shellescape(bin_path) + let offset = go#util#has_job() ? offset : shellescape(offset) + let to_identifier = go#util#has_job() ? to_identifier : shellescape(to_identifier) + + let cmd = [bin_path, "-offset", offset, "-to", to_identifier] + + " check for any tags + if exists('g:go_build_tags') + let tags = get(g:, 'go_build_tags') + call extend(cmd, ["-tags", tags]) + endif + + if go#util#has_job() + call go#util#EchoProgress(printf("renaming to '%s' ...", to_identifier)) + call s:rename_job({ + \ 'cmd': cmd, + \ 'bang': a:bang, + \}) + return + endif + + let command = join(cmd, " ") + let out = go#tool#ExecuteInDir(command) + + let splitted = split(out, '\n') + call s:parse_errors(go#util#ShellError(), a:bang, splitted) +endfunction + +function s:rename_job(args) + let messages = [] + function! s:callback(chan, msg) closure + call add(messages, a:msg) + endfunction + + let status_dir = expand('%:p:h') + + function! s:exit_cb(job, exitval) closure + let status = { + \ 'desc': 'last status', + \ 'type': "gorename", + \ 'state': "finished", + \ } + + if a:exitval + let status.state = "failed" + endif + + call go#statusline#Update(status_dir, status) + + call s:parse_errors(a:exitval, a:args.bang, messages) + endfunction + + let start_options = { + \ 'callback': funcref("s:callback"), + \ 'exit_cb': funcref("s:exit_cb"), + \ } + + " modify GOPATH if needed + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + call go#statusline#Update(status_dir, { + \ 'desc': "current status", + \ 'type': "gorename", + \ 'state': "started", + \}) + + call job_start(a:args.cmd, start_options) + + let $GOPATH = old_gopath +endfunction + +function s:parse_errors(exit_val, bang, out) + " reload all files to reflect the new changes. We explicitly call + " checktime to trigger a reload of all files. See + " http://www.mail-archive.com/vim@vim.org/msg05900.html for more info + " about the autoread bug + let current_autoread = &autoread + set autoread + silent! checktime + let &autoread = current_autoread + + let l:listtype = "quickfix" + if a:exit_val != 0 + call go#util#EchoError("FAILED") + let errors = go#tool#ParseErrors(a:out) + call go#list#Populate(l:listtype, errors, 'Rename') + call go#list#Window(l:listtype, len(errors)) + if !empty(errors) && !a:bang + call go#list#JumpToFirst(l:listtype) + elseif empty(errors) + " failed to parse errors, output the original content + call go#util#EchoError(join(a:out, "")) + endif + + return + endif + + " strip out newline on the end that gorename puts. If we don't remove, it + " will trigger the 'Hit ENTER to continue' prompt + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + call go#util#EchoSuccess(a:out[0]) + + " refresh the buffer so we can see the new content + " TODO(arslan): also find all other buffers and refresh them too. For this + " we need a way to get the list of changes from gorename upon an success + " change. + silent execute ":e" +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/statusline.vim b/vim/bundle/vim-go/autoload/go/statusline.vim new file mode 100644 index 0000000..ba63c6d --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/statusline.vim @@ -0,0 +1,112 @@ +" Statusline +"""""""""""""""""""""""""""""""" + +" s:statuses is a global reference to all statuses. It stores the statuses per +" import paths (map[string]status), where each status is unique per its +" type. Current status dict is in form: +" { +" 'desc' : 'Job description', +" 'state' : 'Job state, such as success, failure, etc..', +" 'type' : 'Job type, such as build, test, etc..' +" 'created_at' : 'Time it was created as seconds since 1st Jan 1970' +" } +let s:statuses = {} + +" timer_id for cleaner +let s:timer_id = 0 + +" last_status stores the last generated text per status +let s:last_status = "" + +" Show returns the current status of the job for 20 seconds (configurable). It +" displays it in form of 'desc: [type|state]' if there is any state available, +" if not it returns an empty string. This function should be plugged directly +" into the statusline. +function! go#statusline#Show() abort + " lazy initialiation of the cleaner + if !s:timer_id + " clean every 60 seconds all statuses + let interval = get(g:, 'go_statusline_duration', 60000) + let s:timer_id = timer_start(interval, function('go#statusline#Clear'), {'repeat': -1}) + endif + + " nothing to show + if empty(s:statuses) + return '' + endif + + let status_dir = expand('%:p:h') + + if !has_key(s:statuses, status_dir) + return '' + endif + + let status = s:statuses[status_dir] + if !has_key(status, 'desc') || !has_key(status, 'state') || !has_key(status, 'type') + return '' + endif + + let status_text = printf("[%s|%s]", status.type, status.state) + if empty(status_text) + return '' + endif + + " only update highlight if status has changed. + if status_text != s:last_status + if status.state =~ "success" || status.state =~ "finished" + hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22 + elseif status.state =~ "started" || status.state =~ "analysing" + hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 + elseif status.state =~ "failed" + hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52 + endif + endif + + let s:last_status = status_text + return status_text +endfunction + +" Update updates (adds) the statusline for the given status_dir with the +" given status dict. It overrides any previously set status. +function! go#statusline#Update(status_dir, status) abort + let a:status.created_at = reltime() + let s:statuses[a:status_dir] = a:status + + " force to update the statusline, otherwise the user needs to move the + " cursor + exe 'let &ro = &ro' + + " 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 + " and thus old jobs will never be cleaned + call go#statusline#Clear(0) + + " 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. + call timer_stop(s:timer_id) + let s:timer_id = 0 +endfunction + +" 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. +function! go#statusline#Clear(timer_id) abort + for [status_dir, status] in items(s:statuses) + let elapsed_time = reltimestr(reltime(status.created_at)) + " strip whitespace + let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') + + if str2nr(elapsed_time) > 10 + call remove(s:statuses, status_dir) + endif + endfor + + if len(s:statuses) == 0 + let s:statuses = {} + endif + + " force to update the statusline, otherwise the user needs to move the + " cursor + exe 'let &ro = &ro' +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/tags.vim b/vim/bundle/vim-go/autoload/go/tags.vim new file mode 100644 index 0000000..4ef7d28 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/tags.vim @@ -0,0 +1,206 @@ +function! go#tags#Add(start, end, count, ...) abort + let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') + if &modified + " Write current unsaved buffer to a temp file and use the modified content + let l:tmpname = tempname() + call writefile(getline(1, '$'), l:tmpname) + let fname = l:tmpname + endif + + let offset = 0 + if a:count == -1 + let offset = go#util#OffsetCursor() + endif + + let test_mode = 0 + call call("go#tags#run", [a:start, a:end, offset, "add", fname, test_mode] + a:000) + + " if exists, delete it as we don't need it anymore + if exists("l:tmpname") + call delete(l:tmpname) + endif +endfunction + +function! go#tags#Remove(start, end, count, ...) abort + let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') + if &modified + " Write current unsaved buffer to a temp file and use the modified content + let l:tmpname = tempname() + call writefile(getline(1, '$'), l:tmpname) + let fname = l:tmpname + endif + + let offset = 0 + if a:count == -1 + let offset = go#util#OffsetCursor() + endif + + let test_mode = 0 + call call("go#tags#run", [a:start, a:end, offset, "remove", fname, test_mode] + a:000) + + " if exists, delete it as we don't need it anymore + if exists("l:tmpname") + call delete(l:tmpname) + endif +endfunction + +" run runs gomodifytag. This is an internal test so we can test it +function! go#tags#run(start, end, offset, mode, fname, test_mode, ...) abort + " do not split this into multiple lines, somehow tests fail in that case + let args = {'mode': a:mode,'start': a:start,'end': a:end,'offset': a:offset,'fname': a:fname,'cmd_args': a:000} + + let result = s:create_cmd(args) + if has_key(result, 'err') + call go#util#EchoError(result.err) + return -1 + endif + + let command = join(result.cmd, " ") + + call go#cmd#autowrite() + let out = go#util#System(command) + if go#util#ShellError() != 0 + call go#util#EchoError(out) + return + endif + + if a:test_mode + exe 'edit ' . a:fname + endif + + call s:write_out(out) + + if a:test_mode + exe 'write! ' . a:fname + endif +endfunc + + +" write_out writes back the given output to the current buffer +func s:write_out(out) abort + " not a json output + if a:out[0] !=# '{' + return + endif + + " nothing to do + if empty(a:out) || type(a:out) != type("") + return + endif + + let result = json_decode(a:out) + if type(result) != type({}) + call go#util#EchoError(printf("malformed output from gomodifytags: %s", a:out)) + return + endif + + let lines = result['lines'] + let start_line = result['start'] + let end_line = result['end'] + + let index = 0 + for line in range(start_line, end_line) + call setline(line, lines[index]) + let index += 1 + endfor +endfunc + + +" create_cmd returns a dict that contains the command to execute gomodifytags +func s:create_cmd(args) abort + if !exists("*json_decode") + return {'err': "requires 'json_decode'. Update your Vim/Neovim version."} + endif + + let bin_path = go#path#CheckBinPath('gomodifytags') + if empty(bin_path) + return {'err': "gomodifytags does not exist"} + endif + + let l:start = a:args.start + let l:end = a:args.end + let l:offset = a:args.offset + let l:mode = a:args.mode + let l:cmd_args = a:args.cmd_args + + " start constructing the command + let cmd = [bin_path] + call extend(cmd, ["-format", "json"]) + call extend(cmd, ["-file", a:args.fname]) + + if l:offset != 0 + call extend(cmd, ["-offset", l:offset]) + else + let range = printf("%d,%d", l:start, l:end) + call extend(cmd, ["-line", range]) + endif + + if l:mode == "add" + let l:tags = [] + let l:options = [] + + if !empty(l:cmd_args) + for item in l:cmd_args + let splitted = split(item, ",") + + " tag only + if len(splitted) == 1 + call add(l:tags, splitted[0]) + endif + + " options only + if len(splitted) == 2 + call add(l:tags, splitted[0]) + call add(l:options, printf("%s=%s", splitted[0], splitted[1])) + endif + endfor + endif + + " construct options + if !empty(l:options) + call extend(cmd, ["-add-options", join(l:options, ",")]) + else + " default value + if empty(l:tags) + let l:tags = ["json"] + endif + + " construct tags + call extend(cmd, ["-add-tags", join(l:tags, ",")]) + endif + elseif l:mode == "remove" + if empty(l:cmd_args) + call add(cmd, "-clear-tags") + else + let l:tags = [] + let l:options = [] + for item in l:cmd_args + let splitted = split(item, ",") + + " tag only + if len(splitted) == 1 + call add(l:tags, splitted[0]) + endif + + " options only + if len(splitted) == 2 + call add(l:options, printf("%s=%s", splitted[0], splitted[1])) + endif + endfor + + " construct tags + if !empty(l:tags) + call extend(cmd, ["-remove-tags", join(l:tags, ",")]) + endif + + " construct options + if !empty(l:options) + call extend(cmd, ["-remove-options", join(l:options, ",")]) + endif + endif + else + return {'err': printf("unknown mode: %s", l:mode)} + endif + + return {'cmd': cmd} +endfunc diff --git a/vim/bundle/vim-go/autoload/go/tags_test.vim b/vim/bundle/vim-go/autoload/go/tags_test.vim new file mode 100644 index 0000000..9d740c8 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/tags_test.vim @@ -0,0 +1,28 @@ +func Test_add_tags() + let input_file = tempname() + call writefile(readfile("test-fixtures/tags/add_all_input.go"), input_file) + + let expected = join(readfile("test-fixtures/tags/add_all_golden.go"), "\n") + + " run for offset 40, which is inside the struct + call go#tags#run(0, 0, 40, "add", input_file, 1) + + let actual = join(readfile(input_file), "\n") + + call assert_equal(expected, actual) +endfunc + + +func Test_remove_tags() + let input_file = tempname() + call writefile(readfile("test-fixtures/tags/remove_all_input.go"), input_file) + + let expected = join(readfile("test-fixtures/tags/remove_all_golden.go"), "\n") + + " run for offset 40, which is inside the struct + call go#tags#run(0, 0, 40, "remove", input_file, 1) + + let actual = join(readfile(input_file), "\n") + + call assert_equal(expected, actual) +endfunc diff --git a/vim/bundle/vim-go/autoload/go/template.vim b/vim/bundle/vim-go/autoload/go/template.vim new file mode 100644 index 0000000..0a92988 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/template.vim @@ -0,0 +1,50 @@ +let s:current_file = expand("") + +function! go#template#create() abort + let l:go_template_use_pkg = get(g:, 'go_template_use_pkg', 0) + let l:root_dir = fnamemodify(s:current_file, ':h:h:h') + + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + execute cd . fnameescape(expand("%:p:h")) + + let l:package_name = go#tool#PackageName() + + " if we can't figure out any package name(no Go files or non Go package + " files) from the directory create the template or use the cwd + " as the name + if l:package_name == -1 && l:go_template_use_pkg != 1 + let l:template_file = get(g:, 'go_template_file', "hello_world.go") + let l:template_path = go#util#Join(l:root_dir, "templates", l:template_file) + exe '0r ' . fnameescape(l:template_path) + $delete _ + elseif l:package_name == -1 && l:go_template_use_pkg == 1 + " cwd is now the dir of the package + let l:path = fnamemodify(getcwd(), ':t') + let l:content = printf("package %s", l:path) + call append(0, l:content) + $delete _ + else + let l:content = printf("package %s", l:package_name) + call append(0, l:content) + $delete _ + endif + + " Remove the '... [New File]' message line from the command line + echon + + execute cd . fnameescape(dir) +endfunction + +function! go#template#ToggleAutoCreate() abort + if get(g:, "go_template_autocreate", 1) + let g:go_template_autocreate = 0 + call go#util#EchoProgress("auto template create disabled") + return + end + + let g:go_template_autocreate = 1 + call go#util#EchoProgress("auto template create enabled") +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/term.vim b/vim/bundle/vim-go/autoload/go/term.vim new file mode 100644 index 0000000..9404ca9 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/term.vim @@ -0,0 +1,139 @@ +if has('nvim') && !exists("g:go_term_mode") + let g:go_term_mode = 'vsplit' +endif + +" s:jobs is a global reference to all jobs started with new() +let s:jobs = {} + +" 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 +function! go#term#new(bang, cmd) abort + return go#term#newmode(a:bang, a:cmd, g:go_term_mode) +endfunction + +" new creates a new terminal with the given command and window mode. +function! go#term#newmode(bang, cmd, mode) abort + let mode = a:mode + if empty(mode) + let mode = g:go_term_mode + endif + + " modify GOPATH if needed + let old_gopath = $GOPATH + let $GOPATH = go#path#Detect() + + " execute go build in the files directory + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + + execute cd . fnameescape(expand("%:p:h")) + + execute mode.' __go_term__' + + setlocal filetype=goterm + setlocal bufhidden=delete + setlocal winfixheight + setlocal noswapfile + setlocal nobuflisted + + let job = { + \ 'stderr' : [], + \ 'stdout' : [], + \ 'bang' : a:bang, + \ 'on_stdout': function('s:on_stdout'), + \ 'on_stderr': function('s:on_stderr'), + \ 'on_exit' : function('s:on_exit'), + \ } + + let id = termopen(a:cmd, job) + + execute cd . fnameescape(dir) + + " restore back GOPATH + let $GOPATH = old_gopath + + let job.id = id + let job.cmd = a:cmd + startinsert + + " resize new term if needed. + let height = get(g:, 'go_term_height', winheight(0)) + let width = get(g:, 'go_term_width', winwidth(0)) + + " we are careful how to resize. for example it's vertical we don't change + " the height. The below command resizes the buffer + if a:mode == "split" + exe 'resize ' . height + elseif a:mode == "vertical" + exe 'vertical resize ' . width + endif + + " we also need to resize the pty, so there you go... + call jobresize(id, width, height) + + let s:jobs[id] = job + return id +endfunction + +function! s:on_stdout(job_id, data, event) dict abort + if !has_key(s:jobs, a:job_id) + return + endif + let job = s:jobs[a:job_id] + + call extend(job.stdout, a:data) +endfunction + +function! s:on_stderr(job_id, data, event) dict abort + if !has_key(s:jobs, a:job_id) + return + endif + let job = s:jobs[a:job_id] + + call extend(job.stderr, a:data) +endfunction + +function! s:on_exit(job_id, exit_status, event) dict abort + if !has_key(s:jobs, a:job_id) + return + endif + let job = s:jobs[a:job_id] + + let l:listtype = "locationlist" + + " usually there is always output so never branch into this clause + if empty(job.stdout) + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + unlet s:jobs[a:job_id] + return + endif + + let errors = go#tool#ParseErrors(job.stdout) + let errors = go#tool#FilterValids(errors) + + if !empty(errors) + " close terminal we don't need it anymore + close + + call go#list#Populate(l:listtype, errors, job.cmd) + call go#list#Window(l:listtype, len(errors)) + if !self.bang + call go#list#JumpToFirst(l:listtype) + endif + unlet s:jobs[a:job_id] + return + endif + + " tests are passing clean the list and close the list. But we only can + " close them from a normal view, so jump back, close the list and then + " again jump back to the terminal + wincmd p + call go#list#Clean(l:listtype) + call go#list#Window(l:listtype) + wincmd p + + unlet s:jobs[a:job_id] +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/test-fixtures/def/jump.go b/vim/bundle/vim-go/autoload/go/test-fixtures/def/jump.go new file mode 100644 index 0000000..50e8d8d --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/test-fixtures/def/jump.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("vim-go") +} diff --git a/vim/bundle/vim-go/autoload/go/test-fixtures/fmt/hello.go b/vim/bundle/vim-go/autoload/go/test-fixtures/fmt/hello.go new file mode 100644 index 0000000..3be42f6 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/test-fixtures/fmt/hello.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + + func main() { +fmt.Println("vim-go") +} diff --git a/vim/bundle/vim-go/autoload/go/test-fixtures/fmt/hello_golden.go b/vim/bundle/vim-go/autoload/go/test-fixtures/fmt/hello_golden.go new file mode 100644 index 0000000..50e8d8d --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/test-fixtures/fmt/hello_golden.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("vim-go") +} diff --git a/vim/bundle/vim-go/autoload/go/test-fixtures/tags/add_all_golden.go b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/add_all_golden.go new file mode 100644 index 0000000..eaa3e7b --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/add_all_golden.go @@ -0,0 +1,16 @@ +package main + +type Server struct { + Name string `json:"name"` + ID int `json:"id"` + MyHomeAddress string `json:"my_home_address"` + SubDomains []string `json:"sub_domains"` + Empty string `json:"empty"` + Example int64 `json:"example"` + Example2 string `json:"example_2"` + Bar struct { + Four string `json:"four"` + Five string `json:"five"` + } `json:"bar"` + Lala interface{} `json:"lala"` +} diff --git a/vim/bundle/vim-go/autoload/go/test-fixtures/tags/add_all_input.go b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/add_all_input.go new file mode 100644 index 0000000..bfc4d3e --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/add_all_input.go @@ -0,0 +1,16 @@ +package main + +type Server struct { + Name string + ID int + MyHomeAddress string + SubDomains []string + Empty string + Example int64 + Example2 string + Bar struct { + Four string + Five string + } + Lala interface{} +} diff --git a/vim/bundle/vim-go/autoload/go/test-fixtures/tags/remove_all_golden.go b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/remove_all_golden.go new file mode 100644 index 0000000..de57085 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/remove_all_golden.go @@ -0,0 +1,16 @@ +package main + +type Server struct { + Name string + ID int + MyHomeAddress string + SubDomains []string + Empty string + Example int64 + Example2 string + Bar struct { + Four string + Five string + } + Lala interface{} +} diff --git a/vim/bundle/vim-go/autoload/go/test-fixtures/tags/remove_all_input.go b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/remove_all_input.go new file mode 100644 index 0000000..eaa3e7b --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/test-fixtures/tags/remove_all_input.go @@ -0,0 +1,16 @@ +package main + +type Server struct { + Name string `json:"name"` + ID int `json:"id"` + MyHomeAddress string `json:"my_home_address"` + SubDomains []string `json:"sub_domains"` + Empty string `json:"empty"` + Example int64 `json:"example"` + Example2 string `json:"example_2"` + Bar struct { + Four string `json:"four"` + Five string `json:"five"` + } `json:"bar"` + Lala interface{} `json:"lala"` +} diff --git a/vim/bundle/vim-go/autoload/go/textobj.vim b/vim/bundle/vim-go/autoload/go/textobj.vim new file mode 100644 index 0000000..21789dc --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/textobj.vim @@ -0,0 +1,180 @@ +if !exists("g:go_textobj_enabled") + let g:go_textobj_enabled = 1 +endif + +if !exists("g:go_textobj_include_function_doc") + let g:go_textobj_include_function_doc = 1 +endif + +" ( ) motions +" { } motions +" s for sentence +" p for parapgrah +" < > +" t for tag + +function! go#textobj#Function(mode) abort + let offset = go#util#OffsetCursor() + + let fname = shellescape(expand("%:p")) + if &modified + " Write current unsaved buffer to a temp file and use the modified content + let l:tmpname = tempname() + call writefile(go#util#GetLines(), l:tmpname) + let fname = l:tmpname + endif + + let bin_path = go#path#CheckBinPath('motion') + if empty(bin_path) + return + endif + + let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset) + let command .= " -mode enclosing" + + if g:go_textobj_include_function_doc + let command .= " -parse-comments" + endif + + let out = go#util#System(command) + if go#util#ShellError() != 0 + call go#util#EchoError(out) + return + endif + + " if exists, delete it as we don't need it anymore + if exists("l:tmpname") + call delete(l:tmpname) + endif + + " convert our string dict representation into native Vim dictionary type + let result = eval(out) + if type(result) != 4 || !has_key(result, 'fn') + return + endif + + let info = result.fn + + if a:mode == 'a' + " anonymous functions doesn't have associated doc. Also check if the user + " want's to include doc comments for function declarations + if has_key(info, 'doc') && g:go_textobj_include_function_doc + call cursor(info.doc.line, info.doc.col) + else + call cursor(info.func.line, info.func.col) + endif + + normal! v + call cursor(info.rbrace.line, info.rbrace.col) + return + endif + + " rest is inner mode, a:mode == 'i' + + " if the function is a one liner we need to select only that portion + if info.lbrace.line == info.rbrace.line + call cursor(info.lbrace.line, info.lbrace.col+1) + normal! v + call cursor(info.rbrace.line, info.rbrace.col-1) + return + endif + + call cursor(info.lbrace.line+1, 1) + normal! V + call cursor(info.rbrace.line-1, 1) +endfunction + +function! go#textobj#FunctionJump(mode, direction) abort + " get count of the motion. This should be done before all the normal + " expressions below as those reset this value(because they have zero + " count!). We abstract -1 because the index starts from 0 in motion. + let l:cnt = v:count1 - 1 + + " set context mark so we can jump back with '' or `` + normal! m' + + " select already previously selected visual content and continue from there. + " If it's the first time starts with the visual mode. This is needed so + " after selecting something in visual mode, every consecutive motion + " continues. + if a:mode == 'v' + normal! gv + endif + + let offset = go#util#OffsetCursor() + + let fname = shellescape(expand("%:p")) + if &modified + " Write current unsaved buffer to a temp file and use the modified content + let l:tmpname = tempname() + call writefile(go#util#GetLines(), l:tmpname) + let fname = l:tmpname + endif + + let bin_path = go#path#CheckBinPath('motion') + if empty(bin_path) + return + endif + + let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset) + let command .= ' -shift ' . l:cnt + + if a:direction == 'next' + let command .= ' -mode next' + else " 'prev' + let command .= ' -mode prev' + endif + + if g:go_textobj_include_function_doc + let command .= " -parse-comments" + endif + + let out = go#util#System(command) + if go#util#ShellError() != 0 + call go#util#EchoError(out) + return + endif + + " if exists, delete it as we don't need it anymore + if exists("l:tmpname") + call delete(l:tmpname) + endif + + " convert our string dict representation into native Vim dictionary type + let result = eval(out) + if type(result) != 4 || !has_key(result, 'fn') + return + endif + + " we reached the end and there are no functions. The usual [[ or ]] jumps to + " the top or bottom, we'll do the same. + if type(result) == 4 && has_key(result, 'err') && result.err == "no functions found" + if a:direction == 'next' + keepjumps normal! G + else " 'prev' + keepjumps normal! gg + endif + return + endif + + let info = result.fn + + " if we select something ,select all function + if a:mode == 'v' && a:direction == 'next' + keepjumps call cursor(info.rbrace.line, 1) + return + endif + + if a:mode == 'v' && a:direction == 'prev' + if has_key(info, 'doc') && g:go_textobj_include_function_doc + keepjumps call cursor(info.doc.line, 1) + else + keepjumps call cursor(info.func.line, 1) + endif + return + endif + + keepjumps call cursor(info.func.line, 1) +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/tool.vim b/vim/bundle/vim-go/autoload/go/tool.vim new file mode 100644 index 0000000..99577f4 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/tool.vim @@ -0,0 +1,209 @@ +function! go#tool#Files() abort + if go#util#IsWin() + let format = '{{range $f := .GoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}' + else + let format = "{{range $f := .GoFiles}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}" + endif + let command = 'go list -f '.shellescape(format) + let out = go#tool#ExecuteInDir(command) + return split(out, '\n') +endfunction + +function! go#tool#Deps() abort + if go#util#IsWin() + let format = '{{range $f := .Deps}}{{$f}}{{printf \"\n\"}}{{end}}' + else + let format = "{{range $f := .Deps}}{{$f}}\n{{end}}" + endif + let command = 'go list -f '.shellescape(format) + let out = go#tool#ExecuteInDir(command) + return split(out, '\n') +endfunction + +function! go#tool#Imports() abort + let imports = {} + if go#util#IsWin() + let format = '{{range $f := .Imports}}{{$f}}{{printf \"\n\"}}{{end}}' + else + let format = "{{range $f := .Imports}}{{$f}}{{printf \"\\n\"}}{{end}}" + endif + let command = 'go list -f '.shellescape(format) + let out = go#tool#ExecuteInDir(command) + if go#util#ShellError() != 0 + echo out + return imports + endif + + for package_path in split(out, '\n') + let cmd = "go list -f '{{.Name}}' " . shellescape(package_path) + let package_name = substitute(go#tool#ExecuteInDir(cmd), '\n$', '', '') + let imports[package_name] = package_path + endfor + + return imports +endfunction + +function! go#tool#Info(auto) abort + let l:mode = get(g:, 'go_info_mode', 'gocode') + if l:mode == 'gocode' + call go#complete#Info(a:auto) + elseif l:mode == 'guru' + call go#guru#DescribeInfo() + else + call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru]') + endif +endfunction + +function! go#tool#PackageName() abort + let command = "go list -f \"{{.Name}}\"" + let out = go#tool#ExecuteInDir(command) + if go#util#ShellError() != 0 + return -1 + endif + + return split(out, '\n')[0] +endfunction + +function! go#tool#ParseErrors(lines) abort + let errors = [] + + for line in a:lines + let fatalerrors = matchlist(line, '^\(fatal error:.*\)$') + let tokens = matchlist(line, '^\s*\(.\{-}\):\(\d\+\):\s*\(.*\)') + + if !empty(fatalerrors) + call add(errors, {"text": fatalerrors[1]}) + elseif !empty(tokens) + " strip endlines of form ^M + let out = substitute(tokens[3], '\r$', '', '') + + call add(errors, { + \ "filename" : fnamemodify(tokens[1], ':p'), + \ "lnum" : tokens[2], + \ "text" : out, + \ }) + elseif !empty(errors) + " Preserve indented lines. + " This comes up especially with multi-line test output. + if match(line, '^\s') >= 0 + call add(errors, {"text": line}) + endif + endif + endfor + + return errors +endfunction + +"FilterValids filters the given items with only items that have a valid +"filename. Any non valid filename is filtered out. +function! go#tool#FilterValids(items) abort + " Remove any nonvalid filename from the location list to avoid opening an + " empty buffer. See https://github.com/fatih/vim-go/issues/287 for + " details. + let filtered = [] + let is_readable = {} + + for item in a:items + if has_key(item, 'bufnr') + let filename = bufname(item.bufnr) + elseif has_key(item, 'filename') + let filename = item.filename + else + " nothing to do, add item back to the list + call add(filtered, item) + continue + endif + + if !has_key(is_readable, filename) + let is_readable[filename] = filereadable(filename) + endif + if is_readable[filename] + call add(filtered, item) + endif + endfor + + for k in keys(filter(is_readable, '!v:val')) + echo "vim-go: " | echohl Identifier | echon "[run] Dropped " | echohl Constant | echon '"' . k . '"' + echohl Identifier | echon " from location list (nonvalid filename)" | echohl None + endfor + + return filtered +endfunction + +function! go#tool#ExecuteInDir(cmd) abort + let old_gopath = $GOPATH + let old_goroot = $GOROOT + let $GOPATH = go#path#Detect() + let $GOROOT = go#util#env("goroot") + + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' + let dir = getcwd() + try + execute cd . fnameescape(expand("%:p:h")) + let out = go#util#System(a:cmd) + finally + execute cd . fnameescape(dir) + endtry + + let $GOROOT = old_goroot + let $GOPATH = old_gopath + return out +endfunction + +" Exists checks whether the given importpath exists or not. It returns 0 if +" the importpath exists under GOPATH. +function! go#tool#Exists(importpath) abort + let command = "go list ". a:importpath + let out = go#tool#ExecuteInDir(command) + + if go#util#ShellError() != 0 + return -1 + endif + + return 0 +endfunction + + +" following two functions are from: https://github.com/mattn/gist-vim +" thanks @mattn +function! s:get_browser_command() abort + let go_play_browser_command = get(g:, 'go_play_browser_command', '') + if go_play_browser_command == '' + if go#util#IsWin() + let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%' + elseif has('mac') || has('macunix') || has('gui_macvim') || go#util#System('uname') =~? '^darwin' + let go_play_browser_command = 'open %URL%' + elseif executable('xdg-open') + let go_play_browser_command = 'xdg-open %URL%' + elseif executable('firefox') + let go_play_browser_command = 'firefox %URL% &' + else + let go_play_browser_command = '' + endif + endif + return go_play_browser_command +endfunction + +function! go#tool#OpenBrowser(url) abort + let cmd = s:get_browser_command() + if len(cmd) == 0 + redraw + echohl WarningMsg + echo "It seems that you don't have general web browser. Open URL below." + echohl None + echo a:url + return + endif + if cmd =~ '^!' + let cmd = substitute(cmd, '%URL%', '\=escape(shellescape(a:url),"#")', 'g') + silent! exec cmd + elseif cmd =~ '^:[A-Z]' + let cmd = substitute(cmd, '%URL%', '\=escape(a:url,"#")', 'g') + exec cmd + else + let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g') + call go#util#System(cmd) + endif +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/ui.vim b/vim/bundle/vim-go/autoload/go/ui.vim new file mode 100644 index 0000000..3f61257 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/ui.vim @@ -0,0 +1,114 @@ +let s:buf_nr = -1 + +"OpenWindow opens a new scratch window and put's the content into the window +function! go#ui#OpenWindow(title, content, filetype) abort + " Ensure there's only one return window in this session/tabpage + call go#util#Windo("unlet! w:vim_go_return_window") + " Mark the window we're leaving as such + let w:vim_go_return_window = 1 + + " reuse existing buffer window if it exists otherwise create a new one + if !bufexists(s:buf_nr) + execute 'botright new' + file `="[" . a:title . "]"` + let s:buf_nr = bufnr('%') + elseif bufwinnr(s:buf_nr) == -1 + execute 'botright new' + execute s:buf_nr . 'buffer' + elseif bufwinnr(s:buf_nr) != bufwinnr('%') + execute bufwinnr(s:buf_nr) . 'wincmd w' + endif + + " Resize window to content length + exe 'resize' . len(a:content) + + execute "setlocal filetype=".a:filetype + + " some sane default values for a readonly buffer + setlocal bufhidden=delete + setlocal buftype=nofile + setlocal noswapfile + setlocal nobuflisted + setlocal winfixheight + setlocal cursorline " make it easy to distinguish + setlocal nonumber + setlocal norelativenumber + setlocal showbreak="" + + " we need this to purge the buffer content + setlocal modifiable + + "delete everything first from the buffer + %delete _ + + " add the content + call append(0, a:content) + + " delete last line that comes from the append call + $delete _ + + " set it back to non modifiable + setlocal nomodifiable + + " Remove the '... [New File]' message line from the command line + echon +endfunction + +function! go#ui#GetReturnWindow() abort + for l:wn in range(1, winnr("$")) + if !empty(getwinvar(l:wn, "vim_go_return_window")) + return l:wn + endif + endfor +endfunction + +" CloseWindow closes the current window +function! go#ui#CloseWindow() abort + " Close any window associated with the ui buffer, if it's there + if bufexists(s:buf_nr) + let ui_window_number = bufwinnr(s:buf_nr) + if ui_window_number != -1 + execute ui_window_number . 'close' + endif + endif + + "return to original window, if it's there + let l:rw = go#ui#GetReturnWindow() + if !empty(l:rw) + execute l:rw . 'wincmd w' + unlet! w:vim_go_return_window + endif +endfunction + +" OpenDefinition parses the current line and jumps to it by openening a new +" tab +function! go#ui#OpenDefinition(filter) abort + let curline = getline('.') + + " don't touch our first line or any blank line + if curline =~ a:filter || curline =~ "^$" + " suppress information about calling this function + echo "" + return + endif + + " format: 'interface file:lnum:coln' + let mx = '^\(^\S*\)\s*\(.\{-}\):\(\d\+\):\(\d\+\)' + + " parse it now into the list + let tokens = matchlist(curline, mx) + + " convert to: 'file:lnum:coln' + let expr = tokens[2] . ":" . tokens[3] . ":" . tokens[4] + + " jump to it in a new tab, we use explicit lgetexpr so we can later change + " the behaviour via settings (like opening in vsplit instead of tab) + lgetexpr expr + tab split + ll 1 + + " center the word + norm! zz +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/autoload/go/util.vim b/vim/bundle/vim-go/autoload/go/util.vim new file mode 100644 index 0000000..86d0726 --- /dev/null +++ b/vim/bundle/vim-go/autoload/go/util.vim @@ -0,0 +1,321 @@ +" PathSep returns the appropriate OS specific path separator. +function! go#util#PathSep() abort + if go#util#IsWin() + return '\' + endif + return '/' +endfunction + +" PathListSep returns the appropriate OS specific path list separator. +function! go#util#PathListSep() abort + if go#util#IsWin() + return ";" + endif + return ":" +endfunction + +" LineEnding returns the correct line ending, based on the current fileformat +function! go#util#LineEnding() abort + if &fileformat == 'dos' + return "\r\n" + elseif &fileformat == 'mac' + return "\r" + endif + + return "\n" +endfunction + +" Join joins any number of path elements into a single path, adding a +" Separator if necessary and returns the result +function! go#util#Join(...) abort + return join(a:000, go#util#PathSep()) +endfunction + +" IsWin returns 1 if current OS is Windows or 0 otherwise +function! go#util#IsWin() abort + let win = ['win16', 'win32', 'win64', 'win95'] + for w in win + if (has(w)) + return 1 + endif + endfor + + return 0 +endfunction + +function! go#util#has_job() abort + " 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 + +let s:env_cache = {} + +" env returns the go environment variable for the given key. Where key can be +" GOARCH, GOOS, GOROOT, etc... It caches the result and returns the cached +" version. +function! go#util#env(key) abort + let l:key = tolower(a:key) + if has_key(s:env_cache, l:key) + return s:env_cache[l:key] + endif + + if executable('go') + let l:var = call('go#util#'.l:key, []) + if go#util#ShellError() != 0 + call go#util#EchoError(printf("'go env %s' failed", toupper(l:key))) + return '' + endif + else + let l:var = eval("$".toupper(a:key)) + endif + + let s:env_cache[l:key] = l:var + return l:var +endfunction + +function! go#util#goarch() abort + return substitute(go#util#System('go env GOARCH'), '\n', '', 'g') +endfunction + +function! go#util#goos() abort + return substitute(go#util#System('go env GOOS'), '\n', '', 'g') +endfunction + +function! go#util#goroot() abort + return substitute(go#util#System('go env GOROOT'), '\n', '', 'g') +endfunction + +function! go#util#gopath() abort + return substitute(go#util#System('go env GOPATH'), '\n', '', 'g') +endfunction + +function! go#util#osarch() abort + return go#util#goos() . '_' . go#util#goarch() +endfunction + +" System runs a shell command. It will reset the shell to /bin/sh for Unix-like +" systems if it is executable. +function! go#util#System(str, ...) abort + let l:shell = &shell + if !go#util#IsWin() && executable('/bin/sh') + let &shell = '/bin/sh' + endif + + try + let l:output = call('system', [a:str] + a:000) + return l:output + finally + let &shell = l:shell + endtry +endfunction + +function! go#util#ShellError() abort + return v:shell_error +endfunction + +" StripPath strips the path's last character if it's a path separator. +" example: '/foo/bar/' -> '/foo/bar' +function! go#util#StripPathSep(path) abort + let last_char = strlen(a:path) - 1 + if a:path[last_char] == go#util#PathSep() + return strpart(a:path, 0, last_char) + endif + + return a:path +endfunction + +" StripTrailingSlash strips the trailing slash from the given path list. +" example: ['/foo/bar/'] -> ['/foo/bar'] +function! go#util#StripTrailingSlash(paths) abort + return map(copy(a:paths), 'go#util#StripPathSep(v:val)') +endfunction + +" Shelljoin returns a shell-safe string representation of arglist. The +" {special} argument of shellescape() may optionally be passed. +function! go#util#Shelljoin(arglist, ...) abort + try + let ssl_save = &shellslash + set noshellslash + if a:0 + return join(map(copy(a:arglist), 'shellescape(v:val, ' . a:1 . ')'), ' ') + endif + + return join(map(copy(a:arglist), 'shellescape(v:val)'), ' ') + finally + let &shellslash = ssl_save + endtry +endfunction + +fu! go#util#Shellescape(arg) + try + let ssl_save = &shellslash + set noshellslash + return shellescape(a:arg) + finally + let &shellslash = ssl_save + endtry +endf + +" Shelllist returns a shell-safe representation of the items in the given +" arglist. The {special} argument of shellescape() may optionally be passed. +function! go#util#Shelllist(arglist, ...) abort + try + let ssl_save = &shellslash + set noshellslash + if a:0 + return map(copy(a:arglist), 'shellescape(v:val, ' . a:1 . ')') + endif + return map(copy(a:arglist), 'shellescape(v:val)') + finally + let &shellslash = ssl_save + endtry +endfunction + +" Returns the byte offset for line and column +function! go#util#Offset(line, col) abort + if &encoding != 'utf-8' + let sep = go#util#LineEnding() + let buf = a:line == 1 ? '' : (join(getline(1, a:line-1), sep) . sep) + let buf .= a:col == 1 ? '' : getline('.')[:a:col-2] + return len(iconv(buf, &encoding, 'utf-8')) + endif + return line2byte(a:line) + (a:col-2) +endfunction +" +" Returns the byte offset for the cursor +function! go#util#OffsetCursor() abort + return go#util#Offset(line('.'), col('.')) +endfunction + +" Windo is like the built-in :windo, only it returns to the window the command +" was issued from +function! go#util#Windo(command) abort + let s:currentWindow = winnr() + try + execute "windo " . a:command + finally + execute s:currentWindow. "wincmd w" + unlet s:currentWindow + endtry +endfunction + +" snippetcase converts the given word to given preferred snippet setting type +" case. +function! go#util#snippetcase(word) abort + let l:snippet_case = get(g:, 'go_snippet_case_type', "snakecase") + if l:snippet_case == "snakecase" + return go#util#snakecase(a:word) + elseif l:snippet_case == "camelcase" + return go#util#camelcase(a:word) + else + return a:word " do nothing + endif +endfunction + +" snakecase converts a string to snake case. i.e: FooBar -> foo_bar +" Copied from tpope/vim-abolish +function! go#util#snakecase(word) abort + let word = substitute(a:word,'::','/','g') + let word = substitute(word,'\(\u\+\)\(\u\l\)','\1_\2','g') + let word = substitute(word,'\(\l\|\d\)\(\u\)','\1_\2','g') + let word = substitute(word,'[.-]','_','g') + let word = tolower(word) + return word +endfunction + +" camelcase converts a string to camel case. i.e: FooBar -> fooBar +" Copied from tpope/vim-abolish +function! go#util#camelcase(word) abort + let word = substitute(a:word, '-', '_', 'g') + if word !~# '_' && word =~# '\l' + return substitute(word,'^.','\l&','') + else + return substitute(word,'\C\(_\)\=\(.\)','\=submatch(1)==""?tolower(submatch(2)) : toupper(submatch(2))','g') + endif +endfunction + +function! go#util#AddTags(line1, line2, ...) abort + " default is json + let l:keys = ["json"] + if a:0 + let l:keys = a:000 + endif + + let l:line1 = a:line1 + let l:line2 = a:line2 + + " If we're inside a struct and just call this function let us add the tags + " to all fields + " TODO(arslan): I don't like using patterns. Check if we can move it to + " `motion` and do it via AST based position + let ln1 = searchpair('struct {', '', '}', 'bcnW') + if ln1 == 0 + echon "vim-go: " | echohl ErrorMsg | echon "cursor is outside the struct" | echohl None + return + endif + + " searchpair only returns a single position + let ln2 = search('}', "cnW") + + " if no range is given we apply for the whole struct + if l:line1 == l:line2 + let l:line1 = ln1 + 1 + let l:line2 = ln2 - 1 + endif + + for line in range(l:line1, l:line2) + " get the field name (word) that are not part of a commented line + let l:matched = matchstr(getline(line), '\(\/\/.*\)\@ +endif + +let s:save_cpo = &cpo +set cpo-=C +if filereadable("makefile") || filereadable("Makefile") + CompilerSet makeprg=make +else + CompilerSet makeprg=go\ build +endif + +" Define the patterns that will be recognized by QuickFix when parsing the +" output of Go command that use this errorforamt (when called make, cexpr or +" lmake, lexpr). This is the global errorformat, however some command might +" use a different output, for those we define them directly and modify the +" errorformat ourselves. More information at: +" http://vimdoc.sourceforge.net/htmldoc/quickfix.html#errorformat +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+=%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:\ %m " Start of multiline unspecified string is 'filename:linenumber:' +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 + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/doc/vim-go.txt b/vim/bundle/vim-go/doc/vim-go.txt new file mode 100644 index 0000000..857924d --- /dev/null +++ b/vim/bundle/vim-go/doc/vim-go.txt @@ -0,0 +1,1670 @@ +*vim-go.txt* Go development plugin +*vim-go* + +============================================================================== +# # +# ## ## #### ## ## ###### ####### # +# ## ## ## ### ### ## ## ## ## # +# ## ## ## #### #### ## ## ## # +# ## ## ## ## ### ## ####### ## #### ## ## # +# ## ## ## ## ## ## ## ## ## # +# ## ## ## ## ## ## ## ## ## # +# ### #### ## ## ###### ####### # +# # +============================================================================== +CONTENTS *go-contents* + + 1. Intro........................................|go-intro| + 2. Install......................................|go-install| + 3. Commands.....................................|go-commands| + 4. Mappings.....................................|go-mappings| + 5. Text Objects.................................|go-text-objects| + 6. Functions....................................|go-functions| + 7. Settings.....................................|go-settings| + 8. FAQ/Troubleshooting..........................|go-troubleshooting| + 9. Development..................................|go-development| + 10. Donation.....................................|go-donation| + 11. Credits......................................|go-credits| + +============================================================================== +INTRO *go-intro* + +Go (golang) support for Vim. vim-go installs automatically all necessary +binaries for providing seamless Vim integration. It comes with pre-defined +sensible settings (like auto gofmt on save), has autocomplete, snippet +support, improved syntax highlighting, go toolchain commands, etc... It's +highly customizable and each individual feature can be disabled/enabled +easily. + + * Improved Syntax highlighting with items such as Functions, Operators, + Methods. + * Auto completion support via `gocode`. + * Better `gofmt` on save, which keeps cursor position and doesn't break your + undo history. + * Go to symbol/declaration with `:GoDef`. + * Look up documentation with `:GoDoc` inside Vim or open it in browser. + * Automatically import packages via `:GoImport` or plug it into autosave. + * Compile your package with `:GoBuild`, install them with `:GoInstall` or + test them with `:GoTest` (also supports running single tests with + `:GoTestFunc`). + * Quickly execute your current file/files with `:GoRun`. + * Automatic `GOPATH` detection based on the directory structure (e.g. `gb` + projects, `godep` vendored projects). + * Change or display `GOPATH` with `:GoPath`. + * Create a coverage profile and display annotated source code in to see + which functions are covered with `:GoCoverage`. + * Call `gometalinter` with `:GoMetaLinter`, which invokes all possible + linters (golint, vet, errcheck, deadcode, etc..) and shows the + warnings/errors. + * Lint your code with `:GoLint`. + * Run your code through `:GoVet` to catch static errors. + * Advanced source analysis tools utilizing guru, such as `:GoImplements`, + `:GoCallees`, and `:GoReferrers`. + * Precise type-safe renaming of identifiers with `:GoRename`. + * List all source files and dependencies. + * Unchecked error checking with `:GoErrCheck`. + * Integrated and improved snippets, supporting `ultisnips` or `neosnippet`. + * Share your current code to [play.golang.org](http://play.golang.org) with + `:GoPlay` + * On-the-fly type information about the word under the cursor. Plug it into + your custom Vim function. + * Go asm formatting on save. + * Tagbar support to show tags of the source code in a sidebar with `gotags`. + * Custom vim text objects such as `a function` or `inner function`. + * A async launcher for the go command is implemented for neovim, fully async + building and testing. + * Integrated with the neovim terminal, launch `:GoRun` and other go commands + in their own new terminal. + * Alternate between implementation and test code with `:GoAlternate`. + +============================================================================== +INSTALL *go-install* + +Vim-go follows the standard runtime path structure, so I highly recommend to +use a common and well known plugin manager to install vim-go. Do not use +vim-go with other Go plugins. For Pathogen just clone the repo, for other +plugin managers add the appropriate lines and execute the plugin's install +command. + +* https://github.com/tpope/vim-pathogen > + + git clone https://github.com/fatih/vim-go.git ~/.vim/bundle/vim-go +< +* https://github.com/junegunn/vim-plug > + + Plug 'fatih/vim-go' + +* https://github.com/Shougo/neobundle.vim > + + NeoBundle 'fatih/vim-go' +< +* https://github.com/gmarik/vundle > + + Plugin 'fatih/vim-go' + +* Vim |packages| +> + git clone https://github.com/fatih/vim-go.git \ + ~/.vim/pack/plugins/start/vim-go +< +* Manual > + + Copy all of the files into your `~/.vim` directory +< + +Please be sure all necessary binaries are installed (such as `gocode`, +`godef`, `goimports`, etc.). You can easily install them with the included +|:GoInstallBinaries| command. If you invoke it, all necessary binaries will be +automatically downloaded and installed to your `$GOBIN` environment (if not +set it will use `$GOPATH/bin`). It requires `git` for fetching the individual +Go packages. + +* Autocompletion is enabled by default via ``, to get real-time +completion (completion by type) install: +https://github.com/Shougo/neocomplete.vim for Vim or +https://github.com/Shougo/deoplete.nvim and +https://github.com/zchee/deoplete-go for Neovim +* To get displayed source code tag informations on a sidebar install +https://github.com/majutsushi/tagbar. +* For snippet feature install: +https://github.com/Shougo/neosnippet.vim or +https://github.com/SirVer/ultisnips. +* For a better documentation viewer check out: + https://github.com/garyburd/go-explorer + +============================================================================== +COMMANDS *go-commands* + + *:GoPath* +:GoPath [path] + + GoPath sets and overrides GOPATH with the given {path}. If no {path} is + given it shows the current GOPATH. If `""` is given as path, it clears + current `GOPATH` which was set with |:GoPath| and restores `GOPATH` back + to the initial value which was sourced when Vim was started. + + *:GoImport* +:GoImport[!] [path] + + Import ensures that the provided package {path} is imported in the current + Go buffer, using proper style and ordering. If {path} is already being + imported, an error will be displayed and the buffer will be untouched. + + If [!] is given it will download the package with `go get` + + *:GoImportAs* +:GoImportAs [localname] [path] + + Same as Import, but uses a custom local name for the package. + + *:GoDrop* +:GoDrop [path] + + Remove the import line for the provided package {path}, if present in the + current Go buffer. If {path} is not being imported, an error will be + displayed and the buffer will be untouched. + + *:GoLint* +:GoLint [packages] + + Run golint for the current Go file, or for given packages. + + *:GoDoc* +:GoDoc [word] + + Open the relevant GoDoc in split window for either the word[s] passed to + the command or by default, the word under the cursor. + + *:GoDocBrowser* +:GoDocBrowser [word] + + Open the relevant GoDoc in browser for either the word[s] passed to the + command or by default, the word under the cursor. + + *:GoFmt* +:GoFmt + + Filter the current Go buffer through gofmt. It tries to preserve cursor + position and avoids replacing the buffer with stderr output. + + *:GoImports* +:GoImports + + Filter the current Go buffer through goimports (needs to be installed). + `goimports` automatically discards/add import path based on the code. Like + |:GoFmt|, It tries to preserve cursor position and avoids replacing the + buffer with stderr output. + + *:GoPlay* +:[range]GoPlay + + Share snippet to play.golang.org. If no [range] is given it shares + the whole file, otherwise the selected lines are shared. Snippet URL + is copied to system clipboard if Vim is compiled with 'clipboard' or + 'xterm-clipboard' otherwise it's get yanked into the `""` register. + + *:GoVet* +:GoVet[!] [options] + + Run `go vet` for the directory under your current file. Vet examines Go + source code and reports suspicious constructs, such as Printf calls whose + arguments do not align with the format string. Vet uses heuristics that do + not guarantee all reports are genuine problems, but it can find errors not + caught by the compilers. + + You may optionally pass any valid go tool vet flags/options. In this case, + `go tool vet` is run in place of `go vet`. For a full list please see + `go tool vet -h`. + + If [!] is not given the first error is jumped to. + + *:GoDef* +:GoDef +gd +CTRL-] + + Goto declaration/definition for the declaration under the cursor. By default + the CTRL-] key and the mapping `gd` are enabled to invoke :GoDef for the + identifier under the cursor. See |'g:go_def_mapping_enabled'| to disable + them. No explicit arguments are supported. + + vim-go also keeps a per-window location stack, roughly analogous to how + Vim's internal |tags| functionality works. This is pushed to every time a + jump is made using the GoDef functionality. In essence, this is a LIFO + list of file locations you have visited with :GoDef that is retained to + help you navigate software. + + *:GoDefStack* +:GoDefStack [number] + + This command Jumps to a given location in the jumpstack, retaining all + other entries. Jumps to non-existent entries will print an informative + message, but are otherwise a noop. + + If no argument is given, it will print out an interactive list of all + items in the stack. Its output looks like this: + + 1 /path/first/file.go|1187 col 16|AddThing func(t *Thing) + > 2 /path/thing/thing.go|624 col 19|String() string + 3 /path/thing/thing.go|744 col 6|func Sprintln(a ...interface{}) string + + This list shows the identifiers that you jumped to and the file and cursor + position before that jump. The older jumps are at the top, the newer at + the bottom. + + The '>' points to the active entry. This entry and any newer entries + below it will be replaced if |:GoDef| is done from this location. The + CTRL-t and |:GoDefPop| command will jump to the position above the active + entry. + + Jumps to non-existent entries will print an informative message, but are + otherwise a noop. + + *:GoDefStackClear* +:GoDefStackClear + + Clears the current stack list and resets it. + + *:GoDefPop* +:GoDefPop [count] +CTRL-t + + Navigate to the [count] earlier entry in the jump stack, retaining the + newer entries. If no argument is given, it will jump to the next most + recent entry (`:GoDefPop 1`). If [count] is greater than the number of + prior entries, an error will be printed and no jump will be performed. + + If you have used :GoDefPop to jump to an earlier location, and you issue + another :GoDef command, the current entry will be replaced, and all newer + entries will be removed, effectively resuming the stack at that location. + + By default [count]CTRL-t is enabled to invoke :GoDefPop. Similarly, + hitting CTRL-t without a prior count is equivalent to `:GoDefPop 1`. See + |'g:go_def_mapping_enabled'| to disable this. + + *:GoRun* +:GoRun[!] [expand] + + Build and run your current main package. By default all main files for the + current file is used. If an argument is passed, [expand] is used as file + selector. For example use `:GoRun %` to select the current file only. + + You may optionally pass any valid go run flags/options. For a full list + please see `go help run`. + + If [!] is not given the first error is jumped to. + + If using neovim then `:GoRun` will run in a new terminal according to + |'g:go_term_mode'|. + + *:GoBuild* +:GoBuild[!] [expand] + + Build your package with `go build`. Errors are populated in the quickfix + window. It automatically builds only the files that depends on the current + file. `:GoBuild` doesn't produce a result file. + Use |:make| to create a result file. + + You may optionally pass any valid go build flags/options. For a full list + please see `go help build`. Options are expanded with [expand]. + + If [!] is not given the first error is jumped to. + + If using neovim then this command is fully async, it does not block the + UI. + + *:GoGenerate* +:GoGenerate[!] [expand] + + Creates or updates your auto-generated source files by running `go + generate`. + + You may optionally pass any valid go generate flags/options. For a full + list please see `go help generate`. Options are expanded with [expand]. + + If [!] is not given the first error is jumped to. + + *:GoInfo* +:GoInfo + Show type information about the identifier under the cursor. For example + putting it above a function call is going to show the full function + signature. By default it uses `gocode` to get the type informations. To + change the underlying tool from `gocode` to another tool, see + |g:go_info_mode|. + + + *:GoInstall* +:GoInstall[!] [options] + + Install your package with `go install`. + + You may optionally pass any valid go install flags/options. For a full + list please see `go help install`. + + If [!] is not given the first error is jumped to. + + *:GoTest* +:GoTest[!] [expand] + + Run the tests on your _test.go files via in your current directory. Errors + are populated in the quickfix window. If an argument is passed, [expand] + is used as file selector (useful for cases like `:GoTest ./...`). + + You may optionally pass any valid go test flags/options. For a full list + please see `go help test`. + + GoTest timesout automatically after 10 seconds. To customize the timeout + use |'g:go_test_timeout'|. This feature is disabled if any arguments are + passed to the `:GoTest` command. + + If [!] is not given the first error is jumped to. + + If using neovim `:GoTest` will run in a new terminal or run asynchronously + in the background according to |'g:go_term_enabled'|. You can set the mode + of the new terminal with |'g:go_term_mode'|. + + *:GoTestFunc* +:GoTestFunc[!] [expand] + + Runs :GoTest, but only on the single test function immediate to your + cursor using 'go test's '-run' flag. + + Lookup is done starting at the cursor (including that line) moving up till + a matching `func Test` pattern is found or top of file is reached. Search + will not wrap around when at the top of the file. + + If [!] is not given the first error is jumped to. + + If using neovim `:GoTestFunc` will run in a new terminal or run + asynchronously in the background according to |'g:go_term_enabled'|. You + can set the mode of the new terminal with |'g:go_term_mode'|. + + *:GoTestCompile* +:GoTestCompile[!] [expand] + + Compile your _test.go files via in your current directory. Errors are + populated in the quickfix window. If an argument is passed, [expand] is + used as file selector (useful for cases like `:GoTest ./...`). Useful to + not run the tests and capture/fix errors before running the tests or to + create test binary. + + If [!] is not given the first error is jumped to. + + If using neovim `:GoTestCompile` will run in a new terminal or run + asynchronously in the background according to |'g:go_term_enabled'|. You + can set the mode of the new terminal with |'g:go_term_mode'|. + + *:GoCoverage* +:GoCoverage[!] [options] + + Create a coverage profile and annotates the current file's source code. If + called again it rerurns the tests. + + If [!] is not given the first error is jumped to. + + *:GoCoverageToggle* +:GoCoverageToggle[!] [options] + + Create a coverage profile and annotates the current file's source code. If + called again clears the annotation (works as a toggle). + + If [!] is not given the first error is jumped to. + + *:GoCoverageClear* +:GoCoverageClear [options] + + Clears the coverage annotation. + + + *:GoCoverageBrowser* +:GoCoverageBrowser[!] [options] + + Create a coverage profile and open a browser to display the annotated + source code of the current package. + + You may optionally pass any valid go test flags/options, such as + `-covermode set,count,atomic`. For a full list please see `go help test`. + + If [!] is not given the first error is jumped to. + + *:GoErrCheck* +:GoErrCheck [options] + + Check for unchecked errors in you current package. Errors are populated in + the quickfix window. + + You may optionally pass any valid errcheck flags/options. For a full list + please see `errcheck -h`. + + *:GoFiles* +:GoFiles + + Show source files that depends for the current package + + *:GoDeps* +:GoDeps + + Show dependencies for the current package + + *:GoInstallBinaries* +:GoInstallBinaries + + Download and Install all necessary Go tool binaries such as `godef`, + `goimports`, `gocode`, etc. under `g:go_bin_path`. Set + |'g:go_get_update'| to disable updating dependencies. + + *:GoUpdateBinaries* +:GoUpdateBinaries + + Download and Update previously installed Go tool binaries such as `godef`, + `goimports`, `gocode`, etc.. under `g:go_bin_path`. This can be used to + update the necessary Go binaries. + + *:GoImplements* +:GoImplements + + Show "implements" relation for a selected package. A list of interfaces + for the type that implements an interface under the cursor (or selected + package) is shown in a location list. + *:GoRename* +:GoRename[!] [to] + + Rename the identifier under the cursor to the desired new name. If no + argument is given a prompt will ask for the desired identifier. + + If [!] is not given the first error is jumped to. + + + *:GoGuruScope* +:GoGuruScope [pattern] [pattern2] ... [patternN] + + Changes the custom |'g:go_guru_scope'| setting and overrides it with the + given package patterns. The custom scope is cleared (unset) if `""` is + given as the only path. If no arguments is given it prints the current + custom scope. Example patterns are: +> + golang.org/x/tools/cmd/guru # a single package + golang.org/x/tools/... # all packages beneath dir + ... # the entire workspace. +< + Example usage, the following sets the scope to a `github.com/fatih/color` + and to all packages under `golang.org/x/tools/`: +> + :GoGuruScope github.com/fatih/color golang.org/x/tools/... +< + The following sets it to the entire workspace: +> + :GoGuruScope ... +< + Under the hood, the patterns are all joined to a comma-separated list and + passed to `guru`'s `-scope` flag. + + *:GoCallees* +:GoCallees + + Show "callees" relation for a selected package. A list of possible call + targets for the type under the cursor (or selected package) is shown in a + location list. + + *:GoCallers* +:GoCallers + + Show "callers" relation for a selected function. A list of possible + callers for the selected function under the cursor is shown in a location + list. + + *:GoDescribe* +:GoDescribe + + Shows various properties of the selected syntax: its syntactic kind, its + type (for an expression), its value (for a constant expression), its size, + alignment, method set and interfaces (for a type), its declaration (for an + identifier), etc. Almost any piece of syntax may be described, and the + guru will try to print all the useful information it can. + + *:GoCallstack* +:GoCallstack + + Shows "callstack" relation for the selected function. An arbitrary path + from the root of the callgraph to the selected function is shown in a + location list. This may be useful to understand how the function is + reached in a given program. + + *:GoFreevars* +:GoFreevars + + Enumerates the free variables of the selection. “Free variables” is a + technical term meaning the set of variables that are referenced but not + defined within the selection, or loosely speaking, its inputs. + + This information is useful if you’re considering whether to refactor the + selection into a function of its own, as the free variables would be the + necessary parameters of that function. It’s also useful when you want to + understand what the inputs are to a complex block of code even if you + don’t plan to change it. + + *:GoChannelPeers* +:GoChannelPeers + + Shows the set of possible sends/receives on the channel operand of the + selected send or receive operation; the selection must be a `<-` token. + + For example, visually select a channel operand in the form of: +> + done <- true +< + And call |:GoChannelPeers| on it. It will show where it was allocated, and + the sending and receiving endings. + + *:GoReferrers* +:GoReferrers + + The referrers query shows the set of identifiers that refer to the same + object as does the selected identifier, within any package in the analysis + scope. + + *:GoSameIds* +:GoSameIds + + Highlights all identifiers that are equivalent to the identifier under the + cursor. + + *:GoSameIdsClear* +:GoSameIdsClear + + Clears all SameIds highlights from a |:GoSameIds| call. + + *:GoSameIdsToggle* +:GoSameIdsToggle + + Toggle between |:GoSameIds| and |:GoSameIdsClear|. + + *:GoSameIdsAutoToggle* +:GoSameIdsAutoToggle + + Enables or disables automatic highlighting of |:GoSameIds| while moving + the cursor. This basically toggles the option |'g:go_auto_sameids'| + on/off. + If enabled it starts highlighting whenever your cursor is staying at the + same position for a configurable period of time (see 'updatetime'). If + disabled it clears and stops automatic highlighting. + + *:GoMetaLinter* +:GoMetaLinter [path] + + Calls the underlying `gometalinter` tool and displays all warnings and + errors in the |quickfix| window. By default the following linters are + enabled: `vet`, `golint`, and `errcheck`. This can be changed with the + |'g:go_metalinter_enabled'| variable. To override the command completely + use the variable |'g:go_metalinter_command'|. To override the maximum + linters execution time use |'g:go_metalinter_deadline'| variable. + + *:GoBuildTags* +:GoBuildTags [tags] + + Changes the build tags for various commands. If you have any file that + uses a custom build tag, such as `//+build integration` , this command can + be used to pass it to all tools that accepts tags, such as guru, gorenate, + etc.. + + The build tags is cleared (unset) if `""` is given. If no arguments is + given it prints the current custom build tags. + + *:AsmFmt* +:AsmFmt + + Filter the current Go asm buffer through asmfmt. It tries to preserve + cursor position and avoids replacing the buffer with stderr output. + + *:GoAlternate* +:GoAlternate[!] + + Alternates between the implementation and test code. For example if in + main.go, switch to main_test.go. Uses the |'g:go_alternate_mode'| setting + as the command to open the file. + + If [!] is given then it switches to the new file even if it does not + exist. + + If you would like to override the traditional commands for alternating, + add the following to your .vimrc: +> + augroup go + autocmd! + autocmd Filetype go + \ command! -bang A call go#alternate#Switch(0, 'edit') + \| command! -bang AV call go#alternate#Switch(0, 'vsplit') + \| command! -bang AS call go#alternate#Switch(0, 'split') + augroup END +< + *:GoWhicherrs* +:GoWhicherrs + + Show the list of possible constants, global variables, and concrete types + for the error type under the cursor in a location list. + + *:GoDecls* +:GoDecls [file] + + Only enabled if `ctrlp.vim` is installed. If run shows all function and + type declarations for the current file. If [file] is non empty it parses + the given file. + By default `type` and `func` declarations are shown. This can be changed + via |'g:go_decls_includes'|. + + *:GoDeclsDir* +:GoDeclsDir [dir] + + Only enabled if `ctrlp.vim` is installed. If run shows all function and + type declarations for the current directory. If [dir] is given it parses + the given directory. + + *:GoImpl* +:GoImpl [receiver] [interface] + + Generates method stubs for implementing an interface. If no arguments is + passed it takes the identifier under the cursor to be the receiver and + asks for the interface type to be generated. If used with arguments, the + receiver and the interface needs to be specified. Example usages: +> + :GoImpl f *Foo io.Writer + :GoImpl T io.ReadWriteCloser +< + *:GoAddTags* +:[range]GoAddTags [key],[option] [key1],[option] ... + + Adds field tags for the fields of a struct. If called inside a struct it + automatically add field tags with the `json` key and the value + automatically generated based on the field name. An error message is given + if it's called outside a struct definition or if the file is not correctly + formatted. + + If [range] is given, only the selected fields will be changed. + + The default `json` can be changed by providing one or more [key] + arguments. An example of adding `xml` and `db` would be: +> + :GoAddTags xml db +< + If [option] is passed it'll either add a new tag with an option or will + modify exising tags. An example of adding `omitempty` to all `json` fields + would be: +> + :GoAddTags json,omitempty +< + You can define a constant value instead of the default field based value. + For example the following command will add ``valid:"1"`` to all fields. +> + :GoAddTags valid=1 +< + *:GoRemoveTags* +:[range]GoRemoveTags [key],[option] [key1],[option1] ... + + Rmove field tags for the fields of a struct. If called inside a struct it + automatically remove all field tags. An error message is given if it's + called outside a struct definition or if the file is not correctly + formatted + + If [range] is given, only the selected fields will be changed. + + If [key] is given, it will only remove those keys. Example: +> + :GoRemoveTags json +< + If [option] is passed with a [key], it will only remove the options. + Example, this will only remove `omitempty` options from fields containing + `json`: +> + :GoRemoveTags json,omitempty +< + *:GoAutoTypeInfoToggle* +:GoAutoTypeInfoToggle + + Toggles |'g:go_auto_type_info'|. + + *:GoFmtAutoSaveToggle* +:GoFmtAutoSaveToggle + + Toggles |'g:go_fmt_autosave'|. + + *:GoAsmFmtAutoSaveToggle* +:GoAsmFmtAutoSaveToggle + + Toggles |'g:go_asmfmt_autosave'|. + + *:GoMetaLinterAutoSaveToggle* +:GoMetaLinterAutoSaveToggle + + Toggles |'g:go_metalinter_autosave'|. + + *:GoTemplateAutoCreateToggle* +:GoTemplateAutoCreateToggle + + Toggles |'g:go_template_autocreate'|. + + +============================================================================== +MAPPINGS *go-mappings* + +vim-go has several keys which can be used to create custom mappings +For example, to create a mapping that `go run` for the current package, create +a mapping for the `(go-run)`: > + + au FileType go nmap r (go-run) + +As always one is free to create more advanced mappings or functions based with +|go-commands|. For more information please check out the mappings command +documentation in the |go-commands| section. Available keys are: + + *(go-run)* + +Calls `go run` for the current main package + + *(go-run-tab)* + +Calls `go run` for the current file in a new terminal tab +This option is neovim only. + + *(go-run-split)* + +Calls `go run` for the current file in a new terminal horizontal split +This option is neovim only. + + *(go-run-vertical)* + +Calls `go run` for the current file in a new terminal vertical split +This option is neovim only. + + *(go-build)* + +Calls `go build` for the current package + + *(go-generate)* + +Calls `go generate` for the current package + + *(go-info)* + +Shows type information for the word under the cursor + + *(go-install)* + +Calls `go install` for the current package + + *(go-test)* + +Calls `go test` for the current package + + *(go-test-func)* + +Calls `go test -run '...'` for the test function immediate to cursor + + *(go-test-compile)* + +Calls `go test -c` for the current package + + *(go-coverage)* + +Calls `go test -coverprofile-temp.out` for the current package and shows the +coverage annotation. + + *(go-coverage-clear)* + +Clears the coverage annotation + + *(go-coverage-toggle)* + +Calls `go test -coverprofile-temp.out` for the current package and shows the +coverage annotation. If run agains it acts as a toggle and clears the +annotation. + + *(go-imports)* + +Calls `goimports` for the current package + + *(go-lint)* + +Calls `golint` for the current package + + *(go-vet)* + +Calls `go vet` for the current package + + + *(go-files)* + +Show source files that depends for the current package + + + *(go-deps)* + +Show dependencies for the current package + + *(go-doc)* + +Show the relevant GoDoc for the word under the cursor in a split window +leftabove (default mode). + + *(go-doc-split)* + +Show the relevant GoDoc for the word under the cursor in a split window. + + + *(go-doc-vertical)* + +Show the relevant GoDoc for the word under the cursor in a vertical split +window. + + *(go-doc-tab)* + +Show the relevant GoDoc for the word under the cursor in a tab window. + + + *(go-doc-browser)* + +Show the relevant GoDoc for the word under in browser + + *(go-def)* + +Goto declaration/definition. Results are shown in the current buffer. + + *(go-def-split)* + +Goto declaration/definition. Results are shown in a split window. +Jumps to an existing buffer if |'g:go_def_reuse_buffer'| is enabled. + + *(go-def-vertical)* + +Goto declaration/definition. Results are shown in a vertical split window. +Jumps to an existing buffer if |'g:go_def_reuse_buffer'| is enabled. + + *(go-def-tab)* + +Goto declaration/definition. Results are shown in a tab window. +Jumps to an existing buffer if |'g:go_def_reuse_buffer'| is enabled. + + *(go-def-stack)* + +Shows the godef tag stack + + *(go-def-stack-clear)* + +Resets and clears the tag stack + + *(go-def-pop)* + +Jump to previous entry in the tag stack + + *(go-implements)* + +Show the interfaces that the type under the cursor implements. + + *(go-rename)* + +Rename the identifier under the cursor to the desired new name + + *(go-callees)* + +Show the call targets for the type under the cursor + + *(go-callers)* + +Show possible callers of selected function + + *(go-describe)* + +Describe selected syntax: definition, methods, etc + + *(go-callstack)* + +Show path from callgraph root to selected function + + *(go-freevars)* + +Show free variables of selection + + *(go-channelpeers)* + +Show send/receive corresponding to selected channel op + + *(go-referrers)* + +Show all refs to entity denoted by selected identifier + + *(go-metalinter)* + +Calls `go-metalinter` for the current directory + + *(go-alternate-edit)* + +Alternates between the implementation and test code in the current window + + *(go-alternate-split)* + +Alternates between the implementation and test code in a new horizontal split + + *(go-alternate-vertical)* + +Alternates between the implementation and test code in a new vertical split + + *(go-import)* + +Calls `:GoImport` for the current package + + +============================================================================== +TEXT OBJECTS *go-text-objects* + +vim-go comes with several custom |text-objects| that can be used to operate +upon regions of text. vim-go currently defines the following text objects: + + *go-v_af* *go-af* +af "a function", select contents from a function definition to the + closing bracket. If |'g:go_textobj_include_function_doc'| is + enabled it also includes the comment doc for a function + declaration. This text-object also supports literal functions. + + *go-v_if* *go-if* +if "inside a function", select contents of a function, + excluding the function definition and the closing bracket. This + text-object also supports literal functions + + +vim-go also defines the following text motion objects: + + *go-v_]]* *go-]]* +]] [count] forward to next function declaration. If + |'g:go_textobj_include_function_doc'| is enabled and if your + on a comment, it skips the function which the comment + belongs and forwards to the next function declaration. + + *go-v_[[* *go-[[* +[[ [count] backward to previous function declaration. + + + +============================================================================== +FUNCTIONS *go-functions* + + *go#statusline#Show()* + +Shows the status of a job running asynchronously. Can be used to plug into the +statusline. It works to show the status per package instead of per +file. Assume you have three files open, all belonging to the same package, if +the package build (`:GoBuild`) is successful, all statusline's will show +`success`, if you it fails all file's statusline will show `failed`. + +To avoid always showing old status information, the status information is +cleaned for each package after `60` seconds. This can be changed with the +|g:go_statusline_duration| setting. + + *go#complete#GetInfo()* + +Returns the description of the identifer under the cursor. Can be used to plug +into the statusline. This function is also used for |'g:go_auto_type_info'|. + +============================================================================== +SETTINGS *go-settings* + + *'g:go_test_timeout'* + +Use this option to change the test timeout of |:GoTest|. By default it is +set to 10 seconds . > + + let g:go_test_timeout= '10s' +< + *'g:go_play_browser_command'* + +Use this option to change the browser that is used to open the snippet url +posted to play.golang.org with |:GoPlay| or for the relevant documentation +used with |:GoDocBrowser|. By default it tries to find it automatically for +the current OS. > + + let g:go_play_browser_command = '' +< + *'g:go_play_open_browser'* + +Use this option to open browser after posting the snippet to play.golang.org +with |:GoPlay|. By default it's enabled. > + + let g:go_play_open_browser = 1 +< + *'g:go_auto_type_info'* + +Use this option to show the type info (|:GoInfo|) for the word under the +cursor automatically. Whenever the cursor changes the type info will be +updated. By default it's disabled. The delay can be configured with the +'g:go_updatetime' setting. +> + let g:go_auto_type_info = 0 +< + + *'g:go_info_mode'* + +Use this option to define the command to be used for |:GoInfo|. By default +`gocode` is being used as it's the fastest option. But one might also use +`guru` as it's covers more cases and is more accurate. Current valid options +are: `[gocode, guru]` > + + let g:go_info_mode = 'gocode' +< + *'g:go_auto_sameids'* + +Use this option to highlight all uses of the identifier under the cursor +(:GoSameIds) automatically. By default it's disabled. The delay can be +configured with the 'g:go_updatetime' setting. +> + let g:go_auto_sameids = 0 +< + *'g:go_updatetime'* + +Use this option to configure the a custom 'updatetime' for Go source files. If +set to 0, no custom time will be configured. By default it's set to 800ms. +> + let g:go_updatetime = 800 +< + *'g:go_jump_to_error'* + +Use this option to enable/disable passing the bang attribute to the mappings +|(go-build)|, |(go-run)|, etc.. When enabled it will jump to the first error +automatically (means it will NOT pass the bang attribute to the appropriate +command, i.e: (go-run) -> :GoRun ). Note, that calling this doesn't have any +affect on calling the commands manually. This setting is only useful for +changing the behaviour of our custom static mappings. By default it's enabled. +> + let g:go_jump_to_error = 1 +< + *'g:go_fmt_autosave'* + +Use this option to auto |:GoFmt| on save. By default it's enabled > + + let g:go_fmt_autosave = 1 +< + *'g:go_fmt_command'* + +Use this option to define which tool is used to gofmt. By default `gofmt` is +used > + + let g:go_fmt_command = "gofmt" +< + *'g:go_fmt_options'* + +Use this option to add additional options to the |'g:go_fmt_command'|. Default +is empty. > + + let g:go_fmt_options = '' +< + *'g:go_fmt_fail_silently'* + +Use this option to disable showing a location list when |'g:go_fmt_command'| +fails. By default the location list is shown. > + + let g:go_fmt_fail_silently = 0 +< + *'g:go_fmt_experimental'* + +Use this option to enable fmt's experimental mode. This experimental mode is +superior to the current mode as it fully saves the undo history, so undo/redo +doesn't break. However it's slows (creates/deletes a file for every save) and +it's causing problems on some Vim versions. By default it's disabled. > + + let g:go_fmt_experimental = 0 +< + *'g:go_doc_keywordprg_enabled'* + +Use this option to run `godoc` on words under the cursor with the default K , +keywordprg shortcut. Usually this shortcut is set to use the program `man`. In +Go, using `godoc` is more idiomatic. Default is enabled. > + + let g:go_doc_keywordprg_enabled = 1 +< + *'g:go_def_mode'* + +Use this option to define the command to be used for |:GoDef|. By default +`guru` is being used as it covers all edge cases. But one might also use +`godef` as it's more faster. Current valid options are: `[guru, godef]` > + + let g:go_def_mode = 'guru' +< + *'g:go_def_mapping_enabled'* + +Use this option to enable/disable the default mapping of CTRL-] and (`gd`) for +GoDef and CTRL-t for :GoDefPop. Disabling it allows you to map something else +to these keys or mappings. Default is enabled. > + + let g:go_def_mapping_enabled = 1 +< + *'g:go_def_reuse_buffer'* + +Use this option to jump to an existing buffer for the split, vsplit and tab +mappings of |:GoDef|. By default it's disabled. > + + let g:go_def_reuse_buffer = 0 +< + *'g:go_doc_command'* + +Use this option to define which tool is used to godoc. By default `godoc` is +used > + + let g:go_doc_command = "godoc" +< + *'g:go_doc_options'* + +Use this option to add additional options to the |'g:go_doc_command'|. Default +is empty. > + + let g:go_doc_options = '' + +< *'g:go_bin_path'* + +Use this option to change default path for vim-go tools when using +|:GoInstallBinaries| and |:GoUpdateBinaries|. If not set `$GOBIN` or +`$GOPATH/bin` is used. > + + let g:go_bin_path = "" +< + *'g:go_snippet_engine'* + +Use this option to define the default snippet engine. By default "ultisnips" +is used. Use "neosnippet" for neosnippet.vim: > + + let g:go_snippet_engine = "ultisnips" +< + *'g:go_snippet_case_type'* + +Use this option to define the default conversion type of snippet expansion for +field tags. For the following case, if `snakecase` is used the `json` snippet +will expand to: +> + type T struct { + FooBarQuz string `json:"foo_bar_quz" + } +< + +If "camelcase" is used: +> + type T struct { + FooBarQuz string `json:"fooBarQuz" + } +< +By default "snakecase" is used. Current values are: ["snakecase", +"camelcase"]. +> + let g:go_snippet_case_type = "snakecase" +< + *'g:go_get_update'* + +Use this option to disable updating dependencies with |:GoInstallBinaries|. By +default this is enabled. +> + let g:go_get_update = 1 +< + *'g:go_guru_scope'* + +Use this option to define the scope of the analysis to be passed for guru +related commands, such as |:GoImplements|, |:GoCallers|, etc. You can change +it on-the-fly with |:GoGuruScope|. The input should be a a list of package +pattern. An example input might be: +`["github.com/fatih/color","github.com/fatih/structs"]` By default it's not +set, so the relevant commands defaults are being used. +> + let g:go_guru_scope = [] +< + *'g:go_build_tags'* + +These options that will be automatically passed to the `-tags` option of +various tools, such as `guru`, `gorename`, etc... This is a permanatent +setting. A more useful way is to use |:GoBuildTags| to dynamically change or +remove build tags. By default it's not set. +> + let g:go_build_tags = '' +< + *'g:go_highlight_array_whitespace_error'* + +Highlights white space after "[]". > + + let g:go_highlight_array_whitespace_error = 1 +< + *'g:go_highlight_chan_whitespace_error'* + +Highlights white space around the communications operator (`<-`) that doesn't +follow the standard style. > + + let g:go_highlight_chan_whitespace_error = 1 +< + *'g:go_highlight_extra_types'* + +Highlights commonly used library types (io.Reader, etc.). > + + let g:go_highlight_extra_types = 1 +< + *'g:go_highlight_space_tab_error'* + +Highlights instances of tabs following spaces. > + + let g:go_highlight_space_tab_error = 1 +< + *'g:go_highlight_trailing_whitespace_error'* + +Highlights trailing white space. > + + let g:go_highlight_trailing_whitespace_error = 1 +< + *'g:go_highlight_operators'* + +Highlights operators such as `:=` , `==`, `-=`, etc. By default it's +disabled. > + + let g:go_highlight_operators = 0 +< + *'g:go_highlight_functions'* + +Highlights function names. By default it's disabled. > + + let g:go_highlight_functions = 0 +< + *'g:go_highlight_methods'* + +Highlights method names. By default it's disabled. > + + let g:go_highlight_methods = 0 +< + *'g:go_highlight_types'* + +Highlights struct and interface names. By default it's disabled. > + + let g:go_highlight_types = 0 +< + *'g:go_highlight_fields'* + +Highlights field names. By default it's disabled. > + + let g:go_highlight_fields = 0 +< + *'g:go_highlight_build_constraints'* + +Highlights build constraints. By default it's disabled. > + + let g:go_highlight_build_constraints = 0 +< + *'g:go_highlight_generate_tags'* + +Highlights go:generate directives. By default it's disabled. > + + let g:go_highlight_generate_tags = 0 +< + *'g:go_highlight_string_spellcheck'* + +Use this option to highlight spelling errors in strings when |spell| is +also enabled. By default it's enabled. > + + let g:go_highlight_string_spellcheck = 1 +< + *'g:go_highlight_format_strings'* + +Use this option to highlight printf-style operators inside string literals. +By default it's enabled. > + + let g:go_highlight_format_strings = 1 +< + *'g:go_autodetect_gopath'* + +Automatically modifies GOPATH for certain directory structures, such as for +the tool `godep` which has his own dependencies via the `Godeps` folder. What +this means is that all tools are now working with the newly modified GOPATH. +So |:GoDef| for example jumps to the source inside the `Godeps` (vendored) +source. Currently `godep` and `gb` is supported, in the near future more tool +supports will be added. By default it's enabled. > + + let g:go_autodetect_gopath = 1 +< + *'g:go_textobj_enabled'* + +Adds custom text objects. By default it's enabled. > + + let g:go_textobj_enabled = 1 +< + *'g:go_textobj_include_function_doc'* + +Consider the comment above a function to be part of the function when using +the `af` text object and `[[` motion. By default it's enabled. > + + let g:go_textobj_include_function_doc = 1 +< + *'g:go_metalinter_autosave'* + +Use this option to auto |:GoMetaLinter| on save. Only linter messages for +the active buffer will be shown. By default it's disabled > + + let g:go_metalinter_autosave = 0 +< + *'g:go_metalinter_autosave_enabled'* + +Specifies the enabled linters for auto |:GoMetaLinter| on save. By +default it's using `vet` and `golint`. +> + let g:go_metalinter_autosave_enabled = ['vet', 'golint'] +< + *'g:go_metalinter_enabled'* + +Specifies the currently enabled linters for the |:GoMetaLinter| command. By +default it's using `vet`, `golint` and `errcheck`. +> + let g:go_metalinter_enabled = ['vet', 'golint', 'errcheck'] +< + *'g:go_metalinter_excludes'* + +Specifies the linters to be excluded from the |:GoMetaLinter| command. By +default it's empty +> + let g:go_metalinter_excludes = [] +< + *'g:go_metalinter_command'* + +Overrides the command to be executed when |:GoMetaLinter| is called. This is +an advanced settings and is for users who want to have a complete control +over how `gometalinter` should be executed. By default it's empty. +> + let g:go_metalinter_command = "" +< + *'g:go_metalinter_deadline'* + +Overrides the maximum time the linters have to complete. By default it's 5 +seconds. +> + let g:go_metalinter_deadline = "5s" +< + *'g:go_list_height'* + +Specifies the window height for the quickfix and location list windows. The +default value (empty) automatically sets the height to the number of items +(maximum up to 10 items to prevent large heights). Setting the value +explicitly overrides this behavior. For standard Vim behavior, set it to 10. +> + let g:go_list_height = 0 +< + *'g:go_list_type'* + +Specifies the type of list to use. The default value (empty) will use the +appropriate kind of list for the command that was called. Supported values are +"", "quickfix", and "locationlist". > + + let g:go_list_type = "" +< + *'g:go_asmfmt_autosave'* + +Use this option to auto |:AsmFmt| on save. By default it's disabled. > + + let g:go_asmfmt_autosave = 0 +< + *'g:go_term_mode'* + +This option is Neovim only. Use it to change the default command used to +open a new terminal for go commands such as |:GoRun|. +The default is vsplit. +> + let g:go_term_mode = "vsplit" +< + *'g:go_term_height'* + *'g:go_term_width'* + +These options are Neovim only. Use them to control the height and width of +a terminal split. By default these are not set, meaning that the height and +width are set automatically by Neovim. The height only applies to a +horizontal split and width only applies to a vertical split. + +For example here is how to set each to 30. +> + let g:go_term_height = 30 + let g:go_term_width = 30 +< + *'g:go_term_enabled'* + +This option is Neovim only. Use it to change the behavior of the test +commands. If set to 1 it opens the test commands inside a new terminal +according to |'g:go_term_mode'|, otherwise it will run them in the background +just like `:GoBuild`. By default it is disabled. +> + let g:go_term_enabled = 0 +< + *'g:go_alternate_mode'* + +Specifies the command that |:GoAlternate| uses to open the alternate file. +By default it is set to edit. +> + let g:go_alternate_mode = "edit" +< + *'g:go_gorename_prefill'* + +Specifies whether |:GoRename| prefills the new identifier name with the +word under the cursor. By default it is enabled. +> + let g:go_gorename_prefill = 1 +< + *'g:go_gocode_autobuild'* + +Specifies whether `gocode` should automatically build out-of-date packages +when their source fields are modified, in order to obtain the freshest +autocomplete results for them. By default it is enabled. +> + let g:go_gocode_autobuild = 1 +< + *'g:go_gocode_propose_builtins'* + +Specifies whether `gocode` should add built-in types, functions and constants +to an autocompletion proposals. By default it is enabled. +> + let g:go_gocode_propose_builtins = 1 +< + *'g:go_gocode_unimported_packages'* + +Specifies whether `gocode` should include suggestions from unimported packages. +By default it is disabled. +> + let g:go_gocode_unimported_packages = 0 +< + + *'g:go_gocode_socket_type'* + +Specifies whether `gocode` should use a different socket type. By default +`unix` is enabled. Possible values: `unix`, `tcp` +> + let g:go_gocode_socket_type = 'unix' +< + *'g:go_template_autocreate'* + +When a new Go file is created, vim-go automatically fills the buffer content +with a Go code template. By default the template under +`templates/hello_world.go` is used. This can be changed with the +|'g:go_template_file'| setting. + +If the new file is created in an already prepopulated package (with other Go +files), in this case a Go code template with only the Go package declaration +(which is automatically determined according to the current package) is added. + +To always use the package name instead of the template, enable the +|`g:go_template_use_pkg`| setting. + +By default it is enabled. +> + let g:go_template_autocreate = 1 +< + *'g:go_template_file'* + +Specifies the file under the `templates` folder that is used if a new Go file +is created. Checkout |'g:go_template_autocreate'| for more info. By default +the `hello_world.go` file is used. +> + let g:go_template_file = "hello_world.go" +< + *'g:go_template_use_pkg'* + +Specifies that, rather than using a template, the package name is used if a new +Go file is created. Checkout |'g:go_template_autocreate'| for more info. By +default the template file specified by |'g:go_template_file'| is used. + +> + let g:go_template_use_pkg = 0 +< + *'g:go_decls_includes'* + +Only useful if `ctrlp.vim` is installed. This sets which declarations to show +for |:GoDecls|. It is a Comma delimited list Possible options are: +{func,type}. The default is: > + + let g:go_decls_includes = 'func,type' +< + *'g:go_echo_command_info'* + +Echoes information about various Go commands, such as `:GoBuild`, `:GoTest`, +`:GoCoverage`, etc... Useful to disable if you use the statusline integration, +i.e: |go#statusline#Show()|. By default it's enabled +> + let g:go_echo_command_info = 1 +< + *'g:go_echo_go_info'* + +Use this option to show the identifier information when completion is done. By +default it's enabled > + + let g:go_echo_go_info = 1 +< +Please note that 'noshowmode' must be set for this feature to work correctly. + + *'g:go_statusline_duration'* + +Specifices the duration of statusline information being showed per package. By +default it's 60 seconds. Must be in milliseconds. +> + let g:go_statusline_duration = 60000 +< +============================================================================== +DEVELOPMENT *go-development* + +vim-go supports test files written in VimL. Please check `autoload` folder for +examples. If you add a new feature be sure you also include the `_test.vim` +file next to the script. Test functions should be starting with `Test_`, +example: +> + function Test_run_fmt() + call assert_equal(expected, actual) + ... + endfunction +< +You can locally test it by running: +> + make +< +This will run all tests and print either `PASS` or `FAIL` to indicate the final +status of all tests. Additionally, each new pull request will trigger a new +Travis-ci job. + + +============================================================================== +FAQ TROUBLESHOOTING *go-troubleshooting* + +I get "not an editor command" error when I invoke :GoXXX~ + +This happens if vim-go is not installed properly. Be sure you have added this +line into your vimrc: +> + filetype plugin indent on +< + +I get a "command not found" error when I invoke :GoXXX~ + +If you try to call |:GoDef|, |:GoInfo| and get a command not found, check that +you have the binaries installed by using |:GoInstallBinaries|. + +Before opening vim, check your current $PATH: +> + echo $PATH +< +After opening vim, run `:echo $PATH`, the output must be your current `$PATH` +plus `$GOPATH/bin` (the location where |:GoInstallBinaries| installed the +binaries). + + +Vim becomes slow while editing Go files~ + +Don't enable these options: +> + let g:go_highlight_types = 0 + let g:go_highlight_operators = 0 +< + +I get errors when using GoInstallBinaries~ + +If you see errors like this: +> + Error installing golang.org/x/tools/cmd/goimports +< +that means your local Go setup is broken or the remote website is down. For +example sometimes code.google.com times out. To test, just execute a simple +`go get`: +> + go get golang.org/x/tools/cmd/goimports +< +You'll see a more detailed error. If this works, vim-go will work too. + + +How do I use vim-go with syntastic?~ + +Sometimes when using both `vim-go` and `syntastic` Vim will start lagging +while saving and opening files. The following fixes this: +> + let g:syntastic_go_checkers = ['golint', 'govet', 'errcheck'] + let g:syntastic_mode_map = { 'mode': 'active', 'passive_filetypes': ['go'] } +< +Another issue with `vim-go` and `syntastic` is that the location list window +that contains the output of commands such as `:GoBuild` and `:GoTest` might +not appear. To resolve this: +> + let g:go_list_type = "quickfix" +< + +Using with NeoVim~ + +Note: Neovim currently is not a first class citizen for vim-go. You are free +to open bug, however I'm not using Neovim so it's hard for me to test it. +vim-go might not work well as good as in Vim. I'm happy to accept pull requests +or very detailed bug reports. If you're interested to improve the state of +Neovim in vim-go you're always welcome! + +Run `:GoRun` in a new tab, horizontal split or vertical split terminal +> + au FileType go nmap rt (go-run-tab) + au FileType go nmap rs (go-run-split) + au FileType go nmap rv (go-run-vertical) +< +By default new terminals are opened in a vertical split. To change it +> + let g:go_term_mode = "split" +> + +============================================================================== +DONATION *go-donation* + +People have asked for this for a long time, now you can be a fully supporter +by being a patreon at: https://www.patreon.com/fatih + +By being a patron, you are enabling vim-go to grow and mature, helping me to +invest in bug fixes, new documentation, and improving both current and future +features. It's completely optional and is just a direct way to support Vim-go's +ongoing development. Thanks! + +Check it out: https://www.patreon.com/fatih + + +============================================================================== +CREDITS *go-credits* + +* Go Authors for official Vim plugins. +* Gocode, Godef, Golint, Guru, Goimports, Errcheck projects and authors of + those projects. +* Other vim-plugins, thanks for inspiration (vim-golang, go.vim, vim-gocode, + vim-godef). +* vim-go contributors: https://github.com/fatih/vim-go/graphs/contributors. + + +vim:ft=help:et:ts=2:sw=2:sts=2:norl diff --git a/vim/bundle/vim-go/ftdetect/gofiletype.vim b/vim/bundle/vim-go/ftdetect/gofiletype.vim new file mode 100644 index 0000000..267d2cc --- /dev/null +++ b/vim/bundle/vim-go/ftdetect/gofiletype.vim @@ -0,0 +1,31 @@ +" We take care to preserve the user's fileencodings and fileformats, +" because those settings are global (not buffer local), yet we want +" to override them for loading Go files, which are defined to be UTF-8. +let s:current_fileformats = '' +let s:current_fileencodings = '' + +" define fileencodings to open as utf-8 encoding even if it's ascii. +function! s:gofiletype_pre(type) + let s:current_fileformats = &g:fileformats + let s:current_fileencodings = &g:fileencodings + set fileencodings=utf-8 fileformats=unix + let &l:filetype = a:type +endfunction + +" restore fileencodings as others +function! s:gofiletype_post() + let &g:fileformats = s:current_fileformats + let &g:fileencodings = s:current_fileencodings +endfunction + +au BufNewFile *.go setfiletype go | setlocal fileencoding=utf-8 fileformat=unix +au BufRead *.go call s:gofiletype_pre("go") +au BufReadPost *.go call s:gofiletype_post() + +au BufNewFile *.s setfiletype asm | setlocal fileencoding=utf-8 fileformat=unix +au BufRead *.s call s:gofiletype_pre("asm") +au BufReadPost *.s call s:gofiletype_post() + +au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/ftplugin/asm.vim b/vim/bundle/vim-go/ftplugin/asm.vim new file mode 100644 index 0000000..99996aa --- /dev/null +++ b/vim/bundle/vim-go/ftplugin/asm.vim @@ -0,0 +1,19 @@ +" asm.vim: Vim filetype plugin for Go assembler. + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let b:undo_ftplugin = "setl fo< com< cms<" + +setlocal formatoptions-=t + +setlocal comments=s1:/*,mb:*,ex:*/,:// +setlocal commentstring=//\ %s + +setlocal noexpandtab + +command! -nargs=0 AsmFmt call go#asmfmt#Format() + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/ftplugin/go.vim b/vim/bundle/vim-go/ftplugin/go.vim new file mode 100644 index 0000000..de830f9 --- /dev/null +++ b/vim/bundle/vim-go/ftplugin/go.vim @@ -0,0 +1,131 @@ +" Copyright 2013 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. +" +" go.vim: Vim filetype plugin for Go. + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let b:undo_ftplugin = "setl fo< com< cms<" + +setlocal formatoptions-=t + +setlocal comments=s1:/*,mb:*,ex:*/,:// +setlocal commentstring=//\ %s + +setlocal noexpandtab + +compiler go + +" Set gocode completion +setlocal omnifunc=go#complete#Complete + +if get(g:, "go_doc_keywordprg_enabled", 1) + " keywordprg doesn't allow to use vim commands, override it + nnoremap K :GoDoc +endif + +if get(g:, "go_def_mapping_enabled", 1) + " these are default Vim mappings, we're overriding them to make them + " useful again for Go source code + nnoremap gd :GoDef + nnoremap :GoDef + nnoremap :call go#def#Jump("split") + nnoremap ] :call go#def#Jump("split") + nnoremap :call go#def#StackPop(v:count1) +endif + +if get(g:, "go_textobj_enabled", 1) + onoremap af :call go#textobj#Function('a') + onoremap if :call go#textobj#Function('i') + + xnoremap af :call go#textobj#Function('a') + xnoremap if :call go#textobj#Function('i') + + " Remap ]] and [[ to jump betweeen functions as they are useless in Go + nnoremap ]] :call go#textobj#FunctionJump('n', 'next') + nnoremap [[ :call go#textobj#FunctionJump('n', 'prev') + + onoremap ]] :call go#textobj#FunctionJump('o', 'next') + onoremap [[ :call go#textobj#FunctionJump('o', 'prev') + + xnoremap ]] :call go#textobj#FunctionJump('v', 'next') + xnoremap [[ :call go#textobj#FunctionJump('v', 'prev') +endif + +if get(g:, "go_auto_type_info", 0) || get(g:, "go_auto_sameids", 0) + let &l:updatetime= get(g:, "go_updatetime", 800) +endif + +" NOTE(arslan): experimental, disabled by default, doesn't work well. No +" documentation as well. If anyone feels adventerous, enable the following and +" try to search for Go identifiers ;) +" +" if get(g:, "go_sameid_search_enabled", 0) +" autocmd FileType go nnoremap * :call Sameids_search(0) +" autocmd FileType go nnoremap # :call Sameids_search(1) +" autocmd FileType go nnoremap n :call Sameids_repeat(0) +" autocmd FileType go nnoremap N :call Sameids_repeat(1) +" autocmd FileType go cabbrev nohlsearch =Sameids_nohlsearch() +" endif + +" " mode 0: next 1: prev +" function! Sameids_repeat(mode) +" let matches = getmatches() +" if empty(matches) +" return +" endif +" let cur_offset = go#util#OffsetCursor() + +" " reverse list to make it easy to find the prev occurence +" if a:mode +" call reverse(matches) +" endif + +" for m in matches +" if !has_key(m, "group") +" return +" endif + +" if m.group != "goSameId" +" return +" endif + +" let offset = go#util#Offset(m.pos1[0], m.pos1[1]) + +" if a:mode && cur_offset > offset +" call cursor(m.pos1[0], m.pos1[1]) +" return +" elseif !a:mode && cur_offset < offset +" call cursor(m.pos1[0], m.pos1[1]) +" return +" endif +" endfor + +" " reached start/end, jump to the end/start +" let initial_match = matches[0] +" if !has_key(initial_match, "group") +" return +" endif + +" if initial_match.group != "goSameId" +" return +" endif + +" call cursor(initial_match.pos1[0], initial_match.pos1[1]) +" endfunction + +" function! Sameids_search(mode) +" call go#guru#SameIds() +" call Sameids_repeat(a:mode) +" endfunction + +" function! Sameids_nohlsearch() +" call go#guru#ClearSameIds() +" return "nohlsearch" +" endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/ftplugin/go/commands.vim b/vim/bundle/vim-go/ftplugin/go/commands.vim new file mode 100644 index 0000000..f5357d2 --- /dev/null +++ b/vim/bundle/vim-go/ftplugin/go/commands.vim @@ -0,0 +1,95 @@ +" -- gorename +command! -nargs=? GoRename call go#rename#Rename(0,) + +" -- guru +command! -nargs=* -complete=customlist,go#package#Complete GoGuruScope call go#guru#Scope() +command! -range=% GoImplements call go#guru#Implements() +command! -range=% GoWhicherrs call go#guru#Whicherrs() +command! -range=% GoCallees call go#guru#Callees() +command! -range=% GoDescribe call go#guru#Describe() +command! -range=% GoCallers call go#guru#Callers() +command! -range=% GoCallstack call go#guru#Callstack() +command! -range=% GoFreevars call go#guru#Freevars() +command! -range=% GoChannelPeers call go#guru#ChannelPeers() +command! -range=% GoReferrers call go#guru#Referrers() + +command! -range=0 GoSameIds call go#guru#SameIds() +command! -range=0 GoSameIdsClear call go#guru#ClearSameIds() +command! -range=0 GoSameIdsToggle call go#guru#ToggleSameIds() +command! -range=0 GoSameIdsAutoToggle call go#guru#AutoToogleSameIds() + +" -- tags +command! -nargs=* -range GoAddTags call go#tags#Add(, , , ) +command! -nargs=* -range GoRemoveTags call go#tags#Remove(, , , ) + +" -- tool +command! -nargs=0 GoFiles echo go#tool#Files() +command! -nargs=0 GoDeps echo go#tool#Deps() +command! -nargs=* GoInfo call go#tool#Info(0) +command! -nargs=0 GoAutoTypeInfoToggle call go#complete#ToggleAutoTypeInfo() + +" -- cmd +command! -nargs=* -bang GoBuild call go#cmd#Build(0,) +command! -nargs=? -bang GoBuildTags call go#cmd#BuildTags(0, ) +command! -nargs=* -bang GoGenerate call go#cmd#Generate(0,) +command! -nargs=* -bang -complete=file GoRun call go#cmd#Run(0,) +command! -nargs=* -bang GoInstall call go#cmd#Install(0, ) +command! -nargs=* -bang GoTest call go#cmd#Test(0, 0, ) +command! -nargs=* -bang GoTestFunc call go#cmd#TestFunc(0, ) +command! -nargs=* -bang GoTestCompile call go#cmd#Test(0, 1, ) + +" -- cover +command! -nargs=* -bang GoCoverage call go#coverage#Buffer(0, ) +command! -nargs=* -bang GoCoverageClear call go#coverage#Clear() +command! -nargs=* -bang GoCoverageToggle call go#coverage#BufferToggle(0, ) +command! -nargs=* -bang GoCoverageBrowser call go#coverage#Browser(0, ) + +" -- play +command! -nargs=0 -range=% GoPlay call go#play#Share(, , ) + +" -- def +command! -nargs=* -range GoDef :call go#def#Jump('') +command! -nargs=? GoDefPop :call go#def#StackPop() +command! -nargs=? GoDefStack :call go#def#Stack() +command! -nargs=? GoDefStackClear :call go#def#StackClear() + +" -- doc +command! -nargs=* -range -complete=customlist,go#package#Complete GoDoc call go#doc#Open('new', 'split', ) +command! -nargs=* -range -complete=customlist,go#package#Complete GoDocBrowser call go#doc#OpenBrowser() + +" -- fmt +command! -nargs=0 GoFmt call go#fmt#Format(-1) +command! -nargs=0 GoFmtAutoSaveToggle call go#fmt#ToggleFmtAutoSave() +command! -nargs=0 GoImports call go#fmt#Format(1) + +" -- asmfmt +command! -nargs=0 GoAsmFmtAutoSaveToggle call go#asmfmt#ToggleAsmFmtAutoSave() + +" -- import +command! -nargs=? -complete=customlist,go#package#Complete GoDrop call go#import#SwitchImport(0, '', , '') +command! -nargs=1 -bang -complete=customlist,go#package#Complete GoImport call go#import#SwitchImport(1, '', , '') +command! -nargs=* -bang -complete=customlist,go#package#Complete GoImportAs call go#import#SwitchImport(1, , '') + +" -- linters +command! -nargs=* GoMetaLinter call go#lint#Gometa(0, ) +command! -nargs=0 GoMetaLinterAutoSaveToggle call go#lint#ToggleMetaLinterAutoSave() +command! -nargs=* GoLint call go#lint#Golint() +command! -nargs=* -bang GoVet call go#lint#Vet(0, ) +command! -nargs=* -complete=customlist,go#package#Complete GoErrCheck call go#lint#Errcheck() + +" -- alternate +command! -bang GoAlternate call go#alternate#Switch(0, '') + +" -- ctrlp +if globpath(&rtp, 'plugin/ctrlp.vim') != "" + command! -nargs=? -complete=file GoDecls call ctrlp#init(ctrlp#decls#cmd(0, )) + command! -nargs=? -complete=dir GoDeclsDir call ctrlp#init(ctrlp#decls#cmd(1, )) +endif + +" -- impl +command! -nargs=* -buffer -complete=customlist,go#impl#Complete GoImpl call go#impl#Impl() + +" -- template +command! -nargs=0 GoTemplateAutoCreateToggle call go#template#ToggleAutoCreate() + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/ftplugin/go/mappings.vim b/vim/bundle/vim-go/ftplugin/go/mappings.vim new file mode 100644 index 0000000..e1bbe46 --- /dev/null +++ b/vim/bundle/vim-go/ftplugin/go/mappings.vim @@ -0,0 +1,75 @@ +" go_jump_to_error defines whether we should pass the bang attribute to the +" command or not. This is only used for mappings, because the user can't pass +" the bang attribute to the plug mappings below. So instead of hardcoding it +" as 0 (no '!' attribute) or 1 (with '!' attribute) we pass the user setting, +" which by default is enabled. For commands the user has the ability to pass +" the '!', such as :GoBuild or :GoBuild! +if !exists("g:go_jump_to_error") + let g:go_jump_to_error = 1 +endif + +" Some handy plug mappings +nnoremap (go-run) :call go#cmd#Run(!g:go_jump_to_error) + +if has("nvim") + nnoremap (go-run-vertical) :call go#cmd#RunTerm(!g:go_jump_to_error, 'vsplit', []) + nnoremap (go-run-split) :call go#cmd#RunTerm(!g:go_jump_to_error, 'split', []) + nnoremap (go-run-tab) :call go#cmd#RunTerm(!g:go_jump_to_error, 'tabe', []) +endif + +nnoremap (go-build) :call go#cmd#Build(!g:go_jump_to_error) +nnoremap (go-generate) :call go#cmd#Generate(!g:go_jump_to_error) +nnoremap (go-install) :call go#cmd#Install(!g:go_jump_to_error) +nnoremap (go-test) :call go#cmd#Test(!g:go_jump_to_error, 0) +nnoremap (go-test-func) :call go#cmd#TestFunc(!g:go_jump_to_error) +nnoremap (go-test-compile) :call go#cmd#Test(!g:go_jump_to_error, 1) + +nnoremap (go-coverage) :call go#coverage#Buffer(!g:go_jump_to_error) +nnoremap (go-coverage-clear) :call go#coverage#Clear() +nnoremap (go-coverage-toggle) :call go#coverage#BufferToggle(!g:go_jump_to_error) +nnoremap (go-coverage-browser) :call go#coverage#Browser(!g:go_jump_to_error) + +nnoremap (go-files) :call go#tool#Files() +nnoremap (go-deps) :call go#tool#Deps() +nnoremap (go-info) :call go#tool#Info(0) +nnoremap (go-import) :call go#import#SwitchImport(1, '', expand(''), '') +nnoremap (go-imports) :call go#fmt#Format(1) + +nnoremap (go-implements) :call go#guru#Implements(-1) +nnoremap (go-callees) :call go#guru#Callees(-1) +nnoremap (go-callers) :call go#guru#Callers(-1) +nnoremap (go-describe) :call go#guru#Describe(-1) +nnoremap (go-callstack) :call go#guru#Callstack(-1) +xnoremap (go-freevars) :call go#guru#Freevars(0) +nnoremap (go-channelpeers) :call go#guru#ChannelPeers(-1) +nnoremap (go-referrers) :call go#guru#Referrers(-1) +nnoremap (go-sameids) :call go#guru#SameIds() +nnoremap (go-whicherrs) :call go#guru#Whicherrs(-1) +nnoremap (go-sameids-toggle) :call go#guru#ToggleSameIds() + +nnoremap (go-rename) :call go#rename#Rename(!g:go_jump_to_error) + +nnoremap (go-def) :call go#def#Jump('') +nnoremap (go-def-vertical) :call go#def#Jump("vsplit") +nnoremap (go-def-split) :call go#def#Jump("split") +nnoremap (go-def-tab) :call go#def#Jump("tab") + +nnoremap (go-def-pop) :call go#def#StackPop() +nnoremap (go-def-stack) :call go#def#Stack() +nnoremap (go-def-stack-clear) :call go#def#StackClear() + +nnoremap (go-doc) :call go#doc#Open("new", "split") +nnoremap (go-doc-tab) :call go#doc#Open("tabnew", "tabe") +nnoremap (go-doc-vertical) :call go#doc#Open("vnew", "vsplit") +nnoremap (go-doc-split) :call go#doc#Open("new", "split") +nnoremap (go-doc-browser) :call go#doc#OpenBrowser() + +nnoremap (go-metalinter) :call go#lint#Gometa(0) +nnoremap (go-lint) :call go#lint#Golint() +nnoremap (go-vet) :call go#lint#Vet(!g:go_jump_to_error) + +nnoremap (go-alternate-edit) :call go#alternate#Switch(0, "edit") +nnoremap (go-alternate-vertical) :call go#alternate#Switch(0, "vsplit") +nnoremap (go-alternate-split) :call go#alternate#Switch(0, "split") + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/ftplugin/go/snippets.vim b/vim/bundle/vim-go/ftplugin/go/snippets.vim new file mode 100644 index 0000000..56c0811 --- /dev/null +++ b/vim/bundle/vim-go/ftplugin/go/snippets.vim @@ -0,0 +1,48 @@ +if exists("g:go_loaded_gosnippets") + finish +endif +let g:go_loaded_gosnippets = 1 + +" by default UltiSnips +if !exists("g:go_snippet_engine") + let g:go_snippet_engine = "ultisnips" +endif + +function! s:GoUltiSnips() + if globpath(&rtp, 'plugin/UltiSnips.vim') == "" + return + endif + + if !exists("g:UltiSnipsSnippetDirectories") + let g:UltiSnipsSnippetDirectories = ["gosnippets/UltiSnips"] + else + let g:UltiSnipsSnippetDirectories += ["gosnippets/UltiSnips"] + endif +endfunction + +function! s:GoNeosnippet() + if globpath(&rtp, 'plugin/neosnippet.vim') == "" + return + endif + + let g:neosnippet#enable_snipmate_compatibility = 1 + + let gosnippets_dir = globpath(&rtp, 'gosnippets/snippets') + if type(g:neosnippet#snippets_directory) == type([]) + let g:neosnippet#snippets_directory += [gosnippets_dir] + elseif type(g:neosnippet#snippets_directory) == type("") + if strlen(g:neosnippet#snippets_directory) > 0 + let g:neosnippet#snippets_directory = g:neosnippet#snippets_directory . "," . gosnippets_dir + else + let g:neosnippet#snippets_directory = gosnippets_dir + endif + endif +endfunction + +if g:go_snippet_engine == "ultisnips" + call s:GoUltiSnips() +elseif g:go_snippet_engine == "neosnippet" + call s:GoNeosnippet() +endif + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/ftplugin/go/tagbar.vim b/vim/bundle/vim-go/ftplugin/go/tagbar.vim new file mode 100644 index 0000000..2d22fd7 --- /dev/null +++ b/vim/bundle/vim-go/ftplugin/go/tagbar.vim @@ -0,0 +1,57 @@ +" Check if tagbar is installed under plugins or is directly under rtp +" this covers pathogen + Vundle/Bundle +" +" Also make sure the ctags command exists +" +if !executable('ctags') + finish +elseif globpath(&rtp, 'plugin/tagbar.vim') == "" + finish +endif + +if !exists("g:go_gotags_bin") + let g:go_gotags_bin = "gotags" +endif + + +function! s:SetTagbar() + let bin_path = go#path#CheckBinPath(g:go_gotags_bin) + if empty(bin_path) + return + endif + + if !exists("g:tagbar_type_go") + let g:tagbar_type_go = { + \ 'ctagstype' : 'go', + \ 'kinds' : [ + \ 'p:package', + \ 'i:imports', + \ 'c:constants', + \ 'v:variables', + \ 't:types', + \ 'n:interfaces', + \ 'w:fields', + \ 'e:embedded', + \ 'm:methods', + \ 'r:constructor', + \ 'f:functions' + \ ], + \ 'sro' : '.', + \ 'kind2scope' : { + \ 't' : 'ctype', + \ 'n' : 'ntype' + \ }, + \ 'scope2kind' : { + \ 'ctype' : 't', + \ 'ntype' : 'n' + \ }, + \ 'ctagsbin' : bin_path, + \ 'ctagsargs' : '-sort -silent' + \ } + endif +endfunction + + +call s:SetTagbar() + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/ftplugin/gohtmltmpl.vim b/vim/bundle/vim-go/ftplugin/gohtmltmpl.vim new file mode 100644 index 0000000..132e3fa --- /dev/null +++ b/vim/bundle/vim-go/ftplugin/gohtmltmpl.vim @@ -0,0 +1,8 @@ +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +setlocal commentstring= + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/gosnippets/UltiSnips/go.snippets b/vim/bundle/vim-go/gosnippets/UltiSnips/go.snippets new file mode 100644 index 0000000..9db78db --- /dev/null +++ b/vim/bundle/vim-go/gosnippets/UltiSnips/go.snippets @@ -0,0 +1,451 @@ +# Snippets for Go + +priority -10 + +# shorthand variable declaration +snippet : "v := value" +${1} := ${0} +endsnippet + +# anonymous function +snippet anon "fn := func() { ... }" +${1:fn} := func() { + ${2:${VISUAL}} +} +${0} +endsnippet + +# append +snippet ap "append(slice, value)" +append(${1:slice}, ${0:value}) +endsnippet + +# append assignment +snippet ap= "a = append(a, value)" +${1:slice} = append($1, ${0:value}) +endsnippet + +# break +snippet br "break" +break +endsnippet + +# channel +snippet ch "chan Type" +chan ${0:int} +endsnippet + +# case +snippet case "case ...:" +case ${1:value}: + ${0:${VISUAL}} +endsnippet + +# constant +snippet con "const XXX Type = ..." +const ${1:NAME} ${2:Type} = ${0:0} +endsnippet + +# constants +snippet cons "const ( ... )" +const ( + ${1:NAME} ${2:Type} = ${3:value} + ${0} +) +endsnippet + +# constants with iota +snippet iota "const ( ... = iota )" +const ( + ${1:NAME} ${2:Type} = iota + ${0} +) +endsnippet + +# continue +snippet cn "continue" +continue +endsnippet + +# default case +snippet default "default: ..." +default: + ${0:${VISUAL}} +endsnippet + +# defer +snippet df "defer someFunction()" +defer ${1:func}(${2}) +${0} +endsnippet + +snippet def "defer func() { ... }" +defer func() { + ${0:${VISUAL}} +}() +endsnippet + +# defer recover +snippet defr +defer func() { + if err := recover(); err != nil { + ${0:${VISUAL}} + } +}() +endsnippet + +# gpl +snippet gpl +/* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see . +* +* Copyright (C) ${1:Author}, `strftime("%Y")` +*/ +${0} +endsnippet + +# import +snippet import "import ( ... )" +import ( + "${1:package}" +) +endsnippet + +# full interface snippet +snippet interface "interface I { ... }" +type ${1:Interface} interface { + ${2:/* TODO: add methods */} +} +endsnippet + +# if condition +snippet if "if ... { ... }" +if ${1:condition} { + ${0:${VISUAL}} +} +endsnippet + +# else snippet +snippet else +else { + ${0:${VISUAL}} +} +endsnippet + +# error snippet +snippet errn "Error return " !b +if err != nil { + return err +} +${0} +endsnippet + +# error log snippet +snippet errl "Error with log.Fatal(err)" !b +if err != nil { + log.Fatal(err) +} +${0} +endsnippet + +# error multiple return +snippet errn, "Error return with two return values" !b +if err != nil { + return ${1:nil}, err +} +${0} +endsnippet + +# error panic +snippet errp "Error panic" !b +if err != nil { + panic(${1}) +} +${0} +endsnippet + +# error test +snippet errt "Error test fatal " !b +if err != nil { + t.Fatal(err) +} +${0} +endsnippet + +# error handle +snippet errh "Error handle and return" !b +if err != nil { + ${1} + return +} +${0} +endsnippet + +# json field tag +snippet json "\`json:key\`" +\`json:"${1:`!v go#util#snippetcase(matchstr(getline("."), '\w\+'))`}"\` +endsnippet + +# yaml field tag +snippet yaml "\`yaml:key\`" +\`yaml:"${1:`!v go#util#snippetcase(matchstr(getline("."), '\w\+'))`}"\` +endsnippet + +# fallthrough +snippet ft "fallthrough" +fallthrough +endsnippet + +# for loop +snippet for "for ... { ... }" +for ${1} { + ${0:${VISUAL}} +} +endsnippet + +# for integer loop +snippet fori "for 0..N-1 { ... }" +for ${1:i} := 0; $1 < ${2:N}; $1++ { + ${0:${VISUAL}} +} +endsnippet + +# for range loop +snippet forr "for k, v := range items { ... }" +for ${2:k}, ${3:v} := range ${1} { + ${0:${VISUAL}} +} +endsnippet + +# function +snippet func "func Function(...) [error] { ... }" +func ${1:name}(${2:params})${3/(.+)/ /}`!p opening_par(snip, 3)`$3`!p closing_par(snip, 3)` { + ${0:${VISUAL}} +} +endsnippet + +# Fmt Printf debug +snippet ff "fmt.Printf(...)" +fmt.Printf("${1:${VISUAL}} = %+v\n", $1) +endsnippet + +# Fmt Println debug +snippet fn "fmt.Println(...)" +fmt.Println("${1:${VISUAL}}") +endsnippet + +# log printf +snippet lf "log.Printf(...)" +log.Printf("${1:${VISUAL}} = %+v\n", $1) +endsnippet + +# log println +snippet ln "log.Println(...)" +log.Println("${1:${VISUAL}}") +endsnippet + +# make +snippet make "make(Type, size)" +make(${1:[]string}, ${2:0})${0} +endsnippet + +# map +snippet map "map[Type]Type" +map[${1:string}]${0:int} +endsnippet + +# main() +snippet main "func main() { ... }" +func main() { + ${0:${VISUAL}} +} +endsnippet + +# method +snippet meth "func (self Type) Method(...) [error] { ... }" +func (${1:receiver} ${2:type}) ${3:name}(${4:params})${5/(.+)/ /}`!p opening_par(snip, 5)`$5`!p closing_par(snip, 5)` { + ${0:${VISUAL}} +} +endsnippet + +# ok +snippet ok "if !ok { ... }" +if !ok { + ${0:${VISUAL}} +} +endsnippet + +# package +snippet package "package ..." +// Package $1 provides ${2:...} +package ${1:main} +${0} +endsnippet + +# panic +snippet pn "panic()" +panic("${0:msg}") +endsnippet + +# return +snippet rt "return" +return ${0:${VISUAL}} +endsnippet + +# select +snippet select "select { case a := <-chan: ... }" +select { +case ${1:v1} := <-${2:chan1} + ${0} +} +endsnippet + +# struct +snippet st "type T struct { ... }" +type ${1:Type} struct { +${0} +} +endsnippet + +# switch +snippet switch "switch x { ... }" +switch ${1:var} { +case ${2:value1}: + ${0} +} +endsnippet + +# sprintf +snippet sp "fmt.Sprintf(...)" +fmt.Sprintf("%${1:s}", ${2:var}) +endsnippet + +# goroutine named function +snippet go "go someFunc(...)" +go ${1:funcName}(${0}) +endsnippet + +# goroutine anonymous function +snippet gof "go func() { ... }()" +go func() { + ${1:${VISUAL}} +}() +${0} +endsnippet + +# test function +snippet test "func TestXYZ(t *testing.T) { ... }" +func Test${1:Function}(t *testing.T) { + ${0:${VISUAL}} +} +endsnippet + +snippet hf "http.HandlerFunc" !b +func ${1:handler}(w http.ResponseWriter, r *http.Request) { + ${0:fmt.Fprintf(w, "hello world")} +} +endsnippet + +snippet hhf "mux.HandleFunc" !b +${1:http}.HandleFunc("${2:/}", func(w http.ResponseWriter, r *http.Request) { + ${0:fmt.Fprintf(w, "hello world")} +}) +endsnippet + +# quick test server +snippet tsrv "httptest.NewServer" +ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, ${1:`response`}) +})) +defer ts.Close() + +${0:someUrl} = ts.URL +endsnippet + +# test error handling +snippet ter "if err != nil { t.Errorf(...) }" +if err != nil { + t.Errorf("${0:message}") +} +endsnippet + +# test fatal error +snippet terf "if err != nil { t.Fatalf(...) }" +if err != nil { + t.Fatalf("${0:message}") +} +endsnippet + +snippet example "func ExampleXYZ() { ... }" +func Example${1:Method}() { + ${0:${VISUAL}} + // Output: +} +endsnippet + +snippet benchmark "func BenchmarkXYZ(b *testing.B) { ... }" +func Benchmark${1:Method}(b *testing.B) { + for i := 0; i < b.N; i++ { + ${0:${VISUAL}} + } +} +endsnippet + +# variable declaration +snippet var "var x Type [= ...]" +var ${1:x} ${2:Type}${3: = ${0:value}} +endsnippet + +# variables declaration +snippet vars "var ( ... )" +var ( + ${1:x} ${2:Type}${3: = ${0:value}} +) +endsnippet + +# equals fails the test if exp is not equal to act. +snippet eq "equals: test two identifiers with DeepEqual" +if !reflect.DeepEqual(${1:expected}, ${2:actual}) { + _, file, line, _ := runtime.Caller(0) + fmt.Printf("%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\n\n", filepath.Base(file), line, $1, $2) + t.FailNow() +} +endsnippet + +global !p + +import re + +# Automatically wrap return types with parentheses + +def return_values(s): + # remove everything wrapped in parentheses + s = re.sub("\(.*?\)|\([^)]*$", "", s) + return len(s.split(",")) + +def opening_par(snip, pos): + if return_values(t[pos]) > 1 and not t[pos].startswith("("): + snip.rv = "(" + else: + snip.rv = "" + +def closing_par(snip, pos): + if return_values(t[pos]) > 1: + snip.rv = ")" + else: + snip.rv = "" + +endglobal + +# vim:ft=snippets: diff --git a/vim/bundle/vim-go/gosnippets/snippets/go.snip b/vim/bundle/vim-go/gosnippets/snippets/go.snip new file mode 100644 index 0000000..2db20f5 --- /dev/null +++ b/vim/bundle/vim-go/gosnippets/snippets/go.snip @@ -0,0 +1,370 @@ +# shorthand variable declaration +snippet : +abbr v := value + ${1} := ${0} +# anonymous function +snippet anon +abbr fn := func() { ... } + ${1:fn} := func() { + ${0} + } +# append +snippet ap +abbr append(slice, value) + append(${1:slice}, ${0:value}) +# append assign +snippet ap= +abbr slice = append(slice, value) + ${1:slice} = append($1, ${0:value}) +# break +snippet br +abbr break + break +# channel +snippet ch +abbr chan Type + chan ${0:int} +# case +snippet case +abbr case ...: + case ${1:value}: + ${0} +# constant +snippet con +abbr const XXX Type = ... + const ${1:NAME} ${2:Type} = ${0:0} +# constants +snippet cons +abbr const ( ... ) + const ( + ${1:NAME} ${2:Type} = ${3:value} + ${0} + ) +# constants with iota +snippet iota +abbr const ( ... = iota ) + const ( + ${1:NAME} ${2:Type} = iota + ${0} + ) +# continue +snippet cn +abbr continue + continue +# default case +snippet default +abbr default: ... + default: + ${0} + +# defer +snippet df +abbr defer someFunction() + defer ${1:func}(${2}) + ${0} +snippet def +abbr defer func() { ... } + defer func() { + ${0} + }() +# defer recover +snippet defr + defer func() { + if err := recover(); err != nil { + ${0} + } + }() +# gpl +snippet gpl + /* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Copyright (C) ${1:Author}, `strftime("%Y")` + */ + + ${0} +# import +snippet import +abbr import ( ... ) + import ( + "${1:package}" + ) +# full interface snippet +snippet interface +abbr interface I { ... } + type ${1:Interface} interface { + ${2:/* TODO: add methods */} + } +# if condition +snippet if +abbr if ... { ... } + if ${1:condition} { + ${0} + } +# else snippet +abbr else { ... } +snippet else + else { + ${0} + } +# error snippet +snippet errn +abbr if err != nil { ... } + if err != nil { + return err + } + ${0} +# error snippet in TestFunc +snippet errt +abbr if err != nil { ... } + if err != nil { + t.Fatal(err) + } + +# error snippet in log.Fatal +snippet errl +abbr if err != nil { ... } + if err != nil { + log.Fatal(err) + } + +# error snippet with two return values +snippet errn, +abbr if err != nil { return [...], err } + if err != nil { + return ${1:nil}, err + } + ${0} + +# error snippet handle and return +snippet errh +abbr if err != nil { return } + if err != nil { + ${1} + return + } + ${0} + +# error snippet with panic +snippet errp +abbr if err != nil { ... } + if err != nil { + panic(${1}) + } + ${0} + +# json snippet +snippet json +abbr \`json:key\` + \`json:"${1:keyName}"\` + +# yaml snippet +snippet yaml +abbr \`yaml:key\` + \`yaml:"${1:keyName}"\` + +# fallthrough +snippet ft +abbr fallthrough + fallthrough +# for loop +snippet for +abbr for ... { ... } + for ${1} { + ${0} + } +# for integer loop +snippet fori +abbr for 0..N-1 { ... } + for ${1:i} := 0; $1 < ${2:N}; $1++ { + ${0} + } +# for range loop +snippet forr +abbr for k, v := range items { ... } + for ${2:k}, ${3:v} := range ${1} { + ${0} + } +# function +snippet func +abbr func function(...) [error] { ... } + func ${1:function}(${2}) ${3:error }{ + ${0} + } +# Fmt Printf debug +snippet ff +abbr fmt.Printf(...) + fmt.Printf("${1} = %+v\n", $1) + ${0} +# Fmt Println debug +snippet fn +abbr fmt.Println(...) + fmt.Println("${1}") +# log printf +snippet lf +abbr log.Printf(...) + log.Printf("${1} = %+v\n", $1) +# log println +snippet ln +abbr log.Println(...) + log.Println("${1}") +# make +snippet make +abbr make(Type, size) + make(${1:[]string}, ${2:0})${0} +# map +snippet map +abbr map[Type]Type + map[${1:string}]${0:int} +# main() +snippet main +abbr func main() { ... } +options head + func main() { + ${0} + } +# method +snippet meth +abbr func (self Type) Method(...) [error] { ... } +regexp /^meth/ + func (${1:self} ${2:Type}) ${3:Do}(${4}) ${5:error }{ + ${0} + } +# ok +snippet ok +abbr if !ok { ... } + if !ok { + ${0} + } +# package +snippet package +abbr package ... + // Package $1 provides ${2:...} + package ${1:main} + ${0} +# panic +snippet panic +alias pn +abbr panic("...") + panic("${0}") +# return +snippet return +alias rt +abbr return ... + return ${0} +# select +snippet select +abbr select { case a := <-chan: ... } + select { + case ${1:v1} := <-${2:chan1} + ${0} + } +# struct +snippet st +abbr type T struct { ... } + type ${1:Type} struct { + ${0} + } +# switch +snippet switch +abbr switch x { ... } + switch ${1:var} { + case ${2:value1}: + ${0} + } +# sprintf +snippet sp +abbr fmt.Sprintf(...) + fmt.Sprintf("%${1:s}", ${2:var}) +# goroutine named function +snippet go +abbr go someFunc(...) + go ${1:funcName}(${0}) +# goroutine anonymous function +snippet gof +abbr go func(...) { ... }(...) + go func(${1}) { + ${3:/* TODO */} + }(${2}) +# test function +snippet test +abbr func TestXYZ(t *testing.T) { ... } + func Test${1:Function}(t *testing.T) { + ${0} + } +# test server +snippet tsrv +abbr ts := httptest.NewServer(...) + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, ${1:`response`}) + })) + defer ts.Close() + + //Use testing server url (type string) somewhere + ${0:someUrl} = ts.URL +# test error +snippet ter +abbr if err != nil { t.Errorf(...) } + if err != nil { + t.Errorf("${1}") + } +# test fatal error +snippet terf +abbr if err != nil { t.Fatalf(...) } + if err != nil { + t.Fatalf("${1}") + } +# test example +snippet example + func Example${1:Method}() { + ${0} + // Output: + } +# test benchmark +snippet benchmark + func Benchmark${1:Method}(b *testing.B) { + for i := 0; i < b.N; i++ { + ${0} + } + } +# variable declaration +snippet var +abbr var x Type [= ...] + var ${1:x} ${2:Type}${3: = ${0:value\}} +# variables declaration +snippet vars +abbr var ( ... ) + var ( + ${1:x} ${2:Type}${3: = ${0:value\}} + ) +# equals fails the test if exp is not equal to act. +snippet eq +abbr equals: test two identifiers with DeepEqual + if !reflect.DeepEqual(${1:expected}, ${2:actual}) { + _, file, line, _ := runtime.Caller(0) + fmt.Printf("%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\n\n", filepath.Base(file), line, $1, $2) + t.FailNow() + } + +snippet hf +abbr http.HandlerFunc + func ${1:handler}(w http.ResponseWriter, r *http.Request) { + ${0:fmt.Fprintf(w, "hello world")} + } + +snippet hhf +abbr mux.HandleFunc(...) + ${1:http}.HandleFunc("${2:/}", func(w http.ResponseWriter, r *http.Request) { + ${0:fmt.Fprintf(w, "hello world")} + }) diff --git a/vim/bundle/vim-go/indent/go.vim b/vim/bundle/vim-go/indent/go.vim new file mode 100644 index 0000000..ba99d54 --- /dev/null +++ b/vim/bundle/vim-go/indent/go.vim @@ -0,0 +1,78 @@ +" Copyright 2011 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. +" +" indent/go.vim: Vim indent file for Go. +" +" TODO: +" - function invocations split across lines +" - general line splits (line ends in an operator) + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" C indentation is too far off useful, mainly due to Go's := operator. +" Let's just define our own. +setlocal nolisp +setlocal autoindent +setlocal indentexpr=GoIndent(v:lnum) +setlocal indentkeys+=<:>,0=},0=) + +if exists("*GoIndent") + finish +endif + +" use shiftwidth function only if it's available +if exists('*shiftwidth') + func s:sw() + return shiftwidth() + endfunc +else + func s:sw() + return &sw + endfunc +endif + +function! GoIndent(lnum) + let prevlnum = prevnonblank(a:lnum-1) + if prevlnum == 0 + " top of file + return 0 + endif + + " grab the previous and current line, stripping comments. + let prevl = substitute(getline(prevlnum), '//.*$', '', '') + let thisl = substitute(getline(a:lnum), '//.*$', '', '') + let previ = indent(prevlnum) + + let ind = previ + + if prevl =~ '[({]\s*$' + " previous line opened a block + let ind += s:sw() + endif + if prevl =~# '^\s*\(case .*\|default\):$' + " previous line is part of a switch statement + let ind += s:sw() + endif + " TODO: handle if the previous line is a label. + + if thisl =~ '^\s*[)}]' + " this line closed a block + let ind -= s:sw() + endif + + " Colons are tricky. + " We want to outdent if it's part of a switch ("case foo:" or "default:"). + " We ignore trying to deal with jump labels because (a) they're rare, and + " (b) they're hard to disambiguate from a composite literal key. + if thisl =~# '^\s*\(case .*\|default\):$' + let ind -= s:sw() + endif + + return ind +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/indent/gohtmltmpl.vim b/vim/bundle/vim-go/indent/gohtmltmpl.vim new file mode 100644 index 0000000..864913d --- /dev/null +++ b/vim/bundle/vim-go/indent/gohtmltmpl.vim @@ -0,0 +1,46 @@ +if exists("b:did_indent") + finish +endif + +runtime! indent/html.vim + +" Indent Golang HTML templates +setlocal indentexpr=GetGoHTMLTmplIndent(v:lnum) +setlocal indentkeys+==else,=end + +" Only define the function once. +if exists("*GetGoHTMLTmplIndent") + finish +endif + +function! GetGoHTMLTmplIndent(lnum) + " Get HTML indent + if exists('*HtmlIndent') + let ind = HtmlIndent() + else + let ind = HtmlIndentGet(a:lnum) + endif + + " The value of a single shift-width + if exists('*shiftwidth') + let sw = shiftwidth() + else + let sw = &sw + endif + + " If need to indent based on last line + let last_line = getline(a:lnum-1) + if last_line =~ '^\s*{{-\=\s*\%(if\|else\|range\|with\|define\|block\).*}}' + let ind += sw + endif + + " End of FuncMap block + let current_line = getline(a:lnum) + if current_line =~ '^\s*{{-\=\s*\%(else\|end\).*}}' + let ind -= sw + endif + + return ind +endfunction + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/plugin/go.vim b/vim/bundle/vim-go/plugin/go.vim new file mode 100644 index 0000000..577c72a --- /dev/null +++ b/vim/bundle/vim-go/plugin/go.vim @@ -0,0 +1,214 @@ +" install necessary Go tools +if exists("g:go_loaded_install") + finish +endif +let g:go_loaded_install = 1 + +" these packages are used by vim-go and can be automatically installed if +" needed by the user with GoInstallBinaries +let s:packages = [ + \ "github.com/nsf/gocode", + \ "github.com/alecthomas/gometalinter", + \ "golang.org/x/tools/cmd/goimports", + \ "golang.org/x/tools/cmd/guru", + \ "golang.org/x/tools/cmd/gorename", + \ "github.com/golang/lint/golint", + \ "github.com/rogpeppe/godef", + \ "github.com/kisielk/errcheck", + \ "github.com/jstemmer/gotags", + \ "github.com/klauspost/asmfmt/cmd/asmfmt", + \ "github.com/fatih/motion", + \ "github.com/fatih/gomodifytags", + \ "github.com/zmb3/gogetdoc", + \ "github.com/josharian/impl", + \ ] + +" These commands are available on any filetypes +command! GoInstallBinaries call s:GoInstallBinaries(-1) +command! GoUpdateBinaries call s:GoInstallBinaries(1) +command! -nargs=? -complete=dir GoPath call go#path#GoPath() + +" GoInstallBinaries downloads and install all necessary binaries stated in the +" packages variable. It uses by default $GOBIN or $GOPATH/bin as the binary +" target install directory. GoInstallBinaries doesn't install binaries if they +" exist, to update current binaries pass 1 to the argument. +function! s:GoInstallBinaries(updateBinaries) + let err = s:CheckBinaries() + if err != 0 + return + endif + + if go#path#Default() == "" + echohl Error + echomsg "vim.go: $GOPATH is not set and 'go env GOPATH' returns empty" + echohl None + return + endif + + let go_bin_path = go#path#BinPath() + + " change $GOBIN so go get can automatically install to it + let $GOBIN = go_bin_path + + " old_path is used to restore users own path + let old_path = $PATH + + " 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 + + " when shellslash is set on MS-* systems, shellescape puts single quotes + " around the output string. cmd on Windows does not handle single quotes + " correctly. Unsetting shellslash forces shellescape to use double quotes + " instead. + let resetshellslash = 0 + if has('win32') && &shellslash + let resetshellslash = 1 + set noshellslash + endif + + let cmd = "go get -v " + if get(g:, "go_get_update", 1) != 0 + let cmd .= "-u " + endif + + let s:go_version = matchstr(go#util#System("go version"), '\d.\d.\d') + + " https://github.com/golang/go/issues/10791 + if s:go_version > "1.4.0" && s:go_version < "1.5.0" + let cmd .= "-f " + endif + + for pkg in s:packages + let basename = fnamemodify(pkg, ":t") + let binname = "go_" . basename . "_bin" + + let bin = basename + if exists("g:{binname}") + let bin = g:{binname} + endif + + if !executable(bin) || a:updateBinaries == 1 + if a:updateBinaries == 1 + echo "vim-go: Updating ". basename .". Reinstalling ". pkg . " to folder " . go_bin_path + else + echo "vim-go: ". basename ." not found. Installing ". pkg . " to folder " . go_bin_path + endif + + + let out = go#util#System(cmd . shellescape(pkg)) + if go#util#ShellError() != 0 + echo "Error installing ". pkg . ": " . out + endif + endif + endfor + + " restore back! + let $PATH = old_path + if resetshellslash + set shellslash + endif +endfunction + +" CheckBinaries checks if the necessary binaries to install the Go tool +" commands are available. +function! s:CheckBinaries() + if !executable('go') + echohl Error | echomsg "vim-go: go executable not found." | echohl None + return -1 + endif + + if !executable('git') + echohl Error | echomsg "vim-go: git executable not found." | echohl None + return -1 + endif +endfunction + +" Autocommands +" ============================================================================ +" +function! s:echo_go_info() + if !get(g:, "go_echo_go_info", 1) + return + endif + + if !exists('v:completed_item') || empty(v:completed_item) + return + endif + let item = v:completed_item + + if !has_key(item, "info") + return + endif + + if empty(item.info) + return + endif + + redraws! | echo "vim-go: " | echohl Function | echon item.info | echohl None +endfunction + +function! s:auto_type_info() + " GoInfo automatic update + if get(g:, "go_auto_type_info", 0) + call go#tool#Info(1) + endif +endfunction + +function! s:auto_sameids() + " GoSameId automatic update + if get(g:, "go_auto_sameids", 0) + call go#guru#SameIds() + endif +endfunction + +function! s:fmt_autosave() + " Go code formatting on save + if get(g:, "go_fmt_autosave", 1) + call go#fmt#Format(-1) + endif +endfunction + +function! s:asmfmt_autosave() + " Go asm formatting on save + if get(g:, "go_asmfmt_autosave", 0) + call go#asmfmt#Format() + endif +endfunction + +function! s:metalinter_autosave() + " run gometalinter on save + if get(g:, "go_metalinter_autosave", 0) + call go#lint#Gometa(1) + endif +endfunction + +function! s:template_autocreate() + " create new template from scratch + if get(g:, "go_template_autocreate", 1) + call go#template#create() + endif +endfunction + +augroup vim-go + autocmd! + + autocmd CursorHold *.go call s:auto_type_info() + autocmd CursorHold *.go call s:auto_sameids() + + " Echo the identifier information when completion is done. Useful to see + " the signature of a function, etc... + if exists('##CompleteDone') + autocmd CompleteDone *.go call s:echo_go_info() + endif + + autocmd BufWritePre *.go call s:fmt_autosave() + autocmd BufWritePre *.s call s:asmfmt_autosave() + autocmd BufWritePost *.go call s:metalinter_autosave() + autocmd BufNewFile *.go call s:template_autocreate() + " clear SameIds when the buffer is unloaded so that loading another buffer + " in the same window doesn't highlight the most recently matched + " identifier's positions. + autocmd BufWinEnter *.go call go#guru#ClearSameIds() +augroup END + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/scripts/runtest.vim b/vim/bundle/vim-go/scripts/runtest.vim new file mode 100644 index 0000000..a096036 --- /dev/null +++ b/vim/bundle/vim-go/scripts/runtest.vim @@ -0,0 +1,81 @@ +let total_started = reltime() + +" add vim-go the only plugin inside the runtimepath +let git_root_path = system("git rev-parse --show-toplevel | tr -d '\\n'") +exe 'set rtp=' . git_root_path + +" source the passed test file +source % + +" cd into the folder of the test file +let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' +let dir = getcwd() +execute cd . expand('%:p:h') + +" initialize variables +let g:testname = expand('%') +let s:fail = 0 +let s:done = 0 +let s:logs = [] + +" get a list of all Test_ functions for the given file +set nomore +redir @q +silent function /^Test_ +redir END +let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g')) + +" Iterate over all tests and execute them +for s:test in sort(s:tests) + let started = reltime() + + call add(s:logs, printf("=== RUN %s", s:test[:-3])) + exe 'call ' . s:test + + let elapsed_time = reltimestr(reltime(started)) + let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') + + let s:done += 1 + + if len(v:errors) > 0 + let s:fail += 1 + call add(s:logs, printf("--- FAIL: %s (%ss)", s:test[:-3], elapsed_time)) + call extend(s:logs, map(v:errors, '" ". v:val')) + + " reset so we can capture failures of next test + let v:errors = [] + else + call add(s:logs, printf("--- PASS: %s (%ss)", s:test[:-3], elapsed_time)) + endif +endfor + +" pop out into the scripts folder +execute cd . fnameescape(dir) + +" create an empty fail to indicate that the test failed +if s:fail > 0 + split FAILED + write +endif + +let total_elapsed_time = reltimestr(reltime(total_started)) +let total_elapsed_time = substitute(total_elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') + +let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test') . '. Total test time: '. total_elapsed_time .'s' +call add(s:logs, "") +call add(s:logs, message) + +" store all error messages from within vim into test.log +redir > test.log +silent messages +redir END + +" also store all internal messages from s:logs: as well +split test.log +call append(line('$'), '') +call append(line('$'), 'From ' . g:testname . ':') +call append(line('$'), s:logs) +write + +" bye, bye! +qall! diff --git a/vim/bundle/vim-go/scripts/test.sh b/vim/bundle/vim-go/scripts/test.sh new file mode 100755 index 0000000..b22fd7d --- /dev/null +++ b/vim/bundle/vim-go/scripts/test.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -e + +cd $(dirname $0) + +# install dependencies +go get github.com/fatih/gomodifytags + +# cleanup test.log +if [ -f "test.log" ]; then + rm test.log +fi + +if [ -f "FAILED" ]; then + rm FAILED +fi + +for test_file in ../autoload/go/*_test.vim +do + vim -u NONE -S runtest.vim $test_file +done + +if [ -f "test.log" ]; then + cat test.log +fi + +# if Failed exists, test failed +if [ -f "FAILED" ]; then + echo 2>&1 "FAIL" + exit 1 +fi +echo 2>&1 "PASS" diff --git a/vim/bundle/vim-go/syntax/go.vim b/vim/bundle/vim-go/syntax/go.vim new file mode 100644 index 0000000..8d7560f --- /dev/null +++ b/vim/bundle/vim-go/syntax/go.vim @@ -0,0 +1,397 @@ +" Copyright 2009 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. +" +" go.vim: Vim syntax file for Go. +" +" Options: +" There are some options for customizing the highlighting; the recommended +" settings are the default values, but you can write: +" let OPTION_NAME = 0 +" in your ~/.vimrc file to disable particular options. You can also write: +" let OPTION_NAME = 1 +" to enable particular options. At present, all options default to off: +" +" - go_highlight_array_whitespace_error +" Highlights white space after "[]". +" - go_highlight_chan_whitespace_error +" Highlights white space around the communications operator that don't follow +" the standard style. +" - go_highlight_extra_types +" Highlights commonly used library types (io.Reader, etc.). +" - go_highlight_space_tab_error +" Highlights instances of tabs following spaces. +" - go_highlight_trailing_whitespace_error +" Highlights trailing white space. +" - go_highlight_string_spellcheck +" Specifies that strings should be spell checked +" - go_highlight_format_strings +" Highlights printf-style operators inside string literals. + +" Quit when a (custom) syntax file was already loaded +if exists("b:current_syntax") + finish +endif + +if !exists("g:go_highlight_array_whitespace_error") + let g:go_highlight_array_whitespace_error = 0 +endif + +if !exists("g:go_highlight_chan_whitespace_error") + let g:go_highlight_chan_whitespace_error = 0 +endif + +if !exists("g:go_highlight_extra_types") + let g:go_highlight_extra_types = 0 +endif + +if !exists("g:go_highlight_space_tab_error") + let g:go_highlight_space_tab_error = 0 +endif + +if !exists("g:go_highlight_trailing_whitespace_error") + let g:go_highlight_trailing_whitespace_error = 0 +endif + +if !exists("g:go_highlight_operators") + let g:go_highlight_operators = 0 +endif + +if !exists("g:go_highlight_functions") + let g:go_highlight_functions = 0 +endif + +if !exists("g:go_highlight_methods") + let g:go_highlight_methods = 0 +endif + +if !exists("g:go_highlight_fields") + let g:go_highlight_fields = 0 +endif + +if !exists("g:go_highlight_types") + let g:go_highlight_types = 0 +endif + +if !exists("g:go_highlight_build_constraints") + let g:go_highlight_build_constraints = 0 +endif + +if !exists("g:go_highlight_string_spellcheck") + let g:go_highlight_string_spellcheck = 1 +endif + +if !exists("g:go_highlight_format_strings") + let g:go_highlight_format_strings = 1 +endif + +if !exists("g:go_highlight_generate_tags") + let g:go_highlight_generate_tags = 0 +endif + +syn case match + +syn keyword goDirective package import +syn keyword goDeclaration var const + +hi def link goDirective Statement +hi def link goDeclaration Keyword + +" Keywords within functions +syn keyword goStatement defer go goto return break continue fallthrough +syn keyword goConditional if else switch select +syn keyword goLabel case default +syn keyword goRepeat for range + +hi def link goStatement Statement +hi def link goConditional Conditional +hi def link goLabel Label +hi def link goRepeat Repeat + +" Predefined types +syn keyword goType chan map bool string error +syn keyword goSignedInts int int8 int16 int32 int64 rune +syn keyword goUnsignedInts byte uint uint8 uint16 uint32 uint64 uintptr +syn keyword goFloats float32 float64 +syn keyword goComplexes complex64 complex128 + +hi def link goType Type +hi def link goSignedInts Type +hi def link goUnsignedInts Type +hi def link goFloats Type +hi def link goComplexes Type + + +" Predefined functions and values +syn match goBuiltins /\<\v(append|cap|close|complex|copy|delete|imag|len)\ze\(/ +syn match goBuiltins /\<\v(make|new|panic|print|println|real|recover)\ze\(/ +syn keyword goBoolean true false +syn keyword goPredefinedIdentifiers nil iota + +hi def link goBuiltins Keyword +hi def link goBoolean Boolean +hi def link goPredefinedIdentifiers goBoolean + +" Comments; their contents +syn keyword goTodo contained TODO FIXME XXX BUG +syn cluster goCommentGroup contains=goTodo +syn region goComment start="/\*" end="\*/" contains=@goCommentGroup,@Spell +syn region goComment start="//" end="$" contains=goGenerate,@goCommentGroup,@Spell + +hi def link goComment Comment +hi def link goTodo Todo + +if g:go_highlight_generate_tags != 0 + syn match goGenerateVariables contained /\(\$GOARCH\|\$GOOS\|\$GOFILE\|\$GOLINE\|\$GOPACKAGE\|\$DOLLAR\)\>/ + syn region goGenerate start="^\s*//go:generate" end="$" contains=goGenerateVariables + hi def link goGenerate PreProc + hi def link goGenerateVariables Special +endif + +" Go escapes +syn match goEscapeOctal display contained "\\[0-7]\{3}" +syn match goEscapeC display contained +\\[abfnrtv\\'"]+ +syn match goEscapeX display contained "\\x\x\{2}" +syn match goEscapeU display contained "\\u\x\{4}" +syn match goEscapeBigU display contained "\\U\x\{8}" +syn match goEscapeError display contained +\\[^0-7xuUabfnrtv\\'"]+ + +hi def link goEscapeOctal goSpecialString +hi def link goEscapeC goSpecialString +hi def link goEscapeX goSpecialString +hi def link goEscapeU goSpecialString +hi def link goEscapeBigU goSpecialString +hi def link goSpecialString Special +hi def link goEscapeError Error + +" Strings and their contents +syn cluster goStringGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU,goEscapeError +if g:go_highlight_string_spellcheck != 0 + syn region goString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup,@Spell + syn region goRawString start=+`+ end=+`+ contains=@Spell +else + syn region goString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup + syn region goRawString start=+`+ end=+`+ +endif + +if g:go_highlight_format_strings != 0 + syn match goFormatSpecifier /\([^%]\(%%\)*\)\@<=%[-#0 +]*\%(\*\|\d\+\)\=\%(\.\%(\*\|\d\+\)\)*[vTtbcdoqxXUeEfgGsp]/ contained containedin=goString + hi def link goFormatSpecifier goSpecialString +endif + +hi def link goString String +hi def link goRawString String + +" Characters; their contents +syn cluster goCharacterGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU +syn region goCharacter start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=@goCharacterGroup + +hi def link goCharacter Character + +" Regions +syn region goBlock start="{" end="}" transparent fold +syn region goParen start='(' end=')' transparent + +" Integers +syn match goDecimalInt "\<-\=\d\+\%([Ee][-+]\=\d\+\)\=\>" +syn match goHexadecimalInt "\<-\=0[xX]\x\+\>" +syn match goOctalInt "\<-\=0\o\+\>" +syn match goOctalError "\<-\=0\o*[89]\d*\>" + +hi def link goDecimalInt Integer +hi def link goHexadecimalInt Integer +hi def link goOctalInt Integer +hi def link goOctalError Error +hi def link Integer Number + +" Floating point +syn match goFloat "\<-\=\d\+\.\d*\%([Ee][-+]\=\d\+\)\=\>" +syn match goFloat "\<-\=\.\d\+\%([Ee][-+]\=\d\+\)\=\>" + +hi def link goFloat Float + +" Imaginary literals +syn match goImaginary "\<-\=\d\+i\>" +syn match goImaginary "\<-\=\d\+[Ee][-+]\=\d\+i\>" +syn match goImaginaryFloat "\<-\=\d\+\.\d*\%([Ee][-+]\=\d\+\)\=i\>" +syn match goImaginaryFloat "\<-\=\.\d\+\%([Ee][-+]\=\d\+\)\=i\>" + +hi def link goImaginary Number +hi def link goImaginaryFloat Float + +" Spaces after "[]" +if g:go_highlight_array_whitespace_error != 0 + syn match goSpaceError display "\(\[\]\)\@<=\s\+" +endif + +" Spacing errors around the 'chan' keyword +if g:go_highlight_chan_whitespace_error != 0 + " receive-only annotation on chan type + " + " \(\\)\@\)\@\)\@=" + + " send-only annotation on chan type + " + " \(<-\)\@ (only pick chan when it doesn't come after an arrow) + " this prevents picking up '<-chan <-chan' but not 'chan <-' + syn match goSpaceError display "\(\(<-\)\@\)\@<=\s\+\(<-\)\@=" + + " value-ignoring receives in a few contexts + syn match goSpaceError display "\(\(^\|[={(,;]\)\s*<-\)\@<=\s\+" +endif + +" Extra types commonly seen +if g:go_highlight_extra_types != 0 + syn match goExtraType /\/ + syn match goExtraType /\/ + syn match goExtraType /\/ + syn match goExtraType /\/ +endif + +" Space-tab error +if g:go_highlight_space_tab_error != 0 + syn match goSpaceError display " \+\t"me=e-1 +endif + +" Trailing white space error +if g:go_highlight_trailing_whitespace_error != 0 + syn match goSpaceError display excludenl "\s\+$" +endif + +hi def link goExtraType Type +hi def link goSpaceError Error + + + +" included from: https://github.com/athom/more-colorful.vim/blob/master/after/syntax/go.vim +" +" Comments; their contents +syn keyword goTodo contained NOTE +hi def link goTodo Todo + +syn match goVarArgs /\.\.\./ + +" Operators; +if g:go_highlight_operators != 0 + " match single-char operators: - + % < > ! & | ^ * = + " and corresponding two-char operators: -= += %= <= >= != &= |= ^= *= == + syn match goOperator /[-+%<>!&|^*=]=\?/ + " match / and /= + syn match goOperator /\/\%(=\|\ze[^/*]\)/ + " match two-char operators: << >> &^ + " and corresponding three-char operators: <<= >>= &^= + syn match goOperator /\%(<<\|>>\|&^\)=\?/ + " match remaining two-char operators: := && || <- ++ -- + syn match goOperator /:=\|||\|<-\|++\|--/ + " match ... + + hi def link goPointerOperator goOperator + hi def link goVarArgs goOperator +endif +hi def link goOperator Operator + +" Functions; +if g:go_highlight_functions != 0 + syn match goDeclaration /\/ nextgroup=goReceiver,goFunction skipwhite skipnl + syn match goReceiver /(\(\w\|[ *]\)\+)/ contained nextgroup=goFunction contains=goReceiverVar skipwhite skipnl + syn match goReceiverVar /\w\+/ nextgroup=goPointerOperator,goReceiverType skipwhite skipnl contained + syn match goPointerOperator /\*/ nextgroup=goReceiverType contained skipwhite skipnl + syn match goReceiverType /\w\+/ contained + syn match goFunction /\w\+/ contained + syn match goFunctionCall /\w\+\ze(/ contains=GoBuiltins,goDeclaration +else + syn keyword goDeclaration func +endif +hi def link goFunction Function +hi def link goFunctionCall Type + +" Methods; +if g:go_highlight_methods != 0 + syn match goMethodCall /\.\w\+\ze(/hs=s+1 +endif +hi def link goMethodCall Type + +" Fields; +if g:go_highlight_fields != 0 + syn match goField /\.\w\+\([.\ \n\r\:\)\[,]\)\@=/hs=s+1 +endif +hi def link goField Identifier + +" Structs & Interfaces; +if g:go_highlight_types != 0 + syn match goTypeConstructor /\<\w\+{/he=e-1 + syn match goTypeDecl /\/ nextgroup=goTypeName skipwhite skipnl + syn match goTypeName /\w\+/ contained nextgroup=goDeclType skipwhite skipnl + syn match goDeclType /\/ skipwhite skipnl + hi def link goReceiverType Type +else + syn keyword goDeclType struct interface + syn keyword goDeclaration type +endif +hi def link goTypeConstructor Type +hi def link goTypeName Type +hi def link goTypeDecl Keyword +hi def link goDeclType Keyword + +" Build Constraints +if g:go_highlight_build_constraints != 0 + syn match goBuildKeyword display contained "+build" + " Highlight the known values of GOOS, GOARCH, and other +build options. + syn keyword goBuildDirectives contained + \ android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 + \ solaris windows 386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 + \ ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc + \ s390 s390x sparc sparc64 cgo ignore race + + " Other words in the build directive are build tags not listed above, so + " avoid highlighting them as comments by using a matchgroup just for the + " start of the comment. + " The rs=s+2 option lets the \s*+build portion be part of the inner region + " instead of the matchgroup so it will be highlighted as a goBuildKeyword. + syn region goBuildComment matchgroup=goBuildCommentStart + \ start="//\s*+build\s"rs=s+2 end="$" + \ contains=goBuildKeyword,goBuildDirectives + hi def link goBuildCommentStart Comment + hi def link goBuildDirectives Type + hi def link goBuildKeyword PreProc + + " One or more line comments that are followed immediately by a "package" + " declaration are treated like package documentation, so these must be + " matched as comments to avoid looking like working build constraints. + " The he, me, and re options let the "package" itself be highlighted by + " the usual rules. + syn region goPackageComment start=/\v(\/\/.*\n)+\s*package/ + \ end=/\v\n\s*package/he=e-7,me=e-7,re=e-7 + \ contains=@goCommentGroup,@Spell + hi def link goPackageComment Comment +endif + +" :GoCoverage commands +hi def link goCoverageNormalText Comment + +function! s:hi() + hi def link goSameId Search + + " :GoCoverage commands + hi def goCoverageCovered ctermfg=green guifg=#A6E22E + hi def goCoverageUncover ctermfg=red guifg=#F92672 +endfunction + +augroup vim-go-hi + autocmd! + autocmd ColorScheme * call s:hi() +augroup end +call s:hi() + +" Search backwards for a global declaration to start processing the syntax. +"syn sync match goSync grouphere NONE /^\(const\|var\|type\|func\)\>/ + +" There's a bug in the implementation of grouphere. For now, use the +" following as a more expensive/less precise workaround. +syn sync minlines=500 + +let b:current_syntax = "go" + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/syntax/godefstack.vim b/vim/bundle/vim-go/syntax/godefstack.vim new file mode 100644 index 0000000..e4eefff --- /dev/null +++ b/vim/bundle/vim-go/syntax/godefstack.vim @@ -0,0 +1,20 @@ +if exists("b:current_syntax") + finish +endif + +syn match godefStackComment '^".*' +syn match godefLinePrefix '^[>\s]\s' nextgroup=godefStackEntryNumber contains=godefStackCurrentPosition +syn match godefStackEntryNumber '\d\+' nextgroup=godefStackFilename skipwhite +syn match godefStackCurrentPosition '>' contained +syn match godefStackFilename '[^|]\+' contained nextgroup=godefStackEntryLocation +syn region godefStackEntryLocation oneline start='|' end='|' contained contains=godefStackEntryLocationNumber +syn match godefStackEntryLocationNumber '\d\+' contained display + +let b:current_syntax = "godefstack" + +hi def link godefStackComment Comment +hi def link godefStackCurrentPosition Special +hi def link godefStackFilename Directory +hi def link godefStackEntryLocationNumber LineNr + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/syntax/gohtmltmpl.vim b/vim/bundle/vim-go/syntax/gohtmltmpl.vim new file mode 100644 index 0000000..f53fbc6 --- /dev/null +++ b/vim/bundle/vim-go/syntax/gohtmltmpl.vim @@ -0,0 +1,15 @@ +if exists("b:current_syntax") + finish +endif + +if !exists("main_syntax") + let main_syntax = 'html' +endif + +runtime! syntax/gotexttmpl.vim +runtime! syntax/html.vim +unlet b:current_syntax + +let b:current_syntax = "gohtmltmpl" + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/syntax/gotexttmpl.vim b/vim/bundle/vim-go/syntax/gotexttmpl.vim new file mode 100644 index 0000000..ab8b1b6 --- /dev/null +++ b/vim/bundle/vim-go/syntax/gotexttmpl.vim @@ -0,0 +1,85 @@ +" Copyright 2011 The Go Authors. All rights reserved. +" Use of this source code is governed by a BSD-style +" license that can be found in the LICENSE file. +" +" gotexttmpl.vim: Vim syntax file for Go templates. + +" Quit when a (custom) syntax file was already loaded +if exists("b:current_syntax") + finish +endif + +syn case match + +" Go escapes +syn match goEscapeOctal display contained "\\[0-7]\{3}" +syn match goEscapeC display contained +\\[abfnrtv\\'"]+ +syn match goEscapeX display contained "\\x\x\{2}" +syn match goEscapeU display contained "\\u\x\{4}" +syn match goEscapeBigU display contained "\\U\x\{8}" +syn match goEscapeError display contained +\\[^0-7xuUabfnrtv\\'"]+ + +hi def link goEscapeOctal goSpecialString +hi def link goEscapeC goSpecialString +hi def link goEscapeX goSpecialString +hi def link goEscapeU goSpecialString +hi def link goEscapeBigU goSpecialString +hi def link goSpecialString Special +hi def link goEscapeError Error + +" Strings and their contents +syn cluster goStringGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU,goEscapeError +syn region goString contained start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup +syn region goRawString contained start=+`+ end=+`+ + +hi def link goString String +hi def link goRawString String + +" Characters; their contents +syn cluster goCharacterGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU +syn region goCharacter contained start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=@goCharacterGroup + +hi def link goCharacter Character + +" Integers +syn match goDecimalInt contained "\<\d\+\([Ee]\d\+\)\?\>" +syn match goHexadecimalInt contained "\<0x\x\+\>" +syn match goOctalInt contained "\<0\o\+\>" +syn match goOctalError contained "\<0\o*[89]\d*\>" +syn cluster goInt contains=goDecimalInt,goHexadecimalInt,goOctalInt +" Floating point +syn match goFloat contained "\<\d\+\.\d*\([Ee][-+]\d\+\)\?\>" +syn match goFloat contained "\<\.\d\+\([Ee][-+]\d\+\)\?\>" +syn match goFloat contained "\<\d\+[Ee][-+]\d\+\>" +" Imaginary literals +syn match goImaginary contained "\<\d\+i\>" +syn match goImaginary contained "\<\d\+\.\d*\([Ee][-+]\d\+\)\?i\>" +syn match goImaginary contained "\<\.\d\+\([Ee][-+]\d\+\)\?i\>" +syn match goImaginary contained "\<\d\+[Ee][-+]\d\+i\>" + +hi def link goInt Number +hi def link goFloat Number +hi def link goImaginary Number + +" Token groups +syn cluster gotplLiteral contains=goString,goRawString,goCharacter,@goInt,goFloat,goImaginary +syn keyword gotplControl contained if else end range with template +syn keyword gotplFunctions contained and html index js len not or print printf println urlquery eq ne lt le gt ge +syn match gotplVariable contained /\$[a-zA-Z0-9_]*\>/ +syn match goTplIdentifier contained /\.[^\s}]+\>/ + +hi def link gotplControl Keyword +hi def link gotplFunctions Function +hi def link goTplVariable Special + +syn region gotplAction start="{{" end="}}" contains=@gotplLiteral,gotplControl,gotplFunctions,gotplVariable,goTplIdentifier display +syn region gotplAction start="\[\[" end="\]\]" contains=@gotplLiteral,gotplControl,gotplFunctions,gotplVariable display +syn region goTplComment start="{{\(- \)\?/\*" end="\*/\( -\)\?}}" display +syn region goTplComment start="\[\[\(- \)\?/\*" end="\*/\( -\)\?\]\]" display + +hi def link gotplAction PreProc +hi def link goTplComment Comment + +let b:current_syntax = "gotexttmpl" + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/syntax/vimgo.vim b/vim/bundle/vim-go/syntax/vimgo.vim new file mode 100644 index 0000000..3a2204c --- /dev/null +++ b/vim/bundle/vim-go/syntax/vimgo.vim @@ -0,0 +1,13 @@ +if exists("b:current_syntax") + finish +endif + +let b:current_syntax = "vimgo" + +syn match goInterface /^\S*/ +syn region goTitle start="\%1l" end=":" + +hi def link goInterface Type +hi def link goTitle Label + +" vim: sw=2 ts=2 et diff --git a/vim/bundle/vim-go/templates/hello_world.go b/vim/bundle/vim-go/templates/hello_world.go new file mode 100644 index 0000000..50e8d8d --- /dev/null +++ b/vim/bundle/vim-go/templates/hello_world.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("vim-go") +}