parent
feaf0b0ff7
commit
9d90477bed
128 changed files with 16344 additions and 0 deletions
12
pack/acp/start/vim-go/.codecov.yml
Normal file
12
pack/acp/start/vim-go/.codecov.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 1
|
||||
base: auto
|
||||
comment: false
|
||||
ignore:
|
||||
- "!autoload/go/*.vim$"
|
||||
- "autoload/go/*_test.vim$"
|
3
pack/acp/start/vim-go/.coveragerc
Normal file
3
pack/acp/start/vim-go/.coveragerc
Normal file
|
@ -0,0 +1,3 @@
|
|||
[run]
|
||||
plugins = covimerage
|
||||
data_file = .coverage.covimerage
|
2
pack/acp/start/vim-go/.dockerignore
Normal file
2
pack/acp/start/vim-go/.dockerignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
.local/
|
||||
.git/
|
17
pack/acp/start/vim-go/.editorconfig
Normal file
17
pack/acp/start/vim-go/.editorconfig
Normal file
|
@ -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
|
12
pack/acp/start/vim-go/.github/CONTRIBUTING.md
vendored
Normal file
12
pack/acp/start/vim-go/.github/CONTRIBUTING.md
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
Thanks for improving vim-go! Before you dive in please read the following:
|
||||
|
||||
1. Please read our
|
||||
[Documentation](https://github.com/fatih/vim-go/blob/master/doc/vim-go.txt),
|
||||
it might have a solution to your problem.
|
||||
2. If you add a new feature then please don't forget to update the documentation:
|
||||
[doc/vim-go.txt](https://github.com/fatih/vim-go/blob/master/doc/vim-go.txt).
|
||||
3. If it's a breaking change or exceeds 100 lines of code then please open an
|
||||
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.
|
||||
|
22
pack/acp/start/vim-go/.github/ISSUE_TEMPLATE.md
vendored
Normal file
22
pack/acp/start/vim-go/.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
### What did you do? (required. The issue will be **closed** when not provided.)
|
||||
|
||||
|
||||
### What did you expect to happen?
|
||||
|
||||
|
||||
### What happened instead?
|
||||
|
||||
|
||||
### Configuration (**MUST** fill this out):
|
||||
|
||||
* Vim version (first two lines from `:version`):
|
||||
|
||||
* Go version (`go version`):
|
||||
|
||||
* 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):
|
||||
|
||||
|
5
pack/acp/start/vim-go/.gitignore
vendored
Normal file
5
pack/acp/start/vim-go/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
.DS_Store
|
||||
/doc/tags
|
||||
/.coverage.covimerage
|
||||
/coverage.xml
|
||||
*.pyc
|
14
pack/acp/start/vim-go/.travis.yml
Normal file
14
pack/acp/start/vim-go/.travis.yml
Normal file
|
@ -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
|
7
pack/acp/start/vim-go/.vintrc.yaml
Normal file
7
pack/acp/start/vim-go/.vintrc.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
policies:
|
||||
ProhibitUnnecessaryDoubleQuote:
|
||||
enabled: false
|
||||
ProhibitEqualTildeOperator:
|
||||
enabled: false
|
||||
ProhibitNoAbortFunction:
|
||||
enabled: false
|
1194
pack/acp/start/vim-go/CHANGELOG.md
Normal file
1194
pack/acp/start/vim-go/CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load diff
20
pack/acp/start/vim-go/Dockerfile
Normal file
20
pack/acp/start/vim-go/Dockerfile
Normal file
|
@ -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"]
|
60
pack/acp/start/vim-go/LICENSE
Normal file
60
pack/acp/start/vim-go/LICENSE
Normal file
|
@ -0,0 +1,60 @@
|
|||
Copyright (c) 2015, Fatih Arslan
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of vim-go nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
This software includes some portions from Go. Go is used under the terms of the
|
||||
BSD like license.
|
||||
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The Go gopher was designed by Renee French. http://reneefrench.blogspot.com/ The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details: https://blog.golang.org/gopher
|
29
pack/acp/start/vim-go/Makefile
Normal file
29
pack/acp/start/vim-go/Makefile
Normal file
|
@ -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
|
70
pack/acp/start/vim-go/README.md
Normal file
70
pack/acp/start/vim-go/README.md
Normal file
|
@ -0,0 +1,70 @@
|
|||
# vim-go [![Build Status](http://img.shields.io/travis/fatih/vim-go.svg?style=flat-square)](https://travis-ci.org/fatih/vim-go)
|
||||
|
||||
<p align="center">
|
||||
<img style="float: right;" src="assets/vim-go.png" alt="Vim-go logo"/>
|
||||
</p>
|
||||
|
||||
## Features
|
||||
|
||||
This plugin adds Go language support for Vim, with the following main features:
|
||||
|
||||
* Compile your package with `:GoBuild`, install it with `:GoInstall` or test it
|
||||
with `:GoTest`. Run a single tests with `:GoTestFunc`).
|
||||
* Quickly execute your current file(s) with `:GoRun`.
|
||||
* Improved syntax highlighting and folding.
|
||||
* Debug programs with integrated `delve` support with `:GoDebugStart`.
|
||||
* Completion support via `gocode`.
|
||||
* `gofmt` or `goimports` on save keeps the cursor position and undo history.
|
||||
* Go to symbol/declaration with `:GoDef`.
|
||||
* Look up documentation with `:GoDoc` or `:GoDocBrowser`.
|
||||
* Easily import packages via `:GoImport`, remove them via `:GoDrop`.
|
||||
* Precise type-safe renaming of identifiers with `:GoRename`.
|
||||
* See which code is covered by tests with `:GoCoverage`.
|
||||
* Add or remove tags on struct fields with `:GoAddTags` and `:GoRemoveTags`.
|
||||
* Call `gometalinter` with `:GoMetaLinter` to invoke all possible linters
|
||||
(`golint`, `vet`, `errcheck`, `deadcode`, etc.) and put the result in the
|
||||
quickfix or location list.
|
||||
* Lint your code with `:GoLint`, run your code through `:GoVet` to catch static
|
||||
errors, or make sure errors are checked with `:GoErrCheck`.
|
||||
* Advanced source analysis tools utilizing `guru`, such as `:GoImplements`,
|
||||
`:GoCallees`, and `:GoReferrers`.
|
||||
* ... and many more! Please see [doc/vim-go.txt](doc/vim-go.txt) for more
|
||||
information.
|
||||
|
||||
## Install
|
||||
|
||||
The [**latest stable release**](https://github.com/fatih/vim-go/releases/latest) is the
|
||||
recommended version to use. If you choose to use the master branch instead,
|
||||
please do so with caution; it is a _development_ branch.
|
||||
|
||||
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)
|
||||
* `git clone https://github.com/fatih/vim-go.git ~/.vim/bundle/vim-go`
|
||||
* [vim-plug](https://github.com/junegunn/vim-plug)
|
||||
* `Plug 'fatih/vim-go'`
|
||||
|
||||
You will also need to install all the necessary binaries. vim-go makes it easy
|
||||
to install all of them by providing a command, `:GoInstallBinaries`, which will
|
||||
`go get` all the required binaries.
|
||||
|
||||
Check out the Install section in [the documentation](doc/vim-go.txt) for more
|
||||
detailed instructions (`:help go-install`).
|
||||
|
||||
## Usage
|
||||
|
||||
The full documentation can be found at [doc/vim-go.txt](doc/vim-go.txt). You can
|
||||
display it from within Vim with `:help vim-go`.
|
||||
|
||||
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`).
|
||||
|
||||
We also have an [official vim-go tutorial](https://github.com/fatih/vim-go-tutorial).
|
||||
|
||||
## License
|
||||
|
||||
The BSD 3-Clause License - see [`LICENSE`](LICENSE) for more details
|
6
pack/acp/start/vim-go/addon-info.json
Normal file
6
pack/acp/start/vim-go/addon-info.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "vim-go",
|
||||
"description": "Full featured Go (golang) support for Vim.",
|
||||
"author": "Fatih Arslan <fatih@arslan.io>",
|
||||
"repository" : {"type": "git", "url": "https://github.com/fatih/vim-go.git"}
|
||||
}
|
BIN
pack/acp/start/vim-go/assets/vim-go.png
Normal file
BIN
pack/acp/start/vim-go/assets/vim-go.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
821
pack/acp/start/vim-go/assets/vim-go.svg
Normal file
821
pack/acp/start/vim-go/assets/vim-go.svg
Normal file
|
@ -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 |
155
pack/acp/start/vim-go/autoload/ctrlp/decls.vim
Normal file
155
pack/acp/start/vim-go/autoload/ctrlp/decls.vim
Normal file
|
@ -0,0 +1,155 @@
|
|||
let s:go_decls_var = {
|
||||
\ 'init': 'ctrlp#decls#init()',
|
||||
\ 'exit': 'ctrlp#decls#exit()',
|
||||
\ 'enter': 'ctrlp#decls#enter()',
|
||||
\ 'accept': 'ctrlp#decls#accept',
|
||||
\ 'lname': 'declarations',
|
||||
\ 'sname': 'decls',
|
||||
\ 'type': 'tabs',
|
||||
\}
|
||||
|
||||
if exists('g:ctrlp_ext_vars') && !empty(g:ctrlp_ext_vars)
|
||||
let g:ctrlp_ext_vars = add(g:ctrlp_ext_vars, s:go_decls_var)
|
||||
else
|
||||
let g:ctrlp_ext_vars = [s:go_decls_var]
|
||||
endif
|
||||
|
||||
function! ctrlp#decls#init() abort
|
||||
cal s:enable_syntax()
|
||||
return s:decls
|
||||
endfunction
|
||||
|
||||
function! ctrlp#decls#exit() abort
|
||||
unlet! s:decls s:current_dir s:target
|
||||
endfunction
|
||||
|
||||
" The action to perform on the selected string
|
||||
" Arguments:
|
||||
" a:mode the mode that has been chosen by pressing <cr> <c-v> <c-t> or <c-x>
|
||||
" the values are 'e', 'v', 't' and 'h', respectively
|
||||
" a:str the selected string
|
||||
function! ctrlp#decls#accept(mode, str) abort
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
let dir = getcwd()
|
||||
try
|
||||
" we jump to the file directory so we can get the fullpath via fnamemodify
|
||||
" below
|
||||
execute cd . s:current_dir
|
||||
|
||||
let vals = matchlist(a:str, '|\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)|')
|
||||
|
||||
" i.e: main.go
|
||||
let filename = vals[1]
|
||||
let line = vals[2]
|
||||
let col = vals[3]
|
||||
|
||||
" i.e: /Users/fatih/vim-go/main.go
|
||||
let filepath = fnamemodify(filename, ":p")
|
||||
|
||||
" acceptile is a very versatile method,
|
||||
call ctrlp#acceptfile(a:mode, filepath)
|
||||
call cursor(line, col)
|
||||
silent! norm! zvzz
|
||||
finally
|
||||
"jump back to old dir
|
||||
execute cd . fnameescape(dir)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! ctrlp#decls#enter() abort
|
||||
let s:current_dir = fnameescape(expand('%:p:h'))
|
||||
let s:decls = []
|
||||
|
||||
let bin_path = go#path#CheckBinPath('motion')
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
let command = printf("%s -format vim -mode decls", bin_path)
|
||||
let command .= " -include ". get(g:, "go_decls_includes", "func,type")
|
||||
|
||||
call go#cmd#autowrite()
|
||||
|
||||
if s:mode == 0
|
||||
" current file mode
|
||||
let fname = expand("%:p")
|
||||
if exists('s:target')
|
||||
let fname = s:target
|
||||
endif
|
||||
|
||||
let command .= printf(" -file %s", fname)
|
||||
else
|
||||
" all functions mode
|
||||
let dir = expand("%:p:h")
|
||||
if exists('s:target')
|
||||
let dir = s:target
|
||||
endif
|
||||
|
||||
let command .= printf(" -dir %s", dir)
|
||||
endif
|
||||
|
||||
let out = go#util#System(command)
|
||||
if go#util#ShellError() != 0
|
||||
call go#util#EchoError(out)
|
||||
return
|
||||
endif
|
||||
|
||||
let result = eval(out)
|
||||
if type(result) != 4 || !has_key(result, 'decls')
|
||||
return
|
||||
endif
|
||||
|
||||
let decls = result.decls
|
||||
|
||||
" find the maximum function name
|
||||
let max_len = 0
|
||||
for decl in decls
|
||||
if len(decl.ident)> max_len
|
||||
let max_len = len(decl.ident)
|
||||
endif
|
||||
endfor
|
||||
|
||||
for decl in decls
|
||||
" paddings
|
||||
let space = " "
|
||||
for i in range(max_len - len(decl.ident))
|
||||
let space .= " "
|
||||
endfor
|
||||
|
||||
call add(s:decls, printf("%s\t%s |%s:%s:%s|\t%s",
|
||||
\ decl.ident . space,
|
||||
\ decl.keyword,
|
||||
\ fnamemodify(decl.filename, ":t"),
|
||||
\ decl.line,
|
||||
\ decl.col,
|
||||
\ decl.full,
|
||||
\))
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
function! s:enable_syntax() abort
|
||||
if !(has('syntax') && exists('g:syntax_on'))
|
||||
return
|
||||
endif
|
||||
|
||||
syntax match CtrlPIdent '\zs\h\+\ze\s'
|
||||
syntax match CtrlPKeyword '\zs[^\t|]\+\ze|[^|]\+:\d\+:\d\+|'
|
||||
syntax match CtrlPFilename '|\zs[^|]\+:\d\+:\d\+\ze|'
|
||||
syntax match CtrlPSignature '\zs\t.*\ze$' contains=CtrlPKeyWord,CtrlPFilename
|
||||
|
||||
highlight link CtrlPIdent Function
|
||||
highlight link CtrlPKeyword Keyword
|
||||
highlight link CtrlPFilename SpecialComment
|
||||
highlight link CtrlPSignature Comment
|
||||
endfunction
|
||||
|
||||
let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars)
|
||||
|
||||
function! ctrlp#decls#cmd(mode, ...) abort
|
||||
let s:mode = a:mode
|
||||
if a:0 && !empty(a:1)
|
||||
let s:target = a:1
|
||||
endif
|
||||
return s:id
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
150
pack/acp/start/vim-go/autoload/fzf/decls.vim
Normal file
150
pack/acp/start/vim-go/autoload/fzf/decls.vim
Normal file
|
@ -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
|
32
pack/acp/start/vim-go/autoload/go/alternate.vim
Normal file
32
pack/acp/start/vim-go/autoload/go/alternate.vim
Normal file
|
@ -0,0 +1,32 @@
|
|||
" By default use edit (current buffer view) to switch
|
||||
if !exists("g:go_alternate_mode")
|
||||
let g:go_alternate_mode = "edit"
|
||||
endif
|
||||
|
||||
" Test alternates between the implementation of code and the test code.
|
||||
function! go#alternate#Switch(bang, cmd) abort
|
||||
let file = expand('%')
|
||||
if empty(file)
|
||||
call go#util#EchoError("no buffer name")
|
||||
return
|
||||
elseif file =~# '^\f\+_test\.go$'
|
||||
let l:root = split(file, '_test.go$')[0]
|
||||
let l:alt_file = l:root . ".go"
|
||||
elseif file =~# '^\f\+\.go$'
|
||||
let l:root = split(file, ".go$")[0]
|
||||
let l:alt_file = l:root . '_test.go'
|
||||
else
|
||||
call go#util#EchoError("not a go file")
|
||||
return
|
||||
endif
|
||||
if !filereadable(alt_file) && !bufexists(alt_file) && !a:bang
|
||||
call go#util#EchoError("couldn't find ".alt_file)
|
||||
return
|
||||
elseif empty(a:cmd)
|
||||
execute ":" . g:go_alternate_mode . " " . alt_file
|
||||
else
|
||||
execute ":" . a:cmd . " " . alt_file
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
69
pack/acp/start/vim-go/autoload/go/asmfmt.vim
Normal file
69
pack/acp/start/vim-go/autoload/go/asmfmt.vim
Normal file
|
@ -0,0 +1,69 @@
|
|||
" asmfmt.vim: Vim command to format Go asm files with asmfmt
|
||||
" (github.com/klauspost/asmfmt).
|
||||
"
|
||||
" This filetype plugin adds new commands for asm buffers:
|
||||
"
|
||||
" :Fmt
|
||||
"
|
||||
" Filter the current asm buffer through asmfmt.
|
||||
" It tries to preserve cursor position and avoids
|
||||
" replacing the buffer with stderr output.
|
||||
"
|
||||
" Options:
|
||||
"
|
||||
" g:go_asmfmt_autosave [default=0]
|
||||
"
|
||||
" Flag to automatically call :Fmt when file is saved.
|
||||
|
||||
let s:got_fmt_error = 0
|
||||
|
||||
" This is a trimmed-down version of the logic in fmt.vim.
|
||||
|
||||
function! go#asmfmt#Format() abort
|
||||
" Save state.
|
||||
let l:curw = winsaveview()
|
||||
|
||||
" Write the current buffer to a tempfile.
|
||||
let l:tmpname = tempname()
|
||||
call writefile(go#util#GetLines(), l:tmpname)
|
||||
|
||||
" Run asmfmt.
|
||||
let path = go#path#CheckBinPath("asmfmt")
|
||||
if empty(path)
|
||||
return
|
||||
endif
|
||||
let out = go#util#System(path . ' -w ' . l:tmpname)
|
||||
|
||||
" If there's no error, replace the current file with the output.
|
||||
if go#util#ShellError() == 0
|
||||
" Remove undo point caused by BufWritePre.
|
||||
try | silent undojoin | catch | endtry
|
||||
|
||||
" Replace the current file with the temp file; then reload the buffer.
|
||||
let old_fileformat = &fileformat
|
||||
" save old file permissions
|
||||
let original_fperm = getfperm(expand('%'))
|
||||
call rename(l:tmpname, expand('%'))
|
||||
" restore old file permissions
|
||||
call setfperm(expand('%'), original_fperm)
|
||||
silent edit!
|
||||
let &fileformat = old_fileformat
|
||||
let &syntax = &syntax
|
||||
endif
|
||||
|
||||
" Restore the cursor/window positions.
|
||||
call winrestview(l:curw)
|
||||
endfunction
|
||||
|
||||
function! go#asmfmt#ToggleAsmFmtAutoSave() abort
|
||||
if get(g:, "go_asmfmt_autosave", 0)
|
||||
let g:go_asmfmt_autosave = 1
|
||||
call go#util#EchoProgress("auto asmfmt enabled")
|
||||
return
|
||||
end
|
||||
|
||||
let g:go_asmfmt_autosave = 0
|
||||
call go#util#EchoProgress("auto asmfmt disabled")
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
312
pack/acp/start/vim-go/autoload/go/cmd.vim
Normal file
312
pack/acp/start/vim-go/autoload/go/cmd.vim
Normal file
|
@ -0,0 +1,312 @@
|
|||
function! go#cmd#autowrite() abort
|
||||
if &autowrite == 1 || &autowriteall == 1
|
||||
silent! wall
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Build builds the source code without producing any output binary. We live in
|
||||
" an editor so the best is to build it to catch errors and fix them. By
|
||||
" default it tries to call simply 'go build', but it first tries to get all
|
||||
" dependent files for the current folder and passes it to go build.
|
||||
function! go#cmd#Build(bang, ...) abort
|
||||
" Create our command arguments. go build discards any results when it
|
||||
" compiles multiple packages. So we pass the `errors` package just as an
|
||||
" placeholder with the current folder (indicated with '.'). We also pass -i
|
||||
" 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)") +
|
||||
\ [".", "errors"]
|
||||
|
||||
" Vim async.
|
||||
if go#util#has_job()
|
||||
if get(g:, 'go_echo_command_info', 1)
|
||||
call go#util#EchoProgress("building dispatched ...")
|
||||
endif
|
||||
|
||||
call s:cmd_job({
|
||||
\ 'cmd': ['go'] + args,
|
||||
\ 'bang': a:bang,
|
||||
\ 'for': 'GoBuild',
|
||||
\})
|
||||
|
||||
" Nvim async.
|
||||
elseif has('nvim')
|
||||
if get(g:, 'go_echo_command_info', 1)
|
||||
call go#util#EchoProgress("building dispatched ...")
|
||||
endif
|
||||
|
||||
call go#jobcontrol#Spawn(a:bang, "build", "GoBuild", args)
|
||||
|
||||
" Vim 7.4 without async
|
||||
else
|
||||
let default_makeprg = &makeprg
|
||||
let &makeprg = "go " . join(go#util#Shelllist(args), ' ')
|
||||
|
||||
let l:listtype = go#list#Type("GoBuild")
|
||||
" execute make inside the source folder so we can parse the errors
|
||||
" correctly
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
let dir = getcwd()
|
||||
try
|
||||
execute cd . fnameescape(expand("%:p:h"))
|
||||
if l:listtype == "locationlist"
|
||||
silent! exe 'lmake!'
|
||||
else
|
||||
silent! exe 'make!'
|
||||
endif
|
||||
redraw!
|
||||
finally
|
||||
execute cd . fnameescape(dir)
|
||||
endtry
|
||||
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors) && !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
else
|
||||
call go#util#EchoSuccess("[build] SUCCESS")
|
||||
endif
|
||||
|
||||
let &makeprg = default_makeprg
|
||||
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
|
||||
|
||||
|
||||
" Run runs the current file (and their dependencies if any) in a new terminal.
|
||||
function! go#cmd#RunTerm(bang, mode, files) abort
|
||||
if empty(a:files)
|
||||
let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
|
||||
else
|
||||
let cmd = "go run ". go#util#Shelljoin(map(copy(a:files), "expand(v:val)"), 1)
|
||||
endif
|
||||
call go#term#newmode(a:bang, cmd, a:mode)
|
||||
endfunction
|
||||
|
||||
" Run runs the current file (and their dependencies if any) and outputs it.
|
||||
" This is intended to test small programs and play with them. It's not
|
||||
" suitable for long running apps, because vim is blocking by default and
|
||||
" calling long running apps will block the whole UI.
|
||||
function! go#cmd#Run(bang, ...) abort
|
||||
if has('nvim')
|
||||
call go#cmd#RunTerm(a:bang, '', a:000)
|
||||
return
|
||||
endif
|
||||
|
||||
if go#util#has_job()
|
||||
" NOTE(arslan): 'term': 'open' case is not implement for +jobs. This means
|
||||
" executions waiting for stdin will not work. That's why we don't do
|
||||
" anything. Once this is implemented we're going to make :GoRun async
|
||||
endif
|
||||
|
||||
if go#util#IsWin()
|
||||
exec '!go run ' . go#util#Shelljoin(go#tool#Files())
|
||||
if v:shell_error
|
||||
redraws! | echon "vim-go: [run] " | echohl ErrorMsg | echon "FAILED"| echohl None
|
||||
else
|
||||
redraws! | echon "vim-go: [run] " | echohl Function | echon "SUCCESS"| echohl None
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
" :make expands '%' and '#' wildcards, so they must also be escaped
|
||||
let default_makeprg = &makeprg
|
||||
if a:0 == 0
|
||||
let &makeprg = 'go run ' . go#util#Shelljoin(go#tool#Files(), 1)
|
||||
else
|
||||
let &makeprg = "go run " . go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
|
||||
endif
|
||||
|
||||
let l:listtype = go#list#Type("GoRun")
|
||||
|
||||
if l:listtype == "locationlist"
|
||||
exe 'lmake!'
|
||||
else
|
||||
exe 'make!'
|
||||
endif
|
||||
|
||||
let items = go#list#Get(l:listtype)
|
||||
let errors = go#tool#FilterValids(items)
|
||||
|
||||
call go#list#Populate(l:listtype, errors, &makeprg)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors) && !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
|
||||
let &makeprg = default_makeprg
|
||||
endfunction
|
||||
|
||||
" Install installs the package by simple calling 'go install'. If any argument
|
||||
" is given(which are passed directly to 'go install') it tries to install
|
||||
" those packages. Errors are populated in the location window.
|
||||
function! go#cmd#Install(bang, ...) abort
|
||||
" use vim's job functionality to call it asynchronously
|
||||
if go#util#has_job()
|
||||
" expand all wildcards(i.e: '%' to the current file name)
|
||||
let goargs = map(copy(a:000), "expand(v:val)")
|
||||
|
||||
if get(g:, 'go_echo_command_info', 1)
|
||||
call go#util#EchoProgress("installing dispatched ...")
|
||||
endif
|
||||
|
||||
call s:cmd_job({
|
||||
\ 'cmd': ['go', 'install'] + goargs,
|
||||
\ 'bang': a:bang,
|
||||
\ 'for': 'GoInstall',
|
||||
\})
|
||||
return
|
||||
endif
|
||||
|
||||
let default_makeprg = &makeprg
|
||||
|
||||
" :make expands '%' and '#' wildcards, so they must also be escaped
|
||||
let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
|
||||
let &makeprg = "go install " . goargs
|
||||
|
||||
let l:listtype = go#list#Type("GoInstall")
|
||||
" execute make inside the source folder so we can parse the errors
|
||||
" correctly
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
let dir = getcwd()
|
||||
try
|
||||
execute cd . fnameescape(expand("%:p:h"))
|
||||
if l:listtype == "locationlist"
|
||||
silent! exe 'lmake!'
|
||||
else
|
||||
silent! exe 'make!'
|
||||
endif
|
||||
redraw!
|
||||
finally
|
||||
execute cd . fnameescape(dir)
|
||||
endtry
|
||||
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors) && !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
else
|
||||
call go#util#EchoSuccess("installed to ". go#path#Default())
|
||||
endif
|
||||
|
||||
let &makeprg = default_makeprg
|
||||
endfunction
|
||||
|
||||
" Generate runs 'go generate' in similar fashion to go#cmd#Build()
|
||||
function! go#cmd#Generate(bang, ...) abort
|
||||
let default_makeprg = &makeprg
|
||||
|
||||
" :make expands '%' and '#' wildcards, so they must also be escaped
|
||||
let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
|
||||
if go#util#ShellError() != 0
|
||||
let &makeprg = "go generate " . goargs
|
||||
else
|
||||
let gofiles = go#util#Shelljoin(go#tool#Files(), 1)
|
||||
let &makeprg = "go generate " . goargs . ' ' . gofiles
|
||||
endif
|
||||
|
||||
let l:listtype = go#list#Type("GoGenerate")
|
||||
|
||||
echon "vim-go: " | echohl Identifier | echon "generating ..."| echohl None
|
||||
if l:listtype == "locationlist"
|
||||
silent! exe 'lmake!'
|
||||
else
|
||||
silent! exe 'make!'
|
||||
endif
|
||||
redraw!
|
||||
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors)
|
||||
if !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
else
|
||||
redraws! | echon "vim-go: " | echohl Function | echon "[generate] SUCCESS"| echohl None
|
||||
endif
|
||||
|
||||
let &makeprg = default_makeprg
|
||||
endfunction
|
||||
|
||||
" ---------------------
|
||||
" | Vim job callbacks |
|
||||
" ---------------------
|
||||
|
||||
function s:cmd_job(args) abort
|
||||
let status_dir = expand('%:p:h')
|
||||
let started_at = reltime()
|
||||
|
||||
call go#statusline#Update(status_dir, {
|
||||
\ 'desc': "current status",
|
||||
\ 'type': a:args.cmd[1],
|
||||
\ 'state': "started",
|
||||
\})
|
||||
|
||||
" autowrite is not enabled for jobs
|
||||
call go#cmd#autowrite()
|
||||
|
||||
function! s:complete(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.complete = funcref('s:complete')
|
||||
let callbacks = go#job#Spawn(a:args)
|
||||
|
||||
let start_options = {
|
||||
\ 'callback': callbacks.callback,
|
||||
\ 'exit_cb': callbacks.exit_cb,
|
||||
\ 'close_cb': callbacks.close_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
|
30
pack/acp/start/vim-go/autoload/go/cmd_test.vim
Normal file
30
pack/acp/start/vim-go/autoload/go/cmd_test.vim
Normal file
|
@ -0,0 +1,30 @@
|
|||
func! Test_GoBuildErrors()
|
||||
try
|
||||
let l:filename = 'cmd/bad.go'
|
||||
let l:tmp = gotest#load_fixture(l:filename)
|
||||
exe 'cd ' . l:tmp . '/src/cmd'
|
||||
|
||||
" set the compiler type so that the errorformat option will be set
|
||||
" correctly.
|
||||
compiler go
|
||||
|
||||
let expected = [{'lnum': 4, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'undefined: notafunc'}]
|
||||
" clear the quickfix lists
|
||||
call setqflist([], 'r')
|
||||
|
||||
call go#cmd#Build(1)
|
||||
|
||||
let actual = getqflist()
|
||||
let start = reltime()
|
||||
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||
sleep 100m
|
||||
let actual = getqflist()
|
||||
endwhile
|
||||
|
||||
call gotest#assert_quickfix(actual, l:expected)
|
||||
finally
|
||||
call delete(l:tmp, 'rf')
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
" vim: sw=2 ts=2 et
|
265
pack/acp/start/vim-go/autoload/go/complete.vim
Normal file
265
pack/acp/start/vim-go/autoload/go/complete.vim
Normal file
|
@ -0,0 +1,265 @@
|
|||
let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix'
|
||||
|
||||
function! s:gocodeCommand(cmd, args) abort
|
||||
let bin_path = go#path#CheckBinPath("gocode")
|
||||
if empty(bin_path)
|
||||
return []
|
||||
endif
|
||||
|
||||
let socket_type = get(g:, 'go_gocode_socket_type', s:sock_type)
|
||||
|
||||
let cmd = [bin_path]
|
||||
let cmd = extend(cmd, ['-sock', socket_type])
|
||||
let cmd = extend(cmd, ['-f', 'vim'])
|
||||
let cmd = extend(cmd, [a:cmd])
|
||||
let cmd = extend(cmd, a:args)
|
||||
|
||||
return cmd
|
||||
endfunction
|
||||
|
||||
function! s:sync_gocode(cmd, args, input) abort
|
||||
" We might hit cache problems, as gocode doesn't handle different GOPATHs
|
||||
" well. See: https://github.com/nsf/gocode/issues/239
|
||||
let old_goroot = $GOROOT
|
||||
let $GOROOT = go#util#env("goroot")
|
||||
|
||||
try
|
||||
let cmd = s:gocodeCommand(a:cmd, a:args)
|
||||
" gocode can sometimes be slow, so redraw now to avoid waiting for gocode
|
||||
" to return before redrawing automatically.
|
||||
redraw
|
||||
|
||||
let [l:result, l:err] = go#util#Exec(cmd, a:input)
|
||||
finally
|
||||
let $GOROOT = old_goroot
|
||||
endtry
|
||||
|
||||
if l:err != 0
|
||||
return "[0, []]"
|
||||
endif
|
||||
|
||||
if &encoding != 'utf-8'
|
||||
let l:result = iconv(l:result, 'utf-8', &encoding)
|
||||
endif
|
||||
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
" TODO(bc): reset when gocode isn't running
|
||||
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()
|
||||
|
||||
" use the offset as is, because the cursor position is the position for
|
||||
" which autocomplete candidates are needed.
|
||||
return s:sync_gocode('autocomplete',
|
||||
\ [expand('%:p'), go#util#OffsetCursor()],
|
||||
\ go#util#GetLines())
|
||||
endfunction
|
||||
|
||||
" go#complete#GoInfo returns the description of the identifier under the
|
||||
" cursor.
|
||||
function! go#complete#GetInfo() abort
|
||||
return s:sync_info(0)
|
||||
endfunction
|
||||
|
||||
function! go#complete#Info(auto) abort
|
||||
if go#util#has_job()
|
||||
return s:async_info(a:auto)
|
||||
else
|
||||
return s:sync_info(a:auto)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:async_info(auto)
|
||||
if exists("s:async_info_job")
|
||||
call job_stop(s:async_info_job)
|
||||
unlet s:async_info_job
|
||||
endif
|
||||
|
||||
let state = {
|
||||
\ 'exited': 0,
|
||||
\ 'exit_status': 0,
|
||||
\ 'closed': 0,
|
||||
\ 'messages': [],
|
||||
\ 'auto': a:auto
|
||||
\ }
|
||||
|
||||
function! s:callback(chan, msg) dict
|
||||
let l:msg = a:msg
|
||||
if &encoding != 'utf-8'
|
||||
let l:msg = iconv(l:msg, 'utf-8', &encoding)
|
||||
endif
|
||||
call add(self.messages, l:msg)
|
||||
endfunction
|
||||
|
||||
function! s:exit_cb(job, exitval) dict
|
||||
let self.exit_status = a:exitval
|
||||
let self.exited = 1
|
||||
|
||||
if self.closed
|
||||
call self.complete()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_cb(ch) dict
|
||||
let self.closed = 1
|
||||
if self.exited
|
||||
call self.complete()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function state.complete() dict
|
||||
if self.exit_status != 0
|
||||
return
|
||||
endif
|
||||
|
||||
let result = s:info_filter(self.auto, join(self.messages, "\n"))
|
||||
call s:info_complete(self.auto, result)
|
||||
endfunction
|
||||
|
||||
" add 1 to the offset, so that the position at the cursor will be included
|
||||
" in gocode's search
|
||||
let offset = go#util#OffsetCursor()+1
|
||||
|
||||
" We might hit cache problems, as gocode doesn't handle different GOPATHs
|
||||
" well. See: https://github.com/nsf/gocode/issues/239
|
||||
let env = {
|
||||
\ "GOROOT": go#util#env("goroot")
|
||||
\ }
|
||||
|
||||
let cmd = s:gocodeCommand('autocomplete',
|
||||
\ [expand('%:p'), offset])
|
||||
|
||||
" TODO(bc): Don't write the buffer to a file; pass the buffer directrly to
|
||||
" gocode's stdin. It shouldn't be necessary to use {in_io: 'file', in_name:
|
||||
" s:gocodeFile()}, but unfortunately {in_io: 'buffer', in_buf: bufnr('%')}
|
||||
" should work.
|
||||
let options = {
|
||||
\ 'env': env,
|
||||
\ 'in_io': 'file',
|
||||
\ 'in_name': s:gocodeFile(),
|
||||
\ 'callback': funcref("s:callback", [], state),
|
||||
\ 'exit_cb': funcref("s:exit_cb", [], state),
|
||||
\ 'close_cb': funcref("s:close_cb", [], state)
|
||||
\ }
|
||||
|
||||
let s:async_info_job = job_start(cmd, options)
|
||||
endfunction
|
||||
|
||||
function! s:gocodeFile()
|
||||
let file = tempname()
|
||||
call writefile(go#util#GetLines(), file)
|
||||
return file
|
||||
endfunction
|
||||
|
||||
function! s:sync_info(auto)
|
||||
" auto is true if we were called by g:go_auto_type_info's autocmd
|
||||
|
||||
" add 1 to the offset, so that the position at the cursor will be included
|
||||
" in gocode's search
|
||||
let offset = go#util#OffsetCursor()+1
|
||||
|
||||
let result = s:sync_gocode('autocomplete',
|
||||
\ [expand('%:p'), offset],
|
||||
\ go#util#GetLines())
|
||||
|
||||
let result = s:info_filter(a:auto, result)
|
||||
call s:info_complete(a:auto, result)
|
||||
endfunction
|
||||
|
||||
function! s:info_filter(auto, result) abort
|
||||
if empty(a:result)
|
||||
return ""
|
||||
endif
|
||||
|
||||
let l:result = eval(a:result)
|
||||
if len(l:result) != 2
|
||||
return ""
|
||||
endif
|
||||
|
||||
let l:candidates = l:result[1]
|
||||
if len(l:candidates) == 1
|
||||
" When gocode panics in vim mode, it returns
|
||||
" [0, [{'word': 'PANIC', 'abbr': 'PANIC PANIC PANIC', 'info': 'PANIC PANIC PANIC'}]]
|
||||
if a:auto && l:candidates[0].info ==# "PANIC PANIC PANIC"
|
||||
return ""
|
||||
endif
|
||||
|
||||
return l:candidates[0].info
|
||||
endif
|
||||
|
||||
let filtered = []
|
||||
let wordMatch = '\<' . expand("<cword>") . '\>'
|
||||
" escape single quotes in wordMatch before passing it to filter
|
||||
let wordMatch = substitute(wordMatch, "'", "''", "g")
|
||||
let filtered = filter(l:candidates, "v:val.info =~ '".wordMatch."'")
|
||||
|
||||
if len(l:filtered) != 1
|
||||
return ""
|
||||
endif
|
||||
|
||||
return l:filtered[0].info
|
||||
endfunction
|
||||
|
||||
function! s:info_complete(auto, result) abort
|
||||
if !empty(a:result)
|
||||
echo "vim-go: " | echohl Function | echon a:result | echohl None
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:trim_bracket(val) abort
|
||||
let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '')
|
||||
return a:val
|
||||
endfunction
|
||||
|
||||
let s:completions = ""
|
||||
function! go#complete#Complete(findstart, base) abort
|
||||
"findstart = 1 when we need to get the text length
|
||||
if a:findstart == 1
|
||||
execute "silent let s:completions = " . s:gocodeAutocomplete()
|
||||
return col('.') - s:completions[0] - 1
|
||||
"findstart = 0 when we need to return the list of completions
|
||||
else
|
||||
let s = getline(".")[col('.') - 1]
|
||||
if s =~ '[(){}\{\}]'
|
||||
return map(copy(s:completions[1]), 's:trim_bracket(v:val)')
|
||||
endif
|
||||
|
||||
return s:completions[1]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
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
|
378
pack/acp/start/vim-go/autoload/go/coverage.vim
Normal file
378
pack/acp/start/vim-go/autoload/go/coverage.vim
Normal file
|
@ -0,0 +1,378 @@
|
|||
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)
|
||||
call go#util#EchoProgress("testing...")
|
||||
endif
|
||||
|
||||
if go#util#has_job()
|
||||
call s:coverage_job({
|
||||
\ 'cmd': ['go', 'test', '-coverprofile', l:tmpname] + a:000,
|
||||
\ 'complete': 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],
|
||||
\ 'complete': 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')
|
||||
let Complete = a:args.complete
|
||||
function! s:complete(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)
|
||||
return Complete(a:job, a:exit_status, a:data)
|
||||
endfunction
|
||||
|
||||
let a:args.complete = funcref('s:complete')
|
||||
let callbacks = go#job#Spawn(a:args)
|
||||
|
||||
let start_options = {
|
||||
\ 'callback': callbacks.callback,
|
||||
\ 'exit_cb': callbacks.exit_cb,
|
||||
\ 'close_cb': callbacks.close_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
|
904
pack/acp/start/vim-go/autoload/go/debug.vim
Normal file
904
pack/acp/start/vim-go/autoload/go/debug.vim
Normal file
|
@ -0,0 +1,904 @@
|
|||
scriptencoding utf-8
|
||||
|
||||
if !exists('g:go_debug_windows')
|
||||
let g:go_debug_windows = {
|
||||
\ 'stack': 'leftabove 20vnew',
|
||||
\ 'out': 'botright 10new',
|
||||
\ 'vars': 'leftabove 30vnew',
|
||||
\ }
|
||||
endif
|
||||
|
||||
if !exists('g:go_debug_address')
|
||||
let g:go_debug_address = '127.0.0.1:8181'
|
||||
endif
|
||||
|
||||
if !exists('s:state')
|
||||
let s:state = {
|
||||
\ 'rpcid': 1,
|
||||
\ 'running': 0,
|
||||
\ 'breakpoint': {},
|
||||
\ 'currentThread': {},
|
||||
\ 'localVars': {},
|
||||
\ 'functionArgs': {},
|
||||
\ 'message': [],
|
||||
\ 'is_test': 0,
|
||||
\}
|
||||
|
||||
if go#util#HasDebug('debugger-state')
|
||||
let g:go_debug_diag = s:state
|
||||
endif
|
||||
endif
|
||||
|
||||
if !exists('s:start_args')
|
||||
let s:start_args = []
|
||||
endif
|
||||
|
||||
function! s:groutineID() abort
|
||||
return s:state['currentThread'].goroutineID
|
||||
endfunction
|
||||
|
||||
function! s:exit(job, status) abort
|
||||
if has_key(s:state, 'job')
|
||||
call remove(s:state, 'job')
|
||||
endif
|
||||
call s:clearState()
|
||||
if a:status > 0
|
||||
call go#util#EchoError(s:state['message'])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:logger(prefix, ch, msg) abort
|
||||
let l:cur_win = bufwinnr('')
|
||||
let l:log_win = bufwinnr(bufnr('__GODEBUG_OUTPUT__'))
|
||||
if l:log_win == -1
|
||||
return
|
||||
endif
|
||||
exe l:log_win 'wincmd w'
|
||||
|
||||
try
|
||||
setlocal modifiable
|
||||
if getline(1) == ''
|
||||
call setline('$', a:prefix . a:msg)
|
||||
else
|
||||
call append('$', a:prefix . a:msg)
|
||||
endif
|
||||
normal! G
|
||||
setlocal nomodifiable
|
||||
finally
|
||||
exe l:cur_win 'wincmd w'
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:call_jsonrpc(method, ...) abort
|
||||
if go#util#HasDebug('debugger-commands')
|
||||
if !exists('g:go_debug_commands')
|
||||
let g:go_debug_commands = []
|
||||
endif
|
||||
echom 'sending to dlv ' . a:method
|
||||
endif
|
||||
|
||||
if len(a:000) > 0 && type(a:000[0]) == v:t_func
|
||||
let Cb = a:000[0]
|
||||
let args = a:000[1:]
|
||||
else
|
||||
let Cb = v:none
|
||||
let args = a:000
|
||||
endif
|
||||
let s:state['rpcid'] += 1
|
||||
let req_json = json_encode({
|
||||
\ 'id': s:state['rpcid'],
|
||||
\ 'method': a:method,
|
||||
\ 'params': args,
|
||||
\})
|
||||
|
||||
try
|
||||
" Use callback
|
||||
if type(Cb) == v:t_func
|
||||
let s:ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'callback': Cb})
|
||||
call ch_sendraw(s:ch, req_json)
|
||||
|
||||
if go#util#HasDebug('debugger-commands')
|
||||
let g:go_debug_commands = add(g:go_debug_commands, {
|
||||
\ 'request': req_json,
|
||||
\ 'response': Cb,
|
||||
\ })
|
||||
endif
|
||||
return
|
||||
endif
|
||||
|
||||
let ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'timeout': 20000})
|
||||
call ch_sendraw(ch, req_json)
|
||||
let resp_json = ch_readraw(ch)
|
||||
|
||||
if go#util#HasDebug('debugger-commands')
|
||||
let g:go_debug_commands = add(g:go_debug_commands, {
|
||||
\ 'request': req_json,
|
||||
\ 'response': resp_json,
|
||||
\ })
|
||||
endif
|
||||
|
||||
let obj = json_decode(resp_json)
|
||||
if type(obj) == v:t_dict && has_key(obj, 'error') && !empty(obj.error)
|
||||
throw obj.error
|
||||
endif
|
||||
return obj
|
||||
catch
|
||||
throw substitute(v:exception, '^Vim', '', '')
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Update the location of the current breakpoint or line we're halted on based on
|
||||
" response from dlv.
|
||||
function! s:update_breakpoint(res) abort
|
||||
if type(a:res) ==# v:t_none
|
||||
return
|
||||
endif
|
||||
|
||||
let state = a:res.result.State
|
||||
if !has_key(state, 'currentThread')
|
||||
return
|
||||
endif
|
||||
|
||||
let s:state['currentThread'] = state.currentThread
|
||||
let bufs = filter(map(range(1, winnr('$')), '[v:val,bufname(winbufnr(v:val))]'), 'v:val[1]=~"\.go$"')
|
||||
if len(bufs) == 0
|
||||
return
|
||||
endif
|
||||
|
||||
exe bufs[0][0] 'wincmd w'
|
||||
let filename = state.currentThread.file
|
||||
let linenr = state.currentThread.line
|
||||
let oldfile = fnamemodify(expand('%'), ':p:gs!\\!/!')
|
||||
if oldfile != filename
|
||||
silent! exe 'edit' filename
|
||||
endif
|
||||
silent! exe 'norm!' linenr.'G'
|
||||
silent! normal! zvzz
|
||||
silent! sign unplace 9999
|
||||
silent! exe 'sign place 9999 line=' . linenr . ' name=godebugcurline file=' . filename
|
||||
endfunction
|
||||
|
||||
" Populate the stacktrace window.
|
||||
function! s:show_stacktrace(res) abort
|
||||
if !has_key(a:res, 'result')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:stack_win = bufwinnr(bufnr('__GODEBUG_STACKTRACE__'))
|
||||
if l:stack_win == -1
|
||||
return
|
||||
endif
|
||||
|
||||
let l:cur_win = bufwinnr('')
|
||||
exe l:stack_win 'wincmd w'
|
||||
|
||||
try
|
||||
setlocal modifiable
|
||||
silent %delete _
|
||||
for i in range(len(a:res.result.Locations))
|
||||
let loc = a:res.result.Locations[i]
|
||||
call setline(i+1, printf('%s - %s:%d', loc.function.name, fnamemodify(loc.file, ':p'), loc.line))
|
||||
endfor
|
||||
finally
|
||||
setlocal nomodifiable
|
||||
exe l:cur_win 'wincmd w'
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Populate the variable window.
|
||||
function! s:show_variables() abort
|
||||
let l:var_win = bufwinnr(bufnr('__GODEBUG_VARIABLES__'))
|
||||
if l:var_win == -1
|
||||
return
|
||||
endif
|
||||
|
||||
let l:cur_win = bufwinnr('')
|
||||
exe l:var_win 'wincmd w'
|
||||
|
||||
try
|
||||
setlocal modifiable
|
||||
silent %delete _
|
||||
|
||||
let v = []
|
||||
let v += ['# Local Variables']
|
||||
if type(get(s:state, 'localVars', [])) is type([])
|
||||
for c in s:state['localVars']
|
||||
let v += split(s:eval_tree(c, 0), "\n")
|
||||
endfor
|
||||
endif
|
||||
|
||||
let v += ['']
|
||||
let v += ['# Function Arguments']
|
||||
if type(get(s:state, 'functionArgs', [])) is type([])
|
||||
for c in s:state['functionArgs']
|
||||
let v += split(s:eval_tree(c, 0), "\n")
|
||||
endfor
|
||||
endif
|
||||
|
||||
call setline(1, v)
|
||||
finally
|
||||
setlocal nomodifiable
|
||||
exe l:cur_win 'wincmd w'
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:clearState() abort
|
||||
let s:state['currentThread'] = {}
|
||||
let s:state['localVars'] = {}
|
||||
let s:state['functionArgs'] = {}
|
||||
let s:state['message'] = []
|
||||
silent! sign unplace 9999
|
||||
endfunction
|
||||
|
||||
function! s:stop() abort
|
||||
call s:clearState()
|
||||
if has_key(s:state, 'job')
|
||||
call job_stop(s:state['job'])
|
||||
call remove(s:state, 'job')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! go#debug#Stop() abort
|
||||
" Remove signs.
|
||||
for k in keys(s:state['breakpoint'])
|
||||
let bt = s:state['breakpoint'][k]
|
||||
if bt.id >= 0
|
||||
silent exe 'sign unplace ' . bt.id
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Remove all commands and add back the default commands.
|
||||
for k in map(split(execute('command GoDebug'), "\n")[1:], 'matchstr(v:val, "^\\s*\\zs\\S\\+")')
|
||||
exe 'delcommand' k
|
||||
endfor
|
||||
command! -nargs=* -complete=customlist,go#package#Complete GoDebugStart call go#debug#Start(0, <f-args>)
|
||||
command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start(1, <f-args>)
|
||||
command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint(<f-args>)
|
||||
|
||||
" Remove all mappings.
|
||||
for k in map(split(execute('map <Plug>(go-debug-'), "\n")[1:], 'matchstr(v:val, "^n\\s\\+\\zs\\S\\+")')
|
||||
exe 'unmap' k
|
||||
endfor
|
||||
|
||||
call s:stop()
|
||||
|
||||
let bufs = filter(map(range(1, winnr('$')), '[v:val,bufname(winbufnr(v:val))]'), 'v:val[1]=~"\.go$"')
|
||||
if len(bufs) > 0
|
||||
exe bufs[0][0] 'wincmd w'
|
||||
else
|
||||
wincmd p
|
||||
endif
|
||||
silent! exe bufwinnr(bufnr('__GODEBUG_STACKTRACE__')) 'wincmd c'
|
||||
silent! exe bufwinnr(bufnr('__GODEBUG_VARIABLES__')) 'wincmd c'
|
||||
silent! exe bufwinnr(bufnr('__GODEBUG_OUTPUT__')) 'wincmd c'
|
||||
|
||||
set noballooneval
|
||||
set balloonexpr=
|
||||
endfunction
|
||||
|
||||
function! s:goto_file() abort
|
||||
let m = matchlist(getline('.'), ' - \(.*\):\([0-9]\+\)$')
|
||||
if m[1] == ''
|
||||
return
|
||||
endif
|
||||
let bufs = filter(map(range(1, winnr('$')), '[v:val,bufname(winbufnr(v:val))]'), 'v:val[1]=~"\.go$"')
|
||||
if len(bufs) == 0
|
||||
return
|
||||
endif
|
||||
exe bufs[0][0] 'wincmd w'
|
||||
let filename = m[1]
|
||||
let linenr = m[2]
|
||||
let oldfile = fnamemodify(expand('%'), ':p:gs!\\!/!')
|
||||
if oldfile != filename
|
||||
silent! exe 'edit' filename
|
||||
endif
|
||||
silent! exe 'norm!' linenr.'G'
|
||||
silent! normal! zvzz
|
||||
endfunction
|
||||
|
||||
function! s:delete_expands()
|
||||
let nr = line('.')
|
||||
while 1
|
||||
let l = getline(nr+1)
|
||||
if empty(l) || l =~ '^\S'
|
||||
return
|
||||
endif
|
||||
silent! exe (nr+1) . 'd _'
|
||||
endwhile
|
||||
silent! exe 'norm!' nr.'G'
|
||||
endfunction
|
||||
|
||||
function! s:expand_var() abort
|
||||
" Get name from struct line.
|
||||
let name = matchstr(getline('.'), '^[^:]\+\ze: [a-zA-Z0-9\.·]\+{\.\.\.}$')
|
||||
" Anonymous struct
|
||||
if name == ''
|
||||
let name = matchstr(getline('.'), '^[^:]\+\ze: struct {.\{-}}$')
|
||||
endif
|
||||
|
||||
if name != ''
|
||||
setlocal modifiable
|
||||
let not_open = getline(line('.')+1) !~ '^ '
|
||||
let l = line('.')
|
||||
call s:delete_expands()
|
||||
|
||||
if not_open
|
||||
call append(l, split(s:eval(name), "\n")[1:])
|
||||
endif
|
||||
silent! exe 'norm!' l.'G'
|
||||
setlocal nomodifiable
|
||||
return
|
||||
endif
|
||||
|
||||
" Expand maps
|
||||
let m = matchlist(getline('.'), '^[^:]\+\ze: map.\{-}\[\(\d\+\)\]$')
|
||||
if len(m) > 0 && m[1] != ''
|
||||
setlocal modifiable
|
||||
let not_open = getline(line('.')+1) !~ '^ '
|
||||
let l = line('.')
|
||||
call s:delete_expands()
|
||||
if not_open
|
||||
" TODO: Not sure how to do this yet... Need to get keys of the map.
|
||||
" let vs = ''
|
||||
" for i in range(0, min([10, m[1]-1]))
|
||||
" let vs .= ' ' . s:eval(printf("%s[%s]", m[0], ))
|
||||
" endfor
|
||||
" call append(l, split(vs, "\n"))
|
||||
endif
|
||||
|
||||
silent! exe 'norm!' l.'G'
|
||||
setlocal nomodifiable
|
||||
return
|
||||
endif
|
||||
|
||||
" Expand string.
|
||||
let m = matchlist(getline('.'), '^\([^:]\+\)\ze: \(string\)\[\([0-9]\+\)\]\(: .\{-}\)\?$')
|
||||
if len(m) > 0 && m[1] != ''
|
||||
setlocal modifiable
|
||||
let not_open = getline(line('.')+1) !~ '^ '
|
||||
let l = line('.')
|
||||
call s:delete_expands()
|
||||
|
||||
if not_open
|
||||
let vs = ''
|
||||
for i in range(0, min([10, m[3]-1]))
|
||||
let vs .= ' ' . s:eval(m[1] . '[' . i . ']')
|
||||
endfor
|
||||
call append(l, split(vs, "\n"))
|
||||
endif
|
||||
|
||||
silent! exe 'norm!' l.'G'
|
||||
setlocal nomodifiable
|
||||
return
|
||||
endif
|
||||
|
||||
" Expand slice.
|
||||
let m = matchlist(getline('.'), '^\([^:]\+\)\ze: \(\[\]\w\{-}\)\[\([0-9]\+\)\]$')
|
||||
if len(m) > 0 && m[1] != ''
|
||||
setlocal modifiable
|
||||
let not_open = getline(line('.')+1) !~ '^ '
|
||||
let l = line('.')
|
||||
call s:delete_expands()
|
||||
|
||||
if not_open
|
||||
let vs = ''
|
||||
for i in range(0, min([10, m[3]-1]))
|
||||
let vs .= ' ' . s:eval(m[1] . '[' . i . ']')
|
||||
endfor
|
||||
call append(l, split(vs, "\n"))
|
||||
endif
|
||||
silent! exe 'norm!' l.'G'
|
||||
setlocal nomodifiable
|
||||
return
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:start_cb(ch, json) abort
|
||||
let res = json_decode(a:json)
|
||||
if type(res) == v:t_dict && has_key(res, 'error') && !empty(res.error)
|
||||
throw res.error
|
||||
endif
|
||||
if empty(res) || !has_key(res, 'result')
|
||||
return
|
||||
endif
|
||||
for bt in res.result.Breakpoints
|
||||
if bt.id >= 0
|
||||
let s:state['breakpoint'][bt.id] = bt
|
||||
exe 'sign place '. bt.id .' line=' . bt.line . ' name=godebugbreakpoint file=' . bt.file
|
||||
endif
|
||||
endfor
|
||||
|
||||
let oldbuf = bufnr('%')
|
||||
silent! only!
|
||||
|
||||
let winnum = bufwinnr(bufnr('__GODEBUG_STACKTRACE__'))
|
||||
if winnum != -1
|
||||
return
|
||||
endif
|
||||
|
||||
if exists('g:go_debug_windows["stack"]') && g:go_debug_windows['stack'] != ''
|
||||
exe 'silent ' . g:go_debug_windows['stack']
|
||||
silent file `='__GODEBUG_STACKTRACE__'`
|
||||
setlocal buftype=nofile bufhidden=wipe nomodified nobuflisted noswapfile nowrap nonumber nocursorline
|
||||
setlocal filetype=godebugstacktrace
|
||||
nmap <buffer> <cr> :<c-u>call <SID>goto_file()<cr>
|
||||
nmap <buffer> q <Plug>(go-debug-stop)
|
||||
endif
|
||||
|
||||
if exists('g:go_debug_windows["out"]') && g:go_debug_windows['out'] != ''
|
||||
exe 'silent ' . g:go_debug_windows['out']
|
||||
silent file `='__GODEBUG_OUTPUT__'`
|
||||
setlocal buftype=nofile bufhidden=wipe nomodified nobuflisted noswapfile nowrap nonumber nocursorline
|
||||
setlocal filetype=godebugoutput
|
||||
nmap <buffer> q <Plug>(go-debug-stop)
|
||||
endif
|
||||
|
||||
if exists('g:go_debug_windows["vars"]') && g:go_debug_windows['vars'] != ''
|
||||
exe 'silent ' . g:go_debug_windows['vars']
|
||||
silent file `='__GODEBUG_VARIABLES__'`
|
||||
setlocal buftype=nofile bufhidden=wipe nomodified nobuflisted noswapfile nowrap nonumber nocursorline
|
||||
setlocal filetype=godebugvariables
|
||||
call append(0, ["# Local Variables", "", "# Function Arguments"])
|
||||
nmap <buffer> <silent> <cr> :<c-u>call <SID>expand_var()<cr>
|
||||
nmap <buffer> q <Plug>(go-debug-stop)
|
||||
endif
|
||||
|
||||
silent! delcommand GoDebugStart
|
||||
silent! delcommand GoDebugTest
|
||||
command! -nargs=0 GoDebugContinue call go#debug#Stack('continue')
|
||||
command! -nargs=0 GoDebugNext call go#debug#Stack('next')
|
||||
command! -nargs=0 GoDebugStep call go#debug#Stack('step')
|
||||
command! -nargs=0 GoDebugStepOut call go#debug#Stack('stepOut')
|
||||
command! -nargs=0 GoDebugRestart call go#debug#Restart()
|
||||
command! -nargs=0 GoDebugStop call go#debug#Stop()
|
||||
command! -nargs=* GoDebugSet call go#debug#Set(<f-args>)
|
||||
command! -nargs=1 GoDebugPrint call go#debug#Print(<q-args>)
|
||||
|
||||
nnoremap <silent> <Plug>(go-debug-breakpoint) :<C-u>call go#debug#Breakpoint()<CR>
|
||||
nnoremap <silent> <Plug>(go-debug-next) :<C-u>call go#debug#Stack('next')<CR>
|
||||
nnoremap <silent> <Plug>(go-debug-step) :<C-u>call go#debug#Stack('step')<CR>
|
||||
nnoremap <silent> <Plug>(go-debug-stepout) :<C-u>call go#debug#Stack('stepout')<CR>
|
||||
nnoremap <silent> <Plug>(go-debug-continue) :<C-u>call go#debug#Stack('continue')<CR>
|
||||
nnoremap <silent> <Plug>(go-debug-stop) :<C-u>call go#debug#Stop()<CR>
|
||||
nnoremap <silent> <Plug>(go-debug-print) :<C-u>call go#debug#Print(expand('<cword>'))<CR>
|
||||
|
||||
nmap <F5> <Plug>(go-debug-continue)
|
||||
nmap <F6> <Plug>(go-debug-print)
|
||||
nmap <F9> <Plug>(go-debug-breakpoint)
|
||||
nmap <F10> <Plug>(go-debug-next)
|
||||
nmap <F11> <Plug>(go-debug-step)
|
||||
|
||||
set balloonexpr=go#debug#BalloonExpr()
|
||||
set ballooneval
|
||||
|
||||
exe bufwinnr(oldbuf) 'wincmd w'
|
||||
endfunction
|
||||
|
||||
function! s:err_cb(ch, msg) abort
|
||||
call go#util#EchoError(a:msg)
|
||||
let s:state['message'] += [a:msg]
|
||||
endfunction
|
||||
|
||||
function! s:out_cb(ch, msg) abort
|
||||
call go#util#EchoProgress(a:msg)
|
||||
let s:state['message'] += [a:msg]
|
||||
|
||||
" TODO: why do this in this callback?
|
||||
if stridx(a:msg, g:go_debug_address) != -1
|
||||
call ch_setoptions(a:ch, {
|
||||
\ 'out_cb': function('s:logger', ['OUT: ']),
|
||||
\ 'err_cb': function('s:logger', ['ERR: ']),
|
||||
\})
|
||||
|
||||
" Tell dlv about the breakpoints that the user added before delve started.
|
||||
let l:breaks = copy(s:state.breakpoint)
|
||||
let s:state['breakpoint'] = {}
|
||||
for l:bt in values(l:breaks)
|
||||
call go#debug#Breakpoint(bt.line)
|
||||
endfor
|
||||
|
||||
call s:call_jsonrpc('RPCServer.ListBreakpoints', function('s:start_cb'))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Start the debug mode. The first argument is the package name to compile and
|
||||
" debug, anything else will be passed to the running program.
|
||||
function! go#debug#Start(is_test, ...) abort
|
||||
if has('nvim')
|
||||
call go#util#EchoError('This feature only works in Vim for now; Neovim is not (yet) supported. Sorry :-(')
|
||||
return
|
||||
endif
|
||||
if !go#util#has_job()
|
||||
call go#util#EchoError('This feature requires Vim 8.0.0087 or newer with +job.')
|
||||
return
|
||||
endif
|
||||
|
||||
" It's already running.
|
||||
if has_key(s:state, 'job') && job_status(s:state['job']) == 'run'
|
||||
return
|
||||
endif
|
||||
|
||||
let s:start_args = a:000
|
||||
|
||||
if go#util#HasDebug('debugger-state')
|
||||
let g:go_debug_diag = s:state
|
||||
endif
|
||||
|
||||
" cd in to test directory; this is also what running "go test" does.
|
||||
if a:is_test
|
||||
lcd %:p:h
|
||||
endif
|
||||
|
||||
let s:state.is_test = a:is_test
|
||||
|
||||
let dlv = go#path#CheckBinPath("dlv")
|
||||
if empty(dlv)
|
||||
return
|
||||
endif
|
||||
|
||||
try
|
||||
if len(a:000) > 0
|
||||
let l:pkgname = a:1
|
||||
" Expand .; otherwise this won't work from a tmp dir.
|
||||
if l:pkgname[0] == '.'
|
||||
let l:pkgname = go#package#FromPath(getcwd()) . l:pkgname[1:]
|
||||
endif
|
||||
else
|
||||
let l:pkgname = go#package#FromPath(getcwd())
|
||||
endif
|
||||
|
||||
let l:args = []
|
||||
if len(a:000) > 1
|
||||
let l:args = ['--'] + a:000[1:]
|
||||
endif
|
||||
|
||||
let l:cmd = [
|
||||
\ dlv,
|
||||
\ (a:is_test ? 'test' : 'debug'),
|
||||
\ '--output', tempname(),
|
||||
\ '--headless',
|
||||
\ '--api-version', '2',
|
||||
\ '--log',
|
||||
\ '--listen', g:go_debug_address,
|
||||
\ '--accept-multiclient',
|
||||
\]
|
||||
if get(g:, 'go_build_tags', '') isnot ''
|
||||
let l:cmd += ['--build-flags', '--tags=' . g:go_build_tags]
|
||||
endif
|
||||
let l:cmd += l:args
|
||||
|
||||
call go#util#EchoProgress('Starting GoDebug...')
|
||||
let s:state['message'] = []
|
||||
let s:state['job'] = job_start(l:cmd, {
|
||||
\ 'out_cb': function('s:out_cb'),
|
||||
\ 'err_cb': function('s:err_cb'),
|
||||
\ 'exit_cb': function('s:exit'),
|
||||
\ 'stoponexit': 'kill',
|
||||
\})
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Translate a reflect kind constant to a human string.
|
||||
function! s:reflect_kind(k)
|
||||
" Kind constants from Go's reflect package.
|
||||
return [
|
||||
\ 'Invalid Kind',
|
||||
\ 'Bool',
|
||||
\ 'Int',
|
||||
\ 'Int8',
|
||||
\ 'Int16',
|
||||
\ 'Int32',
|
||||
\ 'Int64',
|
||||
\ 'Uint',
|
||||
\ 'Uint8',
|
||||
\ 'Uint16',
|
||||
\ 'Uint32',
|
||||
\ 'Uint64',
|
||||
\ 'Uintptr',
|
||||
\ 'Float32',
|
||||
\ 'Float64',
|
||||
\ 'Complex64',
|
||||
\ 'Complex128',
|
||||
\ 'Array',
|
||||
\ 'Chan',
|
||||
\ 'Func',
|
||||
\ 'Interface',
|
||||
\ 'Map',
|
||||
\ 'Ptr',
|
||||
\ 'Slice',
|
||||
\ 'String',
|
||||
\ 'Struct',
|
||||
\ 'UnsafePointer',
|
||||
\ ][a:k]
|
||||
endfunction
|
||||
|
||||
function! s:eval_tree(var, nest) abort
|
||||
if a:var.name =~ '^\~'
|
||||
return ''
|
||||
endif
|
||||
let nest = a:nest
|
||||
let v = ''
|
||||
let kind = s:reflect_kind(a:var.kind)
|
||||
if !empty(a:var.name)
|
||||
let v .= repeat(' ', nest) . a:var.name . ': '
|
||||
|
||||
if kind == 'Bool'
|
||||
let v .= printf("%s\n", a:var.value)
|
||||
|
||||
elseif kind == 'Struct'
|
||||
" Anonymous struct
|
||||
if a:var.type[:8] == 'struct { '
|
||||
let v .= printf("%s\n", a:var.type)
|
||||
else
|
||||
let v .= printf("%s{...}\n", a:var.type)
|
||||
endif
|
||||
|
||||
elseif kind == 'String'
|
||||
let v .= printf("%s[%d]%s\n", a:var.type, a:var.len,
|
||||
\ len(a:var.value) > 0 ? ': ' . a:var.value : '')
|
||||
|
||||
elseif kind == 'Slice' || kind == 'String' || kind == 'Map' || kind == 'Array'
|
||||
let v .= printf("%s[%d]\n", a:var.type, a:var.len)
|
||||
|
||||
elseif kind == 'Chan' || kind == 'Func' || kind == 'Interface'
|
||||
let v .= printf("%s\n", a:var.type)
|
||||
|
||||
elseif kind == 'Ptr'
|
||||
" TODO: We can do something more useful here.
|
||||
let v .= printf("%s\n", a:var.type)
|
||||
|
||||
elseif kind == 'Complex64' || kind == 'Complex128'
|
||||
let v .= printf("%s%s\n", a:var.type, a:var.value)
|
||||
|
||||
" Int, Float
|
||||
else
|
||||
let v .= printf("%s(%s)\n", a:var.type, a:var.value)
|
||||
endif
|
||||
else
|
||||
let nest -= 1
|
||||
endif
|
||||
|
||||
if index(['Chan', 'Complex64', 'Complex128'], kind) == -1 && a:var.type != 'error'
|
||||
for c in a:var.children
|
||||
let v .= s:eval_tree(c, nest+1)
|
||||
endfor
|
||||
endif
|
||||
return v
|
||||
endfunction
|
||||
|
||||
function! s:eval(arg) abort
|
||||
try
|
||||
let res = s:call_jsonrpc('RPCServer.State')
|
||||
let goroutineID = res.result.State.currentThread.goroutineID
|
||||
let res = s:call_jsonrpc('RPCServer.Eval', {
|
||||
\ 'expr': a:arg,
|
||||
\ 'scope': {'GoroutineID': goroutineID}
|
||||
\ })
|
||||
return s:eval_tree(res.result.Variable, 0)
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
return ''
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! go#debug#BalloonExpr() abort
|
||||
silent! let l:v = s:eval(v:beval_text)
|
||||
return l:v
|
||||
endfunction
|
||||
|
||||
function! go#debug#Print(arg) abort
|
||||
try
|
||||
echo substitute(s:eval(a:arg), "\n$", "", 0)
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:update_variables() abort
|
||||
" FollowPointers requests pointers to be automatically dereferenced.
|
||||
" MaxVariableRecurse is how far to recurse when evaluating nested types.
|
||||
" MaxStringLen is the maximum number of bytes read from a string
|
||||
" MaxArrayValues is the maximum number of elements read from an array, a slice or a map.
|
||||
" MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields.
|
||||
let l:cfg = {
|
||||
\ 'scope': {'GoroutineID': s:groutineID()},
|
||||
\ 'cfg': {'MaxStringLen': 20, 'MaxArrayValues': 20}
|
||||
\ }
|
||||
|
||||
try
|
||||
let res = s:call_jsonrpc('RPCServer.ListLocalVars', l:cfg)
|
||||
let s:state['localVars'] = res.result['Variables']
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
|
||||
try
|
||||
let res = s:call_jsonrpc('RPCServer.ListFunctionArgs', l:cfg)
|
||||
let s:state['functionArgs'] = res.result['Args']
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
|
||||
call s:show_variables()
|
||||
endfunction
|
||||
|
||||
function! go#debug#Set(symbol, value) abort
|
||||
try
|
||||
let res = s:call_jsonrpc('RPCServer.State')
|
||||
let goroutineID = res.result.State.currentThread.goroutineID
|
||||
call s:call_jsonrpc('RPCServer.Set', {
|
||||
\ 'symbol': a:symbol,
|
||||
\ 'value': a:value,
|
||||
\ 'scope': {'GoroutineID': goroutineID}
|
||||
\ })
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
|
||||
call s:update_variables()
|
||||
endfunction
|
||||
|
||||
function! s:update_stacktrace() abort
|
||||
try
|
||||
let res = s:call_jsonrpc('RPCServer.Stacktrace', {'id': s:groutineID(), 'depth': 5})
|
||||
call s:show_stacktrace(res)
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:stack_cb(ch, json) abort
|
||||
let s:stack_name = ''
|
||||
let res = json_decode(a:json)
|
||||
if type(res) == v:t_dict && has_key(res, 'error') && !empty(res.error)
|
||||
call go#util#EchoError(res.error)
|
||||
call s:clearState()
|
||||
call go#debug#Restart()
|
||||
return
|
||||
endif
|
||||
|
||||
if empty(res) || !has_key(res, 'result')
|
||||
return
|
||||
endif
|
||||
call s:update_breakpoint(res)
|
||||
call s:update_stacktrace()
|
||||
call s:update_variables()
|
||||
endfunction
|
||||
|
||||
" Send a command to change the cursor location to Delve.
|
||||
"
|
||||
" a:name must be one of continue, next, step, or stepOut.
|
||||
function! go#debug#Stack(name) abort
|
||||
let l:name = a:name
|
||||
|
||||
" Run continue if the program hasn't started yet.
|
||||
if s:state.running is 0
|
||||
let s:state.running = 1
|
||||
let l:name = 'continue'
|
||||
endif
|
||||
|
||||
" Add a breakpoint to the main.Main if the user didn't define any.
|
||||
if len(s:state['breakpoint']) is 0
|
||||
if go#debug#Breakpoint() isnot 0
|
||||
let s:state.running = 0
|
||||
return
|
||||
endif
|
||||
endif
|
||||
|
||||
try
|
||||
" TODO: document why this is needed.
|
||||
if l:name is# 'next' && get(s:, 'stack_name', '') is# 'next'
|
||||
call s:call_jsonrpc('RPCServer.CancelNext')
|
||||
endif
|
||||
let s:stack_name = l:name
|
||||
call s:call_jsonrpc('RPCServer.Command', function('s:stack_cb'), {'name': l:name})
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! go#debug#Restart() abort
|
||||
try
|
||||
call job_stop(s:state['job'])
|
||||
while has_key(s:state, 'job') && job_status(s:state['job']) is# 'run'
|
||||
sleep 50m
|
||||
endwhile
|
||||
|
||||
let l:breaks = s:state['breakpoint']
|
||||
let s:state = {
|
||||
\ 'rpcid': 1,
|
||||
\ 'running': 0,
|
||||
\ 'breakpoint': {},
|
||||
\ 'currentThread': {},
|
||||
\ 'localVars': {},
|
||||
\ 'functionArgs': {},
|
||||
\ 'message': [],
|
||||
\}
|
||||
|
||||
" Preserve breakpoints.
|
||||
for bt in values(l:breaks)
|
||||
" TODO: should use correct filename
|
||||
exe 'sign unplace '. bt.id .' file=' . bt.file
|
||||
call go#debug#Breakpoint(bt.line)
|
||||
endfor
|
||||
call call('go#debug#Start', s:start_args)
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Report if debugger mode is active.
|
||||
function! s:isActive()
|
||||
return len(s:state['message']) > 0
|
||||
endfunction
|
||||
|
||||
" Toggle breakpoint. Returns 0 on success and 1 on failure.
|
||||
function! go#debug#Breakpoint(...) abort
|
||||
let l:filename = fnamemodify(expand('%'), ':p:gs!\\!/!')
|
||||
|
||||
" Get line number from argument.
|
||||
if len(a:000) > 0
|
||||
let linenr = str2nr(a:1)
|
||||
if linenr is 0
|
||||
call go#util#EchoError('not a number: ' . a:1)
|
||||
return 0
|
||||
endif
|
||||
else
|
||||
let linenr = line('.')
|
||||
endif
|
||||
|
||||
try
|
||||
" Check if we already have a breakpoint for this line.
|
||||
let found = v:none
|
||||
for k in keys(s:state.breakpoint)
|
||||
let bt = s:state.breakpoint[k]
|
||||
if bt.file == l:filename && bt.line == linenr
|
||||
let found = bt
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Remove breakpoint.
|
||||
if type(found) == v:t_dict
|
||||
call remove(s:state['breakpoint'], bt.id)
|
||||
exe 'sign unplace '. found.id .' file=' . found.file
|
||||
if s:isActive()
|
||||
let res = s:call_jsonrpc('RPCServer.ClearBreakpoint', {'id': found.id})
|
||||
endif
|
||||
" Add breakpoint.
|
||||
else
|
||||
if s:isActive()
|
||||
let res = s:call_jsonrpc('RPCServer.CreateBreakpoint', {'Breakpoint': {'file': l:filename, 'line': linenr}})
|
||||
let bt = res.result.Breakpoint
|
||||
exe 'sign place '. bt.id .' line=' . bt.line . ' name=godebugbreakpoint file=' . bt.file
|
||||
let s:state['breakpoint'][bt.id] = bt
|
||||
else
|
||||
let id = len(s:state['breakpoint']) + 1
|
||||
let s:state['breakpoint'][id] = {'id': id, 'file': l:filename, 'line': linenr}
|
||||
exe 'sign place '. id .' line=' . linenr . ' name=godebugbreakpoint file=' . l:filename
|
||||
endif
|
||||
endif
|
||||
catch
|
||||
call go#util#EchoError(v:exception)
|
||||
return 1
|
||||
endtry
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
sign define godebugbreakpoint text=> texthl=GoDebugBreakpoint
|
||||
sign define godebugcurline text== linehl=GoDebugCurrent texthl=GoDebugCurrent
|
||||
|
||||
fun! s:hi()
|
||||
hi GoDebugBreakpoint term=standout ctermbg=117 ctermfg=0 guibg=#BAD4F5 guifg=Black
|
||||
hi GoDebugCurrent term=reverse ctermbg=12 ctermfg=7 guibg=DarkBlue guifg=White
|
||||
endfun
|
||||
augroup vim-go-breakpoint
|
||||
autocmd!
|
||||
autocmd ColorScheme * call s:hi()
|
||||
augroup end
|
||||
call s:hi()
|
||||
|
||||
" vim: sw=2 ts=2 et
|
21
pack/acp/start/vim-go/autoload/go/decls.vim
Normal file
21
pack/acp/start/vim-go/autoload/go/decls.vim
Normal file
|
@ -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
|
313
pack/acp/start/vim-go/autoload/go/def.vim
Normal file
313
pack/acp/start/vim-go/autoload/go/def.vim
Normal file
|
@ -0,0 +1,313 @@
|
|||
let s:go_stack = []
|
||||
let s:go_stack_level = 0
|
||||
|
||||
function! go#def#Jump(mode) abort
|
||||
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
|
||||
|
||||
" so guru right now is slow for some people. previously we were using
|
||||
" godef which also has it's own quirks. But this issue come up so many
|
||||
" times I've decided to support both. By default we still use guru as it
|
||||
" covers all edge cases, but now anyone can switch to godef if they wish
|
||||
let bin_name = get(g:, 'go_def_mode', 'guru')
|
||||
if bin_name == 'godef'
|
||||
if &modified
|
||||
" Write current unsaved buffer to a temp file and use the modified content
|
||||
let l:tmpname = tempname()
|
||||
call writefile(go#util#GetLines(), l:tmpname)
|
||||
let fname = l:tmpname
|
||||
endif
|
||||
|
||||
let bin_path = go#path#CheckBinPath("godef")
|
||||
if empty(bin_path)
|
||||
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)
|
||||
return
|
||||
endif
|
||||
|
||||
let cmd = [bin_path]
|
||||
let stdin_content = ""
|
||||
|
||||
if &modified
|
||||
let content = join(go#util#GetLines(), "\n")
|
||||
let stdin_content = fname . "\n" . strlen(content) . "\n" . content
|
||||
call add(cmd, "-modified")
|
||||
endif
|
||||
|
||||
if exists('g:go_build_tags')
|
||||
let tags = get(g:, 'go_build_tags')
|
||||
call extend(cmd, ["-tags", tags])
|
||||
endif
|
||||
|
||||
let fname = fname.':#'.go#util#OffsetCursor()
|
||||
call extend(cmd, ["definition", fname])
|
||||
|
||||
if go#util#has_job()
|
||||
let l:spawn_args = {
|
||||
\ 'cmd': cmd,
|
||||
\ 'complete': function('s:jump_to_declaration_cb', [a:mode, bin_name]),
|
||||
\ }
|
||||
|
||||
if &modified
|
||||
let l:spawn_args.input = stdin_content
|
||||
endif
|
||||
|
||||
call go#util#EchoProgress("searching declaration ...")
|
||||
|
||||
call s:def_job(spawn_args)
|
||||
return
|
||||
endif
|
||||
|
||||
let command = join(cmd, " ")
|
||||
if &modified
|
||||
let out = go#util#System(command, stdin_content)
|
||||
else
|
||||
let out = go#util#System(command)
|
||||
endif
|
||||
else
|
||||
call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru]')
|
||||
return
|
||||
endif
|
||||
|
||||
if go#util#ShellError() != 0
|
||||
call go#util#EchoError(out)
|
||||
return
|
||||
endif
|
||||
|
||||
call go#def#jump_to_declaration(out, a:mode, bin_name)
|
||||
endfunction
|
||||
|
||||
function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort
|
||||
if a:exit_status != 0
|
||||
return
|
||||
endif
|
||||
|
||||
call go#def#jump_to_declaration(a:data[0], a:mode, a:bin_name)
|
||||
call go#util#EchoSuccess(fnamemodify(a:data[0], ":t"))
|
||||
endfunction
|
||||
|
||||
function! go#def#jump_to_declaration(out, mode, bin_name) abort
|
||||
let final_out = a:out
|
||||
if a:bin_name == "godef"
|
||||
" append the type information to the same line so our we can parse it.
|
||||
" This makes it compatible with guru output.
|
||||
let final_out = join(split(a:out, '\n'), ':')
|
||||
endif
|
||||
|
||||
" strip line ending
|
||||
let out = split(final_out, go#util#LineEnding())[0]
|
||||
if go#util#IsWin()
|
||||
let parts = split(out, '\(^[a-zA-Z]\)\@<!:')
|
||||
else
|
||||
let parts = split(out, ':')
|
||||
endif
|
||||
|
||||
let filename = parts[0]
|
||||
let line = parts[1]
|
||||
let col = parts[2]
|
||||
let ident = parts[3]
|
||||
|
||||
" Remove anything newer than the current position, just like basic
|
||||
" vim tag support
|
||||
if s:go_stack_level == 0
|
||||
let s:go_stack = []
|
||||
else
|
||||
let s:go_stack = s:go_stack[0:s:go_stack_level-1]
|
||||
endif
|
||||
|
||||
" increment the stack counter
|
||||
let s:go_stack_level += 1
|
||||
|
||||
" push it on to the jumpstack
|
||||
let stack_entry = {'line': line("."), 'col': col("."), 'file': expand('%:p'), 'ident': ident}
|
||||
call add(s:go_stack, stack_entry)
|
||||
|
||||
" needed for restoring back user setting this is because there are two
|
||||
" modes of switchbuf which we need based on the split mode
|
||||
let old_switchbuf = &switchbuf
|
||||
|
||||
normal! m'
|
||||
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 a:mode == "tab"
|
||||
let &switchbuf = "useopen,usetab,newtab"
|
||||
if bufloaded(filename) == 0
|
||||
tab split
|
||||
else
|
||||
let cmd = 'sbuf'
|
||||
endif
|
||||
elseif a:mode == "split"
|
||||
split
|
||||
elseif a:mode == "vsplit"
|
||||
vsplit
|
||||
endif
|
||||
|
||||
" open the file and jump to line and column
|
||||
exec cmd fnameescape(fnamemodify(filename, ':.'))
|
||||
endif
|
||||
endif
|
||||
call cursor(line, col)
|
||||
|
||||
" also align the line to middle of the view
|
||||
normal! zz
|
||||
|
||||
let &switchbuf = old_switchbuf
|
||||
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
|
||||
let callbacks = go#job#Spawn(a:args)
|
||||
|
||||
let start_options = {
|
||||
\ 'callback': callbacks.callback,
|
||||
\ 'exit_cb': callbacks.exit_cb,
|
||||
\ 'close_cb': callbacks.close_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
|
37
pack/acp/start/vim-go/autoload/go/def_test.vim
Normal file
37
pack/acp/start/vim-go/autoload/go/def_test.vim
Normal file
|
@ -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
|
223
pack/acp/start/vim-go/autoload/go/doc.vim
Normal file
223
pack/acp/start/vim-go/autoload/go/doc.vim
Normal file
|
@ -0,0 +1,223 @@
|
|||
" Copyright 2011 The Go Authors. All rights reserved.
|
||||
" Use of this source code is governed by a BSD-style
|
||||
" license that can be found in the LICENSE file.
|
||||
|
||||
let s:buf_nr = -1
|
||||
|
||||
if !exists("g:go_doc_command")
|
||||
let g:go_doc_command = ["godoc"]
|
||||
endif
|
||||
|
||||
function! go#doc#OpenBrowser(...) abort
|
||||
" check if we have gogetdoc as it gives us more and accurate information.
|
||||
" Only supported if we have json_decode as it's not worth to parse the plain
|
||||
" non-json output of gogetdoc
|
||||
let bin_path = go#path#CheckBinPath('gogetdoc')
|
||||
if !empty(bin_path) && exists('*json_decode')
|
||||
let json_out = s:gogetdoc(1)
|
||||
if go#util#ShellError() != 0
|
||||
call go#util#EchoError(json_out)
|
||||
return
|
||||
endif
|
||||
|
||||
let out = json_decode(json_out)
|
||||
if type(out) != type({})
|
||||
call go#util#EchoError("gogetdoc output is malformed")
|
||||
endif
|
||||
|
||||
let import = out["import"]
|
||||
let name = out["name"]
|
||||
let decl = out["decl"]
|
||||
|
||||
let godoc_url = s:custom_godoc_url()
|
||||
let godoc_url .= "/" . import
|
||||
if decl !~ "^package"
|
||||
let godoc_url .= "#" . name
|
||||
endif
|
||||
|
||||
echo godoc_url
|
||||
|
||||
call go#tool#OpenBrowser(godoc_url)
|
||||
return
|
||||
endif
|
||||
|
||||
let pkgs = s:godocWord(a:000)
|
||||
if empty(pkgs)
|
||||
return
|
||||
endif
|
||||
|
||||
let pkg = pkgs[0]
|
||||
let exported_name = pkgs[1]
|
||||
|
||||
" example url: https://godoc.org/github.com/fatih/set#Set
|
||||
let godoc_url = s:custom_godoc_url() . "/" . pkg . "#" . exported_name
|
||||
call go#tool#OpenBrowser(godoc_url)
|
||||
endfunction
|
||||
|
||||
function! go#doc#Open(newmode, mode, ...) abort
|
||||
" With argument: run "godoc [arg]".
|
||||
if len(a:000)
|
||||
if empty(go#path#CheckBinPath(g:go_doc_command[0]))
|
||||
return
|
||||
endif
|
||||
|
||||
let command = printf("%s %s", go#util#Shelljoin(g:go_doc_command), join(a:000, ' '))
|
||||
let out = go#util#System(command)
|
||||
" Without argument: run gogetdoc on cursor position.
|
||||
else
|
||||
let out = s:gogetdoc(0)
|
||||
if out == -1
|
||||
return
|
||||
endif
|
||||
endif
|
||||
|
||||
if go#util#ShellError() != 0
|
||||
call go#util#EchoError(out)
|
||||
return
|
||||
endif
|
||||
|
||||
call s:GodocView(a:newmode, a:mode, out)
|
||||
endfunction
|
||||
|
||||
function! s:GodocView(newposition, position, content) abort
|
||||
" reuse existing buffer window if it exists otherwise create a new one
|
||||
let is_visible = bufexists(s:buf_nr) && bufwinnr(s:buf_nr) != -1
|
||||
if !bufexists(s:buf_nr)
|
||||
execute a:newposition
|
||||
sil file `="[Godoc]"`
|
||||
let s:buf_nr = bufnr('%')
|
||||
elseif bufwinnr(s:buf_nr) == -1
|
||||
execute a:position
|
||||
execute s:buf_nr . 'buffer'
|
||||
elseif bufwinnr(s:buf_nr) != bufwinnr('%')
|
||||
execute bufwinnr(s:buf_nr) . 'wincmd w'
|
||||
endif
|
||||
|
||||
" if 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 bufhidden=delete
|
||||
setlocal buftype=nofile
|
||||
setlocal noswapfile
|
||||
setlocal nobuflisted
|
||||
setlocal nocursorline
|
||||
setlocal nocursorcolumn
|
||||
setlocal iskeyword+=:
|
||||
setlocal iskeyword-=-
|
||||
|
||||
setlocal modifiable
|
||||
%delete _
|
||||
call append(0, split(a:content, "\n"))
|
||||
sil $delete _
|
||||
setlocal nomodifiable
|
||||
sil normal! gg
|
||||
|
||||
" close easily with <esc> or enter
|
||||
noremap <buffer> <silent> <CR> :<C-U>close<CR>
|
||||
noremap <buffer> <silent> <Esc> :<C-U>close<CR>
|
||||
endfunction
|
||||
|
||||
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:custom_godoc_url() abort
|
||||
let godoc_url = get(g:, 'go_doc_url', 'https://godoc.org')
|
||||
if godoc_url isnot 'https://godoc.org'
|
||||
" strip last '/' character if available
|
||||
let last_char = strlen(godoc_url) - 1
|
||||
if godoc_url[last_char] == '/'
|
||||
let godoc_url = strpart(godoc_url, 0, last_char)
|
||||
endif
|
||||
" custom godoc installations expect /pkg before package names
|
||||
let godoc_url .= "/pkg"
|
||||
endif
|
||||
return godoc_url
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
62
pack/acp/start/vim-go/autoload/go/fillstruct.vim
Normal file
62
pack/acp/start/vim-go/autoload/go/fillstruct.vim
Normal file
|
@ -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
|
90
pack/acp/start/vim-go/autoload/go/fillstruct_test.vim
Normal file
90
pack/acp/start/vim-go/autoload/go/fillstruct_test.vim
Normal file
|
@ -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
|
267
pack/acp/start/vim-go/autoload/go/fmt.vim
Normal file
267
pack/acp/start/vim-go/autoload/go/fmt.vim
Normal file
|
@ -0,0 +1,267 @@
|
|||
" Copyright 2011 The Go Authors. All rights reserved.
|
||||
" Use of this source code is governed by a BSD-style
|
||||
" license that can be found in the LICENSE file.
|
||||
"
|
||||
" fmt.vim: Vim command to format Go files with gofmt (and gofmt compatible
|
||||
" toorls, such as goimports).
|
||||
|
||||
if !exists("g:go_fmt_command")
|
||||
let g:go_fmt_command = "gofmt"
|
||||
endif
|
||||
|
||||
if !exists('g:go_fmt_options')
|
||||
let g:go_fmt_options = ''
|
||||
endif
|
||||
|
||||
if !exists('g:go_fmt_fail_silently')
|
||||
let g:go_fmt_fail_silently = 0
|
||||
endif
|
||||
|
||||
if !exists("g:go_fmt_experimental")
|
||||
let g:go_fmt_experimental = 0
|
||||
endif
|
||||
|
||||
" we have those problems :
|
||||
" http://stackoverflow.com/questions/12741977/prevent-vim-from-updating-its-undo-tree
|
||||
" http://stackoverflow.com/questions/18532692/golang-formatter-and-vim-how-to-destroy-history-record?rq=1
|
||||
"
|
||||
" The below function is an improved version that aims to fix all problems.
|
||||
" it doesn't undo changes and break undo history. If you are here reading
|
||||
" this and have VimL experience, please look at the function for
|
||||
" improvements, patches are welcome :)
|
||||
function! go#fmt#Format(withGoimport) abort
|
||||
if g:go_fmt_experimental == 1
|
||||
" Using winsaveview to save/restore cursor state has the problem of
|
||||
" closing folds on save:
|
||||
" https://github.com/fatih/vim-go/issues/502
|
||||
" One fix is to use mkview instead. Unfortunately, this sometimes causes
|
||||
" other bad side effects:
|
||||
" https://github.com/fatih/vim-go/issues/728
|
||||
" and still closes all folds if foldlevel>0:
|
||||
" https://github.com/fatih/vim-go/issues/732
|
||||
let l:curw = {}
|
||||
try
|
||||
mkview!
|
||||
catch
|
||||
let l:curw = winsaveview()
|
||||
endtry
|
||||
|
||||
" save our undo file to be restored after we are done. This is needed to
|
||||
" prevent an additional undo jump due to BufWritePre auto command and also
|
||||
" restore 'redo' history because it's getting being destroyed every
|
||||
" BufWritePre
|
||||
let tmpundofile = tempname()
|
||||
exe 'wundo! ' . tmpundofile
|
||||
else
|
||||
" Save cursor position and many other things.
|
||||
let l:curw = winsaveview()
|
||||
endif
|
||||
|
||||
" Write current unsaved buffer to a temp file
|
||||
let l:tmpname = tempname() . '.go'
|
||||
call writefile(go#util#GetLines(), l:tmpname)
|
||||
if go#util#IsWin()
|
||||
let l:tmpname = tr(l:tmpname, '\', '/')
|
||||
endif
|
||||
|
||||
let bin_name = g:go_fmt_command
|
||||
if a:withGoimport == 1
|
||||
let bin_name = "goimports"
|
||||
endif
|
||||
|
||||
let current_col = col('.')
|
||||
let out = go#fmt#run(bin_name, l:tmpname, expand('%'))
|
||||
let diff_offset = len(readfile(l:tmpname)) - line('$')
|
||||
|
||||
if go#util#ShellError() == 0
|
||||
call go#fmt#update_file(l:tmpname, expand('%'))
|
||||
elseif g:go_fmt_fail_silently == 0
|
||||
let errors = s:parse_errors(expand('%'), out)
|
||||
call s:show_errors(errors)
|
||||
endif
|
||||
|
||||
" We didn't use the temp file, so clean up
|
||||
call delete(l:tmpname)
|
||||
|
||||
if g:go_fmt_experimental == 1
|
||||
" restore our undo history
|
||||
silent! exe 'rundo ' . tmpundofile
|
||||
call delete(tmpundofile)
|
||||
|
||||
" Restore our cursor/windows positions, folds, etc.
|
||||
if empty(l:curw)
|
||||
silent! loadview
|
||||
else
|
||||
call winrestview(l:curw)
|
||||
endif
|
||||
else
|
||||
" Restore our cursor/windows positions.
|
||||
call winrestview(l:curw)
|
||||
endif
|
||||
|
||||
" be smart and jump to the line the new statement was added/removed
|
||||
call cursor(line('.') + diff_offset, current_col)
|
||||
|
||||
" Syntax highlighting breaks less often.
|
||||
syntax sync fromstart
|
||||
endfunction
|
||||
|
||||
" update_file updates the target file with the given formatted source
|
||||
function! go#fmt#update_file(source, target)
|
||||
" remove undo point caused via BufWritePre
|
||||
try | silent undojoin | catch | endtry
|
||||
|
||||
let old_fileformat = &fileformat
|
||||
if exists("*getfperm")
|
||||
" save file permissions
|
||||
let original_fperm = getfperm(a:target)
|
||||
endif
|
||||
|
||||
call rename(a:source, a:target)
|
||||
|
||||
" restore file permissions
|
||||
if exists("*setfperm") && original_fperm != ''
|
||||
call setfperm(a:target , original_fperm)
|
||||
endif
|
||||
|
||||
" reload buffer to reflect latest changes
|
||||
silent edit!
|
||||
|
||||
let &fileformat = old_fileformat
|
||||
let &syntax = &syntax
|
||||
|
||||
let l:listtype = go#list#Type("GoFmt")
|
||||
|
||||
" the title information was introduced with 7.4-2200
|
||||
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
|
||||
if has('patch-7.4.2200')
|
||||
" clean up previous list
|
||||
if l:listtype == "quickfix"
|
||||
let l:list_title = getqflist({'title': 1})
|
||||
else
|
||||
let l:list_title = getloclist(0, {'title': 1})
|
||||
endif
|
||||
else
|
||||
" can't check the title, so assume that the list was for go fmt.
|
||||
let l:list_title = {'title': 'Format'}
|
||||
endif
|
||||
|
||||
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
|
||||
call go#list#Clean(l:listtype)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" 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 = []
|
||||
for line in splitted
|
||||
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
|
||||
if !empty(tokens)
|
||||
call add(errors,{
|
||||
\"filename": a:filename,
|
||||
\"lnum": tokens[2],
|
||||
\"col": tokens[3],
|
||||
\"text": tokens[4],
|
||||
\ })
|
||||
endif
|
||||
endfor
|
||||
|
||||
return errors
|
||||
endfunction
|
||||
|
||||
" show_errors opens a location list and shows the given errors. If the given
|
||||
" errors is empty, it closes the the location list
|
||||
function! s:show_errors(errors) abort
|
||||
let l:listtype = 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
|
||||
|
||||
" this closes the window if there are no errors or it opens
|
||||
" it if there is any
|
||||
call go#list#Window(l:listtype, len(a:errors))
|
||||
endfunction
|
||||
|
||||
function! go#fmt#ToggleFmtAutoSave() abort
|
||||
if get(g:, "go_fmt_autosave", 1)
|
||||
let g:go_fmt_autosave = 0
|
||||
call go#util#EchoProgress("auto fmt disabled")
|
||||
return
|
||||
end
|
||||
|
||||
let g:go_fmt_autosave = 1
|
||||
call go#util#EchoProgress("auto fmt enabled")
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
49
pack/acp/start/vim-go/autoload/go/fmt_test.vim
Normal file
49
pack/acp/start/vim-go/autoload/go/fmt_test.vim
Normal file
|
@ -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
|
669
pack/acp/start/vim-go/autoload/go/guru.vim
Normal file
669
pack/acp/start/vim-go/autoload/go/guru.vim
Normal file
|
@ -0,0 +1,669 @@
|
|||
" 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 !has("nvim") && !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, a:args.mode)
|
||||
else
|
||||
call s:parse_guru_output(go#util#ShellError(), out, a:args.mode)
|
||||
endif
|
||||
|
||||
return out
|
||||
endfunc
|
||||
|
||||
" use vim or neovim job api as appropriate
|
||||
function! s:job_start(cmd, start_options) abort
|
||||
if go#util#has_job()
|
||||
return job_start(a:cmd, a:start_options)
|
||||
endif
|
||||
|
||||
let opts = {'stdout_buffered': v:true, 'stderr_buffered': v:true}
|
||||
function opts.on_stdout(job_id, data, event) closure
|
||||
call a:start_options.callback(a:job_id, join(a:data, "\n"))
|
||||
endfunction
|
||||
function opts.on_stderr(job_id, data, event) closure
|
||||
call a:start_options.callback(a:job_id, join(a:data, "\n"))
|
||||
endfunction
|
||||
function opts.on_exit(job_id, exit_code, event) closure
|
||||
call a:start_options.exit_cb(a:job_id, a:exit_code)
|
||||
call a:start_options.close_cb(a:job_id)
|
||||
endfunction
|
||||
|
||||
" use a shell for input redirection if needed
|
||||
let cmd = a:cmd
|
||||
if has_key(a:start_options, 'in_io') && a:start_options.in_io ==# 'file' && !empty(a:start_options.in_name)
|
||||
let cmd = ['/bin/sh', '-c', join(a:cmd, ' ') . ' <' . a:start_options.in_name]
|
||||
endif
|
||||
|
||||
return jobstart(cmd, opts)
|
||||
endfunction
|
||||
|
||||
" 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
|
||||
|
||||
|
||||
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 state = {
|
||||
\ 'status_dir': expand('%:p:h'),
|
||||
\ 'statusline_type': printf("%s", a:args.mode),
|
||||
\ 'mode': a:args.mode,
|
||||
\ 'status': {},
|
||||
\ 'exitval': 0,
|
||||
\ 'closed': 0,
|
||||
\ 'exited': 0,
|
||||
\ 'messages': [],
|
||||
\ 'parse' : get(a:args, 'custom_parse', funcref("s:parse_guru_output"))
|
||||
\ }
|
||||
|
||||
function! s:callback(chan, msg) dict
|
||||
call add(self.messages, a:msg)
|
||||
endfunction
|
||||
|
||||
function! s:exit_cb(job, exitval) dict
|
||||
let self.exited = 1
|
||||
|
||||
let status = {
|
||||
\ 'desc': 'last status',
|
||||
\ 'type': self.statusline_type,
|
||||
\ 'state': "finished",
|
||||
\ }
|
||||
|
||||
if a:exitval
|
||||
let self.exitval = a:exitval
|
||||
let status.state = "failed"
|
||||
endif
|
||||
|
||||
call go#statusline#Update(self.status_dir, status)
|
||||
|
||||
if self.closed
|
||||
call self.complete()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_cb(ch) dict
|
||||
let self.closed = 1
|
||||
|
||||
if self.exited
|
||||
call self.complete()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function state.complete() dict
|
||||
let out = join(self.messages, "\n")
|
||||
|
||||
call self.parse(self.exitval, out, self.mode)
|
||||
endfunction
|
||||
|
||||
" explicitly bind the callbacks to state so that self within them always
|
||||
" refers to state. See :help Partial for more information.
|
||||
let start_options = {
|
||||
\ 'callback': function('s:callback', [], state),
|
||||
\ 'exit_cb': function('s:exit_cb', [], state),
|
||||
\ 'close_cb': function('s:close_cb', [], state)
|
||||
\ }
|
||||
|
||||
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(state.status_dir, {
|
||||
\ 'desc': "current status",
|
||||
\ 'type': state.statusline_type,
|
||||
\ 'state': "analysing",
|
||||
\})
|
||||
|
||||
return s:job_start(result.cmd, start_options)
|
||||
endfunc
|
||||
|
||||
" run_guru runs the given guru argument
|
||||
function! s:run_guru(args) abort
|
||||
if has('nvim') || 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, mode)
|
||||
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#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, mode) 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
|
140
pack/acp/start/vim-go/autoload/go/impl.vim
Normal file
140
pack/acp/start/vim-go/autoload/go/impl.vim
Normal file
|
@ -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
|
37
pack/acp/start/vim-go/autoload/go/impl_test.vim
Normal file
37
pack/acp/start/vim-go/autoload/go/impl_test.vim
Normal file
|
@ -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
|
213
pack/acp/start/vim-go/autoload/go/import.vim
Normal file
213
pack/acp/start/vim-go/autoload/go/import.vim
Normal file
|
@ -0,0 +1,213 @@
|
|||
" Copyright 2011 The Go Authors. All rights reserved.
|
||||
" Use of this source code is governed by a BSD-style
|
||||
" license that can be found in the LICENSE file.
|
||||
"
|
||||
" Check out the docs for more information at /doc/vim-go.txt
|
||||
"
|
||||
function! go#import#SwitchImport(enabled, localname, path, bang) abort
|
||||
let view = winsaveview()
|
||||
let path = substitute(a:path, '^\s*\(.\{-}\)\s*$', '\1', '')
|
||||
|
||||
" Quotes are not necessary, so remove them if provided.
|
||||
if path[0] == '"'
|
||||
let path = strpart(path, 1)
|
||||
endif
|
||||
if path[len(path)-1] == '"'
|
||||
let path = strpart(path, 0, len(path) - 1)
|
||||
endif
|
||||
|
||||
" if given a trailing slash, eg. `github.com/user/pkg/`, remove it
|
||||
if path[len(path)-1] == '/'
|
||||
let path = strpart(path, 0, len(path) - 1)
|
||||
endif
|
||||
|
||||
if path == ''
|
||||
call s:Error('Import path not provided')
|
||||
return
|
||||
endif
|
||||
|
||||
if a:bang == "!"
|
||||
let out = go#util#System("go get -u -v ".shellescape(path))
|
||||
if go#util#ShellError() != 0
|
||||
call s:Error("Can't find import: " . path . ":" . out)
|
||||
endif
|
||||
endif
|
||||
let exists = go#tool#Exists(path)
|
||||
if exists == -1
|
||||
call s:Error("Can't find import: " . path)
|
||||
return
|
||||
endif
|
||||
|
||||
" Extract any site prefix (e.g. github.com/).
|
||||
" If other imports with the same prefix are grouped separately,
|
||||
" we will add this new import with them.
|
||||
" Only up to and including the first slash is used.
|
||||
let siteprefix = matchstr(path, "^[^/]*/")
|
||||
|
||||
let qpath = '"' . path . '"'
|
||||
if a:localname != ''
|
||||
let qlocalpath = a:localname . ' ' . qpath
|
||||
else
|
||||
let qlocalpath = qpath
|
||||
endif
|
||||
let indentstr = 0
|
||||
let packageline = -1 " Position of package name statement
|
||||
let appendline = -1 " Position to introduce new import
|
||||
let deleteline = -1 " Position of line with existing import
|
||||
let linesdelta = 0 " Lines added/removed
|
||||
|
||||
" Find proper place to add/remove import.
|
||||
let line = 0
|
||||
while line <= line('$')
|
||||
let linestr = getline(line)
|
||||
|
||||
if linestr =~# '^package\s'
|
||||
let packageline = line
|
||||
let appendline = line
|
||||
|
||||
elseif linestr =~# '^import\s\+('
|
||||
let appendstr = qlocalpath
|
||||
let indentstr = 1
|
||||
let appendline = line
|
||||
let firstblank = -1
|
||||
let lastprefix = ""
|
||||
while line <= line("$")
|
||||
let line = line + 1
|
||||
let linestr = getline(line)
|
||||
let m = matchlist(getline(line), '^\()\|\(\s\+\)\(\S*\s*\)"\(.\+\)"\)')
|
||||
if empty(m)
|
||||
if siteprefix == "" && a:enabled
|
||||
" must be in the first group
|
||||
break
|
||||
endif
|
||||
" record this position, but keep looking
|
||||
if firstblank < 0
|
||||
let firstblank = line
|
||||
endif
|
||||
continue
|
||||
endif
|
||||
if m[1] == ')'
|
||||
" if there's no match, add it to the first group
|
||||
if appendline < 0 && firstblank >= 0
|
||||
let appendline = firstblank
|
||||
endif
|
||||
break
|
||||
endif
|
||||
let lastprefix = matchstr(m[4], "^[^/]*/")
|
||||
if a:localname != '' && m[3] != ''
|
||||
let qlocalpath = printf('%-' . (len(m[3])-1) . 's %s', a:localname, qpath)
|
||||
endif
|
||||
let appendstr = m[2] . qlocalpath
|
||||
let indentstr = 0
|
||||
if m[4] == path
|
||||
let appendline = -1
|
||||
let deleteline = line
|
||||
break
|
||||
elseif m[4] < path
|
||||
" don't set candidate position if we have a site prefix,
|
||||
" we've passed a blank line, and this doesn't share the same
|
||||
" site prefix.
|
||||
if siteprefix == "" || firstblank < 0 || match(m[4], "^" . siteprefix) >= 0
|
||||
let appendline = line
|
||||
endif
|
||||
elseif siteprefix != "" && match(m[4], "^" . siteprefix) >= 0
|
||||
" first entry of site group
|
||||
let appendline = line - 1
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
break
|
||||
|
||||
elseif linestr =~# '^import '
|
||||
if appendline == packageline
|
||||
let appendstr = 'import ' . qlocalpath
|
||||
let appendline = line - 1
|
||||
endif
|
||||
let m = matchlist(linestr, '^import\(\s\+\)\(\S*\s*\)"\(.\+\)"')
|
||||
if !empty(m)
|
||||
if m[3] == path
|
||||
let appendline = -1
|
||||
let deleteline = line
|
||||
break
|
||||
endif
|
||||
if m[3] < path
|
||||
let appendline = line
|
||||
endif
|
||||
if a:localname != '' && m[2] != ''
|
||||
let qlocalpath = printf("%s %" . len(m[2])-1 . "s", a:localname, qpath)
|
||||
endif
|
||||
let appendstr = 'import' . m[1] . qlocalpath
|
||||
endif
|
||||
|
||||
elseif linestr =~# '^\(var\|const\|type\|func\)\>'
|
||||
break
|
||||
|
||||
endif
|
||||
let line = line + 1
|
||||
endwhile
|
||||
|
||||
" Append or remove the package import, as requested.
|
||||
if a:enabled
|
||||
if deleteline != -1
|
||||
call s:Error(qpath . ' already being imported')
|
||||
elseif appendline == -1
|
||||
call s:Error('No package line found')
|
||||
else
|
||||
if appendline == packageline
|
||||
call append(appendline + 0, '')
|
||||
call append(appendline + 1, 'import (')
|
||||
call append(appendline + 2, ')')
|
||||
let appendline += 2
|
||||
let linesdelta += 3
|
||||
let appendstr = qlocalpath
|
||||
let indentstr = 1
|
||||
endif
|
||||
call append(appendline, appendstr)
|
||||
execute appendline + 1
|
||||
if indentstr
|
||||
execute 'normal! >>'
|
||||
endif
|
||||
let linesdelta += 1
|
||||
endif
|
||||
else
|
||||
if deleteline == -1
|
||||
call s:Error(qpath . ' not being imported')
|
||||
else
|
||||
execute deleteline . 'd'
|
||||
let linesdelta -= 1
|
||||
|
||||
if getline(deleteline-1) =~# '^import\s\+(' && getline(deleteline) =~# '^)'
|
||||
" Delete empty import block
|
||||
let deleteline -= 1
|
||||
execute deleteline . "d"
|
||||
execute deleteline . "d"
|
||||
let linesdelta -= 2
|
||||
endif
|
||||
|
||||
if getline(deleteline) == '' && getline(deleteline - 1) == ''
|
||||
" Delete spacing for removed line too.
|
||||
execute deleteline . "d"
|
||||
let linesdelta -= 1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
" Adjust view for any changes.
|
||||
let view.lnum += linesdelta
|
||||
let view.topline += linesdelta
|
||||
if view.topline < 0
|
||||
let view.topline = 0
|
||||
endif
|
||||
|
||||
" Put buffer back where it was.
|
||||
call winrestview(view)
|
||||
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:Error(s) abort
|
||||
echohl Error | echo a:s | echohl None
|
||||
endfunction
|
||||
|
||||
|
||||
" vim: sw=2 ts=2 et
|
149
pack/acp/start/vim-go/autoload/go/job.vim
Normal file
149
pack/acp/start/vim-go/autoload/go/job.vim
Normal file
|
@ -0,0 +1,149 @@
|
|||
" Spawn returns callbacks to be used with job_start. It is abstracted to be
|
||||
" used with various go commands, such as build, test, install, etc.. This
|
||||
" allows us to avoid writing the same callback over and over for some
|
||||
" commands. It's fully customizable so each command can change it to it's own
|
||||
" logic.
|
||||
"
|
||||
" args is a dictionary with the these keys:
|
||||
" 'cmd':
|
||||
" The value to pass to job_start().
|
||||
" 'bang':
|
||||
" Set to 0 to jump to the first error in the error list.
|
||||
" Defaults to 0.
|
||||
" 'for':
|
||||
" The g:go_list_type_command key to use to get the error list type to use.
|
||||
" Defaults to '_job'
|
||||
" 'complete':
|
||||
" A function to call after the job exits and the channel is closed. The
|
||||
" function will be passed three arguments: the job, its exit code, and the
|
||||
" list of messages received from the channel. The default value will
|
||||
" process the messages and manage the error list after the job exits and
|
||||
" the channel is closed.
|
||||
|
||||
" The return value is a dictionary with these keys:
|
||||
" 'callback':
|
||||
" A function suitable to be passed as a job callback handler. See
|
||||
" job-callback.
|
||||
" 'exit_cb':
|
||||
" A function suitable to be passed as a job exit_cb handler. See
|
||||
" job-exit_cb.
|
||||
" 'close_cb':
|
||||
" A function suitable to be passed as a job close_cb handler. See
|
||||
" job-close_cb.
|
||||
function go#job#Spawn(args)
|
||||
let cbs = {}
|
||||
let state = {
|
||||
\ 'winnr': winnr(),
|
||||
\ 'dir': getcwd(),
|
||||
\ 'jobdir': fnameescape(expand("%:p:h")),
|
||||
\ 'messages': [],
|
||||
\ 'args': a:args.cmd,
|
||||
\ 'bang': 0,
|
||||
\ 'for': "_job",
|
||||
\ 'exited': 0,
|
||||
\ 'exit_status': 0,
|
||||
\ 'closed': 0,
|
||||
\ 'errorformat': &errorformat
|
||||
\ }
|
||||
|
||||
if has_key(a:args, 'bang')
|
||||
let state.bang = a:args.bang
|
||||
endif
|
||||
|
||||
if has_key(a:args, 'for')
|
||||
let state.for = a:args.for
|
||||
endif
|
||||
|
||||
" do nothing in state.complete by default.
|
||||
function state.complete(job, exit_status, data)
|
||||
endfunction
|
||||
|
||||
if has_key(a:args, 'complete')
|
||||
let state.complete = a:args.complete
|
||||
endif
|
||||
|
||||
function! s:callback(chan, msg) dict
|
||||
call add(self.messages, a:msg)
|
||||
endfunction
|
||||
" explicitly bind callback to state so that within it, self will
|
||||
" always refer to state. See :help Partial for more information.
|
||||
let cbs.callback = function('s:callback', [], state)
|
||||
|
||||
function! s:exit_cb(job, exitval) dict
|
||||
let self.exit_status = a:exitval
|
||||
let self.exited = 1
|
||||
|
||||
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 self.closed
|
||||
call self.complete(a:job, self.exit_status, self.messages)
|
||||
call self.show_errors(a:job, self.exit_status, self.messages)
|
||||
endif
|
||||
endfunction
|
||||
" explicitly bind exit_cb to state so that within it, self will always refer
|
||||
" to state. See :help Partial for more information.
|
||||
let cbs.exit_cb = function('s:exit_cb', [], state)
|
||||
|
||||
function! s:close_cb(ch) dict
|
||||
let self.closed = 1
|
||||
|
||||
if self.exited
|
||||
let job = ch_getjob(a:ch)
|
||||
call self.complete(job, self.exit_status, self.messages)
|
||||
call self.show_errors(job, self.exit_status, self.messages)
|
||||
endif
|
||||
endfunction
|
||||
" explicitly bind close_cb to state so that within it, self will
|
||||
" always refer to state. See :help Partial for more information.
|
||||
let cbs.close_cb = function('s:close_cb', [], state)
|
||||
|
||||
function state.show_errors(job, exit_status, data)
|
||||
let l:listtype = go#list#Type(self.for)
|
||||
if a:exit_status == 0
|
||||
call go#list#Clean(l:listtype)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:listtype = go#list#Type(self.for)
|
||||
if len(a:data) == 0
|
||||
call go#list#Clean(l:listtype)
|
||||
return
|
||||
endif
|
||||
|
||||
let out = join(self.messages, "\n")
|
||||
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
try
|
||||
" parse the errors relative to self.jobdir
|
||||
execute cd self.jobdir
|
||||
call go#list#ParseFormat(l:listtype, self.errorformat, out, self.for)
|
||||
let errors = go#list#Get(l:listtype)
|
||||
finally
|
||||
execute cd . fnameescape(self.dir)
|
||||
endtry
|
||||
|
||||
|
||||
if empty(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#Window(l:listtype, len(errors))
|
||||
if !self.bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
return cbs
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
190
pack/acp/start/vim-go/autoload/go/jobcontrol.vim
Normal file
190
pack/acp/start/vim-go/autoload/go/jobcontrol.vim
Normal file
|
@ -0,0 +1,190 @@
|
|||
" s:jobs is a global reference to all jobs started with Spawn() or with the
|
||||
" internal function s:spawn
|
||||
let s:jobs = {}
|
||||
|
||||
" s:handlers is a global event handlers for all jobs started with Spawn() or
|
||||
" with the internal function s:spawn
|
||||
let s:handlers = {}
|
||||
|
||||
" Spawn is a wrapper around s:spawn. It can be executed by other files and
|
||||
" scripts if needed. Desc defines the description for printing the status
|
||||
" during the job execution (useful for statusline integration).
|
||||
function! go#jobcontrol#Spawn(bang, desc, for, args) abort
|
||||
" autowrite is not enabled for jobs
|
||||
call go#cmd#autowrite()
|
||||
|
||||
let job = s:spawn(a:bang, a:desc, a:for, a:args)
|
||||
return job.id
|
||||
endfunction
|
||||
|
||||
" AddHandler adds a on_exit callback handler and returns the id.
|
||||
function! go#jobcontrol#AddHandler(handler) abort
|
||||
let i = len(s:handlers)
|
||||
while has_key(s:handlers, string(i))
|
||||
let i += 1
|
||||
break
|
||||
endwhile
|
||||
let s:handlers[string(i)] = a:handler
|
||||
return string(i)
|
||||
endfunction
|
||||
|
||||
" RemoveHandler removes a callback handler by id.
|
||||
function! go#jobcontrol#RemoveHandler(id) abort
|
||||
unlet s:handlers[a:id]
|
||||
endfunction
|
||||
|
||||
" spawn spawns a go subcommand with the name and arguments with jobstart. Once a
|
||||
" job is started a reference will be stored inside s:jobs. 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()
|
||||
|
||||
call go#statusline#Update(status_dir, {
|
||||
\ 'desc': "current status",
|
||||
\ 'type': status_type,
|
||||
\ 'state': "started",
|
||||
\})
|
||||
|
||||
let job = {
|
||||
\ 'desc': a:desc,
|
||||
\ 'bang': a:bang,
|
||||
\ 'winnr': winnr(),
|
||||
\ 'importpath': go#package#ImportPath(),
|
||||
\ 'state': "RUNNING",
|
||||
\ 'stderr' : [],
|
||||
\ 'stdout' : [],
|
||||
\ 'on_stdout': function('s:on_stdout'),
|
||||
\ 'on_stderr': function('s:on_stderr'),
|
||||
\ 'on_exit' : function('s:on_exit'),
|
||||
\ 'status_type' : status_type,
|
||||
\ 'status_dir' : status_dir,
|
||||
\ 'started_at' : started_at,
|
||||
\ 'for' : a:for,
|
||||
\ 'errorformat': &errorformat,
|
||||
\ }
|
||||
|
||||
" execute go build in the files directory
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
|
||||
" cleanup previous jobs for this file
|
||||
for jb in values(s:jobs)
|
||||
if jb.importpath == job.importpath
|
||||
unlet s:jobs[jb.id]
|
||||
endif
|
||||
endfor
|
||||
|
||||
let dir = getcwd()
|
||||
let jobdir = fnameescape(expand("%:p:h"))
|
||||
execute cd . jobdir
|
||||
|
||||
" append the subcommand, such as 'build'
|
||||
let argv = ['go'] + a:args
|
||||
|
||||
" run, forrest, run!
|
||||
let id = jobstart(argv, job)
|
||||
let job.id = id
|
||||
let job.dir = jobdir
|
||||
let s:jobs[id] = job
|
||||
|
||||
execute cd . fnameescape(dir)
|
||||
|
||||
return job
|
||||
endfunction
|
||||
|
||||
" on_exit is the exit handler for jobstart(). It handles cleaning up the job
|
||||
" references and also displaying errors in the quickfix window collected by
|
||||
" on_stderr handler. If there are no errors and a quickfix window is open,
|
||||
" it'll be closed.
|
||||
function! s:on_exit(job_id, exit_status, event) dict abort
|
||||
let status = {
|
||||
\ 'desc': 'last status',
|
||||
\ 'type': self.status_type,
|
||||
\ 'state': "success",
|
||||
\ }
|
||||
|
||||
if a:exit_status
|
||||
let status.state = "failed"
|
||||
endif
|
||||
|
||||
let elapsed_time = reltimestr(reltime(self.started_at))
|
||||
" strip whitespace
|
||||
let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '')
|
||||
let status.state .= printf(" (%ss)", elapsed_time)
|
||||
|
||||
call go#statusline#Update(self.status_dir, status)
|
||||
|
||||
let std_combined = self.stderr + self.stdout
|
||||
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
let dir = getcwd()
|
||||
execute cd self.dir
|
||||
|
||||
call s:callback_handlers_on_exit(s:jobs[a:job_id], a:exit_status, std_combined)
|
||||
|
||||
let l:listtype = go#list#Type(self.for)
|
||||
if a:exit_status == 0
|
||||
call go#list#Clean(l:listtype)
|
||||
|
||||
let self.state = "SUCCESS"
|
||||
|
||||
if get(g:, 'go_echo_command_info', 1)
|
||||
call go#util#EchoSuccess("[" . self.status_type . "] SUCCESS")
|
||||
endif
|
||||
|
||||
execute cd . fnameescape(dir)
|
||||
return
|
||||
endif
|
||||
|
||||
let self.state = "FAILED"
|
||||
|
||||
if get(g:, 'go_echo_command_info', 1)
|
||||
call go#util#EchoError("[" . self.status_type . "] FAILED")
|
||||
endif
|
||||
|
||||
" parse the errors relative to self.jobdir
|
||||
call go#list#ParseFormat(l:listtype, self.errorformat, std_combined, self.for)
|
||||
let errors = go#list#Get(l:listtype)
|
||||
|
||||
execute cd . fnameescape(dir)
|
||||
|
||||
if !len(errors)
|
||||
" failed to parse errors, output the original content
|
||||
call go#util#EchoError(std_combined[0])
|
||||
return
|
||||
endif
|
||||
|
||||
" if we are still in the same windows show the list
|
||||
if self.winnr == winnr()
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors) && !self.bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" callback_handlers_on_exit runs all handlers for job on exit event.
|
||||
function! s:callback_handlers_on_exit(job, exit_status, data) abort
|
||||
if empty(s:handlers)
|
||||
return
|
||||
endif
|
||||
|
||||
for s:handler in values(s:handlers)
|
||||
call s:handler(a:job, a:exit_status, a:data)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" on_stdout is the stdout handler for jobstart(). It collects the output of
|
||||
" stderr and stores them to the jobs internal stdout list.
|
||||
function! s:on_stdout(job_id, data, event) dict abort
|
||||
call extend(self.stdout, a:data)
|
||||
endfunction
|
||||
|
||||
" on_stderr is the stderr handler for jobstart(). It collects the output of
|
||||
" stderr and stores them to the jobs internal stderr list.
|
||||
function! s:on_stderr(job_id, data, event) dict abort
|
||||
call extend(self.stderr, a:data)
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
56
pack/acp/start/vim-go/autoload/go/keyify.vim
Normal file
56
pack/acp/start/vim-go/autoload/go/keyify.vim
Normal file
|
@ -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
|
357
pack/acp/start/vim-go/autoload/go/lint.vim
Normal file
357
pack/acp/start/vim-go/autoload/go/lint.vim
Normal file
|
@ -0,0 +1,357 @@
|
|||
if !exists("g:go_metalinter_command")
|
||||
let g:go_metalinter_command = ""
|
||||
endif
|
||||
|
||||
if !exists("g:go_metalinter_autosave_enabled")
|
||||
let g:go_metalinter_autosave_enabled = ['vet', 'golint']
|
||||
endif
|
||||
|
||||
if !exists("g:go_metalinter_enabled")
|
||||
let g:go_metalinter_enabled = ['vet', 'golint', 'errcheck']
|
||||
endif
|
||||
|
||||
if !exists("g:go_metalinter_disabled")
|
||||
let g:go_metalinter_disabled = []
|
||||
endif
|
||||
|
||||
if !exists("g:go_golint_bin")
|
||||
let g:go_golint_bin = "golint"
|
||||
endif
|
||||
|
||||
if !exists("g:go_errcheck_bin")
|
||||
let g:go_errcheck_bin = "errcheck"
|
||||
endif
|
||||
|
||||
function! go#lint#Gometa(autosave, ...) abort
|
||||
if a:0 == 0
|
||||
let goargs = [expand('%:p:h')]
|
||||
else
|
||||
let goargs = a:000
|
||||
endif
|
||||
|
||||
let bin_path = go#path#CheckBinPath("gometalinter")
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
|
||||
let cmd = [bin_path]
|
||||
let cmd += ["--disable-all"]
|
||||
|
||||
if a:autosave || empty(g:go_metalinter_command)
|
||||
" linters
|
||||
let linters = a:autosave ? g:go_metalinter_autosave_enabled : g:go_metalinter_enabled
|
||||
for linter in linters
|
||||
let cmd += ["--enable=".linter]
|
||||
endfor
|
||||
|
||||
for linter in g:go_metalinter_disabled
|
||||
let cmd += ["--disable=".linter]
|
||||
endfor
|
||||
|
||||
" gometalinter has a --tests flag to tell its linters whether to run
|
||||
" against tests. While not all of its linters respect this flag, for those
|
||||
" that do, it means if we don't pass --tests, the linter won't run against
|
||||
" test files. One example of a linter that will not run against tests if
|
||||
" we do not specify this flag is errcheck.
|
||||
let cmd += ["--tests"]
|
||||
else
|
||||
" the user wants something else, let us use it.
|
||||
let cmd += split(g:go_metalinter_command, " ")
|
||||
endif
|
||||
|
||||
if a:autosave
|
||||
" redraw so that any messages that were displayed while writing the file
|
||||
" will be cleared
|
||||
redraw
|
||||
|
||||
" Include only messages for the active buffer for autosave.
|
||||
let cmd += [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))]
|
||||
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
|
||||
|
||||
let cmd += goargs
|
||||
|
||||
call s:lint_job({'cmd': cmd}, a:autosave)
|
||||
return
|
||||
endif
|
||||
|
||||
" We're calling gometalinter synchronously.
|
||||
let cmd += ["--deadline=" . get(g:, 'go_metalinter_deadline', "5s")]
|
||||
|
||||
let cmd += goargs
|
||||
|
||||
let [l:out, l:err] = go#util#Exec(cmd)
|
||||
|
||||
if a:autosave
|
||||
let l:listtype = go#list#Type("GoMetaLinterAutoSave")
|
||||
else
|
||||
let l:listtype = go#list#Type("GoMetaLinter")
|
||||
endif
|
||||
|
||||
if l:err == 0
|
||||
call go#list#Clean(l:listtype)
|
||||
echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None
|
||||
else
|
||||
" GoMetaLinter can output one of the two, so we look for both:
|
||||
" <file>:<line>:[<column>]: <message> (<linter>)
|
||||
" <file>:<line>:: <message> (<linter>)
|
||||
" This can be defined by the following errorformat:
|
||||
let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m"
|
||||
|
||||
" Parse and populate our location list
|
||||
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter')
|
||||
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
|
||||
if !a:autosave
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Golint calls 'golint' on the current directory. Any warnings are populated in
|
||||
" the location list
|
||||
function! go#lint#Golint(...) abort
|
||||
let bin_path = go#path#CheckBinPath(g:go_golint_bin)
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
let bin_path = go#util#Shellescape(bin_path)
|
||||
|
||||
if a:0 == 0
|
||||
let out = go#util#System(bin_path . " " . go#util#Shellescape(go#package#ImportPath()))
|
||||
else
|
||||
let out = go#util#System(bin_path . " " . go#util#Shelljoin(a:000))
|
||||
endif
|
||||
|
||||
if empty(out)
|
||||
echon "vim-go: " | echohl Function | echon "[lint] PASS" | echohl None
|
||||
return
|
||||
endif
|
||||
|
||||
let l:listtype = go#list#Type("GoLint")
|
||||
call go#list#Parse(l:listtype, out, "GoLint")
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endfunction
|
||||
|
||||
" Vet calls 'go vet' on the current directory. Any warnings are populated in
|
||||
" the location list
|
||||
function! go#lint#Vet(bang, ...) abort
|
||||
call go#cmd#autowrite()
|
||||
echon "vim-go: " | echohl Identifier | echon "calling vet..." | echohl None
|
||||
if a:0 == 0
|
||||
let out = go#util#System('go vet ' . go#util#Shellescape(go#package#ImportPath()))
|
||||
else
|
||||
let out = go#util#System('go tool vet ' . go#util#Shelljoin(a:000))
|
||||
endif
|
||||
|
||||
let l:listtype = go#list#Type("GoVet")
|
||||
if go#util#ShellError() != 0
|
||||
let errorformat="%-Gexit status %\\d%\\+," . &errorformat
|
||||
call go#list#ParseFormat(l:listtype, l:errorformat, out, "GoVet")
|
||||
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)
|
||||
endif
|
||||
echon "vim-go: " | echohl ErrorMsg | echon "[vet] FAIL" | echohl None
|
||||
else
|
||||
call go#list#Clean(l:listtype)
|
||||
redraw | echon "vim-go: " | echohl Function | echon "[vet] PASS" | echohl None
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" ErrCheck calls 'errcheck' for the given packages. Any warnings are populated in
|
||||
" the location list
|
||||
function! go#lint#Errcheck(...) abort
|
||||
if a:0 == 0
|
||||
let import_path = go#package#ImportPath()
|
||||
if import_path == -1
|
||||
echohl Error | echomsg "vim-go: package is not inside GOPATH src" | echohl None
|
||||
return
|
||||
endif
|
||||
else
|
||||
let import_path = go#util#Shelljoin(a:000)
|
||||
endif
|
||||
|
||||
let bin_path = go#path#CheckBinPath(g:go_errcheck_bin)
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
|
||||
echon "vim-go: " | echohl Identifier | echon "errcheck analysing ..." | echohl None
|
||||
redraw
|
||||
|
||||
let command = go#util#Shellescape(bin_path) . ' -abspath ' . import_path
|
||||
let out = go#tool#ExecuteInDir(command)
|
||||
|
||||
let l:listtype = go#list#Type("GoErrCheck")
|
||||
if go#util#ShellError() != 0
|
||||
let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m"
|
||||
|
||||
" Parse and populate our location list
|
||||
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'Errcheck')
|
||||
|
||||
let errors = go#list#Get(l:listtype)
|
||||
if empty(errors)
|
||||
echohl Error | echomsg "GoErrCheck returned error" | echohl None
|
||||
echo out
|
||||
return
|
||||
endif
|
||||
|
||||
if !empty(errors)
|
||||
echohl Error | echomsg "GoErrCheck found errors" | echohl None
|
||||
call go#list#Populate(l:listtype, errors, 'Errcheck')
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors)
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
call go#list#Clean(l:listtype)
|
||||
echon "vim-go: " | echohl Function | echon "[errcheck] PASS" | echohl None
|
||||
endif
|
||||
|
||||
endfunction
|
||||
|
||||
function! go#lint#ToggleMetaLinterAutoSave() abort
|
||||
if get(g:, "go_metalinter_autosave", 0)
|
||||
let g:go_metalinter_autosave = 0
|
||||
call go#util#EchoProgress("auto metalinter disabled")
|
||||
return
|
||||
end
|
||||
|
||||
let g:go_metalinter_autosave = 1
|
||||
call go#util#EchoProgress("auto metalinter enabled")
|
||||
endfunction
|
||||
|
||||
function! s:lint_job(args, autosave)
|
||||
let state = {
|
||||
\ 'status_dir': expand('%:p:h'),
|
||||
\ 'started_at': reltime(),
|
||||
\ 'messages': [],
|
||||
\ 'exited': 0,
|
||||
\ 'closed': 0,
|
||||
\ 'exit_status': 0,
|
||||
\ 'winnr': winnr(),
|
||||
\ 'autosave': a:autosave
|
||||
\ }
|
||||
|
||||
call go#statusline#Update(state.status_dir, {
|
||||
\ 'desc': "current status",
|
||||
\ 'type': "gometalinter",
|
||||
\ 'state': "analysing",
|
||||
\})
|
||||
|
||||
" autowrite is not enabled for jobs
|
||||
call go#cmd#autowrite()
|
||||
|
||||
if a:autosave
|
||||
let state.listtype = go#list#Type("GoMetaLinterAutoSave")
|
||||
else
|
||||
let state.listtype = go#list#Type("GoMetaLinter")
|
||||
endif
|
||||
|
||||
function! s:callback(chan, msg) dict closure
|
||||
call add(self.messages, a:msg)
|
||||
endfunction
|
||||
|
||||
function! s:exit_cb(job, exitval) dict
|
||||
let self.exited = 1
|
||||
let self.exit_status = a:exitval
|
||||
|
||||
let status = {
|
||||
\ 'desc': 'last status',
|
||||
\ 'type': "gometaliner",
|
||||
\ 'state': "finished",
|
||||
\ }
|
||||
|
||||
if a:exitval
|
||||
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)
|
||||
|
||||
if self.closed
|
||||
call self.show_errors()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_cb(ch) dict
|
||||
let self.closed = 1
|
||||
|
||||
if self.exited
|
||||
call self.show_errors()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
function state.show_errors()
|
||||
let l:winnr = winnr()
|
||||
|
||||
" make sure the current window is the window from which gometalinter was
|
||||
" run when the listtype is locationlist so that the location list for the
|
||||
" correct window will be populated.
|
||||
if self.listtype == 'locationlist'
|
||||
exe self.winnr . "wincmd w"
|
||||
endif
|
||||
|
||||
let l:errorformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m'
|
||||
call go#list#ParseFormat(self.listtype, l:errorformat, self.messages, 'GoMetaLinter')
|
||||
|
||||
let errors = go#list#Get(self.listtype)
|
||||
call go#list#Window(self.listtype, len(errors))
|
||||
|
||||
" move to the window that was active before processing the errors, because
|
||||
" the user may have moved around within the window or even moved to a
|
||||
" different window since saving. Moving back to current window as of the
|
||||
" start of this function avoids the perception that the quickfix window
|
||||
" steals focus when linting takes a while.
|
||||
if self.autosave
|
||||
exe l:winnr . "wincmd w"
|
||||
endif
|
||||
|
||||
if get(g:, 'go_echo_command_info', 1)
|
||||
call go#util#EchoSuccess("linting finished")
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" explicitly bind the callbacks to state so that self within them always
|
||||
" refers to state. See :help Partial for more information.
|
||||
let start_options = {
|
||||
\ 'callback': funcref("s:callback", [], state),
|
||||
\ 'exit_cb': funcref("s:exit_cb", [], state),
|
||||
\ 'close_cb': funcref("s:close_cb", [], state),
|
||||
\ }
|
||||
|
||||
call job_start(a:args.cmd, start_options)
|
||||
|
||||
if get(g:, 'go_echo_command_info', 1)
|
||||
call go#util#EchoProgress("linting started ...")
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
131
pack/acp/start/vim-go/autoload/go/lint_test.vim
Normal file
131
pack/acp/start/vim-go/autoload/go/lint_test.vim
Normal file
|
@ -0,0 +1,131 @@
|
|||
func! Test_Gometa() abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
||||
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
||||
|
||||
let expected = [
|
||||
\ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
|
||||
\ ]
|
||||
|
||||
" clear the quickfix lists
|
||||
call setqflist([], 'r')
|
||||
|
||||
" call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will
|
||||
" be autoloaded and the default for g:go_metalinter_enabled will be set so
|
||||
" we can capture it to restore it after the test is run.
|
||||
call go#lint#ToggleMetaLinterAutoSave()
|
||||
" And restore it back to its previous value
|
||||
call go#lint#ToggleMetaLinterAutoSave()
|
||||
|
||||
let orig_go_metalinter_enabled = g:go_metalinter_enabled
|
||||
let g:go_metalinter_enabled = ['golint']
|
||||
|
||||
call go#lint#Gometa(0, $GOPATH . '/src/foo')
|
||||
|
||||
let actual = getqflist()
|
||||
let start = reltime()
|
||||
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||
sleep 100m
|
||||
let actual = getqflist()
|
||||
endwhile
|
||||
|
||||
call gotest#assert_quickfix(actual, expected)
|
||||
let g:go_metalinter_enabled = orig_go_metalinter_enabled
|
||||
endfunc
|
||||
|
||||
func! Test_GometaWithDisabled() abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
||||
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
||||
|
||||
let expected = [
|
||||
\ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'}
|
||||
\ ]
|
||||
|
||||
" clear the quickfix lists
|
||||
call setqflist([], 'r')
|
||||
|
||||
" call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will
|
||||
" be autoloaded and the default for g:go_metalinter_disabled will be set so
|
||||
" we can capture it to restore it after the test is run.
|
||||
call go#lint#ToggleMetaLinterAutoSave()
|
||||
" And restore it back to its previous value
|
||||
call go#lint#ToggleMetaLinterAutoSave()
|
||||
|
||||
let orig_go_metalinter_disabled = g:go_metalinter_disabled
|
||||
let g:go_metalinter_disabled = ['vet']
|
||||
|
||||
call go#lint#Gometa(0, $GOPATH . '/src/foo')
|
||||
|
||||
let actual = getqflist()
|
||||
let start = reltime()
|
||||
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||
sleep 100m
|
||||
let actual = getqflist()
|
||||
endwhile
|
||||
|
||||
call gotest#assert_quickfix(actual, expected)
|
||||
let g:go_metalinter_disabled = orig_go_metalinter_disabled
|
||||
endfunc
|
||||
|
||||
func! Test_GometaAutoSave() abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
||||
silent exe 'e ' . $GOPATH . '/src/lint/lint.go'
|
||||
|
||||
let expected = [
|
||||
\ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'}
|
||||
\ ]
|
||||
|
||||
let winnr = winnr()
|
||||
|
||||
" clear the location lists
|
||||
call setloclist(l:winnr, [], 'r')
|
||||
|
||||
" call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will
|
||||
" be autoloaded and the default for g:go_metalinter_autosave_enabled will be
|
||||
" set so we can capture it to restore it after the test is run.
|
||||
call go#lint#ToggleMetaLinterAutoSave()
|
||||
" And restore it back to its previous value
|
||||
call go#lint#ToggleMetaLinterAutoSave()
|
||||
|
||||
let orig_go_metalinter_autosave_enabled = g:go_metalinter_autosave_enabled
|
||||
let g:go_metalinter_autosave_enabled = ['golint']
|
||||
|
||||
call go#lint#Gometa(1)
|
||||
|
||||
let actual = getloclist(l:winnr)
|
||||
let start = reltime()
|
||||
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||
sleep 100m
|
||||
let actual = getloclist(l:winnr)
|
||||
endwhile
|
||||
|
||||
call gotest#assert_quickfix(actual, expected)
|
||||
let g:go_metalinter_autosave_enabled = orig_go_metalinter_autosave_enabled
|
||||
endfunc
|
||||
|
||||
func! Test_Vet()
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint'
|
||||
silent exe 'e ' . $GOPATH . '/src/vet/vet.go'
|
||||
compiler go
|
||||
|
||||
let expected = [
|
||||
\ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'arg str for printf verb %d of wrong type: string'}
|
||||
\ ]
|
||||
|
||||
let winnr = winnr()
|
||||
|
||||
" clear the location lists
|
||||
call setqflist([], 'r')
|
||||
|
||||
call go#lint#Vet(1)
|
||||
|
||||
let actual = getqflist()
|
||||
let start = reltime()
|
||||
while len(actual) == 0 && reltimefloat(reltime(start)) < 10
|
||||
sleep 100m
|
||||
let actual = getqflist()
|
||||
endwhile
|
||||
|
||||
call gotest#assert_quickfix(actual, expected)
|
||||
endfunc
|
||||
|
||||
" vim: sw=2 ts=2 et
|
175
pack/acp/start/vim-go/autoload/go/list.vim
Normal file
175
pack/acp/start/vim-go/autoload/go/list.vim
Normal file
|
@ -0,0 +1,175 @@
|
|||
if !exists("g:go_list_type")
|
||||
let g:go_list_type = ""
|
||||
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.
|
||||
" Otherwise g:go_loclist_height is used.
|
||||
"
|
||||
" If no or zero height is given it closes the window by default.
|
||||
" 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
|
||||
" ability to resize the window. So, we are going to use lopen and lclose
|
||||
" for a better user experience. If the number of errors in a current
|
||||
" location list increases/decreases, cwindow will not resize when a new
|
||||
" updated height is passed. lopen in the other hand resizes the screen.
|
||||
if !a:0 || a:1 == 0
|
||||
call go#list#Close(a:listtype)
|
||||
return
|
||||
endif
|
||||
|
||||
let height = get(g:, "go_list_height", 0)
|
||||
if height == 0
|
||||
" prevent creating a large location height for a large set of numbers
|
||||
if a:1 > 10
|
||||
let height = 10
|
||||
else
|
||||
let height = a:1
|
||||
endif
|
||||
endif
|
||||
|
||||
if a:listtype == "locationlist"
|
||||
exe 'lopen ' . height
|
||||
else
|
||||
exe 'copen ' . height
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
" Get returns the current items from the list
|
||||
function! go#list#Get(listtype) abort
|
||||
if a:listtype == "locationlist"
|
||||
return getloclist(0)
|
||||
else
|
||||
return getqflist()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Populate populate the list with the given items
|
||||
function! go#list#Populate(listtype, items, title) abort
|
||||
if a:listtype == "locationlist"
|
||||
call setloclist(0, a:items, 'r')
|
||||
|
||||
" The last argument ({what}) is introduced with 7.4.2200:
|
||||
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
|
||||
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
|
||||
else
|
||||
call setqflist(a:items, 'r')
|
||||
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Parse parses the given items based on the specified errorformat and
|
||||
" populates the list.
|
||||
function! go#list#ParseFormat(listtype, errformat, items, title) abort
|
||||
" backup users errorformat, will be restored once we are finished
|
||||
let old_errorformat = &errorformat
|
||||
|
||||
" parse and populate the location list
|
||||
let &errorformat = a:errformat
|
||||
try
|
||||
call go#list#Parse(a:listtype, a:items, a:title)
|
||||
finally
|
||||
"restore back
|
||||
let &errorformat = old_errorformat
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Parse parses the given items based on the global errorformat and
|
||||
" populates the list.
|
||||
function! go#list#Parse(listtype, items, title) abort
|
||||
if a:listtype == "locationlist"
|
||||
lgetexpr a:items
|
||||
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
|
||||
else
|
||||
cgetexpr a:items
|
||||
if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" JumpToFirst jumps to the first item in the location list
|
||||
function! go#list#JumpToFirst(listtype) abort
|
||||
if a:listtype == "locationlist"
|
||||
ll 1
|
||||
else
|
||||
cc 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Clean cleans and closes the location list
|
||||
function! go#list#Clean(listtype) abort
|
||||
if a:listtype == "locationlist"
|
||||
lex []
|
||||
else
|
||||
cex []
|
||||
endif
|
||||
|
||||
call go#list#Close(a:listtype)
|
||||
endfunction
|
||||
|
||||
" Close closes the location list
|
||||
function! go#list#Close(listtype) abort
|
||||
let autoclose_window = get(g:, 'go_list_autoclose', 1)
|
||||
if !autoclose_window
|
||||
return
|
||||
endif
|
||||
|
||||
if a:listtype == "locationlist"
|
||||
lclose
|
||||
else
|
||||
cclose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:listtype(listtype) abort
|
||||
if g:go_list_type == "locationlist"
|
||||
return "locationlist"
|
||||
elseif g:go_list_type == "quickfix"
|
||||
return "quickfix"
|
||||
endif
|
||||
|
||||
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",
|
||||
\ "GoMetaLinterAutoSave": "locationlist",
|
||||
\ "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
|
||||
|
||||
return get(g:go_list_type_commands, a:for, l:listtype)
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
172
pack/acp/start/vim-go/autoload/go/package.vim
Normal file
172
pack/acp/start/vim-go/autoload/go/package.vim
Normal file
|
@ -0,0 +1,172 @@
|
|||
" Copyright 2011 The Go Authors. All rights reserved.
|
||||
" Use of this source code is governed by a BSD-style
|
||||
" license that can be found in the LICENSE file.
|
||||
"
|
||||
" This file provides a utility function that performs auto-completion of
|
||||
" package names, for use by other commands.
|
||||
|
||||
let s:goos = $GOOS
|
||||
let s:goarch = $GOARCH
|
||||
|
||||
if len(s:goos) == 0
|
||||
if exists('g:golang_goos')
|
||||
let s:goos = g:golang_goos
|
||||
elseif has('win32') || has('win64')
|
||||
let s:goos = 'windows'
|
||||
elseif has('macunix')
|
||||
let s:goos = 'darwin'
|
||||
else
|
||||
let s:goos = '*'
|
||||
endif
|
||||
endif
|
||||
|
||||
if len(s:goarch) == 0
|
||||
if exists('g:golang_goarch')
|
||||
let s:goarch = g:golang_goarch
|
||||
else
|
||||
let s:goarch = '*'
|
||||
endif
|
||||
endif
|
||||
|
||||
function! go#package#Paths() abort
|
||||
let dirs = []
|
||||
|
||||
if !exists("s:goroot")
|
||||
if executable('go')
|
||||
let s:goroot = go#util#env("goroot")
|
||||
if go#util#ShellError() != 0
|
||||
echomsg '''go env GOROOT'' failed'
|
||||
endif
|
||||
else
|
||||
let s:goroot = $GOROOT
|
||||
endif
|
||||
endif
|
||||
|
||||
if len(s:goroot) != 0 && isdirectory(s:goroot)
|
||||
let dirs += [s:goroot]
|
||||
endif
|
||||
|
||||
let workspaces = split(go#path#Default(), go#util#PathListSep())
|
||||
if workspaces != []
|
||||
let dirs += workspaces
|
||||
endif
|
||||
|
||||
return dirs
|
||||
endfunction
|
||||
|
||||
let s:import_paths = {}
|
||||
" ImportPath returns the import path in the current directory it was executed
|
||||
function! go#package#ImportPath() abort
|
||||
let dir = expand("%:p:h")
|
||||
if has_key(s:import_paths, dir)
|
||||
return s:import_paths[dir]
|
||||
endif
|
||||
|
||||
let out = go#tool#ExecuteInDir("go list")
|
||||
if go#util#ShellError() != 0
|
||||
return -1
|
||||
endif
|
||||
|
||||
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
|
||||
endif
|
||||
|
||||
let s:import_paths[dir] = import_path
|
||||
|
||||
return import_path
|
||||
endfunction
|
||||
|
||||
|
||||
function! go#package#FromPath(arg) abort
|
||||
let path = fnamemodify(resolve(a:arg), ':p')
|
||||
let dirs = go#package#Paths()
|
||||
|
||||
for dir in dirs
|
||||
if len(dir) && match(path, dir) == 0
|
||||
let workspace = dir
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
if !exists('workspace')
|
||||
return -1
|
||||
endif
|
||||
|
||||
let path = substitute(path, '/*$', '', '')
|
||||
let workspace = substitute(workspace . '/src/', '/+', '', '')
|
||||
if isdirectory(path)
|
||||
return substitute(path, workspace, '', '')
|
||||
else
|
||||
return substitute(substitute(path, workspace, '', ''),
|
||||
\ '/' . fnamemodify(path, ':t'), '', '')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! go#package#CompleteMembers(package, member) abort
|
||||
silent! let content = go#util#System('godoc ' . a:package)
|
||||
if go#util#ShellError() || !len(content)
|
||||
return []
|
||||
endif
|
||||
let lines = filter(split(content, "\n"),"v:val !~ '^\\s\\+$'")
|
||||
try
|
||||
let mx1 = '^\s\+\(\S+\)\s\+=\s\+.*'
|
||||
let mx2 = '^\%(const\|var\|type\|func\) \([A-Z][^ (]\+\).*'
|
||||
let candidates = map(filter(copy(lines), 'v:val =~ mx1'),
|
||||
\ 'substitute(v:val, mx1, "\\1", "")')
|
||||
\ + map(filter(copy(lines), 'v:val =~ mx2'),
|
||||
\ 'substitute(v:val, mx2, "\\1", "")')
|
||||
return filter(candidates, '!stridx(v:val, a:member)')
|
||||
catch
|
||||
return []
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort
|
||||
let words = split(a:CmdLine, '\s\+', 1)
|
||||
|
||||
" do not complete package members for these commands
|
||||
let neglect_commands = ["GoImportAs", "GoGuruScope"]
|
||||
|
||||
if len(words) > 2 && index(neglect_commands, words[0]) == -1
|
||||
" Complete package members
|
||||
return go#package#CompleteMembers(words[1], words[2])
|
||||
endif
|
||||
|
||||
let dirs = go#package#Paths()
|
||||
|
||||
if len(dirs) == 0
|
||||
" should not happen
|
||||
return []
|
||||
endif
|
||||
|
||||
let ret = {}
|
||||
for dir in dirs
|
||||
" this may expand to multiple lines
|
||||
let root = split(expand(dir . '/pkg/' . s:goos . '_' . s:goarch), "\n")
|
||||
call add(root, expand(dir . '/src'))
|
||||
for r in root
|
||||
for i in split(globpath(r, a:ArgLead.'*'), "\n")
|
||||
if isdirectory(i)
|
||||
let i .= '/'
|
||||
elseif i !~ '\.a$'
|
||||
continue
|
||||
endif
|
||||
let i = substitute(substitute(i[len(r)+1:], '[\\]', '/', 'g'),
|
||||
\ '\.a$', '', 'g')
|
||||
|
||||
" without this the result can have duplicates in form of
|
||||
" 'encoding/json' and '/encoding/json/'
|
||||
let i = go#util#StripPathSep(i)
|
||||
|
||||
let ret[i] = i
|
||||
endfor
|
||||
endfor
|
||||
endfor
|
||||
return sort(keys(ret))
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
196
pack/acp/start/vim-go/autoload/go/path.vim
Normal file
196
pack/acp/start/vim-go/autoload/go/path.vim
Normal file
|
@ -0,0 +1,196 @@
|
|||
" initial_go_path is used to store the initial GOPATH that was set when Vim
|
||||
" was started. It's used with :GoPathClear to restore the GOPATH when the user
|
||||
" changed it explicitly via :GoPath. Initially it's empty. It's being set when
|
||||
" :GoPath is used
|
||||
let s:initial_go_path = ""
|
||||
|
||||
" GoPath sets or echos the current GOPATH. If no arguments are passed it
|
||||
" echoes the current GOPATH, if an argument is passed it replaces the current
|
||||
" GOPATH with it. If two double quotes are passed (the empty string in go),
|
||||
" it'll clear the GOPATH and will restore to the initial GOPATH.
|
||||
function! go#path#GoPath(...) abort
|
||||
" no argument, show GOPATH
|
||||
if len(a:000) == 0
|
||||
echo go#path#Default()
|
||||
return
|
||||
endif
|
||||
|
||||
" we have an argument, replace GOPATH
|
||||
" clears the current manually set GOPATH and restores it to the
|
||||
" initial GOPATH, which was set when Vim was started.
|
||||
if len(a:000) == 1 && a:1 == '""'
|
||||
if !empty(s:initial_go_path)
|
||||
let $GOPATH = s:initial_go_path
|
||||
let s:initial_go_path = ""
|
||||
endif
|
||||
|
||||
echon "vim-go: " | echohl Function | echon "GOPATH restored to ". $GOPATH | echohl None
|
||||
return
|
||||
endif
|
||||
|
||||
echon "vim-go: " | echohl Function | echon "GOPATH changed to ". a:1 | echohl None
|
||||
let s:initial_go_path = $GOPATH
|
||||
let $GOPATH = a:1
|
||||
endfunction
|
||||
|
||||
" Default returns the default GOPATH. If GOPATH is not set, it uses the
|
||||
" default GOPATH set starting with Go 1.8. This GOPATH can be retrieved via
|
||||
" 'go env GOPATH'
|
||||
function! go#path#Default() abort
|
||||
if $GOPATH == ""
|
||||
" use default GOPATH via go env
|
||||
return go#util#env("gopath")
|
||||
endif
|
||||
|
||||
return $GOPATH
|
||||
endfunction
|
||||
|
||||
" s:HasPath checks whether the given path exists in GOPATH environment variable
|
||||
" or not
|
||||
function! s:HasPath(path) abort
|
||||
let go_paths = split(go#path#Default(), go#util#PathListSep())
|
||||
let last_char = strlen(a:path) - 1
|
||||
|
||||
" check cases of '/foo/bar/' and '/foo/bar'
|
||||
if a:path[last_char] == go#util#PathSep()
|
||||
let withSep = a:path
|
||||
let noSep = strpart(a:path, 0, last_char)
|
||||
else
|
||||
let withSep = a:path . go#util#PathSep()
|
||||
let noSep = a:path
|
||||
endif
|
||||
|
||||
let hasA = index(go_paths, withSep) != -1
|
||||
let hasB = index(go_paths, noSep) != -1
|
||||
return hasA || hasB
|
||||
endfunction
|
||||
|
||||
" Detect returns the current GOPATH. If a package manager is used, such as
|
||||
" Godeps, GB, it will modify the GOPATH so those directories take precedence
|
||||
" over the current GOPATH. It also detects diretories whose are outside
|
||||
" GOPATH.
|
||||
function! go#path#Detect() abort
|
||||
let gopath = go#path#Default()
|
||||
|
||||
let current_dir = fnameescape(expand('%:p:h'))
|
||||
|
||||
" TODO(arslan): this should be changed so folders or files should be
|
||||
" fetched from a customizable list. The user should define any new package
|
||||
" management tool by it's own.
|
||||
|
||||
" src folders outside $GOPATH
|
||||
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)
|
||||
let src_path = fnamemodify(src_root, ':p:h:h') . go#util#PathSep()
|
||||
|
||||
" gb vendor plugin
|
||||
" (https://github.com/constabulary/gb/tree/master/cmd/gb-vendor)
|
||||
let gb_vendor_root = src_path . "vendor" . go#util#PathSep()
|
||||
if isdirectory(gb_vendor_root) && !s:HasPath(gb_vendor_root)
|
||||
let gopath = gb_vendor_root . go#util#PathListSep() . gopath
|
||||
endif
|
||||
|
||||
if !s:HasPath(src_path)
|
||||
let gopath = src_path . go#util#PathListSep() . gopath
|
||||
endif
|
||||
endif
|
||||
|
||||
" Godeps
|
||||
let godeps_root = finddir("Godeps", current_dir .";")
|
||||
if !empty(godeps_root)
|
||||
let godeps_path = join([fnamemodify(godeps_root, ':p:h:h'), "Godeps", "_workspace" ], go#util#PathSep())
|
||||
|
||||
if !s:HasPath(godeps_path)
|
||||
let gopath = godeps_path . go#util#PathListSep() . gopath
|
||||
endif
|
||||
endif
|
||||
|
||||
" Fix up the case where initial $GOPATH is empty,
|
||||
" and we end up with a trailing :
|
||||
let gopath = substitute(gopath, ":$", "", "")
|
||||
return gopath
|
||||
endfunction
|
||||
|
||||
" BinPath returns the binary path of installed go tools.
|
||||
function! go#path#BinPath() abort
|
||||
let bin_path = ""
|
||||
|
||||
" check if our global custom path is set, if not check if $GOBIN is set so
|
||||
" we can use it, otherwise use default GOPATH
|
||||
if exists("g:go_bin_path")
|
||||
let bin_path = g:go_bin_path
|
||||
elseif $GOBIN != ""
|
||||
let bin_path = $GOBIN
|
||||
else
|
||||
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
|
||||
|
||||
return bin_path
|
||||
endfunction
|
||||
|
||||
" CheckBinPath checks whether the given binary exists or not and returns the
|
||||
" path of the binary. It returns an empty string doesn't exists.
|
||||
function! go#path#CheckBinPath(binpath) abort
|
||||
" remove whitespaces if user applied something like 'goimports '
|
||||
let binpath = substitute(a:binpath, '^\s*\(.\{-}\)\s*$', '\1', '')
|
||||
" save off original path
|
||||
let old_path = $PATH
|
||||
|
||||
" check if we have an appropriate bin_path
|
||||
let go_bin_path = go#path#BinPath()
|
||||
if !empty(go_bin_path)
|
||||
" append our GOBIN and GOPATH paths and be sure they can be found there...
|
||||
" let us search in our GOBIN and GOPATH paths
|
||||
let $PATH = go_bin_path . go#util#PathListSep() . $PATH
|
||||
endif
|
||||
|
||||
" if it's in PATH just return it
|
||||
if executable(binpath)
|
||||
if exists('*exepath')
|
||||
let binpath = exepath(binpath)
|
||||
endif
|
||||
let $PATH = old_path
|
||||
|
||||
if go#util#IsUsingCygwinShell() == 1
|
||||
return s:CygwinPath(binpath)
|
||||
endif
|
||||
|
||||
return binpath
|
||||
endif
|
||||
|
||||
" just get the basename
|
||||
let basename = fnamemodify(binpath, ":t")
|
||||
if !executable(basename)
|
||||
call go#util#EchoError(printf("could not find '%s'. Run :GoInstallBinaries to fix it", basename))
|
||||
|
||||
" restore back!
|
||||
let $PATH = old_path
|
||||
return ""
|
||||
endif
|
||||
|
||||
let $PATH = old_path
|
||||
|
||||
if go#util#IsUsingCygwinShell() == 1
|
||||
return s:CygwinPath(a:binpath)
|
||||
endif
|
||||
|
||||
return go_bin_path . go#util#PathSep() . basename
|
||||
endfunction
|
||||
|
||||
function! s:CygwinPath(path)
|
||||
return substitute(a:path, '\\', '/', "g")
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
73
pack/acp/start/vim-go/autoload/go/play.vim
Normal file
73
pack/acp/start/vim-go/autoload/go/play.vim
Normal file
|
@ -0,0 +1,73 @@
|
|||
if !exists("g:go_play_open_browser")
|
||||
let g:go_play_open_browser = 1
|
||||
endif
|
||||
|
||||
|
||||
function! go#play#Share(count, line1, line2) abort
|
||||
if !executable('curl')
|
||||
echohl ErrorMsg | echomsg "vim-go: require 'curl' command" | echohl None
|
||||
return
|
||||
endif
|
||||
|
||||
let content = join(getline(a:line1, a:line2), "\n")
|
||||
let share_file = tempname()
|
||||
call writefile(split(content, "\n"), share_file, "b")
|
||||
|
||||
let command = "curl -s -X POST https://play.golang.org/share --data-binary '@".share_file."'"
|
||||
let snippet_id = go#util#System(command)
|
||||
|
||||
" we can remove the temp file because it's now posted.
|
||||
call delete(share_file)
|
||||
|
||||
if go#util#ShellError() != 0
|
||||
echo 'A error has occurred. Run this command to see what the problem is:'
|
||||
echo command
|
||||
return
|
||||
endif
|
||||
|
||||
let url = "http://play.golang.org/p/".snippet_id
|
||||
|
||||
" copy to clipboard
|
||||
if has('unix') && !has('xterm_clipboard') && !has('clipboard')
|
||||
let @" = url
|
||||
else
|
||||
let @+ = url
|
||||
endif
|
||||
|
||||
if g:go_play_open_browser != 0
|
||||
call go#tool#OpenBrowser(url)
|
||||
endif
|
||||
|
||||
echo "vim-go: snippet uploaded: ".url
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:get_visual_content() abort
|
||||
let save_regcont = @"
|
||||
let save_regtype = getregtype('"')
|
||||
silent! normal! gvy
|
||||
let content = @"
|
||||
call setreg('"', save_regcont, save_regtype)
|
||||
return content
|
||||
endfunction
|
||||
|
||||
" modified version of
|
||||
" http://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript
|
||||
" another function that returns the content of visual selection, it's not used
|
||||
" but might be useful in the future
|
||||
function! s:get_visual_selection() abort
|
||||
let [lnum1, col1] = getpos("'<")[1:2]
|
||||
let [lnum2, col2] = getpos("'>")[1:2]
|
||||
|
||||
" check if the the visual mode is used before
|
||||
if lnum1 == 0 || lnum2 == 0 || col1 == 0 || col2 == 0
|
||||
return
|
||||
endif
|
||||
|
||||
let lines = getline(lnum1, lnum2)
|
||||
let lines[-1] = lines[-1][: col2 - (&selection == 'inclusive' ? 1 : 2)]
|
||||
let lines[0] = lines[0][col1 - 1:]
|
||||
return join(lines, "\n")
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
181
pack/acp/start/vim-go/autoload/go/rename.vim
Normal file
181
pack/acp/start/vim-go/autoload/go/rename.vim
Normal file
|
@ -0,0 +1,181 @@
|
|||
if !exists("g:go_gorename_bin")
|
||||
let g:go_gorename_bin = "gorename"
|
||||
endif
|
||||
|
||||
" Set the default value. A value of "1" is a shortcut for this, for
|
||||
" 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
|
||||
endfunction
|
||||
call s:default()
|
||||
|
||||
function! go#rename#Rename(bang, ...) abort
|
||||
call s:default()
|
||||
|
||||
let to_identifier = ""
|
||||
if a:0 == 0
|
||||
let ask = printf("vim-go: rename '%s' to: ", expand("<cword>"))
|
||||
if g:go_gorename_prefill != ''
|
||||
let to_identifier = input(ask, eval(g:go_gorename_prefill))
|
||||
else
|
||||
let to_identifier = input(ask)
|
||||
endif
|
||||
redraw!
|
||||
if empty(to_identifier)
|
||||
return
|
||||
endif
|
||||
else
|
||||
let to_identifier = a:1
|
||||
endif
|
||||
|
||||
" return with a warning if the bin doesn't exist
|
||||
let bin_path = go#path#CheckBinPath(g:go_gorename_bin)
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
|
||||
let fname = expand('%:p')
|
||||
let pos = go#util#OffsetCursor()
|
||||
let offset = printf('%s:#%d', fname, pos)
|
||||
|
||||
" no need to escape for job call
|
||||
let bin_path = go#util#has_job() ? bin_path : shellescape(bin_path)
|
||||
let offset = go#util#has_job() ? offset : shellescape(offset)
|
||||
let to_identifier = go#util#has_job() ? to_identifier : shellescape(to_identifier)
|
||||
|
||||
let cmd = [bin_path, "-offset", offset, "-to", to_identifier]
|
||||
|
||||
" check for any tags
|
||||
if exists('g:go_build_tags')
|
||||
let tags = get(g:, 'go_build_tags')
|
||||
call extend(cmd, ["-tags", tags])
|
||||
endif
|
||||
|
||||
if go#util#has_job()
|
||||
call go#util#EchoProgress(printf("renaming to '%s' ...", to_identifier))
|
||||
call s:rename_job({
|
||||
\ 'cmd': cmd,
|
||||
\ 'bang': a:bang,
|
||||
\})
|
||||
return
|
||||
endif
|
||||
|
||||
let command = join(cmd, " ")
|
||||
let out = go#tool#ExecuteInDir(command)
|
||||
|
||||
let splitted = split(out, '\n')
|
||||
call s:parse_errors(go#util#ShellError(), a:bang, splitted)
|
||||
endfunction
|
||||
|
||||
function s:rename_job(args)
|
||||
let state = {
|
||||
\ 'exited': 0,
|
||||
\ 'closed': 0,
|
||||
\ 'exitval': 0,
|
||||
\ 'messages': [],
|
||||
\ 'status_dir': expand('%:p:h'),
|
||||
\ 'bang': a:args.bang
|
||||
\ }
|
||||
|
||||
function! s:callback(chan, msg) dict
|
||||
call add(self.messages, a:msg)
|
||||
endfunction
|
||||
|
||||
function! s:exit_cb(job, exitval) dict
|
||||
let self.exited = 1
|
||||
let self.exitval = a:exitval
|
||||
|
||||
let status = {
|
||||
\ 'desc': 'last status',
|
||||
\ 'type': "gorename",
|
||||
\ 'state': "finished",
|
||||
\ }
|
||||
|
||||
if a:exitval
|
||||
let status.state = "failed"
|
||||
endif
|
||||
|
||||
call go#statusline#Update(self.status_dir, status)
|
||||
|
||||
if self.closed
|
||||
call s:parse_errors(self.exitval, self.bang, self.messages)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_cb(ch) dict
|
||||
let self.closed = 1
|
||||
|
||||
if self.exited
|
||||
call s:parse_errors(self.exitval, self.bang, self.messages)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" explicitly bind the callbacks to state so that self within them always
|
||||
" refers to state. See :help Partial for more information.
|
||||
let start_options = {
|
||||
\ 'callback': funcref("s:callback", [], state),
|
||||
\ 'exit_cb': funcref("s:exit_cb", [], state),
|
||||
\ 'close_cb': funcref("s:close_cb", [], state),
|
||||
\ }
|
||||
|
||||
call go#statusline#Update(state.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))
|
||||
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(a:out)
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
" strip out newline on the end that gorename puts. If we don't remove, it
|
||||
" will trigger the 'Hit ENTER to continue' prompt
|
||||
call go#list#Clean(l:listtype)
|
||||
call go#util#EchoSuccess(a:out[0])
|
||||
|
||||
" refresh the buffer so we can see the new content
|
||||
" TODO(arslan): also find all other buffers and refresh them too. For this
|
||||
" we need a way to get the list of changes from gorename upon an success
|
||||
" change.
|
||||
silent execute ":e"
|
||||
endfunction
|
||||
|
||||
" 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
|
112
pack/acp/start/vim-go/autoload/go/statusline.vim
Normal file
112
pack/acp/start/vim-go/autoload/go/statusline.vim
Normal file
|
@ -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
|
214
pack/acp/start/vim-go/autoload/go/tags.vim
Normal file
214
pack/acp/start/vim-go/autoload/go/tags.vim
Normal file
|
@ -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
|
22
pack/acp/start/vim-go/autoload/go/tags_test.vim
Normal file
22
pack/acp/start/vim-go/autoload/go/tags_test.vim
Normal file
|
@ -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
|
53
pack/acp/start/vim-go/autoload/go/template.vim
Normal file
53
pack/acp/start/vim-go/autoload/go/template.vim
Normal file
|
@ -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 'keepalt 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
|
119
pack/acp/start/vim-go/autoload/go/term.vim
Normal file
119
pack/acp/start/vim-go/autoload/go/term.vim
Normal file
|
@ -0,0 +1,119 @@
|
|||
if has('nvim') && !exists("g:go_term_mode")
|
||||
let g:go_term_mode = 'vsplit'
|
||||
endif
|
||||
|
||||
" new creates a new terminal with the given command. Mode is set based on the
|
||||
" global variable g:go_term_mode, which is by default set to :vsplit
|
||||
function! go#term#new(bang, cmd) abort
|
||||
return go#term#newmode(a:bang, a:cmd, g:go_term_mode)
|
||||
endfunction
|
||||
|
||||
" new creates a new terminal with the given command and window mode.
|
||||
function! go#term#newmode(bang, cmd, mode) abort
|
||||
let mode = a:mode
|
||||
if empty(mode)
|
||||
let mode = g:go_term_mode
|
||||
endif
|
||||
|
||||
let state = {
|
||||
\ 'cmd': a:cmd,
|
||||
\ 'bang' : a:bang,
|
||||
\ 'winid': win_getid(winnr()),
|
||||
\ 'stdout': []
|
||||
\ }
|
||||
|
||||
" execute go build in the files directory
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
let dir = getcwd()
|
||||
|
||||
execute cd . fnameescape(expand("%:p:h"))
|
||||
|
||||
execute mode.' __go_term__'
|
||||
|
||||
setlocal filetype=goterm
|
||||
setlocal bufhidden=delete
|
||||
setlocal winfixheight
|
||||
setlocal noswapfile
|
||||
setlocal nobuflisted
|
||||
|
||||
" explicitly bind callbacks to state so that within them, self will always
|
||||
" refer to state. See :help Partial for more information.
|
||||
"
|
||||
" Don't set an on_stderr, because it will be passed the same data as
|
||||
" on_stdout. See https://github.com/neovim/neovim/issues/2836
|
||||
let job = {
|
||||
\ 'on_stdout': function('s:on_stdout', [], state),
|
||||
\ 'on_exit' : function('s:on_exit', [], state),
|
||||
\ }
|
||||
|
||||
let state.id = termopen(a:cmd, job)
|
||||
let state.termwinid = win_getid(winnr())
|
||||
|
||||
execute cd . fnameescape(dir)
|
||||
|
||||
" resize new term if needed.
|
||||
let height = get(g:, 'go_term_height', winheight(0))
|
||||
let width = get(g:, 'go_term_width', winwidth(0))
|
||||
|
||||
" Adjust the window width or height depending on whether it's a vertical or
|
||||
" horizontal split.
|
||||
if mode =~ "vertical" || mode =~ "vsplit" || mode =~ "vnew"
|
||||
exe 'vertical resize ' . width
|
||||
elseif mode =~ "split" || mode =~ "new"
|
||||
exe 'resize ' . height
|
||||
endif
|
||||
|
||||
" we also need to resize the pty, so there you go...
|
||||
call jobresize(state.id, width, height)
|
||||
|
||||
call win_gotoid(state.winid)
|
||||
|
||||
return state.id
|
||||
endfunction
|
||||
|
||||
function! s:on_stdout(job_id, data, event) dict abort
|
||||
call extend(self.stdout, a:data)
|
||||
endfunction
|
||||
|
||||
function! s:on_exit(job_id, exit_status, event) dict abort
|
||||
let l:listtype = go#list#Type("_term")
|
||||
|
||||
" usually there is always output so never branch into this clause
|
||||
if empty(self.stdout)
|
||||
call s:cleanlist(self.winid, l:listtype)
|
||||
return
|
||||
endif
|
||||
|
||||
let errors = go#tool#ParseErrors(self.stdout)
|
||||
let errors = go#tool#FilterValids(errors)
|
||||
|
||||
if !empty(errors)
|
||||
" close terminal; we don't need it anymore
|
||||
call win_gotoid(self.termwinid)
|
||||
close
|
||||
|
||||
call win_gotoid(self.winid)
|
||||
|
||||
call go#list#Populate(l:listtype, errors, self.cmd)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !self.bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
call s:cleanlist(self.winid, l:listtype)
|
||||
endfunction
|
||||
|
||||
function! s:cleanlist(winid, listtype) abort
|
||||
" There are no errors. Clean and close the list. Jump to the window to which
|
||||
" the location list is attached, close the list, and then jump back to the
|
||||
" current window.
|
||||
let winid = win_getid(winnr())
|
||||
call win_gotoid(a:winid)
|
||||
call go#list#Clean(a:listtype)
|
||||
call win_gotoid(l:winid)
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
50
pack/acp/start/vim-go/autoload/go/term_test.vim
Normal file
50
pack/acp/start/vim-go/autoload/go/term_test.vim
Normal file
|
@ -0,0 +1,50 @@
|
|||
func! Test_GoTermNewMode()
|
||||
if !has('nvim')
|
||||
return
|
||||
endif
|
||||
|
||||
try
|
||||
let l:filename = 'term/term.go'
|
||||
let l:tmp = gotest#load_fixture(l:filename)
|
||||
exe 'cd ' . l:tmp . '/src/term'
|
||||
|
||||
let expected = expand('%:p')
|
||||
|
||||
let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
|
||||
|
||||
set nosplitright
|
||||
call go#term#newmode(0, cmd, '')
|
||||
let actual = expand('%:p')
|
||||
call assert_equal(actual, l:expected)
|
||||
|
||||
finally
|
||||
call delete(l:tmp, 'rf')
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func! Test_GoTermNewMode_SplitRight()
|
||||
if !has('nvim')
|
||||
return
|
||||
endif
|
||||
|
||||
try
|
||||
let l:filename = 'term/term.go'
|
||||
let l:tmp = gotest#load_fixture(l:filename)
|
||||
exe 'cd ' . l:tmp . '/src/term'
|
||||
|
||||
let expected = expand('%:p')
|
||||
|
||||
let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
|
||||
|
||||
set splitright
|
||||
call go#term#newmode(0, cmd, '')
|
||||
let actual = expand('%:p')
|
||||
call assert_equal(actual, l:expected)
|
||||
|
||||
finally
|
||||
call delete(l:tmp, 'rf')
|
||||
set nosplitright
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
" vim: sw=2 ts=2 et
|
|
@ -0,0 +1,5 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
notafunc()
|
||||
}
|
|
@ -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")
|
||||
}
|
12
pack/acp/start/vim-go/autoload/go/test-fixtures/fmt/imports/vendor/gh.com/gi/foo-logging/logger.go
generated
vendored
Normal file
12
pack/acp/start/vim-go/autoload/go/test-fixtures/fmt/imports/vendor/gh.com/gi/foo-logging/logger.go
generated
vendored
Normal file
|
@ -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)
|
||||
}
|
1
pack/acp/start/vim-go/autoload/go/test-fixtures/fmt/src/imports
Symbolic link
1
pack/acp/start/vim-go/autoload/go/test-fixtures/fmt/src/imports
Symbolic link
|
@ -0,0 +1 @@
|
|||
../imports/
|
|
@ -0,0 +1,7 @@
|
|||
package foo
|
||||
|
||||
import "fmt"
|
||||
|
||||
func MissingFooDoc() {
|
||||
fmt.Println("missing doc")
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package lint
|
||||
|
||||
import "fmt"
|
||||
|
||||
func MissingDoc() {
|
||||
fmt.Println("missing doc")
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package lint
|
||||
|
||||
import "fmt"
|
||||
|
||||
func AlsoMissingDoc() {
|
||||
fmt.Println("missing doc")
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
str := "hello world!"
|
||||
fmt.Printf("%d\n", str)
|
||||
}
|
|
@ -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,5 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
println("hello, world")
|
||||
}
|
1
pack/acp/start/vim-go/autoload/go/test-fixtures/test/.gitignore
vendored
Normal file
1
pack/acp/start/vim-go/autoload/go/test-fixtures/test/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/pkg
|
|
@ -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,59 @@
|
|||
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")
|
||||
t.Error("\nthis is another error")
|
||||
}
|
||||
|
||||
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,11 @@
|
|||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestHelloWorld(t *testing.T) {
|
||||
t.Error("so long")
|
||||
|
||||
t.Run("sub", func(t *testing.T) {
|
||||
t.Error("thanks for all the fish")
|
||||
})
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Run a few parallel tests, all in parallel, using multiple techniques for
|
||||
// causing the test to take a while so that the stacktraces resulting from a
|
||||
// test timeout will contain several goroutines to avoid giving a false sense
|
||||
// of confidence or creating error formats that don't account for the more
|
||||
// complex scenarios that can occur with timeouts.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSleep(t *testing.T) {
|
||||
t.Parallel()
|
||||
time.Sleep(15 * time.Second)
|
||||
t.Log("expected panic if run with timeout < 15s")
|
||||
}
|
||||
|
||||
func TestRunning(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := time.After(15 * time.Second)
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case <-c:
|
||||
break Loop
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
t.Log("expected panic if run with timeout < 15s")
|
||||
}
|
||||
|
||||
func TestRunningAlso(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := time.After(15 * time.Second)
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case <-c:
|
||||
break Loop
|
||||
default:
|
||||
}
|
||||
}
|
||||
t.Log("expected panic if run with timeout < 15s")
|
||||
}
|
428
pack/acp/start/vim-go/autoload/go/test.vim
Normal file
428
pack/acp/start/vim-go/autoload/go/test.vim
Normal file
|
@ -0,0 +1,428 @@
|
|||
" 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)
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
call call('go#test#Test', args)
|
||||
endfunction
|
||||
|
||||
function! s:test_job(args) abort
|
||||
let status = {
|
||||
\ 'desc': 'current status',
|
||||
\ 'type': "test",
|
||||
\ 'state': "started",
|
||||
\ }
|
||||
|
||||
if a:args.compile_test
|
||||
let status.state = "compiling"
|
||||
endif
|
||||
|
||||
" autowrite is not enabled for jobs
|
||||
call go#cmd#autowrite()
|
||||
|
||||
let state = {
|
||||
\ 'exited': 0,
|
||||
\ 'closed': 0,
|
||||
\ 'exitval': 0,
|
||||
\ 'messages': [],
|
||||
\ 'args': a:args,
|
||||
\ 'compile_test': a:args.compile_test,
|
||||
\ 'status_dir': expand('%:p:h'),
|
||||
\ 'started_at': reltime()
|
||||
\ }
|
||||
|
||||
call go#statusline#Update(state.status_dir, status)
|
||||
|
||||
function! s:callback(chan, msg) dict
|
||||
call add(self.messages, a:msg)
|
||||
endfunction
|
||||
|
||||
function! s:exit_cb(job, exitval) dict
|
||||
let self.exited = 1
|
||||
let self.exitval = a:exitval
|
||||
|
||||
let status = {
|
||||
\ 'desc': 'last status',
|
||||
\ 'type': "test",
|
||||
\ 'state': "pass",
|
||||
\ }
|
||||
|
||||
if self.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 self.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(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)
|
||||
|
||||
if self.closed
|
||||
call s:show_errors(self.args, self.exitval, self.messages)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_cb(ch) dict
|
||||
let self.closed = 1
|
||||
|
||||
if self.exited
|
||||
call s:show_errors(self.args, self.exitval, self.messages)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" explicitly bind the callbacks to state so that self within them always
|
||||
" refers to state. See :help Partial for more information.
|
||||
let start_options = {
|
||||
\ 'callback': funcref("s:callback", [], state),
|
||||
\ 'exit_cb': funcref("s:exit_cb", [], state),
|
||||
\ 'close_cb': funcref("s:close_cb", [], state)
|
||||
\ }
|
||||
|
||||
" 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")
|
||||
if a:exit_val == 0
|
||||
call go#list#Clean(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.
|
||||
|
||||
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= ""
|
||||
let s:go_test_show_name=0
|
||||
|
||||
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()
|
||||
|
||||
let show_name=get(g:, 'go_test_show_name', 0)
|
||||
if s:efm != "" && s:go_test_show_name == show_name
|
||||
return s:efm
|
||||
endif
|
||||
let s:go_test_show_name = show_name
|
||||
|
||||
" each level of test indents the test output 4 spaces. Capturing groups
|
||||
" (e.g. \(\)) cannot be used in an errorformat, but non-capturing groups can
|
||||
" (e.g. \%(\)).
|
||||
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 show_name
|
||||
let format .= ",%G" . indent . "--- FAIL: %m (%.%#)"
|
||||
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"
|
||||
" also match lines that don't have a message (i.e. the message begins with a
|
||||
" newline or is the empty string):
|
||||
" e.g.:
|
||||
" t.Errorf("\ngot %v; want %v", actual, expected)
|
||||
" t.Error("")
|
||||
let format .= ",%A" . indent . "%\\t%\\+%f:%l: "
|
||||
|
||||
" 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.
|
||||
|
||||
" handle panics from test timeouts
|
||||
let format .= ",%+Gpanic: test timed out after %.%\\+"
|
||||
|
||||
" handle non-timeout 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
|
121
pack/acp/start/vim-go/autoload/go/test_test.vim
Normal file
121
pack/acp/start/vim-go/autoload/go/test_test.vim
Normal file
|
@ -0,0 +1,121 @@
|
|||
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': 21, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': ''},
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is another error'},
|
||||
\ {'lnum': 26, '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': 43, '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': 50, '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': 21, 'bufnr': 2, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': ''},
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'this is another error'},
|
||||
\ {'lnum': 26, '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': 32, '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': 43, '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! Test_GoTestTimeout() abort
|
||||
let expected = [
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'panic: test timed out after 500ms'}
|
||||
\ ]
|
||||
|
||||
let g:go_test_timeout="500ms"
|
||||
call s:test('timeout/timeout_test.go', expected)
|
||||
unlet g:go_test_timeout
|
||||
endfunc
|
||||
|
||||
func! Test_GoTestShowName() abort
|
||||
let expected = [
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'},
|
||||
\ {'lnum': 6, 'bufnr': 9, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'},
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'},
|
||||
\ {'lnum': 9, 'bufnr': 9, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'},
|
||||
\ ]
|
||||
|
||||
let g:go_test_show_name=1
|
||||
call s:test('showname/showname_test.go', expected)
|
||||
let g:go_test_show_name=0
|
||||
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(fnamemodify(getcwd(), ':p')) . '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 item in actual
|
||||
let item.text = s:normalize_durations(item.text)
|
||||
endfor
|
||||
|
||||
for item in a:expected
|
||||
let item.text = s:normalize_durations(item.text)
|
||||
endfor
|
||||
|
||||
call gotest#assert_quickfix(actual, a:expected)
|
||||
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
|
204
pack/acp/start/vim-go/autoload/go/textobj.vim
Normal file
204
pack/acp/start/vim-go/autoload/go/textobj.vim
Normal file
|
@ -0,0 +1,204 @@
|
|||
if !exists("g:go_textobj_enabled")
|
||||
let g:go_textobj_enabled = 1
|
||||
endif
|
||||
|
||||
if !exists("g:go_textobj_include_function_doc")
|
||||
let g:go_textobj_include_function_doc = 1
|
||||
endif
|
||||
|
||||
if !exists("g:go_textobj_include_variable")
|
||||
let g:go_textobj_include_variable = 1
|
||||
endif
|
||||
|
||||
" ( ) motions
|
||||
" { } motions
|
||||
" s for sentence
|
||||
" p for parapgrah
|
||||
" < >
|
||||
" t for tag
|
||||
|
||||
" Select a function in visual mode.
|
||||
function! go#textobj#Function(mode) abort
|
||||
let offset = go#util#OffsetCursor()
|
||||
|
||||
let fname = shellescape(expand("%:p"))
|
||||
if &modified
|
||||
" Write current unsaved buffer to a temp file and use the modified content
|
||||
let l:tmpname = tempname()
|
||||
call writefile(go#util#GetLines(), l:tmpname)
|
||||
let fname = l:tmpname
|
||||
endif
|
||||
|
||||
let bin_path = go#path#CheckBinPath('motion')
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
|
||||
let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset)
|
||||
let command .= " -mode enclosing"
|
||||
|
||||
if g:go_textobj_include_function_doc
|
||||
let command .= " -parse-comments"
|
||||
endif
|
||||
|
||||
let out = go#util#System(command)
|
||||
if go#util#ShellError() != 0
|
||||
call go#util#EchoError(out)
|
||||
return
|
||||
endif
|
||||
|
||||
" if exists, delete it as we don't need it anymore
|
||||
if exists("l:tmpname")
|
||||
call delete(l:tmpname)
|
||||
endif
|
||||
|
||||
" convert our string dict representation into native Vim dictionary type
|
||||
let result = eval(out)
|
||||
if type(result) != 4 || !has_key(result, 'fn')
|
||||
return
|
||||
endif
|
||||
|
||||
let info = result.fn
|
||||
|
||||
if a:mode == 'a'
|
||||
" anonymous functions doesn't have associated doc. Also check if the user
|
||||
" want's to include doc comments for function declarations
|
||||
if has_key(info, 'doc') && g:go_textobj_include_function_doc
|
||||
call cursor(info.doc.line, info.doc.col)
|
||||
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
|
||||
call cursor(info.func.line, info.func.col)
|
||||
endif
|
||||
|
||||
normal! v
|
||||
call cursor(info.rbrace.line, info.rbrace.col)
|
||||
return
|
||||
endif
|
||||
|
||||
" rest is inner mode, a:mode == 'i'
|
||||
|
||||
" if the function is a one liner we need to select only that portion
|
||||
if info.lbrace.line == info.rbrace.line
|
||||
call cursor(info.lbrace.line, info.lbrace.col+1)
|
||||
normal! v
|
||||
call cursor(info.rbrace.line, info.rbrace.col-1)
|
||||
return
|
||||
endif
|
||||
|
||||
call cursor(info.lbrace.line+1, 1)
|
||||
normal! V
|
||||
call cursor(info.rbrace.line-1, 1)
|
||||
endfunction
|
||||
|
||||
" Get the location of the previous or next function.
|
||||
function! go#textobj#FunctionLocation(direction, cnt) abort
|
||||
let offset = go#util#OffsetCursor()
|
||||
|
||||
let fname = shellescape(expand("%:p"))
|
||||
if &modified
|
||||
" Write current unsaved buffer to a temp file and use the modified content
|
||||
let l:tmpname = tempname()
|
||||
call writefile(go#util#GetLines(), l:tmpname)
|
||||
let fname = l:tmpname
|
||||
endif
|
||||
|
||||
let bin_path = go#path#CheckBinPath('motion')
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
|
||||
let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset)
|
||||
let command .= ' -shift ' . a:cnt
|
||||
|
||||
if a:direction == 'next'
|
||||
let command .= ' -mode next'
|
||||
else " 'prev'
|
||||
let command .= ' -mode prev'
|
||||
endif
|
||||
|
||||
if g:go_textobj_include_function_doc
|
||||
let command .= " -parse-comments"
|
||||
endif
|
||||
|
||||
let out = go#util#System(command)
|
||||
if go#util#ShellError() != 0
|
||||
call go#util#EchoError(out)
|
||||
return
|
||||
endif
|
||||
|
||||
" if exists, delete it as we don't need it anymore
|
||||
if exists("l:tmpname")
|
||||
call delete(l:tmpname)
|
||||
endif
|
||||
|
||||
let l:result = json_decode(out)
|
||||
if type(l:result) != 4 || !has_key(l:result, 'fn')
|
||||
return 0
|
||||
endif
|
||||
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
function! go#textobj#FunctionJump(mode, direction) abort
|
||||
" get count of the motion. This should be done before all the normal
|
||||
" expressions below as those reset this value(because they have zero
|
||||
" count!). We abstract -1 because the index starts from 0 in motion.
|
||||
let l:cnt = v:count1 - 1
|
||||
|
||||
" set context mark so we can jump back with '' or ``
|
||||
normal! m'
|
||||
|
||||
" select already previously selected visual content and continue from there.
|
||||
" If it's the first time starts with the visual mode. This is needed so
|
||||
" after selecting something in visual mode, every consecutive motion
|
||||
" continues.
|
||||
if a:mode == 'v'
|
||||
normal! gv
|
||||
endif
|
||||
|
||||
let l:result = go#textobj#FunctionLocation(a:direction, l:cnt)
|
||||
if l:result is 0
|
||||
return
|
||||
endif
|
||||
|
||||
" we reached the end and there are no functions. The usual [[ or ]] jumps to
|
||||
" the top or bottom, we'll do the same.
|
||||
if type(result) == 4 && has_key(result, 'err') && result.err == "no functions found"
|
||||
if a:direction == 'next'
|
||||
keepjumps normal! G
|
||||
else " 'prev'
|
||||
keepjumps normal! gg
|
||||
endif
|
||||
return
|
||||
endif
|
||||
|
||||
let info = result.fn
|
||||
|
||||
" if we select something ,select all function
|
||||
if a:mode == 'v' && a:direction == 'next'
|
||||
keepjumps call cursor(info.rbrace.line, 1)
|
||||
return
|
||||
endif
|
||||
|
||||
if a:mode == 'v' && a:direction == 'prev'
|
||||
if has_key(info, 'doc') && g:go_textobj_include_function_doc
|
||||
keepjumps call cursor(info.doc.line, 1)
|
||||
else
|
||||
keepjumps call cursor(info.func.line, 1)
|
||||
endif
|
||||
return
|
||||
endif
|
||||
|
||||
keepjumps call cursor(info.func.line, 1)
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
245
pack/acp/start/vim-go/autoload/go/tool.vim
Normal file
245
pack/acp/start/vim-go/autoload/go/tool.vim
Normal file
|
@ -0,0 +1,245 @@
|
|||
" 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()
|
||||
let combined .= '{{range $f := .' . sf . '}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}'
|
||||
else
|
||||
let combined .= "{{range $f := ." . sf . "}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}"
|
||||
endif
|
||||
endfor
|
||||
|
||||
let out = go#tool#ExecuteInDir('go list -f ' . shellescape(combined))
|
||||
return split(out, '\n')
|
||||
endfunction
|
||||
|
||||
function! go#tool#Deps() abort
|
||||
if go#util#IsWin()
|
||||
let format = '{{range $f := .Deps}}{{$f}}{{printf \"\n\"}}{{end}}'
|
||||
else
|
||||
let format = "{{range $f := .Deps}}{{$f}}\n{{end}}"
|
||||
endif
|
||||
let command = 'go list -f '.shellescape(format)
|
||||
let out = go#tool#ExecuteInDir(command)
|
||||
return split(out, '\n')
|
||||
endfunction
|
||||
|
||||
function! go#tool#Imports() abort
|
||||
let imports = {}
|
||||
if go#util#IsWin()
|
||||
let format = '{{range $f := .Imports}}{{$f}}{{printf \"\n\"}}{{end}}'
|
||||
else
|
||||
let format = "{{range $f := .Imports}}{{$f}}{{printf \"\\n\"}}{{end}}"
|
||||
endif
|
||||
let command = 'go list -f '.shellescape(format)
|
||||
let out = go#tool#ExecuteInDir(command)
|
||||
if go#util#ShellError() != 0
|
||||
echo out
|
||||
return imports
|
||||
endif
|
||||
|
||||
for package_path in split(out, '\n')
|
||||
let cmd = "go list -f '{{.Name}}' " . shellescape(package_path)
|
||||
let package_name = substitute(go#tool#ExecuteInDir(cmd), '\n$', '', '')
|
||||
let imports[package_name] = package_path
|
||||
endfor
|
||||
|
||||
return imports
|
||||
endfunction
|
||||
|
||||
function! go#tool#Info(auto) abort
|
||||
let l:mode = get(g:, 'go_info_mode', 'gocode')
|
||||
if l:mode == 'gocode'
|
||||
call go#complete#Info(a:auto)
|
||||
elseif l:mode == 'guru'
|
||||
call go#guru#DescribeInfo()
|
||||
else
|
||||
call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru]')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! go#tool#PackageName() abort
|
||||
let command = "go list -f \"{{.Name}}\""
|
||||
let out = go#tool#ExecuteInDir(command)
|
||||
if go#util#ShellError() != 0
|
||||
return -1
|
||||
endif
|
||||
|
||||
return split(out, '\n')[0]
|
||||
endfunction
|
||||
|
||||
function! go#tool#ParseErrors(lines) abort
|
||||
let errors = []
|
||||
|
||||
for line in a:lines
|
||||
let fatalerrors = matchlist(line, '^\(fatal error:.*\)$')
|
||||
let tokens = matchlist(line, '^\s*\(.\{-}\):\(\d\+\):\s*\(.*\)')
|
||||
|
||||
if !empty(fatalerrors)
|
||||
call add(errors, {"text": fatalerrors[1]})
|
||||
elseif !empty(tokens)
|
||||
" strip endlines of form ^M
|
||||
let out = substitute(tokens[3], '\r$', '', '')
|
||||
|
||||
call add(errors, {
|
||||
\ "filename" : fnamemodify(tokens[1], ':p'),
|
||||
\ "lnum" : tokens[2],
|
||||
\ "text" : out,
|
||||
\ })
|
||||
elseif !empty(errors)
|
||||
" Preserve indented lines.
|
||||
" This comes up especially with multi-line test output.
|
||||
if match(line, '^\s') >= 0
|
||||
call add(errors, {"text": line})
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
return errors
|
||||
endfunction
|
||||
|
||||
"FilterValids filters the given items with only items that have a valid
|
||||
"filename. Any non valid filename is filtered out.
|
||||
function! go#tool#FilterValids(items) abort
|
||||
" Remove any nonvalid filename from the location list to avoid opening an
|
||||
" empty buffer. See https://github.com/fatih/vim-go/issues/287 for
|
||||
" details.
|
||||
let filtered = []
|
||||
let is_readable = {}
|
||||
|
||||
for item in a:items
|
||||
if has_key(item, 'bufnr')
|
||||
let filename = bufname(item.bufnr)
|
||||
elseif has_key(item, 'filename')
|
||||
let filename = item.filename
|
||||
else
|
||||
" nothing to do, add item back to the list
|
||||
call add(filtered, item)
|
||||
continue
|
||||
endif
|
||||
|
||||
if !has_key(is_readable, filename)
|
||||
let is_readable[filename] = filereadable(filename)
|
||||
endif
|
||||
if is_readable[filename]
|
||||
call add(filtered, item)
|
||||
endif
|
||||
endfor
|
||||
|
||||
for k in keys(filter(is_readable, '!v:val'))
|
||||
echo "vim-go: " | echohl Identifier | echon "[run] Dropped " | echohl Constant | echon '"' . k . '"'
|
||||
echohl Identifier | echon " from location list (nonvalid filename)" | echohl None
|
||||
endfor
|
||||
|
||||
return filtered
|
||||
endfunction
|
||||
|
||||
function! go#tool#ExecuteInDir(cmd) abort
|
||||
" Verify that the directory actually exists. If the directory does not
|
||||
" 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 dir = getcwd()
|
||||
try
|
||||
execute cd . fnameescape(expand("%:p:h"))
|
||||
let out = go#util#System(a:cmd)
|
||||
finally
|
||||
execute cd . fnameescape(dir)
|
||||
endtry
|
||||
return out
|
||||
endfunction
|
||||
|
||||
" Exists checks whether the given importpath exists or not. It returns 0 if
|
||||
" the importpath exists under GOPATH.
|
||||
function! go#tool#Exists(importpath) abort
|
||||
let command = "go list ". a:importpath
|
||||
let out = go#tool#ExecuteInDir(command)
|
||||
|
||||
if go#util#ShellError() != 0
|
||||
return -1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" following two functions are from: https://github.com/mattn/gist-vim
|
||||
" thanks @mattn
|
||||
function! s:get_browser_command() abort
|
||||
let go_play_browser_command = get(g:, 'go_play_browser_command', '')
|
||||
if go_play_browser_command == ''
|
||||
if go#util#IsWin()
|
||||
let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
|
||||
elseif go#util#IsMac()
|
||||
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% &'
|
||||
elseif executable('chromium')
|
||||
let go_play_browser_command = 'chromium %URL% &'
|
||||
else
|
||||
let go_play_browser_command = ''
|
||||
endif
|
||||
endif
|
||||
return go_play_browser_command
|
||||
endfunction
|
||||
|
||||
function! go#tool#OpenBrowser(url) abort
|
||||
let cmd = s:get_browser_command()
|
||||
if len(cmd) == 0
|
||||
redraw
|
||||
echohl WarningMsg
|
||||
echo "It seems that you don't have general web browser. Open URL below."
|
||||
echohl None
|
||||
echo a:url
|
||||
return
|
||||
endif
|
||||
if cmd =~ '^!'
|
||||
let cmd = substitute(cmd, '%URL%', '\=escape(shellescape(a:url),"#")', 'g')
|
||||
silent! exec cmd
|
||||
elseif cmd =~ '^:[A-Z]'
|
||||
let cmd = substitute(cmd, '%URL%', '\=escape(a:url,"#")', 'g')
|
||||
exec cmd
|
||||
else
|
||||
let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g')
|
||||
call go#util#System(cmd)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
23
pack/acp/start/vim-go/autoload/go/tool_test.vim
Normal file
23
pack/acp/start/vim-go/autoload/go/tool_test.vim
Normal file
|
@ -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
|
114
pack/acp/start/vim-go/autoload/go/ui.vim
Normal file
114
pack/acp/start/vim-go/autoload/go/ui.vim
Normal file
|
@ -0,0 +1,114 @@
|
|||
let s:buf_nr = -1
|
||||
|
||||
"OpenWindow opens a new scratch window and put's the content into the window
|
||||
function! go#ui#OpenWindow(title, content, filetype) abort
|
||||
" Ensure there's only one return window in this session/tabpage
|
||||
call go#util#Windo("unlet! w:vim_go_return_window")
|
||||
" Mark the window we're leaving as such
|
||||
let w:vim_go_return_window = 1
|
||||
|
||||
" reuse existing buffer window if it exists otherwise create a new one
|
||||
if !bufexists(s:buf_nr)
|
||||
execute 'botright new'
|
||||
file `="[" . a:title . "]"`
|
||||
let s:buf_nr = bufnr('%')
|
||||
elseif bufwinnr(s:buf_nr) == -1
|
||||
execute 'botright new'
|
||||
execute s:buf_nr . 'buffer'
|
||||
elseif bufwinnr(s:buf_nr) != bufwinnr('%')
|
||||
execute bufwinnr(s:buf_nr) . 'wincmd w'
|
||||
endif
|
||||
|
||||
" Resize window to content length
|
||||
exe 'resize' . len(a:content)
|
||||
|
||||
execute "setlocal filetype=".a:filetype
|
||||
|
||||
" some sane default values for a readonly buffer
|
||||
setlocal bufhidden=delete
|
||||
setlocal buftype=nofile
|
||||
setlocal noswapfile
|
||||
setlocal nobuflisted
|
||||
setlocal winfixheight
|
||||
setlocal cursorline " make it easy to distinguish
|
||||
setlocal nonumber
|
||||
setlocal norelativenumber
|
||||
setlocal showbreak=""
|
||||
|
||||
" we need this to purge the buffer content
|
||||
setlocal modifiable
|
||||
|
||||
"delete everything first from the buffer
|
||||
%delete _
|
||||
|
||||
" add the content
|
||||
call append(0, a:content)
|
||||
|
||||
" delete last line that comes from the append call
|
||||
$delete _
|
||||
|
||||
" set it back to non modifiable
|
||||
setlocal nomodifiable
|
||||
|
||||
" Remove the '... [New File]' message line from the command line
|
||||
echon
|
||||
endfunction
|
||||
|
||||
function! go#ui#GetReturnWindow() abort
|
||||
for l:wn in range(1, winnr("$"))
|
||||
if !empty(getwinvar(l:wn, "vim_go_return_window"))
|
||||
return l:wn
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" CloseWindow closes the current window
|
||||
function! go#ui#CloseWindow() abort
|
||||
" Close any window associated with the ui buffer, if it's there
|
||||
if bufexists(s:buf_nr)
|
||||
let ui_window_number = bufwinnr(s:buf_nr)
|
||||
if ui_window_number != -1
|
||||
execute ui_window_number . 'close'
|
||||
endif
|
||||
endif
|
||||
|
||||
"return to original window, if it's there
|
||||
let l:rw = go#ui#GetReturnWindow()
|
||||
if !empty(l:rw)
|
||||
execute l:rw . 'wincmd w'
|
||||
unlet! w:vim_go_return_window
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" OpenDefinition parses the current line and jumps to it by openening a new
|
||||
" tab
|
||||
function! go#ui#OpenDefinition(filter) abort
|
||||
let curline = getline('.')
|
||||
|
||||
" don't touch our first line or any blank line
|
||||
if curline =~ a:filter || curline =~ "^$"
|
||||
" suppress information about calling this function
|
||||
echo ""
|
||||
return
|
||||
endif
|
||||
|
||||
" format: 'interface file:lnum:coln'
|
||||
let mx = '^\(^\S*\)\s*\(.\{-}\):\(\d\+\):\(\d\+\)'
|
||||
|
||||
" parse it now into the list
|
||||
let tokens = matchlist(curline, mx)
|
||||
|
||||
" convert to: 'file:lnum:coln'
|
||||
let expr = tokens[2] . ":" . tokens[3] . ":" . tokens[4]
|
||||
|
||||
" jump to it in a new tab, we use explicit lgetexpr so we can later change
|
||||
" the behaviour via settings (like opening in vsplit instead of tab)
|
||||
lgetexpr expr
|
||||
tab split
|
||||
ll 1
|
||||
|
||||
" center the word
|
||||
norm! zz
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
403
pack/acp/start/vim-go/autoload/go/util.vim
Normal file
403
pack/acp/start/vim-go/autoload/go/util.vim
Normal file
|
@ -0,0 +1,403 @@
|
|||
" PathSep returns the appropriate OS specific path separator.
|
||||
function! go#util#PathSep() abort
|
||||
if go#util#IsWin()
|
||||
return '\'
|
||||
endif
|
||||
return '/'
|
||||
endfunction
|
||||
|
||||
" PathListSep returns the appropriate OS specific path list separator.
|
||||
function! go#util#PathListSep() abort
|
||||
if go#util#IsWin()
|
||||
return ";"
|
||||
endif
|
||||
return ":"
|
||||
endfunction
|
||||
|
||||
" LineEnding returns the correct line ending, based on the current fileformat
|
||||
function! go#util#LineEnding() abort
|
||||
if &fileformat == 'dos'
|
||||
return "\r\n"
|
||||
elseif &fileformat == 'mac'
|
||||
return "\r"
|
||||
endif
|
||||
|
||||
return "\n"
|
||||
endfunction
|
||||
|
||||
" Join joins any number of path elements into a single path, adding a
|
||||
" Separator if necessary and returns the result
|
||||
function! go#util#Join(...) abort
|
||||
return join(a:000, go#util#PathSep())
|
||||
endfunction
|
||||
|
||||
" IsWin returns 1 if current OS is Windows or 0 otherwise
|
||||
function! go#util#IsWin() abort
|
||||
let win = ['win16', 'win32', 'win64', 'win95']
|
||||
for w in win
|
||||
if (has(w))
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" 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.
|
||||
" example: '/foo/bar/' -> '/foo/bar'
|
||||
function! go#util#StripPathSep(path) abort
|
||||
let last_char = strlen(a:path) - 1
|
||||
if a:path[last_char] == go#util#PathSep()
|
||||
return strpart(a:path, 0, last_char)
|
||||
endif
|
||||
|
||||
return a:path
|
||||
endfunction
|
||||
|
||||
" StripTrailingSlash strips the trailing slash from the given path list.
|
||||
" example: ['/foo/bar/'] -> ['/foo/bar']
|
||||
function! go#util#StripTrailingSlash(paths) abort
|
||||
return map(copy(a:paths), 'go#util#StripPathSep(v:val)')
|
||||
endfunction
|
||||
|
||||
" Shelljoin returns a shell-safe string representation of arglist. The
|
||||
" {special} argument of shellescape() may optionally be passed.
|
||||
function! go#util#Shelljoin(arglist, ...) abort
|
||||
try
|
||||
let ssl_save = &shellslash
|
||||
set noshellslash
|
||||
if a:0
|
||||
return join(map(copy(a:arglist), 'shellescape(v:val, ' . a:1 . ')'), ' ')
|
||||
endif
|
||||
|
||||
return join(map(copy(a:arglist), 'shellescape(v:val)'), ' ')
|
||||
finally
|
||||
let &shellslash = ssl_save
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
fu! go#util#Shellescape(arg)
|
||||
try
|
||||
let ssl_save = &shellslash
|
||||
set noshellslash
|
||||
return shellescape(a:arg)
|
||||
finally
|
||||
let &shellslash = ssl_save
|
||||
endtry
|
||||
endf
|
||||
|
||||
" Shelllist returns a shell-safe representation of the items in the given
|
||||
" arglist. The {special} argument of shellescape() may optionally be passed.
|
||||
function! go#util#Shelllist(arglist, ...) abort
|
||||
try
|
||||
let ssl_save = &shellslash
|
||||
set noshellslash
|
||||
if a:0
|
||||
return map(copy(a:arglist), 'shellescape(v:val, ' . a:1 . ')')
|
||||
endif
|
||||
return map(copy(a:arglist), 'shellescape(v:val)')
|
||||
finally
|
||||
let &shellslash = ssl_save
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Returns the byte offset for line and column
|
||||
function! go#util#Offset(line, col) abort
|
||||
if &encoding != 'utf-8'
|
||||
let sep = go#util#LineEnding()
|
||||
let buf = a:line == 1 ? '' : (join(getline(1, a:line-1), sep) . sep)
|
||||
let buf .= a:col == 1 ? '' : getline('.')[:a:col-2]
|
||||
return len(iconv(buf, &encoding, 'utf-8'))
|
||||
endif
|
||||
return line2byte(a:line) + (a:col-2)
|
||||
endfunction
|
||||
"
|
||||
" Returns the byte offset for the cursor
|
||||
function! go#util#OffsetCursor() abort
|
||||
return go#util#Offset(line('.'), col('.'))
|
||||
endfunction
|
||||
|
||||
" Windo is like the built-in :windo, only it returns to the window the command
|
||||
" was issued from
|
||||
function! go#util#Windo(command) abort
|
||||
let s:currentWindow = winnr()
|
||||
try
|
||||
execute "windo " . a:command
|
||||
finally
|
||||
execute s:currentWindow. "wincmd w"
|
||||
unlet s:currentWindow
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" snippetcase converts the given word to given preferred snippet setting type
|
||||
" case.
|
||||
function! go#util#snippetcase(word) abort
|
||||
let l:snippet_case = get(g:, 'go_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
|
||||
|
||||
" snakecase converts a string to snake case. i.e: FooBar -> foo_bar
|
||||
" Copied from tpope/vim-abolish
|
||||
function! go#util#snakecase(word) abort
|
||||
let word = substitute(a:word, '::', '/', 'g')
|
||||
let word = substitute(word, '\(\u\+\)\(\u\l\)', '\1_\2', 'g')
|
||||
let word = substitute(word, '\(\l\|\d\)\(\u\)', '\1_\2', 'g')
|
||||
let word = substitute(word, '[.-]', '_', 'g')
|
||||
let word = tolower(word)
|
||||
return word
|
||||
endfunction
|
||||
|
||||
" camelcase converts a string to camel case. e.g. FooBar or foo_bar will become
|
||||
" 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
|
||||
|
||||
" 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)
|
||||
redraw
|
||||
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 == ''
|
||||
call go#util#EchoError('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
|
||||
|
||||
" Report if the user enabled a debug flag in g:go_debug.
|
||||
function! go#util#HasDebug(flag)
|
||||
return index(get(g:, 'go_debug', []), a:flag) >= 0
|
||||
endfunction
|
||||
|
||||
" vim: sw=2 ts=2 et
|
130
pack/acp/start/vim-go/autoload/gotest.vim
Normal file
130
pack/acp/start/vim-go/autoload/gotest.vim
Normal file
|
@ -0,0 +1,130 @@
|
|||
" 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
|
||||
|
||||
func! gotest#assert_quickfix(got, want) abort
|
||||
call assert_equal(len(a:want), len(a:got), "number of errors")
|
||||
if len(a:want) != len(a:got)
|
||||
call assert_equal(a:want, a:got)
|
||||
return
|
||||
endif
|
||||
|
||||
let i = 0
|
||||
while i < len(a:want)
|
||||
let want_item = a:want[i]
|
||||
let got_item = a:got[i]
|
||||
let i += 1
|
||||
|
||||
call assert_equal(want_item.bufnr, got_item.bufnr, "bufnr")
|
||||
call assert_equal(want_item.lnum, got_item.lnum, "lnum")
|
||||
call assert_equal(want_item.col, got_item.col, "col")
|
||||
call assert_equal(want_item.vcol, got_item.vcol, "vcol")
|
||||
call assert_equal(want_item.nr, got_item.nr, "nr")
|
||||
call assert_equal(want_item.pattern, got_item.pattern, "pattern")
|
||||
call assert_equal(want_item.text, got_item.text, "text")
|
||||
call assert_equal(want_item.type, got_item.type, "type")
|
||||
call assert_equal(want_item.valid, got_item.valid, "valid")
|
||||
endwhile
|
||||
endfunc
|
||||
|
||||
" vim: sw=2 ts=2 et
|
70
pack/acp/start/vim-go/autoload/unite/sources/decls.vim
Normal file
70
pack/acp/start/vim-go/autoload/unite/sources/decls.vim
Normal file
|
@ -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
|
41
pack/acp/start/vim-go/compiler/go.vim
Normal file
41
pack/acp/start/vim-go/compiler/go.vim
Normal file
|
@ -0,0 +1,41 @@
|
|||
" Copyright 2013 The Go Authors. All rights reserved.
|
||||
" Use of this source code is governed by a BSD-style
|
||||
" license that can be found in the LICENSE file.
|
||||
"
|
||||
" compiler/go.vim: Vim compiler file for Go.
|
||||
|
||||
if exists("g:current_compiler")
|
||||
finish
|
||||
endif
|
||||
let g:current_compiler = "go"
|
||||
|
||||
if exists(":CompilerSet") != 2
|
||||
command -nargs=* CompilerSet setlocal <args>
|
||||
endif
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo-=C
|
||||
if filereadable("makefile") || filereadable("Makefile")
|
||||
CompilerSet makeprg=make
|
||||
else
|
||||
CompilerSet makeprg=go\ build
|
||||
endif
|
||||
|
||||
" Define the patterns that will be recognized by QuickFix when parsing the
|
||||
" output of Go command that use this errorforamt (when called make, cexpr or
|
||||
" lmake, lexpr). This is the global errorformat, however some command might
|
||||
" use a different output, for those we define them directly and modify the
|
||||
" errorformat ourselves. More information at:
|
||||
" http://vimdoc.sourceforge.net/htmldoc/quickfix.html#errorformat
|
||||
CompilerSet errorformat =%-G#\ %.%# " Ignore lines beginning with '#' ('# command-line-arguments' line sometimes appears?)
|
||||
CompilerSet errorformat+=%-G%.%#panic:\ %m " Ignore lines containing 'panic: message'
|
||||
CompilerSet errorformat+=%Ecan\'t\ load\ package:\ %m " Start of multiline error string is 'can\'t load package'
|
||||
CompilerSet errorformat+=%A%f:%l:%c:\ %m " Start of multiline unspecified string is 'filename:linenumber:columnnumber:'
|
||||
CompilerSet errorformat+=%A%f:%l:\ %m " Start of multiline unspecified string is 'filename:linenumber:'
|
||||
CompilerSet errorformat+=%C%*\\s%m " Continuation of multiline error message is indented
|
||||
CompilerSet errorformat+=%-G%.%# " All lines not matching any of the above patterns are ignored
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim: sw=2 ts=2 et
|
2239
pack/acp/start/vim-go/doc/vim-go.txt
Normal file
2239
pack/acp/start/vim-go/doc/vim-go.txt
Normal file
File diff suppressed because it is too large
Load diff
34
pack/acp/start/vim-go/ftdetect/gofiletype.vim
Normal file
34
pack/acp/start/vim-go/ftdetect/gofiletype.vim
Normal file
|
@ -0,0 +1,34 @@
|
|||
" vint: -ProhibitAutocmdWithNoGroup
|
||||
|
||||
" We take care to preserve the user's fileencodings and fileformats,
|
||||
" because those settings are global (not buffer local), yet we want
|
||||
" to override them for loading Go files, which are defined to be UTF-8.
|
||||
let s:current_fileformats = ''
|
||||
let s:current_fileencodings = ''
|
||||
|
||||
" define fileencodings to open as utf-8 encoding even if it's ascii.
|
||||
function! s:gofiletype_pre(type)
|
||||
let s:current_fileformats = &g:fileformats
|
||||
let s:current_fileencodings = &g:fileencodings
|
||||
set fileencodings=utf-8 fileformats=unix
|
||||
let &l:filetype = a:type
|
||||
endfunction
|
||||
|
||||
" restore fileencodings as others
|
||||
function! s:gofiletype_post()
|
||||
let &g:fileformats = s:current_fileformats
|
||||
let &g:fileencodings = s:current_fileencodings
|
||||
endfunction
|
||||
|
||||
" Note: should not use augroup in ftdetect (see :help ftdetect)
|
||||
au BufNewFile *.go setfiletype go | setlocal fileencoding=utf-8 fileformat=unix
|
||||
au BufRead *.go call s:gofiletype_pre("go")
|
||||
au BufReadPost *.go call s:gofiletype_post()
|
||||
|
||||
au BufNewFile *.s setfiletype asm | setlocal fileencoding=utf-8 fileformat=unix
|
||||
au BufRead *.s call s:gofiletype_pre("asm")
|
||||
au BufReadPost *.s call s:gofiletype_post()
|
||||
|
||||
au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl
|
||||
|
||||
" vim: sw=2 ts=2 et
|
19
pack/acp/start/vim-go/ftplugin/asm.vim
Normal file
19
pack/acp/start/vim-go/ftplugin/asm.vim
Normal file
|
@ -0,0 +1,19 @@
|
|||
" asm.vim: Vim filetype plugin for Go assembler.
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
endif
|
||||
let b:did_ftplugin = 1
|
||||
|
||||
let b:undo_ftplugin = "setl fo< com< cms<"
|
||||
|
||||
setlocal formatoptions-=t
|
||||
|
||||
setlocal comments=s1:/*,mb:*,ex:*/,://
|
||||
setlocal commentstring=//\ %s
|
||||
|
||||
setlocal noexpandtab
|
||||
|
||||
command! -nargs=0 AsmFmt call go#asmfmt#Format()
|
||||
|
||||
" vim: sw=2 ts=2 et
|
133
pack/acp/start/vim-go/ftplugin/go.vim
Normal file
133
pack/acp/start/vim-go/ftplugin/go.vim
Normal file
|
@ -0,0 +1,133 @@
|
|||
" Copyright 2013 The Go Authors. All rights reserved.
|
||||
" Use of this source code is governed by a BSD-style
|
||||
" license that can be found in the LICENSE file.
|
||||
"
|
||||
" go.vim: Vim filetype plugin for Go.
|
||||
|
||||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
endif
|
||||
let b:did_ftplugin = 1
|
||||
|
||||
let b:undo_ftplugin = "setl fo< com< cms<"
|
||||
|
||||
setlocal formatoptions-=t
|
||||
|
||||
setlocal comments=s1:/*,mb:*,ex:*/,://
|
||||
setlocal commentstring=//\ %s
|
||||
|
||||
setlocal noexpandtab
|
||||
|
||||
compiler go
|
||||
|
||||
" Set gocode completion
|
||||
setlocal omnifunc=go#complete#Complete
|
||||
|
||||
if get(g:, "go_doc_keywordprg_enabled", 1)
|
||||
" keywordprg doesn't allow to use vim commands, override it
|
||||
nnoremap <buffer> <silent> K :GoDoc<cr>
|
||||
endif
|
||||
|
||||
if get(g:, "go_def_mapping_enabled", 1)
|
||||
" these are default Vim mappings, we're overriding them to make them
|
||||
" useful again for Go source code
|
||||
nnoremap <buffer> <silent> gd :GoDef<cr>
|
||||
nnoremap <buffer> <silent> <C-]> :GoDef<cr>
|
||||
nnoremap <buffer> <silent> <C-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
|
||||
|
||||
if get(g:, "go_textobj_enabled", 1)
|
||||
onoremap <buffer> <silent> af :<c-u>call go#textobj#Function('a')<cr>
|
||||
onoremap <buffer> <silent> if :<c-u>call go#textobj#Function('i')<cr>
|
||||
|
||||
xnoremap <buffer> <silent> af :<c-u>call go#textobj#Function('a')<cr>
|
||||
xnoremap <buffer> <silent> if :<c-u>call go#textobj#Function('i')<cr>
|
||||
|
||||
" Remap ]] and [[ to jump betweeen functions as they are useless in Go
|
||||
nnoremap <buffer> <silent> ]] :<c-u>call go#textobj#FunctionJump('n', 'next')<cr>
|
||||
nnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('n', 'prev')<cr>
|
||||
|
||||
onoremap <buffer> <silent> ]] :<c-u>call go#textobj#FunctionJump('o', 'next')<cr>
|
||||
onoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('o', 'prev')<cr>
|
||||
|
||||
xnoremap <buffer> <silent> ]] :<c-u>call go#textobj#FunctionJump('v', 'next')<cr>
|
||||
xnoremap <buffer> <silent> [[ :<c-u>call go#textobj#FunctionJump('v', 'prev')<cr>
|
||||
endif
|
||||
|
||||
if get(g:, "go_auto_type_info", 0) || get(g:, "go_auto_sameids", 0)
|
||||
let &l:updatetime= get(g:, "go_updatetime", 800)
|
||||
endif
|
||||
|
||||
" NOTE(arslan): experimental, disabled by default, doesn't work well. No
|
||||
" documentation as well. If anyone feels 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
|
108
pack/acp/start/vim-go/ftplugin/go/commands.vim
Normal file
108
pack/acp/start/vim-go/ftplugin/go/commands.vim
Normal file
|
@ -0,0 +1,108 @@
|
|||
" -- gorename
|
||||
command! -nargs=? -complete=customlist,go#rename#Complete GoRename call go#rename#Rename(<bang>0, <f-args>)
|
||||
|
||||
" -- guru
|
||||
command! -nargs=* -complete=customlist,go#package#Complete GoGuruScope call go#guru#Scope(<f-args>)
|
||||
command! -range=% GoImplements call go#guru#Implements(<count>)
|
||||
command! -range=% GoWhicherrs call go#guru#Whicherrs(<count>)
|
||||
command! -range=% GoCallees call go#guru#Callees(<count>)
|
||||
command! -range=% GoDescribe call go#guru#Describe(<count>)
|
||||
command! -range=% GoCallers call go#guru#Callers(<count>)
|
||||
command! -range=% GoCallstack call go#guru#Callstack(<count>)
|
||||
command! -range=% GoFreevars call go#guru#Freevars(<count>)
|
||||
command! -range=% GoChannelPeers call go#guru#ChannelPeers(<count>)
|
||||
command! -range=% GoReferrers call go#guru#Referrers(<count>)
|
||||
|
||||
command! -range=0 GoSameIds call go#guru#SameIds()
|
||||
command! -range=0 GoSameIdsClear call go#guru#ClearSameIds()
|
||||
command! -range=0 GoSameIdsToggle call go#guru#ToggleSameIds()
|
||||
command! -range=0 GoSameIdsAutoToggle call go#guru#AutoToogleSameIds()
|
||||
|
||||
" -- tags
|
||||
command! -nargs=* -range GoAddTags call go#tags#Add(<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=* GoInfo call go#tool#Info(0)
|
||||
command! -nargs=0 GoAutoTypeInfoToggle call go#complete#ToggleAutoTypeInfo()
|
||||
|
||||
" -- cmd
|
||||
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 -complete=file GoRun call go#cmd#Run(<bang>0,<f-args>)
|
||||
command! -nargs=* -bang GoInstall call go#cmd#Install(<bang>0, <f-args>)
|
||||
|
||||
" -- test
|
||||
command! -nargs=* -bang GoTest call go#test#Test(<bang>0, 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
|
||||
command! -nargs=0 -range=% GoPlay call go#play#Share(<count>, <line1>, <line2>)
|
||||
|
||||
" -- def
|
||||
command! -nargs=* -range GoDef :call go#def#Jump('')
|
||||
command! -nargs=? GoDefPop :call go#def#StackPop(<f-args>)
|
||||
command! -nargs=? GoDefStack :call go#def#Stack(<f-args>)
|
||||
command! -nargs=? GoDefStackClear :call go#def#StackClear(<f-args>)
|
||||
|
||||
" -- doc
|
||||
command! -nargs=* -range -complete=customlist,go#package#Complete GoDoc call go#doc#Open('new', 'split', <f-args>)
|
||||
command! -nargs=* -range -complete=customlist,go#package#Complete GoDocBrowser call go#doc#OpenBrowser(<f-args>)
|
||||
|
||||
" -- fmt
|
||||
command! -nargs=0 GoFmt call go#fmt#Format(-1)
|
||||
command! -nargs=0 GoFmtAutoSaveToggle call go#fmt#ToggleFmtAutoSave()
|
||||
command! -nargs=0 GoImports call go#fmt#Format(1)
|
||||
|
||||
" -- asmfmt
|
||||
command! -nargs=0 GoAsmFmtAutoSaveToggle call go#asmfmt#ToggleAsmFmtAutoSave()
|
||||
|
||||
" -- import
|
||||
command! -nargs=? -complete=customlist,go#package#Complete GoDrop call go#import#SwitchImport(0, '', <f-args>, '')
|
||||
command! -nargs=1 -bang -complete=customlist,go#package#Complete GoImport call go#import#SwitchImport(1, '', <f-args>, '<bang>')
|
||||
command! -nargs=* -bang -complete=customlist,go#package#Complete GoImportAs call go#import#SwitchImport(1, <f-args>, '<bang>')
|
||||
|
||||
" -- linters
|
||||
command! -nargs=* GoMetaLinter call go#lint#Gometa(0, <f-args>)
|
||||
command! -nargs=0 GoMetaLinterAutoSaveToggle call go#lint#ToggleMetaLinterAutoSave()
|
||||
command! -nargs=* GoLint call go#lint#Golint(<f-args>)
|
||||
command! -nargs=* -bang GoVet call go#lint#Vet(<bang>0, <f-args>)
|
||||
command! -nargs=* -complete=customlist,go#package#Complete GoErrCheck call go#lint#Errcheck(<f-args>)
|
||||
|
||||
" -- alternate
|
||||
command! -bang GoAlternate call go#alternate#Switch(<bang>0, '')
|
||||
|
||||
" -- decls
|
||||
command! -nargs=? -complete=file GoDecls call go#decls#Decls(0, <q-args>)
|
||||
command! -nargs=? -complete=dir GoDeclsDir call go#decls#Decls(1, <q-args>)
|
||||
|
||||
" -- 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()
|
||||
|
||||
" -- debug
|
||||
if !exists(':GoDebugStart')
|
||||
command! -nargs=* -complete=customlist,go#package#Complete GoDebugStart call go#debug#Start(0, <f-args>)
|
||||
command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start(1, <f-args>)
|
||||
command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint(<f-args>)
|
||||
endif
|
||||
|
||||
" vim: sw=2 ts=2 et
|
75
pack/acp/start/vim-go/ftplugin/go/mappings.vim
Normal file
75
pack/acp/start/vim-go/ftplugin/go/mappings.vim
Normal file
|
@ -0,0 +1,75 @@
|
|||
" go_jump_to_error defines whether we should pass the bang attribute to the
|
||||
" command or not. This is only used for mappings, because the user can't pass
|
||||
" the bang attribute to the plug mappings below. So instead of hardcoding it
|
||||
" as 0 (no '!' attribute) or 1 (with '!' attribute) we pass the user setting,
|
||||
" which by default is enabled. For commands the user has the ability to pass
|
||||
" the '!', such as :GoBuild or :GoBuild!
|
||||
if !exists("g:go_jump_to_error")
|
||||
let g:go_jump_to_error = 1
|
||||
endif
|
||||
|
||||
" Some handy plug mappings
|
||||
nnoremap <silent> <Plug>(go-run) :<C-u>call go#cmd#Run(!g:go_jump_to_error)<CR>
|
||||
|
||||
if has("nvim")
|
||||
nnoremap <silent> <Plug>(go-run-vertical) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'vsplit', [])<CR>
|
||||
nnoremap <silent> <Plug>(go-run-split) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'split', [])<CR>
|
||||
nnoremap <silent> <Plug>(go-run-tab) :<C-u>call go#cmd#RunTerm(!g:go_jump_to_error, 'tabe', [])<CR>
|
||||
endif
|
||||
|
||||
nnoremap <silent> <Plug>(go-build) :<C-u>call go#cmd#Build(!g:go_jump_to_error)<CR>
|
||||
nnoremap <silent> <Plug>(go-generate) :<C-u>call go#cmd#Generate(!g:go_jump_to_error)<CR>
|
||||
nnoremap <silent> <Plug>(go-install) :<C-u>call go#cmd#Install(!g:go_jump_to_error)<CR>
|
||||
nnoremap <silent> <Plug>(go-test) :<C-u>call go#test#Test(!g:go_jump_to_error, 0)<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#test#Test(!g:go_jump_to_error, 1)<CR>
|
||||
|
||||
nnoremap <silent> <Plug>(go-coverage) :<C-u>call go#coverage#Buffer(!g:go_jump_to_error)<CR>
|
||||
nnoremap <silent> <Plug>(go-coverage-clear) :<C-u>call go#coverage#Clear()<CR>
|
||||
nnoremap <silent> <Plug>(go-coverage-toggle) :<C-u>call go#coverage#BufferToggle(!g:go_jump_to_error)<CR>
|
||||
nnoremap <silent> <Plug>(go-coverage-browser) :<C-u>call go#coverage#Browser(!g:go_jump_to_error)<CR>
|
||||
|
||||
nnoremap <silent> <Plug>(go-files) :<C-u>call go#tool#Files()<CR>
|
||||
nnoremap <silent> <Plug>(go-deps) :<C-u>call go#tool#Deps()<CR>
|
||||
nnoremap <silent> <Plug>(go-info) :<C-u>call go#tool#Info(0)<CR>
|
||||
nnoremap <silent> <Plug>(go-import) :<C-u>call go#import#SwitchImport(1, '', expand('<cword>'), '')<CR>
|
||||
nnoremap <silent> <Plug>(go-imports) :<C-u>call go#fmt#Format(1)<CR>
|
||||
|
||||
nnoremap <silent> <Plug>(go-implements) :<C-u>call go#guru#Implements(-1)<CR>
|
||||
nnoremap <silent> <Plug>(go-callees) :<C-u>call go#guru#Callees(-1)<CR>
|
||||
nnoremap <silent> <Plug>(go-callers) :<C-u>call go#guru#Callers(-1)<CR>
|
||||
nnoremap <silent> <Plug>(go-describe) :<C-u>call go#guru#Describe(-1)<CR>
|
||||
nnoremap <silent> <Plug>(go-callstack) :<C-u>call go#guru#Callstack(-1)<CR>
|
||||
xnoremap <silent> <Plug>(go-freevars) :<C-u>call go#guru#Freevars(0)<CR>
|
||||
nnoremap <silent> <Plug>(go-channelpeers) :<C-u>call go#guru#ChannelPeers(-1)<CR>
|
||||
nnoremap <silent> <Plug>(go-referrers) :<C-u>call go#guru#Referrers(-1)<CR>
|
||||
nnoremap <silent> <Plug>(go-sameids) :<C-u>call go#guru#SameIds()<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-def) :<C-u>call go#def#Jump('')<CR>
|
||||
nnoremap <silent> <Plug>(go-def-vertical) :<C-u>call go#def#Jump("vsplit")<CR>
|
||||
nnoremap <silent> <Plug>(go-def-split) :<C-u>call go#def#Jump("split")<CR>
|
||||
nnoremap <silent> <Plug>(go-def-tab) :<C-u>call go#def#Jump("tab")<CR>
|
||||
|
||||
nnoremap <silent> <Plug>(go-def-pop) :<C-u>call go#def#StackPop()<CR>
|
||||
nnoremap <silent> <Plug>(go-def-stack) :<C-u>call go#def#Stack()<CR>
|
||||
nnoremap <silent> <Plug>(go-def-stack-clear) :<C-u>call go#def#StackClear()<CR>
|
||||
|
||||
nnoremap <silent> <Plug>(go-doc) :<C-u>call go#doc#Open("new", "split")<CR>
|
||||
nnoremap <silent> <Plug>(go-doc-tab) :<C-u>call go#doc#Open("tabnew", "tabe")<CR>
|
||||
nnoremap <silent> <Plug>(go-doc-vertical) :<C-u>call go#doc#Open("vnew", "vsplit")<CR>
|
||||
nnoremap <silent> <Plug>(go-doc-split) :<C-u>call go#doc#Open("new", "split")<CR>
|
||||
nnoremap <silent> <Plug>(go-doc-browser) :<C-u>call go#doc#OpenBrowser()<CR>
|
||||
|
||||
nnoremap <silent> <Plug>(go-metalinter) :<C-u>call go#lint#Gometa(0)<CR>
|
||||
nnoremap <silent> <Plug>(go-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-alternate-edit) :<C-u>call go#alternate#Switch(0, "edit")<CR>
|
||||
nnoremap <silent> <Plug>(go-alternate-vertical) :<C-u>call go#alternate#Switch(0, "vsplit")<CR>
|
||||
nnoremap <silent> <Plug>(go-alternate-split) :<C-u>call go#alternate#Switch(0, "split")<CR>
|
||||
|
||||
" vim: sw=2 ts=2 et
|
67
pack/acp/start/vim-go/ftplugin/go/snippets.vim
Normal file
67
pack/acp/start/vim-go/ftplugin/go/snippets.vim
Normal file
|
@ -0,0 +1,67 @@
|
|||
if exists("g:go_loaded_gosnippets")
|
||||
finish
|
||||
endif
|
||||
let g:go_loaded_gosnippets = 1
|
||||
|
||||
function! s:GoUltiSnips() abort
|
||||
if get(g:, 'did_plugin_ultisnips') isnot 1
|
||||
return
|
||||
endif
|
||||
|
||||
if !exists("g:UltiSnipsSnippetDirectories")
|
||||
let g:UltiSnipsSnippetDirectories = ["gosnippets/UltiSnips"]
|
||||
else
|
||||
let g:UltiSnipsSnippetDirectories += ["gosnippets/UltiSnips"]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GoNeosnippet() abort
|
||||
if get(g:, 'loaded_neosnippet') isnot 1
|
||||
return
|
||||
endif
|
||||
|
||||
let g:neosnippet#enable_snipmate_compatibility = 1
|
||||
|
||||
let l:gosnippets_dir = globpath(&rtp, 'gosnippets/snippets')
|
||||
if type(g:neosnippet#snippets_directory) == type([])
|
||||
let g:neosnippet#snippets_directory += [l:gosnippets_dir]
|
||||
elseif type(g:neosnippet#snippets_directory) == type("")
|
||||
if strlen(g:neosnippet#snippets_directory) > 0
|
||||
let g:neosnippet#snippets_directory = g:neosnippet#snippets_directory . "," . l:gosnippets_dir
|
||||
else
|
||||
let g:neosnippet#snippets_directory = l:gosnippets_dir
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:GoMinisnip() abort
|
||||
if get(g:, 'loaded_minisnip') isnot 1
|
||||
return
|
||||
endif
|
||||
|
||||
if exists('g:minisnip_dir')
|
||||
let g:minisnip_dir .= go#util#PathListSep() . globpath(&rtp, 'gosnippets/minisnip')
|
||||
else
|
||||
let g:minisnip_dir = globpath(&rtp, 'gosnippets/minisnip')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
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()
|
||||
elseif get(g:, 'loaded_neosnippet') is 1
|
||||
call s:GoNeosnippet()
|
||||
elseif get(g:, 'loaded_minisnip') is 1
|
||||
call s:GoMinisnip()
|
||||
endif
|
||||
elseif s:engine is? "ultisnips"
|
||||
call s:GoUltiSnips()
|
||||
elseif s:engine is? "neosnippet"
|
||||
call s:GoNeosnippet()
|
||||
elseif s:engine is? "minisnip"
|
||||
call s:GoMinisnip()
|
||||
endif
|
||||
|
||||
" vim: sw=2 ts=2 et
|
57
pack/acp/start/vim-go/ftplugin/go/tagbar.vim
Normal file
57
pack/acp/start/vim-go/ftplugin/go/tagbar.vim
Normal file
|
@ -0,0 +1,57 @@
|
|||
" Check if tagbar is installed under plugins or is directly under rtp
|
||||
" this covers pathogen + Vundle/Bundle
|
||||
"
|
||||
" Also make sure the ctags command exists
|
||||
"
|
||||
if !executable('ctags')
|
||||
finish
|
||||
elseif globpath(&rtp, 'plugin/tagbar.vim') == ""
|
||||
finish
|
||||
endif
|
||||
|
||||
if !exists("g:go_gotags_bin")
|
||||
let g:go_gotags_bin = "gotags"
|
||||
endif
|
||||
|
||||
|
||||
function! s:SetTagbar()
|
||||
let bin_path = go#path#CheckBinPath(g:go_gotags_bin)
|
||||
if empty(bin_path)
|
||||
return
|
||||
endif
|
||||
|
||||
if !exists("g:tagbar_type_go")
|
||||
let g:tagbar_type_go = {
|
||||
\ 'ctagstype' : 'go',
|
||||
\ 'kinds' : [
|
||||
\ 'p:package',
|
||||
\ 'i:imports',
|
||||
\ 'c:constants',
|
||||
\ 'v:variables',
|
||||
\ 't:types',
|
||||
\ 'n:interfaces',
|
||||
\ 'w:fields',
|
||||
\ 'e:embedded',
|
||||
\ 'm:methods',
|
||||
\ 'r:constructor',
|
||||
\ 'f:functions'
|
||||
\ ],
|
||||
\ 'sro' : '.',
|
||||
\ 'kind2scope' : {
|
||||
\ 't' : 'ctype',
|
||||
\ 'n' : 'ntype'
|
||||
\ },
|
||||
\ 'scope2kind' : {
|
||||
\ 'ctype' : 't',
|
||||
\ 'ntype' : 'n'
|
||||
\ },
|
||||
\ 'ctagsbin' : bin_path,
|
||||
\ 'ctagsargs' : '-sort -silent'
|
||||
\ }
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
call s:SetTagbar()
|
||||
|
||||
" vim: sw=2 ts=2 et
|
7
pack/acp/start/vim-go/ftplugin/gohtmltmpl.vim
Normal file
7
pack/acp/start/vim-go/ftplugin/gohtmltmpl.vim
Normal file
|
@ -0,0 +1,7 @@
|
|||
if exists("b:did_ftplugin")
|
||||
finish
|
||||
endif
|
||||
|
||||
runtime! ftplugin/html.vim
|
||||
|
||||
" vim: sw=2 ts=2 et
|
463
pack/acp/start/vim-go/gosnippets/UltiSnips/go.snippets
Normal file
463
pack/acp/start/vim-go/gosnippets/UltiSnips/go.snippets
Normal file
|
@ -0,0 +1,463 @@
|
|||
# Snippets for Go
|
||||
|
||||
priority -10
|
||||
|
||||
# shorthand variable declaration
|
||||
snippet : "v := value"
|
||||
${1} := ${0}
|
||||
endsnippet
|
||||
|
||||
# anonymous function
|
||||
snippet anon "fn := func() { ... }"
|
||||
${1:fn} := func() {
|
||||
${2:${VISUAL}}
|
||||
}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# append
|
||||
snippet ap "append(slice, value)"
|
||||
append(${1:slice}, ${0:value})
|
||||
endsnippet
|
||||
|
||||
# append assignment
|
||||
snippet ap= "a = append(a, value)"
|
||||
${1:slice} = append($1, ${0:value})
|
||||
endsnippet
|
||||
|
||||
# break
|
||||
snippet br "break"
|
||||
break
|
||||
endsnippet
|
||||
|
||||
# channel
|
||||
snippet ch "chan Type"
|
||||
chan ${0:int}
|
||||
endsnippet
|
||||
|
||||
# case
|
||||
snippet case "case ...:"
|
||||
case ${1:value}:
|
||||
${0:${VISUAL}}
|
||||
endsnippet
|
||||
|
||||
# constant
|
||||
snippet con "const XXX Type = ..."
|
||||
const ${1:NAME} ${2:Type} = ${0:0}
|
||||
endsnippet
|
||||
|
||||
# constants
|
||||
snippet cons "const ( ... )"
|
||||
const (
|
||||
${1:NAME} ${2:Type} = ${3:value}
|
||||
${0}
|
||||
)
|
||||
endsnippet
|
||||
|
||||
# constants with iota
|
||||
snippet iota "const ( ... = iota )"
|
||||
const (
|
||||
${1:NAME} ${2:Type} = iota
|
||||
${0}
|
||||
)
|
||||
endsnippet
|
||||
|
||||
# continue
|
||||
snippet cn "continue"
|
||||
continue
|
||||
endsnippet
|
||||
|
||||
# default case
|
||||
snippet default "default: ..."
|
||||
default:
|
||||
${0:${VISUAL}}
|
||||
endsnippet
|
||||
|
||||
# defer
|
||||
snippet df "defer someFunction()"
|
||||
defer ${1:func}(${2})
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
snippet def "defer func() { ... }"
|
||||
defer func() {
|
||||
${0:${VISUAL}}
|
||||
}()
|
||||
endsnippet
|
||||
|
||||
# defer recover
|
||||
snippet defr
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
}()
|
||||
endsnippet
|
||||
|
||||
# gpl
|
||||
snippet gpl
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright (C) ${1:Author}, `!v strftime("%Y")`
|
||||
*/
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# import
|
||||
snippet import "import ( ... )"
|
||||
import (
|
||||
"${1:package}"
|
||||
)
|
||||
endsnippet
|
||||
|
||||
# full interface snippet
|
||||
snippet interface "interface I { ... }"
|
||||
type ${1:Interface} interface {
|
||||
${2:/* TODO: add methods */}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# if condition
|
||||
snippet if "if ... { ... }"
|
||||
if ${1:condition} {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# else snippet
|
||||
snippet else
|
||||
else {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# if inline error
|
||||
snippet ife "If with inline erro"
|
||||
if err := ${1:condition}; err != nil {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# error snippet
|
||||
snippet errn "Error return " !b
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# error log snippet
|
||||
snippet errl "Error with log.Fatal(err)" !b
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# error multiple return
|
||||
snippet errn, "Error return with two return values" !b
|
||||
if err != nil {
|
||||
return ${1:nil}, err
|
||||
}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# error panic
|
||||
snippet errp "Error panic" !b
|
||||
if err != nil {
|
||||
panic(${1})
|
||||
}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# error test
|
||||
snippet errt "Error test fatal " !b
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# error handle
|
||||
snippet errh "Error handle and return" !b
|
||||
if err != nil {
|
||||
${1}
|
||||
return
|
||||
}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# json field tag
|
||||
snippet json "\`json:key\`"
|
||||
\`json:"${1:`!v go#util#snippetcase(matchstr(getline("."), '\w\+'))`}"\`
|
||||
endsnippet
|
||||
|
||||
# yaml field tag
|
||||
snippet yaml "\`yaml:key\`"
|
||||
\`yaml:"${1:`!v go#util#snippetcase(matchstr(getline("."), '\w\+'))`}"\`
|
||||
endsnippet
|
||||
|
||||
# fallthrough
|
||||
snippet ft "fallthrough"
|
||||
fallthrough
|
||||
endsnippet
|
||||
|
||||
# for loop
|
||||
snippet for "for ... { ... }"
|
||||
for ${1} {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# for integer loop
|
||||
snippet fori "for 0..N-1 { ... }"
|
||||
for ${1:i} := 0; $1 < ${2:N}; $1++ {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# for range loop
|
||||
snippet forr "for k, v := range items { ... }"
|
||||
for ${2:k}, ${3:v} := range ${1} {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# function
|
||||
snippet func "func Function(...) [error] { ... }"
|
||||
func ${1:name}(${2:params})${3/(.+)/ /}`!p opening_par(snip, 3)`$3`!p closing_par(snip, 3)` {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# Fmt Printf debug
|
||||
snippet ff "fmt.Printf(...)"
|
||||
fmt.Printf("${1:${VISUAL}} = %+v\n", $1)
|
||||
endsnippet
|
||||
|
||||
# Fmt Println debug
|
||||
snippet fn "fmt.Println(...)"
|
||||
fmt.Println("${1:${VISUAL}}")
|
||||
endsnippet
|
||||
|
||||
# Fmt Errorf debug
|
||||
snippet fe "fmt.Errorf(...)"
|
||||
fmt.Errorf("${1:${VISUAL}}")
|
||||
endsnippet
|
||||
|
||||
# log printf
|
||||
snippet lf "log.Printf(...)"
|
||||
log.Printf("${1:${VISUAL}} = %+v\n", $1)
|
||||
endsnippet
|
||||
|
||||
# log println
|
||||
snippet ln "log.Println(...)"
|
||||
log.Println("${1:${VISUAL}}")
|
||||
endsnippet
|
||||
|
||||
# make
|
||||
snippet make "make(Type, size)"
|
||||
make(${1:[]string}, ${2:0})${0}
|
||||
endsnippet
|
||||
|
||||
# map
|
||||
snippet map "map[Type]Type"
|
||||
map[${1:string}]${0:int}
|
||||
endsnippet
|
||||
|
||||
# main()
|
||||
snippet main "func main() { ... }"
|
||||
func main() {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# method
|
||||
snippet meth "func (self Type) Method(...) [error] { ... }"
|
||||
func (${1:receiver} ${2:type}) ${3:name}(${4:params})${5/(.+)/ /}`!p opening_par(snip, 5)`$5`!p closing_par(snip, 5)` {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# ok
|
||||
snippet ok "if !ok { ... }"
|
||||
if !ok {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# package
|
||||
snippet package "package ..."
|
||||
// Package $1 provides ${2:...}
|
||||
package ${1:main}
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# panic
|
||||
snippet pn "panic()"
|
||||
panic("${0:msg}")
|
||||
endsnippet
|
||||
|
||||
# return
|
||||
snippet rt "return"
|
||||
return ${0:${VISUAL}}
|
||||
endsnippet
|
||||
|
||||
# select
|
||||
snippet select "select { case a := <-chan: ... }"
|
||||
select {
|
||||
case ${1:v1} := <-${2:chan1}
|
||||
${0}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# struct
|
||||
snippet st "type T struct { ... }"
|
||||
type ${1:Type} struct {
|
||||
${0}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# switch
|
||||
snippet switch "switch x { ... }"
|
||||
switch ${1:var} {
|
||||
case ${2:value1}:
|
||||
${0}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# sprintf
|
||||
snippet sp "fmt.Sprintf(...)"
|
||||
fmt.Sprintf("%${1:s}", ${2:var})
|
||||
endsnippet
|
||||
|
||||
# goroutine named function
|
||||
snippet go "go someFunc(...)"
|
||||
go ${1:funcName}(${0})
|
||||
endsnippet
|
||||
|
||||
# goroutine anonymous function
|
||||
snippet gof "go func() { ... }()"
|
||||
go func() {
|
||||
${1:${VISUAL}}
|
||||
}()
|
||||
${0}
|
||||
endsnippet
|
||||
|
||||
# test function
|
||||
snippet test "func TestXYZ(t *testing.T) { ... }"
|
||||
func Test${1:Function}(t *testing.T) {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
snippet hf "http.HandlerFunc" !b
|
||||
func ${1:handler}(w http.ResponseWriter, r *http.Request) {
|
||||
${0:fmt.Fprintf(w, "hello world")}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
snippet hhf "mux.HandleFunc" !b
|
||||
${1:http}.HandleFunc("${2:/}", func(w http.ResponseWriter, r *http.Request) {
|
||||
${0:fmt.Fprintf(w, "hello world")}
|
||||
})
|
||||
endsnippet
|
||||
|
||||
# quick test server
|
||||
snippet tsrv "httptest.NewServer"
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, ${1:`response`})
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
${0:someUrl} = ts.URL
|
||||
endsnippet
|
||||
|
||||
# test error handling
|
||||
snippet ter "if err != nil { t.Errorf(...) }"
|
||||
if err != nil {
|
||||
t.Errorf("${0:message}")
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# test fatal error
|
||||
snippet terf "if err != nil { t.Fatalf(...) }"
|
||||
if err != nil {
|
||||
t.Fatalf("${0:message}")
|
||||
}
|
||||
endsnippet
|
||||
|
||||
snippet example "func ExampleXYZ() { ... }"
|
||||
func Example${1:Method}() {
|
||||
${0:${VISUAL}}
|
||||
// Output:
|
||||
}
|
||||
endsnippet
|
||||
|
||||
snippet benchmark "func BenchmarkXYZ(b *testing.B) { ... }"
|
||||
func Benchmark${1:Method}(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
${0:${VISUAL}}
|
||||
}
|
||||
}
|
||||
endsnippet
|
||||
|
||||
# variable declaration
|
||||
snippet var "var x Type [= ...]"
|
||||
var ${1:x} ${2:Type}${3: = ${0:value}}
|
||||
endsnippet
|
||||
|
||||
# variables declaration
|
||||
snippet vars "var ( ... )"
|
||||
var (
|
||||
${1:x} ${2:Type}${3: = ${0:value}}
|
||||
)
|
||||
endsnippet
|
||||
|
||||
# equals fails the test if exp is not equal to act.
|
||||
snippet eq "equals: test two identifiers with DeepEqual"
|
||||
if !reflect.DeepEqual(${1:expected}, ${2:actual}) {
|
||||
_, file, line, _ := runtime.Caller(0)
|
||||
fmt.Printf("%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\n\n", filepath.Base(file), line, $1, $2)
|
||||
t.FailNow()
|
||||
}
|
||||
endsnippet
|
||||
|
||||
global !p
|
||||
|
||||
import re
|
||||
|
||||
# Automatically wrap return types with parentheses
|
||||
|
||||
def return_values(s):
|
||||
# remove everything wrapped in parentheses
|
||||
s = re.sub("\(.*?\)|\([^)]*$", "", s)
|
||||
return len(s.split(","))
|
||||
|
||||
def opening_par(snip, pos):
|
||||
if return_values(t[pos]) > 1 and not t[pos].startswith("("):
|
||||
snip.rv = "("
|
||||
else:
|
||||
snip.rv = ""
|
||||
|
||||
def closing_par(snip, pos):
|
||||
if return_values(t[pos]) > 1:
|
||||
snip.rv = ")"
|
||||
else:
|
||||
snip.rv = ""
|
||||
|
||||
endglobal
|
||||
|
||||
# vim:ft=snippets:
|
3
pack/acp/start/vim-go/gosnippets/minisnip/_go_eq
Normal file
3
pack/acp/start/vim-go/gosnippets/minisnip/_go_eq
Normal file
|
@ -0,0 +1,3 @@
|
|||
if !reflect.DeepEqual({{+got+}}, {{+want+}}) {
|
||||
t.Errorf("\ngot: %#v\nwant: %#v\n", {{+~\~2+}}, {{+~\~2+}})
|
||||
}
|
3
pack/acp/start/vim-go/gosnippets/minisnip/_go_err
Normal file
3
pack/acp/start/vim-go/gosnippets/minisnip/_go_err
Normal file
|
@ -0,0 +1,3 @@
|
|||
if err != nil {
|
||||
return {{+err+}}
|
||||
}
|
4
pack/acp/start/vim-go/gosnippets/minisnip/_go_errt
Normal file
4
pack/acp/start/vim-go/gosnippets/minisnip/_go_errt
Normal file
|
@ -0,0 +1,4 @@
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
{{++}}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue