Initial commit

This commit is contained in:
2016-12-27 19:38:56 -07:00
commit bace104fdd
1636 changed files with 125236 additions and 0 deletions

View File

@@ -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](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.

View File

@@ -0,0 +1,28 @@
### Actual behavior
Write here what's happening ...
### Expected behavior
Write here what you're expecting ...
### Steps to reproduce:
Please create a reproducible case of your problem. 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

View File

@@ -0,0 +1 @@
doc/tags

View File

@@ -0,0 +1,143 @@
## 1.8 (unplanned)
FEATURES:
* 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]
* 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. Checkout the demo to see it in action: https://github.com/fatih/vim-go/pull/927 [gh-927]
* **`:GoSameIds`** support. When called highlights all same identifiers in the current file. Can be also enabled to highlight identifiers automatically. Checkout the demo to see it in action: https://twitter.com/fatih/status/753673709278339072. [gh-936]
* Add new `errp` snippet to expand an `if err != nil { panic() }` clause [gh-926]
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: fix indentations on all files to **2-spaces/no tabs**. This is now the default vim-go style across all VimL files [gh-915]
* Syntax: improved syntax highglighting performance for methods, fields, structs and interface type declarations [gh-917]
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]
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 `<C-w><C-]>` and `<C-w>]>` 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 `<Plug>(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

View File

@@ -0,0 +1,58 @@
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.

View File

@@ -0,0 +1,301 @@
# vim-go
Go (golang) support for Vim, which comes with pre-defined sensible settings (like
auto gofmt on save), with autocomplete, snippet support, improved syntax
highlighting, go toolchain commands, and more. If needed vim-go installs all
necessary binaries for providing seamless Vim integration with current
commands. It's highly customizable and each individual feature can be
disabled/enabled easily.
![vim-go](https://dl.dropboxusercontent.com/u/174404/vim-go-2.png)
## Features
* 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 it with `:GoInstall` or test
them with `:GoTest` (also supports running single tests via `:GoTestFunc`)
* Quickly execute your current file/files with `:GoRun`
* Automatic `GOPATH` detection based on the directory structure (i.e. `gb`
projects, `godep` vendored projects)
* Change or display `GOPATH` with `:GoPath`
* Create a coverage profile and display annotated source code 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`
list.
* Jump to function or type declarations with `:GoDecls` or `:GoDeclsDir`
* A async launcher for the go command is implemented for Neovim, fully async
building and testing (beta).
* Integrated with the Neovim terminal, launch `:GoRun` and other go commands
in their own new terminal. (beta)
* Alternate between implementation and test code with `:GoAlternate`
## Install
Master branch is supposed to be a development branch. So stuff here can break and change.
Please try use always the [latest release](https://github.com/fatih/vim-go/releases/latest)
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 oriented vim plugins. For Pathogen just clone the repo. For other
plugin managers add the appropriate lines and execute the plugin's install
command.
* [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'`
* [NeoBundle](https://github.com/Shougo/neobundle.vim)
* `NeoBundle 'fatih/vim-go'`
* [Vundle](https://github.com/gmarik/vundle)
* `Plugin 'fatih/vim-go'`
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 invoked, all necessary binaries will be
automatically downloaded and installed to your `$GOBIN` environment (if not set
it will use `$GOPATH/bin`). Note that this command requires `git` for fetching
the individual Go packages. Additionally, use `:GoUpdateBinaries` to update the
installed binaries.
### Optional
* Autocompletion is enabled by default via `<C-x><C-o>`. To get real-time
completion (completion by type) install:
[neocomplete](https://github.com/Shougo/neocomplete.vim) for Vim or
[deoplete](https://github.com/Shougo/deoplete.nvim) and
[deoplete-go](https://github.com/zchee/deoplete-go) for NeoVim
* To display source code tag information on a sidebar install
[tagbar](https://github.com/majutsushi/tagbar).
* For snippet features install:
[neosnippet](https://github.com/Shougo/neosnippet.vim) or
[ultisnips](https://github.com/SirVer/ultisnips).
* Screenshot color scheme is a slightly modified molokai:
[fatih/molokai](https://github.com/fatih/molokai).
* For a better documentation viewer checkout:
[go-explorer](https://github.com/garyburd/go-explorer).
## Usage
Many of the plugin's [features](#features) are enabled by default. There are no
additional settings needed. All usages and commands are listed in
`doc/vim-go.txt`. Note that help tags needs to be populated. Check your plugin
manager settings to generate the documentation (some do it automatically).
After that just open the help page to see all commands:
:help vim-go
## Example Mappings
vim-go has several `<Plug>` mappings which can be used to create custom
mappings. Unless otherwise specified, none of these mappings are enabled
by default. Here some examples you might find useful:
Run commands such as `go run` for the current file with `<leader>r` or `go
build` and `go test` for the current package with `<leader>b` and `<leader>t`
respectively. Display beautifully annotated source code to see which functions
are covered with `<leader>c`.
```vim
au FileType go nmap <leader>r <Plug>(go-run)
au FileType go nmap <leader>b <Plug>(go-build)
au FileType go nmap <leader>t <Plug>(go-test)
au FileType go nmap <leader>c <Plug>(go-coverage)
```
By default the mapping `gd` is enabled, which opens the target identifier in
current buffer. You can also open the definition/declaration, in a new vertical,
horizontal, or tab, for the word under your cursor:
```vim
au FileType go nmap <Leader>ds <Plug>(go-def-split)
au FileType go nmap <Leader>dv <Plug>(go-def-vertical)
au FileType go nmap <Leader>dt <Plug>(go-def-tab)
```
Open the relevant Godoc for the word under the cursor with `<leader>gd` or open
it vertically with `<leader>gv`
```vim
au FileType go nmap <Leader>gd <Plug>(go-doc)
au FileType go nmap <Leader>gv <Plug>(go-doc-vertical)
```
Or open the Godoc in browser
```vim
au FileType go nmap <Leader>gb <Plug>(go-doc-browser)
```
Show a list of interfaces which is implemented by the type under your cursor
with `<leader>s`
```vim
au FileType go nmap <Leader>s <Plug>(go-implements)
```
Show type info for the word under your cursor with `<leader>i` (useful if you
have disabled auto showing type info via `g:go_auto_type_info`)
```vim
au FileType go nmap <Leader>i <Plug>(go-info)
```
Rename the identifier under the cursor to a new name
```vim
au FileType go nmap <Leader>e <Plug>(go-rename)
```
More `<Plug>` mappings can be seen with `:he go-mappings`. Also these are just
recommendations, you are free to create more advanced mappings or functions
based on `:he go-commands`.
## Settings
Below are some settings you might find useful. For the full list see `:he
go-settings`.
By default syntax-highlighting for Functions, Methods and Structs is disabled.
To change it:
```vim
let g:go_highlight_functions = 1
let g:go_highlight_methods = 1
let g:go_highlight_fields = 1
let g:go_highlight_types = 1
let g:go_highlight_operators = 1
let g:go_highlight_build_constraints = 1
```
Enable goimports to automatically insert import paths instead of gofmt:
```vim
let g:go_fmt_command = "goimports"
```
By default vim-go shows errors for the fmt command, to disable it:
```vim
let g:go_fmt_fail_silently = 1
```
Disable auto fmt on save:
```vim
let g:go_fmt_autosave = 0
```
Disable opening browser after posting your snippet to `play.golang.org`:
```vim
let g:go_play_open_browser = 0
```
By default when `:GoInstallBinaries` is called, the binaries are installed to
`$GOBIN` or `$GOPATH/bin`. To change it:
```vim
let g:go_bin_path = expand("~/.gotools")
let g:go_bin_path = "/home/fatih/.mypath" "or give absolute path
```
Disable updating dependencies when installing/updating binaries:
```vim
let g:go_get_update = 0
```
### Using with Neovim (beta)
Note: Neovim currently is not a first class citizen for vim-go. You are free
to open bugs but I'm not going to look at them. Even though I'm using Neovim
myself, Neovim itself is still alpha. So vim-go might not work well as good as
in Vim. I'm happy to accept pull requests or very detailed bug reports.
Run `:GoRun` in a new tab, horizontal split or vertical split terminal
```vim
au FileType go nmap <leader>rt <Plug>(go-run-tab)
au FileType go nmap <Leader>rs <Plug>(go-run-split)
au FileType go nmap <Leader>rv <Plug>(go-run-vertical)
```
By default new terminals are opened in a vertical split. To change it
```vim
let g:go_term_mode = "split"
```
By default the testing commands run asynchronously in the background and
display results with `go#jobcontrol#Statusline()`. To make them run in a new
terminal
```vim
let g:go_term_enabled = 1
```
### Using with Syntastic
Sometimes when using both `vim-go` and `syntastic` Vim will start lagging while
saving and opening files. The following fixes this:
```vim
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:
```vim
let g:go_list_type = "quickfix"
```
## More info
Check out the [Wiki](https://github.com/fatih/vim-go/wiki) page for more
information. It includes
[Screencasts](https://github.com/fatih/vim-go/wiki/Screencasts), an [FAQ
section](https://github.com/fatih/vim-go/wiki/FAQ-Troubleshooting), and many
other [various pieces](https://github.com/fatih/vim-go/wiki) of information.
## Donation
People have asked for this for a long time, now you can be a fully supporter by
[being a patron](https://www.patreon.com/fatih)! This is fully optional and is
just a way to support vim-go's ongoing development directly. Thanks!
[https://www.patreon.com/fatih](https://www.patreon.com/fatih)
## Credits
* Go Authors for official vim plugins
* Gocode, Godef, Golint, Guru, Goimports, Gotags, Errcheck projects and
authors of those projects.
* Other vim-plugins, thanks for inspiration (vim-golang, go.vim, vim-gocode,
vim-godef)
* [Contributors](https://github.com/fatih/vim-go/graphs/contributors) of vim-go
## License
The BSD 3-Clause License - see `LICENSE` for more details

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env rake
task :ci => [:dump, :test]
task :dump do
sh 'vim --version'
end
# Firstly, `bundle install; bundle install --deployment`
# Then, `rake test`
task :test do
sh 'bundle exec vim-flavor test'
end

View File

@@ -0,0 +1,6 @@
{
"name": "vim-go",
"description": "Full featured Go (golang) support for Vim.",
"author": "Fatih Arslan <fatih@arslan.io>",
"repository" : {"type": "git", "url": "https://github.com/fatih/vim-go.git"}
}

View File

@@ -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()
cal s:enable_syntax()
return s:decls
endfunction
function! ctrlp#decls#exit()
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 <cr> <c-v> <c-t> or <c-x>
" the values are 'e', 'v', 't' and 'h', respectively
" a:str the selected string
function! ctrlp#decls#accept(mode, str)
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()
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()
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, ...)
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

View File

@@ -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)
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

View File

@@ -0,0 +1,54 @@
" 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=1]
"
" 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()
" Save state.
let l:curw = winsaveview()
" Write the current buffer to a tempfile.
let l:tmpname = tempname()
call writefile(getline(1, '$'), 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
call rename(l:tmpname, expand('%'))
silent edit!
let &fileformat = old_fileformat
let &syntax = &syntax
endif
" Restore the cursor/window positions.
call winrestview(l:curw)
endfunction
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,359 @@
if !exists("g:go_dispatch_enabled")
let g:go_dispatch_enabled = 0
endif
function! go#cmd#autowrite()
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, ...)
" 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
let goargs = go#util#Shelllist(goargs, 1)
" 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 we have nvim, call it asynchronously and return early ;)
if has('nvim')
call go#util#EchoProgress("building dispatched ...")
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 g:go_dispatch_enabled && exists(':Make') == 2
call go#util#EchoProgress("building dispatched ...")
silent! exe 'Make'
elseif 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)
if !a:bang
call go#list#JumpToFirst(l:listtype)
endif
else
call go#util#EchoSuccess("[build] SUCCESS")
endif
let &makeprg = default_makeprg
let $GOPATH = old_gopath
endfunction
" Run runs the current file (and their dependencies if any) in a new terminal.
function! go#cmd#RunTerm(bang, mode, files)
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, ...)
if has('nvim')
call go#cmd#RunTerm(a:bang, '', a:000)
return
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 g:go_dispatch_enabled && exists(':Make') == 2
silent! exe 'Make'
elseif 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)
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, ...)
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 g:go_dispatch_enabled && exists(':Make') == 2
call go#util#EchoProgress("building dispatched ...")
silent! exe 'Make'
elseif 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)
if !a:bang
call go#list#JumpToFirst(l:listtype)
endif
else
redraws! | echon "vim-go: " | echohl Function | echon "installed to ". $GOPATH | echohl None
endif
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, ...)
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
" expand all wildcards(i.e: '%' to the current file name)
let goargs = map(copy(a:000), "expand(v:val)")
if !has('nvim')
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 a:compile
echon "vim-go: " | echohl Identifier | echon "compiling tests ..." | echohl None
else
echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None
endif
if has('nvim')
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)
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, ...)
" 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, ...)
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 g:go_dispatch_enabled && exists(':Make') == 2
silent! exe 'Make'
elseif 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
" -----------------------
" | Neovim job handlers |
" -----------------------
let s:test_compile_handlers = {}
function! s:test_compile_handler(job, exit_status, data)
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

View File

@@ -0,0 +1,156 @@
function! s:gocodeCurrentBuffer()
let buf = getline(1, '$')
if &encoding != 'utf-8'
let buf = map(buf, 'iconv(v:val, &encoding, "utf-8")')
endif
if &l:fileformat == 'dos'
" XXX: line2byte() depend on 'fileformat' option.
" so if fileformat is 'dos', 'buf' must include '\r'.
let buf = map(buf, 'v:val."\r"')
endif
let file = tempname()
call writefile(buf, file)
return file
endfunction
function! s:gocodeCommand(cmd, preargs, args)
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 $GOPATH = go#path#Detect()
let result = go#util#System(printf('%s %s %s %s', go#util#Shellescape(bin_path), join(a:preargs), go#util#Shellescape(a:cmd), join(a:args)))
let $GOPATH = old_gopath
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)
return '-in=' . a:filename
endfunction
let s:optionsEnabled = 0
function! s:gocodeEnableOptions()
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))))
endfunction
function! s:toBool(val)
if a:val | return 'true ' | else | return 'false' | endif
endfunction
function! s:gocodeAutocomplete()
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()
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("<cword>") . '\>'
" 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)
" 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)
let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '')
return a:val
endfunction
function! go#complete#Complete(findstart, base)
"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
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,285 @@
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, ...)
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, ...)
" 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 tests files available")
return
endif
finally
execute cd . fnameescape(dir)
endtry
let s:toggle = 1
let l:tmpname = tempname()
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()
" only reset the syntax if the user has syntax enabled
if !empty(&syntax)
if exists("g:syntax_on") | syntax enable | endif
endif
if exists("s:toggle") | let s:toggle = 0 | endif
" remove the autocmd we defined
if exists("#BufWinLeave#<buffer>")
autocmd! BufWinLeave <buffer>
endif
call clearmatches()
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, ...)
let l:tmpname = tempname()
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)
" 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)
let color = 'covered'
if a:cov.cnt == 0
let color = 'uncover'
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)
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 normaltext. 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': 'normaltext', 'pos': [cnt], 'priority': 1})
let cnt += 1
endwhile
let fname = expand('%:t')
" 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
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
syntax manual
highlight normaltext term=bold ctermfg=darkgrey guifg=#75715E
highlight covered term=bold ctermfg=green guifg=#A6E22E
highlight uncover term=bold ctermfg=red guifg=#F92672
" clear the matches if we leave the buffer
autocmd BufWinLeave <buffer> call go#coverage#Clear()
for m in matches
call matchaddpos(m.group, m.pos)
endfor
endfunction
" -----------------------
" | Neovim job handlers |
" -----------------------
let s:coverage_handler_jobs = {}
let s:coverage_browser_handler_jobs = {}
function! s:coverage_handler(job, exit_status, data)
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)
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

View File

@@ -0,0 +1,239 @@
let s:go_stack = []
let s:go_stack_level = 0
function! go#def#Jump(mode)
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
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
" 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'
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)
" append the type information to the same line so our
" jump_to_declaration() function can parse it. This makes it
" compatible with guru definition as well too
let out = join(split(out, '\n'), ':')
elseif bin_name == 'guru'
let bin_path = go#path#CheckBinPath("guru")
if empty(bin_path)
let $GOPATH = old_gopath
return
endif
let flags = ""
if exists('g:go_guru_tags')
let tags = get(g:, 'go_guru_tags')
let flags = printf(" -tags %s", tags)
endif
let fname = shellescape(fname.':#'.go#util#OffsetCursor())
let command = printf("%s %s definition %s", bin_path, flags, fname)
let out = go#util#System(command)
else
call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru]')
return
endif
if exists("l:tmpname")
call delete(l:tmpname)
endif
if go#util#ShellError() != 0
call go#util#EchoError(out)
return
endif
call s:jump_to_declaration(out, a:mode)
let $GOPATH = old_gopath
endfunction
function! s:jump_to_declaration(out, mode)
" strip line ending
let out = split(a:out, go#util#LineEnding())[0]
if go#util#IsWin()
let parts = split(out, '\(^[a-zA-Z]\)\@<!:')
else
let parts = split(out, ':')
endif
let filename = parts[0]
let line = parts[1]
let col = parts[2]
let ident = parts[3]
" Remove anything newer than the current position, just like basic
" vim tag support
if s:go_stack_level == 0
let s:go_stack = []
else
let s:go_stack = s:go_stack[0:s:go_stack_level-1]
endif
" increment the stack counter
let s:go_stack_level += 1
" push it on to the jumpstack
let stack_entry = {'line': line("."), 'col': col("."), 'file': expand('%:p'), 'ident': ident}
call add(s:go_stack, stack_entry)
" needed for restoring back user setting this is because there are two
" modes of switchbuf which we need based on the split mode
let old_switchbuf = &switchbuf
" jump to existing buffer if, 1. we have enabled it, 2. the buffer is loaded
" and 3. there is buffer window number we switch to
if get(g:, 'go_def_reuse_buffer', 0) && bufloaded(filename) != 0 && bufwinnr(filename) != -1
" jumpt to existing buffer if it exists
execute bufwinnr(filename) . 'wincmd w'
elseif a:mode == "tab"
let &switchbuf = "usetab"
if bufloaded(filename) == 0
tab split
endif
elseif a:mode == "split"
split
elseif a:mode == "vsplit"
vsplit
endif
" open the file and jump to line and column
exec 'edit '.filename
call cursor(line, col)
" also align the line to middle of the view
normal! zz
let &switchbuf = old_switchbuf
endfunction
function! go#def#SelectStackEntry()
let target_window = go#ui#GetReturnWindow()
if empty(target_window)
let target_window = winnr()
endif
let highlighted_stack_entry = matchstr(getline("."), '^..\zs\(\d\+\)')
if !empty(highlighted_stack_entry)
execute target_window . "wincmd w"
call go#def#Stack(str2nr(highlighted_stack_entry))
endif
call go#ui#CloseWindow()
endfunction
function! go#def#StackUI()
if len(s:go_stack) == 0
call go#util#EchoError("godef stack empty")
return
endif
let stackOut = ['" <Up>,<Down>:navigate <Enter>:jump <Esc>,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 <buffer> <silent> <CR> :<C-U>call go#def#SelectStackEntry()<CR>
noremap <buffer> <silent> <Esc> :<C-U>call go#ui#CloseWindow()<CR>
noremap <buffer> <silent> q :<C-U>call go#ui#CloseWindow()<CR>
endfunction
function! go#def#StackClear(...)
let s:go_stack = []
let s:go_stack_level = 0
endfunction
function! go#def#StackPop(...)
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(...)
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
exec 'edit '.target["file"]
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
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,155 @@
" 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
" 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)
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('<cword>')
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)
if len(a:content) == 0
return 1
endif
return a:content =~# '^.*: no such file or directory\n$'
endfunction
function! go#doc#OpenBrowser(...)
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, ...)
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, ' '))
else
" check if we have 'gogetdoc' and use it automatically
let bin_path = go#path#CheckBinPath('gogetdoc')
if empty(bin_path)
return
endif
let offset = go#util#OffsetCursor()
let fname = expand("%:p:gs!\\!/!")
let pos = shellescape(fname.':#'.offset)
let command = printf("%s -pos %s", bin_path, pos)
endif
let out = go#util#System(command)
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)
" 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
" 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
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 <esc> or enter
noremap <buffer> <silent> <CR> :<C-U>close<CR>
noremap <buffer> <silent> <Esc> :<C-U>close<CR>
endfunction
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,210 @@
" 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.
"
" This filetype plugin add a new commands for go buffers:
"
" :Fmt
"
" Filter the current Go buffer through gofmt.
" It tries to preserve cursor position and avoids
" replacing the buffer with stderr output.
"
" Options:
"
" g:go_fmt_command [default="gofmt"]
"
" Flag naming the gofmt executable to use.
"
" g:go_fmt_autosave [default=1]
"
" Flag to auto call :Fmt when saved file
"
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)
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
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(getline(1, '$'), l:tmpname)
if g:go_fmt_experimental == 1
" 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
endif
" get the command first so we can test it
let bin_name = g:go_fmt_command
if a:withGoimport == 1
let bin_name = g:go_goimports_bin
endif
" 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(bin_name)
if empty(bin_path)
return
endif
if bin_name != "gofmt"
" change GOPATH too, so goimports can pick up the correct library
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
endif
" populate the final command with user based fmt options
let command = bin_path . ' -w '
if a:withGoimport != 1
let command = command . g:go_fmt_options
endif
if bin_name == "goimports"
if !exists('b:goimports_vendor_compatible')
let out = go#util#System(bin_path . " --help")
if out !~ "-srcdir"
call go#util#EchoWarning("vim-go: goimports does not support srcdir. update with: :GoUpdateBinaries")
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
let command = command . '-srcdir ' . shellescape(expand("%:p:h"))
let &shellslash = ssl_save
endif
endif
" execute our command...
if go#util#IsWin()
let l:tmpname = tr(l:tmpname, '\', '/')
endif
let out = go#util#System(command . " " . l:tmpname)
if bin_name != "gofmt"
let $GOPATH = old_gopath
endif
let l:listtype = "locationlist"
"if there is no error on the temp file replace the output with the current
"file (if this fails, we can always check the outputs first line with:
"splitted =~ 'package \w\+')
if go#util#ShellError() == 0
" remove undo point caused via BufWritePre
try | silent undojoin | catch | endtry
" Replace current file with temp file, then reload buffer
let old_fileformat = &fileformat
call rename(l:tmpname, expand('%'))
silent edit!
let &fileformat = old_fileformat
let &syntax = &syntax
" clean up previous location list, but only if it's due to fmt
if exists('b:got_fmt_error') && b:got_fmt_error
let b:got_fmt_error = 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
endif
elseif g:go_fmt_fail_silently == 0
let splitted = split(out, '\n')
"otherwise get the errors and put them to location list
let errors = []
for line in splitted
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
if !empty(tokens)
call add(errors, {"filename": @%,
\"lnum": tokens[2],
\"col": tokens[3],
\"text": tokens[4]})
endif
endfor
if empty(errors)
% | " Couldn't detect gofmt error format, output errors
endif
if !empty(errors)
call go#list#Populate(l:listtype, errors)
echohl Error | echomsg "Gofmt returned error" | echohl None
endif
let b:got_fmt_error = 1
call go#list#Window(l:listtype, len(errors))
" We didn't use the temp file, so clean up
call delete(l:tmpname)
endif
if g:go_fmt_experimental == 1
" restore our undo history
silent! exe 'rundo ' . tmpundofile
call delete(tmpundofile)
endif
if g:go_fmt_experimental == 1
" 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
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,349 @@
" guru.vim -- Vim integration for the Go guru.
func! s:RunGuru(mode, format, selected, needs_scope) range abort
"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
let filename = fnamemodify(expand("%"), ':p:gs?\\?/?')
if !filereadable(filename)
" this might happen for new buffers which are not written yet
return {'err': "file does not exist"}
endif
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 filename = l:tmpname
endif
let dirname = expand('%:p:h')
let pkg = go#package#ImportPath(dirname)
" this is important, check it!
if pkg == -1 && a:needs_scope
return {'err': "current directory is not inside of a valid GOPATH"}
endif
" start constructing the 'command' variable
let command = bin_path
" enable outputting in json format
if a:format == "json"
let command .= " -json"
endif
" check for any tags
if exists('g:go_guru_tags')
let tags = get(g:, 'go_guru_tags')
let command .= printf(" -tags %s", 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 a: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
let scopes = go#util#Shelllist(scopes)
" guru expect a comma-separated list of patterns, construct it
let scope = join(scopes, ",")
let command .= printf(" -scope %s", scope)
endif
let pos = printf("#%s", go#util#OffsetCursor())
if a: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
" this is our final command
let filename .= ':'.pos
let command .= printf(' %s %s', a:mode, shellescape(filename))
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
if a:mode !=# 'what'
" the query might take time, let us give some feedback
call go#util#EchoProgress("analysing ...")
endif
" run, forrest run!!!
let out = go#util#System(command)
if exists("l:tmpname")
call delete(l:tmpname)
endif
let $GOPATH = old_gopath
if go#util#ShellError() != 0
" the output contains the error message
return {'err' : out}
endif
return {'out': out}
endfunc
" 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.
func! s:loclistSecond(output)
" backup users errorformat, will be restored once we are finished
let old_errorformat = &errorformat
" 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
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
call go#list#ParseFormat("locationlist", errformat, split(a:output, "\n"))
let errors = go#list#Get("locationlist")
call go#list#Window("locationlist", len(errors))
endfun
function! go#guru#Scope(...)
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
function! go#guru#Tags(...)
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_guru_tags
call go#util#EchoSuccess("guru tags is cleared")
else
let g:go_guru_tags = a:1
call go#util#EchoSuccess("guru tags changed to: ". a:1)
endif
return
endif
if !exists('g:go_guru_tags')
call go#util#EchoSuccess("guru tags is not set")
else
call go#util#EchoSuccess("current guru tags: ". a:1)
endif
endfunction
" Show 'implements' relation for selected package
function! go#guru#Implements(selected)
let out = s:RunGuru('implements', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
" Describe selected syntax: definition, methods, etc
function! go#guru#Describe(selected)
let out = s:RunGuru('describe', 'plain', a:selected, 0)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
" Show possible targets of selected function call
function! go#guru#Callees(selected)
let out = s:RunGuru('callees', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
" Show possible callers of selected function
function! go#guru#Callers(selected)
let out = s:RunGuru('callers', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
" Show path from callgraph root to selected function
function! go#guru#Callstack(selected)
let out = s:RunGuru('callstack', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
" Show free variables of selection
function! go#guru#Freevars(selected)
" Freevars requires a selection
if a:selected == -1
call go#util#EchoError("GoFreevars requires a selection (range) of code")
return
endif
let out = s:RunGuru('freevars', 'plain', a:selected, 0)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
" Show send/receive corresponding to selected channel op
function! go#guru#ChannelPeers(selected)
let out = s:RunGuru('peers', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
" Show all refs to entity denoted by selected identifier
function! go#guru#Referrers(selected)
let out = s:RunGuru('referrers', 'plain', a:selected, 0)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
endfunction
function! go#guru#What(selected)
" nvim doesn't have JSON support, though they work on it:
" https://github.com/neovim/neovim/pull/4131
if has('nvim')
return {'err': "GoWhat is not supported in Neovim"}
endif
" json_encode() and friends are introduced with this patch
" https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
if !has('patch-7.4.1304')
return {'err': "GoWhat is supported with Vim version 7.4-1304 or later"}
endif
let out = s:RunGuru('what', 'json', a:selected, 0)
if has_key(out, 'err')
return {'err': out.err}
endif
let result = json_decode(out.out)
if type(result) != type({})
return {'err': "malformed output from guru"}
endif
return result
endfunction
function! go#guru#SameIds(selected)
call go#guru#ClearSameIds()
let result = go#guru#What(a:selected)
if has_key(result, 'err') && !get(g:, 'go_auto_sameids', 0)
" only echo if it's called via `:GoSameIds, but not if it's in automode
call go#util#EchoError(result.err)
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
hi goSameId term=bold cterm=bold ctermbg=white ctermfg=black
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
endfunction
function! go#guru#ClearSameIds()
let m = getmatches()
for item in m
if item['group'] == 'goSameId'
call matchdelete(item['id'])
endif
endfor
endfunction
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,126 @@
function! go#impl#Impl(...)
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("<cword>")
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("<cword>")
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()
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)
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)
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)
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

View File

@@ -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)
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)
echohl Error | echo a:s | echohl None
endfunction
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,214 @@
" 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)
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let job = s:spawn(a:bang, a:desc, a:args)
return job.id
endfunction
" Statusline returns the current status of the job
function! go#jobcontrol#Statusline() abort
if empty(s:jobs)
return ''
endif
let import_path = go#package#ImportPath(expand('%:p:h'))
for job in values(s:jobs)
if job.importpath != import_path
continue
endif
if job.state == "SUCCESS"
return ''
endif
return printf("%s ... [%s]", job.desc, job.state)
endfor
return ''
endfunction
" AddHandler adds a on_exit callback handler and returns the id.
function! go#jobcontrol#AddHandler(handler)
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)
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)
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'),
\ }
" 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)
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)
if a:exit_status == 0
call go#list#Clean(0)
call go#list#Window(0)
let self.state = "SUCCESS"
call go#util#EchoSuccess("SUCCESS")
execute cd . fnameescape(dir)
return
endif
let self.state = "FAILED"
call go#util#EchoError("FAILED")
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()
let l:listtype = "locationlist"
call go#list#Populate(l:listtype, errors)
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)
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)
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)
call extend(self.stderr, a:data)
endfunction
" abort_all aborts all current jobs created with s:spawn()
function! s:abort_all()
if empty(s:jobs)
return
endif
for id in keys(s:jobs)
if id > 0
silent! call jobstop(id)
endif
endfor
let s:jobs = {}
endfunction
" abort aborts the job with the given name, where name is the first argument
" passed to s:spawn()
function! s:abort(path)
if empty(s:jobs)
return
endif
for job in values(s:jobs)
if job.importpath == path && job.id > 0
silent! call jobstop(job.id)
unlet s:jobs['job.id']
endif
endfor
endfunction
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,199 @@
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_deadline")
let g:go_metalinter_deadline = "5s"
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 meta_command = "gometalinter --disable-all"
if a:autosave || empty(g:go_metalinter_command)
let bin_path = go#path#CheckBinPath("gometalinter")
if empty(bin_path)
return
endif
if a:autosave
" include only messages for the active buffer
let meta_command .= " --include='^" . expand('%:p') . ".*$'"
endif
" linters
let linters = a:autosave ? g:go_metalinter_autosave_enabled : g:go_metalinter_enabled
for linter in linters
let meta_command .= " --enable=".linter
endfor
" deadline
let meta_command .= " --deadline=" . g:go_metalinter_deadline
" path
let meta_command .= " " . goargs
else
" the user wants something else, let us use it.
let meta_command = g:go_metalinter_command
endif
" comment out the following two lines for debugging
" echo meta_command
" return
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:
" <file>:<line>:[<column>]: <message> (<linter>)
" <file>:<line>:: <message> (<linter>)
" 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"))
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, ...)
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)
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"))
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)
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
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,126 @@
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, ...)
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)
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)
let l:listtype = go#list#Type(a:listtype)
if l:listtype == "locationlist"
call setloclist(0, a:items, 'r')
else
call setqflist(a:items, 'r')
endif
endfunction
function! go#list#PopulateWin(winnr, items)
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)
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
else
cgetexpr a:items
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)
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)
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)
let l:listtype = go#list#Type(a:listtype)
if l:listtype == "locationlist"
lex []
else
cex []
endif
endfunction
function! go#list#Type(listtype)
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

