Squashed 'vim/bundle/go/' changes from 3efc952a7..bf390af42

bf390af42 New release: v1.16
e0f9c34ff Merge pull request #1626 from delphinus/feature/add-note-for-vim8
b670f2372 Add note for deoplete on Vim 8
6fb095f1d update CHANGELOG.md for #1611
19ae4ac25 Merge pull request #1611 from hiberabyss/master
d6609168e verify 'vsplit' first
c5d695482 also check whether mode contains 'vertical'
3a8cc93e5 Fix go#template#create() for directories that don't exist yet (#1618)
60a03b1ba fix errorformat for compilation errors (#1620)
7836e8a06 match vsplit instead of vertical
ebe70faf6 improve neovim support
f4b4ba13f Merge pull request #1583 from bhcleek/tests/test-output-parsing
40e2e1992 update changelog
6bfc9e2a6 Merge pull request #1613 from bhcleek/fix-neovim-tests
869928c83 Run all test files for Neovim, but skip :GoTest tests
3bc0099e4 Make sure all tests run in Neovim
978f01054 Merge pull request #1607 from Carpetsmoker/fillstruct-line
85c966323 change go_test_prepend_name to go_test_show_name
3f53d9bc7 add tests for test output parsing
b8ad7d0eb Implement -line for fillstruct
0c98bdf53 Another Travis test
3df438c7d See if this get build on master
b50d8f2c8 Fix installing `gocode` on Windows (#1606)
2a4272238 Append Go file type when creating temporary file (#1601)
7904a2776 Add support for denite.nvim about :GoDecls / :GoDeclsDir (#1604)
47251aa65 improve testing story (#1605)
21c262935 Update changelog.md
48c12aa1a Merge pull request #1597 from fatih/go-doc-url
2fe16b99f Support minisnip (#1589)
6366c6ef2 Code coverage reports with covimerage (#1586)
539cec678 Highlighting arguments (#1587)
7f4673573 Merge pull request #1602 from mocheryl/rename-usage-function
a8af95cc2 Rename the usage function to make it callable
7938c88eb Update Changelog.md
3953d53e6 doc: use isnot instead of != for better safety
5daaaf640 guru: scope is not needed for describe mode (#1596)
07af1c520 doc: make godoc instance configurable
bbe47d165 Revert "Use :sbuffer in :GoAlternate" (#1595)
b870a052c Merge pull request #1592 from bhcleek/fix-vim-vint
f63ac32c4 fix vim-vint installation
c923e2927 update CHANGELOG.md for #1585
feee7fa82 Merge pull request #1585 from Carpetsmoker/test-alternate
8554d229a show compiler errors when :GoTest fails (#1588)
48ecb61af Use :sbuffer in :GoAlternate
ccf98e095 Update CHANGELOG
974b2896c Remove g:go_autodetect_gopath (#1525)
a9bf3cbaa Some small test running improvements (#1584)
6318e1aa0 Sync syntax from start after gofmt (#1582)
c191a672e Fix :GoImpl completion (#1581)
432dc7f7f prepend test name to test errors (#1578)
e2559cb3f update CHANGELOG.md (#1577)
ca8ef8a9f Merge pull request #1513 from bhcleek/fix-test-error-processing
57ac640df improve test output handling
456186fd0 update CHANGELOG.md (#1573)
bcd555d47 Merge pull request #1527 from bhcleek/fix-fugitive-errors
a50c83146 Add test and fix Exec() call
4fe11eacf eliminate errors when trying to run a command in a directory that does not exist
ebbc5b34d Add some VimScript lint tools (#1558)
a81c1bd52 Merge pull request #1565 from bhcleek/changelog/1562-1563
e581f3f01 typo (#1569)
c6ea0c1fe update CHANGELOG.md for #1562
c0d209cce Merge pull request #1562 from washtubs/master
d79dd9cbe update CHANGELOG.md for #1563
90384c0ca Merge pull request #1563 from horgh/horgh/run-gometalinter-on-tests
770164ab2 Add --tests only when using the default gometalinter command
70ecda391 Pass --tests flag to gometalinter so that we lint test files
d05d93a7e Make :GoTestCompile respect build tags
ba6ce99a6 Expand test framework (#1548)
bd35a4ec2 Add scripts/docker-test (#1550)
3eefef0b1 Merge pull request #1553 from wuzangsama/master
8ee54fa96 comment out err modeline
d735fc9fc Merge pull request #1551 from bhcleek/docker-image-install-vim
ee377102d run scripts directly instead of via make in Dockerfile
95584e32d install vim in the Docker image
d27a937a3 Ask for "go env" (#1547)
7efc3fe06 Better testing (#1476)
40e02891d Fix UltiSnips gpl snippet (#1535)
44e7173aa add modeline to CHANGELOG.md (#1546)
4409db9b2 Merge pull request #1540 from bhcleek/changelog/1538
06ba514d0 update CHANGELOG.md
5a3a2319a Merge pull request #1538 from 'tmatias:toggle_same_ids_check_group'
ee76970c5 improve go#guru#ClearSameIds readability
d3832a4e1 check group in when toggling same ids
087899210 Display warning when people use an older Vim (#1524)
cc93090b0 Add .editorconfig (#1523)
b28351fdd Merge pull request #1528 from bhcleek/add-modelines
4a8e342e8 Merge pull request #1529 from fatih/fix-go-play
219b9a12c tool: fix :GoPlay by using the correct IsMac() function
448a95767 add missing modelines
51dbbc412 Merge pull request #1461 from bhcleek/gopath-autodetect-default
2e6b84757 disable g:go_autodetect_gopath by default
faf628814 Merge pull request #1521 from bhcleek/changelog-1519
544c894c3 update changelog
0643e9ecc Merge pull request #1519 from bhcleek/fix-go-test-compile
b2ffdaa8e do not try to run tests for :GoTestCompile
011dcadc0 normalize message output (#1512)
f6196ad98 Update ChangeLog
112ea9090 Merge pull request #1465 from Carpetsmoker/rename-complete
57d60ff05 Also clarify docs a bit
d3a07e2c3 Address PR feedback
172139cab Better prefill and completion for :GoRename
2f838940e Clarify documentation for g:go_play_browser_command (#1495)
bd5bd982d edit issue template (#1502)
f61f97fbb edit help file and function description (#1503)
da4a86afa Update CHANGELOG
6ba5992fc Turnoff window resize if its still visible (#1488)
8ccaa5134 edit documentation (#1504)
863008a33 Fix util echo function: ensure l:msg is a list after split() (#1498)
96995056c Merge pull request #1492 from fatih/new-release
010d0cc59 New release: v1.15
4d518eef8 Merge pull request #1491 from fatih/update-changelog
a0a528a0f Update CHANGELOG.md
e3725d45a Merge pull request #1474 from bhcleek/close-gofmt-list-vim7.4
be4133a0b Merge pull request #1485 from cassiobotaro/master
1c1980fd6 ensure fmt list gets closed when title cannot be checked
7cb6d701c Fix #1484  GoDecls break when motion returns empty
dcd3e3bfb Don't use `v:t_list`. (#1479)
54150c199 Fix GoInstallBinaries error message (#1478)
8914c7e39 Allow arguments for :Go{Install,Update}Binaries (#1467)
2a9c03edd Clarify the documentation for the guru scope. (#1466)
ff2936872 Add go#util#Exec() (#1471)
620717490 Documentation for syntax highlighting (#1469)
78b7db128 Support fzf on GoDecls[Dir] (#1437)
458d23085 Merge pull request #1463 from bhcleek/better-assignment-highlight
09911f93f update CHANGELOG.md (#1451)
8fe9a2425 reduce goVarAssignment regex branches
40bdb6ab0 Implement :GoFillStruct (#1443)
0371da68c Show multiline errors (#1456)
40bf77e5f teach goVarAssign about all assignment operators
5e4ed05df Merge pull request #1460 from bhcleek/update-change-log-higlight-assignment
7a3316f59 update changelog
7a7af87f8 Merge pull request #1458 from xlucas/master
7fbccd9da Variable assignments syntax highlight
1e7560e0e Merge pull request #1453 from Carpetsmoker/fix-list-type-commands
6ce489126 Fix string comparison
2b2ffcdde Fix syntax for `s:default_list_type_commands`
2162c2fa1 Fix :GoBuild shell escaping (#1450)
5730b71ea Merge pull request #1449 from bhcleek/consolidate-list-type-command-keys
b319ed975 Load ftplugin/html.vim for gohtmltmpl (#1442)
2b3610ff5 fix arguments to jobcontrol#s:spawn (#1448)
0ff17516c change GoModifyTags default list type
ce9e0fcd8 refactor for maintainability
262fb6308 doc: add example for go_list_type_commands
6b7bab65a Update CHANGELOG.md
df60f2652 support for customizable lists types (#1415)
dfc89933c Update CHANGELOG.md
eac41c98a Merge pull request #1439 from guns/fix-async-guru-data-race
17c03852f Parse messages from guru on close_cb, not exit_cb
b71f2b757 Fix ChangeLog links (#1436)
5f0c5941b Fix go#package#FromPath() (#1435)
2d36a7882 Merge pull request #1434 from fatih/remove-brackets
a5cdeb59d CHANGELOG.md: fix GH links syntax
e287f9b83 Merge pull request #1433 from fatih/fix-issue-links
5ecd7966f CHANGELOG.md: fix markdown syntax to link to GH issues/pr's
b88a5c989 Proof read documentation: "Intro", "Install", and README (#1432)
f71d6e70a Update CHANGELOG
75d0e9f7a GoImpl: support relative (vendor) imports (#1322)
37e5082d4 Add support for unite.vim for :GoDecls / :GoDeclsDir (#1391)
54bcb5bfa Fix g:go_fold_enable, 'comment' value
aa526f0fb Update CHANGELOG
9cce36bd8 Allow folding any comment (#1428)
0be825dd4 Vim syntax match for variable definitions (#1426)
5db7dd6a6 Load buffers with :GoDef relative to cwd (#1277)
506ddafc2 Add support of g:go_doc_command option (#1420)
67a3e972a Show output of vimhelplint failures (#1430)
ea3346620 Remove accidentally committed file; update CHANGELOG
55a54f149 Merge branch 'pr-1414'
63c76f919 Update CHANGELOG.md
b0ae2c584 Merge pull request #1386 from Carpetsmoker/goimpl
6d15159e8 Update CHANGELOG.md
18eba1a08 Merge pull request #1411 from kirstein/master
cdd056ff8 Merge pull request #1377 from Carpetsmoker/fold-pkgcmt
8ba55ec3c Update Changelog.md
fb2763465 Merge pull request #1422 from jasonkeene/ginkgo-faq
79f451448 Some small :GoImpl improvements
125d5caf3 Fold package-level comments
c420b47cd Add FAQ entry for how to run focused ginkgo tests
117c33413 update comment
b5271d098 Fix to fails of GoMetalinter result filepath in subdir. resolve #1413
79152447b term: exit insert mode
52c5b1f74 fmt: fix backwards compatibility with getqflist
df99b193e Update CHANGELOG.md
9a433e5db Merge pull request #1407 from fatih/fix-autoclose-gofmt
a9ad6b3f0 fmt.vim: only close quickfix if its belongs to gofmt
dfd860471 Add initial commit
8eef8ea57 Add all release information to changelog
4fd3a60da Add old changelog (v1.3)
5939bdd8f Add old changelog (v1.4)
9391a575a Add old changelog (v1.5)
30d036a02 Update CHANGELOG.md
ba09b8fef Merge pull request #1401 from fatih/gomodifytags-improvements
e655a39ba Update CHANGELOG.md
a0ecfabad Merge pull request #1400 from cfsalguero/issue-1396
386e81004 tags: use -modified flag and show errors
525fe8af9 Update CHANGELOG.md
e8e49eac5 Merge pull request #1387 from Carpetsmoker/import-comments
cf15171af Add demo link to syntax based folding
25d00acf3 New release: v1.14
5d5c96665 Updaste Changelog.md
c9052d527 def: only show filename to prevent showing long paths
250c6397c Merge pull request #1385 from Carpetsmoker/godef-msg
78a87d866 Merge pull request #1384 from Carpetsmoker/fold-var
9c292d9ee Update CHANGELOG.md
9c49d42a0 Merge pull request #1394 from mikelue/master
239cbec81 Update CHANGELOG.md
6a470dac4 Update CHANGELOG.md
ebdcf3ad9 Merge pull request #1382 from Carpetsmoker/lint
d758e7f52 Update CHANGELOG.md
13b9eb578 Merge pull request #1381 from Carpetsmoker/vet
805334818 Document how to use a different Go binary (#1373)
d4f931d7e Merge pull request #1395 from deltaskelta/doc-typo-fix
e8cf579db Issue 1396 go#def#tab fails if file is already open
60db0a282 Typo fix
c16c29a8a Complement the path of command for different situations of Cygwin environment
ec6500bb4 Allow comments in import blocks
436bfd58f Show message when using :GoDef and opening a new buffer
a683b6a38 Fixes for folding var/const blocks
2d91dbdcf Run :GoLint against the package of the open file
f439c0cb5 Fix filepaths in the quickfix list for :GoVet
76cd99db6 Merge pull request #1356 from antoineco/master
8de2e7df9 Clarify :helpt prerequisite for using :help vim-go
a35c51f3e Update CHANGELOG.md
68c70160f Merge pull request #1371 from Carpetsmoker/new-file
0da59fe21 Update CHANGELOG.md
629cd6d42 Merge pull request #1372 from Carpetsmoker/gofiles-types
3ba1fefa0 Update CHANGELOG.md
307180cd7 Merge pull request #1374 from Carpetsmoker/spaces
82f7e25c5 Update CHANGELOG.md
64bdf041f Merge pull request #1379 from Carpetsmoker/missing-gogetdoc
026728c51 Merge pull request #1378 from clee/fix-contributing-link
64bd8ddd3 Don't show window if "gogetdoc" command isn't found
f8ce5e051 Fix link in CONTRIBUTING.md
6be1c2175 Preserve cursor column through formatting (#1369)
857eaa5b9 Fix various commands when GOPATH contains spaces.
702b1a490 Make :GoDef work if a file path contains spaces
3b7b37626 Allow specifying which filestypes to list for :GoFiles
bd6c4562b Show correct message when editing a new file
2d89f0052 Merge pull request #1368 from anarchyrucks/patch-1
f95eb84f6 Fix typo
1575dcab2 Update CHANGELOG.md
d5f55053f Fold import, var, and const blocks (#1339)
3b6270e06 Update CHANGELOG.md
ab0df08ca Merge pull request #1367 from fatih/improve-cursor-replacement-fmt
838492059 fmt.vim: fix cursor staying on the same line when goimports is used
ca1d7127b Update CHANGELOG.md
e0e8032a7 Merge pull request #1366 from fatih/fix-multiple-src
02c5d8a57 path: fix autp detecting of GOPATH for import paths with string 'src'
d98b80ecf Update CHANGELOG.md
cc28ff699 Merge pull request #1365 from fatih/fix-gofmt-list
e4e992a1c fmt.vim: default to quickfix list for showing errors
d5979c91e Merge pull request #1364 from Carpetsmoker/hl-type
dd6e15468 Don't add offset to goTypeConstructor.
82998ea2f Update CHANGELOG.md
872bef43d Merge pull request #1363 from fatih/fix-array-index
6d8b86ed9 path: fix gobin path for go => 1.7
bfcf8b057 Update CHANGELOG.md
e56673862 Merge pull request #1361 from seanpile/keep_list_open
4e3f55be7 Update CHANGELOG.md
b54de478e Merge pull request #1362 from fatih/fix-swap-file
fd44242d5 fmt: fix blocking ui when swapfile is enabled
06987d569 Added ability to keep the quickfix/location list window open after successful operations instead of autoclosing
58bfea76b Update CHANGELOG.md
8b02779ba Merge pull request #1345 from fatih/include-func-variable
789ffb460 textobj: include function variable for anonymous functions
f08fcab5c Update CHANGELOG.md
657d0937f Merge pull request #1338 from Carpetsmoker/fix-1282
2647e9bda Merge pull request #1340 from Carpetsmoker/vimhelplint
971f3071f Update CHANGELOG.md
acd0be01a Merge pull request #1344 from robot-dreams/patch-1
1a946d9be Fix warning when goimports doesn't support srcdir
55ba44a57 Fix doc lint error
f7df583a0 Add vimhelplint to Travis tests
cfa9713eb Match zero-width in goTypeConstructor
bcf3f23dd Update CHANGELOG.md
0a8af0caa Update CHANGELOG.md
4787f2762 Merge pull request #1335 from Carpetsmoker/go_doc_max_height
290887538 Update CHANGELOG.md
4fd118269 coverage.vim: add echo message for GoCoverage
837143b72 Merge pull request #1336 from rhysd/fix-typo
841457035 fix typos in docs, changelog and sources
2eb88b70a Add g:go_doc_max_height setting
3806c4e59 Update Changelog.md
2df21ebaf Merge pull request #1330 from fatih/go-build-cache
e1c0d7b0b cmd: add -i flag to go build
182a9dd14 Add a note about the recent test refactor
7b93bae4b commands: expose :GoDecls{Dir} command to show a warning
147360e9a Update Changelog.md
91b159a7e Merge pull request #1326 from tmc/coverage-args
f5898d3c8 Create CHANGELOG.md
aefc0a2a0 Merge pull request #1327 from fatih/fix-echo-output-tesst
21cfbbc0d test: fix outputing message when test finishes
b9bef683b coverage.vim: pass along arguments to coverage_job
fec6321d2 Update CHANGELOG.md
d75e17546 Fix syntastic help (#1323)
4f2bdd61a Update Changelog.md
bf9cdc211 Update Changelog.md
913c181b8 Merge pull request #1321 from fatih/improve-import-path
15d3b3c86 package: improve import_path by using go list
61b897f14 Update CHANGELOG.md
bc097c164 Merge pull request #1320 from fatih/cache-env-calls
52e5ad5cf Update CHANGELOG.md
e2be1fa7e Update CHANGELOG.md
a4b64e28e Merge pull request #1318 from bhcleek/feature-test-template
f4be8f612 Use a different template for test files
4f04d680e New release: v1.13
b0a11f016 Improve caching for go env calls
d2e1e1764 Update CHANGELOG.md
404dca66d Merge pull request #1319 from fatih/fix-def-tags
150b2cc05 def: fix passing build tags to guru
16e0ccf28 Update CHANGELOG.md
196792d20 Merge pull request #1317 from fatih/test-compile
21376e689 test.vim: more efficient compiling of test files
7fafcb14f fix coverage to use new test.vim file
9b3aa3f2d Update CHANGELOG.md
161bc4632 Merge pull request #1316 from fatih/fix-test-coloni
8f0029172 test.vim: fix messages with colons
57aaa95ac Merge pull request #1315 from fatih/standalone-test-parsing
d2ff39ca7 test.vim: refactor to use its own parse function
76044c0c5 Merge pull request #1314 from fatih/refactor-parsing
8f9699486 Refactor all test related commands into test.vim
899b741f2 Merge pull request #1311 from tgrosinger/typo-fix
57e062a27 docs: fix typo in command
476239117 Update Changelog.md
60565da2d goimports fails when proj symlinked in GOPATH (#1310)
aec329223 Update Changelog.md
0325c5e04 Specifies the type of list to use in GoMetaLinter, by go_list_type (#1309)
aab6381ea Update Changelog.md
016c03c99 path: do not use a dedicated function for cygwin
3f5dd0a5a Add path convertion for native-win-vim with Cygwin support (#1092)
0235a8f85 Update Changelog.md
66b04e85d Merge pull request #1308 from fatih/improve-fmt-commands
e6533efc8 fmt: change go_fmt_options's type to dict
00ab89e4d Update CHANGELOG.md
b8a6dc963 Merge pull request #1296 from fatih/term-neovim-fix
ff3c10ec4 Update CHANGELOG.md
e63e16602 Merge pull request #1304 from fatih/add-listtype-support
e3760a58d fmt: add support of 'go_list_type' for :GoFmt and :GoImports
8efd1dd73 Update CHANGELOG.md
66e3d342f Merge pull request #1301 from zkry/highlight-interface-struct-fix
f8863b067 Fix the highlighting error by putting the interface\|struct section inside \( \) to correctly identify word boundries
403b9bb29 Merge pull request #1300 from robphoenix/master
276e7abc2 fix single spelling error in vim-go.txt
7b311be14 Update CHANGELOG.md
162e26369 do not jump to the quickfix window when gometalinter is executed (#1293)
1cc18529e Merge pull request #1299 from fatih/fix-tags-settings
07e055236 addtags: unify settings for case setting
c1ae945f6 util: remove nonused go#util#AddTags function
4fda59601 term: fix cwd after running command
05efdfe80 Update CHANGELOG.md
2e1979847 Merge pull request #1295 from etdub/master
fd7d4d40d Change GoLint command to lint the current directory instead of the current file (issue #1263)
7fb96896f Update CHANGELOG.md
26e61829c Merge pull request #1280 from fatih/fix-autodetect-gopath
c609352bb path: return the unmodified GOPATH if autodetect is disabled
6f392c454 Update CONTRIBUTING.md
1143f398e Merge pull request #1279 from fatih/update-docs
8b7d743e5 docs: add new :GoDef mouse mappings
1c6ccb1f2 Update CHANGELOG.md
eb739e185 Merge pull request #1264 from lilydjwg/master
4cdb20ca5 Update CHANGELOG.md
f6554604f Add :GoAddTags transform (#1275)
8532385af Update CHANGELOG.md
8e0ddef60 Merge pull request #1276 from creaky/master
d92a4f6f0 Updated code based on feedback and further analysis
27228dada Merge pull request #1278 from dorons/master
872e4e190 Fixed indent for 'ife' snippet
b57ee9088 Update CHANGELOG.md
1a7887e32 Include keyify support (#1258)
e9bb5eaa4 Fixed issue Vim-Go broken on freebsd #1224
aab745ece Update CHANGELOG.md
cdffa16f5 Merge pull request #1268 from Foxboron/patch-1
f1c6f6649 Include if with inline error handling
78c2a9a0b support <C-LeftMouse> as well
b4936d89b Update README.md
ae5e0d887 Merge pull request #1255 from fatih/readme-improvement
580103e67 Simplify Readme.md
08d0c34d0 Update changelog.md
c71c75e4c Merge pull request #1247 from pborzenkov/close-race
48e0660e2 Update Changelog and add docs for new gometalinter feature
18a5dad3c Merge pull request #1253 from redforks/master
882a1932e Add go_metalinter_excludes config variable
55906b13d Merge pull request #1250 from bradleyfalzon/patch-1
f16e5d9fe Minor typo in change log
26362e4bf New release: v1.12
c20e192ea Update CHANGELOG.md
7871cd94b Update CHANGELOG.md
727aed364 Merge pull request #1248 from fatih/default-gopath
6db12a966 Go 1.8 compatible GOPATH improvements
5c721a278 job: fix race between channel close and job exit
411981189 Update CHANGELOG.md
b14621829 Merge pull request #1246 from fatih/fix-install-arg
58adebd7a cmd: we don't need to shellescape for jobs
e0a7b12e1 Update CHANGELOG.md
5d684f6da Merge pull request #1235 from thsnr/master
58853d520 Update CHANGELOG.md
a83c4c0bc Merge pull request #1242 from danielheller/godef-help-explicit-arguments
cec0fc361 Update GoDef help: remove explicit arguments
1aa048b2d Allow trimming around comments in gotexttmpl syntax.
362e15ab4 Merge pull request #1233 from rigelrozanski/patch-1
8cb66af59 Updated Broken Link
eb8adf52b Tidy up and fix typos
091a8c1f9 Update CHANGELOG.md
0586539e0 Add :GoBuildTags to set build tags (#1232)
cf3aad953 Update CHANGELOG.md
03fc6a710 Add build tags support for gorename (#1225)
b9c815626 Update CHANGELOG.md
71efb2e6d Set GOPATH for both possible go guru execution paths (#1193)
7ff6d8e06 Update CHANGELOG.md
92d0d07a6 Merge pull request #1195 from haleyrc/master
70aba7c27 Update CHANGELOG.md
ac2f89b41 Merge pull request #1197 from jhillyerd/noshowdoc
7149f3eec Update CHANGELOG.md
468fa9823 Merge pull request #1199 from tarrant/master
9a9f010ec Update CHANGELOG.md
2fc67cd72 Merge pull request #1211 from cespare/goimports-options
ded4d3169 Respect go_fmt_options when running goimports
4490a1f67 Fix whitespace and typo (#1201)
68f398b3b Update CHANGELOG.md
a8a253bb8 Update CHANGELOG.md
e4e5e2267 Merge pull request #1204 from fatih/gotags
eca86e03f New GoTags improvements
d3f90c21e Set the filename in the location-list
d5d826a69 Document 'noshowmode' requirement for echo_go_info
884870e88 Modify the resize behavior for godoc
1425decf6 Update CHANGELOG.md
fc1ab4052 Merge pull request #1194 from jblebrun/no-gopath-env-fix
a4edbfc8e Ensure no trailing : in gopath
9b0362562 Update CHANGELOG.md
119eec1b3 Merge pull request #1177 from francescomari/guru-tags
0dacf2917 Update CHANGELOG.md
86834ce79 Merge pull request #1184 from mattn/non-utf8
9cb5965f5 Update CHANGELOG.md
6e832e6c0 Merge pull request #1185 from mattn/errl
f6ad41d15 Update CHANGELOG.md
a8592baf7 Merge pull request #1192 from vieiralucas/patch-1
375ce716c Update CHANGELOG.md
3c5f09de5 Merge pull request #1176 from joshuarubin/neovim_go_build_fixes
d7860c34d Lowercase <Leader> in mappings examples
c29fac849 log.Fatal(err) is useful
ddf3ad471 Support 'encoding != utf-8'
3e8551253 Correctly report the value of the 'g:go_guru_tags' variable
83296ac0b fix :GoBuild issues in neovim
3eb57ac3a New release: v1.11
07dabeb11 Update CHANGELOG.md
001cce799 Merge pull request #1174 from zmb3/zb-godoc-browser
e3a760fd9 Fix :GoDocBrowser for third party package doc.
ba08326b2 Update CHANGELOG.md
41f5fd135 Merge pull request #1146 from horgh/master
7635fc0eb Update CHANGELOG.md
f9391628d Merge pull request #1152 from ismail/ismail-patch-1
8775ba7f5 Merge pull request #1168 from fatih/fix-docs
e3e9fef6a Update CHANGELOG.md
fba058f98 Merge pull request #1167 from fatih/disable-highlight
16ffe5d88 docs: fix unused feature
0a3b205c8 syntax: switch options to off
47447feea Update CHANGELOG.md
283fe500e Merge pull request #1160 from thsnr/master
10af7bc2a Use go_metalinter_command as List after split().
d7c628ff2 Merge pull request #1159 from fatih/godef-tests
e27a00365 tests: add def_test.vim
a9bc540b0 Update readme.md
73f707d46 Merge pull request #1158 from fatih/improve_tests
b586c7e4f tests: add new test, update runttest.vim
b27031ab0 Update CHANGELOG.md
bd6e33ed4 Merge pull request #1157 from fatih/vim-go-tests
145893132 Add travis integration and initial test suite
7d3e4bc8b Merge pull request #1156 from bhcleek/fix-sameids-BufWinEnter
ffe8fc402 clear buffer-local BufWinEnter properly
fa7dc2eaa Update CHANGELOG.md
edcd9c813 Merge pull request #1155 from bhcleek/fix-guru-async
7eeb2f87e use funcref() instead of function() for closures used as callbacks
407dcda3f If GOPATH is empty check for the value of go env GOPATH
95be72ddd go_metalinter_deadline applies in async mode now
e46dd4dde Update CHANGELOG.md
708861202 Merge pull request #1133 from bhcleek/fix-godef-stack-pop
66c72b4ad def: indent
d5abc9d80 Update CHANGELOG.md
054951253 Merge pull request #1132 from bhcleek/fix-godef-split
57e19fa7a Update CHANGELOG.md
398680c1f job: set explicit bang to avoid errors in case it's being used
cd793b75a Update CHANGELOG.md
9f9b93767 Merge pull request #1124 from jimmyfrasche/master
ca4b4437b Update CHANGELOG.md
86adc49b1 Merge pull request #1136 from jdhenke/master
0eaa355a7 Update CHANGELOG.md
8e44afc0f Merge pull request #1145 from entombedvirus/fix_jobcontrol_on_exit_err
709a4585e Update CHANGELOG.md
e15c781d1 Merge pull request #1143 from kechako/fix-indentation-broken
69e2b2c66 Update CHANGELOG.md
7cde15acd Merge pull request #1141 from oystedal/oystedal/1140
39ebca3a1 fixes #1144: "E118: Too many arguments for function: <SNR>173_on_exit"
d1f5dd3bd Update README.md
a55c85338 Fix indentation broken when using a action with a minus sign like `{{-'
d3c9fc07b Change default value of `g:go_asmfmt_autosave` to 0.
93984b340 fix bug in guru vim script
08c881dea Changelog.md: add requirement
66ce0c0d3 make requested changes to documentation and setting name
6bf649098 Merge pull request #1135 from fatih/fix-setloclist
edacc3687 list: set title only for recent Vim versions
6094a38b2 allow popping from jump list when buffer is modified
973ba8c29 handle :GoDef from modified buffer
4a993be12 Update CHANGELOG.md
309c94fbe Merge pull request #1128 from fatih/fix-coverage-syntax
10a8ddcda coverage: no need to change turn on/off syntax
eeae7b0bf Update CHANGELOG.md
b882d1fa7 Merge pull request #1127 from fatih/fix-coverage
4aee04ff7 cmd: do not expand coverage arguments
6ee972ddd Update ISSUE_TEMPLATE.md
d277006b4 Update CHANGELOG.md
01ec25cae Provide a descriptive quickfix/location list title. (#1004)
9e88616c2 Add option to use cwd as package name instead of template
96a07bd88 Update CHANGELOG.md
cb88925a4 Merge pull request #1123 from pborzenkov/job-ccl
40344d43b job: close quickfix window if a job has succeeded
c07e9e0a3 Update CHANGELOG.md
1a9f0ee2e Merge pull request #1122 from fatih/patch-echom-fix
dd2a13642 path: use echom so it's showed when used completion
4944f0ef8 Update Changelog.md
f60e4fd42 Merge pull request #1121 from pborzenkov/statusbar-update
5265ad2da Update CHANGELOG.md
7785d369c Merge pull request #1055 from svanharmelen/f-setlocal-updatetime
0996bdacb Add `g:go_updatetime` to configure a custom `updatetime`
79fa535b1 Always use full path as statusline target directory
bf2110457 Update CHANGELOG.md
b4adab50e Merge pull request #1120 from fatih/gometalinter-statusline
c27297286 lint: add statusline support for GoMetaLinter
d07982689 Update CHANGELOG.md
dcbedd7b8 New release: v1.10
824f44ab8 Merge branch 'master' of https://github.com/fatih/vim-go
8df04a986 New release: v1.10
f3ee8cd5c Update CHANGELOG.md
c0b180a52 Update CHANGELOG.md
d9194b7d1 Update CHANGELOG.md
c44f799be Merge pull request #1089 from tdilo/add-golint-plug-mapping
0b6d16c57 Merge pull request #1119 from fatih/goinfo-improvements
05f7fb837 info: add option to change underlying tool for :GoInfo
cb8329a2b Update CHANGELOG.md
b84f01ae9 Merge pull request #1033 from pborzenkov/coverage
2b34076d0 coverage: allow to run coverage on _test.go files in subdirs
7c27c6be9 Merge pull request #1118 from fatih/fix-wall
d35e866a8 cmd: wall tries to write to unnamed buffer, neglect errors
3b6da4942 Merge pull request #1117 from fatih/test-func-fix
303c0a2bc cmd: fix :GoTestFunc for job API
d3c4fb3d2 Merge branch 'master' of https://github.com/fatih/vim-go
505e726e2 Update README.md
75b6713bc Merge pull request #1114 from fatih/check-job
86c7e12f5 vim: require at least 8.0.0087 for +job features
c212e28fa guru: do not use abort, is not compatible with old Vim versions
b2ecbf8c0 Merge pull request #1110 from fatih/fix-new-variables
b82060212 go: do not use new type variables
59c56f090 Merge pull request #1104 from fatih/vim-8.0-squash
dc8073386 Add vim-8.0 support
362decf1a complete: disable unimported support
303667f4f Update CHANGELOG.md
e198faaa7 Merge pull request #1100 from Alok/add-abort
37f828315 Update CHANGELOG.md
de782e8ac Merge pull request #1101 from haya14busa/option-go_echo_type_info
ec9f4ac3f Merge pull request #1102 from stamm/patch-1
26d766a27 typos in changelog
298520ce1 add an option to show type info when completion is done
a822b9792 Add abort to every autoload function
d85444b32 lint: add (go-lint) plug mapping
10c805b83 Update CHANGELOG.md
fcd04ce1f Merge pull request #954 from fatih/fix-gocode-goroot
23c0cb00c Update CHANGELOG.md
42bc216cc Merge pull request #1067 from bhcleek/fix-sameids-change-buffer
0b631151f Update CHANGELOG.md
be4eae0ba Merge pull request #1070 from svanharmelen/f-highlight-func-calls
64021135f Update CHANGELOG.md
b76d55f52 Merge pull request #1075 from magicalbanana/allow-nested-struct-highlighting
936837ec0 Update CHANGELOG.md
8b73c3f71 Merge pull request #1084 from zmb3/unimported-packages
54b2650c4 Provide completions for unimported packages.
7461762f7 Update CHANGELOG.md
127ecfedd Merge pull request #1083 from fatih/fix-jumping-to-split-modified
54fa4679a def: do not open a split for modified file
80b0ca2d1 Make sure builtins are hightlighted correctly
31c13f672 Syntax nested structs
1f8e10ceb Merge pull request #1072 from hitjim/patch-1
f41f55323 Update license to credit Renee French for Gopher
8faedbebf Update CHANGELOG.md
977b68d22 Merge pull request #1048 from svanharmelen/f-highlight-func-calls
a09d179d8 Clear most recent goSameId highlights groups
bae1529cd util: add go#util#env function
6ca257751 Update CHANGELOG.md
32f9d2bf5 Merge pull request #1062 from lukatendai/master
acab9b3f6 Update cmd.vim
2b19e6c18 Merge pull request #1047 from abhinav/patch-1
4bf1d139f skip go#util#Shelllist if nvim is being used
09522e50c Update CHANGELOG.md
fc4f5a432 Merge pull request #1061 from egonelbre/master
4e3628042 Use transparent background for image.
fecb68867 Update CHANGELOG.md
5fda1883f Merge pull request #1060 from fatih/assets
38ff97edc Add vim-go logo /cc @egonelbre
d6c1ec9a4 Add assets dir with new logo from @egonelbre
8205e3542 Merge pull request #1052 from mattn/sock_type
86b1e7aa2 fix default sock type
961466fb2 Add support for highlighting function calls
7fd92a842 Update CHANGELOG.md
ac4a9757d Merge pull request #1049 from nhooyr/syntax-fix
451f8a0da goPredefinedIdentifiers should link to goBoolean by default
b14be232b Fix reference to go_highlight_{structs,interface}
d9fa1bcca New release: v1.9
b52601889 Update CHANGELOG.md
417fd0ca7 Merge pull request #1046 from mattn/v8.0
168c4a4b3 better to use exists('*exepath')
8575d9e3c Fix bug in syntax highlighting (#1035)
0a25a0ddd Update CHANGELOG.md
8d6356616 Exclude iota and nil from goBoolean (#1030)
c63c798f7 Update CHANGELOG.md
a5222bfdc fmt: print full goimports path if it's not compatible
2aad0a8a6 Update CHANGELOG.md
495cf403c Merge pull request #1007 from magicalbanana/highlight-field-field
990916af8 Update CHANGELOG.md
1f143f3dc Merge pull request #1020 from kaneshin/patch-1
5b53a72bb Update CHANGELOG.md
d5ac28c35 Merge pull request #1011 from ArkBriar/master
804130fc9 Update CHANGELOG.md
8de252ae9 allow :GoDoc on modified buffers (#1014)
9380cc445 Update CHANGELOG.md
31ea0aaf7 Merge pull request #1017 from fd0/add-hint-updatetime
b76f8f501 Update CHANGELOG.md
cbe7d101b Merge pull request #1029 from nhooyr/master
5d4fcaa47 Update CHANGELOG.md
0a66df41d Merge pull request #1023 from yyoshiki41/update/doc
4b9258e8a update jumplist in :GoDef
c306de904 Add go_highlight_generate_tags in docs
313127ee4 Rename GoMetalinterAutoSaveToggle to GoMetaLinterAutoSaveToggle
63bdcdf65 Update CHANGELOG.md
f1f6e71a3 Merge pull request #1016 from kisielk/patch-1
241818330 SameIds: Fix Sentence, add hint to 'updatetime'
41dfa207b set updatetime if g:go_auto_sameids is enabled
d72ed3ab5 Fix syntax goFormatSpecifier: check '%%'
359a8c5ca Highlight nested fields or chained fields
a4ba0a5b1 Update CHANGELOG.md
973724f6e Merge pull request #998 from bhcleek/sameid-autocmd
a0edd32f7 Update CHANGELOG.md
4c2069649 Merge pull request #999 from umitkablan/master
2514a4221 Update CHANGELOG.md
67084f500 Merge pull request #1000 from fatih/add-gocode-socket-type
d9c531fca complete: add g:go_gocode_socket_type setting
a6e097cb9 Fixed Windows tagbar&GoCallers errors with g:go#use_vimproc=0.
7d1433761 Re-evaluate sameids after buffer is re-entered
a0d769dd9 Update CHANGELOG.md
e7f5e5756 Update CHANGELOG.md
37b95186a Fix :GoSameIds for light background, GUI, and after changing colour schemes (#983)
ecac6556a util: do not clear the screen
99d5bf8e0 Update CHANGELOG.md
445e5bf10 use guru's -modified flag (#944)
af2798046 Update CHANGELOG.md
49f4e2a34 Doc cleanup (#987)
7bcf1f554 Update CHANGELOG.md
011d76fbd Merge pull request #988 from Carpetsmoker/windows-shell
2dfd933c5 Use go#util#IsWin
53261bc0a More robust resetting of the shell.
3030ecc86 New release: v1.8
12b3f65a0 Update CHANGELOG.md
4f06fda92 Merge pull request #971 from fatih/gooaddtags
6e0d6c363 commands: add :GoAddTags
13affe57d fixed goField regexp (#981)
51930f327 Update CHANGELOG.md
7af695b1b add commands to toggle settings that control auto behavior (#945)
55fe1705d Escape all template path special characters (#966)
d3fb314ea Update CHANGELOG.md
881a9cc0f Reset shell before running a command in go#util#System (#967)
9ed023b39 Merge pull request #972 from roxma/master
b329b1c10 Merge pull request #974 from bhcleek/sameid-warning
6adfed303 Update CHANGELOG.md
4a403b6e3 Merge pull request #980 from fatih/fixes-from-wladh
7e30f82b5 Add guifg to go coverage syntax.
4c8a7046e Make GoInstall use detected $GOPATH
85a9d62e4 Merge pull request #979 from datanoise/master
59f38f020 link goPointerOperator and goVarArgs to goOperator.
5e36218d0 goVarArgs highlight groups is too gready.
7689ab482 add warning to GoSameIds when matchaddpos is unavailable
bc2746c1e add SimpleAutoComplPop to the list
59a236108 Merge pull request #969 from vrischmann/master
62d6026b9 tool: use double quotes in PackageName for Windows compatibility
69e038e5c Update CHANGELOG.md
a4c9c4e44 Merge pull request #968 from fatih/idawes-master
d24cd35a1 doc: add more context
844cf27ca Consisten mappings and commands
e272cf309 Merge branch 'auto-toggle' into idawes-master
271766d76 Merge branch 'master' of https://github.com/idawes/vim-go into idawes-master
e977689a3 guru: add GoSameidsAutoToggle
c8cf79257 Merge pull request #946 from bhcleek/buffer-sameids
b7ac76ad7 Update CHANGELOG.md
1e7d0480a Merge pull request #962 from fatih/separate-coverage-syntax
e648b71f6 syntax: add goCoverage specific highlights
c3cd94941 Update README.md
368f72927 Update README.md
9754508b3 Merge pull request #958 from datanoise/master
7c096c20e go#fmt#Format fails on new unsaved files
c5101afa6 Update CHANGELOG.md
4de469674 Merge pull request #957 from fatih/make-goimports-great-again
5fb42bd4e fmt: pass full name to -srcdir for upcoming new features
0faef8a43 refactor: use lowercase function names
2db19ffd2 Merge pull request #952 from magicalbanana/fix-setfperm
d8eb1cdb7 Fixes the 'setfperm' issue
8ce50ff3e guru: make whicherrs usable for empty results
23abbac23 Update CHANGELOG.md
81bee4405 Merge pull request #948 from krishicks/guru-add-whicherrs
71aeea6d5 Merge pull request #949 from ArkBriar/master
1a38ce6c7 Merge pull request #942 from dobegor/patch-1
c38cb772d Update CHANGELOG.md
902f626c4 Merge pull request #922 from joegrasse/master
3a86d0f8a guru: add :GoWhicherrs
140a2ff75 Replace 'he=e-1' with '\ze' to avoid conflicts with other highlight plugins (e.g. luochen1990/rainbow).
e53e6126f use CursorHold instead of CursorMove for go_auto_sameids
081f3423e Vim & Neovim now both support JSON
595df5118 Update CHANGELOG.md
684548da2 Merge pull request #937 from dangogh/yaml-tag
9fce7407a Merge pull request #939 from bhcleek/allow-disable-auto-features
96105a22a Merge pull request #938 from bhcleek/reduce-guru-what-flicker
94f579cdc Merge pull request #940 from bhcleek/customizable-goSameId-highlight
4801d2853 Add ToggleSameIds
df02251e4 Neovim supports JSON, :GoSameIds now works.
3715a8908 allow goSameId highlight group to be overridden
30a6a2c6c allow auto features to be disabled without restarting Vim
7a312d97f reduce flicker when using go_auto_sameids
789de8e4e Update CHANGELOG.md
78a766756 Merge pull request #936 from fatih/bhcleek-master
41ae14a74 guru: improvements
6de8841f0 Add support to run Guru commands on umodified buffers
82ff2d872 add setting to automatically run :GoSameIds
16f3d7415 implement :GoSameIds
f9549b752 add yaml tags completion
7fe846b1c Merge pull request #930 from datanoise/master
ab01e7e5a Merge pull request #931 from svanburen/patch-1
7d1616ad4 Fix typo in docs
9816d691a small syntax fixes
dede10f4a Update CHANGELOG.md
0b1fa09d9 Merge pull request #927 from fatih/json-snippet-case-type
153f2231e snippet: make json field tag expansion smarter
7876aaf55 snippets: make json snippet more smarter
a049691f0 snippet: fix panic
01624ffc3 Update CHANGELOG.md
98d4f5eee Merge pull request #926 from fatih/add-snippet-err-panic
cb442358b snippets: add errp for error panic
48d31eb2b Change setting name to something better and coherent with others
4778de4ae Update CHANGELOG.md
d142f7db3 Merge pull request #918 from fatih/auto-create-template
23b7c2268 Fill the content of a new file automatically based on the context
eb585ff6d Merge pull request #924 from tsne/fix-type-highlighting
cd35ebdf5 fix highlight type keyword
2c5295871 Restore original files permissions
25bbb3135 Update CHANGELOG.md
d3fb19d78 Merge pull request #920 from dobegor/master
498e709cf Fixed typo causing GoDocBrowser to fail
7c3414e5f Update CHANGELOG.md
50ceca52a Various improvements to syntax highlighting. (#917)
ecfd5cff3 Update CHANGELOG.md
1a9cc7867 Merge pull request #915 from fatih/indentations-fixes
5a4abb592 style: use two spaces for all files
a7a37517a Update CHANGELOG.md
1e9590dba Merge pull request #910 from fatih/def-modified-file
336e3b090 def: support modified files
b12fd9bb5 Update CHANGELOG.md
9875a4690 Merge pull request #909 from fatih/fix-go-test-compile
1457e6e2c cmd: fix :GoTestCompile leaving behind artifacts
523d5a435 Update CHANGELOG.md
7b92adf89 Merge pull request #904 from fatih/fix-goimports-picking-srcdir
67489a688 fmt: fix goimports picking up -srcdir
6efcfb275 Update CHANGELOG.md
4f20c2524 Merge pull request #900 from fatih/fix-coverage-nvim
f846d078e coverage: fix running coverage for neovim
76d295c19 Update CHANGELOG.md
478a23942 Merge pull request #897 from ryunix/fix-doc
1147bbc70 Update CHANGELOG.md
a3452fdf2 Merge pull request #895 from mattn/fix-openbrowser
492e54bb2 Update CHANGELOG.md
8d73ed0bc Merge pull request #894 from mattn/godoc
85579cbd5 Fix doc
98fe1f95e escape #
cf4f0ea1e open GodocView if argument is provided for :GoDoc
6a0c880df New Release: v1.7.1
0fd6f46e7 doc: fix wrong documentation about field and struct highlighting
8c9cbabfd Merge pull request #892 from ryunix/fix-typo
ab62d6ddd Fix typo
191ba9a60 New release: v1.7
28e63a50b Update CHANGELOG.md
9b198271a Merge pull request #888 from fatih/go-def
10187323d def: add go_def_mode setting, we now support godef too
3c099cc66 cmd: check test files only for coverage
473c0bdfb Update CHANGELOG.md
a284b6196 Merge pull request #854 from hhsnopek/hs.goField
ae89f68f1 add goField
2f115dcf7 Update CHANGELOG.md
e46c5efcd Merge pull request #883 from macb/get_update
04a0faae2 make go get -u configurable
211289683 Update CHANGELOG.md
28d6c0048 Increase compatibility with tcsh (#869)
684be5dfb Merge pull request #882 from yukidarake/fix-neosnippet-invalid-syntax
485d8ba3c Fix broken snippets
c72fd199f Update CHANGELOG.md
99e06a043 cmd: fix showing SUCCESS for non tests
b7147085c Revert wrong fix
8e0ea1266 cmd: run tests only if the test file exists
e6a76161c cmd: fix runtime error for :GoCoverage
acb2d8c91 docs: add docs for go-import and go-imports
bc3726303 Update CHANGELOG.md
572617f16 Merge pull request #879 from fatih/do-not-create-test-binary
be326e6a8 cmd: do not create test binary artifact for :GoTestCompile
a9611d7d6 Properly use exepath for CheckBinPath (#864)
b25dbfb23 Update CHANGELOG.md
b74234bbd Merge pull request #878 from edganiukov/goimports-mapping
484ead33c added goimports mapping
e9f44d933 fmt: use helper function to print warning
53c779f82 Update CHANGELOG.md
0a1f71faa Merge branch 'master' of https://github.com/fatih/vim-go
46da9d331 coverage: use color aliases for backwards compability
42c73c2a8 Update CHANGELOG.md
92632a024 def: quote the file argument completely for tcsh
8b1c0e93f Update CHANGELOG.md
dc1496713 Merge pull request #862 from fatih/fix-lint-escape
eb19cc520 textobj: escape files for motion as well
c1e976135 Merge pull request #866 from trayo/master
76d43aca5 fixes typo
d54819ddc Update CHANGELOG.md
5d5a5b228 Merge pull request #861 from DeepAnchor/master
d909e2e41 lint: escape directory for shell invocation
d570e89b4 Add non-standard workspaces to package path list
48cc65dfb Update CHANGELOG.md
8765cee38 Update CHANGELOG.md
a3c0dab15 Merge pull request #856 from fatih/add-gocode-autobuild
b0e00f631 complete: enable autobuild and propose-builtins
5c74881e0 Update CHANGELOG.md
fea6ef317 Merge pull request #855 from fatih/fix-gorename
4311f5b18 rename: reload all files to reflect the new changes
1ec3373f2 Update CHANGELOG.md
96b0aa584 Merge pull request #847 from shawnps/patch-1
eb6ae9d1c use https in playground URL for GoPlay
1f2245335 impl: this is a better copy
5e589bba6 Update CHANGELOG.md
87a3bb954 impl: add vim-go-impl (#846)
1dfaae447 Added http to http handler snippet (#843)
78c56adc1 Update CHANGELOG.md
927e31ad2 add nnoremap <buffer> <silent> <C-w><C-]> :<C-u>call go#def#Jump(spli… (#838)
2d9124f1a Updated `benchmark` snippet to use for loop (#840)
9f0cf00f6 path: do not exepath
ca46f2d0a Update CHANGELOG.md
95f43b8ab Update CHANGELOG.md
62f8aa38e don't default to binaries in the PATH (#823)
d2f22ba3d Update CHANGELOG.md
ff70ed5b6 Snippets for Example and Benchmark (#836)
5a846f358 Document using quickfix list for syntastic (#834)
91ffc4108 Update CHANGELOG.md
7a5dc84aa Merge branch 'master' of https://github.com/fatih/vim-go
bbe4357a6 mappings: fix freevars mapping
849a8bb0b guru: fix preventing printing the output twice
91ff811b6 Update CHANGELOG.md
36e96cd52 Update CHANGELOG.md
56ac0d7dc guru: fix providing meaningful error messages instead of showing "-1"
e3ebd69d2 Update CHANGELOG.md
93831e8b3 guru: implements needs scope to function well
1ebda8368 Update CHANGELOG.md
2541180a5 Merge pull request #813 from fatih/fix-gohtmltmpl
4679725cf Update CHANGELOG.md
1469db423 Merge pull request #827 from fatih/fix-coverage-syntax
766e836bc coverage: fix for cases of syntax=off
dcbe7cef6 Update CHANGELOG.md
42a782f38 Merge pull request #821 from sillyousu/master
6e2df56e7 Merge pull request #826 from mattn/fixes-824
7a8384acc exit code should be checked with 0
12e8bed78 pass -tags flag to guru
dfb0ee1ec Update CHANGELOG.md
f830d0dc1 use go#util#system(), go#util#shell_errors() instead of system(), v:shell_error (#801)
e9df17fc7 Update CHANGELOG.md
08a9c7c70 Merge pull request #816 from andrewstuart/master
ede2ec511 Add http handler snippets
480b7660f New release: v1.6
8a78ded14 def: reuse is a better word
d439e855a ftplugin: add gohtmltmpl.vim
a605c6216 Merge pull request #812 from fatih/coverage-improvements
7351848a2 coverage: add :GoCoverageClear and :GoCoverageToggle
4f67ae2dc Merge pull request #802 from sethvargo/patch-1
4c7967c08 Clarify that mappings are enabled by default
b3fddb60f Merge branch 'master' of https://github.com/fatih/vim-go
abd3d1490 doc: fix wording for (go-run) mapping
fd10ba68f Handle windows paths (#799)
5c45ba9c4 coverage: check if matchaddpos exists
a0f8bd34d def: fix selecting from tag stack
c3fdca0e4 def: fix displaying guru errors
cd473451e Update CHANGELOG
24aeacc43 def: jump to an existing buffer if its exist
58d73af73 Merge branch 'master' of https://github.com/fatih/vim-go
53e924411 def.vim: revert back mapping to ctrl-t
c0f7d3ee8 Update CHANGELOG.md
16cc4d62c mappings: change CTRL-t to CTRL-T for compatibility
cce10c75d guru: fix output format
ab55541df def: use script local variable
3a596f5bf Update README.md
2e5996015 Merge pull request #781 from fatih/guru
3eac959bf Add support for new guru tool
b97962689 Merge pull request #794 from cuzelac/master
985c0922a Update CHANGELOG.md
075cfb3a7 Update CHANGELOG.md
fbc9b4e6c Update CHANGELOG.md
6d88d521b improve :GoDef and  tag stack commands
449dc59a4 GoTestFunc: support testable examples
80f6cf8fa Add custom godef jump stack (fixes #667) (#776)
385a92f01 Update Changelog
7f248b206 Merge pull request #782 from fatih/godoc-improvement
160bedc2b syntax: remove not used godoc.vim
f478b530c doc: use gogetdoc to display docs in a better way
9f2fac6cb Merge pull request #790 from fatih/coverage-term-fix
52dbc47b7 coverage: fix not working if go_term_enabled is set
5ce65295c coverage: open only if file exists
a4f44db42 Merge pull request #746 from eliasgs/master
451cb1acc Update README.md
f6c71e7c7 Update docs
fe718fc9c Merge branch 'master' of https://github.com/fatih/vim-go
dc98bc775 Update Readme.md
aea106131 Merge pull request #787 from cespare/optional-format-highlight
cc4584404 Remove whitespaces
952b75259 Add go_highlight_format_strings option for printf-style format strings
1ac0d1f8e Update Changelog
e35dfca6c Remove artifact
407908ad6 Merge pull request #786 from fatih/t-yuki-vim-go-coverlay
0eff02604 coverage: improvements and integration into vim-go
f92fac2fd Add vim-go-coverlay
e93048420 fmt: use shellescape instead of fnameescape
5c282de1a Update CHANGELOG.md
1a82fb7d5 Add fix
c4183771f term: close location list if cmd's result is successful
ef9bc716a term: close location list if cmd's result is successful
230b1bb69 Update CHANGELOG.md
0ff0a2dde Add CHANGELOG.md
19cfa6fbb jobcontrol: add AddHandler and RemoveHandler API to catch on_exit callback for callers of caller

git-subtree-dir: vim/bundle/go
git-subtree-split: bf390af42c53ae217356d7763ac3e7767f0162a4
main
Buddy Sandidge 7 years ago
parent c9ca63a819
commit c7496b2816

@ -0,0 +1,3 @@
[run]
plugins = covimerage
data_file = .coverage.covimerage

@ -0,0 +1,2 @@
.local/
.git/

@ -0,0 +1,17 @@
# http://EditorConfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[*.go]
indent_style = tab
indent_size = 4
[Makefile]
indent_style = tab
indent_size = 8

@ -1,9 +1,12 @@
Thanks for improving vim-go! Before you dive in please read the following: Thanks for improving vim-go! Before you dive in please read the following:
1. Please read our 1. Please read our
[FAQ](https://github.com/fatih/vim-go/wiki/FAQ-Troubleshooting), it might [Documentation](https://github.com/fatih/vim-go/blob/master/doc/vim-go.txt),
have answers for your problem it might have a solution to your problem.
2. If you add a new feature please don't forget to update the documentation: 2. If you add a new feature then please don't forget to update the documentation:
[doc/vim-go.txt](doc/vim-go.txt) [doc/vim-go.txt](https://github.com/fatih/vim-go/blob/master/doc/vim-go.txt).
3. If it's a breaking change or exceed +100 lines please open an issue first 3. If it's a breaking change or exceeds 100 lines of code then please open an
and describe the changes you want to make. issue first and describe the changes you want to make.
4. See `:help go-development` for instructions on how to run and write tests. If
you add a new feature be sure you also include a test if feasible.

@ -1,28 +1,22 @@
### Actual behavior ### What did you do? (required. The issue will be **closed** when not provided.)
Write here what's happening ...
### Expected behavior ### What did you expect to happen?
Write here what you're expecting ...
### Steps to reproduce: ### What happened instead?
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. ### Configuration (**MUST** fill this out):
2.
3.
### Configuration * Vim version (first two lines from `:version`):
Add here your current configuration and additional information that might be * Go version (`go version`):
useful, such as:
* Go environment (`go env`):
* vim-go version:
* `vimrc` you used to reproduce (use a *minimal* vimrc with other plugins disabled; do not link to a 2,000 line vimrc):
* `vimrc` you used to reproduce
* vim version:
* vim-go version
* go version

6
.gitignore vendored

@ -1 +1,5 @@
doc/tags .DS_Store
/doc/tags
/.coverage.covimerage
/coverage.xml
*.pyc

@ -0,0 +1,14 @@
language: go
notifications:
email: false
matrix:
include:
- env: SCRIPT="test -c" VIM_VERSION=vim-7.4
- env: SCRIPT="test -c" VIM_VERSION=vim-8.0
- env: SCRIPT="test -c" VIM_VERSION=nvim
- env: SCRIPT=lint VIM_VERSION=vim-8.0
install:
- ./scripts/install-vim $VIM_VERSION
- pip install --user vim-vint covimerage codecov
script:
- ./scripts/$SCRIPT $VIM_VERSION

@ -0,0 +1,7 @@
policies:
ProhibitUnnecessaryDoubleQuote:
enabled: false
ProhibitEqualTildeOperator:
enabled: false
ProhibitNoAbortFunction:
enabled: false

File diff suppressed because it is too large Load Diff

@ -0,0 +1,20 @@
FROM golang:1.9.2
RUN apt-get update -y && \
apt-get install -y build-essential curl git libncurses5-dev python3-pip && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN pip3 install vim-vint
RUN useradd -ms /bin/bash -d /vim-go vim-go
USER vim-go
COPY . /vim-go/
WORKDIR /vim-go
RUN scripts/install-vim vim-7.4
RUN scripts/install-vim vim-8.0
RUN scripts/install-vim nvim
ENTRYPOINT ["make"]

@ -56,3 +56,5 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The Go gopher was designed by Renee French. http://reneefrench.blogspot.com/ The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details: https://blog.golang.org/gopher

@ -0,0 +1,29 @@
VIMS ?= vim-7.4 vim-8.0 nvim
all: install test lint
install:
@echo "==> Installing Vims: $(VIMS)"
@for vim in $(VIMS); do \
./scripts/install-vim $$vim; \
done
test:
@echo "==> Running tests for $(VIMS)"
@for vim in $(VIMS); do \
./scripts/test $$vim; \
done
lint:
@echo "==> Running linting tools"
@./scripts/lint vim-8.0
docker:
@echo "==> Building/starting Docker container"
@./scripts/docker-test
clean:
@echo "==> Cleaning /tmp/vim-go-test"
@rm -rf /tmp/vim-go-test
.PHONY: all test install clean lint docker

@ -1,282 +1,71 @@
# vim-go # vim-go [![Build Status](http://img.shields.io/travis/fatih/vim-go.svg?style=flat-square)](https://travis-ci.org/fatih/vim-go)
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)
<p align="center">
<img style="float: right;" src="assets/vim-go.png" alt="Vim-go logo"/>
</p>
## Features ## Features
* Improved Syntax highlighting with items such as Functions, Operators, Methods. This plugin adds Go language support for Vim, with the following main features:
* Auto completion support via `gocode`
* Better `gofmt` on save, which keeps cursor position and doesn't break your undo * Compile your package with `:GoBuild`, install it with `:GoInstall` or test it
history with `:GoTest`. Run a single tests with `:GoTestFunc`).
* Go to symbol/declaration with `:GoDef` * Quickly execute your current file(s) with `:GoRun`.
* Look up documentation with `:GoDoc` inside Vim or open it in browser * Improved syntax highlighting and folding.
* Automatically import packages via `:GoImport` or plug it into autosave * Completion support via `gocode`.
* Compile your package with `:GoBuild`, install it with `:GoInstall` or test * `gofmt` or `goimports` on save keeps the cursor position and undo history.
them with `:GoTest` (also supports running single tests via `:GoTestFunc`) * Go to symbol/declaration with `:GoDef`.
* Quickly execute your current file/files with `:GoRun` * Look up documentation with `:GoDoc` or `:GoDocBrowser`.
* Automatic `GOPATH` detection based on the directory structure (i.e. `gb` * Easily import packages via `:GoImport`, remove them via `:GoDrop`.
projects, `godep` vendored projects) * Automatic `GOPATH` detection which works with `gb` and `godep`. Change or
* Change or display `GOPATH` with `:GoPath` display `GOPATH` with `:GoPath`.
* Create a coverage profile and display annotated source code in browser to see * See which code is covered by tests with `:GoCoverage`.
which functions are covered with `:GoCoverage` * Add or remove tags on struct fields with `:GoAddTags` and `:GoRemoveTags`.
* Call `gometalinter` with `:GoMetaLinter`, which invokes all possible linters * Call `gometalinter` with `:GoMetaLinter` to invoke all possible linters
(golint, vet, errcheck, deadcode, etc..) and shows the warnings/errors (`golint`, `vet`, `errcheck`, `deadcode`, etc.) and put the result in the
* Lint your code with `:GoLint` quickfix or location list.
* Run your code through `:GoVet` to catch static errors * Lint your code with `:GoLint`, run your code through `:GoVet` to catch static
* Advanced source analysis tools utilizing oracle, such as `:GoImplements`, errors, or make sure errors are checked with `:GoErrCheck`.
`:GoCallees`, and `:GoReferrers` * Advanced source analysis tools utilizing `guru`, such as `:GoImplements`,
* Precise type-safe renaming of identifiers with `:GoRename` `:GoCallees`, and `:GoReferrers`.
* List all source files and dependencies * Precise type-safe renaming of identifiers with `:GoRename`.
* Unchecked error checking with `:GoErrCheck` * ... and many more! Please see [doc/vim-go.txt](doc/vim-go.txt) for more
* Integrated and improved snippets, supporting `ultisnips` or `neosnippet` information.
* 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.
* 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`
## 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)
## Install ## Install
Vim-go follows the standard runtime path structure, so I highly recommend to The [**latest stable release**](https://github.com/fatih/vim-go/releases/latest) is the
use a common and well known plugin manager to install vim-go. Do not use vim-go recommended version to use. If you choose to use the master branch instead,
with other Go oriented vim plugins. For Pathogen just clone the repo. For other please do so with caution; it is a _development_ branch.
plugin managers add the appropriate lines and execute the plugin's install
command. vim-go follows the standard runtime path structure. Below are some helper lines
for popular package managers:
* [Vim 8 packages](http://vimhelp.appspot.com/repeat.txt.html#packages)
* `git clone https://github.com/fatih/vim-go.git ~/.vim/pack/plugins/start/vim-go`
* [Pathogen](https://github.com/tpope/vim-pathogen) * [Pathogen](https://github.com/tpope/vim-pathogen)
* `git clone https://github.com/fatih/vim-go.git ~/.vim/bundle/vim-go` * `git clone https://github.com/fatih/vim-go.git ~/.vim/bundle/vim-go`
* [vim-plug](https://github.com/junegunn/vim-plug) * [vim-plug](https://github.com/junegunn/vim-plug)
* `Plug 'fatih/vim-go'` * `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`, You will also need to install all the necessary binaries. vim-go makes it easy
`goimports`, etc.). You can easily install them with the included to install all of them by providing a command, `:GoInstallBinaries`, which will
`:GoInstallBinaries` command. If invoked, all necessary binaries will be `go get` all the required binaries.
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 Check out the Install section in [the documentation](doc/vim-go.txt) for more
detailed instructions (`:help go-install`).
* 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 ## Usage
Many of the plugin's [features](#features) are enabled by default. There are no The full documentation can be found at [doc/vim-go.txt](doc/vim-go.txt). You can
additional settings needed. All usages and commands are listed in display it from within Vim with `:help vim-go`.
`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
## Mappings
vim-go has several `<Plug>` mappings which can be used to create custom
mappings. Below are 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_structs = 1
let g:go_highlight_interfaces = 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
```
### 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'] }
```
## 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.
## Credits Depending on your installation method, you may have to generate the plugin's
[`help tags`](http://vimhelp.appspot.com/helphelp.txt.html#%3Ahelptags)
manually (e.g. `:helptags ALL`).
* Go Authors for official vim plugins We also have an [official vim-go tutorial](https://github.com/fatih/vim-go-tutorial).
* Gocode, Godef, Golint, Oracle, 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 ## License
The BSD 3-Clause License - see `LICENSE` for more details The BSD 3-Clause License - see [`LICENSE`](LICENSE) for more details

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@ -0,0 +1,821 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="173.53481mm"
height="147.26407mm"
viewBox="0 0 614.88711 521.80181"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="vim-go.svg"
style="enable-background:new"
inkscape:export-filename="F:\Go\src\github.com\egonelbre\vim-go\assets\vim-go.png"
inkscape:export-xdpi="46.84"
inkscape:export-ydpi="46.84">
<defs
id="defs4">
<linearGradient
id="gopher-iris"
osb:paint="solid"
gradientTransform="translate(-9.2596241,38.869516)">
<stop
style="stop-color:#394455;stop-opacity:1;"
offset="0"
id="stop4317" />
</linearGradient>
<linearGradient
id="docker-iris"
osb:paint="solid">
<stop
style="stop-color:#394d54;stop-opacity:1;"
offset="0"
id="stop4311" />
</linearGradient>
<linearGradient
id="docker-jaw"
osb:paint="solid">
<stop
style="stop-color:#d4edf1;stop-opacity:1;"
offset="0"
id="stop4305" />
</linearGradient>
<linearGradient
id="docker-eye"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4299" />
</linearGradient>
<linearGradient
id="docker-line"
osb:paint="solid">
<stop
style="stop-color:#394d54;stop-opacity:1;"
offset="0"
id="stop4293" />
</linearGradient>
<linearGradient
id="docker-body"
osb:paint="solid">
<stop
style="stop-color:#24b8eb;stop-opacity:1;"
offset="0"
id="stop4287" />
</linearGradient>
<linearGradient
id="gopher-limbs"
osb:paint="solid">
<stop
style="stop-color:#e1d6b9;stop-opacity:1;"
offset="0"
id="stop4269" />
</linearGradient>
<linearGradient
id="gopher-nose"
osb:paint="solid">
<stop
style="stop-color:#e1d0cb;stop-opacity:1;"
offset="0"
id="stop4263" />
</linearGradient>
<linearGradient
id="gopher-body"
osb:paint="solid"
gradientTransform="matrix(-0.18574987,-0.98259706,0.98259706,-0.18574987,-1213.2665,1828.8814)">
<stop
style="stop-color:#96d6ff;stop-opacity:1;"
offset="0"
id="stop4334" />
</linearGradient>
<linearGradient
id="linearGradient4253">
<stop
style="stop-color:#bce8ff;stop-opacity:1;"
offset="0"
id="stop4194" />
</linearGradient>
<linearGradient
id="linearGradient4182">
<stop
style="stop-color:#2e3436;stop-opacity:1;"
offset="0"
id="stop4184" />
</linearGradient>
<linearGradient
id="gopher-eye"
osb:paint="solid"
gradientTransform="translate(381.30424,802.02286)">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4178" />
</linearGradient>
<linearGradient
id="gopher-lines"
osb:paint="solid"
gradientTransform="matrix(2.0620253,3.9293227,1.3839016,-0.24027903,2506.9621,8572.3972)">
<stop
style="stop-color:#394655;stop-opacity:1;"
offset="0"
id="stop4166" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-lines"
id="linearGradient4168"
x1="776.14288"
y1="39.505058"
x2="822.42859"
y2="39.505058"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92105265,0,0,0.92105265,79.548449,262.52483)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-eye"
id="linearGradient4180"
x1="776.14288"
y1="90.770309"
x2="822.42859"
y2="90.770309"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92105266,0,0,0.92105266,124.54841,215.30684)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-body"
id="linearGradient4336"
x1="-628.69226"
y1="371.77307"
x2="-151.41731"
y2="371.77307"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1,0,0,1,-681.83098,347.55492)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-nose"
id="linearGradient4265"
x1="198.05417"
y1="374.50043"
x2="263.28683"
y2="374.50043"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.65610141,0,0,0.65610141,185.97779,480.81383)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-limbs"
id="linearGradient4271"
x1="730.36273"
y1="373.60995"
x2="831.0592"
y2="373.60995"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.90381797,-0.29515654,-0.62039307,-0.90381797,-597.71307,820.3894)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-limbs"
id="linearGradient4273"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.54351115,-0.65417141,-1.0770811,0.54351115,655.01412,667.6722)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-limbs"
id="linearGradient4275"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.94401471,-0.3302474,-0.32955964,0.94401471,1151.0861,721.50542)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-limbs"
id="linearGradient4279"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.89463991,0.4064691,0.49110603,-0.89463991,-749.6705,579.40921)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-limbs"
id="linearGradient4281"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.49170605,0.377674,2.0076181,-0.49170605,229.12024,357.65841)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-iris"
id="linearGradient4319"
x1="427.26477"
y1="316.13431"
x2="488.88409"
y2="316.13431"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1,0,0,1,744.54563,401.01143)" />
<linearGradient
inkscape:collect="always"
xlink:href="#gopher-iris"
id="linearGradient4321"
gradientTransform="matrix(5.6994379,2.2315229,-1.9072375,4.8711945,4487.6828,1182.8772)"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.76274166"
inkscape:cx="499.78979"
inkscape:cy="92.336365"
inkscape:document-units="px"
inkscape:current-layer="layer11"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1018"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:snap-global="false"
showguides="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid4305"
originx="-15.732723"
originy="-274.01154" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer11"
inkscape:label="background"
style="display:none"
transform="translate(-15.732722,-256.54886)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d3e5de;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4347"
width="614.88708"
height="521.80182"
x="15.732722"
y="256.54886"
inkscape:export-filename="vim-go.png"
inkscape:export-xdpi="46.84"
inkscape:export-ydpi="46.84" />
</g>
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="shadow"
transform="translate(-15.732722,-256.54886)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2e4233;fill-opacity:0.10714285;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 287.3893,695.44531 c -50.0612,-2.78118 -62.1134,11.12305 -91.7793,11.12305 -29.6659,0 -47.28069,-6.48881 -76.01953,-1.85352 -28.738834,4.6353 -40.790093,3.70867 -55.623042,16.6875 -14.832949,12.97883 -21.926707,11.85327 -18.541016,20.39454 1.318705,3.32677 3.956373,1.53579 10.703125,0.83984 115.165183,-11.87969 237.050993,16.53486 337.406243,16.77539 83.20192,0.19942 110.33047,-21.09623 105.22253,-34.76541 -16.86616,-45.13499 -81.24683,-23.67849 -211.36901,-29.20139 z"
id="path4349"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssssssc" />
</g>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="cape-back"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-15.732722,-256.54886)">
<path
style="fill:#0c7a31;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 260.24444,535.87695 c -20.68496,5.13447 -3.94094,36.63825 -23.78246,45.53288 -18.22356,8.16932 -29.87743,27.29784 -48.21487,37.53094 -24.3143,13.56845 -47.25416,17.93122 -70.94376,35.71927 -11.54022,8.66532 -48.036929,3.46906 -49.132109,17.96915 56.226929,-8.73065 86.269619,15.95087 120.882979,20.57024 30.54605,4.07656 53.64011,2.39756 79.48357,-7.50413 89.71977,-34.37532 52.16171,-111.74704 51.81195,-135.28471 -17.69563,-3.28964 -42.98659,-18.78289 -60.1053,-14.53364 z"
id="path4321"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssscsscs" />
</g>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="gopher-body"
style="display:inline;opacity:1"
sodipodi:insensitive="true"
transform="translate(-15.732722,-256.54886)">
<g
style="display:inline;opacity:1"
transform="matrix(-0.34823803,-0.28093567,-0.33018747,0.52325377,856.33627,409.62314)"
id="g4537">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4275);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 419.84023,584.57289 c -1.11092,4.23495 -3.11543,7.14238 -5.84936,9.02308 -2.73394,1.8807 -6.19236,2.76095 -10.13743,3.23943 -3.94504,0.47846 -8.37351,0.59759 -13.05363,0.66122 -4.6801,0.0636 -9.60653,0.0259 -14.5852,-0.15006 -4.97865,-0.17599 -9.67742,-0.66266 -13.94891,-1.44453 -4.27148,-0.78187 -8.12262,-1.83504 -11.28827,-3.15781 -3.16564,-1.32277 -5.63542,-2.92368 -7.07427,-4.89074 -1.43884,-1.96709 -1.83785,-4.30021 -0.94134,-7.07932 0.89648,-2.77911 2.64686,-4.65171 5.05838,-5.71202 2.41152,-1.06032 5.47772,-1.29847 8.97039,-1.04717 3.49268,0.25132 7.40119,0.98198 11.60615,1.60695 4.20496,0.62498 8.71575,1.10136 13.55734,0.95747 4.84159,-0.14387 9.82241,-1.20624 14.59946,-2.18657 4.77703,-0.9803 9.35663,-1.80521 13.2055,-1.76209 3.8489,0.0431 6.93814,0.92314 8.72484,2.84805 1.78673,1.92488 0.0493,13.32997 1.15633,9.09414 z"
id="path4539"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssssssssssssssssc" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 411.66722,570.50504 c -3.64483,-0.3204 -7.91192,0.0353 -12.44327,0.67313 -5.17866,0.72899 -10.69026,1.78243 -16.25596,1.96339 -5.56571,0.181 -10.75654,-0.27799 -15.6406,-0.87383 -4.8841,-0.59575 -9.46828,-1.26261 -13.59381,-1.35067 -4.12552,-0.0881 -7.77812,0.41271 -10.6665,1.77043 -2.88834,1.35772 -5.00621,3.55109 -6.11385,6.60546 -1.10762,3.05438 -0.68341,5.7953 0.96623,8.19507 1.64966,2.39979 4.51594,4.46252 8.19691,6.21125 3.681,1.74874 8.16283,3.1933 13.12136,4.28264 4.95854,1.08935 10.4013,1.79657 16.15733,2.05756 5.756,0.26106 11.2421,0.29972 16.33832,0.21929 5.09618,-0.0804 9.79866,-0.25121 13.94009,-0.87517 1.57579,-0.23741 3.06793,-0.55279 4.47088,-0.96129 2.8331,-0.82603 3.60613,-5.66983 1.06694,-4.35369 -2.35253,1.21937 -5.13009,1.88834 -8.23473,2.27934 -3.78352,0.47652 -8.03435,0.60519 -12.52976,0.67623 -4.49538,0.071 -9.22983,0.0403 -14.01368,-0.12137 -4.78387,-0.16172 -9.29761,-0.62006 -13.39935,-1.36274 -4.10176,-0.74271 -7.79879,-1.74643 -10.8363,-3.01023 -3.03748,-1.2638 -5.40588,-2.79646 -6.78423,-4.6796 -1.37835,-1.88316 -1.75885,-4.11616 -0.89417,-6.78092 0.86467,-2.66475 2.54876,-4.4645 4.86314,-5.48862 2.31437,-1.0241 5.2526,-1.265 8.60072,-1.03925 3.34811,0.22576 7.09649,0.90864 11.13305,1.49473 4.03653,0.5862 8.37113,1.03632 13.02879,0.89877 4.65766,-0.13756 9.45383,-1.14909 14.04535,-2.09377 4.59152,-0.94468 8.9823,-1.75345 12.66755,-1.73592 0.46066,0.002 0.91144,0.0161 1.3482,0.0436 1.1223,0.0708 2.1698,0.20509 3.10067,0.47739 1.0735,0.314 2.95461,-2.6047 -0.11758,-2.94357 -0.49859,-0.055 -1.54942,0.19872 -1.52174,-0.17766 z"
id="path4541"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csscsscssssssssssssssssssssccsssc" />
</g>
<g
transform="matrix(-0.20408679,0.36109427,0.8060854,0.48598006,286.09208,226.24278)"
id="g4640"
style="display:inline;opacity:1">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 767.29926,387.32674 c 11.1235,7.96555 31.77795,11.29978 44.73159,15.54502 12.95363,4.24526 18.14889,9.35948 22.12936,13.37285 3.98046,4.01338 5.94428,7.14463 4.71807,9.52723 -1.2262,2.38259 -5.54351,3.99405 -14.00119,4.81166 -8.45765,0.81761 -15.90978,0.12055 -23.02358,-1.72572 -7.11381,-1.84628 -13.80694,-4.86649 -21.70559,-8.603 -7.89866,-3.73649 -17.3272,-8.0507 -25.81115,-14.18439 -8.48395,-6.13369 -17.62324,-13.90003 -23.14238,-24.13356 -5.51915,-10.23352 -5.78201,-21.34406 -5.37146,-30.88264 0.41055,-9.53859 1.51092,-17.55377 2.71572,-23.74931 1.20482,-6.19553 2.71509,-10.67437 4.77102,-13.66952 2.05591,-2.99513 4.65165,-4.52673 7.71923,-4.52673 3.06759,0 5.70357,1.83092 7.62535,5.49926 1.9218,3.66832 3.04778,9.24444 3.28639,16.76004 0.23861,7.51561 -0.67126,17.08072 0.34029,27.19831 1.01155,10.1176 3.89485,20.79494 15.01833,28.7605 z"
id="path4642"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4281);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 760.81735,387.61463 c 8.35351,7.22933 23.40419,11.34465 36.92829,14.85447 13.52408,3.50986 21.76315,7.50998 26.41399,11.29491 4.65086,3.78492 7.04347,6.96136 6.89289,9.28045 -0.15059,2.31908 -3.07202,3.85186 -9.99413,4.53735 -6.92209,0.68549 -13.12478,-0.17957 -19.18856,-2.15841 -6.06375,-1.97886 -12.01277,-5.06603 -19.62326,-8.64782 -7.61047,-3.5818 -16.94465,-7.61787 -24.98938,-13.21535 -8.04472,-5.59749 -15.82286,-12.65396 -20.9022,-21.24583 -5.07935,-8.59186 -6.01346,-17.801 -5.99188,-25.91871 0.0216,-8.1177 0.93462,-15.14861 1.86635,-20.66954 0.93173,-5.52092 2.01706,-9.59713 3.38259,-12.30465 1.36554,-2.70753 3.03466,-4.06947 5.01979,-4.01398 1.98511,0.0555 3.57672,1.84704 4.61437,5.2751 1.03765,3.42807 1.44745,8.54444 1.4737,15.15288 0.0262,6.60845 -0.43638,14.76057 0.91317,23.27473 1.34954,8.51418 4.83074,17.27506 13.18427,24.5044 z"
id="path4644"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
</g>
<g
style="display:inline;opacity:1"
id="g4594"
transform="matrix(-0.13664232,-0.29657059,-0.88136995,0.09664282,727.56031,790.52022)">
<path
sodipodi:nodetypes="sssssssssssssssss"
inkscape:connector-curvature="0"
id="path4588"
d="m 767.29926,387.32674 c 11.1235,7.96555 31.77795,11.29978 44.73159,15.54502 12.95363,4.24526 18.14889,9.35948 22.12936,13.37285 3.98046,4.01338 5.94428,7.14463 4.71807,9.52723 -1.2262,2.38259 -5.54351,3.99405 -14.00119,4.81166 -8.45765,0.81761 -15.90978,0.12055 -23.02358,-1.72572 -7.11381,-1.84628 -13.80694,-4.86649 -21.70559,-8.603 -7.89866,-3.73649 -17.3272,-8.0507 -25.81115,-14.18439 -8.48395,-6.13369 -17.62324,-13.90003 -23.14238,-24.13356 -5.51915,-10.23352 -5.78201,-21.34406 -5.37146,-30.88264 0.41055,-9.53859 1.51092,-17.55377 2.71572,-23.74931 1.20482,-6.19553 2.71509,-10.67437 4.77102,-13.66952 2.05591,-2.99513 4.65165,-4.52673 7.71923,-4.52673 3.06759,0 5.70357,1.83092 7.62535,5.49926 1.9218,3.66832 3.04778,9.24444 3.28639,16.76004 0.23861,7.51561 -0.67126,17.08072 0.34029,27.19831 1.01155,10.1176 3.89485,20.79494 15.01833,28.7605 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="sssssssssssssssss"
inkscape:connector-curvature="0"
id="ellipse4590"
d="m 760.81735,387.61463 c 8.35351,7.22933 23.40419,11.34465 36.92829,14.85447 13.52408,3.50986 21.76315,7.50998 26.41399,11.29491 4.65086,3.78492 7.04347,6.96136 6.89289,9.28045 -0.15059,2.31908 -3.07202,3.85186 -9.99413,4.53735 -6.92209,0.68549 -13.12478,-0.17957 -19.18856,-2.15841 -6.06375,-1.97886 -12.01277,-5.06603 -19.62326,-8.64782 -7.61047,-3.5818 -16.94465,-7.61787 -24.98938,-13.21535 -8.04472,-5.59749 -15.82286,-12.65396 -20.9022,-21.24583 -5.07935,-8.59186 -6.01346,-17.801 -5.99188,-25.91871 0.0216,-8.1177 0.93462,-15.14861 1.86635,-20.66954 0.93173,-5.52092 2.01706,-9.59713 3.38259,-12.30465 1.36554,-2.70753 3.03466,-4.06947 5.01979,-4.01398 1.98511,0.0555 3.57672,1.84704 4.61437,5.2751 1.03765,3.42807 1.44745,8.54444 1.4737,15.15288 0.0262,6.60845 -0.43638,14.76057 0.91317,23.27473 1.34954,8.51418 4.83074,17.27506 13.18427,24.5044 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4271);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
style="display:inline"
id="g4533-2"
transform="matrix(-0.60102903,0.32221978,0.53870829,0.77401445,526.12645,47.501077)" />
<g
style="opacity:1"
transform="matrix(-0.32879267,0.17361606,0.20143296,0.28338802,143.13323,319.59452)"
id="g4404">
<path
sodipodi:nodetypes="sssssssssssssssss"
inkscape:connector-curvature="0"
id="path4406"
d="m -626.54672,402.3529 c 2.22767,10.86299 0.34493,21.82632 -3.86747,31.42527 -4.21252,9.59894 -10.55173,17.86115 -17.72096,24.29983 -7.1694,6.43883 -15.25476,11.10591 -24.5716,13.61353 -9.31698,2.50761 -20.94966,4.46936 -31.63903,1.98398 -10.68939,-2.48537 -18.0688,-9.22838 -24.09401,-15.89285 -6.02508,-6.66442 -12.35923,-14.47524 -22.96531,-22.06805 -10.60584,-7.59266 -20.8648,-15.59839 -25.16123,-23.3775 -4.29632,-7.77931 -7.008,-15.66934 -7.81517,-23.39095 -0.80717,-7.7215 0.35908,-14.55922 3.12288,-20.54462 2.76393,-5.98548 7.12557,-11.1208 12.7854,-15.40902 5.65998,-4.28811 12.61751,-7.73606 20.64204,-10.24271 8.02465,-2.50651 17.11262,-4.07552 27.13941,-4.41504 10.0268,-0.3395 20.06604,0.59388 29.76158,2.87504 9.69543,2.2813 19.05511,5.92037 27.47739,11.02309 8.42215,5.10286 15.89307,11.69212 21.60465,19.6287 5.71147,7.93674 13.0738,19.62846 15.30143,30.4913 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-body);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="csssccscsccscscccsccscsssscscscc"
inkscape:connector-curvature="0"
id="path4408"
d="m -784.21409,457.33922 c -0.56136,0.0656 -1.08141,0.1809 -1.55606,0.33615 -0.63289,0.20699 -1.18396,0.48516 -1.6349,0.82686 -0.45093,0.3417 -0.80184,0.74659 -1.02778,1.21891 -0.22595,0.47234 -0.32669,1.01119 -0.27449,1.62035 0.0522,0.60917 0.25282,1.23371 0.57968,1.84938 0.32687,0.61567 0.98957,1.25218 1.83531,1.84156 0.84574,0.58937 1.35671,1.20529 1.82543,1.72857 0.46713,0.52147 1.13451,0.85371 2.02424,0.92674 0.10253,0.008 0.12328,-0.30471 0.0344,-0.32876 -0.78083,-0.20262 -1.25826,-0.72023 -1.71877,-1.11076 -0.4254,-0.46645 -0.87231,-1.01406 -1.62104,-1.54604 -0.74871,-0.53197 -1.47289,-1.09304 -1.77689,-1.63886 -0.30398,-0.54584 -0.49685,-1.10009 -0.55469,-1.64239 -0.0579,-0.54231 0.0245,-1.0222 0.21918,-1.44322 0.19469,-0.42103 0.50198,-0.78371 0.90168,-1.08623 0.39973,-0.30252 0.89062,-0.54587 1.4577,-0.7237 0.28355,-0.0889 0.5872,-0.16119 0.90722,-0.21465 0.32002,-0.0535 0.6576,-0.0885 1.01178,-0.10163 0.70839,-0.0255 1.4163,0.0392 2.10043,0.1987 0.68412,0.15947 1.34499,0.41522 1.93838,0.77329 0.59338,0.35806 1.11885,0.81986 1.52108,1.37653 0.40222,0.55667 0.92117,1.37523 1.07925,2.13677 0.12981,0.62539 0.0734,1.25844 -0.13288,1.83379 -0.0385,0.10712 0.4977,0.29416 0.62787,-0.0111 0.24265,-0.5698 0.23445,-1.24057 0.1026,-1.8741 -0.17834,-0.85666 -0.69031,-1.76937 -1.13671,-2.40019 -0.4464,-0.6308 -1.03123,-1.15292 -1.68895,-1.55276 -0.65772,-0.39984 -1.38674,-0.68003 -2.14271,-0.85021 -0.75599,-0.17016 -1.54036,-0.23166 -2.32498,-0.19142 -0.19617,0.0101 -0.38815,0.0268 -0.57528,0.0484 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
transform="matrix(13.851095,0,0,13.851095,10133.213,-6001.611)" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -753.77185,413.0219 c -0.13663,-2.61847 2.18018,-4.94804 7.2193,-6.20054 7.65443,-1.90257 20.03831,1.84566 27.93811,5.67152 4.33357,2.09883 8.88981,3.89076 12.66635,7.19411 1.28185,1.12133 2.51799,2.28349 3.36855,4.40869 -1.65849,0.577 -4.10492,-0.92134 -5.87278,-2.13046 -6.96771,-4.76531 -14.69502,-8.08983 -22.67695,-9.12646 -6.71591,-0.87187 -8.86923,-3.11022 -14.75541,-2.56175 -3.72583,0.34716 -4.90626,2.13878 -7.88716,2.74489 z"
id="path4365-1-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssscsssc" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -720.16989,411.68353 c 0.28532,-2.32502 0.86962,3.90377 -0.31886,5.45995 -4.46007,5.84 -8.20289,12.32072 -12.42083,18.36519 -1.37385,1.96787 -3.29463,0.0414 -2.42738,-2.09874 0.88118,-2.1739 2.06053,-3.99898 3.34915,-5.8153 1.20809,-1.70147 2.81353,-3.0576 3.88834,-4.85958 2.06619,-3.46267 2.39577,-6.62873 4.25443,-10.2393 0.63712,-1.23818 3.5225,0.42546 3.67386,-0.80905 z"
id="path4367-9-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssss" />
</g>
<g
style="display:inline;opacity:1"
id="g4198"
transform="matrix(0.69027452,0,0,0.73815345,642.18876,259.65104)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -140.71724,398.66408 c -9.31409,71.69689 -25.7611,141.32 -83.87724,188.8641 -73.31672,59.97949 -208.09131,67.90599 -303.42706,10.99618 -27.57065,-16.45805 -49.52457,-62.17665 -53.04177,-91.74122 -7.35191,-61.79791 19.82699,-103.64945 13.47928,-160.67805 -5.05249,-45.39216 -29.63784,-82.95495 -27.30836,-137.00138 1.56315,-36.26681 11.06536,-78.46439 40.50727,-100.88356 38.57103,-29.370718 83.60539,-46.188952 134.68095,-45.031125 72.73731,1.648875 151.17838,6.326503 212.18714,49.939365 43.544,31.12796 68.50323,82.53699 72.90385,135.3004 4.52019,54.19698 -0.16075,104.48555 -6.10406,150.23529 z"
id="path4188"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4336);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -158.93683,464.92976 c -15.56115,65.9367 -58.42288,127.39267 -134.42207,151.72082 -70.61462,22.6045 -163.49236,17.29949 -232.18476,-25.54762 -26.14623,-16.30879 -46.09162,-61.46233 -48.95901,-89.47579 -6.03547,-58.9646 19.04741,-102.17429 13.30293,-156.59502 -4.7951,-45.42661 -28.02123,-78.34585 -27.29597,-132.22289 0.47399,-35.21112 8.99044,-76.95773 37.82112,-98.79995 36.52466,-27.671205 78.3526,-45.238515 126.45621,-45.012482 76.22124,0.358155 162.16208,5.533182 222.84373,56.658952 55.47879,46.74224 63.38318,129.04796 60.81019,193.3049 -2.12217,52.99813 -7.67242,100.63054 -18.37237,145.96908 z"
id="ellipse4190"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssss" />
</g>
<g
id="g4376"
transform="matrix(0.40138799,-0.13710458,0.13710458,0.40138799,470.81791,82.723801)"
style="opacity:1">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-body);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -626.57295,401.69566 c 2.24713,11.35067 0.36741,22.38948 -3.843,32.03835 -4.21053,9.64886 -10.54997,17.90531 -17.7192,24.34399 -7.1694,6.43883 -15.25457,11.1106 -24.57171,13.61082 -9.31727,2.5002 -20.94956,4.47176 -31.64526,1.82793 -10.69571,-2.64383 -18.09209,-9.81214 -24.14818,-17.25062 -6.05597,-7.43843 -12.44269,-16.56671 -23.09665,-25.35944 -10.65372,-8.79255 -20.95218,-17.78817 -25.30072,-26.87318 -4.34843,-9.08528 -7.1154,-18.36084 -7.98,-27.52156 -0.86459,-9.1606 0.24716,-17.36404 2.9617,-24.58398 2.71467,-7.22004 7.03243,-13.45488 12.66059,-18.5369 5.6283,-5.08191 12.56665,-9.01064 20.59229,-11.48936 8.02576,-2.47858 17.13537,-3.50537 27.20916,-2.66707 10.0738,0.83832 20.1809,3.47234 29.95223,7.6529 9.77122,4.18068 19.21426,9.9086 27.71179,16.89733 8.49741,6.98886 16.03465,15.24007 21.79567,24.41557 5.7609,9.17565 13.1742,22.14471 15.42129,33.49522 z"
id="path4398"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -784.27135,455.90422 c -0.56339,0.0147 -1.08437,0.10666 -1.55902,0.26191 -0.63289,0.20699 -1.18231,0.52669 -1.63059,0.93484 -0.44828,0.40815 -0.79558,0.90361 -1.01756,1.4752 -0.22199,0.5716 -0.31844,1.21792 -0.26185,1.93717 0.0566,0.71926 0.26134,1.4471 0.59196,2.157 0.33063,0.7099 0.99621,1.41858 1.84494,2.08284 0.84872,0.66425 1.36325,1.36931 1.83382,1.93901 0.46898,0.56774 1.13678,0.9105 2.02675,0.98962 0.10256,0.009 0.12294,-0.31321 0.034,-0.33899 -0.78143,-0.21746 -1.26048,-0.77583 -1.72293,-1.21489 -0.42768,-0.5236 -0.87838,-1.16625 -1.63058,-1.78505 -0.75217,-0.61879 -1.47924,-1.25213 -1.78697,-1.89162 -0.30772,-0.63951 -0.50455,-1.29287 -0.56648,-1.9378 -0.062,-0.64492 0.0165,-1.22191 0.20772,-1.73042 0.1912,-0.50852 0.49539,-0.94884 0.89287,-1.30706 0.3975,-0.35822 0.88707,-0.63484 1.45426,-0.80994 0.2836,-0.0875 0.58767,-0.1494 0.90851,-0.1822 0.32084,-0.0328 0.65966,-0.0369 1.01552,-0.008 0.71174,0.0585 1.42446,0.24383 2.11396,0.53794 0.6895,0.29412 1.35628,0.69807 1.95502,1.19025 0.59873,0.49218 1.12894,1.07271 1.53474,1.71893 0.4058,0.64623 0.9285,1.5589 1.08808,2.35795 0.13104,0.65619 0.075,1.29927 -0.13103,1.88026 -0.0384,0.10817 0.49808,0.30362 0.62824,-0.002 0.24262,-0.57052 0.23429,-1.24452 0.10166,-1.89748 -0.17938,-0.88293 -0.69436,-1.871 -1.14416,-2.58711 -0.44981,-0.71609 -1.03943,-1.35821 -1.70275,-1.89855 -0.66333,-0.54034 -1.3987,-0.97968 -2.16052,-1.29649 -0.76184,-0.31679 -1.55154,-0.51173 -2.33984,-0.56369 -0.19709,-0.013 -0.38986,-0.0163 -0.57767,-0.0116 z"
id="path4369"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssccscsccscscccsccscsssscscscc"
transform="matrix(13.851095,0,0,13.851095,10133.213,-6001.611)" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -730.27274,382.91266 c 1.8068,-2.76405 6.31309,-3.63001 13.24575,-1.6171 10.53068,3.05761 22.43414,14.97755 28.94834,24.04709 3.57338,4.97534 7.6424,9.78266 9.64772,15.62449 0.68055,1.98294 1.27611,3.97774 0.68898,6.70435 -2.4056,-0.49416 -4.1871,-3.62313 -5.37952,-6.01329 -4.69962,-9.4202 -11.38574,-17.86492 -20.09536,-24.13889 -7.3284,-5.27852 -8.20487,-8.9719 -15.61502,-12.25742 -4.69053,-2.07967 -7.44128,-1.02076 -11.44089,-2.34923 z"
id="path4365-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssscsssc" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m -689.31909,403.49962 c 2.08771,-2.1886 -1.9021,4.5559 -4.48533,5.36905 -9.69439,3.05157 -19.01784,7.22624 -28.57811,10.64488 -3.11327,1.11257 -3.94795,-2.11026 -1.30738,-3.72982 2.68251,-1.64492 5.45711,-2.73872 8.35507,-3.75217 2.71578,-0.94874 5.64428,-1.2851 8.27731,-2.4236 5.06052,-2.18718 7.83343,-5.20599 12.75841,-7.67984 1.68866,-0.84854 3.86766,2.73608 4.97603,1.5739 z"
id="path4367-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssss" />
</g>
<g
id="g4634"
transform="matrix(0.13058783,-0.42795023,-0.60869797,-0.11092817,632.15501,956.21909)"
style="display:inline;opacity:1">
<path
sodipodi:nodetypes="sssssssssssssssss"
inkscape:connector-curvature="0"
id="path4636"
d="m 423.50332,581.83521 c -0.004,4.40048 -1.19837,7.58856 -3.37524,9.82844 -2.17687,2.23987 -5.33154,3.55156 -9.14619,4.44292 -3.81465,0.89135 -8.28246,1.39523 -13.05675,1.83828 -4.77428,0.44304 -9.85163,0.79076 -14.95001,1.09928 -5.09838,0.30851 -9.94541,0.34741 -14.40217,0.0862 -4.45676,-0.26122 -8.52354,-0.79908 -11.99271,-1.71189 -3.46915,-0.91282 -6.33736,-2.21356 -8.3562,-4.09288 -2.01885,-1.87935 -3.18709,-4.34475 -3.25466,-7.51083 -0.0676,-3.16607 0.9983,-5.4859 2.92534,-7.0838 1.92703,-1.5979 4.71248,-2.46394 8.09977,-2.84688 3.38729,-0.38293 7.37282,-0.28336 11.77044,-0.16051 4.39762,0.12284 9.21051,0.23456 14.33166,-0.12202 5.12115,-0.35659 10.27171,-1.47349 15.16022,-2.54099 4.88852,-1.06749 9.50395,-2.05149 13.43823,-2.27114 3.9343,-0.21967 7.17754,0.32322 9.39823,2.04598 2.22069,1.72276 3.41425,4.59936 3.41004,8.99986 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4279);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="csscsscssssssssssssssssssssccsssc"
inkscape:connector-curvature="0"
id="path4638"
d="m 411.91406,568.54883 c -3.75011,-0.0271 -8.08701,0.53975 -12.76172,1.28711 -5.34251,0.85413 -11.10706,1.92059 -17.00976,2.32617 -5.9027,0.40562 -11.41103,0.38326 -16.44727,0.41406 -5.03624,0.0309 -9.6045,0.1607 -13.50781,0.85938 -3.9033,0.69867 -7.13503,1.96743 -9.4082,3.96875 -2.27316,2.00131 -3.58535,4.71676 -3.65235,8.17578 -0.067,3.45901 1.21821,6.3073 3.54297,8.58008 2.32476,2.27278 5.68789,3.9795 9.76172,5.25 4.07385,1.27051 8.85237,2.11894 14.05664,2.59765 5.20427,0.47871 10.83381,0.56134 16.70313,0.22266 5.86931,-0.33868 11.47146,-0.78653 16.60547,-1.34961 5.13399,-0.56309 9.79334,-1.22365 13.70703,-2.34375 1.48913,-0.4262 2.86677,-0.9287 4.12695,-1.51953 2.54507,-1.19325 2.05015,-6.17249 -0.0996,-4.54102 -1.99172,1.51153 -4.14364,1.68162 -7.15735,2.35061 -3.67269,0.81527 -8.18136,0.99111 -12.55008,1.3428 -4.3687,0.35167 -8.7789,1.78431 -13.31332,2.07736 -4.53444,0.29304 -8.86787,0.32801 -12.93181,0.0702 -4.06396,-0.25785 -7.85651,-0.78075 -11.12475,-1.64296 -3.26823,-0.86221 -5.99695,-2.08037 -7.8846,-3.81399 -1.88765,-1.73365 -2.92537,-3.9871 -2.97865,-6.80086 -0.0533,-2.81374 0.90176,-4.8192 2.66881,-6.10562 1.76704,-1.28641 5.61732,-0.58475 8.69196,-0.71399 3.07463,-0.12925 6.90624,-0.54484 10.78772,-0.41733 3.88147,0.12754 6.54592,-0.48119 11.04844,-1.2139 4.50252,-0.73264 9.15212,-2.3434 13.88736,-3.72101 4.73523,-1.37761 9.22461,-2.34259 13.00861,-2.55385 0.473,-0.0264 0.93707,-0.0422 1.38868,-0.0449 1.16046,-0.007 2.25007,0.0442 3.25,0.23633 1.15313,0.22156 2.31543,-2.86146 -0.83789,-2.92773 -0.51177,-0.0108 -1.03459,-0.045 -1.57032,-0.0488 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer9"
inkscape:label="gopher-shadow"
style="display:inline;opacity:0.06000001"
sodipodi:insensitive="true"
transform="translate(-15.732722,-256.54886)">
<ellipse
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="path4544"
cx="-467.52527"
cy="482.66467"
rx="22.450642"
ry="20.682871"
transform="scale(-1,1)" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 234.60547,309.98047 c -6.62163,-0.0703 -10.7426,0.83465 -15.61133,3.26758 -5.0378,2.51742 -10.044,7.91661 -11.55273,12.45898 -2.26972,6.83348 -0.42196,14.92592 5.01757,21.97656 3.19606,4.1427 6.84938,6.56071 14.60938,9.66993 3.20846,1.28553 7.68985,3.50108 9.95898,4.92382 5.6211,3.52442 9.83526,5.31873 13.54102,5.76563 2.42194,0.29208 3.11523,0.63719 3.11523,1.55469 0,0.89182 -0.7061,1.28567 -2.89062,1.61328 -1.58919,0.23867 -3.77121,0.24076 -4.84961,0.004 -1.95019,-0.42833 -1.9703,-0.40483 -3.65625,4.68555 -3.87667,11.7048 -5.82609,25.85658 -5.80859,42.15625 0.0196,18.31899 1.82597,28.89111 9.58007,56.04688 5.56137,19.47655 7.15656,26.40249 8.58008,37.26171 2.05331,15.66359 1.31467,26.60445 -3.90625,57.79102 -4.8641,29.05517 -5.15869,31.69637 -5.18359,46.54297 -0.0239,14.28001 0.63486,19.84952 3.52539,29.8125 5.44577,18.77032 13.72789,34.11825 23.9082,44.30078 8.00321,8.00498 22.62783,16.26261 41.23438,23.2832 5.47456,2.06566 5.83617,2.12101 6.46679,0.99414 1.72277,-3.07839 3.2087,-3.7772 9.33203,-3.79882 -38.68101,-33.75954 -34.48259,-82.29367 -25.52281,-108.9339 7.33431,-21.80723 31.77025,-53.23407 31.77025,-53.23407 l -22.41052,-1.98245 c 0,0 -7.25969,-42.63753 -13.15682,-59.9065 -22.58603,-66.14023 -29.82384,-120.35922 4.37069,-158.19894 5.84309,-6.46598 12.5988,-11.21335 19.60937,-14.69727 -9.02679,1.89877 -18.30173,4.80561 -26.41601,8.32813 -6.65247,2.88791 -19.01394,9.90994 -18.99415,10.78906 0.009,0.39075 0.30731,1.97487 0.66407,3.52148 0.79845,3.46141 -0.0807,5.55969 -2.20117,5.25782 -1.1871,-0.16901 -1.49742,-0.76108 -1.83008,-3.48633 -0.63121,-5.17109 -3.20076,-9.39815 -9.06836,-14.91797 -9.25402,-8.70552 -17.29671,-12.21829 -29.22461,-12.76172 -1.05756,-0.0482 -2.05405,-0.0778 -3,-0.0879 z m 1.38086,24.10156 c 1.88404,0.0642 3.99413,0.41696 5.88476,1.04492 3.99187,1.32589 12.35644,6.69047 14.31446,9.17969 3.00519,3.82048 1.04901,4.01008 -3.4043,0.33008 -1.74522,-1.44216 -3.36983,-2.6211 -3.60937,-2.6211 -0.23954,0 -2.78812,1.91597 -5.66407,4.25782 -2.87594,2.34185 -5.59815,4.25776 -6.04883,4.25976 -1.88842,0.007 -0.56519,-2.08264 3.10938,-4.91015 4.64288,-3.57262 5.88952,-5.38766 4.12891,-6.00977 -0.64649,-0.22845 -2.92374,-1.13445 -5.06055,-2.01367 -3.0123,-1.23949 -4.52138,-1.50334 -6.71875,-1.17383 -3.06661,0.45987 -3.82178,-0.39095 -1.46485,-1.65234 0.9899,-0.52978 2.64916,-0.75563 4.53321,-0.69141 z m 103.78515,383.73633 c -0.005,0.0152 -0.007,0.0256 -0.0117,0.041 l -0.70118,2.28906 5.65625,1.01562 c 0.0901,0.0162 0.20551,0.0326 0.29688,0.0488 -1.81728,-1.11236 -3.56263,-2.24473 -5.24024,-3.39453 z"
id="path4271"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssscssssssssssscsccsscscssssssscsssscscsssscccccccc" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 328.4205,548.25967 -4.47623,14.88037 c 2.60939,0.0254 9.84161,-6.41982 16.75619,-6.818 76.94638,-4.43102 125.04829,-0.40565 187.26295,-5.40532 1.45456,-0.11689 3.76527,-0.10936 5.20677,0.2079 5.21485,1.14773 8.09003,14.3736 9.3628,13.60525 0.6055,-14.12878 -2.32372,-19.14168 -5.81784,-22.69773 z"
id="path4275"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsssccc" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="gopher-face"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-15.732722,-256.54886)">
<g
id="g4818"
transform="matrix(-0.65610141,0,0,0.65610141,655.70091,210.42145)">
<path
sodipodi:nodetypes="sssssssssssssssss"
inkscape:connector-curvature="0"
id="path4812"
d="m 547.42756,318.16456 c -0.44046,14.77191 -4.12869,29.02667 -10.38967,42.25266 -6.26099,13.22599 -15.09198,25.42687 -25.80466,35.99686 -10.71268,10.57 -23.30432,19.50822 -37.11826,26.08983 -13.81394,6.58161 -28.85103,10.80263 -44.50193,11.8618 -15.65091,1.05917 -30.4406,-1.15844 -43.81781,-6.16756 -13.37721,-5.00911 -25.3405,-12.8075 -35.30087,-22.80416 -9.96037,-9.99666 -17.91599,-22.19037 -23.26581,-35.90798 -5.34983,-13.71761 -8.0915,-28.95913 -7.64195,-44.98105 0.44955,-16.02192 4.04447,-31.2937 10.1422,-45.07896 6.09773,-13.78526 14.69591,-26.08175 25.16951,-36.25747 10.4736,-10.17571 22.82245,-18.23043 36.46168,-23.66123 13.63924,-5.4308 28.57214,-8.24285 44.22923,-8.02541 15.6571,0.21745 30.56095,3.42714 44.11009,8.94154 13.54914,5.5144 25.7404,13.33722 35.92568,22.91495 10.18529,9.57774 18.36233,20.91345 23.87736,33.53282 5.51504,12.61936 8.36566,26.52144 7.92521,41.29336 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="sssssssssssssssss"
inkscape:connector-curvature="0"
id="ellipse4814"
d="m 539.72249,314.79002 c 10e-4,13.89984 -3.01572,27.53808 -8.51346,40.35257 -5.49774,12.81449 -13.48047,24.80543 -23.37659,35.2527 -9.89612,10.44726 -21.70519,19.34133 -34.78531,25.87862 -13.08011,6.53727 -27.4256,10.71236 -42.3773,11.7667 -14.9517,1.05435 -29.09103,-1.11258 -41.85904,-5.93108 -12.76803,-4.81852 -24.16883,-12.28715 -33.66552,-21.79076 -9.49671,-9.50362 -17.08979,-21.04298 -22.23241,-33.95465 -5.14261,-12.91166 -7.83328,-27.19561 -7.52333,-42.13595 0.30995,-14.94034 3.58995,-29.10832 9.22975,-41.85842 5.63981,-12.7501 13.63743,-24.08168 23.39638,-33.47108 9.75897,-9.38941 21.27795,-16.83842 34.00359,-21.94183 12.72563,-5.10342 26.66067,-7.86812 41.28534,-7.94317 14.62467,-0.0751 28.55938,2.53224 41.26083,7.24431 12.70145,4.71207 24.16709,11.5339 33.81555,20.03646 9.64847,8.50257 17.47884,18.68937 22.90117,30.21241 5.42232,11.52304 8.43889,24.38332 8.44035,38.28317 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-eye);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<circle
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4319);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="path4828"
cx="458.07443"
cy="316.13431"
r="30.809652" />
<circle
r="15.152287"
cy="301.99216"
cx="444.43738"
id="circle4830"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-eye);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
transform="matrix(-0.49821858,-0.255998,-0.255998,0.49821858,841.05915,359.59091)"
id="g4822">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 544.2609,323.96628 c -5.95391,12.33766 -15.20034,24.2228 -25.89846,35.91934 -10.69814,11.69654 -22.74349,23.28172 -34.52447,34.21851 -11.78099,10.93679 -23.27607,21.15489 -34.23709,29.30247 -10.96102,8.14759 -21.47285,14.18083 -32.04267,16.95199 -10.56982,2.77117 -20.29711,2.02561 -29.30402,-1.67713 -9.00692,-3.70274 -20.58076,-7.76561 -27.66538,-16.71749 -7.08461,-8.95188 -12.84054,-20.18257 -16.5035,-33.03389 -3.66297,-12.85133 -5.229,-27.32914 -3.92417,-42.72858 1.30484,-15.39944 5.36688,-30.24976 11.81788,-43.75488 6.45101,-13.5051 15.29008,-25.65823 26.00811,-35.78271 10.71803,-10.12447 28.44246,-20.29305 42.24879,-25.86698 13.80633,-5.57394 28.83304,-8.62768 44.20973,-8.80364 15.3767,-0.17594 29.62737,2.52591 41.94358,7.37479 12.31622,4.84887 22.69735,11.85058 30.35956,20.34718 7.66222,8.49661 12.60139,18.48263 14.06496,29.34879 1.4636,10.86615 -0.59894,22.56457 -6.55285,34.90223 z"
id="path4824"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 538.18032,322.65868 c -5.17728,11.63182 -13.27733,23.10077 -22.96883,34.40428 -9.69151,11.30351 -20.93897,22.46482 -32.34413,32.7753 -11.40514,10.31051 -22.90789,19.71873 -33.85893,27.13351 -10.95103,7.41476 -21.39599,12.82014 -31.59528,15.28718 -10.19931,2.46703 -19.30202,1.76338 -27.56839,-1.62958 -8.26637,-3.39295 -19.13397,-6.9512 -25.3913,-15.16185 -6.25732,-8.21068 -11.24381,-18.53447 -14.30417,-30.37519 -3.06035,-11.84072 -4.18965,-25.20221 -2.68634,-39.42576 1.5033,-14.22354 5.50837,-27.94818 11.67956,-40.43838 6.17119,-12.4902 14.50792,-23.74111 24.54768,-33.13895 10.03978,-9.39782 26.99021,-19.0621 39.83566,-24.2929 12.84546,-5.2308 26.78412,-8.15811 41.0009,-8.45853 14.21678,-0.30038 27.34319,2.03758 38.64284,6.33106 11.29965,4.29349 20.7704,10.54463 27.74089,18.16875 6.97048,7.62413 11.43794,16.6127 12.81335,26.51165 1.37541,9.89894 -0.36624,20.67759 -5.54351,32.30941 z"
id="path4826"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
<circle
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4321);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="path4828-0"
cx="438.70038"
cy="219.30804"
r="27.721321"
transform="matrix(0.98640333,0.16434257,-0.16434257,0.98640333,0,0)" />
<circle
r="13.633434"
cy="205.95601"
cx="431.24106"
id="circle4830-3"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
transform="matrix(0.98640333,0.16434257,-0.16434257,0.98640333,0,0)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer7"
inkscape:label="gopher-mouth"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-15.732722,-256.54886)">
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 477.59321,477.72343 -6.36763,0.0828 -3.71113,-0.0821 c -1.18372,-0.0262 -2.23819,0.53559 -3.00662,1.36379 -0.76845,0.82822 -1.14658,1.97521 -1.32551,3.22687 l -1.01303,7.08562 -1.40711,7.111 c -0.25342,1.28069 0.0841,2.40965 0.70518,3.23132 0.6211,0.82165 1.57363,1.28978 2.69674,1.31649 l 3.7446,0.0891 7.40657,-0.17258 c 1.42055,-0.0331 2.74014,-0.58514 3.70785,-1.43299 0.96771,-0.84787 1.54004,-2.00084 1.65553,-3.2592 l 0.6476,-7.05621 0.52522,-7.04505 c 0.0935,-1.25398 -0.46676,-2.37726 -1.25366,-3.18163 -0.78689,-0.80437 -1.85738,-1.2842 -3.00457,-1.27716 z"
id="rect4659"
inkscape:connector-curvature="0"
sodipodi:nodetypes="scssscssscssscsss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 476.43064,479.86835 -5.19684,0.0698 -2.47497,-0.10149 c -0.94018,-0.0386 -1.80825,0.43586 -2.46124,1.11384 -0.65298,0.67797 -1.03424,1.61771 -1.21175,2.64338 l -1.0026,5.79325 -1.25494,5.80832 c -0.22406,1.03701 0.002,1.97056 0.48938,2.64162 0.48783,0.67105 1.26653,1.03411 2.19892,1.07115 l 2.54193,0.101 5.88547,-0.12754 c 1.11447,-0.0242 2.17518,-0.47212 2.97321,-1.1643 0.79803,-0.69218 1.30904,-1.6349 1.43939,-2.66511 l 0.73009,-5.77006 0.63032,-5.76301 c 0.11259,-1.02637 -0.28558,-1.94744 -0.89178,-2.6062 -0.60618,-0.65877 -1.45658,-1.05733 -2.39458,-1.04471 z"
id="rect4661"
inkscape:connector-curvature="0"
sodipodi:nodetypes="scssscssscssscsss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 447.45177,471.71537 c 0.17729,2.27145 1.57656,4.32647 3.56538,6.17684 1.98881,1.85037 4.73553,3.49055 7.9169,4.83408 3.18137,1.34353 6.76993,2.37673 10.40491,2.92876 3.63499,0.55204 7.31771,0.61337 10.93742,0.17695 3.61969,-0.43645 6.8614,-1.30517 9.67542,-2.37849 2.81402,-1.07332 5.17844,-2.3467 7.04073,-3.75925 1.86231,-1.41254 3.23922,-2.97722 4.10853,-4.72358 0.86932,-1.74636 1.22997,-3.67959 0.91461,-5.76285 -0.31535,-2.08326 -1.29186,-4.11481 -2.79935,-5.98131 -1.5075,-1.86649 -3.53491,-3.56576 -5.91642,-4.97983 -2.3815,-1.41407 -5.11304,-2.54212 -8.12844,-3.28158 -3.0154,-0.73946 -6.31783,-1.09096 -9.93094,-0.97174 -3.6131,0.11924 -7.2186,0.69446 -10.6419,1.64517 -3.4233,0.95069 -6.6496,2.2832 -9.33875,3.91065 -2.68913,1.62746 -4.89892,3.50256 -6.18894,5.61926 -1.32139,2.16817 -1.77021,4.61153 -1.61916,6.54692 z"
id="ellipse4650"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4265);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 455.1011,471.20532 c 0.31019,1.80429 1.36577,3.48937 2.98663,4.99917 1.62086,1.5098 3.80505,2.84719 6.28703,3.91437 2.48197,1.06719 5.24944,1.8562 8.07117,2.27071 2.82174,0.4145 5.70079,0.45265 8.53169,0.10713 2.83089,-0.34553 5.35911,-1.02976 7.553,-1.90451 2.19389,-0.87475 4.04484,-1.93848 5.497,-3.12538 1.45217,-1.1869 2.50911,-2.50179 3.13219,-3.93394 0.62308,-1.43214 0.81446,-2.98543 0.48985,-4.63056 -0.32461,-1.64514 -1.13916,-3.22548 -2.3414,-4.6674 -1.20224,-1.44192 -2.78948,-2.74346 -4.65903,-3.82078 -1.86955,-1.07733 -4.01937,-1.92982 -6.38974,-2.4811 -2.37037,-0.55129 -4.96168,-0.80162 -7.76722,-0.68542 -2.80553,0.11621 -5.57317,0.58631 -8.1874,1.34158 -2.61424,0.75528 -5.07126,1.79757 -7.14628,3.06167 -2.07504,1.26412 -3.75959,2.75051 -4.8326,4.37276 -1.07302,1.62225 -1.53509,3.37741 -1.22489,5.1817 z"
id="ellipse4652"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 465.13937,460.19393 c 0.45232,1.29294 1.43586,2.44115 2.79664,3.4102 1.36078,0.96906 3.0934,1.76079 4.97332,2.36791 1.87992,0.60712 3.89927,1.0315 5.87533,1.25741 1.97606,0.2259 3.90879,0.25223 5.71982,0.052 1.81102,-0.20028 3.33955,-0.60742 4.63321,-1.17435 1.29367,-0.56695 2.35232,-1.29343 3.18646,-2.14861 0.83413,-0.85519 1.44471,-1.8405 1.79916,-2.93195 0.35445,-1.09146 0.45213,-2.29028 0.21175,-3.55738 -0.24038,-1.2671 -0.80099,-2.48156 -1.64917,-3.57911 -0.84818,-1.09755 -1.9831,-2.07741 -3.35494,-2.8723 -1.37184,-0.7949 -2.98056,-1.40441 -4.76729,-1.7664 -1.78672,-0.36199 -3.75169,-0.47615 -5.82322,-0.29097 -2.07153,0.18518 -4.05358,0.65136 -5.84566,1.3298 -1.79207,0.67844 -3.39432,1.56902 -4.69144,2.60198 -1.29713,1.03296 -2.28898,2.20893 -2.84443,3.45293 -0.55546,1.24399 -0.67186,2.55593 -0.21954,3.84888 z"
id="path4648"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssssssssssss" />
</g>
<g
inkscape:groupmode="layer"
id="layer12"
inkscape:label="gopher-hands"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-15.732722,-256.54886)">
<g
id="g4533"
transform="matrix(-0.28489616,-0.34500545,-0.42832103,0.44649678,715.99765,474.46827)">
<path
sodipodi:nodetypes="sssssssssssssssss"
inkscape:connector-curvature="0"
id="ellipse4523"
d="m 423.50332,581.83521 c -0.004,4.40048 -1.19837,7.58856 -3.37524,9.82844 -2.17687,2.23987 -5.33154,3.55156 -9.14619,4.44292 -3.81465,0.89135 -8.28246,1.39523 -13.05675,1.83828 -4.77428,0.44304 -9.85163,0.79076 -14.95001,1.09928 -5.09838,0.30851 -9.94541,0.34741 -14.40217,0.0862 -4.45676,-0.26122 -8.52354,-0.79908 -11.99271,-1.71189 -3.46915,-0.91282 -6.33736,-2.21356 -8.3562,-4.09288 -2.01885,-1.87935 -3.18709,-4.34475 -3.25466,-7.51083 -0.0676,-3.16607 0.9983,-5.4859 2.92534,-7.0838 1.92703,-1.5979 4.71248,-2.46394 8.09977,-2.84688 3.38729,-0.38293 7.37282,-0.28336 11.77044,-0.16051 4.39762,0.12284 9.21051,0.23456 14.33166,-0.12202 5.12115,-0.35659 10.27171,-1.47349 15.16022,-2.54099 4.88852,-1.06749 9.50395,-2.05149 13.43823,-2.27114 3.9343,-0.21967 7.17754,0.32322 9.39823,2.04598 2.22069,1.72276 3.41425,4.59936 3.41004,8.99986 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4273);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
sodipodi:nodetypes="ssscsscssssssssssssssssssssccsss"
inkscape:connector-curvature="0"
id="path4521"
d="m 411.91406,568.54883 c -3.75011,-0.0271 -8.08701,0.53975 -12.76172,1.28711 -5.34251,0.85413 -11.10706,1.92059 -17.00976,2.32617 -5.9027,0.40562 -11.41103,0.38326 -16.44727,0.41406 -5.03624,0.0309 -9.6045,0.1607 -13.50781,0.85938 -3.9033,0.69867 -7.13503,1.96743 -9.4082,3.96875 -2.27316,2.00131 -3.58535,4.71676 -3.65235,8.17578 -0.067,3.45901 1.21821,6.3073 3.54297,8.58008 2.32476,2.27278 5.68789,3.9795 9.76172,5.25 4.07385,1.27051 8.85237,2.11894 14.05664,2.59765 5.20427,0.47871 10.83381,0.56134 16.70313,0.22266 5.86931,-0.33868 11.47146,-0.78653 16.60547,-1.34961 5.13399,-0.56309 9.79334,-1.22365 13.70703,-2.34375 1.48913,-0.4262 2.86677,-0.9287 4.12695,-1.51953 2.54507,-1.19325 2.05015,-6.17249 -0.0996,-4.54102 -1.99172,1.51153 -4.55969,2.50355 -7.57031,3.20703 -3.66893,0.85731 -7.96668,1.34146 -12.5586,1.76758 -4.59191,0.42612 -9.47527,0.75991 -14.3789,1.05664 -4.90363,0.29673 -9.56506,0.33523 -13.85156,0.084 -4.28652,-0.25124 -8.19851,-0.76855 -11.53516,-1.64649 -3.33664,-0.87795 -6.09539,-2.12996 -8.03711,-3.9375 -1.94173,-1.80756 -3.06587,-4.17751 -3.13086,-7.22265 -0.065,-3.04513 0.96102,-5.2776 2.81445,-6.81446 1.85342,-1.53686 4.53117,-2.36997 7.78907,-2.73828 3.2579,-0.36831 7.09262,-0.27244 11.32226,-0.1543 4.22963,0.11816 8.85767,0.22578 13.7832,-0.11718 4.92553,-0.34297 9.88026,-1.41664 14.58204,-2.44336 4.70178,-1.02671 9.13982,-1.97234 12.92382,-2.1836 0.473,-0.0264 0.93707,-0.0422 1.38868,-0.0449 1.16046,-0.007 2.25007,0.0442 3.25,0.23633 1.15313,0.22156 2.31543,-2.86146 -0.83789,-2.92773 -0.51177,-0.0108 -1.03459,-0.045 -1.57032,-0.0488 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#gopher-lines);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="cape-front"
style="display:inline"
transform="translate(-15.732722,-256.54886)">
<path
sodipodi:nodetypes="cssscscc"
inkscape:connector-curvature="0"
id="path4248"
d="m 250.62773,531.91504 c -9.09672,21.35801 -15.29674,29.07226 -30.27188,44.83759 -11.50237,12.10933 -28.85117,24.46609 -43.81134,39.61682 -13.55246,13.72509 -26.12338,21.00434 -64.22257,32.01103 -11.97434,3.45934 -44.031036,6.55017 -51.472472,37.30246 C 107.21772,654.7909 183.17617,662.32228 228.40418,636.09787 266.34279,614.10005 317.82474,552.6315 355.9453,547.7268 284.49621,547.05928 263.34291,542.49874 250.62773,531.91504 Z"
style="display:inline;fill:#019833;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#019833;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 473.29262,543.99873 73.7751,-5.10117 c 0,0 2.29258,1.0455 2.68673,2.11494 7.36409,19.98076 -12.72148,60.84328 -12.72148,60.84328 0,-2.97132 13.53121,-43.94425 -5.91529,-53.46522 -16.4456,-8.05173 -38.16124,-2.06803 -57.82506,-4.39183 z"
id="path4265"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccscsc" />
<path
style="display:inline;fill:#019432;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 249.90625,533.57227 c -8.70868,20.08478 -14.97837,27.83833 -29.55078,43.17968 -11.50237,12.10933 -28.85038,24.46646 -43.81055,39.61719 -13.55246,13.72509 -26.12346,21.00503 -64.22265,32.01172 -10.63128,3.07133 -37.077893,5.86957 -48.087895,27.97656 2.731585,-3.48747 7.206694,-4.8761 9.881319,-8.70029 4.506995,-6.44411 60.824806,-11.61546 75.673426,-21.06752 9.77176,-6.22033 32.61216,-17.69963 44.08393,-25.40211 11.47178,-7.70248 50.16856,-39.82139 59.98047,-41.62695 30.99143,-5.70295 56.04882,-31.95703 56.04882,-31.95703 0,0 -5.76873,-1.34099 -7.30468,-1.69727 -26.4653,-1.9743 -39.57284,-5.58234 -48.29883,-11.28125 -1.77957,-0.42346 -3.78649,-0.89828 -4.39258,-1.05273 z"
id="path4280"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssscsssscccc" />
<path
style="fill:#01a939;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 250.88543,527.29897 c 4.9284,1.23444 7.57648,5.23948 12.39942,6.83706 14.83134,4.91283 28.22069,8.13985 43.80356,9.2706 19.18619,1.39223 40.09821,1.50171 59.33179,1.15882 36.63136,-0.65304 73.4946,-1.92414 110.08831,-3.70824 19.9513,-0.97271 40.58394,-2.2893 60.49061,-3.94 3.86874,-0.3208 7.97563,-6.05622 11.58825,-4.6353 2.39418,0.94168 2.01049,3.29975 2.64058,5.79412 2.44082,4.93143 0.14511,6.64447 -5.65353,7.64824 -19.43937,3.05253 -39.20884,3.55847 -58.86827,4.40354 -48.01128,2.06378 -96.10464,2.11621 -144.15772,1.62235 -17.00379,-0.17475 -34.11943,0.52285 -50.98827,-1.62235 -13.27515,-1.68819 -26.90453,-3.45163 -39.16825,-8.80707 -4.12399,-1.80091 -7.99437,-2.72852 -8.97266,-7.12095 -0.30759,-1.38101 1.19417,-2.17728 1.88173,-3.29956 0.57446,-0.93767 0.21317,-2.26036 1.23886,-2.84803 1.34064,-0.76812 2.84679,-1.12864 4.34559,-0.75323 z"
id="path4267"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssssccssssssss" />
<path
style="fill:#019d35;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 245.9043,528.82812 c -0.24767,0.63868 -0.21658,1.44068 -0.60352,2.07227 -0.68756,1.12228 -2.18845,1.91782 -1.88086,3.29883 0.97829,4.39243 4.84867,5.32018 8.97266,7.12109 12.26372,5.35544 25.89282,7.11845 39.16797,8.80664 16.86884,2.1452 33.98449,1.4483 50.98828,1.62305 48.05308,0.49386 96.14692,0.44073 144.1582,-1.62305 19.65943,-0.84507 39.42782,-1.34981 58.86719,-4.40234 5.79864,-1.00377 8.09512,-2.71701 5.6543,-7.64844 -0.0557,-0.22031 -0.0962,-0.43699 -0.13868,-0.65429 0.48647,4.64963 -6.66572,4.9037 -11.87478,5.92187 -33.64204,6.57569 -68.48165,3.5437 -102.75586,4.0957 -42.87828,0.69057 -93.34812,6.52037 -135.57053,-0.98242 -17.79033,-3.16129 -43.90403,-10.17243 -54.98437,-17.62891 z"
id="path4340"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssssscccsssc" />
</g>
<g
inkscape:groupmode="layer"
id="layer8"
inkscape:label="vim"
transform="translate(-15.732722,-256.54886)">
<g
id="g4330">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#005d04;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4293"
width="194.71968"
height="194.71968"
x="-29.381023"
y="744.44128"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
<rect
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
y="753.35699"
x="-20.465342"
height="176.88821"
width="176.88821"
id="rect4283"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#019833;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
id="text4285"
style="font-style:normal;font-weight:normal;font-size:203.27047729px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#fefefe;fill-opacity:1;stroke:#005d04;stroke-width:4;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.0880646,0,-0.29154603,1.0880646,-528.83975,-369.0604)">
<path
sodipodi:nodetypes="cccccccccccccccsc"
inkscape:connector-curvature="0"
id="path4324"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-family:Eczar;-inkscape-font-specification:'Eczar Ultra-Bold';fill:#fefefe;fill-opacity:1;stroke:#005d04;stroke-width:5.01092911;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 202.34975,1029.0537 -56.02157,-157.11507 -17.82505,-3.05571 0.25466,-14.0054 89.88914,0 1.52787,8.1486 c -2.7162,2.2069 -5.77193,4.32893 -9.16717,6.36609 -3.22549,2.03714 -6.70561,3.98941 -10.44038,5.85679 l 26.38345,87.17129 39.56921,-89.71773 -21.89934,-3.81964 0.25464,-14.0054 72.06411,0 -68.4991,168.82868 0.25465,0.2547 c -6.28122,1.0184 -13.49612,1.9522 -21.6447,2.8011 -8.14859,0.8487 -16.38207,1.6126 -24.70042,2.2917 z" />
</g>
</g>
<use
x="0"
y="0"
xlink:href="#g4330"
id="use4338"
transform="matrix(0.4546439,-0.10745401,-0.02175104,0.44922994,711.99298,282.73776)"
width="100%"
height="100%" />
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="palette"
style="display:inline"
sodipodi:insensitive="true"
transform="translate(-15.732722,-256.54886)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4168);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4162"
width="40.789474"
height="40.789474"
x="779.60529"
y="21.967466" />
<rect
y="21.967466"
x="824.60529"
height="40.789474"
width="40.789474"
id="rect4170"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4180);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052742;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#bce8ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4208"
width="40.789474"
height="40.789474"
x="779.60529"
y="86.967468" />
<rect
y="-127.75694"
x="824.60529"
height="40.789474"
width="40.789474"
id="rect4223"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#abccd9;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
transform="scale(1,-1)" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c3b0cb;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4227"
width="40.789474"
height="40.789474"
x="779.60529"
y="131.96747" />
<rect
y="131.96747"
x="824.60529"
height="40.789474"
width="40.789474"
id="rect4231"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#e1d0cb;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#f5c3d2;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4233"
width="40.789474"
height="40.789474"
x="869.60529"
y="131.96747" />
<rect
y="176.96747"
x="779.60529"
height="40.789474"
width="40.789474"
id="rect4248"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#cec4ad;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
transform="scale(1,-1)"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#96d6ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4263"
width="40.789474"
height="40.789474"
x="869.60529"
y="-127.75694" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#f2f2ce;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4267"
width="40.789474"
height="40.789474"
x="824.60529"
y="176.96747" />
<rect
y="-327.75693"
x="779.60529"
height="40.789474"
width="40.789474"
id="rect4280"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#24b8eb;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
transform="scale(1,-1)" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#8aa9ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4284"
width="40.789474"
height="40.789474"
x="824.60529"
y="286.96747" />
<rect
y="331.96747"
x="779.60529"
height="40.789474"
width="40.789474"
id="rect4297"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d4edf1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#394d54;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4301"
width="40.789474"
height="40.789474"
x="779.60529"
y="241.96747" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d6e2ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:9.21052647;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4303"
width="40.789474"
height="40.789474"
x="824.60529"
y="331.96747" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 84 KiB

@ -14,12 +14,12 @@ else
let g:ctrlp_ext_vars = [s:go_decls_var] let g:ctrlp_ext_vars = [s:go_decls_var]
endif endif
function! ctrlp#decls#init() function! ctrlp#decls#init() abort
cal s:enable_syntax() cal s:enable_syntax()
return s:decls return s:decls
endfunction endfunction
function! ctrlp#decls#exit() function! ctrlp#decls#exit() abort
unlet! s:decls s:current_dir s:target unlet! s:decls s:current_dir s:target
endfunction endfunction
@ -28,7 +28,7 @@ endfunction
" a:mode the mode that has been chosen by pressing <cr> <c-v> <c-t> or <c-x> " 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 " the values are 'e', 'v', 't' and 'h', respectively
" a:str the selected string " a:str the selected string
function! ctrlp#decls#accept(mode, str) function! ctrlp#decls#accept(mode, str) abort
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd() let dir = getcwd()
try try
@ -56,7 +56,7 @@ function! ctrlp#decls#accept(mode, str)
endtry endtry
endfunction endfunction
function! ctrlp#decls#enter() function! ctrlp#decls#enter() abort
let s:current_dir = fnameescape(expand('%:p:h')) let s:current_dir = fnameescape(expand('%:p:h'))
let s:decls = [] let s:decls = []
@ -87,16 +87,12 @@ function! ctrlp#decls#enter()
let command .= printf(" -dir %s", dir) let command .= printf(" -dir %s", dir)
endif endif
let out = system(command) let out = go#util#System(command)
if v:shell_error != 0 if go#util#ShellError() != 0
call go#util#EchoError(out) call go#util#EchoError(out)
return return
endif endif
if exists("l:tmpname")
call delete(l:tmpname)
endif
let result = eval(out) let result = eval(out)
if type(result) != 4 || !has_key(result, 'decls') if type(result) != 4 || !has_key(result, 'decls')
return return
@ -130,7 +126,7 @@ function! ctrlp#decls#enter()
endfor endfor
endfunc endfunc
function! s:enable_syntax() function! s:enable_syntax() abort
if !(has('syntax') && exists('g:syntax_on')) if !(has('syntax') && exists('g:syntax_on'))
return return
endif endif
@ -148,7 +144,7 @@ endfunction
let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars)
function! ctrlp#decls#cmd(mode, ...) function! ctrlp#decls#cmd(mode, ...) abort
let s:mode = a:mode let s:mode = a:mode
if a:0 && !empty(a:1) if a:0 && !empty(a:1)
let s:target = a:1 let s:target = a:1
@ -156,3 +152,4 @@ function! ctrlp#decls#cmd(mode, ...)
return s:id return s:id
endfunction endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,150 @@
function! s:code(group, attr) abort
let code = synIDattr(synIDtrans(hlID(a:group)), a:attr, "cterm")
if code =~ '^[0-9]\+$'
return code
endif
endfunction
function! s:color(str, group) abort
let fg = s:code(a:group, "fg")
let bg = s:code(a:group, "bg")
let bold = s:code(a:group, "bold")
let italic = s:code(a:group, "italic")
let reverse = s:code(a:group, "reverse")
let underline = s:code(a:group, "underline")
let color = (empty(fg) ? "" : ("38;5;".fg)) .
\ (empty(bg) ? "" : (";48;5;".bg)) .
\ (empty(bold) ? "" : ";1") .
\ (empty(italic) ? "" : ";3") .
\ (empty(reverse) ? "" : ";7") .
\ (empty(underline) ? "" : ";4")
return printf("\x1b[%sm%s\x1b[m", color, a:str)
endfunction
function! s:sink(str) abort
if len(a:str) < 2
return
endif
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 . fnameescape(s:current_dir)
let vals = matchlist(a:str[1], '|\(.\{-}\):\(\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")
let cmd = get({'ctrl-x': 'split',
\ 'ctrl-v': 'vertical split',
\ 'ctrl-t': 'tabe'}, a:str[0], 'e')
execute cmd fnameescape(filepath)
call cursor(line, col)
silent! norm! zvzz
finally
"jump back to old dir
execute cd . fnameescape(dir)
endtry
endfunction
function! s:source(mode,...) abort
let s:current_dir = expand('%:p:h')
let ret_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 a:mode == 0
" current file mode
let fname = expand("%:p")
if a:0 && !empty(a:1)
let fname = a:1
endif
let command .= printf(" -file %s", shellescape(fname))
else
" all functions mode
if a:0 && !empty(a:1)
let s:current_dir = a:1
endif
let command .= printf(" -dir %s", shellescape(s:current_dir))
endif
let out = go#util#System(command)
if go#util#ShellError() != 0
call go#util#EchoError(out)
return
endif
let result = eval(out)
if type(result) != 4 || !has_key(result, 'decls')
return ret_decls
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
let pos = printf("|%s:%s:%s|",
\ fnamemodify(decl.filename, ":t"),
\ decl.line,
\ decl.col
\)
call add(ret_decls, printf("%s\t%s %s\t%s",
\ s:color(decl.ident . space, "Function"),
\ s:color(decl.keyword, "Keyword"),
\ s:color(pos, "SpecialComment"),
\ s:color(decl.full, "Comment"),
\))
endfor
return ret_decls
endfunc
function! fzf#decls#cmd(...) abort
let normal_fg = s:code("Normal", "fg")
let normal_bg = s:code("Normal", "bg")
let cursor_fg = s:code("CursorLine", "fg")
let cursor_bg = s:code("CursorLine", "bg")
let colors = printf(" --color %s%s%s%s%s",
\ &background,
\ empty(normal_fg) ? "" : (",fg:".normal_fg),
\ empty(normal_bg) ? "" : (",bg:".normal_bg),
\ empty(cursor_fg) ? "" : (",fg+:".cursor_fg),
\ empty(cursor_bg) ? "" : (",bg+:".cursor_bg),
\)
call fzf#run(fzf#wrap('GoDecls', {
\ 'source': call('<sid>source', a:000),
\ 'options': '-n 1 --ansi --prompt "GoDecls> " --expect=ctrl-t,ctrl-v,ctrl-x'.colors,
\ 'sink*': function('s:sink')
\ }))
endfunction
" vim: sw=2 ts=2 et

@ -4,7 +4,7 @@ if !exists("g:go_alternate_mode")
endif endif
" Test alternates between the implementation of code and the test code. " Test alternates between the implementation of code and the test code.
function! go#alternate#Switch(bang, cmd) function! go#alternate#Switch(bang, cmd) abort
let file = expand('%') let file = expand('%')
if empty(file) if empty(file)
call go#util#EchoError("no buffer name") call go#util#EchoError("no buffer name")
@ -28,3 +28,5 @@ function! go#alternate#Switch(bang, cmd)
execute ":" . a:cmd . " " . alt_file execute ":" . a:cmd . " " . alt_file
endif endif
endfunction endfunction
" vim: sw=2 ts=2 et

@ -11,7 +11,7 @@
" "
" Options: " Options:
" "
" g:go_asmfmt_autosave [default=1] " g:go_asmfmt_autosave [default=0]
" "
" Flag to automatically call :Fmt when file is saved. " Flag to automatically call :Fmt when file is saved.
@ -19,29 +19,33 @@ let s:got_fmt_error = 0
" This is a trimmed-down version of the logic in fmt.vim. " This is a trimmed-down version of the logic in fmt.vim.
function! go#asmfmt#Format() function! go#asmfmt#Format() abort
" Save state. " Save state.
let l:curw = winsaveview() let l:curw = winsaveview()
" Write the current buffer to a tempfile. " Write the current buffer to a tempfile.
let l:tmpname = tempname() let l:tmpname = tempname()
call writefile(getline(1, '$'), l:tmpname) call writefile(go#util#GetLines(), l:tmpname)
" Run asmfmt. " Run asmfmt.
let path = go#path#CheckBinPath("asmfmt") let path = go#path#CheckBinPath("asmfmt")
if empty(path) if empty(path)
return return
endif endif
let out = system(path . ' -w ' . l:tmpname) let out = go#util#System(path . ' -w ' . l:tmpname)
" If there's no error, replace the current file with the output. " If there's no error, replace the current file with the output.
if v:shell_error == 0 if go#util#ShellError() == 0
" Remove undo point caused by BufWritePre. " Remove undo point caused by BufWritePre.
try | silent undojoin | catch | endtry try | silent undojoin | catch | endtry
" Replace the current file with the temp file; then reload the buffer. " Replace the current file with the temp file; then reload the buffer.
let old_fileformat = &fileformat let old_fileformat = &fileformat
" save old file permissions
let original_fperm = getfperm(expand('%'))
call rename(l:tmpname, expand('%')) call rename(l:tmpname, expand('%'))
" restore old file permissions
call setfperm(expand('%'), original_fperm)
silent edit! silent edit!
let &fileformat = old_fileformat let &fileformat = old_fileformat
let &syntax = &syntax let &syntax = &syntax
@ -50,3 +54,16 @@ function! go#asmfmt#Format()
" Restore the cursor/window positions. " Restore the cursor/window positions.
call winrestview(l:curw) call winrestview(l:curw)
endfunction endfunction
function! go#asmfmt#ToggleAsmFmtAutoSave() abort
if get(g:, "go_asmfmt_autosave", 0)
let g:go_asmfmt_autosave = 1
call go#util#EchoProgress("auto asmfmt enabled")
return
end
let g:go_asmfmt_autosave = 0
call go#util#EchoProgress("auto asmfmt disabled")
endfunction
" vim: sw=2 ts=2 et

@ -1,53 +1,57 @@
if !exists("g:go_dispatch_enabled") function! go#cmd#autowrite() abort
let g:go_dispatch_enabled = 0
endif
function! go#cmd#autowrite()
if &autowrite == 1 if &autowrite == 1
silent wall silent! wall
endif endif
endfunction endfunction
" Build builds the source code without producing any output binary. We live in
" 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 " 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 " 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. " dependent files for the current folder and passes it to go build.
function! go#cmd#Build(bang, ...) function! go#cmd#Build(bang, ...) abort
" expand all wildcards(i.e: '%' to the current file name) " Create our command arguments. go build discards any results when it
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 " compiles multiple packages. So we pass the `errors` package just as an
" placeholder with the current folder (indicated with '.') " placeholder with the current folder (indicated with '.'). We also pass -i
let args = ["build"] + goargs + [".", "errors"] " that tries to install the dependencies, this has the side effect that it
" caches the build results, so every other build is faster.
let args =
\ ["build"] +
\ map(copy(a:000), "expand(v:val)") +
\ ["-i", ".", "errors"]
" Vim async.
if go#util#has_job()
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoProgress("building dispatched ...")
endif
" if we have nvim, call it asynchronously and return early ;) call s:cmd_job({
if has('nvim') \ 'cmd': ['go'] + args,
\ 'bang': a:bang,
\ 'for': 'GoBuild',
\})
" Nvim async.
elseif has('nvim')
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoProgress("building dispatched ...") call go#util#EchoProgress("building dispatched ...")
call go#jobcontrol#Spawn(a:bang, "build", args)
return
endif endif
let old_gopath = $GOPATH call go#jobcontrol#Spawn(a:bang, "build", "GoBuild", args)
let $GOPATH = go#path#Detect()
" Vim 7.4 without async
else
let default_makeprg = &makeprg let default_makeprg = &makeprg
let &makeprg = "go " . join(args, ' ') let &makeprg = "go " . join(go#util#Shelllist(args), ' ')
let l:listtype = go#list#Type("quickfix") let l:listtype = go#list#Type("GoBuild")
" execute make inside the source folder so we can parse the errors " execute make inside the source folder so we can parse the errors
" correctly " correctly
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd() let dir = getcwd()
try try
execute cd . fnameescape(expand("%:p:h")) execute cd . fnameescape(expand("%:p:h"))
if g:go_dispatch_enabled && exists(':Make') == 2 if l:listtype == "locationlist"
call go#util#EchoProgress("building dispatched ...")
silent! exe 'Make'
elseif l:listtype == "locationlist"
silent! exe 'lmake!' silent! exe 'lmake!'
else else
silent! exe 'make!' silent! exe 'make!'
@ -59,22 +63,41 @@ function! go#cmd#Build(bang, ...)
let errors = go#list#Get(l:listtype) let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang
if !empty(errors)
if !a:bang
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
endif
else else
call go#util#EchoSuccess("[build] SUCCESS") call go#util#EchoSuccess("[build] SUCCESS")
endif endif
let &makeprg = default_makeprg let &makeprg = default_makeprg
let $GOPATH = old_gopath endif
endfunction
" BuildTags sets or shows the current build tags used for tools
function! go#cmd#BuildTags(bang, ...) abort
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_build_tags
call go#util#EchoSuccess("build tags are cleared")
else
let g:go_build_tags = a:1
call go#util#EchoSuccess("build tags are changed to: ". a:1)
endif
return
endif
if !exists('g:go_build_tags')
call go#util#EchoSuccess("build tags are not set")
else
call go#util#EchoSuccess("current build tags: ". g:go_build_tags)
endif
endfunction endfunction
" Run runs the current file (and their dependencies if any) in a new terminal. " Run runs the current file (and their dependencies if any) in a new terminal.
function! go#cmd#RunTerm(bang, mode, files) function! go#cmd#RunTerm(bang, mode, files) abort
if empty(a:files) if empty(a:files)
let cmd = "go run ". go#util#Shelljoin(go#tool#Files()) let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
else else
@ -84,17 +107,20 @@ function! go#cmd#RunTerm(bang, mode, files)
endfunction endfunction
" Run runs the current file (and their dependencies if any) and outputs it. " 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 " This is intended to test small programs and play with them. It's not
" suitable for long running apps, because vim is blocking by default and " suitable for long running apps, because vim is blocking by default and
" calling long running apps will block the whole UI. " calling long running apps will block the whole UI.
function! go#cmd#Run(bang, ...) function! go#cmd#Run(bang, ...) abort
if has('nvim') if has('nvim')
call go#cmd#RunTerm(a:bang, '', a:000) call go#cmd#RunTerm(a:bang, '', a:000)
return return
endif endif
let old_gopath = $GOPATH if go#util#has_job()
let $GOPATH = go#path#Detect() " NOTE(arslan): 'term': 'open' case is not implement for +jobs. This means
" executions waiting for stdin will not work. That's why we don't do
" anything. Once this is implemented we're going to make :GoRun async
endif
if go#util#IsWin() if go#util#IsWin()
exec '!go run ' . go#util#Shelljoin(go#tool#Files()) exec '!go run ' . go#util#Shelljoin(go#tool#Files())
@ -104,7 +130,6 @@ function! go#cmd#Run(bang, ...)
redraws! | echon "vim-go: [run] " | echohl Function | echon "SUCCESS"| echohl None redraws! | echon "vim-go: [run] " | echohl Function | echon "SUCCESS"| echohl None
endif endif
let $GOPATH = old_gopath
return return
endif endif
@ -116,11 +141,9 @@ function! go#cmd#Run(bang, ...)
let &makeprg = "go run " . go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1) let &makeprg = "go run " . go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
endif endif
let l:listtype = go#list#Type("quickfix") let l:listtype = go#list#Type("GoRun")
if g:go_dispatch_enabled && exists(':Make') == 2 if l:listtype == "locationlist"
silent! exe 'Make'
elseif l:listtype == "locationlist"
exe 'lmake!' exe 'lmake!'
else else
exe 'make!' exe 'make!'
@ -129,37 +152,50 @@ function! go#cmd#Run(bang, ...)
let items = go#list#Get(l:listtype) let items = go#list#Get(l:listtype)
let errors = go#tool#FilterValids(items) let errors = go#tool#FilterValids(items)
call go#list#Populate(l:listtype, errors) call go#list#Populate(l:listtype, errors, &makeprg)
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
endif endif
let $GOPATH = old_gopath
let &makeprg = default_makeprg let &makeprg = default_makeprg
endfunction endfunction
" Install installs the package by simple calling 'go install'. If any argument " Install installs the package by simple calling 'go install'. If any argument
" is given(which are passed directly to 'go install') it tries to install those " is given(which are passed directly to 'go install') it tries to install
" packages. Errors are populated in the location window. " those packages. Errors are populated in the location window.
function! go#cmd#Install(bang, ...) function! go#cmd#Install(bang, ...) abort
" use vim's job functionality to call it asynchronously
if go#util#has_job()
" expand all wildcards(i.e: '%' to the current file name)
let goargs = map(copy(a:000), "expand(v:val)")
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoProgress("installing dispatched ...")
endif
call s:cmd_job({
\ 'cmd': ['go', 'install'] + goargs,
\ 'bang': a:bang,
\ 'for': 'GoInstall',
\})
return
endif
let default_makeprg = &makeprg let default_makeprg = &makeprg
" :make expands '%' and '#' wildcards, so they must also be escaped " :make expands '%' and '#' wildcards, so they must also be escaped
let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1) let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
let &makeprg = "go install " . goargs let &makeprg = "go install " . goargs
let l:listtype = go#list#Type("quickfix") let l:listtype = go#list#Type("GoInstall")
" execute make inside the source folder so we can parse the errors " execute make inside the source folder so we can parse the errors
" correctly " correctly
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd() let dir = getcwd()
try try
execute cd . fnameescape(expand("%:p:h")) execute cd . fnameescape(expand("%:p:h"))
if g:go_dispatch_enabled && exists(':Make') == 2 if l:listtype == "locationlist"
call go#util#EchoProgress("building dispatched ...")
silent! exe 'Make'
elseif l:listtype == "locationlist"
silent! exe 'lmake!' silent! exe 'lmake!'
else else
silent! exe 'make!' silent! exe 'make!'
@ -171,177 +207,32 @@ function! go#cmd#Install(bang, ...)
let errors = go#list#Get(l:listtype) let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !empty(errors)
if !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 or
" to create a test binary.
if a:compile
call add(args, "-c")
endif
if a:0
" expand all wildcards(i.e: '%' to the current file name)
let goargs = map(copy(a:000), "expand(v:val)")
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)
call go#term#new(a:bang, ["go"] + args)
else
call go#jobcontrol#Spawn(a:bang, "test", args)
endif
return
endif
call go#cmd#autowrite()
redraw
let command = "go " . join(args, ' ')
let out = go#tool#ExecuteInDir(command)
let l:listtype = "quickfix"
if v:shell_error
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
try
execute cd fnameescape(expand("%:p:h"))
let errors = go#tool#ParseErrors(split(out, '\n'))
let errors = go#tool#FilterValids(errors)
finally
execute cd . fnameescape(dir)
endtry
call go#list#Populate(l:listtype, errors)
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
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 else
call go#list#Clean(l:listtype) call go#util#EchoSuccess("installed to ". go#path#Default())
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 endif
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", "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
" Coverage creates a new cover profile with 'go test -coverprofile' and opens
" a new HTML coverage page from that profile.
function! go#cmd#Coverage(bang, ...)
let l:tmpname=tempname()
let command = "go test -coverprofile=" . l:tmpname . ' ' . go#util#Shelljoin(a:000)
let l:listtype = "quickfix" let &makeprg = default_makeprg
call go#cmd#autowrite()
let out = go#tool#ExecuteInDir(command)
if v:shell_error
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
else
" clear previous location list
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
let openHTML = 'go tool cover -html='.l:tmpname
call go#tool#ExecuteInDir(openHTML)
endif
call delete(l:tmpname)
endfunction endfunction
" Generate runs 'go generate' in similar fashion to go#cmd#Build() " Generate runs 'go generate' in similar fashion to go#cmd#Build()
function! go#cmd#Generate(bang, ...) function! go#cmd#Generate(bang, ...) abort
let default_makeprg = &makeprg let default_makeprg = &makeprg
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
" :make expands '%' and '#' wildcards, so they must also be escaped " :make expands '%' and '#' wildcards, so they must also be escaped
let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1) let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
if v:shell_error if go#util#ShellError() != 0
let &makeprg = "go generate " . goargs let &makeprg = "go generate " . goargs
else else
let gofiles = go#util#Shelljoin(go#tool#Files(), 1) let gofiles = go#util#Shelljoin(go#tool#Files(), 1)
let &makeprg = "go generate " . goargs . ' ' . gofiles let &makeprg = "go generate " . goargs . ' ' . gofiles
endif endif
let l:listtype = go#list#Type("quickfix") let l:listtype = go#list#Type("GoGenerate")
echon "vim-go: " | echohl Identifier | echon "generating ..."| echohl None echon "vim-go: " | echohl Identifier | echon "generating ..."| echohl None
if g:go_dispatch_enabled && exists(':Make') == 2 if l:listtype == "locationlist"
silent! exe 'Make'
elseif l:listtype == "locationlist"
silent! exe 'lmake!' silent! exe 'lmake!'
else else
silent! exe 'make!' silent! exe 'make!'
@ -359,7 +250,62 @@ function! go#cmd#Generate(bang, ...)
endif endif
let &makeprg = default_makeprg let &makeprg = default_makeprg
let $GOPATH = old_gopath
endfunction endfunction
" vim:ts=4:sw=4:et " ---------------------
" | Vim job callbacks |
" ---------------------
function s:cmd_job(args) abort
let status_dir = expand('%:p:h')
let started_at = reltime()
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': a:args.cmd[1],
\ 'state': "started",
\})
" autowrite is not enabled for jobs
call go#cmd#autowrite()
function! s:error_info_cb(job, exit_status, data) closure abort
let status = {
\ 'desc': 'last status',
\ 'type': a:args.cmd[1],
\ 'state': "success",
\ }
if a:exit_status
let status.state = "failed"
endif
let elapsed_time = reltimestr(reltime(started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
call go#statusline#Update(status_dir, status)
endfunction
let a:args.error_info_cb = funcref('s:error_info_cb')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ }
" pre start
let dir = getcwd()
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let jobdir = fnameescape(expand("%:p:h"))
execute cd . jobdir
call job_start(a:args.cmd, start_options)
" post start
execute cd . fnameescape(dir)
endfunction
" vim: sw=2 ts=2 et

@ -1,79 +1,45 @@
if !exists("g:go_gocode_bin") let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix'
let g:go_gocode_bin = "gocode"
endif
fu! s:gocodeCurrentBuffer() function! s:gocodeCurrentBuffer() abort
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() let file = tempname()
call writefile(buf, file) call writefile(go#util#GetLines(), file)
return file return file
endf endfunction
if go#vimproc#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
fu! s:shell_error()
if empty(s:vim_shell_error)
return v:shell_error
endif
return call(s:vim_shell_error, [])
endf
fu! s:system(str, ...)
return call(s:vim_system, [a:str] + a:000)
endf
fu! s:gocodeShellescape(arg)
if go#vimproc#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
fu! s:gocodeCommand(cmd, preargs, args) function! s:gocodeCommand(cmd, preargs, args) abort
for i in range(0, len(a:args) - 1) for i in range(0, len(a:args) - 1)
let a:args[i] = s:gocodeShellescape(a:args[i]) let a:args[i] = go#util#Shellescape(a:args[i])
endfor endfor
for i in range(0, len(a:preargs) - 1) for i in range(0, len(a:preargs) - 1)
let a:preargs[i] = s:gocodeShellescape(a:preargs[i]) let a:preargs[i] = go#util#Shellescape(a:preargs[i])
endfor endfor
let bin_path = go#path#CheckBinPath(g:go_gocode_bin) let bin_path = go#path#CheckBinPath("gocode")
if empty(bin_path) if empty(bin_path)
return return
endif endif
" we might hit cache problems, as gocode doesn't handle well different " We might hit cache problems, as gocode doesn't handle different GOPATHs
" GOPATHS: https://github.com/nsf/gocode/issues/239 " well. See: https://github.com/nsf/gocode/issues/239
let old_gopath = $GOPATH let old_goroot = $GOROOT
let $GOPATH = go#path#Detect() let $GOROOT = go#util#env("goroot")
let result = s:system(printf('%s %s %s %s', s:gocodeShellescape(bin_path), join(a:preargs), s:gocodeShellescape(a:cmd), join(a:args))) try
let socket_type = get(g:, 'go_gocode_socket_type', s:sock_type)
let $GOPATH = old_gopath let cmd = printf('%s -sock %s %s %s %s',
\ go#util#Shellescape(bin_path),
\ socket_type,
\ join(a:preargs),
\ go#util#Shellescape(a:cmd),
\ join(a:args)
\ )
let result = go#util#System(cmd)
finally
let $GOROOT = old_goroot
endtry
if s:shell_error() != 0 if go#util#ShellError() != 0
return "[\"0\", []]" return "[\"0\", []]"
else else
if &encoding != 'utf-8' if &encoding != 'utf-8'
@ -81,22 +47,46 @@ fu! s:gocodeCommand(cmd, preargs, args)
endif endif
return result return result
endif endif
endf endfunction
fu! s:gocodeCurrentBufferOpt(filename) function! s:gocodeCurrentBufferOpt(filename) abort
return '-in=' . a:filename return '-in=' . a:filename
endf endfunction
let s:optionsEnabled = 0
function! s:gocodeEnableOptions() abort
if s:optionsEnabled
return
endif
let bin_path = go#path#CheckBinPath("gocode")
if empty(bin_path)
return
endif
let s:optionsEnabled = 1
call go#util#System(printf('%s set propose-builtins %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_propose_builtins', 1))))
call go#util#System(printf('%s set autobuild %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_autobuild', 1))))
call go#util#System(printf('%s set unimported-packages %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_unimported_packages', 0))))
endfunction
function! s:toBool(val) abort
if a:val | return 'true ' | else | return 'false' | endif
endfunction
function! s:gocodeAutocomplete() abort
call s:gocodeEnableOptions()
fu! s:gocodeAutocomplete()
let filename = s:gocodeCurrentBuffer() let filename = s:gocodeCurrentBuffer()
let result = s:gocodeCommand('autocomplete', let result = s:gocodeCommand('autocomplete',
\ [s:gocodeCurrentBufferOpt(filename), '-f=vim'], \ [s:gocodeCurrentBufferOpt(filename), '-f=vim'],
\ [expand('%:p'), go#util#OffsetCursor()]) \ [expand('%:p'), go#util#OffsetCursor()])
call delete(filename) call delete(filename)
return result return result
endf endfunction
function! go#complete#GetInfo() function! go#complete#GetInfo() abort
let offset = go#util#OffsetCursor()+1 let offset = go#util#OffsetCursor()+1
let filename = s:gocodeCurrentBuffer() let filename = s:gocodeCurrentBuffer()
let result = s:gocodeCommand('autocomplete', let result = s:gocodeCommand('autocomplete',
@ -113,7 +103,7 @@ function! go#complete#GetInfo()
return "" return ""
endif endif
" only one candiate is found " only one candidate is found
if len(out) == 2 if len(out) == 2
return split(out[1], ',,')[0] return split(out[1], ',,')[0]
endif endif
@ -137,7 +127,7 @@ function! go#complete#GetInfo()
return "" return ""
endfunction endfunction
function! go#complete#Info(auto) function! go#complete#Info(auto) abort
" auto is true if we were called by g:go_auto_type_info's autocmd " auto is true if we were called by g:go_auto_type_info's autocmd
let result = go#complete#GetInfo() let result = go#complete#GetInfo()
if !empty(result) if !empty(result)
@ -147,12 +137,12 @@ function! go#complete#Info(auto)
endif endif
endfunction endfunction
function! s:trim_bracket(val) function! s:trim_bracket(val) abort
let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '') let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '')
return a:val return a:val
endfunction endfunction
fu! go#complete#Complete(findstart, base) function! go#complete#Complete(findstart, base) abort
"findstart = 1 when we need to get the text length "findstart = 1 when we need to get the text length
if a:findstart == 1 if a:findstart == 1
execute "silent let g:gocomplete_completions = " . s:gocodeAutocomplete() execute "silent let g:gocomplete_completions = " . s:gocodeAutocomplete()
@ -167,4 +157,16 @@ fu! go#complete#Complete(findstart, base)
endif endif
endf endf
" vim:ts=4:sw=4:et function! go#complete#ToggleAutoTypeInfo() abort
if get(g:, "go_auto_type_info", 0)
let g:go_auto_type_info = 0
call go#util#EchoProgress("auto type info disabled")
return
end
let g:go_auto_type_info = 1
call go#util#EchoProgress("auto type info enabled")
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,375 @@
let s:toggle = 0
" Buffer creates a new cover profile with 'go test -coverprofile' and changes
" the current buffers highlighting to show covered and uncovered sections of
" the code. If run again it clears the annotation.
function! go#coverage#BufferToggle(bang, ...) abort
if s:toggle
call go#coverage#Clear()
return
endif
if a:0 == 0
return call(function('go#coverage#Buffer'), [a:bang])
endif
return call(function('go#coverage#Buffer'), [a:bang] + a:000)
endfunction
" Buffer creates a new cover profile with 'go test -coverprofile' and changes
" the current buffers highlighting to show covered and uncovered sections of
" the code. Calling it again reruns the tests and shows the last updated
" coverage.
function! go#coverage#Buffer(bang, ...) abort
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
if !exists("*matchaddpos")
call go#util#EchoError("GoCoverage is supported with Vim version 7.4-330 or later")
return -1
endif
" check if there is any test file, if not we just return
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
try
execute cd . fnameescape(expand("%:p:h"))
if empty(glob("*_test.go"))
call go#util#EchoError("no test files available")
return
endif
finally
execute cd . fnameescape(dir)
endtry
let s:toggle = 1
let l:tmpname = tempname()
if get(g:, 'go_echo_command_info', 1)
echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None
endif
if go#util#has_job()
call s:coverage_job({
\ 'cmd': ['go', 'test', '-coverprofile', l:tmpname] + a:000,
\ 'custom_cb': function('s:coverage_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ })
return
endif
let args = [a:bang, 0, "-coverprofile", l:tmpname]
if a:0
call extend(args, a:000)
endif
let disabled_term = 0
if get(g:, 'go_term_enabled')
let disabled_term = 1
let g:go_term_enabled = 0
endif
let id = call('go#test#Test', args)
if disabled_term
let g:go_term_enabled = 1
endif
if has('nvim')
call go#jobcontrol#AddHandler(function('s:coverage_handler'))
let s:coverage_handler_jobs[id] = l:tmpname
return
endif
if go#util#ShellError() == 0
call go#coverage#overlay(l:tmpname)
endif
call delete(l:tmpname)
endfunction
" Clear clears and resets the buffer annotation matches
function! go#coverage#Clear() abort
call clearmatches()
if exists("s:toggle") | let s:toggle = 0 | endif
" remove the autocmd we defined
augroup vim-go-coverage
autocmd!
augroup end
endfunction
" Browser creates a new cover profile with 'go test -coverprofile' and opens
" a new HTML coverage page from that profile in a new browser
function! go#coverage#Browser(bang, ...) abort
let l:tmpname = tempname()
if go#util#has_job()
call s:coverage_job({
\ 'cmd': ['go', 'test', '-coverprofile', l:tmpname],
\ 'custom_cb': function('s:coverage_browser_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ })
return
endif
let args = [a:bang, 0, "-coverprofile", l:tmpname]
if a:0
call extend(args, a:000)
endif
let id = call('go#test#Test', args)
if has('nvim')
call go#jobcontrol#AddHandler(function('s:coverage_browser_handler'))
let s:coverage_browser_handler_jobs[id] = l:tmpname
return
endif
if go#util#ShellError() == 0
let openHTML = 'go tool cover -html='.l:tmpname
call go#tool#ExecuteInDir(openHTML)
endif
call delete(l:tmpname)
endfunction
" Parses a single line from the cover file generated via go test -coverprofile
" and returns a single coverage profile block.
function! go#coverage#parsegocoverline(line) abort
" file:startline.col,endline.col numstmt count
let mx = '\([^:]\+\):\(\d\+\)\.\(\d\+\),\(\d\+\)\.\(\d\+\)\s\(\d\+\)\s\(\d\+\)'
let tokens = matchlist(a:line, mx)
let ret = {}
let ret.file = tokens[1]
let ret.startline = str2nr(tokens[2])
let ret.startcol = str2nr(tokens[3])
let ret.endline = str2nr(tokens[4])
let ret.endcol = str2nr(tokens[5])
let ret.numstmt = tokens[6]
let ret.cnt = tokens[7]
return ret
endfunction
" Generates matches to be added to matchaddpos for the given coverage profile
" block
function! go#coverage#genmatch(cov) abort
let color = 'goCoverageCovered'
if a:cov.cnt == 0
let color = 'goCoverageUncover'
endif
let matches = []
" if start and end are the same, also specify the byte length
" example: foo.go:92.2,92.65 1 0
if a:cov.startline == a:cov.endline
call add(matches, {
\ 'group': color,
\ 'pos': [[a:cov.startline, a:cov.startcol, a:cov.endcol - a:cov.startcol]],
\ 'priority': 2,
\ })
return matches
endif
" add start columns. Because we don't know the length of the of
" the line, we assume it is at maximum 200 bytes. I know this is hacky,
" but that's only way of fixing the issue
call add(matches, {
\ 'group': color,
\ 'pos': [[a:cov.startline, a:cov.startcol, 200]],
\ 'priority': 2,
\ })
" and then the remaining lines
let start_line = a:cov.startline
while start_line < a:cov.endline
let start_line += 1
call add(matches, {
\ 'group': color,
\ 'pos': [[start_line]],
\ 'priority': 2,
\ })
endwhile
" finally end columns
call add(matches, {
\ 'group': color,
\ 'pos': [[a:cov.endline, a:cov.endcol-1]],
\ 'priority': 2,
\ })
return matches
endfunction
" Reads the given coverprofile file and annotates the current buffer
function! go#coverage#overlay(file) abort
if !filereadable(a:file)
return
endif
let lines = readfile(a:file)
" cover mode, by default it's 'set'. Just here for debugging purposes
let mode = lines[0]
" contains matches for matchaddpos()
let matches = []
" first mark all lines as goCoverageNormalText. We use a custom group to not
" interfere with other buffers highlightings. Because the priority is
" lower than the cover and uncover matches, it'll be overridden.
let cnt = 1
while cnt <= line('$')
call add(matches, {'group': 'goCoverageNormalText', 'pos': [cnt], 'priority': 1})
let cnt += 1
endwhile
let fname = expand('%')
" when called for a _test.go file, run the coverage for the actuall file
" file
if fname =~# '^\f\+_test\.go$'
let l:root = split(fname, '_test.go$')[0]
let fname = l:root . ".go"
if !filereadable(fname)
call go#util#EchoError("couldn't find ".fname)
return
endif
" open the alternate file to show the coverage
exe ":edit ". fnamemodify(fname, ":p")
endif
" cov.file includes only the filename itself, without full path
let fname = fnamemodify(fname, ":t")
for line in lines[1:]
let cov = go#coverage#parsegocoverline(line)
" TODO(arslan): for now only include the coverage for the current
" buffer
if fname != fnamemodify(cov.file, ':t')
continue
endif
call extend(matches, go#coverage#genmatch(cov))
endfor
" clear the matches if we leave the buffer
augroup vim-go-coverage
autocmd!
autocmd BufWinLeave <buffer> call go#coverage#Clear()
augroup end
for m in matches
call matchaddpos(m.group, m.pos)
endfor
endfunction
" ---------------------
" | Vim job callbacks |
" ---------------------
"
function s:coverage_job(args)
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let status_dir = expand('%:p:h')
function! s:error_info_cb(job, exit_status, data) closure
let status = {
\ 'desc': 'last status',
\ 'type': "coverage",
\ 'state': "finished",
\ }
if a:exit_status
let status.state = "failed"
endif
call go#statusline#Update(status_dir, status)
endfunction
let a:args.error_info_cb = funcref('s:error_info_cb')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ }
" pre start
let dir = getcwd()
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let jobdir = fnameescape(expand("%:p:h"))
execute cd . jobdir
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': "coverage",
\ 'state': "started",
\})
call job_start(a:args.cmd, start_options)
" post start
execute cd . fnameescape(dir)
endfunction
" coverage_callback is called when the coverage execution is finished
function! s:coverage_callback(coverfile, job, exit_status, data)
if a:exit_status == 0
call go#coverage#overlay(a:coverfile)
endif
call delete(a:coverfile)
endfunction
function! s:coverage_browser_callback(coverfile, job, exit_status, data)
if a:exit_status == 0
let openHTML = 'go tool cover -html='.a:coverfile
call go#tool#ExecuteInDir(openHTML)
endif
call delete(a:coverfile)
endfunction
" -----------------------
" | Neovim job handlers |
" -----------------------
let s:coverage_handler_jobs = {}
let s:coverage_browser_handler_jobs = {}
function! s:coverage_handler(job, exit_status, data) abort
if !has_key(s:coverage_handler_jobs, a:job.id)
return
endif
let l:tmpname = s:coverage_handler_jobs[a:job.id]
if a:exit_status == 0
call go#coverage#overlay(l:tmpname)
endif
call delete(l:tmpname)
unlet s:coverage_handler_jobs[a:job.id]
endfunction
function! s:coverage_browser_handler(job, exit_status, data) abort
if !has_key(s:coverage_browser_handler_jobs, a:job.id)
return
endif
let l:tmpname = s:coverage_browser_handler_jobs[a:job.id]
if a:exit_status == 0
let openHTML = 'go tool cover -html='.l:tmpname
call go#tool#ExecuteInDir(openHTML)
endif
call delete(l:tmpname)
unlet s:coverage_browser_handler_jobs[a:job.id]
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,21 @@
if !exists('g:go_decls_mode')
let g:go_decls_mode = ''
endif
function! go#decls#Decls(mode, ...) abort
if g:go_decls_mode == 'ctrlp'
call ctrlp#init(call("ctrlp#decls#cmd", [a:mode] + a:000))
elseif g:go_decls_mode == 'fzf'
call call("fzf#decls#cmd", [a:mode] + a:000)
else
if globpath(&rtp, 'plugin/ctrlp.vim') != ""
call ctrlp#init(call("ctrlp#decls#cmd", [a:mode] + a:000))
elseif globpath(&rtp, 'plugin/fzf.vim') != ""
call call("fzf#decls#cmd", [a:mode] + a:000)
else
call go#util#EchoError("neither ctrlp.vim nor fzf.vim are installed. Please install either one")
end
end
endfunction
" vim: sw=2 ts=2 et

@ -1,111 +1,317 @@
if !exists("g:go_godef_bin") let s:go_stack = []
let g:go_godef_bin = "godef" let s:go_stack_level = 0
endif
if go#vimproc#has_vimproc()
let s:vim_system = get(g:, 'gocomplete#system_function', 'vimproc#system2')
else
let s:vim_system = get(g:, 'gocomplete#system_function', 'system')
endif
fu! s:system(str, ...) function! go#def#Jump(mode) abort
return call(s:vim_system, [a:str] + a:000) let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
endf
" modified and improved version of vim-godef " so guru right now is slow for some people. previously we were using
function! go#def#Jump(...) " godef which also has it's own quirks. But this issue come up so many
if !len(a:000) " times I've decided to support both. By default we still use guru as it
let arg = "-o=" . go#util#OffsetCursor() " covers all edge cases, but now anyone can switch to godef if they wish
else let bin_name = get(g:, 'go_def_mode', 'guru')
let arg = a:1 if bin_name == 'godef'
if &modified
" Write current unsaved buffer to a temp file and use the modified content
let l:tmpname = tempname()
call writefile(go#util#GetLines(), l:tmpname)
let fname = l:tmpname
endif endif
let bin_path = go#path#CheckBinPath(g:go_godef_bin) let bin_path = go#path#CheckBinPath("godef")
if empty(bin_path)
return
endif
let command = printf("%s -f=%s -o=%s -t", go#util#Shellescape(bin_path),
\ go#util#Shellescape(fname), go#util#OffsetCursor())
let out = go#util#System(command)
if exists("l:tmpname")
call delete(l:tmpname)
endif
elseif bin_name == 'guru'
let bin_path = go#path#CheckBinPath("guru")
if empty(bin_path) if empty(bin_path)
return return
endif endif
let old_gopath = $GOPATH let cmd = [bin_path]
let $GOPATH = go#path#Detect() let stdin_content = ""
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') if &modified
let command = bin_path . " -f=" . shellescape(fname) . " -i " . shellescape(arg) let content = join(go#util#GetLines(), "\n")
let stdin_content = fname . "\n" . strlen(content) . "\n" . content
call add(cmd, "-modified")
endif
if exists('g:go_build_tags')
let tags = get(g:, 'go_build_tags')
call extend(cmd, ["-tags", tags])
endif
" get output of godef let fname = fname.':#'.go#util#OffsetCursor()
let out = s:system(command, join(getbufline(bufnr('%'), 1, '$'), go#util#LineEnding())) call extend(cmd, ["definition", fname])
" jump to it if go#util#has_job()
call s:godefJump(out, "") let l:spawn_args = {
let $GOPATH = old_gopath \ 'cmd': cmd,
endfunction \ 'custom_cb': function('s:jump_to_declaration_cb', [a:mode, bin_name]),
\ }
if &modified
let l:spawn_args.input = stdin_content
endif
function! go#def#JumpMode(mode) call go#util#EchoProgress("searching declaration ...")
let arg = "-o=" . go#util#OffsetCursor()
let bin_path = go#path#CheckBinPath(g:go_godef_bin) call s:def_job(spawn_args)
if empty(bin_path)
return return
endif endif
let old_gopath = $GOPATH let command = join(cmd, " ")
let $GOPATH = go#path#Detect() if &modified
let out = go#util#System(command, stdin_content)
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') else
let command = bin_path . " -f=" . shellescape(fname) . " -i " . shellescape(arg) let out = go#util#System(command)
endif
else
call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru]')
return
endif
" get output of godef if go#util#ShellError() != 0
let out = s:system(command, join(getbufline(bufnr('%'), 1, '$'), go#util#LineEnding())) call go#util#EchoError(out)
return
endif
call s:godefJump(out, a:mode) call go#def#jump_to_declaration(out, a:mode, bin_name)
let $GOPATH = old_gopath
endfunction endfunction
function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort
if a:exit_status != 0
return
endif
function! s:getOffset() call go#def#jump_to_declaration(a:data[0], a:mode, a:bin_name)
return "-o=" . go#util#OffsetCursor() call go#util#EchoSuccess(fnamemodify(a:data[0], ":t"))
endfunction endfunction
function! go#def#jump_to_declaration(out, mode, bin_name) abort
let final_out = a:out
if a:bin_name == "godef"
" append the type information to the same line so our we can parse it.
" This makes it compatible with guru output.
let final_out = join(split(a:out, '\n'), ':')
endif
function! s:godefJump(out, mode) " strip line ending
let old_errorformat = &errorformat let out = split(final_out, go#util#LineEnding())[0]
let &errorformat = "%f:%l:%c" if go#util#IsWin()
let parts = split(out, '\(^[a-zA-Z]\)\@<!:')
else
let parts = split(out, ':')
endif
if a:out =~ 'godef: ' let filename = parts[0]
let out = substitute(a:out, go#util#LineEnding() . '$', '', '') let line = parts[1]
echom out 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 else
let parts = split(a:out, ':') let s:go_stack = s:go_stack[0:s:go_stack_level-1]
" parts[0] contains filename endif
let fileName = parts[0]
" increment the stack counter
let s:go_stack_level += 1
" put the error format into location list so we can jump automatically to " push it on to the jumpstack
" it let stack_entry = {'line': line("."), 'col': col("."), 'file': expand('%:p'), 'ident': ident}
lgetexpr a:out call add(s:go_stack, stack_entry)
" needed for restoring back user setting this is because there are two " needed for restoring back user setting this is because there are two
" modes of switchbuf which we need based on the split mode " modes of switchbuf which we need based on the split mode
let old_switchbuf = &switchbuf let old_switchbuf = &switchbuf
if a:mode == "tab" normal! m'
let &switchbuf = "usetab" if filename != fnamemodify(expand("%"), ':p:gs?\\?/?')
" 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'
else
if &modified
let cmd = 'hide edit'
else
let cmd = 'edit'
endif
if bufloaded(fileName) == 0 if a:mode == "tab"
let &switchbuf = "useopen,usetab,newtab"
if bufloaded(filename) == 0
tab split tab split
endif
else else
if a:mode == "split" let cmd = 'sbuf'
endif
elseif a:mode == "split"
split split
elseif a:mode == "vsplit" elseif a:mode == "vsplit"
vsplit vsplit
endif endif
" open the file and jump to line and column
exec cmd fnameescape(fnamemodify(filename, ':.'))
endif
endif endif
call cursor(line, col)
" jump to file now " also align the line to middle of the view
sil ll 1
normal! zz normal! zz
let &switchbuf = old_switchbuf let &switchbuf = old_switchbuf
end
let &errorformat = old_errorformat
endfunction endfunction
function! go#def#SelectStackEntry() abort
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() abort
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(...) abort
let s:go_stack = []
let s:go_stack_level = 0
endfunction
function! go#def#StackPop(...) abort
if len(s:go_stack) == 0
call go#util#EchoError("godef stack empty")
return
endif
if s:go_stack_level == 0
call go#util#EchoError("at bottom of the godef stack")
return
endif
if !len(a:000)
let numPop = 1
else
let numPop = a:1
endif
let newLevel = str2nr(s:go_stack_level) - str2nr(numPop)
call go#def#Stack(newLevel + 1)
endfunction
function! go#def#Stack(...) abort
if len(s:go_stack) == 0
call go#util#EchoError("godef stack empty")
return
endif
if !len(a:000)
" Display interactive stack
call go#def#StackUI()
return
else
let jumpTarget = a:1
endif
if jumpTarget !~ '^\d\+$'
if jumpTarget !~ '^\s*$'
call go#util#EchoError("location must be a number")
endif
return
endif
let jumpTarget = str2nr(jumpTarget) - 1
if jumpTarget >= 0 && jumpTarget < len(s:go_stack)
let s:go_stack_level = jumpTarget
let target = s:go_stack[s:go_stack_level]
" jump
if expand('%:p') != target["file"]
if &modified
exec 'hide edit' target["file"]
else
exec 'edit' target["file"]
endif
endif
call cursor(target["line"], target["col"])
normal! zz
else
call go#util#EchoError("invalid location. Try :GoDefStack to see the list of valid entries")
endif
endfunction
function s:def_job(args) abort
function! s:error_info_cb(job, exit_status, data) closure
" do not print anything during async definition search&jump
endfunction
let a:args.error_info_cb = funcref('s:error_info_cb')
let callbacks = go#job#Spawn(a:args)
let start_options = {
\ 'callback': callbacks.callback,
\ 'exit_cb': callbacks.exit_cb,
\ }
if &modified
let l:tmpname = tempname()
call writefile(split(a:args.input, "\n"), l:tmpname, "b")
let l:start_options.in_io = "file"
let l:start_options.in_name = l:tmpname
endif
call job_start(a:args.cmd, start_options)
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,37 @@
func! Test_jump_to_declaration_guru() abort
try
let l:filename = 'def/jump.go'
let lnum = 5
let col = 6
let l:tmp = gotest#load_fixture(l:filename)
let guru_out = printf("%s:%d:%d: defined here as func main", filename, lnum, col)
call go#def#jump_to_declaration(guru_out, "", 'guru')
call assert_equal(filename, bufname("%"))
call assert_equal(lnum, getcurpos()[1])
call assert_equal(col, getcurpos()[2])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_jump_to_declaration_godef() abort
try
let filename = 'def/jump.go'
let lnum = 5
let col = 6
let l:tmp = gotest#load_fixture(l:filename)
let godef_out = printf("%s:%d:%d\ndefined here as func main", filename, lnum, col)
call go#def#jump_to_declaration(godef_out, "", 'godef')
call assert_equal(filename, bufname("%"))
call assert_equal(lnum, getcurpos()[1])
call assert_equal(col, getcurpos()[2])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
" vim: sw=2 ts=2 et

@ -1,85 +1,57 @@
" Copyright 2011 The Go Authors. All rights reserved. " Copyright 2011 The Go Authors. All rights reserved.
" Use of this source code is governed by a BSD-style " Use of this source code is governed by a BSD-style
" license that can be found in the LICENSE file. " license that can be found in the LICENSE file.
"
" godoc.vim: Vim command to see godoc.
"
"
" Commands:
"
" :GoDoc
"
" Open the relevant Godoc for either the word[s] passed to the command or
" the, by default, the word under the cursor.
"
" Options:
"
" g:go_godoc_commands [default=1]
"
" Flag to indicate whether to enable the commands listed above.
let s:buf_nr = -1 let s:buf_nr = -1
if !exists("g:go_doc_command") if !exists("g:go_doc_command")
let g:go_doc_command = "godoc" let g:go_doc_command = ["godoc"]
endif
function! go#doc#OpenBrowser(...) abort
" check if we have gogetdoc as it gives us more and accurate information.
" Only supported if we have json_decode as it's not worth to parse the plain
" non-json output of gogetdoc
let bin_path = go#path#CheckBinPath('gogetdoc')
if !empty(bin_path) && exists('*json_decode')
let json_out = s:gogetdoc(1)
if go#util#ShellError() != 0
call go#util#EchoError(json_out)
return
endif endif
if !exists("g:go_doc_options") let out = json_decode(json_out)
let g:go_doc_options = "" if type(out) != type({})
call go#util#EchoError("gogetdoc output is malformed")
endif endif
" returns the package and exported name. exported name might be empty. let import = out["import"]
" ie: fmt and Println let name = out["name"]
" ie: github.com/fatih/set and New let decl = out["decl"]
function! s:godocWord(args)
if !executable('godoc')
echohl WarningMsg
echo "godoc command not found."
echo " install with: go get golang.org/x/tools/cmd/godoc"
echohl None
return []
endif
if !len(a:args) let godoc_url = get(g:, 'go_doc_url', 'https://godoc.org')
let oldiskeyword = &iskeyword if godoc_url isnot 'https://godoc.org'
setlocal iskeyword+=. " strip last '/' character if available
let word = expand('<cword>') let last_char = strlen(godoc_url) - 1
let &iskeyword = oldiskeyword if godoc_url[last_char] == '/'
let word = substitute(word, '[^a-zA-Z0-9\\/._~-]', '', 'g') let godoc_url = strpart(godoc_url, 0, last_char)
let words = split(word, '\.\ze[^./]\+$')
else
let words = a:args
endif endif
if !len(words) " custom godoc installations expects it
return [] let godoc_url .= "/pkg"
endif endif
let pkg = words[0] let godoc_url .= "/" . import
if len(words) == 1 if decl !~ "^package"
let exported_name = "" let godoc_url .= "#" . name
else
let exported_name = words[1]
endif endif
let packages = go#tool#Imports() echo godoc_url
if has_key(packages, pkg)
let pkg = packages[pkg]
endif
return [pkg, exported_name]
endfunction
function! s:godocNotFound(content) call go#tool#OpenBrowser(godoc_url)
if len(a:content) == 0 return
return 1
endif endif
return a:content =~# '^.*: no such file or directory\n$'
endfunction
function! go#doc#OpenBrowser(...)
let pkgs = s:godocWord(a:000) let pkgs = s:godocWord(a:000)
if empty(pkgs) if empty(pkgs)
return return
@ -93,52 +65,34 @@ function! go#doc#OpenBrowser(...)
call go#tool#OpenBrowser(godoc_url) call go#tool#OpenBrowser(godoc_url)
endfunction endfunction
function! go#doc#Open(newmode, mode, ...) function! go#doc#Open(newmode, mode, ...) abort
let pkgs = s:godocWord(a:000) " With argument: run "godoc [arg]".
if empty(pkgs) if len(a:000)
if empty(go#path#CheckBinPath(g:go_doc_command[0]))
return return
endif endif
let pkg = pkgs[0] let command = printf("%s %s", go#util#Shelljoin(g:go_doc_command), join(a:000, ' '))
let exported_name = pkgs[1] let out = go#util#System(command)
" Without argument: run gogetdoc on cursor position.
let command = g:go_doc_command . ' ' . g:go_doc_options . ' ' . pkg else
let out = s:gogetdoc(0)
silent! let content = system(command) if out == -1
if v:shell_error || s:godocNotFound(content) return
echo 'No documentation found for "' . pkg . '".'
return -1
endif
call s:GodocView(a:newmode, a:mode, content)
if exported_name == ''
silent! normal! gg
return -1
endif endif
" jump to the specified name
if search('^func ' . exported_name . '(')
silent! normal! zt
return -1
endif endif
if search('^type ' . exported_name) if go#util#ShellError() != 0
silent! normal! zt call go#util#EchoError(out)
return -1 return
endif
if search('^\%(const\|var\|type\|\s\+\) ' . pkg . '\s\+=\s')
silent! normal! zt
return -1
endif endif
" nothing found, jump to top call s:GodocView(a:newmode, a:mode, out)
silent! normal! gg
endfunction endfunction
function! s:GodocView(newposition, position, content) function! s:GodocView(newposition, position, content) abort
" reuse existing buffer window if it exists otherwise create a new one " reuse existing buffer window if it exists otherwise create a new one
let is_visible = bufexists(s:buf_nr) && bufwinnr(s:buf_nr) != -1
if !bufexists(s:buf_nr) if !bufexists(s:buf_nr)
execute a:newposition execute a:newposition
sil file `="[Godoc]"` sil file `="[Godoc]"`
@ -150,6 +104,25 @@ function! s:GodocView(newposition, position, content)
execute bufwinnr(s:buf_nr) . 'wincmd w' execute bufwinnr(s:buf_nr) . 'wincmd w'
endif endif
" if window was not visible then resize it
if !is_visible
if a:position == "split"
" cap window height to 20, but resize it for smaller contents
let max_height = get(g:, "go_doc_max_height", 20)
let content_height = len(split(a:content, "\n"))
if content_height > max_height
exe 'resize ' . max_height
else
exe 'resize ' . content_height
endif
else
" set a sane maximum width for vertical splits. In this case the minimum
" that fits the godoc for package http without extra linebreaks and line
" numbers on
exe 'vertical resize 84'
endif
endif
setlocal filetype=godoc setlocal filetype=godoc
setlocal bufhidden=delete setlocal bufhidden=delete
setlocal buftype=nofile setlocal buftype=nofile
@ -165,7 +138,92 @@ function! s:GodocView(newposition, position, content)
call append(0, split(a:content, "\n")) call append(0, split(a:content, "\n"))
sil $delete _ sil $delete _
setlocal nomodifiable 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
function! s:gogetdoc(json) abort
" check if we have 'gogetdoc' and use it automatically
let bin_path = go#path#CheckBinPath('gogetdoc')
if empty(bin_path)
return -1
endif
let cmd = [go#util#Shellescape(bin_path)]
let offset = go#util#OffsetCursor()
let fname = expand("%:p:gs!\\!/!")
let pos = shellescape(fname.':#'.offset)
let cmd += ["-pos", pos]
if a:json
let cmd += ["-json"]
endif
let command = join(cmd, " ")
if &modified
let command .= " -modified"
let out = go#util#System(command, go#util#archive())
else
let out = go#util#System(command)
endif
return out
endfunction
" returns the package and exported name. exported name might be empty.
" ie: fmt and Println
" ie: github.com/fatih/set and New
function! s:godocWord(args) abort
if !executable('godoc')
let msg = "godoc command not found."
let msg .= " install with: go get golang.org/x/tools/cmd/godoc"
call go#util#EchoWarning(msg)
return []
endif
if !len(a:args)
let oldiskeyword = &iskeyword
setlocal iskeyword+=.
let word = expand('<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) abort
if len(a:content) == 0
return 1
endif
return a:content =~# '^.*: no such file or directory\n$'
endfunction endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -0,0 +1,62 @@
function! go#fillstruct#FillStruct() abort
let l:cmd = ['fillstruct',
\ '-file', bufname(''),
\ '-offset', go#util#OffsetCursor(),
\ '-line', line('.')]
" Read from stdin if modified.
if &modified
call add(l:cmd, '-modified')
let [l:out, l:err] = go#util#Exec(l:cmd, go#util#archive())
else
let [l:out, l:err] = go#util#Exec(l:cmd)
endif
if l:err
call go#util#EchoError(l:out)
return
endif
try
let l:json = json_decode(l:out)
catch
call go#util#EchoError(l:out)
return
endtry
" Output is array:
"[
" {"start": 92, "end": 106, "code": "mail.Address{\n\tName: \"\",\n\tAddress: \"\",\n}"},
" {...second struct...}
" ]
let l:pos = getpos('.')
try
for l:struct in l:json
let l:code = split(l:struct['code'], "\n")
" Add any code before/after the struct.
exe l:struct['start'] . 'go'
let l:code[0] = getline('.')[:col('.')-1] . l:code[0]
exe l:struct['end'] . 'go'
let l:code[len(l:code)-1] .= getline('.')[col('.'):]
" Indent every line except the first one; makes it look nice.
let l:indent = repeat("\t", indent('.') / &tabstop)
for l:i in range(1, len(l:code)-1)
let l:code[l:i] = l:indent . l:code[l:i]
endfor
" Out with the old ...
exe 'normal! ' . l:struct['start'] . 'gov' . l:struct['end'] . 'gox'
" ... in with the new.
call setline('.', l:code[0])
call append('.', l:code[1:])
endfor
finally
call setpos('.', l:pos)
endtry
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,90 @@
func! Test_fillstruct() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import "net/mail"',
\ "var addr = mail.\x1fAddress{}"])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
\ 'var addr = mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}'])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_fillstruct_line() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import "net/mail"',
\ "\x1f" . 'var addr = mail.Address{}'])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
\ 'var addr = mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}'])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_fillstruct_two_line() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ "\x1f" . 'func x() { fmt.Println(mail.Address{}, mail.Address{}) }'])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ 'func x() { fmt.Println(mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}, mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}) }'])
finally
"call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_fillstruct_two_cursor() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ "func x() { fmt.Println(mail.Address{}, mail.Ad\x1fdress{}) }"])
call go#fillstruct#FillStruct()
call gotest#assert_buffer(1, [
\ 'import (',
\ '"fmt"',
\ '"net/mail"',
\ ')',
\ 'func x() { fmt.Println(mail.Address{}, mail.Address{',
\ '\tName: "",',
\ '\tAddress: "",',
\ '}) }'])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
" vim: sw=2 ts=2 et

@ -2,43 +2,21 @@
" Use of this source code is governed by a BSD-style " Use of this source code is governed by a BSD-style
" license that can be found in the LICENSE file. " license that can be found in the LICENSE file.
" "
" fmt.vim: Vim command to format Go files with gofmt. " fmt.vim: Vim command to format Go files with gofmt (and gofmt compatible
" " toorls, such as goimports).
" 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") if !exists("g:go_fmt_command")
let g:go_fmt_command = "gofmt" let g:go_fmt_command = "gofmt"
endif endif
if !exists("g:go_goimports_bin") if !exists('g:go_fmt_options')
let g:go_goimports_bin = "goimports" let g:go_fmt_options = ''
endif endif
if !exists('g:go_fmt_fail_silently') if !exists('g:go_fmt_fail_silently')
let g:go_fmt_fail_silently = 0 let g:go_fmt_fail_silently = 0
endif endif
if !exists('g:go_fmt_options')
let g:go_fmt_options = ''
endif
if !exists("g:go_fmt_experimental") if !exists("g:go_fmt_experimental")
let g:go_fmt_experimental = 0 let g:go_fmt_experimental = 0
endif endif
@ -51,7 +29,7 @@ endif
" it doesn't undo changes and break undo history. If you are here reading " 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 " this and have VimL experience, please look at the function for
" improvements, patches are welcome :) " improvements, patches are welcome :)
function! go#fmt#Format(withGoimport) function! go#fmt#Format(withGoimport) abort
if g:go_fmt_experimental == 1 if g:go_fmt_experimental == 1
" Using winsaveview to save/restore cursor state has the problem of " Using winsaveview to save/restore cursor state has the problem of
" closing folds on save: " closing folds on save:
@ -67,144 +45,224 @@ function! go#fmt#Format(withGoimport)
catch catch
let l:curw = winsaveview() let l:curw = winsaveview()
endtry 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 " 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 " prevent an additional undo jump due to BufWritePre auto command and also
" restore 'redo' history because it's getting being destroyed every " restore 'redo' history because it's getting being destroyed every
" BufWritePre " BufWritePre
let tmpundofile = tempname() let tmpundofile = tempname()
exe 'wundo! ' . tmpundofile exe 'wundo! ' . tmpundofile
else
" Save cursor position and many other things.
let l:curw = winsaveview()
endif endif
" get the command first so we can test it " Write current unsaved buffer to a temp file
let fmt_command = g:go_fmt_command let l:tmpname = tempname() . '.go'
if a:withGoimport == 1 call writefile(go#util#GetLines(), l:tmpname)
let fmt_command = g:go_goimports_bin if go#util#IsWin()
let l:tmpname = tr(l:tmpname, '\', '/')
endif endif
" check if the user has installed command binary. let bin_name = g:go_fmt_command
" For example if it's goimports, let us check if it's installed, if a:withGoimport == 1
" if not the user get's a warning via go#path#CheckBinPath() let bin_name = "goimports"
let bin_path = go#path#CheckBinPath(fmt_command)
if empty(bin_path)
return
endif endif
if fmt_command != "gofmt" let current_col = col('.')
" change GOPATH too, so goimports can pick up the correct library let out = go#fmt#run(bin_name, l:tmpname, expand('%'))
let old_gopath = $GOPATH let diff_offset = len(readfile(l:tmpname)) - line('$')
let $GOPATH = go#path#Detect()
let fmt_command = bin_path if go#util#ShellError() == 0
call go#fmt#update_file(l:tmpname, expand('%'))
elseif g:go_fmt_fail_silently == 0
let errors = s:parse_errors(expand('%'), out)
call s:show_errors(errors)
endif endif
" populate the final command with user based fmt options " We didn't use the temp file, so clean up
let command = fmt_command . ' -w ' call delete(l:tmpname)
if a:withGoimport != 1
let command = command . g:go_fmt_options
endif
if fmt_command == "goimports" if g:go_fmt_experimental == 1
if !exists('b:goimports_vendor_compatible') " restore our undo history
let out = system("goimports --help") silent! exe 'rundo ' . tmpundofile
if out !~ "-srcdir" call delete(tmpundofile)
echohl WarningMsg
echomsg "vim-go: goimports does not support srcdir."
echomsg " update with: :GoUpdateBinaries"
echohl None
else
let b:goimports_vendor_compatible = 1
endif
endif
if exists('b:goimports_vendor_compatible') && b:goimports_vendor_compatible " Restore our cursor/windows positions, folds, etc.
let command = command . '-srcdir ' . fnameescape(expand("%:p:h")) if empty(l:curw)
silent! loadview
else
call winrestview(l:curw)
endif endif
else
" Restore our cursor/windows positions.
call winrestview(l:curw)
endif endif
" execute our command... " be smart and jump to the line the new statement was added/removed
let out = system(command . " " . l:tmpname) call cursor(line('.') + diff_offset, current_col)
if fmt_command != "gofmt" " Syntax highlighting breaks less often.
let $GOPATH = old_gopath syntax sync fromstart
endif endfunction
let l:listtype = "locationlist" " update_file updates the target file with the given formatted source
"if there is no error on the temp file replace the output with the current function! go#fmt#update_file(source, target)
"file (if this fails, we can always check the outputs first line with:
"splitted =~ 'package \w\+')
if v:shell_error == 0
" remove undo point caused via BufWritePre " remove undo point caused via BufWritePre
try | silent undojoin | catch | endtry try | silent undojoin | catch | endtry
" Replace current file with temp file, then reload buffer
let old_fileformat = &fileformat let old_fileformat = &fileformat
call rename(l:tmpname, expand('%')) if exists("*getfperm")
" save file permissions
let original_fperm = getfperm(a:target)
endif
call rename(a:source, a:target)
" restore file permissions
if exists("*setfperm") && original_fperm != ''
call setfperm(a:target , original_fperm)
endif
" reload buffer to reflect latest changes
silent edit! silent edit!
let &fileformat = old_fileformat let &fileformat = old_fileformat
let &syntax = &syntax let &syntax = &syntax
" clean up previous location list, but only if it's due to fmt let l:listtype = go#list#Type("GoFmt")
if exists('b:got_fmt_error') && b:got_fmt_error
let b:got_fmt_error = 0 " the title information was introduced with 7.4-2200
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
if has('patch-7.4.2200')
" clean up previous list
if l:listtype == "quickfix"
let l:list_title = getqflist({'title': 1})
else
let l:list_title = getloclist(0, {'title': 1})
endif
else
" can't check the title, so assume that the list was for go fmt.
let l:list_title = {'title': 'Format'}
endif
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
call go#list#Clean(l:listtype) call go#list#Clean(l:listtype)
call go#list#Window(l:listtype) call go#list#Window(l:listtype)
endif endif
elseif g:go_fmt_fail_silently == 0 endfunction
let splitted = split(out, '\n')
"otherwise get the errors and put them to location list " run runs the gofmt/goimport command for the given source file and returns
" the output of the executed command. Target is the real file to be formatted.
function! go#fmt#run(bin_name, source, target)
let cmd = s:fmt_cmd(a:bin_name, a:source, a:target)
if empty(cmd)
return
endif
let command = join(cmd, " ")
" execute our command...
let out = go#util#System(command)
return out
endfunction
" fmt_cmd returns a dict that contains the command to execute gofmt (or
" goimports). args is dict with
function! s:fmt_cmd(bin_name, source, target)
" check if the user has installed command binary.
" For example if it's goimports, let us check if it's installed,
" if not the user get's a warning via go#path#CheckBinPath()
let bin_path = go#path#CheckBinPath(a:bin_name)
if empty(bin_path)
return []
endif
" start constructing the command
let bin_path = go#util#Shellescape(bin_path)
let cmd = [bin_path]
call add(cmd, "-w")
" add the options for binary (if any). go_fmt_options was by default of type
" string, however to allow customization it's now a dictionary of binary
" name mapping to options.
let opts = g:go_fmt_options
if type(g:go_fmt_options) == type({})
let opts = has_key(g:go_fmt_options, a:bin_name) ? g:go_fmt_options[a:bin_name] : ""
endif
call extend(cmd, split(opts, " "))
if a:bin_name == "goimports"
" lazy check if goimports support `-srcdir`. We should eventually remove
" this in the future
if !exists('b:goimports_vendor_compatible')
let out = go#util#System(bin_path . " --help")
if out !~ "-srcdir"
call go#util#EchoWarning(printf("vim-go: goimports (%s) does not support srcdir. Update with: :GoUpdateBinaries", bin_path))
else
let b:goimports_vendor_compatible = 1
endif
endif
if exists('b:goimports_vendor_compatible') && b:goimports_vendor_compatible
let ssl_save = &shellslash
set noshellslash
" use the filename without the fully qualified name if the tree is
" symlinked into the GOPATH, goimports won't work properly.
call extend(cmd, ["-srcdir", shellescape(a:target)])
let &shellslash = ssl_save
endif
endif
call add(cmd, a:source)
return cmd
endfunction
" parse_errors parses the given errors and returns a list of parsed errors
function! s:parse_errors(filename, content) abort
let splitted = split(a:content, '\n')
" list of errors to be put into location list
let errors = [] let errors = []
for line in splitted for line in splitted
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)') let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
if !empty(tokens) if !empty(tokens)
call add(errors, {"filename": @%, call add(errors,{
\"filename": a:filename,
\"lnum": tokens[2], \"lnum": tokens[2],
\"col": tokens[3], \"col": tokens[3],
\"text": tokens[4]}) \"text": tokens[4],
\ })
endif endif
endfor 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 return errors
call go#list#Window(l:listtype, len(errors)) endfunction
" We didn't use the temp file, so clean up
call delete(l:tmpname)
endif
if g:go_fmt_experimental == 1 " show_errors opens a location list and shows the given errors. If the given
" restore our undo history " errors is empty, it closes the the location list
silent! exe 'rundo ' . tmpundofile function! s:show_errors(errors) abort
call delete(tmpundofile) let l:listtype = go#list#Type("GoFmt")
if !empty(a:errors)
call go#list#Populate(l:listtype, a:errors, 'Format')
echohl Error | echomsg "Gofmt returned error" | echohl None
endif endif
if g:go_fmt_experimental == 1 " this closes the window if there are no errors or it opens
" Restore our cursor/windows positions, folds, etc. " it if there is any
if empty(l:curw) call go#list#Window(l:listtype, len(a:errors))
silent! loadview
else
call winrestview(l:curw)
endif
else
" Restore our cursor/windows positions.
call winrestview(l:curw)
endif
endfunction endfunction
function! go#fmt#ToggleFmtAutoSave() abort
if get(g:, "go_fmt_autosave", 1)
let g:go_fmt_autosave = 0
call go#util#EchoProgress("auto fmt disabled")
return
end
let g:go_fmt_autosave = 1
call go#util#EchoProgress("auto fmt enabled")
endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -0,0 +1,49 @@
func! Test_run_fmt() abort
let actual_file = tempname()
call writefile(readfile("test-fixtures/fmt/hello.go"), actual_file)
let expected = join(readfile("test-fixtures/fmt/hello_golden.go"), "\n")
" run our code
call go#fmt#run("gofmt", actual_file, "test-fixtures/fmt/hello.go")
" this should now contain the formatted code
let actual = join(readfile(actual_file), "\n")
call assert_equal(expected, actual)
endfunc
func! Test_update_file() abort
let expected = join(readfile("test-fixtures/fmt/hello_golden.go"), "\n")
let source_file = tempname()
call writefile(readfile("test-fixtures/fmt/hello_golden.go"), source_file)
let target_file = tempname()
call writefile([""], target_file)
" update_file now
call go#fmt#update_file(source_file, target_file)
" this should now contain the formatted code
let actual = join(readfile(target_file), "\n")
call assert_equal(expected, actual)
endfunc
func! Test_goimports() abort
let $GOPATH = 'test-fixtures/fmt/'
let actual_file = tempname()
call writefile(readfile("test-fixtures/fmt/src/imports/goimports.go"), actual_file)
let expected = join(readfile("test-fixtures/fmt/src/imports/goimports_golden.go"), "\n")
" run our code
call go#fmt#run("goimports", actual_file, "test-fixtures/fmt/src/imports/goimports.go")
" this should now contain the formatted code
let actual = join(readfile(actual_file), "\n")
call assert_equal(expected, actual)
endfunc
" vim: sw=2 ts=2 et

@ -0,0 +1,628 @@
" guru.vim -- Vim integration for the Go guru.
" guru_cmd returns a dict that contains the command to execute guru. args
" is dict with following options:
" mode : guru mode, such as 'implements'
" format : output format, either 'plain' or 'json'
" needs_scope : if 1, adds the current package to the scope
" selected : if 1, means it's a range of selection, otherwise it picks up the
" offset under the cursor
" example output:
" {'cmd' : ['guru', '-json', 'implements', 'demo/demo.go:#66']}
function! s:guru_cmd(args) range abort
let mode = a:args.mode
let format = a:args.format
let needs_scope = a:args.needs_scope
let selected = a:args.selected
let result = {}
let pkg = go#package#ImportPath()
" this is important, check it!
if pkg == -1 && needs_scope
return {'err': "current directory is not inside of a valid GOPATH"}
endif
"return with a warning if the binary doesn't exist
let bin_path = go#path#CheckBinPath("guru")
if empty(bin_path)
return {'err': "bin path not found"}
endif
" start constructing the command
let cmd = [bin_path]
let filename = fnamemodify(expand("%"), ':p:gs?\\?/?')
if &modified
let result.stdin_content = go#util#archive()
call add(cmd, "-modified")
endif
" enable outputting in json format
if format == "json"
call add(cmd, "-json")
endif
" check for any tags
if exists('g:go_build_tags')
let tags = get(g:, 'go_build_tags')
call extend(cmd, ["-tags", tags])
let result.tags = tags
endif
" some modes require scope to be defined (such as callers). For these we
" choose a sensible setting, which is using the current file's package
let scopes = []
if needs_scope
let scopes = [pkg]
endif
" check for any user defined scope setting. users can define the scope,
" in package pattern form. examples:
" golang.org/x/tools/cmd/guru # a single package
" golang.org/x/tools/... # all packages beneath dir
" ... # the entire workspace.
if exists('g:go_guru_scope')
" check that the setting is of type list
if type(get(g:, 'go_guru_scope')) != type([])
return {'err' : "go_guru_scope should of type list"}
endif
let scopes = get(g:, 'go_guru_scope')
endif
" now add the scope to our command if there is any
if !empty(scopes)
" strip trailing slashes for each path in scoped. bug:
" https://github.com/golang/go/issues/14584
let scopes = go#util#StripTrailingSlash(scopes)
" create shell-safe entries of the list
if !go#util#has_job() | let scopes = go#util#Shelllist(scopes) | endif
" guru expect a comma-separated list of patterns, construct it
let l:scope = join(scopes, ",")
let result.scope = l:scope
call extend(cmd, ["-scope", l:scope])
endif
let pos = printf("#%s", go#util#OffsetCursor())
if selected != -1
" means we have a range, get it
let pos1 = go#util#Offset(line("'<"), col("'<"))
let pos2 = go#util#Offset(line("'>"), col("'>"))
let pos = printf("#%s,#%s", pos1, pos2)
endif
let filename .= ':'.pos
call extend(cmd, [mode, filename])
let result.cmd = cmd
return result
endfunction
" sync_guru runs guru in sync mode with the given arguments
function! s:sync_guru(args) abort
let result = s:guru_cmd(a:args)
if has_key(result, 'err')
call go#util#EchoError(result.err)
return -1
endif
if !has_key(a:args, 'disable_progress')
if a:args.needs_scope
call go#util#EchoProgress("analysing with scope ". result.scope .
\ " (see ':help go-guru-scope' if this doesn't work)...")
elseif a:args.mode !=# 'what'
" the query might take time, let us give some feedback
call go#util#EchoProgress("analysing ...")
endif
endif
" run, forrest run!!!
let command = join(result.cmd, " ")
if has_key(result, 'stdin_content')
let out = go#util#System(command, result.stdin_content)
else
let out = go#util#System(command)
endif
if has_key(a:args, 'custom_parse')
call a:args.custom_parse(go#util#ShellError(), out)
else
call s:parse_guru_output(go#util#ShellError(), out, a:args.mode)
endif
return out
endfunc
" async_guru runs guru in async mode with the given arguments
function! s:async_guru(args) abort
let result = s:guru_cmd(a:args)
if has_key(result, 'err')
call go#util#EchoError(result.err)
return
endif
let status_dir = expand('%:p:h')
let statusline_type = printf("%s", a:args.mode)
if !has_key(a:args, 'disable_progress')
if a:args.needs_scope
call go#util#EchoProgress("analysing with scope " . result.scope .
\ " (see ':help go-guru-scope' if this doesn't work)...")
endif
endif
let messages = []
function! s:callback(chan, msg) closure
call add(messages, a:msg)
endfunction
let status = {}
let exitval = 0
function! s:exit_cb(job, exitval) closure
let status = {
\ 'desc': 'last status',
\ 'type': statusline_type,
\ 'state': "finished",
\ }
if a:exitval
let exitval = a:exitval
let status.state = "failed"
endif
call go#statusline#Update(status_dir, status)
endfunction
function! s:close_cb(ch) closure
let out = join(messages, "\n")
if has_key(a:args, 'custom_parse')
call a:args.custom_parse(exitval, out)
else
call s:parse_guru_output(exitval, out, a:args.mode)
endif
endfunction
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ 'close_cb': funcref("s:close_cb"),
\ }
if has_key(result, 'stdin_content')
let l:tmpname = tempname()
call writefile(split(result.stdin_content, "\n"), l:tmpname, "b")
let l:start_options.in_io = "file"
let l:start_options.in_name = l:tmpname
endif
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': statusline_type,
\ 'state': "analysing",
\})
return job_start(result.cmd, start_options)
endfunc
" run_guru runs the given guru argument
function! s:run_guru(args) abort
if go#util#has_job()
let res = s:async_guru(a:args)
else
let res = s:sync_guru(a:args)
endif
return res
endfunction
" Show 'implements' relation for selected package
function! go#guru#Implements(selected) abort
let args = {
\ 'mode': 'implements',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:run_guru(args)
endfunction
" Report the possible constants, global variables, and concrete types that may
" appear in a value of type error
function! go#guru#Whicherrs(selected) abort
let args = {
\ 'mode': 'whicherrs',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
" TODO(arslan): handle empty case for both sync/async
" if empty(out.out)
" call go#util#EchoSuccess("no error variables found. Try to change the scope with :GoGuruScope")
" return
" endif
call s:run_guru(args)
endfunction
" Describe selected syntax: definition, methods, etc
function! go#guru#Describe(selected) abort
let args = {
\ 'mode': 'describe',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:run_guru(args)
endfunction
function! go#guru#DescribeInfo() abort
" json_encode() and friends are introduced with this patch (7.4.1304)
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
" nvim: https://github.com/neovim/neovim/pull/4131
if !exists("*json_decode")
call go#util#EchoError("requires 'json_decode'. Update your Vim/Neovim version.")
return
endif
function! s:info(exit_val, output)
if a:exit_val != 0
return
endif
if a:output[0] !=# '{'
return
endif
if empty(a:output) || type(a:output) != type("")
return
endif
let result = json_decode(a:output)
if type(result) != type({})
call go#util#EchoError(printf("malformed output from guru: %s", a:output))
return
endif
if !has_key(result, 'detail')
" if there is no detail check if there is a description and print it
if has_key(result, "desc")
call go#util#EchoInfo(result["desc"])
return
endif
call go#util#EchoError("detail key is missing. Please open a bug report on vim-go repo.")
return
endif
let detail = result['detail']
let info = ""
" guru gives different information based on the detail mode. Let try to
" extract the most useful information
if detail == "value"
if !has_key(result, 'value')
call go#util#EchoError("value key is missing. Please open a bug report on vim-go repo.")
return
endif
let val = result["value"]
if !has_key(val, 'type')
call go#util#EchoError("type key is missing (value.type). Please open a bug report on vim-go repo.")
return
endif
let info = val["type"]
elseif detail == "type"
if !has_key(result, 'type')
call go#util#EchoError("type key is missing. Please open a bug report on vim-go repo.")
return
endif
let type = result["type"]
if !has_key(type, 'type')
call go#util#EchoError("type key is missing (type.type). Please open a bug report on vim-go repo.")
return
endif
let info = type["type"]
elseif detail == "package"
if !has_key(result, 'package')
call go#util#EchoError("package key is missing. Please open a bug report on vim-go repo.")
return
endif
let package = result["package"]
if !has_key(package, 'path')
call go#util#EchoError("path key is missing (package.path). Please open a bug report on vim-go repo.")
return
endif
let info = printf("package %s", package["path"])
elseif detail == "unknown"
let info = result["desc"]
else
call go#util#EchoError(printf("unknown detail mode found '%s'. Please open a bug report on vim-go repo", detail))
return
endif
call go#util#EchoInfo(info)
endfunction
let args = {
\ 'mode': 'describe',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 0,
\ 'custom_parse': function('s:info'),
\ 'disable_progress': 1,
\ }
call s:run_guru(args)
endfunction
" Show possible targets of selected function call
function! go#guru#Callees(selected) abort
let args = {
\ 'mode': 'callees',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:run_guru(args)
endfunction
" Show possible callers of selected function
function! go#guru#Callers(selected) abort
let args = {
\ 'mode': 'callers',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:run_guru(args)
endfunction
" Show path from callgraph root to selected function
function! go#guru#Callstack(selected) abort
let args = {
\ 'mode': 'callstack',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:run_guru(args)
endfunction
" Show free variables of selection
function! go#guru#Freevars(selected) abort
" Freevars requires a selection
if a:selected == -1
call go#util#EchoError("GoFreevars requires a selection (range) of code")
return
endif
let args = {
\ 'mode': 'freevars',
\ 'format': 'plain',
\ 'selected': 1,
\ 'needs_scope': 0,
\ }
call s:run_guru(args)
endfunction
" Show send/receive corresponding to selected channel op
function! go#guru#ChannelPeers(selected) abort
let args = {
\ 'mode': 'peers',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:run_guru(args)
endfunction
" Show all refs to entity denoted by selected identifier
function! go#guru#Referrers(selected) abort
let args = {
\ 'mode': 'referrers',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 0,
\ }
call s:run_guru(args)
endfunction
function! go#guru#SameIdsTimer() abort
call timer_start(200, function('go#guru#SameIds'), {'repeat': -1})
endfunction
function! go#guru#SameIds() abort
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
if !exists("*matchaddpos")
call go#util#EchoError("GoSameIds requires 'matchaddpos'. Update your Vim/Neovim version.")
return
endif
" json_encode() and friends are introduced with this patch (7.4.1304)
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
" nvim: https://github.com/neovim/neovim/pull/4131
if !exists("*json_decode")
call go#util#EchoError("GoSameIds requires 'json_decode'. Update your Vim/Neovim version.")
return
endif
let args = {
\ 'mode': 'what',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 0,
\ 'custom_parse': function('s:same_ids_highlight'),
\ }
call s:run_guru(args)
endfunction
function! s:same_ids_highlight(exit_val, output) abort
call go#guru#ClearSameIds() " run after calling guru to reduce flicker.
if a:output[0] !=# '{'
if !get(g:, 'go_auto_sameids', 0)
call go#util#EchoError(a:output)
endif
return
endif
let result = json_decode(a:output)
if type(result) != type({}) && !get(g:, 'go_auto_sameids', 0)
call go#util#EchoError("malformed output from guru")
return
endif
if !has_key(result, 'sameids')
if !get(g:, 'go_auto_sameids', 0)
call go#util#EchoError("no same_ids founds for the given identifier")
endif
return
endif
let poslen = 0
for enclosing in result['enclosing']
if enclosing['desc'] == 'identifier'
let poslen = enclosing['end'] - enclosing['start']
break
endif
endfor
" return when there's no identifier to highlight.
if poslen == 0
return
endif
let same_ids = result['sameids']
" highlight the lines
for item in same_ids
let pos = split(item, ':')
call matchaddpos('goSameId', [[str2nr(pos[-2]), str2nr(pos[-1]), str2nr(poslen)]])
endfor
if get(g:, "go_auto_sameids", 0)
" re-apply SameIds at the current cursor position at the time the buffer
" is redisplayed: e.g. :edit, :GoRename, etc.
augroup vim-go-sameids
autocmd!
autocmd BufWinEnter <buffer> nested call go#guru#SameIds()
augroup end
endif
endfunction
" ClearSameIds returns 0 when it removes goSameId groups and non-zero if no
" goSameId groups are found.
function! go#guru#ClearSameIds() abort
let l:cleared = 0
let m = getmatches()
for item in m
if item['group'] == 'goSameId'
call matchdelete(item['id'])
let l:cleared = 1
endif
endfor
if !l:cleared
return 1
endif
" remove the autocmds we defined
augroup vim-go-sameids
autocmd!
augroup end
return 0
endfunction
function! go#guru#ToggleSameIds() abort
if go#guru#ClearSameIds() != 0
call go#guru#SameIds()
endif
endfunction
function! go#guru#AutoToogleSameIds() abort
if get(g:, "go_auto_sameids", 0)
call go#util#EchoProgress("sameids auto highlighting disabled")
call go#guru#ClearSameIds()
let g:go_auto_sameids = 0
return
endif
call go#util#EchoSuccess("sameids auto highlighting enabled")
let g:go_auto_sameids = 1
endfunction
""""""""""""""""""""""""""""""""""""""""
"" HELPER FUNCTIONS
""""""""""""""""""""""""""""""""""""""""
" This uses Vim's errorformat to parse the output from Guru's 'plain output
" and put it into location list. I believe using errorformat is much more
" easier to use. If we need more power we can always switch back to parse it
" via regex. Match two possible styles of errorformats:
"
" 'file:line.col-line2.col2: message'
" 'file:line:col: message'
"
" We discard line2 and col2 for the first errorformat, because it's not
" useful and location only has the ability to show one line and column
" number
function! s:parse_guru_output(exit_val, output, title) abort
if a:exit_val
call go#util#EchoError(a:output)
return
endif
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
let l:listtype = go#list#Type("_guru")
call go#list#ParseFormat(l:listtype, errformat, a:output, a:title)
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
endfun
function! go#guru#Scope(...) abort
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_guru_scope
call go#util#EchoSuccess("guru scope is cleared")
else
let g:go_guru_scope = a:000
call go#util#EchoSuccess("guru scope changed to: ". join(a:000, ","))
endif
return
endif
if !exists('g:go_guru_scope')
call go#util#EchoError("guru scope is not set")
else
call go#util#EchoSuccess("current guru scope: ". join(g:go_guru_scope, ","))
endif
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,140 @@
function! go#impl#Impl(...) abort
let recv = ""
let iface = ""
let interactive = 0
let pos = getpos('.')
if a:0 is 0
" Interactive mode if user didn't pass any arguments.
let recv = s:getReceiver()
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 is 1
" we assume the user only passed the interface type,
" i.e: ':GoImpl io.Writer'
let recv = s:getReceiver()
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
" Make sure we put the generated code *after* the struct.
if getline(".") =~ "struct "
normal! $%
endif
try
let dirname = fnameescape(expand('%:p:h'))
let [result, err] = go#util#Exec(['impl', '-dir', dirname, recv, iface])
let result = substitute(result, "\n*$", "", "")
if err
call go#util#EchoError(result)
return
endif
if result is# ''
return
end
put =''
silent put =result
finally
call setpos('.', pos)
endtry
endfunction
function! s:getReceiver()
let receiveType = expand("<cword>")
if receiveType == "type"
normal! w
let receiveType = expand("<cword>")
elseif receiveType == "struct"
normal! ge
let receiveType = expand("<cword>")
endif
return printf("%s *%s", tolower(receiveType)[0], receiveType)
endfunction
if exists('*uniq')
function! s:uniq(list)
return uniq(a:list)
endfunction
else
" Note: Believe that the list is sorted
function! s:uniq(list)
let i = len(a:list) - 1
while 0 < i
if a:list[i-1] ==# a:list[i]
call remove(a:list, i)
let i -= 2
else
let i -= 1
endif
endwhile
return a:list
endfunction
endif
function! s:root_dirs() abort
let dirs = []
let root = go#util#env("goroot")
if root !=# '' && isdirectory(root)
call add(dirs, root)
endif
let paths = map(split(go#util#env("gopath"), go#util#PathListSep()), "substitute(v:val, '\\\\', '/', 'g')")
if !empty(filter(paths, 'isdirectory(v:val)'))
call extend(dirs, paths)
endif
return dirs
endfunction
function! s:go_packages(dirs) abort
let pkgs = []
for d in a:dirs
let pkg_root = expand(d . '/pkg/' . go#util#osarch())
call extend(pkgs, split(globpath(pkg_root, '**/*.a', 1), "\n"))
endfor
return map(pkgs, "fnamemodify(v:val, ':t:r')")
endfunction
function! s:interface_list(pkg) abort
let [contents, err] = go#util#Exec(['go', 'doc', a:pkg])
if err
return []
endif
let contents = split(contents, "\n")
call filter(contents, 'v:val =~# ''^type\s\+\h\w*\s\+interface''')
return map(contents, 'a:pkg . "." . matchstr(v:val, ''^type\s\+\zs\h\w*\ze\s\+interface'')')
endfunction
" Complete package and interface for {interface}
function! go#impl#Complete(arglead, cmdline, cursorpos) abort
let words = split(a:cmdline, '\s\+', 1)
if words[-1] ==# ''
return s:uniq(sort(s:go_packages(s:root_dirs())))
elseif words[-1] =~# '^\h\w*$'
return s:uniq(sort(filter(s:go_packages(s:root_dirs()), 'stridx(v:val, words[-1]) == 0')))
elseif words[-1] =~# '^\h\w*\.\%(\h\w*\)\=$'
let [pkg, interface] = split(words[-1], '\.', 1)
echomsg pkg
return s:uniq(sort(filter(s:interface_list(pkg), 'v:val =~? words[-1]')))
else
return []
endif
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,37 @@
func! Test_impl() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ '',
\ ''])
call go#impl#Impl('r', 'reader', 'io.Reader')
call gotest#assert_buffer(1, [
\ 'func (r reader) Read(p []byte) (n int, err error) {',
\ ' panic("not implemented")',
\ '}'])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_impl_get() abort
try
let l:tmp = gotest#write_file('a/a.go', [
\ 'package a',
\ '',
\ 'type reader struct {}'])
call go#impl#Impl('io.Reader')
call gotest#assert_buffer(0, [
\ 'package a',
\ '',
\ 'type reader struct {}',
\ '',
\ 'func (r *reader) Read(p []byte) (n int, err error) {',
\ ' panic("not implemented")',
\ '}'])
finally
call delete(l:tmp, 'rf')
endtry
endfunc

@ -4,7 +4,7 @@
" "
" Check out the docs for more information at /doc/vim-go.txt " Check out the docs for more information at /doc/vim-go.txt
" "
function! go#import#SwitchImport(enabled, localname, path, bang) function! go#import#SwitchImport(enabled, localname, path, bang) abort
let view = winsaveview() let view = winsaveview()
let path = substitute(a:path, '^\s*\(.\{-}\)\s*$', '\1', '') let path = substitute(a:path, '^\s*\(.\{-}\)\s*$', '\1', '')
@ -27,8 +27,8 @@ function! go#import#SwitchImport(enabled, localname, path, bang)
endif endif
if a:bang == "!" if a:bang == "!"
let out = system("go get -u -v ".shellescape(path)) let out = go#util#System("go get -u -v ".shellescape(path))
if v:shell_error if go#util#ShellError() != 0
call s:Error("Can't find import: " . path . ":" . out) call s:Error("Can't find import: " . path . ":" . out)
endif endif
endif endif
@ -205,9 +205,9 @@ function! go#import#SwitchImport(enabled, localname, path, bang)
endfunction endfunction
function! s:Error(s) function! s:Error(s) abort
echohl Error | echo a:s | echohl None echohl Error | echo a:s | echohl None
endfunction endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -0,0 +1,102 @@
" Spawn returns callbacks to be used with job_start. It's abstracted to be
" used with various go command, such as build, test, install, etc.. This avoid
" us to write the same callback over and over for some commands. It's fully
" customizable so each command can change it to it's own logic.
function go#job#Spawn(args)
let cbs = {
\ 'winnr': winnr(),
\ 'dir': getcwd(),
\ 'jobdir': fnameescape(expand("%:p:h")),
\ 'messages': [],
\ 'args': a:args.cmd,
\ 'bang': 0,
\ 'for': "_job",
\ }
if has_key(a:args, 'bang')
let cbs.bang = a:args.bang
endif
if has_key(a:args, 'for')
let cbs.for = a:args.for
endif
" add final callback to be called if async job is finished
" The signature should be in form: func(job, exit_status, messages)
if has_key(a:args, 'custom_cb')
let cbs.custom_cb = a:args.custom_cb
endif
if has_key(a:args, 'error_info_cb')
let cbs.error_info_cb = a:args.error_info_cb
endif
function cbs.callback(chan, msg) dict
call add(self.messages, a:msg)
endfunction
function cbs.exit_cb(job, exitval) dict
if has_key(self, 'error_info_cb')
call self.error_info_cb(a:job, a:exitval, self.messages)
endif
if get(g:, 'go_echo_command_info', 1)
if a:exitval == 0
call go#util#EchoSuccess("SUCCESS")
else
call go#util#EchoError("FAILED")
endif
endif
if has_key(self, 'custom_cb')
call self.custom_cb(a:job, a:exitval, self.messages)
endif
let l:listtype = go#list#Type(self.for)
if a:exitval == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
return
endif
call self.show_errors(l:listtype)
endfunction
function cbs.show_errors(listtype) dict
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
try
execute cd self.jobdir
let errors = go#tool#ParseErrors(self.messages)
let errors = go#tool#FilterValids(errors)
finally
execute cd . fnameescape(self.dir)
endtry
if !len(errors)
" failed to parse errors, output the original content
call go#util#EchoError(self.messages + [self.dir])
return
endif
if self.winnr == winnr()
call go#list#Populate(a:listtype, errors, join(self.args))
call go#list#Window(a:listtype, len(errors))
if !empty(errors) && !self.bang
call go#list#JumpToFirst(a:listtype)
endif
endif
endfunction
" override callback handler if user provided it
if has_key(a:args, 'callback')
let cbs.callback = a:args.callback
endif
" override exit callback handler if user provided it
if has_key(a:args, 'exit_cb')
let cbs.exit_cb = a:args.exit_cb
endif
return cbs
endfunction
" vim: sw=2 ts=2 et

@ -2,62 +2,68 @@
" internal function s:spawn " internal function s:spawn
let s:jobs = {} 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 " 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 " scripts if needed. Desc defines the description for printing the status
" during the job execution (useful for statusline integration). " during the job execution (useful for statusline integration).
function! go#jobcontrol#Spawn(bang, desc, args) function! go#jobcontrol#Spawn(bang, desc, for, args) abort
" autowrite is not enabled for jobs " autowrite is not enabled for jobs
call go#cmd#autowrite() call go#cmd#autowrite()
let job = s:spawn(a:bang, a:desc, a:args) let job = s:spawn(a:bang, a:desc, a:for, a:args)
return job.id return job.id
endfunction endfunction
" Statusline returns the current status of the job " AddHandler adds a on_exit callback handler and returns the id.
function! go#jobcontrol#Statusline() abort function! go#jobcontrol#AddHandler(handler) abort
if empty(s:jobs) let i = len(s:handlers)
return '' while has_key(s:handlers, string(i))
endif let i += 1
break
let import_path = go#package#ImportPath(expand('%:p:h')) endwhile
let s:handlers[string(i)] = a:handler
for job in values(s:jobs) return string(i)
if job.importpath != import_path endfunction
continue
endif
if job.state == "SUCCESS" " RemoveHandler removes a callback handler by id.
return '' function! go#jobcontrol#RemoveHandler(id) abort
endif unlet s:handlers[a:id]
endfunction
return printf("%s ... [%s]", job.desc, job.state) " spawn spawns a go subcommand with the name and arguments with jobstart. Once a
endfor " job is started a reference will be stored inside s:jobs. The job is started
" inside the current files folder.
function! s:spawn(bang, desc, for, args) abort
let status_type = a:args[0]
let status_dir = expand('%:p:h')
let started_at = reltime()
return '' call go#statusline#Update(status_dir, {
endfunction \ 'desc': "current status",
\ 'type': status_type,
\ 'state': "started",
\})
" 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 = { let job = {
\ 'desc': a:desc, \ 'desc': a:desc,
\ 'bang': a:bang, \ 'bang': a:bang,
\ 'winnr': winnr(), \ 'winnr': winnr(),
\ 'importpath': go#package#ImportPath(expand('%:p:h')), \ 'importpath': go#package#ImportPath(),
\ 'state': "RUNNING", \ 'state': "RUNNING",
\ 'stderr' : [], \ 'stderr' : [],
\ 'stdout' : [], \ 'stdout' : [],
\ 'on_stdout': function('s:on_stdout'), \ 'on_stdout': function('s:on_stdout'),
\ 'on_stderr': function('s:on_stderr'), \ 'on_stderr': function('s:on_stderr'),
\ 'on_exit' : function('s:on_exit'), \ 'on_exit' : function('s:on_exit'),
\ 'status_type' : status_type,
\ 'status_dir' : status_dir,
\ 'started_at' : started_at,
\ 'for' : a:for,
\ } \ }
" modify GOPATH if needed
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
" execute go build in the files directory " execute go build in the files directory
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
@ -83,9 +89,6 @@ function! s:spawn(bang, desc, args)
execute cd . fnameescape(dir) execute cd . fnameescape(dir)
" restore back GOPATH
let $GOPATH = old_gopath
return job return job
endfunction endfunction
@ -93,29 +96,57 @@ endfunction
" references and also displaying errors in the quickfix window collected by " 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, " on_stderr handler. If there are no errors and a quickfix window is open,
" it'll be closed. " it'll be closed.
function! s:on_exit(job_id, exit_status) function! s:on_exit(job_id, exit_status, event) dict abort
let status = {
\ 'desc': 'last status',
\ 'type': self.status_type,
\ 'state': "success",
\ }
if a:exit_status
let status.state = "failed"
endif
let elapsed_time = reltimestr(reltime(self.started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
call go#statusline#Update(self.status_dir, status)
let std_combined = self.stderr + self.stdout let std_combined = self.stderr + self.stdout
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
execute cd self.dir
call s:callback_handlers_on_exit(s:jobs[a:job_id], a:exit_status, std_combined)
let l:listtype = go#list#Type(self.for)
if a:exit_status == 0 if a:exit_status == 0
call go#list#Clean(0) call go#list#Clean(l:listtype)
call go#list#Window(0) call go#list#Window(l:listtype)
let self.state = "SUCCESS" let self.state = "SUCCESS"
call go#util#EchoSuccess("SUCCESS")
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoSuccess("[" . self.status_type . "] SUCCESS")
endif
execute cd . fnameescape(dir)
return return
endif endif
let self.state = "FAILED" let self.state = "FAILED"
call go#util#EchoError("FAILED")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' if get(g:, 'go_echo_command_info', 1)
let dir = getcwd() call go#util#EchoError("[" . self.status_type . "] FAILED")
try endif
execute cd self.dir
let errors = go#tool#ParseErrors(std_combined) let errors = go#tool#ParseErrors(std_combined)
let errors = go#tool#FilterValids(errors) let errors = go#tool#FilterValids(errors)
finally
execute cd . fnameescape(dir) execute cd . fnameescape(dir)
endtry
if !len(errors) if !len(errors)
" failed to parse errors, output the original content " failed to parse errors, output the original content
@ -125,8 +156,7 @@ function! s:on_exit(job_id, exit_status)
" if we are still in the same windows show the list " if we are still in the same windows show the list
if self.winnr == winnr() if self.winnr == winnr()
let l:listtype = "locationlist" call go#list#Populate(l:listtype, errors, self.desc)
call go#list#Populate(l:listtype, errors)
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !self.bang if !empty(errors) && !self.bang
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
@ -134,46 +164,27 @@ function! s:on_exit(job_id, exit_status)
endif endif
endfunction endfunction
" callback_handlers_on_exit runs all handlers for job on exit event.
function! s:callback_handlers_on_exit(job, exit_status, data) abort
if empty(s:handlers)
return
endif
for s:handler in values(s:handlers)
call s:handler(a:job, a:exit_status, a:data)
endfor
endfunction
" on_stdout is the stdout handler for jobstart(). It collects the output of " on_stdout is the stdout handler for jobstart(). It collects the output of
" stderr and stores them to the jobs internal stdout list. " stderr and stores them to the jobs internal stdout list.
function! s:on_stdout(job_id, data) function! s:on_stdout(job_id, data, event) dict abort
call extend(self.stdout, a:data) call extend(self.stdout, a:data)
endfunction endfunction
" on_stderr is the stderr handler for jobstart(). It collects the output of " on_stderr is the stderr handler for jobstart(). It collects the output of
" stderr and stores them to the jobs internal stderr list. " stderr and stores them to the jobs internal stderr list.
function! s:on_stderr(job_id, data) function! s:on_stderr(job_id, data, event) dict abort
call extend(self.stderr, a:data) call extend(self.stderr, a:data)
endfunction endfunction
" abort_all aborts all current jobs created with s:spawn() " vim: sw=2 ts=2 et
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:ts=2:sw=2:et

@ -0,0 +1,56 @@
function! go#keyify#Keyify()
let bin_path = go#path#CheckBinPath("keyify")
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
if empty(bin_path) || !exists('*json_decode')
return
endif
" Get result of command as json, that contains `start`, `end` and `replacement`
let command = printf("%s -json %s:#%s", go#util#Shellescape(bin_path),
\ go#util#Shellescape(fname), go#util#OffsetCursor())
let output = go#util#System(command)
silent! let result = json_decode(output)
" We want to output the error message in case the result isn't a JSON
if type(result) != type({})
call go#util#EchoError(s:chomp(output))
return
endif
" Because keyify returns the byte before the region we want, we goto the
" byte after that
execute "goto" result.start + 1
let start = getpos('.')
execute "goto" result.end
let end = getpos('.')
let vis_start = getpos("'<")
let vis_end = getpos("'>")
" Replace contents between start and end with `replacement`
call setpos("'<", start)
call setpos("'>", end)
let select = 'gv'
" Make sure the visual mode is 'v', to avoid some bugs
normal! gv
if mode() !=# 'v'
let select .= 'v'
endif
silent! execute "normal!" select."\"=result.replacement\<cr>p"
" Replacement text isn't aligned, so it needs fix
normal! '<v'>=
call setpos("'<", vis_start)
call setpos("'>", vis_end)
endfunction
function! s:chomp(string)
return substitute(a:string, '\n\+$', '', '')
endfunction
" vim: sw=2 ts=2 et

@ -10,8 +10,8 @@ if !exists("g:go_metalinter_enabled")
let g:go_metalinter_enabled = ['vet', 'golint', 'errcheck'] let g:go_metalinter_enabled = ['vet', 'golint', 'errcheck']
endif endif
if !exists("g:go_metalinter_deadline") if !exists("g:go_metalinter_excludes")
let g:go_metalinter_deadline = "5s" let g:go_metalinter_excludes = []
endif endif
if !exists("g:go_golint_bin") if !exists("g:go_golint_bin")
@ -24,47 +24,80 @@ endif
function! go#lint#Gometa(autosave, ...) abort function! go#lint#Gometa(autosave, ...) abort
if a:0 == 0 if a:0 == 0
let goargs = expand('%:p:h') let goargs = shellescape(expand('%:p:h'))
else else
let goargs = go#util#Shelljoin(a:000) let goargs = go#util#Shelljoin(a:000)
endif endif
let meta_command = "gometalinter --disable-all"
if a:autosave || empty(g:go_metalinter_command)
let bin_path = go#path#CheckBinPath("gometalinter") let bin_path = go#path#CheckBinPath("gometalinter")
if empty(bin_path) if empty(bin_path)
return return
endif endif
if a:autosave let cmd = [bin_path]
" include only messages for the active buffer let cmd += ["--disable-all"]
let meta_command .= " --include='^" . expand('%:p') . ".*$'"
endif
if a:autosave || empty(g:go_metalinter_command)
" linters " linters
let linters = a:autosave ? g:go_metalinter_autosave_enabled : g:go_metalinter_enabled let linters = a:autosave ? g:go_metalinter_autosave_enabled : g:go_metalinter_enabled
for linter in linters for linter in linters
let meta_command .= " --enable=".linter let cmd += ["--enable=".linter]
endfor
for exclude in g:go_metalinter_excludes
let cmd += ["--exclude=".exclude]
endfor endfor
" deadline " gometalinter has a --tests flag to tell its linters whether to run
let meta_command .= " --deadline=" . g:go_metalinter_deadline " against tests. While not all of its linters respect this flag, for those
" that do, it means if we don't pass --tests, the linter won't run against
" test files. One example of a linter that will not run against tests if
" we do not specify this flag is errcheck.
let cmd += ["--tests"]
" path " path
let meta_command .= " " . goargs let cmd += [expand('%:p:h')]
else else
" the user wants something else, let us use it. " the user wants something else, let us use it.
let meta_command = g:go_metalinter_command let cmd += split(g:go_metalinter_command, " ")
endif
" gometalinter has a default deadline of 5 seconds.
"
" For async mode (s:lint_job), we want to override the default deadline only
" if we have a deadline configured.
"
" For sync mode (go#util#System), always explicitly pass the 5 seconds
" deadline if there is no other deadline configured. If a deadline is
" configured, then use it.
" Call gometalinter asynchronously.
if go#util#has_job() && has('lambda')
let deadline = get(g:, 'go_metalinter_deadline', 0)
if deadline != 0
let cmd += ["--deadline=" . deadline]
endif
call s:lint_job({'cmd': cmd})
return
endif
" We're calling gometalinter synchronously.
let cmd += ["--deadline=" . get(g:, 'go_metalinter_deadline', "5s")]
if a:autosave
" include only messages for the active buffer
let cmd += ["--include='^" . expand('%:p') . ".*$'"]
endif endif
" comment out the following two lines for debugging
" echo meta_command
" return
let out = go#tool#ExecuteInDir(meta_command) let meta_command = join(cmd, " ")
let out = go#util#System(meta_command)
let l:listtype = "quickfix" let l:listtype = go#list#Type("GoMetaLinter")
if v:shell_error == 0 if go#util#ShellError() == 0
redraw | echo redraw | echo
call go#list#Clean(l:listtype) call go#list#Clean(l:listtype)
call go#list#Window(l:listtype) call go#list#Window(l:listtype)
@ -77,7 +110,7 @@ function! go#lint#Gometa(autosave, ...) abort
let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m" let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m"
" Parse and populate our location list " Parse and populate our location list
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n")) call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter')
let errors = go#list#Get(l:listtype) let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
@ -95,20 +128,20 @@ function! go#lint#Golint(...) abort
if empty(bin_path) if empty(bin_path)
return return
endif endif
let bin_path = go#util#Shellescape(bin_path)
if a:0 == 0 if a:0 == 0
let goargs = shellescape(expand('%')) let out = go#util#System(bin_path . " " . go#util#Shellescape(go#package#ImportPath()))
else else
let goargs = go#util#Shelljoin(a:000) let out = go#util#System(bin_path . " " . go#util#Shelljoin(a:000))
endif endif
let out = system(bin_path . " " . goargs)
if empty(out) if empty(out)
echon "vim-go: " | echohl Function | echon "[lint] PASS" | echohl None echon "vim-go: " | echohl Function | echon "[lint] PASS" | echohl None
return return
endif endif
let l:listtype = "quickfix" let l:listtype = go#list#Type("GoLint")
call go#list#Parse(l:listtype, out) call go#list#Parse(l:listtype, out)
let errors = go#list#Get(l:listtype) let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
@ -117,19 +150,19 @@ endfunction
" Vet calls 'go vet' on the current directory. Any warnings are populated in " Vet calls 'go vet' on the current directory. Any warnings are populated in
" the location list " the location list
function! go#lint#Vet(bang, ...) function! go#lint#Vet(bang, ...) abort
call go#cmd#autowrite() call go#cmd#autowrite()
echon "vim-go: " | echohl Identifier | echon "calling vet..." | echohl None echon "vim-go: " | echohl Identifier | echon "calling vet..." | echohl None
if a:0 == 0 if a:0 == 0
let out = go#tool#ExecuteInDir('go vet') let out = go#util#System('go vet ' . go#util#Shellescape(go#package#ImportPath()))
else else
let out = go#tool#ExecuteInDir('go tool vet ' . go#util#Shelljoin(a:000)) let out = go#util#System('go tool vet ' . go#util#Shelljoin(a:000))
endif endif
let l:listtype = "quickfix" let l:listtype = go#list#Type("GoVet")
if v:shell_error if go#util#ShellError() != 0
let errors = go#tool#ParseErrors(split(out, '\n')) let errors = go#tool#ParseErrors(split(out, '\n'))
call go#list#Populate(l:listtype, errors) call go#list#Populate(l:listtype, errors, 'Vet')
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
@ -146,13 +179,13 @@ endfunction
" the location list " the location list
function! go#lint#Errcheck(...) abort function! go#lint#Errcheck(...) abort
if a:0 == 0 if a:0 == 0
let goargs = go#package#ImportPath(expand('%:p:h')) let import_path = go#package#ImportPath()
if goargs == -1 if import_path == -1
echohl Error | echomsg "vim-go: package is not inside GOPATH src" | echohl None echohl Error | echomsg "vim-go: package is not inside GOPATH src" | echohl None
return return
endif endif
else else
let goargs = go#util#Shelljoin(a:000) let import_path = go#util#Shelljoin(a:000)
endif endif
let bin_path = go#path#CheckBinPath(g:go_errcheck_bin) let bin_path = go#path#CheckBinPath(g:go_errcheck_bin)
@ -163,18 +196,17 @@ function! go#lint#Errcheck(...) abort
echon "vim-go: " | echohl Identifier | echon "errcheck analysing ..." | echohl None echon "vim-go: " | echohl Identifier | echon "errcheck analysing ..." | echohl None
redraw redraw
let command = bin_path . ' -abspath ' . goargs let command = go#util#Shellescape(bin_path) . ' -abspath ' . import_path
let out = go#tool#ExecuteInDir(command) let out = go#tool#ExecuteInDir(command)
let l:listtype = "quickfix" let l:listtype = go#list#Type("GoErrCheck")
if v:shell_error if go#util#ShellError() != 0
let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m" let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m"
" Parse and populate our location list " Parse and populate our location list
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n")) call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'Errcheck')
let errors = go#list#Get(l:listtype) let errors = go#list#Get(l:listtype)
if empty(errors) if empty(errors)
echohl Error | echomsg "GoErrCheck returned error" | echohl None echohl Error | echomsg "GoErrCheck returned error" | echohl None
echo out echo out
@ -182,7 +214,8 @@ function! go#lint#Errcheck(...) abort
endif endif
if !empty(errors) if !empty(errors)
call go#list#Populate(l:listtype, errors) echohl Error | echomsg "GoErrCheck found errors" | echohl None
call go#list#Populate(l:listtype, errors, 'Errcheck')
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !empty(errors) if !empty(errors)
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
@ -196,4 +229,101 @@ function! go#lint#Errcheck(...) abort
endfunction endfunction
" vim:ts=4:sw=4:et function! go#lint#ToggleMetaLinterAutoSave() abort
if get(g:, "go_metalinter_autosave", 0)
let g:go_metalinter_autosave = 0
call go#util#EchoProgress("auto metalinter disabled")
return
end
let g:go_metalinter_autosave = 1
call go#util#EchoProgress("auto metalinter enabled")
endfunction
function s:lint_job(args)
let status_dir = expand('%:p:h')
let started_at = reltime()
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': "gometalinter",
\ 'state': "analysing",
\})
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let l:listtype = go#list#Type("GoMetaLinter")
let l:errformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m'
function! s:callback(chan, msg) closure
let old_errorformat = &errorformat
let &errorformat = l:errformat
try
if l:listtype == "locationlist"
lad a:msg
elseif l:listtype == "quickfix"
caddexpr a:msg
endif
finally
let &errorformat = old_errorformat
endtry
" TODO(jinleileiking): give a configure to jump or not
let l:winnr = winnr()
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
exe l:winnr . "wincmd w"
endfunction
function! s:exit_cb(job, exitval) closure
let status = {
\ 'desc': 'last status',
\ 'type': "gometaliner",
\ 'state': "finished",
\ }
if a:exitval
let status.state = "failed"
endif
let elapsed_time = reltimestr(reltime(started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
call go#statusline#Update(status_dir, status)
let errors = go#list#Get(l:listtype)
if empty(errors)
call go#list#Window(l:listtype, len(errors))
elseif has("patch-7.4.2200")
if l:listtype == 'quickfix'
call setqflist([], 'a', {'title': 'GoMetaLinter'})
else
call setloclist(0, [], 'a', {'title': 'GoMetaLinter'})
endif
endif
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoSuccess("linting finished")
endif
endfunction
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ }
call job_start(a:args.cmd, start_options)
call go#list#Clean(l:listtype)
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoProgress("linting started ...")
endif
endfunction
" vim: sw=2 ts=2 et

@ -2,22 +2,30 @@ if !exists("g:go_list_type")
let g:go_list_type = "" let g:go_list_type = ""
endif endif
if !exists("g:go_list_type_commands")
let g:go_list_type_commands = {}
endif
" Window opens the list with the given height up to 10 lines maximum. " 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 " Otherwise g:go_loclist_height is used.
" closes the window "
function! go#list#Window(listtype, ...) " If no or zero height is given it closes the window by default.
let l:listtype = go#list#Type(a:listtype) " To prevent this, set g:go_list_autoclose = 0
function! go#list#Window(listtype, ...) abort
" we don't use lwindow to close the location list as we need also the " 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 " 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 " for a better user experience. If the number of errors in a current
" location list increases/decreases, cwindow will not resize when a new " location list increases/decreases, cwindow will not resize when a new
" updated height is passed. lopen in the other hand resizes the screen. " updated height is passed. lopen in the other hand resizes the screen.
if !a:0 || a:1 == 0 if !a:0 || a:1 == 0
if l:listtype == "locationlist" let autoclose_window = get(g:, 'go_list_autoclose', 1)
if autoclose_window
if a:listtype == "locationlist"
lclose lclose
else else
cclose cclose
endif endif
endif
return return
endif endif
@ -31,7 +39,7 @@ function! go#list#Window(listtype, ...)
endif endif
endif endif
if l:listtype == "locationlist" if a:listtype == "locationlist"
exe 'lopen ' . height exe 'lopen ' . height
else else
exe 'copen ' . height exe 'copen ' . height
@ -39,54 +47,55 @@ function! go#list#Window(listtype, ...)
endfunction endfunction
" Get returns the current list of items from the location list " Get returns the current items from the list
function! go#list#Get(listtype) function! go#list#Get(listtype) abort
let l:listtype = go#list#Type(a:listtype) if a:listtype == "locationlist"
if l:listtype == "locationlist"
return getloclist(0) return getloclist(0)
else else
return getqflist() return getqflist()
endif endif
endfunction endfunction
" Populate populate the location list with the given items " Populate populate the list with the given items
function! go#list#Populate(listtype, items) function! go#list#Populate(listtype, items, title) abort
let l:listtype = go#list#Type(a:listtype) if a:listtype == "locationlist"
if l:listtype == "locationlist"
call setloclist(0, a:items, 'r') call setloclist(0, a:items, 'r')
" The last argument ({what}) is introduced with 7.4.2200:
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
else else
call setqflist(a:items, 'r') call setqflist(a:items, 'r')
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
endif endif
endfunction endfunction
function! go#list#PopulateWin(winnr, items) " Parse parses the given items based on the specified errorformat and
call setloclist(a:winnr, a:items, 'r') " populates the list.
endfunction function! go#list#ParseFormat(listtype, errformat, items, title) abort
" 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 " backup users errorformat, will be restored once we are finished
let old_errorformat = &errorformat let old_errorformat = &errorformat
" parse and populate the location list " parse and populate the location list
let &errorformat = a:errformat let &errorformat = a:errformat
if l:listtype == "locationlist" try
if a:listtype == "locationlist"
lgetexpr a:items lgetexpr a:items
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
else else
cgetexpr a:items cgetexpr a:items
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
endif endif
finally
"restore back "restore back
let &errorformat = old_errorformat let &errorformat = old_errorformat
endtry
endfunction endfunction
" Parse parses the given items based on the global errorformat and " Parse parses the given items based on the global errorformat and
" populates the location list. " populates the list.
function! go#list#Parse(listtype, items) function! go#list#Parse(listtype, items) abort
let l:listtype = go#list#Type(a:listtype) if a:listtype == "locationlist"
if l:listtype == "locationlist"
lgetexpr a:items lgetexpr a:items
else else
cgetexpr a:items cgetexpr a:items
@ -94,9 +103,8 @@ function! go#list#Parse(listtype, items)
endfunction endfunction
" JumpToFirst jumps to the first item in the location list " JumpToFirst jumps to the first item in the location list
function! go#list#JumpToFirst(listtype) function! go#list#JumpToFirst(listtype) abort
let l:listtype = go#list#Type(a:listtype) if a:listtype == "locationlist"
if l:listtype == "locationlist"
ll 1 ll 1
else else
cc 1 cc 1
@ -104,23 +112,58 @@ function! go#list#JumpToFirst(listtype)
endfunction endfunction
" Clean cleans the location list " Clean cleans the location list
function! go#list#Clean(listtype) function! go#list#Clean(listtype) abort
let l:listtype = go#list#Type(a:listtype) if a:listtype == "locationlist"
if l:listtype == "locationlist"
lex [] lex []
else else
cex [] cex []
endif endif
endfunction endfunction
function! go#list#Type(listtype) function! s:listtype(listtype) abort
if g:go_list_type == "locationlist" if g:go_list_type == "locationlist"
return "locationlist" return "locationlist"
elseif g:go_list_type == "quickfix" elseif g:go_list_type == "quickfix"
return "quickfix" return "quickfix"
else endif
return a:listtype return a:listtype
endfunction
" s:default_list_type_commands is the defaults that will be used for each of
" the supported commands (see documentation for g:go_list_type_commands). When
" defining a default, quickfix should be used if the command operates on
" multiple files, while locationlist should be used if the command operates on a
" single file or buffer. Keys that begin with an underscore are not supported
" in g:go_list_type_commands.
let s:default_list_type_commands = {
\ "GoBuild": "quickfix",
\ "GoErrCheck": "quickfix",
\ "GoFmt": "locationlist",
\ "GoGenerate": "quickfix",
\ "GoInstall": "quickfix",
\ "GoLint": "quickfix",
\ "GoMetaLinter": "quickfix",
\ "GoModifyTags": "locationlist",
\ "GoRename": "quickfix",
\ "GoRun": "quickfix",
\ "GoTest": "quickfix",
\ "GoVet": "quickfix",
\ "_guru": "locationlist",
\ "_term": "locationlist",
\ "_job": "locationlist",
\ }
function! go#list#Type(for) abort
let l:listtype = s:listtype(get(s:default_list_type_commands, a:for))
if l:listtype == "0"
call go#util#EchoError(printf(
\ "unknown list type command value found ('%s'). Please open a bug report in the vim-go repo.",
\ a:for))
let l:listtype = "quickfix"
endif endif
return get(g:go_list_type_commands, a:for, l:listtype)
endfunction endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -1,233 +0,0 @@
" oracle.vim -- Vim integration for the Go oracle.
"
" Part of this plugin was taken directly from the oracle repo, however it's
" massively changed for a better integration into vim-go. Thanks Alan Donovan
" for the first iteration based on quickfix! - Fatih Arslan
"
if !exists("g:go_oracle_bin")
let g:go_oracle_bin = "oracle"
endif
" Parses (via regex) Oracle's 'plain' format output and puts them into a
" location list
func! s:loclist(output)
let llist = []
" Parse GNU-style 'file:line.col-line.col: message' format.
let mx = '^\(\a:[\\/][^:]\+\|[^:]\+\):\(\d\+\):\(\d\+\):\(.*\)$'
for line in split(a:output, "\n")
let ml = matchlist(line, mx)
" Ignore non-match lines or warnings
if ml == [] || ml[4] =~ '^ warning:'
continue
endif
let item = {
\ 'filename': ml[1],
\ 'text': ml[4],
\ 'lnum': ml[2],
\ 'col': ml[3],
\}
let bnr = bufnr(fnameescape(ml[1]))
if bnr != -1
let item['bufnr'] = bnr
endif
call add(llist, item)
endfor
call go#list#Populate("locationlist", llist)
call go#list#Window("locationlist", len(llist))
endfun
" This uses Vim's errorformat to parse the output from Oracle'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
func! s:RunOracle(mode, selected, needs_package) range abort
let fname = expand('%:p')
let dname = expand('%:p:h')
let pkg = go#package#ImportPath(dname)
if exists('g:go_oracle_scope')
" let the user defines the scope, must be a space separated string,
" example: 'fmt math net/http'
let scopes = split(get(g:, 'go_oracle_scope'))
elseif a:needs_package || exists('g:go_oracle_include_tests') && pkg != -1
" give import path so it includes all _test.go files too
let scopes = [pkg]
else
" best usable way, only pass the package itself, without the test
" files
let scopes = go#tool#Files()
endif
"return with a warning if the bin doesn't exist
let bin_path = go#path#CheckBinPath(g:go_oracle_bin)
if empty(bin_path)
return
endif
if exists('g:go_oracle_tags')
let tags = get(g:, 'go_oracle_tags')
else
let tags = ""
endif
if a:selected != -1
let pos1 = go#util#Offset(line("'<"), col("'<"))
let pos2 = go#util#Offset(line("'>"), col("'>"))
let cmd = printf('%s -format plain -pos=%s:#%d,#%d -tags=%s %s',
\ bin_path,
\ shellescape(fname), pos1, pos2, tags, a:mode)
else
let pos = go#util#OffsetCursor()
let cmd = printf('%s -format plain -pos=%s:#%d -tags=%s %s',
\ bin_path,
\ shellescape(fname), pos, tags, a:mode)
endif
" strip trailing slashes for each path in scoped. bug:
" https://github.com/golang/go/issues/14584
let scopes = go#util#StripTrailingSlash(scopes)
" now append each scope to the end as Oracle's scope parameter. It can be
" a packages or go files, dependent on the User's own choice. For more
" info check Oracle's User Manual section about scopes:
" https://docs.google.com/document/d/1SLk36YRjjMgKqe490mSRzOPYEDe0Y_WQNRv-EiFYUyw/view#heading=h.nwso96pj07q8
let cmd .= ' ' . go#util#Shelljoin(scopes)
echon "vim-go: " | echohl Identifier | echon "analysing ..." | echohl None
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
let out = system(cmd)
let $GOPATH = old_gopath
if v:shell_error
" unfortunaly oracle outputs a very long stack trace that is not
" parsable to show the real error. But the main issue is usually the
" package which doesn't build.
redraw | echon "vim-go: " | echohl Statement | echon out | echohl None
return ""
endif
return out
endfunc
function! go#oracle#Scope(...)
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_oracle_scope
echon "vim-go: " | echohl Function | echon "oracle scope is cleared"| echohl None
else
let g:go_oracle_scope = join(a:000, ' ')
echon "vim-go: " | echohl Function | echon "oracle scope changed to: '". g:go_oracle_scope ."'" | echohl None
endif
return
endif
if !exists('g:go_oracle_scope')
echon "vim-go: " | echohl Function | echon "oracle scope is not set"| echohl None
else
echon "vim-go: " | echohl Function | echon "current oracle scope: '". g:go_oracle_scope ."'" | echohl None
endif
endfunction
function! go#oracle#Tags(...)
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_oracle_tags
echon "vim-go: " | echohl Function | echon "oracle tags is cleared"| echohl None
else
let g:go_oracle_tags = a:1
echon "vim-go: " | echohl Function | echon "oracle tags changed to: '". g:go_oracle_tags ."'" | echohl None
endif
return
endif
if !exists('g:go_oracle_tags')
echon "vim-go: " | echohl Function | echon "oracle tags is not set"| echohl None
else
echon "vim-go: " | echohl Function | echon "current oracle tags: '". g:go_oracle_tags ."'" | echohl None
endif
endfunction
" Show 'implements' relation for selected package
function! go#oracle#Implements(selected)
let out = s:RunOracle('implements', a:selected, 0)
call s:loclistSecond(out)
endfunction
" Describe selected syntax: definition, methods, etc
function! go#oracle#Describe(selected)
let out = s:RunOracle('describe', a:selected, 0)
call s:loclistSecond(out)
endfunction
" Show possible targets of selected function call
function! go#oracle#Callees(selected)
let out = s:RunOracle('callees', a:selected, 1)
call s:loclistSecond(out)
endfunction
" Show possible callers of selected function
function! go#oracle#Callers(selected)
let out = s:RunOracle('callers', a:selected, 1)
call s:loclistSecond(out)
endfunction
" Show path from callgraph root to selected function
function! go#oracle#Callstack(selected)
let out = s:RunOracle('callstack', a:selected, 1)
call s:loclistSecond(out)
endfunction
" Show free variables of selection
function! go#oracle#Freevars(selected)
" Freevars requires a selection
if a:selected == -1
echon "vim-go: " | echohl Statement | echon "GoFreevars requires a selection (range) of code "| echohl None
return
endif
let out = s:RunOracle('freevars', a:selected, 0)
call s:loclistSecond(out)
endfunction
" Show send/receive corresponding to selected channel op
function! go#oracle#ChannelPeers(selected)
let out = s:RunOracle('peers', a:selected, 1)
call s:loclistSecond(out)
endfunction
" Show all refs to entity denoted by selected identifier
function! go#oracle#Referrers(selected)
let out = s:RunOracle('referrers', a:selected, 0)
call s:loclistSecond(out)
endfunction
" vim:ts=4:sw=4:et
"

@ -28,13 +28,13 @@ if len(s:goarch) == 0
endif endif
endif endif
function! go#package#Paths() function! go#package#Paths() abort
let dirs = [] let dirs = []
if !exists("s:goroot") if !exists("s:goroot")
if executable('go') if executable('go')
let s:goroot = substitute(system('go env GOROOT'), '\n', '', 'g') let s:goroot = go#util#env("goroot")
if v:shell_error if go#util#ShellError() != 0
echomsg '''go env GOROOT'' failed' echomsg '''go env GOROOT'' failed'
endif endif
else else
@ -46,7 +46,7 @@ function! go#package#Paths()
let dirs += [s:goroot] let dirs += [s:goroot]
endif endif
let workspaces = split($GOPATH, go#util#PathListSep()) let workspaces = split(go#path#Default(), go#util#PathListSep())
if workspaces != [] if workspaces != []
let dirs += workspaces let dirs += workspaces
endif endif
@ -54,31 +54,33 @@ function! go#package#Paths()
return dirs return dirs
endfunction endfunction
function! go#package#ImportPath(arg) " ImportPath returns the import path in the current directory it was executed
let path = fnamemodify(resolve(a:arg), ':p') function! go#package#ImportPath() abort
let dirs = go#package#Paths() let out = go#tool#ExecuteInDir("go list")
if go#util#ShellError() != 0
for dir in dirs return -1
if len(dir) && match(path, dir) == 0
let workspace = dir
endif endif
endfor
if !exists('workspace') let import_path = split(out, '\n')[0]
" go list returns '_CURRENTDIRECTORY' if the directory is not inside GOPATH.
" Check it and retun an error if that is the case
if import_path[0] ==# '_'
return -1 return -1
endif endif
let srcdir = substitute(workspace . '/src/', '//', '/', '') return import_path
return substitute(path, srcdir, '', '')
endfunction endfunction
function! go#package#FromPath(arg)
function! go#package#FromPath(arg) abort
let path = fnamemodify(resolve(a:arg), ':p') let path = fnamemodify(resolve(a:arg), ':p')
let dirs = go#package#Paths() let dirs = go#package#Paths()
for dir in dirs for dir in dirs
if len(dir) && match(path, dir) == 0 if len(dir) && match(path, dir) == 0
let workspace = dir let workspace = dir
break
endif endif
endfor endfor
@ -86,17 +88,19 @@ function! go#package#FromPath(arg)
return -1 return -1
endif endif
let path = substitute(path, '/*$', '', '')
let workspace = substitute(workspace . '/src/', '/+', '', '')
if isdirectory(path) if isdirectory(path)
return substitute(path, workspace . 'src/', '', '') return substitute(path, workspace, '', '')
else else
return substitute(substitute(path, workspace . 'src/', '', ''), return substitute(substitute(path, workspace, '', ''),
\ '/' . fnamemodify(path, ':t'), '', '') \ '/' . fnamemodify(path, ':t'), '', '')
endif endif
endfunction endfunction
function! go#package#CompleteMembers(package, member) function! go#package#CompleteMembers(package, member) abort
silent! let content = system('godoc ' . a:package) silent! let content = go#util#System('godoc ' . a:package)
if v:shell_error || !len(content) if go#util#ShellError() || !len(content)
return [] return []
endif endif
let lines = filter(split(content, "\n"),"v:val !~ '^\\s\\+$'") let lines = filter(split(content, "\n"),"v:val !~ '^\\s\\+$'")
@ -113,11 +117,11 @@ function! go#package#CompleteMembers(package, member)
endtry endtry
endfunction endfunction
function! go#package#Complete(ArgLead, CmdLine, CursorPos) function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort
let words = split(a:CmdLine, '\s\+', 1) let words = split(a:CmdLine, '\s\+', 1)
" do not complete package members for these commands " do not complete package members for these commands
let neglect_commands = ["GoImportAs", "GoOracleScope"] let neglect_commands = ["GoImportAs", "GoGuruScope"]
if len(words) > 2 && index(neglect_commands, words[0]) == -1 if len(words) > 2 && index(neglect_commands, words[0]) == -1
" Complete package members " Complete package members
@ -157,4 +161,4 @@ function! go#package#Complete(ArgLead, CmdLine, CursorPos)
return sort(keys(ret)) return sort(keys(ret))
endfunction endfunction
" vim:sw=4:et " vim: sw=2 ts=2 et

@ -4,13 +4,18 @@
" :GoPath is used " :GoPath is used
let s:initial_go_path = "" let s:initial_go_path = ""
" GoPath sets or returns the current GOPATH. If no arguments are passed it " GoPath sets or echos the current GOPATH. If no arguments are passed it
" echoes the current GOPATH, if an argument is passed it replaces the current " 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), " 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. " it'll clear the GOPATH and will restore to the initial GOPATH.
function! go#path#GoPath(...) function! go#path#GoPath(...) abort
" no argument, show GOPATH
if len(a:000) == 0
echo go#path#Default()
return
endif
" we have an argument, replace GOPATH " we have an argument, replace GOPATH
if len(a:000)
" clears the current manually set GOPATH and restores it to the " clears the current manually set GOPATH and restores it to the
" initial GOPATH, which was set when Vim was started. " initial GOPATH, which was set when Vim was started.
if len(a:000) == 1 && a:1 == '""' if len(a:000) == 1 && a:1 == '""'
@ -26,29 +31,24 @@ function! go#path#GoPath(...)
echon "vim-go: " | echohl Function | echon "GOPATH changed to ". a:1 | echohl None echon "vim-go: " | echohl Function | echon "GOPATH changed to ". a:1 | echohl None
let s:initial_go_path = $GOPATH let s:initial_go_path = $GOPATH
let $GOPATH = a:1 let $GOPATH = a:1
return
endif
echo go#path#Detect()
endfunction endfunction
" Default returns the default GOPATH. If there is a single GOPATH it returns " Default returns the default GOPATH. If GOPATH is not set, it uses the
" it. For multiple GOPATHS separated with a the OS specific separator, only " default GOPATH set starting with Go 1.8. This GOPATH can be retrieved via
" the first one is returned " 'go env GOPATH'
function! go#path#Default() function! go#path#Default() abort
let go_paths = split($GOPATH, go#util#PathListSep()) if $GOPATH == ""
" use default GOPATH via go env
if len(go_paths) == 1 return go#util#env("gopath")
return $GOPATH
endif endif
return go_paths[0] return $GOPATH
endfunction endfunction
" HasPath checks whether the given path exists in GOPATH environment variable " HasPath checks whether the given path exists in GOPATH environment variable
" or not " or not
function! go#path#HasPath(path) function! go#path#HasPath(path) abort
let go_paths = split($GOPATH, go#util#PathListSep()) let go_paths = split(go#path#Default(), go#util#PathListSep())
let last_char = strlen(a:path) - 1 let last_char = strlen(a:path) - 1
" check cases of '/foo/bar/' and '/foo/bar' " check cases of '/foo/bar/' and '/foo/bar'
@ -69,13 +69,8 @@ endfunction
" Godeps, GB, it will modify the GOPATH so those directories take precedence " Godeps, GB, it will modify the GOPATH so those directories take precedence
" over the current GOPATH. It also detects diretories whose are outside " over the current GOPATH. It also detects diretories whose are outside
" GOPATH. " GOPATH.
function! go#path#Detect() function! go#path#Detect() abort
let gopath = $GOPATH let gopath = go#path#Default()
" don't lookup for godeps if autodetect is disabled.
if !get(g:, "go_autodetect_gopath", 1)
return gopath
endif
let current_dir = fnameescape(expand('%:p:h')) let current_dir = fnameescape(expand('%:p:h'))
@ -83,8 +78,16 @@ function! go#path#Detect()
" fetched from a customizable list. The user should define any new package " fetched from a customizable list. The user should define any new package
" management tool by it's own. " management tool by it's own.
" src folder outside $GOPATH " src folders outside $GOPATH
let src_root = finddir("src", current_dir .";") let src_roots = finddir("src", current_dir .";", -1)
" for cases like GOPATH/src/foo/src/bar, pick up GOPATH/src instead of
" GOPATH/src/foo/src
let src_root = ""
if len(src_roots) > 0
let src_root = src_roots[-1]
endif
if !empty(src_root) if !empty(src_root)
let src_path = fnamemodify(src_root, ':p:h:h') . go#util#PathSep() let src_path = fnamemodify(src_root, ':p:h:h') . go#util#PathSep()
@ -110,24 +113,28 @@ function! go#path#Detect()
endif endif
endif endif
" Fix up the case where initial $GOPATH is empty,
" and we end up with a trailing :
let gopath = substitute(gopath, ":$", "", "")
return gopath return gopath
endfunction endfunction
" BinPath returns the binary path of installed go tools. " BinPath returns the binary path of installed go tools.
function! go#path#BinPath() function! go#path#BinPath() abort
let bin_path = "" let bin_path = ""
" check if our global custom path is set, if not check if $GOBIN is set so " check if our global custom path is set, if not check if $GOBIN is set so
" we can use it, otherwise use $GOPATH + '/bin' " we can use it, otherwise use default GOPATH
if exists("g:go_bin_path") if exists("g:go_bin_path")
let bin_path = g:go_bin_path let bin_path = g:go_bin_path
elseif $GOBIN != "" elseif $GOBIN != ""
let bin_path = $GOBIN let bin_path = $GOBIN
elseif $GOPATH != ""
let bin_path = expand(go#path#Default() . "/bin/")
else else
" could not find anything let go_paths = split(go#path#Default(), go#util#PathListSep())
if len(go_paths) == 0
return "" "nothing found
endif
let bin_path = expand(go_paths[0] . "/bin/")
endif endif
return bin_path return bin_path
@ -135,32 +142,39 @@ endfunction
" CheckBinPath checks whether the given binary exists or not and returns the " CheckBinPath checks whether the given binary exists or not and returns the
" path of the binary. It returns an empty string doesn't exists. " path of the binary. It returns an empty string doesn't exists.
function! go#path#CheckBinPath(binpath) function! go#path#CheckBinPath(binpath) abort
" remove whitespaces if user applied something like 'goimports ' " remove whitespaces if user applied something like 'goimports '
let binpath = substitute(a:binpath, '^\s*\(.\{-}\)\s*$', '\1', '') 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 it's in PATH just return it
if executable(binpath) if executable(binpath)
return binpath if exists('*exepath')
let binpath = exepath(binpath)
endif endif
let $PATH = old_path
" just get the basename if go#util#IsUsingCygwinShell() == 1
let basename = fnamemodify(binpath, ":t") return go#path#CygwinPath(binpath)
" check if we have an appropriate bin_path
let go_bin_path = go#path#BinPath()
if empty(go_bin_path)
echo "vim-go: could not find '" . basename . "'. Run :GoInstallBinaries to fix it."
return ""
endif endif
" append our GOBIN and GOPATH paths and be sure they can be found there... return binpath
" let us search in our GOBIN and GOPATH paths endif
let old_path = $PATH
let $PATH = $PATH . go#util#PathListSep() .go_bin_path
" just get the basename
let basename = fnamemodify(binpath, ":t")
if !executable(basename) if !executable(basename)
echo "vim-go: could not find '" . basename . "'. Run :GoInstallBinaries to fix it." call go#util#EchoError(printf("could not find '%s'. Run :GoInstallBinaries to fix it", basename))
" restore back! " restore back!
let $PATH = old_path let $PATH = old_path
return "" return ""
@ -168,7 +182,15 @@ function! go#path#CheckBinPath(binpath)
let $PATH = old_path let $PATH = old_path
if go#util#IsUsingCygwinShell() == 1
return go#path#CygwinPath(a:binpath)
endif
return go_bin_path . go#util#PathSep() . basename return go_bin_path . go#util#PathSep() . basename
endfunction endfunction
" vim:ts=4:sw=4:et function! go#path#CygwinPath(path)
return substitute(a:path, '\\', '/', "g")
endfunction
" vim: sw=2 ts=2 et

@ -3,7 +3,7 @@ if !exists("g:go_play_open_browser")
endif endif
function! go#play#Share(count, line1, line2) function! go#play#Share(count, line1, line2) abort
if !executable('curl') if !executable('curl')
echohl ErrorMsg | echomsg "vim-go: require 'curl' command" | echohl None echohl ErrorMsg | echomsg "vim-go: require 'curl' command" | echohl None
return return
@ -13,14 +13,14 @@ function! go#play#Share(count, line1, line2)
let share_file = tempname() let share_file = tempname()
call writefile(split(content, "\n"), share_file, "b") call writefile(split(content, "\n"), share_file, "b")
let command = "curl -s -X POST http://play.golang.org/share --data-binary '@".share_file."'" let command = "curl -s -X POST https://play.golang.org/share --data-binary '@".share_file."'"
let snippet_id = system(command) let snippet_id = go#util#System(command)
" we can remove the temp file because it's now posted. " we can remove the temp file because it's now posted.
call delete(share_file) call delete(share_file)
if v:shell_error if go#util#ShellError() != 0
echo 'A error has occured. Run this command to see what the problem is:' echo 'A error has occurred. Run this command to see what the problem is:'
echo command echo command
return return
endif endif
@ -42,7 +42,7 @@ function! go#play#Share(count, line1, line2)
endfunction endfunction
function! s:get_visual_content() function! s:get_visual_content() abort
let save_regcont = @" let save_regcont = @"
let save_regtype = getregtype('"') let save_regtype = getregtype('"')
silent! normal! gvy silent! normal! gvy
@ -55,7 +55,7 @@ endfunction
" http://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript " 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 " another function that returns the content of visual selection, it's not used
" but might be useful in the future " but might be useful in the future
function! s:get_visual_selection() function! s:get_visual_selection() abort
let [lnum1, col1] = getpos("'<")[1:2] let [lnum1, col1] = getpos("'<")[1:2]
let [lnum2, col2] = getpos("'>")[1:2] let [lnum2, col2] = getpos("'>")[1:2]
@ -70,25 +70,4 @@ function! s:get_visual_selection()
return join(lines, "\n") return join(lines, "\n")
endfunction endfunction
" following two functions are from: https://github.com/mattn/gist-vim " vim: sw=2 ts=2 et
" 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') || 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:ts=4:sw=4:et

@ -2,26 +2,34 @@ if !exists("g:go_gorename_bin")
let g:go_gorename_bin = "gorename" let g:go_gorename_bin = "gorename"
endif endif
if !exists("g:go_gorename_prefill") " Set the default value. A value of "1" is a shortcut for this, for
let g:go_gorename_prefill = 1 " compatibility reasons.
function! s:default() abort
if !exists("g:go_gorename_prefill") || g:go_gorename_prefill == 1
let g:go_gorename_prefill = 'expand("<cword>") =~# "^[A-Z]"' .
\ '? go#util#pascalcase(expand("<cword>"))' .
\ ': go#util#camelcase(expand("<cword>"))'
endif endif
endfunction
call s:default()
function! go#rename#Rename(bang, ...) abort
call s:default()
function! go#rename#Rename(bang, ...) let to_identifier = ""
let to = ""
if a:0 == 0 if a:0 == 0
let from = expand("<cword>") let ask = printf("vim-go: rename '%s' to: ", expand("<cword>"))
let ask = printf("vim-go: rename '%s' to: ", from) if g:go_gorename_prefill != ''
if g:go_gorename_prefill let to_identifier = input(ask, eval(g:go_gorename_prefill))
let to = input(ask, from)
else else
let to = input(ask) let to_identifier = input(ask)
endif endif
redraw! redraw!
if empty(to) if empty(to_identifier)
return return
endif endif
else else
let to = a:1 let to_identifier = a:1
endif endif
" return with a warning if the bin doesn't exist " return with a warning if the bin doesn't exist
@ -32,31 +40,106 @@ function! go#rename#Rename(bang, ...)
let fname = expand('%:p') let fname = expand('%:p')
let pos = go#util#OffsetCursor() 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 offset = printf('%s:#%d', fname, pos)
let out = go#tool#ExecuteInDir(cmd) " no need to escape for job call
let bin_path = go#util#has_job() ? bin_path : shellescape(bin_path)
let offset = go#util#has_job() ? offset : shellescape(offset)
let to_identifier = go#util#has_job() ? to_identifier : shellescape(to_identifier)
" strip out newline on the end that gorename puts. If we don't remove, it let cmd = [bin_path, "-offset", offset, "-to", to_identifier]
" will trigger the 'Hit ENTER to continue' prompt
let clean = split(out, '\n') " check for any tags
if exists('g:go_build_tags')
let tags = get(g:, 'go_build_tags')
call extend(cmd, ["-tags", tags])
endif
if go#util#has_job()
call go#util#EchoProgress(printf("renaming to '%s' ...", to_identifier))
call s:rename_job({
\ 'cmd': cmd,
\ 'bang': a:bang,
\})
return
endif
let command = join(cmd, " ")
let out = go#tool#ExecuteInDir(command)
let splitted = split(out, '\n')
call s:parse_errors(go#util#ShellError(), a:bang, splitted)
endfunction
function s:rename_job(args)
let messages = []
function! s:callback(chan, msg) closure
call add(messages, a:msg)
endfunction
let status_dir = expand('%:p:h')
function! s:exit_cb(job, exitval) closure
let status = {
\ 'desc': 'last status',
\ 'type': "gorename",
\ 'state': "finished",
\ }
if a:exitval
let status.state = "failed"
endif
let l:listtype = "quickfix" call go#statusline#Update(status_dir, status)
if v:shell_error
let errors = go#tool#ParseErrors(split(out, '\n')) call s:parse_errors(a:exitval, a:args.bang, messages)
call go#list#Populate(l:listtype, errors) endfunction
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ }
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': "gorename",
\ 'state': "started",
\})
call job_start(a:args.cmd, start_options)
endfunction
function s:parse_errors(exit_val, bang, out)
" reload all files to reflect the new changes. We explicitly call
" checktime to trigger a reload of all files. See
" http://www.mail-archive.com/vim@vim.org/msg05900.html for more info
" about the autoread bug
let current_autoread = &autoread
set autoread
silent! checktime
let &autoread = current_autoread
let l:listtype = go#list#Type("GoRename")
if a:exit_val != 0
call go#util#EchoError("FAILED")
let errors = go#tool#ParseErrors(a:out)
call go#list#Populate(l:listtype, errors, 'Rename')
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
elseif empty(errors) elseif empty(errors)
" failed to parse errors, output the original content " failed to parse errors, output the original content
call go#util#EchoError(out) call go#util#EchoError(a:out)
endif endif
return return
else endif
" strip out newline on the end that gorename puts. If we don't remove, it
" will trigger the 'Hit ENTER to continue' prompt
call go#list#Clean(l:listtype) call go#list#Clean(l:listtype)
call go#list#Window(l:listtype) call go#list#Window(l:listtype)
redraw | echon "vim-go: " | echohl Function | echon clean[0] | echohl None call go#util#EchoSuccess(a:out[0])
endif
" refresh the buffer so we can see the new content " refresh the buffer so we can see the new content
" TODO(arslan): also find all other buffers and refresh them too. For this " TODO(arslan): also find all other buffers and refresh them too. For this
@ -65,5 +148,13 @@ function! go#rename#Rename(bang, ...)
silent execute ":e" silent execute ":e"
endfunction endfunction
" vim:ts=4:sw=4:et " Commandline completion: original, unexported camelCase, and exported
" " CamelCase.
function! go#rename#Complete(lead, cmdline, cursor)
let l:word = expand('<cword>')
return filter(uniq(sort(
\ [l:word, go#util#camelcase(l:word), go#util#pascalcase(l:word)])),
\ 'strpart(v:val, 0, len(a:lead)) == a:lead')
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,112 @@
" Statusline
""""""""""""""""""""""""""""""""
" s:statuses is a global reference to all statuses. It stores the statuses per
" import paths (map[string]status), where each status is unique per its
" type. Current status dict is in form:
" {
" 'desc' : 'Job description',
" 'state' : 'Job state, such as success, failure, etc..',
" 'type' : 'Job type, such as build, test, etc..'
" 'created_at' : 'Time it was created as seconds since 1st Jan 1970'
" }
let s:statuses = {}
" timer_id for cleaner
let s:timer_id = 0
" last_status stores the last generated text per status
let s:last_status = ""
" Show returns the current status of the job for 20 seconds (configurable). It
" displays it in form of 'desc: [type|state]' if there is any state available,
" if not it returns an empty string. This function should be plugged directly
" into the statusline.
function! go#statusline#Show() abort
" lazy initialiation of the cleaner
if !s:timer_id
" clean every 60 seconds all statuses
let interval = get(g:, 'go_statusline_duration', 60000)
let s:timer_id = timer_start(interval, function('go#statusline#Clear'), {'repeat': -1})
endif
" nothing to show
if empty(s:statuses)
return ''
endif
let status_dir = expand('%:p:h')
if !has_key(s:statuses, status_dir)
return ''
endif
let status = s:statuses[status_dir]
if !has_key(status, 'desc') || !has_key(status, 'state') || !has_key(status, 'type')
return ''
endif
let status_text = printf("[%s|%s]", status.type, status.state)
if empty(status_text)
return ''
endif
" only update highlight if status has changed.
if status_text != s:last_status
if status.state =~ "success" || status.state =~ "finished" || status.state =~ "pass"
hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22
elseif status.state =~ "started" || status.state =~ "analysing" || status.state =~ "compiling"
hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88
elseif status.state =~ "failed"
hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52
endif
endif
let s:last_status = status_text
return status_text
endfunction
" Update updates (adds) the statusline for the given status_dir with the
" given status dict. It overrides any previously set status.
function! go#statusline#Update(status_dir, status) abort
let a:status.created_at = reltime()
let s:statuses[a:status_dir] = a:status
" force to update the statusline, otherwise the user needs to move the
" cursor
exe 'let &ro = &ro'
" before we stop the timer, check if we have any previous jobs to be cleaned
" up. Otherwise every job will reset the timer when this function is called
" and thus old jobs will never be cleaned
call go#statusline#Clear(0)
" also reset the timer, so the user has time to see it in the statusline.
" Setting the timer_id to 0 will trigger a new cleaner routine.
call timer_stop(s:timer_id)
let s:timer_id = 0
endfunction
" Clear clears all currently stored statusline data. The timer_id argument is
" just a placeholder so we can pass it to a timer_start() function if needed.
function! go#statusline#Clear(timer_id) abort
for [status_dir, status] in items(s:statuses)
let elapsed_time = reltimestr(reltime(status.created_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
if str2nr(elapsed_time) > 10
call remove(s:statuses, status_dir)
endif
endfor
if len(s:statuses) == 0
let s:statuses = {}
endif
" force to update the statusline, otherwise the user needs to move the
" cursor
exe 'let &ro = &ro'
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,214 @@
" mapped to :GoAddTags
function! go#tags#Add(start, end, count, ...) abort
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
let offset = 0
if a:count == -1
let offset = go#util#OffsetCursor()
endif
let test_mode = 0
call call("go#tags#run", [a:start, a:end, offset, "add", fname, test_mode] + a:000)
endfunction
" mapped to :GoRemoveTags
function! go#tags#Remove(start, end, count, ...) abort
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
let offset = 0
if a:count == -1
let offset = go#util#OffsetCursor()
endif
let test_mode = 0
call call("go#tags#run", [a:start, a:end, offset, "remove", fname, test_mode] + a:000)
endfunction
" run runs gomodifytag. This is an internal test so we can test it
function! go#tags#run(start, end, offset, mode, fname, test_mode, ...) abort
" do not split this into multiple lines, somehow tests fail in that case
let args = {'mode': a:mode,'start': a:start,'end': a:end,'offset': a:offset,'fname': a:fname,'cmd_args': a:000}
if &modified
let args["modified"] = 1
endif
let result = s:create_cmd(args)
if has_key(result, 'err')
call go#util#EchoError(result.err)
return -1
endif
let command = join(result.cmd, " ")
if &modified
let filename = expand("%:p:gs!\\!/!")
let content = join(go#util#GetLines(), "\n")
let in = filename . "\n" . strlen(content) . "\n" . content
let out = go#util#System(command, in)
else
let out = go#util#System(command)
endif
if go#util#ShellError() != 0
call go#util#EchoError(out)
return
endif
if a:test_mode
exe 'edit ' . a:fname
endif
call s:write_out(out)
if a:test_mode
exe 'write! ' . a:fname
endif
endfunc
" write_out writes back the given output to the current buffer
func s:write_out(out) abort
" not a json output
if a:out[0] !=# '{'
return
endif
" nothing to do
if empty(a:out) || type(a:out) != type("")
return
endif
let result = json_decode(a:out)
if type(result) != type({})
call go#util#EchoError(printf("malformed output from gomodifytags: %s", a:out))
return
endif
let lines = result['lines']
let start_line = result['start']
let end_line = result['end']
let index = 0
for line in range(start_line, end_line)
call setline(line, lines[index])
let index += 1
endfor
if has_key(result, 'errors')
let l:winnr = winnr()
let l:listtype = go#list#Type("GoModifyTags")
call go#list#ParseFormat(l:listtype, "%f:%l:%c:%m", result['errors'], "gomodifytags")
call go#list#Window(l:listtype, len(result['errors']))
"prevent jumping to quickfix list
exe l:winnr . "wincmd w"
endif
endfunc
" create_cmd returns a dict that contains the command to execute gomodifytags
func s:create_cmd(args) abort
if !exists("*json_decode")
return {'err': "requires 'json_decode'. Update your Vim/Neovim version."}
endif
let bin_path = go#path#CheckBinPath('gomodifytags')
if empty(bin_path)
return {'err': "gomodifytags does not exist"}
endif
let bin_path = go#util#Shellescape(bin_path)
let l:start = a:args.start
let l:end = a:args.end
let l:offset = a:args.offset
let l:mode = a:args.mode
let l:cmd_args = a:args.cmd_args
let l:modifytags_transform = get(g:, 'go_addtags_transform', "snakecase")
" start constructing the command
let cmd = [bin_path]
call extend(cmd, ["-format", "json"])
call extend(cmd, ["-file", go#util#Shellescape(a:args.fname)])
call extend(cmd, ["-transform", l:modifytags_transform])
if has_key(a:args, "modified")
call add(cmd, "-modified")
endif
if l:offset != 0
call extend(cmd, ["-offset", l:offset])
else
let range = printf("%d,%d", l:start, l:end)
call extend(cmd, ["-line", range])
endif
if l:mode == "add"
let l:tags = []
let l:options = []
if !empty(l:cmd_args)
for item in l:cmd_args
let splitted = split(item, ",")
" tag only
if len(splitted) == 1
call add(l:tags, splitted[0])
endif
" options only
if len(splitted) == 2
call add(l:tags, splitted[0])
call add(l:options, printf("%s=%s", splitted[0], splitted[1]))
endif
endfor
endif
" construct options
if !empty(l:options)
call extend(cmd, ["-add-options", join(l:options, ",")])
else
" default value
if empty(l:tags)
let l:tags = ["json"]
endif
" construct tags
call extend(cmd, ["-add-tags", join(l:tags, ",")])
endif
elseif l:mode == "remove"
if empty(l:cmd_args)
call add(cmd, "-clear-tags")
else
let l:tags = []
let l:options = []
for item in l:cmd_args
let splitted = split(item, ",")
" tag only
if len(splitted) == 1
call add(l:tags, splitted[0])
endif
" options only
if len(splitted) == 2
call add(l:options, printf("%s=%s", splitted[0], splitted[1]))
endif
endfor
" construct tags
if !empty(l:tags)
call extend(cmd, ["-remove-tags", join(l:tags, ",")])
endif
" construct options
if !empty(l:options)
call extend(cmd, ["-remove-options", join(l:options, ",")])
endif
endif
else
return {'err': printf("unknown mode: %s", l:mode)}
endif
return {'cmd': cmd}
endfunc
" vim: sw=2 ts=2 et

@ -0,0 +1,22 @@
func! Test_add_tags() abort
try
let l:tmp = gotest#load_fixture('tags/add_all_input.go')
silent call go#tags#run(0, 0, 40, "add", bufname(''), 1)
call gotest#assert_fixture('tags/add_all_golden.go')
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_remove_tags() abort
try
let l:tmp = gotest#load_fixture('tags/remove_all_input.go')
silent call go#tags#run(0, 0, 40, "remove", bufname(''), 1)
call gotest#assert_fixture('tags/remove_all_golden.go')
finally
call delete(l:tmp, 'rf')
endtry
endfunc
" vim:ts=2:sts=2:sw=2:et

@ -0,0 +1,53 @@
let s:current_file = expand("<sfile>")
function! go#template#create() abort
let l:go_template_use_pkg = get(g:, 'go_template_use_pkg', 0)
let l:root_dir = fnamemodify(s:current_file, ':h:h:h')
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
let l:package_name = -1
if isdirectory(expand('%:p:h'))
execute cd . fnameescape(expand('%:p:h'))
let l:package_name = go#tool#PackageName()
endif
" if we can't figure out any package name(no Go files or non Go package
" files) from the directory create the template or use the cwd
" as the name
if l:package_name == -1 && l:go_template_use_pkg != 1
let l:filename = fnamemodify(expand("%"), ':t')
if l:filename =~ "_test.go$"
let l:template_file = get(g:, 'go_template_test_file', "hello_world_test.go")
else
let l:template_file = get(g:, 'go_template_file', "hello_world.go")
endif
let l:template_path = go#util#Join(l:root_dir, "templates", l:template_file)
silent exe '0r ' . fnameescape(l:template_path)
elseif l:package_name == -1 && l:go_template_use_pkg == 1
" cwd is now the dir of the package
let l:path = fnamemodify(getcwd(), ':t')
let l:content = printf("package %s", l:path)
call append(0, l:content)
else
let l:content = printf("package %s", l:package_name)
call append(0, l:content)
endif
$delete _
execute cd . fnameescape(dir)
endfunction
function! go#template#ToggleAutoCreate() abort
if get(g:, "go_template_autocreate", 1)
let g:go_template_autocreate = 0
call go#util#EchoProgress("auto template create disabled")
return
end
let g:go_template_autocreate = 1
call go#util#EchoProgress("auto template create enabled")
endfunction
" vim: sw=2 ts=2 et

@ -7,22 +7,19 @@ let s:jobs = {}
" new creates a new terminal with the given command. Mode is set based on the " new creates a new terminal with the given command. Mode is set based on the
" global variable g:go_term_mode, which is by default set to :vsplit " global variable g:go_term_mode, which is by default set to :vsplit
function! go#term#new(bang, cmd) function! go#term#new(bang, cmd) abort
return go#term#newmode(a:bang, a:cmd, g:go_term_mode) return go#term#newmode(a:bang, a:cmd, g:go_term_mode)
endfunction endfunction
" new creates a new terminal with the given command and window mode. " new creates a new terminal with the given command and window mode.
function! go#term#newmode(bang, cmd, mode) function! go#term#newmode(bang, cmd, mode) abort
let mode = a:mode let mode = a:mode
if empty(mode) if empty(mode)
let mode = g:go_term_mode let mode = g:go_term_mode
endif endif
" modify GOPATH if needed
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
" execute go build in the files directory " execute go build in the files directory
let l:winnr = winnr()
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd() let dir = getcwd()
@ -49,32 +46,37 @@ function! go#term#newmode(bang, cmd, mode)
execute cd . fnameescape(dir) execute cd . fnameescape(dir)
" restore back GOPATH
let $GOPATH = old_gopath
let job.id = id let job.id = id
let job.cmd = a:cmd
startinsert startinsert
" resize new term if needed. " resize new term if needed.
let height = get(g:, 'go_term_height', winheight(0)) let height = get(g:, 'go_term_height', winheight(0))
let width = get(g:, 'go_term_width', winwidth(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 " we are careful how to resize. for example it's vsplit we don't change
" the height. The below command resizes the buffer " the height. The below command resizes the buffer
if a:mode == "split"
exe 'resize ' . height if mode =~ "vertical" || mode =~ "vsplit" || mode =~ "vnew"
elseif a:mode == "vertical"
exe 'vertical resize ' . width exe 'vertical resize ' . width
elseif mode =~ "split" || mode =~ "new"
exe 'resize ' . height
endif endif
" we also need to resize the pty, so there you go... " we also need to resize the pty, so there you go...
call jobresize(id, width, height) call jobresize(id, width, height)
let s:jobs[id] = job let s:jobs[id] = job
stopinsert
if l:winnr !=# winnr()
exe l:winnr . "wincmd w"
endif
return id return id
endfunction endfunction
function! s:on_stdout(job_id, data) function! s:on_stdout(job_id, data, event) dict abort
if !has_key(s:jobs, a:job_id) if !has_key(s:jobs, a:job_id)
return return
endif endif
@ -83,7 +85,7 @@ function! s:on_stdout(job_id, data)
call extend(job.stdout, a:data) call extend(job.stdout, a:data)
endfunction endfunction
function! s:on_stderr(job_id, data) function! s:on_stderr(job_id, data, event) dict abort
if !has_key(s:jobs, a:job_id) if !has_key(s:jobs, a:job_id)
return return
endif endif
@ -92,37 +94,47 @@ function! s:on_stderr(job_id, data)
call extend(job.stderr, a:data) call extend(job.stderr, a:data)
endfunction endfunction
function! s:on_exit(job_id, data) function! s:on_exit(job_id, exit_status, event) dict abort
if !has_key(s:jobs, a:job_id) if !has_key(s:jobs, a:job_id)
return return
endif endif
let job = s:jobs[a:job_id] let job = s:jobs[a:job_id]
let l:listtype = "locationlist" let l:listtype = go#list#Type("_term")
" usually there is always output so never branch into this clause " usually there is always output so never branch into this clause
if empty(job.stdout) if empty(job.stdout)
call go#list#Clean(l:listtype) call go#list#Clean(l:listtype)
call go#list#Window(l:listtype) call go#list#Window(l:listtype)
else unlet s:jobs[a:job_id]
return
endif
let errors = go#tool#ParseErrors(job.stdout) let errors = go#tool#ParseErrors(job.stdout)
let errors = go#tool#FilterValids(errors) let errors = go#tool#FilterValids(errors)
if !empty(errors) if !empty(errors)
" close terminal we don't need it " close terminal we don't need it anymore
close close
call go#list#Populate(l:listtype, errors) call go#list#Populate(l:listtype, errors, job.cmd)
call go#list#Window(l:listtype, len(errors)) call go#list#Window(l:listtype, len(errors))
if !self.bang if !self.bang
call go#list#JumpToFirst(l:listtype) call go#list#JumpToFirst(l:listtype)
endif endif
else unlet s:jobs[a:job_id]
call go#list#Clean(l:listtype) return
call go#list#Window(l:listtype)
endif endif
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] unlet s:jobs[a:job_id]
endfunction endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

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

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

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

@ -0,0 +1,13 @@
package main
import (
"fmt"
)
func Foo(log *logging.TestLogger) {
log.Debug("vim-go")
}
func main() {
fmt.Println("vim-go")
}

@ -0,0 +1,15 @@
package main
import (
"fmt"
logging "gh.com/gi/foo-logging"
)
func Foo(log *logging.TestLogger) {
log.Debug("vim-go")
}
func main() {
fmt.Println("vim-go")
}

@ -0,0 +1,12 @@
package logging
import "fmt"
type TestLogger struct {
Value string
}
func (l *TestLogger) Debug(msg string) {
fmt.Println(msg)
fmt.Println(l.Value)
}

@ -0,0 +1,16 @@
package main
type Server struct {
Name string `json:"name"`
ID int `json:"id"`
MyHomeAddress string `json:"my_home_address"`
SubDomains []string `json:"sub_domains"`
Empty string `json:"empty"`
Example int64 `json:"example"`
Example2 string `json:"example_2"`
Bar struct {
Four string `json:"four"`
Five string `json:"five"`
} `json:"bar"`
Lala interface{} `json:"lala"`
}

@ -0,0 +1,16 @@
package main
type Server struct {
Name string
ID int
MyHomeAddress string
SubDomains []string
Empty string
Example int64
Example2 string
Bar struct {
Four string
Five string
}
Lala interface{}
}

@ -0,0 +1,16 @@
package main
type Server struct {
Name string
ID int
MyHomeAddress string
SubDomains []string
Empty string
Example int64
Example2 string
Bar struct {
Four string
Five string
}
Lala interface{}
}

@ -0,0 +1,16 @@
package main
type Server struct {
Name string `json:"name"`
ID int `json:"id"`
MyHomeAddress string `json:"my_home_address"`
SubDomains []string `json:"sub_domains"`
Empty string `json:"empty"`
Example int64 `json:"example"`
Example2 string `json:"example_2"`
Bar struct {
Four string `json:"four"`
Five string `json:"five"`
} `json:"bar"`
Lala interface{} `json:"lala"`
}

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

@ -0,0 +1,7 @@
package mock
import "testing"
func Fail(t *testing.T) {
t.Fatal("another package badness")
}

@ -0,0 +1,58 @@
package play
import (
"sync"
"testing"
"play/mock"
)
func TestTopSubHelper(t *testing.T) {
t.Run("sub", func(t *testing.T) {
t.Log("log message")
t.Error("sub badness")
})
t.Error("badness")
helper(t)
}
func TestMultiline(t *testing.T) {
t.Error("this is an error\nand a second line, too")
}
func TestSub(t *testing.T) {
t.Run("indented", func(t *testing.T) {
t.Error("this is a sub-test error\nand a second line, too")
})
}
func TestOK(t *testing.T) {
t.Run("log", func(t *testing.T) {
t.Log("goodness")
})
}
// TestMocked tests behavior similar to what users may experience when using
// github.com/golang/mock/gomock.
func TestMocked(t *testing.T) {
mock.Fail(t)
}
func TestPanic(t *testing.T) {
panic("worst ever")
}
func TestConcurrentPanic(t *testing.T) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
panic("concurrent fail")
wg.Done()
}()
wg.Wait()
}
func helper(t *testing.T) {
t.Helper()
t.Fatal("helper badness")
}

@ -0,0 +1,389 @@
" 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 appended to the final `go test` command.
function! go#test#Test(bang, compile, ...) abort
let args = ["test"]
" don't run the test, only compile it. Useful to capture and fix errors.
if a:compile
let testfile = tempname() . ".vim-go.test"
call extend(args, ["-c", "-o", testfile])
endif
if exists('g:go_build_tags')
let tags = get(g:, 'go_build_tags')
call extend(args, ["-tags", tags])
endif
if a:0
let goargs = a:000
" do not expand for coverage mode as we're passing the arg ourself
if a:1 != '-coverprofile'
" expand all wildcards(i.e: '%' to the current file name)
let goargs = map(copy(a:000), "expand(v:val)")
endif
if !(has('nvim') || go#util#has_job())
let goargs = go#util#Shelllist(goargs, 1)
endif
call extend(args, goargs, 1)
else
" only add this if no custom flags are passed
let timeout = get(g:, 'go_test_timeout', '10s')
call add(args, printf("-timeout=%s", timeout))
endif
if get(g:, 'go_echo_command_info', 1)
if a:compile
call go#util#EchoProgress("compiling tests ...")
else
call go#util#EchoProgress("testing...")
endif
endif
if go#util#has_job()
" use vim's job functionality to call it asynchronously
let job_args = {
\ 'cmd': ['go'] + args,
\ 'bang': a:bang,
\ 'winnr': winnr(),
\ 'dir': getcwd(),
\ 'compile_test': a:compile,
\ 'jobdir': fnameescape(expand("%:p:h")),
\ }
call s:test_job(job_args)
return
elseif has('nvim')
" use nvims's job functionality
if get(g:, 'go_term_enabled', 0)
let id = go#term#new(a:bang, ["go"] + args)
else
let id = go#jobcontrol#Spawn(a:bang, "test", "GoTest", args)
endif
return id
endif
call go#cmd#autowrite()
redraw
let command = "go " . join(args, ' ')
let out = go#tool#ExecuteInDir(command)
" TODO(bc): When the output is JSON, the JSON should be run through a
" filter to produce lines that are more easily described by errorformat.
let l:listtype = go#list#Type("GoTest")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
execute cd fnameescape(expand("%:p:h"))
if go#util#ShellError() != 0
call go#list#ParseFormat(l:listtype, s:errorformat(), split(out, '\n'), command)
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype)
elseif empty(errors)
" failed to parse errors, output the original content
call go#util#EchoError(out)
endif
call go#util#EchoError("[test] FAIL")
else
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
if a:compile
call go#util#EchoSuccess("[test] SUCCESS")
else
call go#util#EchoSuccess("[test] PASS")
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#test#Func(bang, ...) abort
" search flags legend (used only)
" 'b' search backward instead of forward
" 'c' accept a match at the cursor position
" 'n' do Not move the cursor
" 'W' don't wrap around the end of the file
"
" for the full list
" :help search
let test = search('func \(Test\|Example\)', "bcnW")
if test == 0
echo "vim-go: [test] no test found immediate to cursor"
return
end
let line = getline(test)
let name = split(split(line, " ")[1], "(")[0]
let args = [a:bang, 0, "-run", name . "$"]
if a:0
call extend(args, a:000)
endif
call call('go#test#Test', args)
endfunction
function! s:test_job(args) abort
let status_dir = expand('%:p:h')
let started_at = reltime()
let status = {
\ 'desc': 'current status',
\ 'type': "test",
\ 'state': "started",
\ }
if a:args.compile_test
let status.state = "compiling"
endif
call go#statusline#Update(status_dir, status)
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let messages = []
function! s:callback(chan, msg) closure
call add(messages, a:msg)
endfunction
function! s:exit_cb(job, exitval) closure
let status = {
\ 'desc': 'last status',
\ 'type': "test",
\ 'state': "pass",
\ }
if a:args.compile_test
let status.state = "success"
endif
if a:exitval
let status.state = "failed"
endif
if get(g:, 'go_echo_command_info', 1)
if a:exitval == 0
if a:args.compile_test
call go#util#EchoSuccess("[test] SUCCESS")
else
call go#util#EchoSuccess("[test] PASS")
endif
else
call go#util#EchoError("[test] FAIL")
endif
endif
let elapsed_time = reltimestr(reltime(started_at))
" strip whitespace
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
let status.state .= printf(" (%ss)", elapsed_time)
call go#statusline#Update(status_dir, status)
let l:listtype = go#list#Type("GoTest")
if a:exitval == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
return
endif
" TODO(bc): When messages is JSON, the JSON should be run through a
" filter to produce lines that are more easily described by errorformat.
call s:show_errors(a:args, a:exitval, messages)
endfunction
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ }
" pre start
let dir = getcwd()
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let jobdir = fnameescape(expand("%:p:h"))
execute cd . jobdir
call job_start(a:args.cmd, start_options)
" post start
execute cd . fnameescape(dir)
endfunction
" show_errors parses the given list of lines of a 'go test' output and returns
" a quickfix compatible list of errors. It's intended to be used only for go
" test output.
function! s:show_errors(args, exit_val, messages) abort
let l:listtype = go#list#Type("GoTest")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
try
execute cd a:args.jobdir
call go#list#ParseFormat(l:listtype, s:errorformat(), a:messages, join(a:args.cmd))
let errors = go#list#Get(l:listtype)
finally
execute cd . fnameescape(a:args.dir)
endtry
if !len(errors)
" failed to parse errors, output the original content
call go#util#EchoError(a:messages)
call go#util#EchoError(a:args.dir)
return
endif
if a:args.winnr == winnr()
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:args.bang
call go#list#JumpToFirst(l:listtype)
endif
endif
endfunction
let s:efm= ""
function! s:errorformat() abort
" NOTE(arslan): once we get JSON output everything will be easier :).
" TODO(bc): When the output is JSON, the JSON should be run through a
" filter to produce lines that are more easily described by errorformat.
" https://github.com/golang/go/issues/2981.
let goroot = go#util#goroot()
if s:efm != ""
return s:efm
endif
" each level of test indents the test output 4 spaces.
" TODO(bc): figure out how to use 0 or more groups of four spaces for the
" indentation. '%\\( %\\)%#' should work, but doesn't.
let indent = " %#"
" match compiler errors
let format = "%f:%l:%c: %m"
" ignore `go test -v` output for starting tests
let format .= ",%-G=== RUN %.%#"
" ignore `go test -v` output for passing tests
let format .= ",%-G" . indent . "--- PASS: %.%#"
" Match failure lines.
"
" Test failures start with '--- FAIL: ', followed by the test name followed
" by a space the duration of the test in parentheses
"
" e.g.:
" '--- FAIL: TestSomething (0.00s)'
if get(g:, 'go_test_show_name', 0)
let format .= ",%+G" . indent . "--- FAIL: %.%#"
else
let format .= ",%-G" . indent . "--- FAIL: %.%#"
endif
" Matches test output lines.
"
" All test output lines start with the test indentation and a tab, followed
" by the filename, a colon, the line number, another colon, a space, and the
" message. e.g.:
" '\ttime_test.go:30: Likely problem: the time zone files have not been installed.'
let format .= ",%A" . indent . "%\\t%\\+%f:%l: %m"
" Match the 2nd and later lines of multi-line output. These lines are
" indented the number of spaces for the level of nesting of the test,
" followed by two tabs, followed by the message.
"
" Treat these lines as if they are stand-alone lines of output by using %G.
" It would also be valid to treat these lines as if they were the
" continuation of a multi-line error by using %C instead of %G, but that
" would also require that all test errors using a %A or %E modifier to
" indicate that they're multiple lines of output, but in that case the lines
" get concatenated in the quickfix list, which is not what users typically
" want when writing a newline into their test output.
let format .= ",%G" . indent . "%\\t%\\{2}%m"
" set the format for panics.
" In addition to 'panic', check for 'fatal error' to support older versions
" of Go that used 'fatal error'.
"
" Panics come in two flavors. When the goroutine running the tests panics,
" `go test` recovers and tries to exit more cleanly. In that case, the panic
" message is suffixed with ' [recovered]'. If the panic occurs in a
" different goroutine, it will not be suffixed with ' [recovered]'.
let format .= ",%+Afatal error: %.%# [recovered]"
let format .= ",%+Apanic: %.%# [recovered]"
let format .= ",%+Afatal error: %.%#"
let format .= ",%+Apanic: %.%#"
" Match address lines in stacktraces produced by panic.
"
" Address lines in the stack trace have leading tabs, followed by the path
" to the file. The file path is followed by a colon and then the line number
" within the file where the panic occurred. After that there's a space and
" hexadecimal number.
"
" e.g.:
" '\t/usr/local/go/src/time.go:1313 +0x5d'
" panicaddress, and readyaddress are identical except for
" panicaddress sets the filename and line number.
let panicaddress = "%\\t%f:%l +0x%[0-9A-Fa-f]%\\+"
let readyaddress = "%\\t%\\f%\\+:%\\d%\\+ +0x%[0-9A-Fa-f]%\\+"
" stdlib address is identical to readyaddress, except it matches files
" inside GOROOT.
let stdlibaddress = "%\\t" . goroot . "%\\f%\\+:%\\d%\\+ +0x%[0-9A-Fa-f]%\\+"
" Match and ignore the running goroutine line.
let format .= ",%-Cgoroutine %\\d%\\+ [running]:"
" Match address lines that refer to stdlib, but consider them informational
" only. This is to catch the lines after the first address line in the
" running goroutine of a panic stack trace. Ideally, this wouldn't be
" necessary, but when a panic happens in the goroutine running a test, it's
" recovered and another panic is created, so the stack trace actually has
" the line that caused the original panic a couple of addresses down the
" stack.
let format .= ",%-C" . stdlibaddress
" Match address lines in the first matching goroutine. This means the panic
" message will only be shown as the error message in the first address of
" the running goroutine's stack.
let format .= ",%Z" . panicaddress
" Match and ignore panic address without being part of a multi-line message.
" This is to catch those lines that come after the top most non-standard
" library line in stack traces.
let format .= ",%-G" . readyaddress
" Match and ignore exit status lines (produced when go test panics) whether
" part of a multi-line message or not, because these lines sometimes come
" before and sometimes after panic stacktraces.
let format .= ",%-Cexit status %[0-9]%\\+"
"let format .= ",exit status %[0-9]%\\+"
" Match and ignore exit failure lines whether part of a multi-line message
" or not, because these lines sometimes come before and sometimes after
" panic stacktraces.
let format .= ",%-CFAIL%\\t%.%#"
"let format .= ",FAIL%\\t%.%#"
" Match and ignore everything else in multi-line messages.
let format .= ",%-C%.%#"
" Match and ignore everything else not in a multi-line message:
let format .= ",%-G%.%#"
let s:efm = format
return s:efm
endfunction
" vim: sw=2 ts=2 et

@ -0,0 +1,123 @@
func! Test_GoTest() abort
let expected = [
\ {'lnum': 12, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'log message'},
\ {'lnum': 13, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'sub badness'},
\ {'lnum': 15, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'badness'},
\ {'lnum': 16, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'helper badness'},
\ {'lnum': 20, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is an error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 25, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is a sub-test error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 6, 'bufnr': 3, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'another package badness'},
\ {'lnum': 42, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: worst ever [recovered]'}
\ ]
call s:test('play/play_test.go', expected)
endfunc
func! Test_GoTestConcurrentPanic()
let expected = [
\ {'lnum': 49, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: concurrent fail'}
\ ]
call s:test('play/play_test.go', expected, "-run", "TestConcurrentPanic")
endfunc
func! Test_GoTestVerbose() abort
let expected = [
\ {'lnum': 12, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'log message'},
\ {'lnum': 13, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'sub badness'},
\ {'lnum': 15, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'badness'},
\ {'lnum': 16, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'helper badness'},
\ {'lnum': 20, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is an error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 25, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is a sub-test error'},
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'and a second line, too'},
\ {'lnum': 31, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'goodness'},
\ {'lnum': 6, 'bufnr': 3, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'another package badness'},
\ {'lnum': 42, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: worst ever [recovered]'}
\ ]
call s:test('play/play_test.go', expected, "-v")
endfunc
func! Test_GoTestCompilerError() abort
let expected = [
\ {'lnum': 6, 'bufnr': 6, 'col': 22, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'syntax error: unexpected newline, expecting comma or )'}
\ ]
call s:test('compilerror/compilerror_test.go', expected)
endfunc
func! s:test(file, expected, ...) abort
if has('nvim')
" nvim mostly shows test errors correctly, but the the expected errors are
" slightly different; buffer numbers are not the same and stderr doesn't
" seem to be redirected to the job, so the lines from the panic aren't in
" the output to be parsed, and hence are not in the quickfix lists. Once
" those two issues are resolved, this early return should be removed so
" the tests will run for Neovim, too.
return
endif
let $GOPATH = fnameescape(expand("%:p:h")) . '/test-fixtures/test'
silent exe 'e ' . $GOPATH . '/src/' . a:file
" clear the quickfix lists
call setqflist([], 'r')
let args = [1,0]
if a:0
let args += a:000
endif
" run the tests
call call(function('go#test#Test'), args)
let actual = getqflist()
let start = reltime()
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
sleep 100m
let actual = getqflist()
endwhile
" for some reason, when run headless, the quickfix lists includes a line
" that should have been filtered out; remove it manually. The line is not
" present when run manually.
let i = 0
while i < len(actual)
if actual[i].text =~# '^=== RUN .*'
call remove(actual, i)
endif
let i += 1
endwhile
call assert_equal(len(a:expected), len(actual), "number of errors")
if len(a:expected) != len(actual)
return
endif
let i = 0
while i < len(a:expected)
let expected_item = a:expected[i]
let actual_item = actual[i]
let i += 1
call assert_equal(expected_item.bufnr, actual_item.bufnr, "bufnr")
call assert_equal(expected_item.lnum, actual_item.lnum, "lnum")
call assert_equal(expected_item.col, actual_item.col, "col")
call assert_equal(expected_item.vcol, actual_item.vcol, "vcol")
call assert_equal(expected_item.nr, actual_item.nr, "nr")
call assert_equal(expected_item.pattern, actual_item.pattern, "pattern")
let expected_text = s:normalize_durations(expected_item.text)
let actual_text = s:normalize_durations(actual_item.text)
call assert_equal(expected_text, actual_text, "text")
call assert_equal(expected_item.type, actual_item.type, "type")
call assert_equal(expected_item.valid, actual_item.valid, "valid")
endwhile
endfunc
func! s:normalize_durations(str) abort
return substitute(a:str, '[0-9]\+\(\.[0-9]\+\)\?s', '0.000s', 'g')
endfunc
" vim: sw=2 ts=2 et

@ -6,6 +6,10 @@ if !exists("g:go_textobj_include_function_doc")
let g:go_textobj_include_function_doc = 1 let g:go_textobj_include_function_doc = 1
endif endif
if !exists("g:go_textobj_include_variable")
let g:go_textobj_include_variable = 1
endif
" ( ) motions " ( ) motions
" { } motions " { } motions
" s for sentence " s for sentence
@ -13,14 +17,14 @@ endif
" < > " < >
" t for tag " t for tag
function! go#textobj#Function(mode) function! go#textobj#Function(mode) abort
let offset = go#util#OffsetCursor() let offset = go#util#OffsetCursor()
let fname = expand("%:p") let fname = shellescape(expand("%:p"))
if &modified if &modified
" Write current unsaved buffer to a temp file and use the modified content " Write current unsaved buffer to a temp file and use the modified content
let l:tmpname = tempname() let l:tmpname = tempname()
call writefile(getline(1, '$'), l:tmpname) call writefile(go#util#GetLines(), l:tmpname)
let fname = l:tmpname let fname = l:tmpname
endif endif
@ -36,8 +40,8 @@ function! go#textobj#Function(mode)
let command .= " -parse-comments" let command .= " -parse-comments"
endif endif
let out = system(command) let out = go#util#System(command)
if v:shell_error != 0 if go#util#ShellError() != 0
call go#util#EchoError(out) call go#util#EchoError(out)
return return
endif endif
@ -60,6 +64,16 @@ function! go#textobj#Function(mode)
" want's to include doc comments for function declarations " want's to include doc comments for function declarations
if has_key(info, 'doc') && g:go_textobj_include_function_doc if has_key(info, 'doc') && g:go_textobj_include_function_doc
call cursor(info.doc.line, info.doc.col) call cursor(info.doc.line, info.doc.col)
elseif info['sig']['name'] == '' && g:go_textobj_include_variable
" one liner anonymous functions
if info.lbrace.line == info.rbrace.line
" jump to first nonblack char, to get the correct column
call cursor(info.lbrace.line, 0 )
normal! ^
call cursor(info.func.line, col("."))
else
call cursor(info.func.line, info.rbrace.col)
endif
else else
call cursor(info.func.line, info.func.col) call cursor(info.func.line, info.func.col)
endif endif
@ -84,7 +98,7 @@ function! go#textobj#Function(mode)
call cursor(info.rbrace.line-1, 1) call cursor(info.rbrace.line-1, 1)
endfunction endfunction
function! go#textobj#FunctionJump(mode, direction) function! go#textobj#FunctionJump(mode, direction) abort
" get count of the motion. This should be done before all the normal " get count of the motion. This should be done before all the normal
" expressions below as those reset this value(because they have zero " expressions below as those reset this value(because they have zero
" count!). We abstract -1 because the index starts from 0 in motion. " count!). We abstract -1 because the index starts from 0 in motion.
@ -103,11 +117,11 @@ function! go#textobj#FunctionJump(mode, direction)
let offset = go#util#OffsetCursor() let offset = go#util#OffsetCursor()
let fname = expand("%:p") let fname = shellescape(expand("%:p"))
if &modified if &modified
" Write current unsaved buffer to a temp file and use the modified content " Write current unsaved buffer to a temp file and use the modified content
let l:tmpname = tempname() let l:tmpname = tempname()
call writefile(getline(1, '$'), l:tmpname) call writefile(go#util#GetLines(), l:tmpname)
let fname = l:tmpname let fname = l:tmpname
endif endif
@ -129,8 +143,8 @@ function! go#textobj#FunctionJump(mode, direction)
let command .= " -parse-comments" let command .= " -parse-comments"
endif endif
let out = system(command) let out = go#util#System(command)
if v:shell_error != 0 if go#util#ShellError() != 0
call go#util#EchoError(out) call go#util#EchoError(out)
return return
endif endif
@ -177,4 +191,4 @@ function! go#textobj#FunctionJump(mode, direction)
keepjumps call cursor(info.func.line, 1) keepjumps call cursor(info.func.line, 1)
endfunction endfunction
" vim:ts=2:sw=2:et " vim: sw=2 ts=2 et

@ -1,38 +1,72 @@
function! go#tool#Files() " From "go list -h".
function! go#tool#ValidFiles(...)
let l:list = ["GoFiles", "CgoFiles", "IgnoredGoFiles", "CFiles", "CXXFiles",
\ "MFiles", "HFiles", "FFiles", "SFiles", "SwigFiles", "SwigCXXFiles",
\ "SysoFiles", "TestGoFiles", "XTestGoFiles"]
" Used as completion
if len(a:000) > 0
let l:list = filter(l:list, 'strpart(v:val, 0, len(a:1)) == a:1')
endif
return l:list
endfunction
function! go#tool#Files(...) abort
if len(a:000) > 0
let source_files = a:000
else
let source_files = ['GoFiles']
endif
let combined = ''
for sf in source_files
" Strip dot in case people used ":GoFiles .GoFiles".
let sf = substitute(sf, '^\.', '', '')
" Make sure the passed options are valid.
if index(go#tool#ValidFiles(), sf) == -1
echoerr "unknown source file variable: " . sf
endif
if go#util#IsWin() if go#util#IsWin()
let command = 'go list -f "{{range $f := .GoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}"' let combined .= '{{range $f := .' . sf . '}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}'
else else
let command = "go list -f '{{range $f := .GoFiles}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}'" let combined .= "{{range $f := ." . sf . "}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}"
endif endif
let out = go#tool#ExecuteInDir(command) endfor
let out = go#tool#ExecuteInDir('go list -f ' . shellescape(combined))
return split(out, '\n') return split(out, '\n')
endfunction endfunction
function! go#tool#Deps() function! go#tool#Deps() abort
if go#util#IsWin() if go#util#IsWin()
let command = 'go list -f "{{range $f := .Deps}}{{$f}}{{printf \"\n\"}}{{end}}"' let format = '{{range $f := .Deps}}{{$f}}{{printf \"\n\"}}{{end}}'
else else
let command = "go list -f $'{{range $f := .Deps}}{{$f}}\n{{end}}'" let format = "{{range $f := .Deps}}{{$f}}\n{{end}}"
endif endif
let command = 'go list -f '.shellescape(format)
let out = go#tool#ExecuteInDir(command) let out = go#tool#ExecuteInDir(command)
return split(out, '\n') return split(out, '\n')
endfunction endfunction
function! go#tool#Imports() function! go#tool#Imports() abort
let imports = {} let imports = {}
if go#util#IsWin() if go#util#IsWin()
let command = 'go list -f "{{range $f := .Imports}}{{$f}}{{printf \"\n\"}}{{end}}"' let format = '{{range $f := .Imports}}{{$f}}{{printf \"\n\"}}{{end}}'
else else
let command = "go list -f $'{{range $f := .Imports}}{{$f}}\n{{end}}'" let format = "{{range $f := .Imports}}{{$f}}{{printf \"\\n\"}}{{end}}"
endif endif
let command = 'go list -f '.shellescape(format)
let out = go#tool#ExecuteInDir(command) let out = go#tool#ExecuteInDir(command)
if v:shell_error if go#util#ShellError() != 0
echo out echo out
return imports return imports
endif endif
for package_path in split(out, '\n') for package_path in split(out, '\n')
let cmd = "go list -f {{.Name}} " . package_path let cmd = "go list -f '{{.Name}}' " . shellescape(package_path)
let package_name = substitute(go#tool#ExecuteInDir(cmd), '\n$', '', '') let package_name = substitute(go#tool#ExecuteInDir(cmd), '\n$', '', '')
let imports[package_name] = package_path let imports[package_name] = package_path
endfor endfor
@ -40,7 +74,28 @@ function! go#tool#Imports()
return imports return imports
endfunction endfunction
function! go#tool#ParseErrors(lines) function! go#tool#Info(auto) abort
let l:mode = get(g:, 'go_info_mode', 'gocode')
if l:mode == 'gocode'
call go#complete#Info(a:auto)
elseif l:mode == 'guru'
call go#guru#DescribeInfo()
else
call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru]')
endif
endfunction
function! go#tool#PackageName() abort
let command = "go list -f \"{{.Name}}\""
let out = go#tool#ExecuteInDir(command)
if go#util#ShellError() != 0
return -1
endif
return split(out, '\n')[0]
endfunction
function! go#tool#ParseErrors(lines) abort
let errors = [] let errors = []
for line in a:lines for line in a:lines
@ -72,7 +127,7 @@ endfunction
"FilterValids filters the given items with only items that have a valid "FilterValids filters the given items with only items that have a valid
"filename. Any non valid filename is filtered out. "filename. Any non valid filename is filtered out.
function! go#tool#FilterValids(items) function! go#tool#FilterValids(items) abort
" Remove any nonvalid filename from the location list to avoid opening an " Remove any nonvalid filename from the location list to avoid opening an
" empty buffer. See https://github.com/fatih/vim-go/issues/287 for " empty buffer. See https://github.com/fatih/vim-go/issues/287 for
" details. " details.
@ -107,49 +162,57 @@ function! go#tool#FilterValids(items)
endfunction endfunction
function! go#tool#ExecuteInDir(cmd) abort function! go#tool#ExecuteInDir(cmd) abort
let old_gopath = $GOPATH " Verify that the directory actually exists. If the directory does not
let $GOPATH = go#path#Detect() " exist, then assume that the a:cmd should not be executed. Callers expect
" to check v:shell_error (via go#util#ShellError()), so execute a command
" that will return an error as if a:cmd was run and exited with an error.
" This helps avoid errors when working with plugins that use virtual files
" that don't actually exist on the file system (e.g. vim-fugitive's
" GitDiff).
if !isdirectory(expand("%:p:h"))
let [out, err] = go#util#Exec(["false"])
return ''
endif
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd() let dir = getcwd()
try try
execute cd . fnameescape(expand("%:p:h")) execute cd . fnameescape(expand("%:p:h"))
let out = system(a:cmd) let out = go#util#System(a:cmd)
finally finally
execute cd . fnameescape(dir) execute cd . fnameescape(dir)
endtry endtry
let $GOPATH = old_gopath
return out return out
endfunction endfunction
" Exists checks whether the given importpath exists or not. It returns 0 if " Exists checks whether the given importpath exists or not. It returns 0 if
" the importpath exists under GOPATH. " the importpath exists under GOPATH.
function! go#tool#Exists(importpath) function! go#tool#Exists(importpath) abort
let command = "go list ". a:importpath let command = "go list ". a:importpath
let out = go#tool#ExecuteInDir(command) let out = go#tool#ExecuteInDir(command)
if v:shell_error if go#util#ShellError() != 0
return -1 return -1
endif endif
return 0 return 0
endfunction endfunction
" following two functions are from: https://github.com/mattn/gist-vim " following two functions are from: https://github.com/mattn/gist-vim
" thanks @mattn " thanks @mattn
function! s:get_browser_command() function! s:get_browser_command() abort
let go_play_browser_command = get(g:, 'go_play_browser_command', '') let go_play_browser_command = get(g:, 'go_play_browser_command', '')
if go_play_browser_command == '' if go_play_browser_command == ''
if go#util#IsWin() if go#util#IsWin()
let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%' let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
elseif has('mac') || has('macunix') || has('gui_macvim') || system('uname') =~? '^darwin' elseif go#util#IsMac()
let go_play_browser_command = 'open %URL%' let go_play_browser_command = 'open %URL%'
elseif executable('xdg-open') elseif executable('xdg-open')
let go_play_browser_command = 'xdg-open %URL%' let go_play_browser_command = 'xdg-open %URL%'
elseif executable('firefox') elseif executable('firefox')
let go_play_browser_command = 'firefox %URL% &' let go_play_browser_command = 'firefox %URL% &'
elseif executable('chromium')
let go_play_browser_command = 'chromium %URL% &'
else else
let go_play_browser_command = '' let go_play_browser_command = ''
endif endif
@ -157,7 +220,7 @@ function! s:get_browser_command()
return go_play_browser_command return go_play_browser_command
endfunction endfunction
function! go#tool#OpenBrowser(url) function! go#tool#OpenBrowser(url) abort
let cmd = s:get_browser_command() let cmd = s:get_browser_command()
if len(cmd) == 0 if len(cmd) == 0
redraw redraw
@ -168,15 +231,15 @@ function! go#tool#OpenBrowser(url)
return return
endif endif
if cmd =~ '^!' if cmd =~ '^!'
let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g') let cmd = substitute(cmd, '%URL%', '\=escape(shellescape(a:url),"#")', 'g')
silent! exec cmd silent! exec cmd
elseif cmd =~ '^:[A-Z]' elseif cmd =~ '^:[A-Z]'
let cmd = substitute(cmd, '%URL%', '\=a:url', 'g') let cmd = substitute(cmd, '%URL%', '\=escape(a:url,"#")', 'g')
exec cmd exec cmd
else else
let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g') let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g')
call system(cmd) call go#util#System(cmd)
endif endif
endfunction endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -0,0 +1,23 @@
func! Test_ExecuteInDir() abort
let l:tmp = gotest#write_file('a/a.go', ['package a'])
try
let l:out = go#tool#ExecuteInDir("pwd")
call assert_equal(l:tmp . "/src/a\n", l:out)
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func! Test_ExecuteInDir_nodir() abort
let l:tmp = go#util#tempdir("executeindir")
exe ':e ' . l:tmp . '/new-dir/a'
try
let l:out = go#tool#ExecuteInDir("pwd")
call assert_equal('', l:out)
finally
call delete(l:tmp, 'rf')
endtry
endfunc
" vim: sw=2 ts=2 et

@ -1,7 +1,12 @@
let s:buf_nr = -1 let s:buf_nr = -1
"OpenWindow opens a new scratch window and put's the content into the window "OpenWindow opens a new scratch window and put's the content into the window
function! go#ui#OpenWindow(title, content) function! go#ui#OpenWindow(title, content, filetype) abort
" Ensure there's only one return window in this session/tabpage
call go#util#Windo("unlet! w:vim_go_return_window")
" Mark the window we're leaving as such
let w:vim_go_return_window = 1
" reuse existing buffer window if it exists otherwise create a new one " reuse existing buffer window if it exists otherwise create a new one
if !bufexists(s:buf_nr) if !bufexists(s:buf_nr)
execute 'botright new' execute 'botright new'
@ -14,24 +19,21 @@ function! go#ui#OpenWindow(title, content)
execute bufwinnr(s:buf_nr) . 'wincmd w' execute bufwinnr(s:buf_nr) . 'wincmd w'
endif endif
" Resize window to content length
" Keep minimum height to 10, if there is more just increase it that it
" occupies all results
let buffer_height = 10
if len(a:content) < buffer_height
exe 'resize ' . buffer_height
else
exe 'resize' . len(a:content) exe 'resize' . len(a:content)
endif
execute "setlocal filetype=".a:filetype
" some sane default values for a readonly buffer " some sane default values for a readonly buffer
setlocal filetype=vimgo
setlocal bufhidden=delete setlocal bufhidden=delete
setlocal buftype=nofile setlocal buftype=nofile
setlocal noswapfile setlocal noswapfile
setlocal nobuflisted setlocal nobuflisted
setlocal winfixheight setlocal winfixheight
setlocal cursorline " make it easy to distinguish setlocal cursorline " make it easy to distinguish
setlocal nonumber
setlocal norelativenumber
setlocal showbreak=""
" we need this to purge the buffer content " we need this to purge the buffer content
setlocal modifiable setlocal modifiable
@ -47,23 +49,45 @@ function! go#ui#OpenWindow(title, content)
" set it back to non modifiable " set it back to non modifiable
setlocal nomodifiable setlocal nomodifiable
" Remove the '... [New File]' message line from the command line
echon
endfunction endfunction
function! go#ui#GetReturnWindow() abort
for l:wn in range(1, winnr("$"))
if !empty(getwinvar(l:wn, "vim_go_return_window"))
return l:wn
endif
endfor
endfunction
" CloseWindow closes the current window " CloseWindow closes the current window
function! go#ui#CloseWindow() function! go#ui#CloseWindow() abort
close " Close any window associated with the ui buffer, if it's there
echo "" 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 endfunction
" OpenDefinition parses the current line and jumps to it by openening a new " OpenDefinition parses the current line and jumps to it by openening a new
" tab " tab
function! go#ui#OpenDefinition(filter) function! go#ui#OpenDefinition(filter) abort
let curline = getline('.') let curline = getline('.')
" don't touch our first line or any blank line " don't touch our first line or any blank line
if curline =~ a:filter || curline =~ "^$" if curline =~ a:filter || curline =~ "^$"
" supress information about calling this function " suppress information about calling this function
echo "" echo ""
return return
endif endif
@ -87,3 +111,4 @@ function! go#ui#OpenDefinition(filter)
norm! zz norm! zz
endfunction endfunction
" vim: sw=2 ts=2 et

@ -1,5 +1,5 @@
" PathSep returns the appropriate OS specific path separator. " PathSep returns the appropriate OS specific path separator.
function! go#util#PathSep() function! go#util#PathSep() abort
if go#util#IsWin() if go#util#IsWin()
return '\' return '\'
endif endif
@ -7,7 +7,7 @@ function! go#util#PathSep()
endfunction endfunction
" PathListSep returns the appropriate OS specific path list separator. " PathListSep returns the appropriate OS specific path list separator.
function! go#util#PathListSep() function! go#util#PathListSep() abort
if go#util#IsWin() if go#util#IsWin()
return ";" return ";"
endif endif
@ -15,7 +15,7 @@ function! go#util#PathListSep()
endfunction endfunction
" LineEnding returns the correct line ending, based on the current fileformat " LineEnding returns the correct line ending, based on the current fileformat
function! go#util#LineEnding() function! go#util#LineEnding() abort
if &fileformat == 'dos' if &fileformat == 'dos'
return "\r\n" return "\r\n"
elseif &fileformat == 'mac' elseif &fileformat == 'mac'
@ -25,8 +25,14 @@ function! go#util#LineEnding()
return "\n" return "\n"
endfunction endfunction
" Join joins any number of path elements into a single path, adding a
" Separator if necessary and returns the result
function! go#util#Join(...) abort
return join(a:000, go#util#PathSep())
endfunction
" IsWin returns 1 if current OS is Windows or 0 otherwise " IsWin returns 1 if current OS is Windows or 0 otherwise
function! go#util#IsWin() function! go#util#IsWin() abort
let win = ['win16', 'win32', 'win64', 'win95'] let win = ['win16', 'win32', 'win64', 'win95']
for w in win for w in win
if (has(w)) if (has(w))
@ -37,9 +43,136 @@ function! go#util#IsWin()
return 0 return 0
endfunction endfunction
" IsMac returns 1 if current OS is macOS or 0 otherwise.
function! go#util#IsMac() abort
return has('mac') ||
\ has('macunix') ||
\ has('gui_macvim') ||
\ go#util#System('uname') =~? '^darwin'
endfunction
" Checks if using:
" 1) Windows system,
" 2) And has cygpath executable,
" 3) And uses *sh* as 'shell'
function! go#util#IsUsingCygwinShell()
return go#util#IsWin() && executable('cygpath') && &shell =~ '.*sh.*'
endfunction
function! go#util#has_job() abort
" job was introduced in 7.4.xxx however there are multiple bug fixes and one
" of the latest is 8.0.0087 which is required for a stable async API.
return has('job') && has("patch-8.0.0087")
endfunction
let s:env_cache = {}
" env returns the go environment variable for the given key. Where key can be
" GOARCH, GOOS, GOROOT, etc... It caches the result and returns the cached
" version.
function! go#util#env(key) abort
let l:key = tolower(a:key)
if has_key(s:env_cache, l:key)
return s:env_cache[l:key]
endif
if executable('go')
let l:var = call('go#util#'.l:key, [])
if go#util#ShellError() != 0
call go#util#EchoError(printf("'go env %s' failed", toupper(l:key)))
return ''
endif
else
let l:var = eval("$".toupper(a:key))
endif
let s:env_cache[l:key] = l:var
return l:var
endfunction
" goarch returns 'go env GOARCH'. This is an internal function and shouldn't
" be used. Instead use 'go#util#env("goarch")'
function! go#util#goarch() abort
return substitute(go#util#System('go env GOARCH'), '\n', '', 'g')
endfunction
" goos returns 'go env GOOS'. This is an internal function and shouldn't
" be used. Instead use 'go#util#env("goos")'
function! go#util#goos() abort
return substitute(go#util#System('go env GOOS'), '\n', '', 'g')
endfunction
" goroot returns 'go env GOROOT'. This is an internal function and shouldn't
" be used. Instead use 'go#util#env("goroot")'
function! go#util#goroot() abort
return substitute(go#util#System('go env GOROOT'), '\n', '', 'g')
endfunction
" gopath returns 'go env GOPATH'. This is an internal function and shouldn't
" be used. Instead use 'go#util#env("gopath")'
function! go#util#gopath() abort
return substitute(go#util#System('go env GOPATH'), '\n', '', 'g')
endfunction
function! go#util#osarch() abort
return go#util#env("goos") . '_' . go#util#env("goarch")
endfunction
" Run a shell command.
"
" It will temporary set the shell to /bin/sh for Unix-like systems if possible,
" so that we always use a standard POSIX-compatible Bourne shell (and not e.g.
" csh, fish, etc.) See #988 and #1276.
function! s:system(cmd, ...) abort
" Preserve original shell and shellredir values
let l:shell = &shell
let l:shellredir = &shellredir
if !go#util#IsWin() && executable('/bin/sh')
set shell=/bin/sh shellredir=>%s\ 2>&1
endif
try
return call('system', [a:cmd] + a:000)
finally
" Restore original values
let &shell = l:shell
let &shellredir = l:shellredir
endtry
endfunction
" System runs a shell command "str". Every arguments after "str" is passed to
" stdin.
function! go#util#System(str, ...) abort
return call('s:system', [a:str] + a:000)
endfunction
" Exec runs a shell command "cmd", which must be a list, one argument per item.
" Every list entry will be automatically shell-escaped
" Every other argument is passed to stdin.
function! go#util#Exec(cmd, ...) abort
if len(a:cmd) == 0
call go#util#EchoError("go#util#Exec() called with empty a:cmd")
return
endif
" CheckBinPath will show a warning for us.
let l:bin = go#path#CheckBinPath(a:cmd[0])
if empty(l:bin)
return ["", 1]
endif
let l:out = call('s:system', [go#util#Shelljoin([l:bin] + a:cmd[1:])] + a:000)
return [l:out, go#util#ShellError()]
endfunction
function! go#util#ShellError() abort
return v:shell_error
endfunction
" StripPath strips the path's last character if it's a path separator. " StripPath strips the path's last character if it's a path separator.
" example: '/foo/bar/' -> '/foo/bar' " example: '/foo/bar/' -> '/foo/bar'
function! go#util#StripPathSep(path) function! go#util#StripPathSep(path) abort
let last_char = strlen(a:path) - 1 let last_char = strlen(a:path) - 1
if a:path[last_char] == go#util#PathSep() if a:path[last_char] == go#util#PathSep()
return strpart(a:path, 0, last_char) return strpart(a:path, 0, last_char)
@ -50,13 +183,13 @@ endfunction
" StripTrailingSlash strips the trailing slash from the given path list. " StripTrailingSlash strips the trailing slash from the given path list.
" example: ['/foo/bar/'] -> ['/foo/bar'] " example: ['/foo/bar/'] -> ['/foo/bar']
function! go#util#StripTrailingSlash(paths) function! go#util#StripTrailingSlash(paths) abort
return map(copy(a:paths), 'go#util#StripPathSep(v:val)') return map(copy(a:paths), 'go#util#StripPathSep(v:val)')
endfunction endfunction
" Shelljoin returns a shell-safe string representation of arglist. The " Shelljoin returns a shell-safe string representation of arglist. The
" {special} argument of shellescape() may optionally be passed. " {special} argument of shellescape() may optionally be passed.
function! go#util#Shelljoin(arglist, ...) function! go#util#Shelljoin(arglist, ...) abort
try try
let ssl_save = &shellslash let ssl_save = &shellslash
set noshellslash set noshellslash
@ -70,9 +203,19 @@ function! go#util#Shelljoin(arglist, ...)
endtry endtry
endfunction endfunction
fu! go#util#Shellescape(arg)
try
let ssl_save = &shellslash
set noshellslash
return shellescape(a:arg)
finally
let &shellslash = ssl_save
endtry
endf
" Shelllist returns a shell-safe representation of the items in the given " Shelllist returns a shell-safe representation of the items in the given
" arglist. The {special} argument of shellescape() may optionally be passed. " arglist. The {special} argument of shellescape() may optionally be passed.
function! go#util#Shelllist(arglist, ...) function! go#util#Shelllist(arglist, ...) abort
try try
let ssl_save = &shellslash let ssl_save = &shellslash
set noshellslash set noshellslash
@ -86,7 +229,7 @@ function! go#util#Shelllist(arglist, ...)
endfunction endfunction
" Returns the byte offset for line and column " Returns the byte offset for line and column
function! go#util#Offset(line, col) function! go#util#Offset(line, col) abort
if &encoding != 'utf-8' if &encoding != 'utf-8'
let sep = go#util#LineEnding() let sep = go#util#LineEnding()
let buf = a:line == 1 ? '' : (join(getline(1, a:line-1), sep) . sep) let buf = a:line == 1 ? '' : (join(getline(1, a:line-1), sep) . sep)
@ -97,27 +240,159 @@ function! go#util#Offset(line, col)
endfunction endfunction
" "
" Returns the byte offset for the cursor " Returns the byte offset for the cursor
function! go#util#OffsetCursor() function! go#util#OffsetCursor() abort
return go#util#Offset(line('.'), col('.')) return go#util#Offset(line('.'), col('.'))
endfunction endfunction
" TODO(arslan): I couldn't parameterize the highlight types. Check if we can " Windo is like the built-in :windo, only it returns to the window the command
" simplify the following functions " was issued from
function! go#util#Windo(command) abort
let s:currentWindow = winnr()
try
execute "windo " . a:command
finally
execute s:currentWindow. "wincmd w"
unlet s:currentWindow
endtry
endfunction
function! go#util#EchoSuccess(msg) " snippetcase converts the given word to given preferred snippet setting type
redraws! | echon "vim-go: " | echohl Function | echon a:msg | echohl None " case.
function! go#util#snippetcase(word) abort
let l:snippet_case = get(g:, 'go_addtags_transform', "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 endfunction
function! go#util#EchoError(msg) " snakecase converts a string to snake case. i.e: FooBar -> foo_bar
redraws! | echon "vim-go: " | echohl ErrorMsg | echon a:msg | echohl None " Copied from tpope/vim-abolish
function! go#util#snakecase(word) abort
let word = substitute(a:word, '::', '/', 'g')
let word = substitute(word, '\(\u\+\)\(\u\l\)', '\1_\2', 'g')
let word = substitute(word, '\(\l\|\d\)\(\u\)', '\1_\2', 'g')
let word = substitute(word, '[.-]', '_', 'g')
let word = tolower(word)
return word
endfunction endfunction
function! go#util#EchoWarning(msg) " camelcase converts a string to camel case. e.g. FooBar or foo_bar will become
redraws! | echon "vim-go: " | echohl WarningMsg | echon a:msg | echohl None " fooBar.
" Copied from tpope/vim-abolish.
function! go#util#camelcase(word) abort
let word = substitute(a:word, '-', '_', 'g')
if word !~# '_' && word =~# '\l'
return substitute(word, '^.', '\l&', '')
else
return substitute(word, '\C\(_\)\=\(.\)', '\=submatch(1)==""?tolower(submatch(2)) : toupper(submatch(2))','g')
endif
endfunction endfunction
" pascalcase converts a string to 'PascalCase'. e.g. fooBar or foo_bar will
" become FooBar.
function! go#util#pascalcase(word) abort
let word = go#util#camelcase(a:word)
return toupper(word[0]) . word[1:]
endfunction
" Echo a message to the screen and highlight it with the group in a:hi.
"
" The message can be a list or string; every line with be :echomsg'd separately.
function! s:echo(msg, hi)
let l:msg = []
if type(a:msg) != type([])
let l:msg = split(a:msg, "\n")
else
let l:msg = a:msg
endif
" Tabs display as ^I or <09>, so manually expand them.
let l:msg = map(l:msg, 'substitute(v:val, "\t", " ", "")')
exe 'echohl ' . a:hi
for line in l:msg
echom "vim-go: " . line
endfor
echohl None
endfunction
function! go#util#EchoSuccess(msg)
call s:echo(a:msg, 'Function')
endfunction
function! go#util#EchoError(msg)
call s:echo(a:msg, 'ErrorMsg')
endfunction
function! go#util#EchoWarning(msg)
call s:echo(a:msg, 'WarningMsg')
endfunction
function! go#util#EchoProgress(msg) function! go#util#EchoProgress(msg)
redraws! | echon "vim-go: " | echohl Identifier | echon a:msg | echohl None call s:echo(a:msg, 'Identifier')
endfunction
function! go#util#EchoInfo(msg)
call s:echo(a:msg, 'Debug')
endfunction
" Get all lines in the buffer as a a list.
function! go#util#GetLines()
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
return buf
endfunction
" Convert the current buffer to the "archive" format of
" golang.org/x/tools/go/buildutil:
" https://godoc.org/golang.org/x/tools/go/buildutil#ParseOverlayArchive
"
" > The archive consists of a series of files. Each file consists of a name, a
" > decimal file size and the file contents, separated by newlinews. No newline
" > follows after the file contents.
function! go#util#archive()
let l:buffer = join(go#util#GetLines(), "\n")
return expand("%:p:gs!\\!/!") . "\n" . strlen(l:buffer) . "\n" . l:buffer
endfunction
" Make a named temporary directory which starts with "prefix".
"
" Unfortunately Vim's tempname() is not portable enough across various systems;
" see: https://github.com/mattn/vim-go/pull/3#discussion_r138084911
function! go#util#tempdir(prefix) abort
" See :help tempfile
if go#util#IsWin()
let l:dirs = [$TMP, $TEMP, 'c:\tmp', 'c:\temp']
else
let l:dirs = [$TMPDIR, '/tmp', './', $HOME]
endif
let l:dir = ''
for l:d in dirs
if !empty(l:d) && filewritable(l:d) == 2
let l:dir = l:d
break
endif
endfor
if l:dir == ''
echoerr 'Unable to find directory to store temporary directory in'
return
endif
" Not great randomness, but "good enough" for our purpose here.
let l:rnd = sha256(printf('%s%s', localtime(), fnamemodify(bufname(''), ":p")))
let l:tmp = printf("%s/%s%s", l:dir, a:prefix, l:rnd)
call mkdir(l:tmp, 'p', 0700)
return l:tmp
endfunction endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -1,21 +0,0 @@
"Check if has vimproc
function! go#vimproc#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
" vim:ts=4:sw=4:et

@ -0,0 +1,105 @@
" Write a Go file to a temporary directory and append this directory to $GOPATH.
"
" The file will written to a:path, which is relative to the temporary directory,
" and this file will be loaded as the current buffer.
"
" The cursor will be placed on the character before any 0x1f byte.
"
" The full path to the created directory is returned, it is the caller's
" responsibility to clean that up!
fun! gotest#write_file(path, contents) abort
let l:dir = go#util#tempdir("vim-go-test/testrun/")
let $GOPATH .= ':' . l:dir
let l:full_path = l:dir . '/src/' . a:path
call mkdir(fnamemodify(l:full_path, ':h'), 'p')
call writefile(a:contents, l:full_path)
exe 'cd ' . l:dir . '/src'
silent exe 'e! ' . a:path
" Set cursor.
let l:lnum = 1
for l:line in a:contents
let l:m = match(l:line, "\x1f")
if l:m > -1
call setpos('.', [0, l:lnum, l:m, 0])
call setline('.', substitute(getline('.'), "\x1f", '', ''))
break
endif
let l:lnum += 1
endfor
return l:dir
endfun
" Load a fixture file from test-fixtures.
"
" The file will be copied to a new GOPATH-compliant temporary directory and
" loaded as the current buffer.
fun! gotest#load_fixture(path) abort
let l:dir = go#util#tempdir("vim-go-test/testrun/")
let $GOPATH .= ':' . l:dir
let l:full_path = l:dir . '/src/' . a:path
call mkdir(fnamemodify(l:full_path, ':h'), 'p')
exe 'cd ' . l:dir . '/src'
silent exe 'noautocmd e ' . a:path
silent exe printf('read %s/test-fixtures/%s', g:vim_go_root, a:path)
silent noautocmd w!
return l:dir
endfun
" Diff the contents of the current buffer to a:want, which should be a list.
" If a:skipHeader is true we won't bother with the package and import
" declarations; so e.g.:
"
" let l:diff = s:diff_buffer(1, ['_ = mail.Address{}'])
"
" will pass, whereas otherwise you'd have to:
"
" let l:diff = s:diff_buffer(0, ['package main', 'import "net/mail", '_ = mail.Address{}'])
fun! gotest#assert_buffer(skipHeader, want) abort
let l:buffer = go#util#GetLines()
if a:skipHeader
for l:lnum in range(0, len(l:buffer) - 1)
" Bit rudimentary, but works reasonably well.
if match(l:buffer[l:lnum], '^\v(func|var|const|import \(|\))') > -1
" vint bug: https://github.com/Kuniwak/vint/issues/179
" vint: -ProhibitUsingUndeclaredVariable
let l:buffer = l:buffer[l:lnum:len(l:buffer)]
break
endif
endfor
endif
" Using ' is often easier so we don't have to escape ".
let l:want = map(a:want, 'substitute(v:val, "\\\\t", "\t", "")')
let l:tmp = go#util#tempdir('assert_buffer')
try
call writefile(l:buffer, l:tmp . '/have')
call writefile(l:want, l:tmp . '/want')
call go#fmt#run('gofmt', l:tmp . '/have', l:tmp . '/have')
call go#fmt#run('gofmt', l:tmp . '/want', l:tmp . '/want')
let [l:out, l:err] = go#util#Exec(["diff", "-u", l:tmp . '/have', l:tmp . '/want'])
finally
call delete(l:tmp . '/have')
call delete(l:tmp . '/want')
call delete(l:tmp, 'd')
endtry
if l:err || l:out != ''
let v:errors = extend(v:errors, split(l:out, "\n"))
endif
endfun
" Diff the contents of the current buffer to the fixture file in a:path.
fun! gotest#assert_fixture(path) abort
let l:want = readfile(printf('%s/test-fixtures/%s', g:vim_go_root, a:path))
call gotest#assert_buffer(0, l:want)
endfun
" vim: sw=2 ts=2 et

@ -0,0 +1,70 @@
let s:save_cpo = &cpoptions
set cpoptions&vim
let s:source = {
\ 'name': 'decls',
\ 'description': 'GoDecls implementation for unite',
\ 'syntax': 'uniteSource__Decls',
\ 'action_table': {},
\ 'hooks': {},
\ }
function! unite#sources#decls#define()
return s:source
endfunction
function! s:source.gather_candidates(args, context) abort
let l:bin_path = go#path#CheckBinPath('motion')
if empty(l:bin_path)
return []
endif
let l:path = expand(get(a:args, 0, '%:p:h'))
if isdirectory(l:path)
let l:mode = 'dir'
elseif filereadable(l:path)
let l:mode = 'file'
else
return []
endif
let l:include = get(g:, 'go_decls_includes', 'func,type')
let l:command = printf('%s -format vim -mode decls -include %s -%s %s', l:bin_path, l:include, l:mode, shellescape(l:path))
let l:candidates = []
try
let l:result = eval(unite#util#system(l:command))
let l:candidates = get(l:result, 'decls', [])
catch
call unite#print_source_error(['command returned invalid response.', v:exception], s:source.name)
endtry
return map(l:candidates, "{
\ 'word': printf('%s :%d :%s', fnamemodify(v:val.filename, ':~:.'), v:val.line, v:val.full),
\ 'kind': 'jump_list',
\ 'action__path': v:val.filename,
\ 'action__line': v:val.line,
\ 'action__col': v:val.col,
\ }")
endfunction
function! s:source.hooks.on_syntax(args, context) abort
syntax match uniteSource__Decls_Filepath /[^:]*\ze:/ contained containedin=uniteSource__Decls
syntax match uniteSource__Decls_Line /\d\+\ze :/ contained containedin=uniteSource__Decls
syntax match uniteSource__Decls_WholeFunction /\vfunc %(\([^)]+\) )?[^(]+/ contained containedin=uniteSource__Decls
syntax match uniteSource__Decls_Function /\S\+\ze(/ contained containedin=uniteSource__Decls_WholeFunction
syntax match uniteSource__Decls_WholeType /type \S\+/ contained containedin=uniteSource__Decls
syntax match uniteSource__Decls_Type /\v( )@<=\S+/ contained containedin=uniteSource__Decls_WholeType
highlight default link uniteSource__Decls_Filepath Comment
highlight default link uniteSource__Decls_Line LineNr
highlight default link uniteSource__Decls_Function Function
highlight default link uniteSource__Decls_Type Type
syntax match uniteSource__Decls_Separator /:/ contained containedin=uniteSource__Decls conceal
syntax match uniteSource__Decls_SeparatorFunction /func / contained containedin=uniteSource__Decls_WholeFunction conceal
syntax match uniteSource__Decls_SeparatorType /type / contained containedin=uniteSource__Decls_WholeType conceal
endfunction
let &cpoptions = s:save_cpo
unlet s:save_cpo
" vim: sw=2 ts=2 et

@ -4,10 +4,10 @@
" "
" compiler/go.vim: Vim compiler file for Go. " compiler/go.vim: Vim compiler file for Go.
if exists("current_compiler") if exists("g:current_compiler")
finish finish
endif endif
let current_compiler = "go" let g:current_compiler = "go"
if exists(":CompilerSet") != 2 if exists(":CompilerSet") != 2
command -nargs=* CompilerSet setlocal <args> command -nargs=* CompilerSet setlocal <args>
@ -38,4 +38,4 @@ CompilerSet errorformat+=%-G%.%# " All lines not matching a
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

File diff suppressed because it is too large Load Diff

@ -18,6 +18,8 @@ function! s:gofiletype_post()
let &g:fileencodings = s:current_fileencodings let &g:fileencodings = s:current_fileencodings
endfunction endfunction
augroup vim-go-filetype
autocmd!
au BufNewFile *.go setfiletype go | setlocal fileencoding=utf-8 fileformat=unix au BufNewFile *.go setfiletype go | setlocal fileencoding=utf-8 fileformat=unix
au BufRead *.go call s:gofiletype_pre("go") au BufRead *.go call s:gofiletype_pre("go")
au BufReadPost *.go call s:gofiletype_post() au BufReadPost *.go call s:gofiletype_post()
@ -27,5 +29,6 @@ au BufRead *.s call s:gofiletype_pre("asm")
au BufReadPost *.s call s:gofiletype_post() au BufReadPost *.s call s:gofiletype_post()
au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl
augroup end
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -15,3 +15,5 @@ setlocal commentstring=//\ %s
setlocal noexpandtab setlocal noexpandtab
command! -nargs=0 AsmFmt call go#asmfmt#Format() command! -nargs=0 AsmFmt call go#asmfmt#Format()
" vim: sw=2 ts=2 et

@ -29,7 +29,15 @@ if get(g:, "go_doc_keywordprg_enabled", 1)
endif endif
if get(g:, "go_def_mapping_enabled", 1) 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> gd :GoDef<cr>
nnoremap <buffer> <silent> <C-]> :GoDef<cr>
nnoremap <buffer> <silent> <C-LeftMouse> <LeftMouse>:GoDef<cr>
nnoremap <buffer> <silent> g<LeftMouse> <LeftMouse>: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 endif
if get(g:, "go_textobj_enabled", 1) if get(g:, "go_textobj_enabled", 1)
@ -50,8 +58,76 @@ if get(g:, "go_textobj_enabled", 1)
xnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('v', 'prev')<cr> xnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('v', 'prev')<cr>
endif endif
if get(g:, "go_auto_type_info", 0) if get(g:, "go_auto_type_info", 0) || get(g:, "go_auto_sameids", 0)
setlocal updatetime=800 let &l:updatetime= get(g:, "go_updatetime", 800)
endif endif
" vim:ts=4:sw=4:et " NOTE(arslan): experimental, disabled by default, doesn't work well. No
" documentation as well. If anyone feels adventurous, enable the following and
" try to search for Go identifiers ;)
"
" if get(g:, "go_sameid_search_enabled", 0)
" autocmd FileType go nnoremap <buffer> <silent> * :<c-u>call Sameids_search(0)<CR>
" autocmd FileType go nnoremap <buffer> <silent> # :<c-u>call Sameids_search(1)<CR>
" autocmd FileType go nnoremap <buffer> <silent> n :<c-u>call Sameids_repeat(0)<CR>
" autocmd FileType go nnoremap <buffer> <silent> N :<c-u>call Sameids_repeat(1)<CR>
" autocmd FileType go cabbrev nohlsearch <C-r>=Sameids_nohlsearch()<CR>
" endif
" " mode 0: next 1: prev
" function! Sameids_repeat(mode)
" let matches = getmatches()
" if empty(matches)
" return
" endif
" let cur_offset = go#util#OffsetCursor()
" " reverse list to make it easy to find the prev occurrence
" if a:mode
" call reverse(matches)
" endif
" for m in matches
" if !has_key(m, "group")
" return
" endif
" if m.group != "goSameId"
" return
" endif
" let offset = go#util#Offset(m.pos1[0], m.pos1[1])
" if a:mode && cur_offset > offset
" call cursor(m.pos1[0], m.pos1[1])
" return
" elseif !a:mode && cur_offset < offset
" call cursor(m.pos1[0], m.pos1[1])
" return
" endif
" endfor
" " reached start/end, jump to the end/start
" let initial_match = matches[0]
" if !has_key(initial_match, "group")
" return
" endif
" if initial_match.group != "goSameId"
" return
" endif
" call cursor(initial_match.pos1[0], initial_match.pos1[1])
" endfunction
" function! Sameids_search(mode)
" call go#guru#SameIds()
" call Sameids_repeat(a:mode)
" endfunction
" function! Sameids_nohlsearch()
" call go#guru#ClearSameIds()
" return "nohlsearch"
" endfunction
" vim: sw=2 ts=2 et

@ -1,38 +1,59 @@
" gorename " -- gorename
command! -nargs=? GoRename call go#rename#Rename(<bang>0,<f-args>) command! -nargs=? -complete=customlist,go#rename#Complete GoRename call go#rename#Rename(<bang>0, <f-args>)
" oracle " -- guru
command! -nargs=* -complete=customlist,go#package#Complete GoOracleScope call go#oracle#Scope(<f-args>) command! -nargs=* -complete=customlist,go#package#Complete GoGuruScope call go#guru#Scope(<f-args>)
command! -range=% GoImplements call go#oracle#Implements(<count>) command! -range=% GoImplements call go#guru#Implements(<count>)
command! -range=% GoCallees call go#oracle#Callees(<count>) command! -range=% GoWhicherrs call go#guru#Whicherrs(<count>)
command! -range=% GoDescribe call go#oracle#Describe(<count>) command! -range=% GoCallees call go#guru#Callees(<count>)
command! -range=% GoCallers call go#oracle#Callers(<count>) command! -range=% GoDescribe call go#guru#Describe(<count>)
command! -range=% GoCallstack call go#oracle#Callstack(<count>) command! -range=% GoCallers call go#guru#Callers(<count>)
command! -range=% GoFreevars call go#oracle#Freevars(<count>) command! -range=% GoCallstack call go#guru#Callstack(<count>)
command! -range=% GoChannelPeers call go#oracle#ChannelPeers(<count>) command! -range=% GoFreevars call go#guru#Freevars(<count>)
command! -range=% GoReferrers call go#oracle#Referrers(<count>) command! -range=% GoChannelPeers call go#guru#ChannelPeers(<count>)
command! -nargs=? GoOracleTags call go#oracle#Tags(<f-args>) command! -range=% GoReferrers call go#guru#Referrers(<count>)
" tool command! -range=0 GoSameIds call go#guru#SameIds()
command! -nargs=0 GoFiles echo go#tool#Files() command! -range=0 GoSameIdsClear call go#guru#ClearSameIds()
command! -range=0 GoSameIdsToggle call go#guru#ToggleSameIds()
command! -range=0 GoSameIdsAutoToggle call go#guru#AutoToogleSameIds()
" -- tags
command! -nargs=* -range GoAddTags call go#tags#Add(<line1>, <line2>, <count>, <f-args>)
command! -nargs=* -range GoRemoveTags call go#tags#Remove(<line1>, <line2>, <count>, <f-args>)
" -- tool
command! -nargs=* -complete=customlist,go#tool#ValidFiles GoFiles echo go#tool#Files(<f-args>)
command! -nargs=0 GoDeps echo go#tool#Deps() command! -nargs=0 GoDeps echo go#tool#Deps()
command! -nargs=* GoInfo call go#complete#Info(0) command! -nargs=* GoInfo call go#tool#Info(0)
command! -nargs=0 GoAutoTypeInfoToggle call go#complete#ToggleAutoTypeInfo()
" cmd " -- cmd
command! -nargs=* -bang GoBuild call go#cmd#Build(<bang>0,<f-args>) command! -nargs=* -bang GoBuild call go#cmd#Build(<bang>0,<f-args>)
command! -nargs=? -bang GoBuildTags call go#cmd#BuildTags(<bang>0, <f-args>)
command! -nargs=* -bang GoGenerate call go#cmd#Generate(<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 -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 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>) " -- test
command! -nargs=* -bang GoTestCompile call go#cmd#Test(<bang>0, 1, <f-args>) command! -nargs=* -bang GoTest call go#test#Test(<bang>0, 0, <f-args>)
command! -nargs=* -bang GoCoverage call go#cmd#Coverage(<bang>0, <f-args>) command! -nargs=* -bang GoTestFunc call go#test#Func(<bang>0, <f-args>)
command! -nargs=* -bang GoTestCompile call go#test#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 " -- play
command! -nargs=0 -range=% GoPlay call go#play#Share(<count>, <line1>, <line2>) command! -nargs=0 -range=% GoPlay call go#play#Share(<count>, <line1>, <line2>)
" -- def " -- def
command! -nargs=* -range GoDef :call go#def#Jump(<f-args>) 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 " -- 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 GoDoc call go#doc#Open('new', 'split', <f-args>)
@ -40,8 +61,12 @@ command! -nargs=* -range -complete=customlist,go#package#Complete GoDocBrowser c
" -- fmt " -- fmt
command! -nargs=0 GoFmt call go#fmt#Format(-1) command! -nargs=0 GoFmt call go#fmt#Format(-1)
command! -nargs=0 GoFmtAutoSaveToggle call go#fmt#ToggleFmtAutoSave()
command! -nargs=0 GoImports call go#fmt#Format(1) command! -nargs=0 GoImports call go#fmt#Format(1)
" -- asmfmt
command! -nargs=0 GoAsmFmtAutoSaveToggle call go#asmfmt#ToggleAsmFmtAutoSave()
" -- import " -- import
command! -nargs=? -complete=customlist,go#package#Complete GoDrop call go#import#SwitchImport(0, '', <f-args>, '') 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=1 -bang -complete=customlist,go#package#Complete GoImport call go#import#SwitchImport(1, '', <f-args>, '<bang>')
@ -49,6 +74,7 @@ command! -nargs=* -bang -complete=customlist,go#package#Complete GoImportAs call
" -- linters " -- linters
command! -nargs=* GoMetaLinter call go#lint#Gometa(0, <f-args>) command! -nargs=* GoMetaLinter call go#lint#Gometa(0, <f-args>)
command! -nargs=0 GoMetaLinterAutoSaveToggle call go#lint#ToggleMetaLinterAutoSave()
command! -nargs=* GoLint call go#lint#Golint(<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=* -bang GoVet call go#lint#Vet(<bang>0, <f-args>)
command! -nargs=* -complete=customlist,go#package#Complete GoErrCheck call go#lint#Errcheck(<f-args>) command! -nargs=* -complete=customlist,go#package#Complete GoErrCheck call go#lint#Errcheck(<f-args>)
@ -56,10 +82,20 @@ command! -nargs=* -complete=customlist,go#package#Complete GoErrCheck call go#li
" -- alternate " -- alternate
command! -bang GoAlternate call go#alternate#Switch(<bang>0, '') command! -bang GoAlternate call go#alternate#Switch(<bang>0, '')
" -- ctrlp " -- decls
if globpath(&rtp, 'plugin/ctrlp.vim') != "" command! -nargs=? -complete=file GoDecls call go#decls#Decls(0, <q-args>)
command! -nargs=? -complete=file GoDecls call ctrlp#init(ctrlp#decls#cmd(0, <q-args>)) command! -nargs=? -complete=dir GoDeclsDir call go#decls#Decls(1, <q-args>)
command! -nargs=? -complete=dir GoDeclsDir call ctrlp#init(ctrlp#decls#cmd(1, <q-args>))
endif " -- impl
command! -nargs=* -complete=customlist,go#impl#Complete GoImpl call go#impl#Impl(<f-args>)
" -- template
command! -nargs=0 GoTemplateAutoCreateToggle call go#template#ToggleAutoCreate()
" -- keyify
command! -nargs=0 GoKeyify call go#keyify#Keyify()
" -- fillstruct
command! -nargs=0 GoFillStruct call go#fillstruct#FillStruct()
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -20,31 +20,43 @@ endif
nnoremap <silent> <Plug>(go-build) :<C-u>call go#cmd#Build(!g:go_jump_to_error)<CR> 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-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-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) :<C-u>call go#test#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-func) :<C-u>call go#test#Func(!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-test-compile) :<C-u>call go#test#Test(!g:go_jump_to_error, 1)<CR>
nnoremap <silent> <Plug>(go-coverage) :<C-u>call go#cmd#Coverage(!g:go_jump_to_error)<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-files) :<C-u>call go#tool#Files()<CR>
nnoremap <silent> <Plug>(go-deps) :<C-u>call go#tool#Deps()<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-info) :<C-u>call go#tool#Info(0)<CR>
nnoremap <silent> <Plug>(go-import) :<C-u>call go#import#SwitchImport(1, '', expand('<cword>'), '')<CR> nnoremap <silent> <Plug>(go-import) :<C-u>call go#import#SwitchImport(1, '', expand('<cword>'), '')<CR>
nnoremap <silent> <Plug>(go-imports) :<C-u>call go#fmt#Format(1)<CR>
nnoremap <silent> <Plug>(go-implements) :<C-u>call go#oracle#Implements(-1)<CR> nnoremap <silent> <Plug>(go-implements) :<C-u>call go#guru#Implements(-1)<CR>
nnoremap <silent> <Plug>(go-callees) :<C-u>call go#oracle#Callees(-1)<CR> nnoremap <silent> <Plug>(go-callees) :<C-u>call go#guru#Callees(-1)<CR>
nnoremap <silent> <Plug>(go-callers) :<C-u>call go#oracle#Callers(-1)<CR> nnoremap <silent> <Plug>(go-callers) :<C-u>call go#guru#Callers(-1)<CR>
nnoremap <silent> <Plug>(go-describe) :<C-u>call go#oracle#Describe(-1)<CR> nnoremap <silent> <Plug>(go-describe) :<C-u>call go#guru#Describe(-1)<CR>
nnoremap <silent> <Plug>(go-callstack) :<C-u>call go#oracle#Callstack(-1)<CR> nnoremap <silent> <Plug>(go-callstack) :<C-u>call go#guru#Callstack(-1)<CR>
nnoremap <silent> <Plug>(go-freevars) :<C-u>call go#oracle#Freevars(-1)<CR> xnoremap <silent> <Plug>(go-freevars) :<C-u>call go#guru#Freevars(0)<CR>
nnoremap <silent> <Plug>(go-channelpeers) :<C-u>call go#oracle#ChannelPeers(-1)<CR> nnoremap <silent> <Plug>(go-channelpeers) :<C-u>call go#guru#ChannelPeers(-1)<CR>
nnoremap <silent> <Plug>(go-referrers) :<C-u>call go#oracle#Referrers(-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()<CR>
nnoremap <silent> <Plug>(go-whicherrs) :<C-u>call go#guru#Whicherrs(-1)<CR>
nnoremap <silent> <Plug>(go-sameids-toggle) :<C-u>call go#guru#ToggleSameIds()<CR>
nnoremap <silent> <Plug>(go-rename) :<C-u>call go#rename#Rename(!g:go_jump_to_error)<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) :<C-u>call go#def#Jump('')<CR>
nnoremap <silent> <Plug>(go-def-vertical) :<C-u>call go#def#JumpMode("vsplit")<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#JumpMode("split")<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#JumpMode("tab")<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) :<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-tab) :<C-u>call go#doc#Open("tabnew", "tabe")<CR>
@ -53,8 +65,11 @@ 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-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-metalinter) :<C-u>call go#lint#Gometa(0)<CR>
nnoremap <silent> <Plug>(go-lint) :<C-u>call go#lint#Golint()<CR>
nnoremap <silent> <Plug>(go-vet) :<C-u>call go#lint#Vet(!g:go_jump_to_error)<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-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-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> nnoremap <silent> <Plug>(go-alternate-split) :<C-u>call go#alternate#Switch(0, "split")<CR>
" vim: sw=2 ts=2 et

@ -3,13 +3,8 @@ if exists("g:go_loaded_gosnippets")
endif endif
let g:go_loaded_gosnippets = 1 let g:go_loaded_gosnippets = 1
" by default UltiSnips function! s:GoUltiSnips() abort
if !exists("g:go_snippet_engine") if get(g:, 'did_plugin_ultisnips') isnot 1
let g:go_snippet_engine = "ultisnips"
endif
function! s:GoUltiSnips()
if globpath(&rtp, 'plugin/UltiSnips.vim') == ""
return return
endif endif
@ -20,27 +15,53 @@ function! s:GoUltiSnips()
endif endif
endfunction endfunction
function! s:GoNeosnippet() function! s:GoNeosnippet() abort
if globpath(&rtp, 'plugin/neosnippet.vim') == "" if get(g:, 'loaded_neosnippet') isnot 1
return return
endif endif
let g:neosnippet#enable_snipmate_compatibility = 1 let g:neosnippet#enable_snipmate_compatibility = 1
let gosnippets_dir = globpath(&rtp, 'gosnippets/snippets') let l:gosnippets_dir = globpath(&rtp, 'gosnippets/snippets')
if type(g:neosnippet#snippets_directory) == type([]) if type(g:neosnippet#snippets_directory) == type([])
let g:neosnippet#snippets_directory += [gosnippets_dir] let g:neosnippet#snippets_directory += [l:gosnippets_dir]
elseif type(g:neosnippet#snippets_directory) == type("") elseif type(g:neosnippet#snippets_directory) == type("")
if strlen(g:neosnippet#snippets_directory) > 0 if strlen(g:neosnippet#snippets_directory) > 0
let g:neosnippet#snippets_directory = g:neosnippet#snippets_directory . "," . gosnippets_dir let g:neosnippet#snippets_directory = g:neosnippet#snippets_directory . "," . l:gosnippets_dir
else else
let g:neosnippet#snippets_directory = gosnippets_dir let g:neosnippet#snippets_directory = l:gosnippets_dir
endif
endif
endfunction
function! s:GoMinisnip() abort
if get(g:, 'loaded_minisnip') isnot 1
return
endif endif
if exists('g:minisnip_dir')
let g:minisnip_dir .= ':' . globpath(&rtp, 'gosnippets/minisnip')
else
let g:minisnip_dir = globpath(&rtp, 'gosnippets/minisnip')
endif endif
endfunction endfunction
if g:go_snippet_engine == "ultisnips"
let s:engine = get(g:, 'go_snippet_engine', 'automatic')
if s:engine is? "automatic"
if get(g:, 'did_plugin_ultisnips') is 1
call s:GoUltiSnips() call s:GoUltiSnips()
elseif g:go_snippet_engine == "neosnippet" elseif get(g:, 'loaded_neosnippet') is 1
call s:GoNeosnippet() call s:GoNeosnippet()
elseif get(g:, 'loaded_minisnip') is 1
call s:GoMinisnip()
endif endif
elseif s:engine is? "ultisnips"
call s:GoUltiSnips()
elseif s:engine is? "neosnippet"
call s:GoNeosnippet()
elseif s:engine is? "minisnip"
call s:GoMinisnip()
endif
" vim: sw=2 ts=2 et

@ -45,7 +45,7 @@ function! s:SetTagbar()
\ 'ctype' : 't', \ 'ctype' : 't',
\ 'ntype' : 'n' \ 'ntype' : 'n'
\ }, \ },
\ 'ctagsbin' : expand(bin_path), \ 'ctagsbin' : bin_path,
\ 'ctagsargs' : '-sort -silent' \ 'ctagsargs' : '-sort -silent'
\ } \ }
endif endif
@ -53,3 +53,5 @@ endfunction
call s:SetTagbar() call s:SetTagbar()
" vim: sw=2 ts=2 et

@ -0,0 +1,7 @@
if exists("b:did_ftplugin")
finish
endif
runtime! ftplugin/html.vim
" vim: sw=2 ts=2 et

@ -110,7 +110,7 @@ snippet gpl
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. * along with this program; if not, see <http://www.gnu.org/licenses/>.
* *
* Copyright (C) ${1:Author}, `strftime("%Y")` * Copyright (C) ${1:Author}, `!v strftime("%Y")`
*/ */
${0} ${0}
endsnippet endsnippet
@ -143,6 +143,13 @@ else {
} }
endsnippet endsnippet
# if inline error
snippet ife "If with inline erro"
if err := ${1:condition}; err != nil {
${0:${VISUAL}}
}
endsnippet
# error snippet # error snippet
snippet errn "Error return " !b snippet errn "Error return " !b
if err != nil { if err != nil {
@ -151,14 +158,15 @@ if err != nil {
${0} ${0}
endsnippet endsnippet
# error snippet # error log snippet
snippet errt "Error test fatal " !b snippet errl "Error with log.Fatal(err)" !b
if err != nil { if err != nil {
t.Fatal(err) log.Fatal(err)
} }
${0} ${0}
endsnippet endsnippet
# error multiple return
snippet errn, "Error return with two return values" !b snippet errn, "Error return with two return values" !b
if err != nil { if err != nil {
return ${1:nil}, err return ${1:nil}, err
@ -166,6 +174,23 @@ if err != nil {
${0} ${0}
endsnippet 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 snippet errh "Error handle and return" !b
if err != nil { if err != nil {
${1} ${1}
@ -174,8 +199,14 @@ if err != nil {
${0} ${0}
endsnippet endsnippet
# json field tag
snippet json "\`json:key\`" snippet json "\`json:key\`"
\`json:"${1:keyName}"\` \`json:"${1:`!v go#util#snippetcase(matchstr(getline("."), '\w\+'))`}"\`
endsnippet
# yaml field tag
snippet yaml "\`yaml:key\`"
\`yaml:"${1:`!v go#util#snippetcase(matchstr(getline("."), '\w\+'))`}"\`
endsnippet endsnippet
# fallthrough # fallthrough
@ -327,6 +358,18 @@ func Test${1:Function}(t *testing.T) {
} }
endsnippet 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 # quick test server
snippet tsrv "httptest.NewServer" snippet tsrv "httptest.NewServer"
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -351,6 +394,21 @@ if err != nil {
} }
endsnippet 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 # variable declaration
snippet var "var x Type [= ...]" snippet var "var x Type [= ...]"
var ${1:x} ${2:Type}${3: = ${0:value}} var ${1:x} ${2:Type}${3: = ${0:value}}
@ -372,7 +430,6 @@ if !reflect.DeepEqual(${1:expected}, ${2:actual}) {
} }
endsnippet endsnippet
global !p global !p
import re import re

@ -0,0 +1,3 @@
if !reflect.DeepEqual({{+got+}}, {{+want+}}) {
t.Errorf("\ngot: %#v\nwant: %#v\n", {{+~\~2+}}, {{+~\~2+}})
}

@ -0,0 +1,3 @@
if err != nil {
return {{+err+}}
}

@ -0,0 +1,4 @@
if err != nil {
t.Fatal(err)
}
{{++}}

@ -0,0 +1,3 @@
if err != nil {
return errors.Wrap(err, "{{++}}")
}

@ -0,0 +1,3 @@
// {{++}}
func {{+~\~1+}}() {
}

@ -0,0 +1 @@
fmt.Printf("%#v\n", {{++}})

@ -0,0 +1,3 @@
for i := 0; i < {{++}}; i++ {
{{++}}
}

@ -0,0 +1,2 @@
// Package {{+~expand('%:p:h:t')+}} {{++}}
package {{+~\~2+}}

@ -0,0 +1,2 @@
fmt.Sprintf("{{++}}", {{++}})

@ -118,6 +118,14 @@ snippet else
else { else {
${0} ${0}
} }
# if inline error
snippet ife
abbr if err := ...; err != nil { ... }
if err := ${1:condition}; err != nil {
${0}
}
# error snippet # error snippet
snippet errn snippet errn
abbr if err != nil { ... } abbr if err != nil { ... }
@ -132,6 +140,13 @@ abbr if err != nil { ... }
t.Fatal(err) t.Fatal(err)
} }
# error snippet in log.Fatal
snippet errl
abbr if err != nil { ... }
if err != nil {
log.Fatal(err)
}
# error snippet with two return values # error snippet with two return values
snippet errn, snippet errn,
abbr if err != nil { return [...], err } abbr if err != nil { return [...], err }
@ -149,11 +164,24 @@ abbr if err != nil { return }
} }
${0} ${0}
# error snippet with panic
snippet errp
abbr if err != nil { ... }
if err != nil {
panic(${1})
}
${0}
# json snippet # json snippet
snippet json snippet json
abbr \`json:key\` abbr \`json:key\`
\`json:"${1:keyName}"\` \`json:"${1:keyName}"\`
# yaml snippet
snippet yaml
abbr \`yaml:key\`
\`yaml:"${1:keyName}"\`
# fallthrough # fallthrough
snippet ft snippet ft
abbr fallthrough abbr fallthrough
@ -305,6 +333,19 @@ abbr if err != nil { t.Fatalf(...) }
if err != nil { if err != nil {
t.Fatalf("${1}") 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 # variable declaration
snippet var snippet var
abbr var x Type [= ...] abbr var x Type [= ...]
@ -323,3 +364,15 @@ abbr equals: test two identifiers with DeepEqual
fmt.Printf("%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\n\n", filepath.Base(file), line, $1, $2) fmt.Printf("%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\n\n", filepath.Base(file), line, $1, $2)
t.FailNow() 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")}
})

@ -75,4 +75,4 @@ function! GoIndent(lnum)
return ind return ind
endfunction endfunction
" vim:ts=4:sw=4:et " vim: sw=2 ts=2 et

@ -30,15 +30,17 @@ function! GetGoHTMLTmplIndent(lnum)
" If need to indent based on last line " If need to indent based on last line
let last_line = getline(a:lnum-1) let last_line = getline(a:lnum-1)
if last_line =~ '^\s*{{\s*\%(if\|else\|range\|with\|define\|block\).*}}' if last_line =~ '^\s*{{-\=\s*\%(if\|else\|range\|with\|define\|block\).*}}'
let ind += sw let ind += sw
endif endif
" End of FuncMap block " End of FuncMap block
let current_line = getline(a:lnum) let current_line = getline(a:lnum)
if current_line =~ '^\s*{{\s*\%(else\|end\).*}}' if current_line =~ '^\s*{{-\=\s*\%(else\|end\).*}}'
let ind -= sw let ind -= sw
endif endif
return ind return ind
endfunction endfunction
" vim: sw=2 ts=2 et

@ -4,43 +4,74 @@ if exists("g:go_loaded_install")
endif endif
let g:go_loaded_install = 1 let g:go_loaded_install = 1
" Not using the has('patch-7.4.1689') syntax because that wasn't added until
" 7.4.237, and we want to be sure this works for everyone (this is also why
" we're not using utils#EchoError()).
"
" Version 7.4.1689 was chosen because that's what the most recent Ubuntu LTS
" release (16.04) uses.
if
\ get(g:, 'go_version_warning', 1) != 0 &&
\ (v:version < 704 || (v:version == 704 && !has('patch1689')))
\ && !has('nvim')
echohl Error
echom "vim-go requires Vim 7.4.1689 or Neovim, but you're using an older version."
echom "Please update your Vim for the best vim-go experience."
echom "If you really want to continue you can set this to make the error go away:"
echom " let g:go_version_warning = 0"
echom "Note that some features may error out or behave incorrectly."
echom "Please do not report bugs unless you're using Vim 7.4.1689 or newer."
echohl None
" Make sure people see this.
sleep 2
endif
" these packages are used by vim-go and can be automatically installed if " these packages are used by vim-go and can be automatically installed if
" needed by the user with GoInstallBinaries " needed by the user with GoInstallBinaries
let s:packages = [ let s:packages = {
\ "github.com/nsf/gocode", \ 'asmfmt': ['github.com/klauspost/asmfmt/cmd/asmfmt'],
\ "github.com/alecthomas/gometalinter", \ 'errcheck': ['github.com/kisielk/errcheck'],
\ "golang.org/x/tools/cmd/goimports", \ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct'],
\ "github.com/rogpeppe/godef", \ 'gocode': ['github.com/nsf/gocode', {'windows': '-ldflags -H=windowsgui'}],
\ "golang.org/x/tools/cmd/oracle", \ 'godef': ['github.com/rogpeppe/godef'],
\ "golang.org/x/tools/cmd/gorename", \ 'gogetdoc': ['github.com/zmb3/gogetdoc'],
\ "github.com/golang/lint/golint", \ 'goimports': ['golang.org/x/tools/cmd/goimports'],
\ "github.com/kisielk/errcheck", \ 'golint': ['github.com/golang/lint/golint'],
\ "github.com/jstemmer/gotags", \ 'gometalinter': ['github.com/alecthomas/gometalinter'],
\ "github.com/klauspost/asmfmt/cmd/asmfmt", \ 'gomodifytags': ['github.com/fatih/gomodifytags'],
\ "github.com/fatih/motion", \ 'gorename': ['golang.org/x/tools/cmd/gorename'],
\ ] \ 'gotags': ['github.com/jstemmer/gotags'],
\ 'guru': ['golang.org/x/tools/cmd/guru'],
\ 'impl': ['github.com/josharian/impl'],
\ 'keyify': ['github.com/dominikh/go-tools/cmd/keyify'],
\ 'motion': ['github.com/fatih/motion'],
\ }
" These commands are available on any filetypes " These commands are available on any filetypes
command! GoInstallBinaries call s:GoInstallBinaries(-1) command! -nargs=* -complete=customlist,s:complete GoInstallBinaries call s:GoInstallBinaries(-1, <f-args>)
command! GoUpdateBinaries call s:GoInstallBinaries(1) command! -nargs=* -complete=customlist,s:complete GoUpdateBinaries call s:GoInstallBinaries(1, <f-args>)
command! -nargs=? -complete=dir GoPath call go#path#GoPath(<f-args>) command! -nargs=? -complete=dir GoPath call go#path#GoPath(<f-args>)
fun! s:complete(lead, cmdline, cursor)
return filter(keys(s:packages), 'strpart(v:val, 0, len(a:lead)) == a:lead')
endfun
" GoInstallBinaries downloads and install all necessary binaries stated in the " GoInstallBinaries downloads and installs binaries defined in s:packages to
" packages variable. It uses by default $GOBIN or $GOPATH/bin as the binary " $GOBIN or $GOPATH/bin. GoInstallBinaries will update already installed
" target install directory. GoInstallBinaries doesn't install binaries if they " binaries only if updateBinaries = 1. By default, all packages in s:packages
" exist, to update current binaries pass 1 to the argument. " will be installed, but the set can be limited by passing the desired
function! s:GoInstallBinaries(updateBinaries) " packages in the unnamed arguments.
if $GOPATH == "" function! s:GoInstallBinaries(updateBinaries, ...)
echohl Error let err = s:CheckBinaries()
echomsg "vim.go: $GOPATH is not set" if err != 0
echohl None
return return
endif endif
let err = s:CheckBinaries() if go#path#Default() == ""
if err != 0 echohl Error
echomsg "vim.go: $GOPATH is not set and 'go env GOPATH' returns empty"
echohl None
return return
endif endif
@ -53,7 +84,7 @@ function! s:GoInstallBinaries(updateBinaries)
let old_path = $PATH let old_path = $PATH
" vim's executable path is looking in PATH so add our go_bin path to it " vim's executable path is looking in PATH so add our go_bin path to it
let $PATH = $PATH . go#util#PathListSep() .go_bin_path let $PATH = go_bin_path . go#util#PathListSep() . $PATH
" when shellslash is set on MS-* systems, shellescape puts single quotes " when shellslash is set on MS-* systems, shellescape puts single quotes
" around the output string. cmd on Windows does not handle single quotes " around the output string. cmd on Windows does not handle single quotes
@ -65,35 +96,59 @@ function! s:GoInstallBinaries(updateBinaries)
set noshellslash set noshellslash
endif endif
let cmd = "go get -u -v " let cmd = "go get -v "
if get(g:, "go_get_update", 1) != 0
let cmd .= "-u "
endif
let s:go_version = matchstr(system("go version"), '\d.\d.\d') let s:go_version = matchstr(go#util#System("go version"), '\d.\d.\d')
" https://github.com/golang/go/issues/10791 " https://github.com/golang/go/issues/10791
if s:go_version > "1.4.0" && s:go_version < "1.5.0" if s:go_version > "1.4.0" && s:go_version < "1.5.0"
let cmd .= "-f " let cmd .= "-f "
endif endif
for pkg in s:packages " Filter packages from arguments (if any).
let basename = fnamemodify(pkg, ":t") let l:packages = {}
let binname = "go_" . basename . "_bin" if a:0 > 0
for l:bin in a:000
let l:pkg = get(s:packages, l:bin, [])
if len(l:pkg) == 0
call go#util#EchoError('unknown binary: ' . l:bin)
return
endif
let l:packages[l:bin] = l:pkg
endfor
else
let l:packages = s:packages
endif
let l:platform = ''
if go#util#IsWin()
let l:platform = 'windows'
endif
for [binary, pkg] in items(l:packages)
let l:importPath = pkg[0]
let l:goGetFlags = len(pkg) > 1 ? get(pkg[1], l:platform, '') : ''
let bin = basename let binname = "go_" . binary . "_bin"
let bin = binary
if exists("g:{binname}") if exists("g:{binname}")
let bin = g:{binname} let bin = g:{binname}
endif endif
if !executable(bin) || a:updateBinaries == 1 if !executable(bin) || a:updateBinaries == 1
if a:updateBinaries == 1 if a:updateBinaries == 1
echo "vim-go: Updating ". basename .". Reinstalling ". pkg . " to folder " . go_bin_path echo "vim-go: Updating " . binary . ". Reinstalling ". importPath . " to folder " . go_bin_path
else else
echo "vim-go: ". basename ." not found. Installing ". pkg . " to folder " . go_bin_path echo "vim-go: ". binary ." not found. Installing ". importPath . " to folder " . go_bin_path
endif endif
let out = go#util#System(printf('%s %s %s', cmd, l:goGetFlags, shellescape(importPath)))
let out = system(cmd . shellescape(pkg)) if go#util#ShellError() != 0
if v:shell_error echom "Error installing " . importPath . ": " . out
echo "Error installing ". pkg . ": " . out
endif endif
endif endif
endfor endfor
@ -123,6 +178,10 @@ endfunction
" ============================================================================ " ============================================================================
" "
function! s:echo_go_info() function! s:echo_go_info()
if !get(g:, "go_echo_go_info", 1)
return
endif
if !exists('v:completed_item') || empty(v:completed_item) if !exists('v:completed_item') || empty(v:completed_item)
return return
endif endif
@ -139,35 +198,81 @@ function! s:echo_go_info()
redraws! | echo "vim-go: " | echohl Function | echon item.info | echohl None redraws! | echo "vim-go: " | echohl Function | echon item.info | echohl None
endfunction endfunction
augroup vim-go function! s:auto_type_info()
autocmd!
" GoInfo automatic update " GoInfo automatic update
if get(g:, "go_auto_type_info", 0) if get(g:, "go_auto_type_info", 0)
autocmd CursorHold *.go nested call go#complete#Info(1) call go#tool#Info(1)
endif endif
endfunction
" Echo the identifier information when completion is done. Useful to see function! s:auto_sameids()
" the signature of a function, etc... " GoSameId automatic update
if exists('##CompleteDone') if get(g:, "go_auto_sameids", 0)
autocmd CompleteDone *.go nested call s:echo_go_info() call go#guru#SameIds()
endif endif
endfunction
function! s:fmt_autosave()
" Go code formatting on save " Go code formatting on save
if get(g:, "go_fmt_autosave", 1) if get(g:, "go_fmt_autosave", 1)
autocmd BufWritePre *.go call go#fmt#Format(-1) call go#fmt#Format(-1)
endif endif
endfunction
function! s:asmfmt_autosave()
" Go asm formatting on save " Go asm formatting on save
if get(g:, "go_asmfmt_autosave", 1) if get(g:, "go_asmfmt_autosave", 0)
autocmd BufWritePre *.s call go#asmfmt#Format() call go#asmfmt#Format()
endif endif
endfunction
function! s:metalinter_autosave()
" run gometalinter on save " run gometalinter on save
if get(g:, "go_metalinter_autosave", 0) if get(g:, "go_metalinter_autosave", 0)
autocmd BufWritePost *.go call go#lint#Gometa(1) call go#lint#Gometa(1)
endif endif
augroup END endfunction
function! s:template_autocreate()
" create new template from scratch
if get(g:, "go_template_autocreate", 1)
call go#template#create()
endif
endfunction
augroup vim-go
autocmd!
autocmd CursorHold *.go call s:auto_type_info()
autocmd CursorHold *.go call s:auto_sameids()
" Echo the identifier information when completion is done. Useful to see
" the signature of a function, etc...
if exists('##CompleteDone')
autocmd CompleteDone *.go call s:echo_go_info()
endif
" vim:ts=4:sw=4:et autocmd BufWritePre *.go call s:fmt_autosave()
autocmd BufWritePre *.s call s:asmfmt_autosave()
autocmd BufWritePost *.go call s:metalinter_autosave()
autocmd BufNewFile *.go call s:template_autocreate()
" clear SameIds when the buffer is unloaded so that loading another buffer
" in the same window doesn't highlight the most recently matched
" identifier's positions.
autocmd BufWinEnter *.go call go#guru#ClearSameIds()
autocmd BufEnter *.go
\ if get(g:, 'go_autodetect_gopath', 0) && !exists('b:old_gopath')
\| let b:old_gopath = exists('$GOPATH') ? $GOPATH : -1
\| let $GOPATH = go#path#Detect()
\| endif
autocmd BufLeave *.go
\ if exists('b:old_gopath')
\| if b:old_gopath isnot -1
\| let $GOPATH = b:old_gopath
\| endif
\| unlet b:old_gopath
\| endif
augroup end
" vim: sw=2 ts=2 et

@ -0,0 +1,93 @@
# ============================================================================
# FILE: decls.py
# AUTHOR: delphinus <delphinus@remora.cx>
# License: MIT license
# ============================================================================
import os
import subprocess
import json
import denite.util
from .base import Base
DECLS_SYNTAX_HIGHLIGHT = [
{'name': 'FilePath', 're': r'[^:]*\ze:', 'link': 'Comment'},
{'name': 'Line', 're': r'\d\+\ze :', 'link': 'LineNr'},
{'name': 'WholeFunction', 're': r'\vfunc %(\([^)]+\) )?[^(]+'},
{'name': 'Function', 'parent': 'WholeFunction',
're': r'\S\+\ze(', 'link': 'Function'},
{'name': 'WholeType', 're': r'type \S\+'},
{'name': 'Type', 'parent': 'WholeType',
're': r'\v( )@<=\S+', 'link': 'Type'},
{'name': 'Separator', 're': r':', 'conceal': True},
{'name': 'SeparatorFunction', 'parent': 'WholeFunction',
're': r'func ', 'conceal': True},
{'name': 'SeparatorType', 'parent': 'WholeType',
're': r'type ', 'conceal': True},
]
class Source(Base):
def __init__(self, vim):
super().__init__(vim)
self.name = 'decls'
self.kind = 'file'
def gather_candidates(self, context):
bin_path = self.vim.call('go#path#CheckBinPath', 'motion')
if bin_path == '':
return []
expand = context['args'][0] if context['args'] else '%:p:h'
target = self.vim.funcs.expand(expand)
if os.path.isdir(target):
mode = 'dir'
elif os.path.isfile(target):
mode = 'file'
else:
return []
if self.vim.funcs.exists('g:go_decls_includes'):
include = self.vim.eval('g:go_decls_includes')
else:
include = 'func,type'
command = [bin_path, '-mode', 'decls', '-include', include,
'-' + mode, target]
try:
cmd = subprocess.run(command, stdout=subprocess.PIPE, check=True)
except subprocess.CalledProcessError as err:
denite.util.error(self.vim,
'command returned invalid response: ' + str(err))
return []
txt = cmd.stdout.decode('utf-8')
output = json.loads(txt, encoding='utf-8')
def make_candidates(row):
name = self.vim.funcs.fnamemodify(row['filename'], ':~:.')
return {
'word': '{0} :{1} :{2}'.format(name, row['line'], row['full']),
'action__path': row['filename'],
'action__line': row['line'],
'action__col': row['col'],
}
return list(map(make_candidates, output['decls']))
def highlight(self):
for syn in DECLS_SYNTAX_HIGHLIGHT:
containedin = self.syntax_name
containedin += '_' + syn['parent'] if 'parent' in syn else ''
conceal = ' conceal' if 'conceal' in syn else ''
self.vim.command(
'syntax match {0}_{1} /{2}/ contained containedin={3}{4}'
.format(self.syntax_name, syn['name'], syn['re'],
containedin, conceal))
if 'link' in syn:
self.vim.command('highlight default link {0}_{1} {2}'.format(
self.syntax_name, syn['name'], syn['link']))

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save