-
-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd/govim: refactor functionality of govim into separate files (#192)
Just makes working with it easier.
- Loading branch information
Showing
9 changed files
with
672 additions
and
600 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/myitcv/govim/cmd/govim/internal/lsp/protocol" | ||
"github.com/myitcv/govim/cmd/govim/types" | ||
) | ||
|
||
func (v *vimstate) balloonExpr(args ...json.RawMessage) (interface{}, error) { | ||
var vpos struct { | ||
BufNum int `json:"bufnum"` | ||
Line int `json:"line"` | ||
Col int `json:"col"` | ||
} | ||
expr := v.ChannelExpr(`{"bufnum": v:beval_bufnr, "line": v:beval_lnum, "col": v:beval_col}`) | ||
if err := json.Unmarshal(expr, &vpos); err != nil { | ||
return nil, fmt.Errorf("failed to unmarshal current mouse position info: %v", err) | ||
} | ||
b, ok := v.buffers[vpos.BufNum] | ||
if !ok { | ||
return nil, fmt.Errorf("unable to resolve buffer %v", vpos.BufNum) | ||
} | ||
pos, err := types.PointFromVim(b, vpos.Line, vpos.Col) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to determine mouse position: %v", err) | ||
} | ||
go func() { | ||
params := &protocol.TextDocumentPositionParams{ | ||
TextDocument: b.ToTextDocumentIdentifier(), | ||
Position: pos.ToPosition(), | ||
} | ||
hovRes, err := v.server.Hover(context.Background(), params) | ||
if err != nil { | ||
v.ChannelCall("balloon_show", fmt.Sprintf("failed to get hover details: %v", err)) | ||
} else { | ||
msg := strings.TrimSpace(hovRes.Contents.Value) | ||
var args interface{} = msg | ||
if !v.isGui { | ||
args = strings.Split(msg, "\n") | ||
} | ||
v.ChannelCall("balloon_show", args) | ||
} | ||
|
||
}() | ||
return "", nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/myitcv/govim/cmd/govim/internal/lsp/protocol" | ||
"github.com/myitcv/govim/cmd/govim/types" | ||
) | ||
|
||
func (v *vimstate) bufReadPost(args ...json.RawMessage) error { | ||
b := v.currentBufferInfo(args[0]) | ||
if cb, ok := v.buffers[b.Num]; ok { | ||
// reload of buffer, e.v. e! | ||
b.Version = cb.Version + 1 | ||
} else if wf, ok := v.watchedFiles[b.Name]; ok { | ||
// We are now picking up from a file that was previously watched. If we subsequently | ||
// close this buffer then we will handle that event and delete the entry in v.buffers | ||
// at which point the file watching will take back over again. | ||
delete(v.watchedFiles, b.Name) | ||
b.Version = wf.Version + 1 | ||
} else { | ||
b.Version = 0 | ||
} | ||
return v.handleBufferEvent(b) | ||
} | ||
|
||
func (v *vimstate) bufTextChanged(args ...json.RawMessage) error { | ||
b := v.currentBufferInfo(args[0]) | ||
cb, ok := v.buffers[b.Num] | ||
if !ok { | ||
return fmt.Errorf("have not seen buffer %v (%v) - this should be impossible", b.Num, b.Name) | ||
} | ||
b.Version = cb.Version + 1 | ||
return v.handleBufferEvent(b) | ||
} | ||
|
||
func (v *vimstate) handleBufferEvent(b *types.Buffer) error { | ||
v.buffers[b.Num] = b | ||
|
||
if b.Version == 0 { | ||
params := &protocol.DidOpenTextDocumentParams{ | ||
TextDocument: protocol.TextDocumentItem{ | ||
URI: string(b.URI()), | ||
Version: float64(b.Version), | ||
Text: string(b.Contents), | ||
}, | ||
} | ||
err := v.server.DidOpen(context.Background(), params) | ||
return err | ||
} | ||
|
||
params := &protocol.DidChangeTextDocumentParams{ | ||
TextDocument: protocol.VersionedTextDocumentIdentifier{ | ||
TextDocumentIdentifier: b.ToTextDocumentIdentifier(), | ||
Version: float64(b.Version), | ||
}, | ||
ContentChanges: []protocol.TextDocumentContentChangeEvent{ | ||
{ | ||
Text: string(b.Contents), | ||
}, | ||
}, | ||
} | ||
err := v.server.DidChange(context.Background(), params) | ||
return err | ||
} | ||
|
||
func (v *vimstate) deleteCurrentBuffer(args ...json.RawMessage) error { | ||
currBufNr := v.ParseInt(args[0]) | ||
cb, ok := v.buffers[currBufNr] | ||
if !ok { | ||
return fmt.Errorf("tried to remove buffer %v; but we have no record of it", currBufNr) | ||
} | ||
delete(v.buffers, cb.Num) | ||
params := &protocol.DidCloseTextDocumentParams{ | ||
TextDocument: cb.ToTextDocumentIdentifier(), | ||
} | ||
if err := v.server.DidClose(context.Background(), params); err != nil { | ||
return fmt.Errorf("failed to call gopls.DidClose on %v: %v", cb.Name, err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/myitcv/govim/cmd/govim/internal/lsp/protocol" | ||
) | ||
|
||
func (v *vimstate) complete(args ...json.RawMessage) (interface{}, error) { | ||
// Params are: findstart int, base string | ||
findstart := v.ParseInt(args[0]) == 1 | ||
|
||
if findstart { | ||
b, pos, err := v.cursorPos() | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to get current position: %v", err) | ||
} | ||
params := &protocol.CompletionParams{ | ||
TextDocumentPositionParams: protocol.TextDocumentPositionParams{ | ||
TextDocument: protocol.TextDocumentIdentifier{ | ||
URI: string(b.URI()), | ||
}, | ||
Position: pos.ToPosition(), | ||
}, | ||
} | ||
res, err := v.server.Completion(context.Background(), params) | ||
if err != nil { | ||
return nil, fmt.Errorf("called to gopls.Completion failed: %v", err) | ||
} | ||
|
||
v.lastCompleteResults = res | ||
return pos.Col(), nil | ||
} else { | ||
var matches []completionResult | ||
for _, i := range v.lastCompleteResults.Items { | ||
matches = append(matches, completionResult{ | ||
Abbr: i.Label, | ||
Word: i.TextEdit.NewText, | ||
Info: i.Detail, | ||
}) | ||
} | ||
|
||
return matches, nil | ||
} | ||
} | ||
|
||
type completionResult struct { | ||
Abbr string `json:"abbr"` | ||
Word string `json:"word"` | ||
Info string `json:"info"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/myitcv/govim/cmd/govim/config" | ||
"github.com/myitcv/govim/cmd/govim/internal/lsp/protocol" | ||
"github.com/myitcv/govim/cmd/govim/types" | ||
) | ||
|
||
func (v *vimstate) formatCurrentBuffer(args ...json.RawMessage) (err error) { | ||
tool := v.ParseString(v.ChannelExpr(config.GlobalFormatOnSave)) | ||
// we are an autocmd endpoint so we need to be told the current | ||
// buffer number via <abuf> | ||
currBufNr := v.ParseInt(args[0]) | ||
b, ok := v.buffers[currBufNr] | ||
if !ok { | ||
return fmt.Errorf("failed to resolve buffer %v", currBufNr) | ||
} | ||
|
||
var edits []protocol.TextEdit | ||
|
||
switch config.FormatOnSave(tool) { | ||
case config.FormatOnSaveNone: | ||
return nil | ||
case config.FormatOnSaveGoFmt: | ||
params := &protocol.DocumentFormattingParams{ | ||
TextDocument: b.ToTextDocumentIdentifier(), | ||
} | ||
edits, err = v.server.Formatting(context.Background(), params) | ||
if err != nil { | ||
return fmt.Errorf("failed to call gopls.Formatting: %v", err) | ||
} | ||
case config.FormatOnSaveGoImports: | ||
params := &protocol.CodeActionParams{ | ||
TextDocument: b.ToTextDocumentIdentifier(), | ||
} | ||
actions, err := v.server.CodeAction(context.Background(), params) | ||
if err != nil { | ||
return fmt.Errorf("failed to call gopls.CodeAction: %v", err) | ||
} | ||
switch len(actions) { | ||
case 0: | ||
return nil | ||
case 1: | ||
edits = (*actions[0].Edit.Changes)[string(b.URI())] | ||
default: | ||
return fmt.Errorf("don't know how to handle %v actions", len(actions)) | ||
} | ||
default: | ||
return fmt.Errorf("unknown format tool specified for %v: %v", config.GlobalFormatOnSave, tool) | ||
} | ||
|
||
// see :help wundo. The use of wundo! is significant. It first deletes | ||
// the temp file we created, but only recreates it if there is something | ||
// to write. This is inherently racey... because theorectically the file | ||
// might in the meantime have been created by another instance of | ||
// govim.... We reduce that risk using the time above | ||
tf, err := ioutil.TempFile("", strconv.FormatInt(time.Now().UnixNano(), 10)) | ||
if err != nil { | ||
return fmt.Errorf("failed to create temp undo file") | ||
} | ||
|
||
v.ChannelExf("wundo! %v", tf.Name()) | ||
defer func() { | ||
if _, err := os.Stat(tf.Name()); err != nil { | ||
return | ||
} | ||
v.ChannelExf("silent! rundo %v", tf.Name()) | ||
err = os.Remove(tf.Name()) | ||
}() | ||
|
||
preEventIgnore := v.ParseString(v.ChannelExpr("&eventignore")) | ||
v.ChannelEx("set eventignore=all") | ||
defer v.ChannelExf("set eventignore=%v", preEventIgnore) | ||
v.ToggleOnViewportChange() | ||
defer v.ToggleOnViewportChange() | ||
for ie := len(edits) - 1; ie >= 0; ie-- { | ||
e := edits[ie] | ||
start, err := types.PointFromPosition(b, e.Range.Start) | ||
if err != nil { | ||
return fmt.Errorf("failed to derive start point from position: %v", err) | ||
} | ||
end, err := types.PointFromPosition(b, e.Range.End) | ||
if err != nil { | ||
return fmt.Errorf("failed to derive end point from position: %v", err) | ||
} | ||
|
||
if start.Col() != 1 || end.Col() != 1 { | ||
// Whether this is a delete or not, we will implement support for this later | ||
return fmt.Errorf("saw an edit where start col != end col (range start: %v, range end: %v start: %v, end: %v). We can't currently handle this", e.Range.Start, e.Range.End, start, end) | ||
} | ||
|
||
if start.Line() != end.Line() { | ||
if e.NewText != "" { | ||
return fmt.Errorf("saw an edit where start line != end line with replacement text %q; We can't currently handle this", e.NewText) | ||
} | ||
// This is a delete of line | ||
if res := v.ParseInt(v.ChannelCall("deletebufline", b.Num, start.Line(), end.Line()-1)); res != 0 { | ||
return fmt.Errorf("deletebufline(%v, %v, %v) failed", b.Num, start.Line(), end.Line()-1) | ||
} | ||
} else { | ||
// do we have anything to do? | ||
if e.NewText == "" { | ||
continue | ||
} | ||
// we are within the same line so strip the newline | ||
if e.NewText[len(e.NewText)-1] == '\n' { | ||
e.NewText = e.NewText[:len(e.NewText)-1] | ||
} | ||
repl := strings.Split(e.NewText, "\n") | ||
v.ChannelCall("append", start.Line()-1, repl) | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.