View File

@@ -0,0 +1,160 @@
" 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()
let dirs = []
if !exists("s:goroot")
if executable('go')
let s:goroot = substitute(go#util#System('go env GOROOT'), '\n', '', 'g')
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)
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
let srcdir = substitute(workspace . '/src/', '//', '/', '')
return substitute(path, srcdir, '', '')
endfunction
function! go#package#FromPath(arg)
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)
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)
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

View File

@@ -0,0 +1,175 @@
" 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(...)
" we have an argument, replace GOPATH
if len(a:000)
" 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
return
endif
echo go#path#Detect()
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
function! go#path#Default()
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)
let go_paths = split($GOPATH, 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()
let gopath = $GOPATH
" 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
return gopath
endfunction
" BinPath returns the binary path of installed go tools.
function! go#path#BinPath()
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 $GOPATH + '/bin'
if exists("g:go_bin_path")
let bin_path = g:go_bin_path
elseif $GOBIN != ""
let bin_path = $GOBIN
elseif $GOPATH != ""
let bin_path = expand(go#path#Default() . "/bin/")
else
" could not find anything
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)
" 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 v:version == 704 && has('patch235')
let binpath = exepath(binpath)
endif
let $PATH = old_path
return binpath
endif
" just get the basename
let basename = fnamemodify(binpath, ":t")
if !executable(basename)
echo "vim-go: could not find '" . basename . "'. Run :GoInstallBinaries to fix it."
" 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

View File

@@ -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)
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()
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()
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()
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

