Skip to content

Commit

Permalink
cmd/govim: initial quickfix window support (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
myitcv committed Apr 16, 2019
1 parent 0bf5360 commit 3ac877d
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 3 deletions.
70 changes: 70 additions & 0 deletions cmd/govim/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
Expand All @@ -14,6 +16,7 @@ import (
"github.com/myitcv/govim"
"github.com/myitcv/govim/cmd/govim/config"
"github.com/myitcv/govim/cmd/govim/internal/lsp/protocol"
"github.com/myitcv/govim/cmd/govim/internal/span"
"github.com/myitcv/govim/cmd/govim/types"
"github.com/myitcv/govim/internal/plugin"
"github.com/russross/blackfriday/v2"
Expand All @@ -28,6 +31,10 @@ type vimstate struct {
// or autocommand.
buffers map[int]*types.Buffer

// diagnostics gives us the current diagnostics by URI
diagnostics map[span.URI][]protocol.Diagnostic
diagnosticsChanged bool

// jumpStack is akin to the Vim concept of a tagstack
jumpStack []protocol.Location
jumpStackPos int
Expand Down Expand Up @@ -442,3 +449,66 @@ func (v *vimstate) hover(args ...json.RawMessage) (interface{}, error) {
plain = strings.TrimSpace(plain)
return plain, nil
}

func (v *vimstate) updateQuickfix() error {
defer func() {
v.diagnosticsChanged = false
}()
var fns []span.URI
for u := range v.diagnostics {
fns = append(fns, u)
}
sort.Slice(fns, func(i, j int) bool {
return string(fns[i]) < string(fns[j])
})

tf, err := ioutil.TempFile("", "govim-quickfix-*")
if err != nil {
return fmt.Errorf("failed to create file for quickfix results: %v", err)
}
defer os.Remove(tf.Name())

// TODO this will become fragile at some point
cwd := v.ParseString(v.ChannelCall("getcwd"))

// now update the quickfix window based on the current diagnostics
for _, uri := range fns {
diags := v.diagnostics[uri]
fn, err := uri.Filename()
if err != nil {
return fmt.Errorf("failed to resolve filename from URI %q: %v", uri, err)
}
var buf *types.Buffer
for _, b := range v.buffers {
if b.URI() == uri {
buf = b
}
}
if buf == nil {
byts, err := ioutil.ReadFile(fn)
if err != nil {
return fmt.Errorf("failed to read contents of %v: %v", fn, err)
}
// create a temp buffer
buf = &types.Buffer{
Num: -1,
Name: fn,
Contents: byts,
}
}
// make fn relative for reporting purposes
fn, err = filepath.Rel(cwd, fn)
if err != nil {
return fmt.Errorf("failed to call filepath.Rel(%q, %q): %v", cwd, fn, err)
}
for _, d := range diags {
p, err := types.PointFromPosition(buf, d.Range.Start)
if err != nil {
return fmt.Errorf("failed to resolve position: %v", err)
}
fmt.Fprintf(tf, "%v:%v:%v: %v\n", fn, p.Line(), p.Col(), d.Message)
}
}
v.ChannelExf("cgetfile %v", tf.Name())
return nil
}
15 changes: 15 additions & 0 deletions cmd/govim/gopls_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"

"github.com/kr/pretty"
"github.com/myitcv/govim"
"github.com/myitcv/govim/cmd/govim/internal/lsp/protocol"
"github.com/myitcv/govim/cmd/govim/internal/span"
)

var _ protocol.Client = (*govimplugin)(nil)
Expand Down Expand Up @@ -40,6 +42,19 @@ func (g *govimplugin) ApplyEdit(context.Context, *protocol.ApplyWorkspaceEditPar

func (g *govimplugin) PublishDiagnostics(ctxt context.Context, params *protocol.PublishDiagnosticsParams) error {
g.logGoplsClientf("PublishDiagnostics callback: %v", pretty.Sprint(params))
g.Schedule(func(govim.Govim) error {
v := g.vimstate
// TODO improve the efficiency of this. When we are watching files not yet loaded
// in Vim, we will likely have a reference to the file in vimstate. At this point
// we will need a lookup from URI -> Buffer which might give us nothing, at which
// point we fall back to the file. For now we simply check buffers first, then fall
// back to loading the file from disk

v.diagnostics[span.URI(params.URI)] = params.Diagnostics
v.diagnosticsChanged = true

return nil
})
return nil
}

Expand Down
6 changes: 4 additions & 2 deletions cmd/govim/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@ func newplugin(goplspath string) *govimplugin {
goplspath: goplspath,
Driver: d,
vimstate: &vimstate{
Driver: d,
buffers: make(map[int]*types.Buffer),
Driver: d,
buffers: make(map[int]*types.Buffer),
diagnostics: make(map[span.URI][]protocol.Diagnostic),
},
}
res.vimstate.govimplugin = res
Expand All @@ -148,6 +149,7 @@ func (g *govimplugin) Init(gg govim.Govim, errCh chan error) error {
g.DefineCommand(string(config.CommandGoToDef), g.gotoDef, govim.NArgsZeroOrOne)
g.DefineCommand(string(config.CommandGoToPrevDef), g.gotoPrevDef, govim.NArgsZeroOrOne, govim.CountN(1))
g.DefineFunction(string(config.FunctionHover), []string{}, g.hover)
g.DefineAutoCommand("", govim.Events{govim.EventCursorHold, govim.EventCursorHoldI}, govim.Patterns{"*.go"}, false, g.updateQuickfix)

g.isGui = g.ParseInt(g.ChannelExpr(`has("gui_running")`)) == 1

Expand Down
1 change: 0 additions & 1 deletion cmd/govim/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ func TestScripts(t *testing.T) {
if err != nil {
t.Fatalf("failed to create new driver: %v", err)
}
td.Log = os.Stderr
if *fLogGovim {
tf, err := ioutil.TempFile("", "govim_test_script_govim_log*")
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions plugin/govim.vim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ set ttymouse=sgr
set balloondelay=250
set ballooneval
set balloonevalterm
set updatetime=500
syntax on

" TODO these probably doesn't belong here?
Expand Down

0 comments on commit 3ac877d

Please sign in to comment.