Autoformatting

This commit is contained in:
Zachary Yedidia
2020-08-12 16:03:14 -04:00
parent 08f772b7d0
commit c1621086a2
7 changed files with 96 additions and 10 deletions

View File

@@ -15,6 +15,7 @@ import (
"github.com/zyedidia/micro/v2/internal/shell"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/tcell"
"go.lsp.dev/protocol"
)
// ScrollUp is not an action
@@ -1815,6 +1816,9 @@ func (h *BufPane) RemoveAllMultiCursors() bool {
return true
}
// SemanticInfo returns information about the identifier the cursor is on and
// displays the information in the infobar
// The information is fetched using the LSP server (must be enabled)
func (h *BufPane) SemanticInfo() bool {
info, err := h.Buf.Server.Hover(h.Buf.AbsPath, lsp.Position(h.Cursor.X, h.Cursor.Y))
@@ -1829,6 +1833,24 @@ func (h *BufPane) SemanticInfo() bool {
return true
}
// AutoFormat automatically formats the document using LSP
func (h *BufPane) AutoFormat() bool {
edits, err := h.Buf.Server.DocumentFormat(h.Buf.AbsPath, protocol.FormattingOptions{
InsertSpaces: h.Buf.Settings["tabstospaces"].(bool),
TabSize: h.Buf.Settings["tabsize"].(float64),
})
if err != nil {
InfoBar.Error(err)
return false
}
for _, e := range edits {
h.Buf.ApplyEdit(e)
}
return true
}
// None is an action that does nothing
func (h *BufPane) None() bool {
return true

View File

@@ -689,6 +689,7 @@ var BufKeyActions = map[string]BufKeyAction{
"Deselect": (*BufPane).Deselect,
"ClearInfo": (*BufPane).ClearInfo,
"SemanticInfo": (*BufPane).SemanticInfo,
"AutoFormat": (*BufPane).AutoFormat,
"None": (*BufPane).None,
// This was changed to InsertNewline but I don't want to break backwards compatibility

View File

@@ -419,7 +419,8 @@ func (b *Buffer) lspInit() {
var err error
b.Server, err = lsp.StartServer(l)
if err == nil {
b.Server.Initialize(gopath.Dir(b.AbsPath))
d, _ := os.Getwd()
b.Server.Initialize(d)
}
}
if b.HasLSP() {
@@ -505,6 +506,17 @@ func (b *Buffer) Remove(start, end Loc) {
}
}
// ApplyEdit performs a LSP text edit on the buffer
func (b *Buffer) ApplyEdit(e lspt.TextEdit) {
if len(e.NewText) == 0 {
// deletion
b.Remove(toLoc(e.Range.Start), toLoc(e.Range.End))
} else {
// insertion
b.Insert(toLoc(e.Range.Start), e.NewText)
}
}
// FileType returns the buffer's filetype
func (b *Buffer) FileType() string {
return b.Settings["filetype"].(string)

View File

@@ -2,6 +2,7 @@ package buffer
import (
"github.com/zyedidia/micro/v2/internal/util"
"go.lsp.dev/protocol"
)
// Loc stores a location
@@ -146,3 +147,10 @@ func clamp(pos Loc, la *LineArray) Loc {
}
return pos
}
func toLoc(r protocol.Position) Loc {
return Loc{
X: int(r.Character),
Y: int(r.Line),
}
}

View File

@@ -13,12 +13,24 @@ type RPCCompletion struct {
Result lsp.CompletionList `json:"result"`
}
type RPCCompletionAlternate struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
Result []lsp.CompletionItem `json:"result"`
}
type RPCHover struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
Result lsp.Hover `json:"result"`
}
type RPCFormat struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
Result []lsp.TextEdit `json:"result"`
}
type hoverAlternate struct {
// Contents is the hover's content
Contents []interface{} `json:"contents"`
@@ -41,8 +53,28 @@ func Position(x, y int) lsp.Position {
}
}
func (s *Server) DocumentFormat() {
func (s *Server) DocumentFormat(filename string, options lsp.FormattingOptions) ([]lsp.TextEdit, error) {
doc := lsp.TextDocumentIdentifier{
URI: uri.File(filename),
}
params := lsp.DocumentFormattingParams{
Options: options,
TextDocument: doc,
}
resp, err := s.sendRequest(lsp.MethodTextDocumentFormatting, params)
if err != nil {
return nil, err
}
var r RPCFormat
err = json.Unmarshal(resp, &r)
if err != nil {
return nil, err
}
return r.Result, nil
}
func (s *Server) DocumentRangeFormat() {
@@ -65,18 +97,22 @@ func (s *Server) Completion(filename string, pos lsp.Position) ([]lsp.Completion
TextDocumentPositionParams: docpos,
Context: &cc,
}
resp, err := s.sendRequest("textDocument/completion", params)
resp, err := s.sendRequest(lsp.MethodTextDocumentCompletion, params)
if err != nil {
return nil, err
}
var r RPCCompletion
err = json.Unmarshal(resp, &r)
if err == nil {
return r.Result.Items, nil
}
var ra RPCCompletionAlternate
err = json.Unmarshal(resp, &ra)
if err != nil {
return nil, err
}
return r.Result.Items, nil
return ra.Result, nil
}
func (s *Server) CompletionResolve() {
@@ -91,7 +127,7 @@ func (s *Server) Hover(filename string, pos lsp.Position) (string, error) {
Position: pos,
}
resp, err := s.sendRequest("textDocument/hover", params)
resp, err := s.sendRequest(lsp.MethodTextDocumentHover, params)
if err != nil {
return "", err
}

View File

@@ -3,6 +3,7 @@ package lsp
import (
"bufio"
"encoding/json"
"errors"
"io"
"log"
"os"
@@ -10,6 +11,7 @@ import (
"strconv"
"strings"
"sync"
"time"
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"
@@ -263,10 +265,15 @@ func (s *Server) sendRequest(method string, params interface{}) ([]byte, error)
return nil, err
}
bytes := <-r
var bytes []byte
select {
case bytes = <-r:
case <-time.After(5 * time.Second):
err = errors.New("Request timed out")
}
delete(s.responses, id)
return bytes, nil
return bytes, err
}
func (s *Server) sendMessage(m interface{}) error {

View File

@@ -32,11 +32,11 @@ command = "pyls"
install = [["pip", "install", "python-language-server"]]
[language.c]
command = "ccls"
command = "clangd"
args = []
[language.cpp]
command = "ccls"
command = "clangd"
args = []
[language.haskell]