View File

@@ -0,0 +1,77 @@
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, ...)
let to = ""
if a:0 == 0
let from = expand("<cword>")
let ask = printf("vim-go: rename '%s' to: ", from)
if g:go_gorename_prefill
let to = input(ask, from)
else
let to = input(ask)
endif
redraw!
if empty(to)
return
endif
else
let to = 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 cmd = printf('%s -offset %s -to %s', shellescape(bin_path), shellescape(printf('%s:#%d', fname, pos)), shellescape(to))
let out = go#tool#ExecuteInDir(cmd)
" 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
" strip out newline on the end that gorename puts. If we don't remove, it
" will trigger the 'Hit ENTER to continue' prompt
let clean = split(out, '\n')
let l:listtype = "quickfix"
if go#util#ShellError() != 0
let errors = go#tool#ParseErrors(split(out, '\n'))
call go#list#Populate(l:listtype, errors)
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
return
else
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
redraw | echon "vim-go: " | echohl Function | echon clean[0] | echohl None
endif
" 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

View File

@@ -0,0 +1,31 @@
let s:current_file = expand("<sfile>")
function! go#template#create()
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
if l:package_name == -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 ' . l:template_path
$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
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,138 @@
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)
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)
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
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)
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)
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)
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)
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

View File

@@ -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)
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(getline(1, '$'), 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)
" 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(getline(1, '$'), 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

View File

@@ -0,0 +1,195 @@
function! go#tool#Files()
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()
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()
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#PackageName()
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)
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)
" 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 $GOPATH = go#path#Detect()
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 $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)
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()
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)
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

View File

@@ -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)
" 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()
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()
" 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)
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

View File

@@ -0,0 +1,251 @@
" PathSep returns the appropriate OS specific path separator.
function! go#util#PathSep()
if go#util#IsWin()
return '\'
endif
return '/'
endfunction
" PathListSep returns the appropriate OS specific path list separator.
function! go#util#PathListSep()
if go#util#IsWin()
return ";"
endif
return ":"
endfunction
" LineEnding returns the correct line ending, based on the current fileformat
function! go#util#LineEnding()
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(...)
return join(a:000, go#util#PathSep())
endfunction
" IsWin returns 1 if current OS is Windows or 0 otherwise
function! go#util#IsWin()
let win = ['win16', 'win32', 'win64', 'win95']
for w in win
if (has(w))
return 1
endif
endfor
return 0
endfunction
function! go#util#GOARCH()
return substitute(go#util#System('go env GOARCH'), '\n', '', 'g')
endfunction
function! go#util#GOOS()
return substitute(go#util#System('go env GOOS'), '\n', '', 'g')
endfunction
function! go#util#GOROOT()
return substitute(go#util#System('go env GOROOT'), '\n', '', 'g')
endfunction
function! go#util#GOPATH()
return substitute(go#util#System('go env GOPATH'), '\n', '', 'g')
endfunction
function! go#util#OSARCH()
return go#util#GOOS() . '_' . go#util#GOARCH()
endfunction
"Check if has vimproc
function! s:has_vimproc()
if !exists('g:go#use_vimproc')
if go#util#IsWin()
try
call vimproc#version()
let exists_vimproc = 1
catch
let exists_vimproc = 0
endtry
else
let exists_vimproc = 0
endif
let g:go#use_vimproc = exists_vimproc
endif
return g:go#use_vimproc
endfunction
if s:has_vimproc()
let s:vim_system = get(g:, 'gocomplete#system_function', 'vimproc#system2')
let s:vim_shell_error = get(g:, 'gocomplete#shell_error_function', 'vimproc#get_last_status')
else
let s:vim_system = get(g:, 'gocomplete#system_function', 'system')
let s:vim_shell_error = ''
endif
function! go#util#System(str, ...)
return call(s:vim_system, [a:str] + a:000)
endfunction
function! go#util#ShellError()
if empty(s:vim_shell_error)
return v:shell_error
endif
return call(s:vim_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)
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)
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, ...)
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)
if s:has_vimproc()
return vimproc#shellescape(a:arg)
endif
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, ...)
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)
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()
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)
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)
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)
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)
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
" TODO(arslan): I couldn't parameterize the highlight types. Check if we can
" simplify the following functions
function! go#util#EchoSuccess(msg)
redraws! | echon "vim-go: " | echohl Function | echon a:msg | echohl None
endfunction
function! go#util#EchoError(msg)
redraws! | echon "vim-go: " | echohl ErrorMsg | echon a:msg | echohl None
endfunction
function! go#util#EchoWarning(msg)
redraws! | echon "vim-go: " | echohl WarningMsg | echon a:msg | echohl None
endfunction
function! go#util#EchoProgress(msg)
redraws! | echon "vim-go: " | echohl Identifier | echon a:msg | echohl None
endfunction
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,41 @@
" 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.
"
" compiler/go.vim: Vim compiler file for Go.
if exists("current_compiler")
finish
endif
let current_compiler = "go"
if exists(":CompilerSet") != 2
command -nargs=* CompilerSet setlocal <args>
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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,63 @@
" 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 <buffer> <silent> K :GoDoc<cr>
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 <buffer> <silent> gd :GoDef<cr>
nnoremap <buffer> <silent> <C-]> :GoDef<cr>
nnoremap <buffer> <silent> <C-w><C-]> :<C-u>call go#def#Jump("split")<CR>
nnoremap <buffer> <silent> <C-w>] :<C-u>call go#def#Jump("split")<CR>
nnoremap <buffer> <silent> <C-t> :<C-U>call go#def#StackPop(v:count1)<cr>
endif
if get(g:, "go_textobj_enabled", 1)
onoremap <buffer> <silent> af :<c-u>call go#textobj#Function('a')<cr>
onoremap <buffer> <silent> if :<c-u>call go#textobj#Function('i')<cr>
xnoremap <buffer> <silent> af :<c-u>call go#textobj#Function('a')<cr>
xnoremap <buffer> <silent> if :<c-u>call go#textobj#Function('i')<cr>
" Remap ]] and [[ to jump betweeen functions as they are useless in Go
nnoremap <buffer> <silent> ]] :<c-u>call go#textobj#FunctionJump('n', 'next')<cr>
nnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('n', 'prev')<cr>
onoremap <buffer> <silent> ]] :<c-u>call go#textobj#FunctionJump('o', 'next')<cr>
onoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('o', 'prev')<cr>
xnoremap <buffer> <silent> ]] :<c-u>call go#textobj#FunctionJump('v', 'next')<cr>
xnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('v', 'prev')<cr>
endif
if get(g:, "go_auto_type_info", 0)
setlocal updatetime=800
endif
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,78 @@
" -- gorename
command! -nargs=? GoRename call go#rename#Rename(<bang>0,<f-args>)
" -- guru
command! -nargs=* -complete=customlist,go#package#Complete GoGuruScope call go#guru#Scope(<f-args>)
command! -range=% GoImplements call go#guru#Implements(<count>)
command! -range=% GoCallees call go#guru#Callees(<count>)
command! -range=% GoDescribe call go#guru#Describe(<count>)
command! -range=% GoCallers call go#guru#Callers(<count>)
command! -range=% GoCallstack call go#guru#Callstack(<count>)
command! -range=% GoFreevars call go#guru#Freevars(<count>)
command! -range=% GoChannelPeers call go#guru#ChannelPeers(<count>)
command! -range=% GoReferrers call go#guru#Referrers(<count>)
command! -nargs=? GoGuruTags call go#guru#Tags(<f-args>)
command! -range=% GoSameIds call go#guru#SameIds(<count>)
command! -range=0 GoSameIdsClear call go#guru#ClearSameIds()
" -- tool
command! -nargs=0 GoFiles echo go#tool#Files()
command! -nargs=0 GoDeps echo go#tool#Deps()
command! -nargs=* GoInfo call go#complete#Info(0)
" -- cmd
command! -nargs=* -bang GoBuild call go#cmd#Build(<bang>0,<f-args>)
command! -nargs=* -bang GoGenerate call go#cmd#Generate(<bang>0,<f-args>)
command! -nargs=* -bang -complete=file GoRun call go#cmd#Run(<bang>0,<f-args>)
command! -nargs=* -bang GoInstall call go#cmd#Install(<bang>0, <f-args>)
command! -nargs=* -bang GoTest call go#cmd#Test(<bang>0, 0, <f-args>)
command! -nargs=* -bang GoTestFunc call go#cmd#TestFunc(<bang>0, <f-args>)
command! -nargs=* -bang GoTestCompile call go#cmd#Test(<bang>0, 1, <f-args>)
" -- cover
command! -nargs=* -bang GoCoverage call go#coverage#Buffer(<bang>0, <f-args>)
command! -nargs=* -bang GoCoverageClear call go#coverage#Clear()
command! -nargs=* -bang GoCoverageToggle call go#coverage#BufferToggle(<bang>0, <f-args>)
command! -nargs=* -bang GoCoverageBrowser call go#coverage#Browser(<bang>0, <f-args>)
" -- play
command! -nargs=0 -range=% GoPlay call go#play#Share(<count>, <line1>, <line2>)
" -- def
command! -nargs=* -range GoDef :call go#def#Jump('')
command! -nargs=? GoDefPop :call go#def#StackPop(<f-args>)
command! -nargs=? GoDefStack :call go#def#Stack(<f-args>)
command! -nargs=? GoDefStackClear :call go#def#StackClear(<f-args>)
" -- doc
command! -nargs=* -range -complete=customlist,go#package#Complete GoDoc call go#doc#Open('new', 'split', <f-args>)
command! -nargs=* -range -complete=customlist,go#package#Complete GoDocBrowser call go#doc#OpenBrowser(<f-args>)
" -- fmt
command! -nargs=0 GoFmt call go#fmt#Format(-1)
command! -nargs=0 GoImports call go#fmt#Format(1)
" -- import
command! -nargs=? -complete=customlist,go#package#Complete GoDrop call go#import#SwitchImport(0, '', <f-args>, '')
command! -nargs=1 -bang -complete=customlist,go#package#Complete GoImport call go#import#SwitchImport(1, '', <f-args>, '<bang>')
command! -nargs=* -bang -complete=customlist,go#package#Complete GoImportAs call go#import#SwitchImport(1, <f-args>, '<bang>')
" -- linters
command! -nargs=* GoMetaLinter call go#lint#Gometa(0, <f-args>)
command! -nargs=* GoLint call go#lint#Golint(<f-args>)
command! -nargs=* -bang GoVet call go#lint#Vet(<bang>0, <f-args>)
command! -nargs=* -complete=customlist,go#package#Complete GoErrCheck call go#lint#Errcheck(<f-args>)
" -- alternate
command! -bang GoAlternate call go#alternate#Switch(<bang>0, '')
" -- ctrlp
if globpath(&rtp, 'plugin/ctrlp.vim') != ""
command! -nargs=? -complete=file GoDecls call ctrlp#init(ctrlp#decls#cmd(0, <q-args>))
command! -nargs=? -complete=dir GoDeclsDir call ctrlp#init(ctrlp#decls#cmd(1, <q-args>))
endif
" -- impl
command! -nargs=* -buffer -complete=customlist,go#impl#Complete GoImpl call go#impl#Impl(<f-args>)
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,72 @@
" 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 <silent> <Plug>(go-run) :<C-u>call go#cmd#Run(!g:go_jump_to_error)<CR>
if has("nvim")
nnoremap <silent> <Plug>(go-run-vertical) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'vsplit', [])<CR>
nnoremap <silent> <Plug>(go-run-split) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'split', [])<CR>
nnoremap <silent> <Plug>(go-run-tab) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'tabe', [])<CR>
endif
nnoremap <silent> <Plug>(go-build) :<C-u>call go#cmd#Build(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-generate) :<C-u>call go#cmd#Generate(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-install) :<C-u>call go#cmd#Install(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-test) :<C-u>call go#cmd#Test(!g:go_jump_to_error, 0)<CR>
nnoremap <silent> <Plug>(go-test-func) :<C-u>call go#cmd#TestFunc(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-test-compile) :<C-u>call go#cmd#Test(!g:go_jump_to_error, 1)<CR>
nnoremap <silent> <Plug>(go-coverage) :<C-u>call go#coverage#Buffer(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-coverage-clear) :<C-u>call go#coverage#Clear()<CR>
nnoremap <silent> <Plug>(go-coverage-toggle) :<C-u>call go#coverage#BufferToggle(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-coverage-browser) :<C-u>call go#coverage#Browser(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-files) :<C-u>call go#tool#Files()<CR>
nnoremap <silent> <Plug>(go-deps) :<C-u>call go#tool#Deps()<CR>
nnoremap <silent> <Plug>(go-info) :<C-u>call go#complete#Info(0)<CR>
nnoremap <silent> <Plug>(go-import) :<C-u>call go#import#SwitchImport(1, '', expand('<cword>'), '')<CR>
nnoremap <silent> <Plug>(go-imports) :<C-u>call go#fmt#Format(1)<CR>
nnoremap <silent> <Plug>(go-implements) :<C-u>call go#guru#Implements(-1)<CR>
nnoremap <silent> <Plug>(go-callees) :<C-u>call go#guru#Callees(-1)<CR>
nnoremap <silent> <Plug>(go-callers) :<C-u>call go#guru#Callers(-1)<CR>
nnoremap <silent> <Plug>(go-describe) :<C-u>call go#guru#Describe(-1)<CR>
nnoremap <silent> <Plug>(go-callstack) :<C-u>call go#guru#Callstack(-1)<CR>
xnoremap <silent> <Plug>(go-freevars) :<C-u>call go#guru#Freevars(0)<CR>
nnoremap <silent> <Plug>(go-channelpeers) :<C-u>call go#guru#ChannelPeers(-1)<CR>
nnoremap <silent> <Plug>(go-referrers) :<C-u>call go#guru#Referrers(-1)<CR>
nnoremap <silent> <Plug>(go-sameids) :<C-u>call go#guru#SameIds(-1)<CR>
nnoremap <silent> <Plug>(go-rename) :<C-u>call go#rename#Rename(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-def) :<C-u>call go#def#Jump('')<CR>
nnoremap <silent> <Plug>(go-def-vertical) :<C-u>call go#def#Jump("vsplit")<CR>
nnoremap <silent> <Plug>(go-def-split) :<C-u>call go#def#Jump("split")<CR>
nnoremap <silent> <Plug>(go-def-tab) :<C-u>call go#def#Jump("tab")<CR>
nnoremap <silent> <Plug>(go-def-pop) :<C-u>call go#def#StackPop()<CR>
nnoremap <silent> <Plug>(go-def-stack) :<C-u>call go#def#Stack()<CR>
nnoremap <silent> <Plug>(go-def-stack-clear) :<C-u>call go#def#StackClear()<CR>
nnoremap <silent> <Plug>(go-doc) :<C-u>call go#doc#Open("new", "split")<CR>
nnoremap <silent> <Plug>(go-doc-tab) :<C-u>call go#doc#Open("tabnew", "tabe")<CR>
nnoremap <silent> <Plug>(go-doc-vertical) :<C-u>call go#doc#Open("vnew", "vsplit")<CR>
nnoremap <silent> <Plug>(go-doc-split) :<C-u>call go#doc#Open("new", "split")<CR>
nnoremap <silent> <Plug>(go-doc-browser) :<C-u>call go#doc#OpenBrowser()<CR>
nnoremap <silent> <Plug>(go-metalinter) :<C-u>call go#lint#Gometa(0)<CR>
nnoremap <silent> <Plug>(go-vet) :<C-u>call go#lint#Vet(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-alternate-edit) :<C-u>call go#alternate#Switch(0, "edit")<CR>
nnoremap <silent> <Plug>(go-alternate-vertical) :<C-u>call go#alternate#Switch(0, "vsplit")<CR>
nnoremap <silent> <Plug>(go-alternate-split) :<C-u>call go#alternate#Switch(0, "split")<CR>
" vim: sw=2 ts=2 et

View File

@@ -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

View File

@@ -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' : expand(bin_path),
\ 'ctagsargs' : '-sort -silent'
\ }
endif
endfunction
call s:SetTagbar()
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,8 @@
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
setlocal commentstring=<!--\ %s\ -->
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,438 @@
# 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 <http://www.gnu.org/licenses/>.
*
* 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 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
# 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:

View File

@@ -0,0 +1,358 @@
# 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 <http://www.gnu.org/licenses/>.
*
* 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 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}"\`
# 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")}
})

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,186 @@
" 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/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(<f-args>)
" 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)
if $GOPATH == ""
echohl Error
echomsg "vim.go: $GOPATH is not set"
echohl None
return
endif
let err = s:CheckBinaries()
if err != 0
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 !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
augroup vim-go
autocmd!
" GoInfo automatic update
if get(g:, "go_auto_type_info", 0)
autocmd CursorHold *.go nested call go#complete#Info(1)
endif
" GoSameId automatic update
if get(g:, "go_auto_sameids", 0)
autocmd CursorMoved *.go nested call go#guru#SameIds(-1)
endif
" Echo the identifier information when completion is done. Useful to see
" the signature of a function, etc...
if exists('##CompleteDone')
autocmd CompleteDone *.go nested call s:echo_go_info()
endif
" Go code formatting on save
if get(g:, "go_fmt_autosave", 1)
autocmd BufWritePre *.go call go#fmt#Format(-1)
endif
" Go asm formatting on save
if get(g:, "go_asmfmt_autosave", 1)
autocmd BufWritePre *.s call go#asmfmt#Format()
endif
" run gometalinter on save
if get(g:, "go_metalinter_autosave", 0)
autocmd BufWritePost *.go call go#lint#Gometa(1)
endif
" create new template from scratch
if get(g:, "go_template_autocreate", 1)
autocmd BufNewFile *.go call go#template#create()
endif
augroup END
" vim: sw=2 ts=2 et

View File

@@ -0,0 +1,78 @@
#!/bin/bash -e
#
# Copyright 2012 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.
#
# Tests for import.vim.
cd $(dirname $0)
cat > base.go <<EOF
package test
import (
"bytes"
"io"
"net"
"mycorp/foo"
)
EOF
fail=0
# usage: test_one command pattern
# Pattern is a PCRE expression that will match across lines.
test_one() {
echo 2>&1 -n "$1: "
vim -e -s -u /dev/null -U /dev/null --noplugin -c "source import.vim" \
-c "$1" -c 'wq! test.go' base.go
# ensure blank lines are treated correctly
if ! gofmt test.go | cmp test.go -; then
echo 2>&1 "gofmt conflict"
gofmt test.go | diff -u test.go - | sed "s/^/ /" 2>&1
fail=1
return
fi
if ! [[ $(cat test.go) =~ $2 ]]; then
echo 2>&1 "$2 did not match"
cat test.go | sed "s/^/ /" 2>&1
fail=1
return
fi
echo 2>&1 "ok"
}
# Tests for Import
test_one "Import baz" '"baz".*"bytes"'
test_one "Import io/ioutil" '"io".*"io/ioutil".*"net"'
test_one "Import myc" '"io".*"myc".*"net"' # prefix of a site prefix
test_one "Import nat" '"io".*"nat".*"net"'
test_one "Import net/http" '"net".*"net/http".*"mycorp/foo"'
test_one "Import zoo" '"net".*"zoo".*"mycorp/foo"'
test_one "Import mycorp/bar" '"net".*"mycorp/bar".*"mycorp/foo"'
test_one "Import mycorp/goo" '"net".*"mycorp/foo".*"mycorp/goo"'
# Tests for Drop
cat > base.go <<EOF
package test
import (
"foo"
"something"
"zoo"
)
EOF
test_one "Drop something" '\([^"]*"foo"[^"]*"zoo"[^"]*\)'
rm -f base.go test.go
if [ $fail -gt 0 ]; then
echo 2>&1 "FAIL"
exit 1
fi
echo 2>&1 "PASS"

View File

@@ -0,0 +1,380 @@
" 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 on, except highlight of:
" functions, methods, structs, operators, build constraints and interfaces.
"
" - 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 = 1
endif
if !exists("g:go_highlight_chan_whitespace_error")
let g:go_highlight_chan_whitespace_error = 1
endif
if !exists("g:go_highlight_extra_types")
let g:go_highlight_extra_types = 1
endif
if !exists("g:go_highlight_space_tab_error")
let g:go_highlight_space_tab_error = 1
endif
if !exists("g:go_highlight_trailing_whitespace_error")
let g:go_highlight_trailing_whitespace_error = 1
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 iota true false nil
hi def link goBuiltins Keyword
hi def link goBoolean Boolean
" 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
"
" \(\<chan\>\)\@<!<- (only pick arrow when it doesn't come after a chan)
" this prevents picking up 'chan<- chan<-' but not '<- chan'
syn match goSpaceError display "\(\(\<chan\>\)\@<!<-\)\@<=\s\+\(\<chan\>\)\@="
" send-only annotation on chan type
"
" \(<-\)\@<!\<chan\> (only pick chan when it doesn't come after an arrow)
" this prevents picking up '<-chan <-chan' but not 'chan <-'
syn match goSpaceError display "\(\(<-\)\@<!\<chan\>\)\@<=\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 /\<bytes\.\(Buffer\)\>/
syn match goExtraType /\<io\.\(Reader\|ReadSeeker\|ReadWriter\|ReadCloser\|ReadWriteCloser\|Writer\|WriteCloser\|Seeker\)\>/
syn match goExtraType /\<reflect\.\(Kind\|Type\|Value\)\>/
syn match goExtraType /\<unsafe\.Pointer\>/
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
" 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 ...
syn match goOperator /\.\.\./
hi def link goPointerOperator Operator
endif
hi def link goOperator Operator
" Functions;
if g:go_highlight_functions != 0
syn match goDeclaration /\<func\>/ 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
else
syn keyword goDeclaration func
endif
hi def link goFunction Function
" Methods;
if g:go_highlight_methods != 0
syn match goMethod /\.\w\+(/hs=s+1,he=e-1
endif
hi def link goMethod Type
" Fields;
if g:go_highlight_fields != 0
syn match goVarArgs /\.\.\.\w\+\>/
syn match goField /\.\a\+\([\ \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 /\<type\>/ nextgroup=goTypeName skipwhite skipnl
syn match goTypeName /\w\+/ contained nextgroup=goDeclType skipwhite skipnl
syn match goDeclType /\<interface\|struct\>/ contained 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
hi def link goSameId IncSearch
" 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,191 @@
" to execute, `rake test` on parent dir
describe 'go#coverage#Buffer'
before
new
let g:curdir = expand('<sfile>:p:h') . '/'
let g:srcpath = 't/fixtures/src/'
let g:sample = 'pkg1/sample.go'
let g:sampleabs = g:curdir . g:srcpath . 'pkg1/sample.go'
let g:samplecover = g:curdir . g:srcpath . 'pkg1/sample.out'
let g:go_gopath = g:curdir . 't/fixtures'
execute "badd " . g:srcpath . g:sample
execute "buffer " . bufnr("$")
end
after
execute "bprev"
execute "bdelete " . g:srcpath . g:sample
close!
end
it 'puts match to the list'
call go#coverage#Buffer(0)
Expect len(go#coverlay#matches()) == 5
call go#coverlay#Clearlay()
Expect len(go#coverlay#matches()) == 0
call go#coverage#Buffer(0)
Expect len(go#coverlay#matches()) == 5
call go#coverlay#Clearlay()
Expect len(go#coverlay#matches()) == 0
call go#coverage#Buffer(0)
Expect len(go#coverlay#matches()) == 5
call go#coverage#Buffer(0)
Expect len(go#coverlay#matches()) == 5
call go#coverlay#Clearlay()
Expect len(go#coverlay#matches()) == 0
end
end
describe 'go#coverage#Buffer fail'
before
new
let g:curdir = expand('<sfile>:p:h') . '/'
let g:srcpath = 't/fixtures/src/'
let g:sample = 'failtest/sample.go'
let g:sampletest = 'failtest/sample_test.go'
let g:sampleabs = g:curdir . g:srcpath . 'failtest/sample.go'
let g:go_gopath = g:curdir . 't/fixtures'
execute "badd " . g:srcpath . g:sample
execute "buffer " . bufnr("$")
end
after
execute "bprev"
execute "bdelete " . g:srcpath . g:sampletest
execute "bdelete " . g:srcpath . g:sample
end
it 'does nothing if test fail'
call go#coverage#Buffer(0)
Expect len(go#coverlay#matches()) == 0
Expect len(getqflist()) == 1
end
end
describe 'go#coverage#Buffer build fail'
before
new
let g:curdir = expand('<sfile>:p:h') . '/'
let g:srcpath = 't/fixtures/src/'
let g:sample = 'buildfail/sample.go'
let g:sampleabs = g:curdir . g:srcpath . 'buildfail/sample.go'
let g:go_gopath = g:curdir . 't/fixtures'
execute "badd " . g:srcpath . g:sample
execute "buffer " . bufnr("$")
end
after
execute "bprev"
execute "bdelete " . g:srcpath . g:sample
end
it 'does nothing if test fail'
call go#coverage#Buffer(0)
Expect len(go#coverlay#matches()) == 0
end
end
describe 'go#coverage#Buffer build test fail'
before
new
let g:curdir = expand('<sfile>:p:h') . '/'
let g:srcpath = 't/fixtures/src/'
let g:sample = 'buildtestfail/sample.go'
let g:sampleabs = g:curdir . g:srcpath . 'buildtestfail/sample.go'
let g:go_gopath = g:curdir . 't/fixtures'
execute "badd " . g:srcpath . g:sample
execute "buffer " . bufnr("$")
end
after
execute "bprev"
execute "bdelete " . g:srcpath . g:sample
end
it 'does nothing if test fail'
call go#coverage#Buffer(0)
Expect len(go#coverlay#matches()) == 0
end
end
describe 'go#coverlay#findbufnr'
before
new
let g:curdir = expand('<sfile>:p:h') . '/'
let g:srcpath = 't/fixtures/src/'
let g:sample = 'pkg1/sample.go'
let g:sample2 = 'pkg2/sample.go'
let g:sampleabs = g:curdir . g:srcpath . 'pkg1/sample.go'
let g:sampleabs2 = g:curdir . g:srcpath . 'pkg2/sample.go'
let g:go_gopath = g:curdir . 't/fixtures'
execute "badd " . g:srcpath . g:sample
execute "badd " . g:srcpath . g:sample2
end
after
execute "bdelete " . g:srcpath . g:sample2
execute "bdelete " . g:srcpath . g:sample
close!
end
it 'returns BUFNR if FILE is opened at BUFNR'
Expect go#coverlay#findbufnr('_' . g:sampleabs) == bufnr(g:sampleabs)
Expect go#coverlay#findbufnr(g:sample) == bufnr(g:sampleabs)
Expect go#coverlay#findbufnr('_' . g:sampleabs2) == bufnr(g:sampleabs2)
Expect go#coverlay#findbufnr(g:sample2) == bufnr(g:sampleabs2)
end
it 'returns -1 if FILE is not exists'
Expect go#coverlay#findbufnr('pkg1/NOTEXISTS.go') == -1
Expect go#coverlay#findbufnr('_' . g:curdir . g:srcpath . 'pkg1/NOTEXISTS.go') == -1
end
end
describe 'go#coverlay#isopenedon'
before
new
let g:curdir = expand('<sfile>:p:h') . '/'
let g:srcpath = 't/fixtures/src/'
let g:sample = 'pkg1/sample.go'
let g:sampleabs = g:curdir . g:srcpath . 'pkg1/sample.go'
let g:go_gopath = g:curdir . 't/fixtures'
execute "badd " . g:srcpath . g:sample
end
after
execute "bdelete " . g:srcpath . g:sample
close!
end
it 'returns 1 if FILE is opened at BUFNR'
Expect go#coverlay#isopenedon('_' . g:sampleabs, bufnr(g:sampleabs)) == 1
Expect go#coverlay#isopenedon(g:sample, bufnr(g:sampleabs)) == 1
end
it 'returns 0 if FILE is not opened at BUFNR'
Expect go#coverlay#isopenedon('_' . g:sampleabs, 42) == 0
Expect go#coverlay#isopenedon(g:sample, 42) == 0
end
it 'returns 0 if FILE is not exists'
Expect go#coverlay#isopenedon('_' . g:curdir . g:srcpath . 'pkg1/NOTEXISTS', bufnr(g:sampleabs)) == 0
Expect go#coverlay#isopenedon('pkg1/NOTEXISTS.go', bufnr(g:sampleabs)) == 0
end
end
describe 'go#coverlay#parsegocoverline'
it 'parses a go cover output line and returns as dict'
let d = {'file': 'f',"startline": "1", "startcol": "2", "endline": "3", "endcol": "4", "numstmt": "5", "cnt": "6"}
" file:startline.col,endline.col numstmt count
Expect go#coverlay#parsegocoverline("f:1.2,3.4 5 6") == d
end
end
describe 'go#coverlay#genmatch'
it 'generate mark pattern from cover data'
let d = {'file': 'f',"startline": "1", "startcol": "2", "endline": "3", "endcol": "4", "numstmt": "5", "cnt": "6"}
Expect go#coverlay#genmatch(d) == {'group': 'covered', "pattern": '\%>1l\_^\s\+\%<3l\|\%1l\_^\s\+\|\%3l\_^\s\+\(\}$\)\@!', "priority": 6}
let d = {'file': 'f',"startline": "1", "startcol": "2", "endline": "3", "endcol": "4", "numstmt": "5", "cnt": "0"}
Expect go#coverlay#genmatch(d) == {'group': 'uncover', "pattern": '\%>1l\_^\s\+\%<3l\|\%1l\_^\s\+\|\%3l\_^\s\+\(\}$\)\@!', "priority": 5}
end
end

View File

@@ -0,0 +1,13 @@
// set gopath before
//go:generate go test --coverprofile=sample.out
// go1.5.3 example output:
// GOPATH=`pwd`/fixtures go test --coverprofile=log.out buildfail
// # buildfail
// /tmp/go-build264733986/buildfail/_test/_obj_test/sample.go:7: undefined: IT_SHOULD_BE_BUILD_FAILED
// /tmp/go-build264733986/buildfail/_test/_obj_test/sample.go:8: missing return at end of function
// FAIL buildfail [build failed]
package pkg
func Sample() int {
IT_SHOULD_BE_BUILD_FAILED
}

View File

@@ -0,0 +1,7 @@
package pkg
import "testing"
func TestSample(t *testing.T) {
Sample()
}

View File

@@ -0,0 +1,7 @@
// set gopath before
//go:generate go test --coverprofile=sample.out
package pkg
func Sample() int {
return 1
}

View File

@@ -0,0 +1,15 @@
// go1.5.3 example output:
// GOPATH=`pwd`/fixtures go test --coverprofile=log.out buildtestfail
// # buildtestfail
// fixtures/src/buildtestfail/sample_test.go:14: undefined: IT_SHOULD_BE_BUILD_FAILED
// FAIL buildtestfail [build failed]
// echo $?
// 2
package pkg
import "testing"
func TestSample(t *testing.T) {
IT_SHOULD_BE_BUILD_FAILED
}

View File

@@ -0,0 +1,12 @@
// set gopath before
//go:generate go test --coverprofile=sample.out
package pkg
func Sample() int {
if false {
return 0
} else if false {
return 0
}
return 1
}

View File

@@ -0,0 +1,8 @@
package pkg
import "testing"
func TestSample(t *testing.T) {
Sample()
t.Fatal("itwillfail")
}

View File

@@ -0,0 +1,14 @@
// set gopath before
//go:generate go test --coverprofile=sample.out
// go1.5.3 example output:
// GOPATH=`pwd`/fixtures go test --coverprofile=log.out parsefail
// # cover parsefail
// 2016/01/17 23:59:08 cover: /home/sey/vimfiles/_vim/bundle/vim-go-coverlay/t/fixtures/src/parsefail/sample.go: /home/sey/vimfiles/_vim/bundle/vim-go-coverlay/t/fixtures/src/parsefail/sample.go:10:1: expected declaration, found 'IDENT' PARSEFAIL
// FAIL parsefail [build failed]
// echo $?
// 2
package pkg
PARSEFAIL Sample() int {
return 0
}

View File

@@ -0,0 +1,7 @@
package pkg
import "testing"
func TestSample(t *testing.T) {
Sample()
}

View File

@@ -0,0 +1,12 @@
// set gopath before
//go:generate go test --coverprofile=sample.out
package pkg1
func Sample() int {
if false {
return 0
} else if false {
return 0
}
return 1
}

View File

@@ -0,0 +1,6 @@
mode: set
pkg1/sample.go:5.19,6.11 1 1
pkg1/sample.go:11.2,11.10 1 1
pkg1/sample.go:6.11,8.3 1 0
pkg1/sample.go:8.3,8.18 1 1
pkg1/sample.go:8.18,10.3 1 0

View File

@@ -0,0 +1,7 @@
package pkg1
import "testing"
func TestSample(t *testing.T) {
Sample()
}

View File

@@ -0,0 +1,7 @@
package main
import "fmt"
func main() {
fmt.Println("vim-go")
}