Compare commits

...

28 commits
master ... lsp

Author SHA1 Message Date
Zachary Yedidia
afd50e40c2 Disable fake cursor for Windows Terminal
Ref #1900
2020-11-06 13:43:40 -05:00
Zachary Yedidia
38f63ae432 Autocomplete for any non-whitespace 2020-08-30 15:44:19 -04:00
Zachary Yedidia
188b579b22 Show detail and doc 2020-08-16 17:20:17 -04:00
Zachary Yedidia
01f55a6c79 Ensure correct ordering of notifications 2020-08-16 12:35:08 -04:00
Zachary Yedidia
98b3ed0eec Fix undo autocomplete 2020-08-16 01:03:41 -04:00
Zachary Yedidia
724cedd37b Basic autocomplete box 2020-08-15 20:41:54 -04:00
Zachary Yedidia
132630a9a5 Apply additional edits if they exist 2020-08-15 18:20:10 -04:00
Zachary Yedidia
9999ef643f Use delta instead of textedit 2020-08-15 18:17:57 -04:00
Zachary Yedidia
68270773dd Use text edits for autocompletion 2020-08-15 18:05:29 -04:00
Zachary Yedidia
3821a7a075 Allow configuring lsp server list 2020-08-13 13:06:37 -04:00
Zachary Yedidia
a26dd63d93 Replace toml with yaml 2020-08-12 21:56:49 -04:00
Zachary Yedidia
25f65a5f7b LSP option and better LSP status 2020-08-12 21:40:20 -04:00
Zachary Yedidia
c822a16596 Shutdown lsp servers 2020-08-12 21:15:17 -04:00
Zachary Yedidia
eb5c123674 Fix usage of multireplace 2020-08-12 17:16:32 -04:00
Zachary Yedidia
8f6f336b6c Range format 2020-08-12 16:56:57 -04:00
Zachary Yedidia
0b49ffd7cb Fix nullwriter 2020-08-12 16:27:44 -04:00
Zachary Yedidia
3c50ac1666 Fix edit application in formatting 2020-08-12 16:21:05 -04:00
Zachary Yedidia
c1621086a2 Autoformatting 2020-08-12 16:03:23 -04:00
Zachary Yedidia
08f772b7d0 Better hover parsing 2020-08-12 16:03:23 -04:00
Zachary Yedidia
5ea8bd3aa1 Convert filetypes to language IDs 2020-08-12 16:03:23 -04:00
Zachary Yedidia
e3689ffbd8 Hover support 2020-08-12 16:03:23 -04:00
Zachary Yedidia
4af1dfcbd8 Handle initialization and didOpen properly 2020-08-12 16:03:23 -04:00
Zachary Yedidia
a4148d069a Fix issue with didChange position 2020-08-12 16:03:23 -04:00
Zachary Yedidia
f0b1158ab6 Run notifications in background to hide latency 2020-08-12 16:03:23 -04:00
Zachary Yedidia
c344f1bfce Fix notifications vs requests 2020-08-12 16:03:23 -04:00
Zachary Yedidia
053134af1c Basic non-compliant autocompletion via LSP 2020-08-12 16:03:23 -04:00
Zachary Yedidia
f6ba76424a Send didChange events 2020-08-12 16:03:23 -04:00
Zachary Yedidia
26442bdbbe Basic communication with lsp server 2020-08-12 16:03:23 -04:00
28 changed files with 1460 additions and 121 deletions

View file

@ -12,7 +12,7 @@ type NullWriter struct{}
// Write is empty
func (NullWriter) Write(data []byte) (n int, err error) {
return 0, nil
return len(data), nil
}
// InitLog sets up the debug log system for micro if it has been enabled by compile-time variables

View file

@ -10,6 +10,7 @@ import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/display"
"github.com/zyedidia/micro/v2/internal/lsp"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
@ -34,6 +35,8 @@ func LuaImport(pkg string) *lua.LTable {
return luaImportMicroConfig()
case "micro/util":
return luaImportMicroUtil()
case "micro/lsp":
return luaImportMicroLsp()
default:
return ulua.Import(pkg)
}
@ -153,3 +156,10 @@ func luaImportMicroUtil() *lua.LTable {
return pkg
}
func luaImportMicroLsp() *lua.LTable {
pkg := ulua.L.NewTable()
ulua.L.SetField(pkg, "GetLanguage", luar.New(ulua.L, lsp.GetLanguage))
return pkg
}

View file

@ -20,6 +20,7 @@ import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/clipboard"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/lsp"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/shell"
@ -218,6 +219,8 @@ func LoadInput(args []string) []*buffer.Buffer {
func main() {
defer func() {
lsp.ShutdownAllServers()
if util.Stdout.Len() > 0 {
fmt.Fprint(os.Stdout, util.Stdout.String())
}
@ -250,6 +253,11 @@ func main() {
screen.TermMessage(err)
}
err = lsp.Init()
if err != nil {
screen.TermMessage(err)
}
// flag options
for k, v := range optionFlags {
if *v != "" {
@ -405,6 +413,7 @@ func DoEvent() {
action.MainTab().Display()
action.InfoBar.Display()
screen.Screen.Show()
action.InfoBar.Message("")
// Check for new events
select {

2
go.mod
View file

@ -19,6 +19,8 @@ require (
github.com/zyedidia/pty v2.0.0+incompatible // indirect
github.com/zyedidia/tcell v1.4.10
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415
go.lsp.dev/protocol v0.8.0
go.lsp.dev/uri v0.3.0
golang.org/x/text v0.3.2
gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/yaml.v2 v2.2.7

194
go.sum
View file

@ -1,40 +1,136 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/p-e-w/go-runewidth v0.0.10-0.20200613030200-3e1705c5c059 h1:/+h2b6i15wh4EWsFkfdNdBE1jjGA872tpXEyhPM5aYg=
github.com/p-e-w/go-runewidth v0.0.10-0.20200613030200-3e1705c5c059/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA=
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
@ -56,22 +152,120 @@ github.com/zyedidia/tcell v1.4.10 h1:40iES9kNgiaTvp/wLTB4Elikx4uDPIPdV5fhI2EQiog
github.com/zyedidia/tcell v1.4.10/go.mod h1:HhlbMSCcGX15rFDB+Q1Lk3pKEOocsCUAQC3zhZ9sadA=
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415 h1:752dTQ5OatJ9M5ULK2+9lor+nzyZz+LYDo3WGngg3Rc=
github.com/zyedidia/terminal v0.0.0-20180726154117-533c623e2415/go.mod h1:8leT8G0Cm8NoJHdrrKHyR9MirWoF4YW7pZh06B6H+1E=
go.lsp.dev/jsonrpc2 v0.5.0 h1:nZfFY/G0SkMoogjAj2ltoWRvQ9xMzHDMIBWMS3CaUak=
go.lsp.dev/jsonrpc2 v0.5.0/go.mod h1:YPWQH63927Zzz1M+t4r3p/OrmQ3EfKjRLBd3S2E0e4g=
go.lsp.dev/protocol v0.8.0 h1:hSmnNllbCfvkRi0AjsKa8nua3EdCa4iAey75mDCpEv4=
go.lsp.dev/protocol v0.8.0/go.mod h1:SD+a8QoAIIR7H7/SAYPDLn6iQnEeHNEicfkFOR1j9E8=
go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo=
go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
layeh.com/gopher-luar v1.0.7 h1:53iv6CCkRs5wyofZ+qVXcyAYQOIG52s6pt4xkqZdq7k=
layeh.com/gopher-luar v1.0.7/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

View file

@ -10,10 +10,12 @@ import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/clipboard"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/lsp"
"github.com/zyedidia/micro/v2/internal/screen"
"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
@ -664,6 +666,13 @@ func (h *BufPane) Autocomplete() bool {
return false
}
// if there is an existing completion, always cycle it
if b.HasSuggestions {
h.cycleAutocomplete(true)
return true
}
// don't start a new completion unless the correct conditions are met
if h.Cursor.X == 0 {
return false
}
@ -673,12 +682,14 @@ func (h *BufPane) Autocomplete() bool {
// don't autocomplete if cursor is on alpha numeric character (middle of a word)
return false
}
if b.HasSuggestions {
b.CycleAutocomplete(true)
return true
ret := true
if !b.Autocomplete(buffer.LSPComplete) {
ret = b.Autocomplete(buffer.BufferComplete)
}
return b.Autocomplete(buffer.BufferComplete)
if ret {
h.displayCompletionDoc()
}
return true
}
// CycleAutocompleteBack cycles back in the autocomplete suggestion list
@ -688,12 +699,24 @@ func (h *BufPane) CycleAutocompleteBack() bool {
}
if h.Buf.HasSuggestions {
h.Buf.CycleAutocomplete(false)
h.cycleAutocomplete(false)
return true
}
return false
}
func (h *BufPane) cycleAutocomplete(forward bool) {
h.Buf.CycleAutocomplete(forward)
h.displayCompletionDoc()
}
func (h *BufPane) displayCompletionDoc() {
c := h.Buf.CurCompletion
if c >= 0 && c < len(h.Buf.Completions) {
InfoBar.Message(h.Buf.Completions[c].Doc)
}
}
// InsertTab inserts a tab or spaces
func (h *BufPane) InsertTab() bool {
b := h.Buf
@ -1814,6 +1837,52 @@ 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))
if err != nil {
InfoBar.Error(err)
return false
}
info = strings.Split(info, "\n")[0]
InfoBar.Message(info)
return true
}
// AutoFormat automatically formats the document using LSP
func (h *BufPane) AutoFormat() bool {
var err error
var edits []protocol.TextEdit
if h.Cursor.HasSelection() {
edits, err = h.Buf.Server.DocumentRangeFormat(h.Buf.AbsPath, protocol.Range{
Start: lsp.Position(h.Cursor.CurSelection[0].X, h.Cursor.CurSelection[0].Y),
End: lsp.Position(h.Cursor.CurSelection[1].X, h.Cursor.CurSelection[1].Y),
}, protocol.FormattingOptions{
InsertSpaces: h.Buf.Settings["tabstospaces"].(bool),
TabSize: h.Buf.Settings["tabsize"].(float64),
})
} else {
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
}
h.Buf.ApplyEdits(edits)
return true
}
// None is an action that does nothing
func (h *BufPane) None() bool {
return true

View file

@ -688,6 +688,8 @@ var BufKeyActions = map[string]BufKeyAction{
"JumpLine": (*BufPane).JumpLine,
"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

@ -72,6 +72,7 @@ var bufdefaults = map[string]string{
"Ctrl-w": "NextSplit",
"Ctrl-u": "ToggleMacro",
"Ctrl-j": "PlayMacro",
"Alt-i": "SemanticInfo",
"Insert": "ToggleOverwriteMode",
// Emacs-style keybindings

View file

@ -15,7 +15,7 @@ import (
// for example with `vsplit filename`.
// CommandComplete autocompletes commands
func CommandComplete(b *buffer.Buffer) ([]string, []string) {
func CommandComplete(b *buffer.Buffer) []buffer.Completion {
c := b.GetActiveCursor()
input, argstart := buffer.GetArg(b)
@ -32,11 +32,11 @@ func CommandComplete(b *buffer.Buffer) ([]string, []string) {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return completions, suggestions
return buffer.ConvertCompletions(completions, suggestions, c)
}
// HelpComplete autocompletes help topics
func HelpComplete(b *buffer.Buffer) ([]string, []string) {
func HelpComplete(b *buffer.Buffer) []buffer.Completion {
c := b.GetActiveCursor()
input, argstart := buffer.GetArg(b)
@ -54,7 +54,7 @@ func HelpComplete(b *buffer.Buffer) ([]string, []string) {
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return completions, suggestions
return buffer.ConvertCompletions(completions, suggestions, c)
}
// colorschemeComplete tab-completes names of colorschemes.
@ -87,7 +87,7 @@ func contains(s []string, e string) bool {
}
// OptionComplete autocompletes options
func OptionComplete(b *buffer.Buffer) ([]string, []string) {
func OptionComplete(b *buffer.Buffer) []buffer.Completion {
c := b.GetActiveCursor()
input, argstart := buffer.GetArg(b)
@ -97,22 +97,17 @@ func OptionComplete(b *buffer.Buffer) ([]string, []string) {
suggestions = append(suggestions, option)
}
}
// for option := range localSettings {
// if strings.HasPrefix(option, input) && !contains(suggestions, option) {
// suggestions = append(suggestions, option)
// }
// }
sort.Strings(suggestions)
completions := make([]string, len(suggestions))
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return completions, suggestions
return buffer.ConvertCompletions(completions, suggestions, c)
}
// OptionValueComplete completes values for various options
func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
func OptionValueComplete(b *buffer.Buffer) []buffer.Completion {
c := b.GetActiveCursor()
l := b.LineBytes(c.Y)
l = util.SliceStart(l, c.X)
@ -128,12 +123,6 @@ func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
break
}
}
// for option := range localSettings {
// if option == string(args[len(args)-2]) {
// completeValue = true
// break
// }
// }
}
if !completeValue {
return OptionComplete(b)
@ -150,11 +139,6 @@ func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
optionVal = option
}
}
// for k, option := range localSettings {
// if k == inputOpt {
// optionVal = option
// }
// }
switch optionVal.(type) {
case bool:
@ -204,11 +188,11 @@ func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return completions, suggestions
return buffer.ConvertCompletions(completions, suggestions, c)
}
// PluginCmdComplete autocompletes the plugin command
func PluginCmdComplete(b *buffer.Buffer) ([]string, []string) {
func PluginCmdComplete(b *buffer.Buffer) []buffer.Completion {
c := b.GetActiveCursor()
input, argstart := buffer.GetArg(b)
@ -224,11 +208,11 @@ func PluginCmdComplete(b *buffer.Buffer) ([]string, []string) {
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return completions, suggestions
return buffer.ConvertCompletions(completions, suggestions, c)
}
// PluginComplete completes values for the plugin command
func PluginComplete(b *buffer.Buffer) ([]string, []string) {
func PluginComplete(b *buffer.Buffer) []buffer.Completion {
c := b.GetActiveCursor()
l := b.LineBytes(c.Y)
l = util.SliceStart(l, c.X)
@ -260,7 +244,7 @@ func PluginComplete(b *buffer.Buffer) ([]string, []string) {
for i := range suggestions {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return completions, suggestions
return buffer.ConvertCompletions(completions, suggestions, c)
}
// PluginNameComplete completes with the names of loaded plugins

View file

@ -7,7 +7,9 @@ import (
"sort"
"strings"
"github.com/zyedidia/micro/v2/internal/lsp"
"github.com/zyedidia/micro/v2/internal/util"
"go.lsp.dev/protocol"
)
// A Completer is a function that takes a buffer and returns info
@ -17,49 +19,61 @@ import (
// the current cursor location if selected as well as a list of
// suggestion names which can be displayed in an autocomplete box or
// other UI element
type Completer func(*Buffer) ([]string, []string)
func (b *Buffer) GetSuggestions() {
type Completer func(*Buffer) []Completion
type Completion struct {
Edits []Delta
Label string
CommitChars []rune
Kind string
Filter string
Detail string
Doc string
}
// Autocomplete starts the autocomplete process
func (b *Buffer) Autocomplete(c Completer) bool {
b.Completions, b.Suggestions = c(b)
if len(b.Completions) != len(b.Suggestions) || len(b.Completions) == 0 {
b.Completions = c(b)
if len(b.Completions) == 0 {
return false
}
b.CurSuggestion = -1
b.CurCompletion = -1
b.CycleAutocomplete(true)
return true
}
// CycleAutocomplete moves to the next suggestion
func (b *Buffer) CycleAutocomplete(forward bool) {
prevSuggestion := b.CurSuggestion
prevCompletion := b.CurCompletion
if forward {
b.CurSuggestion++
b.CurCompletion++
} else {
b.CurSuggestion--
b.CurCompletion--
}
if b.CurSuggestion >= len(b.Suggestions) {
b.CurSuggestion = 0
} else if b.CurSuggestion < 0 {
b.CurSuggestion = len(b.Suggestions) - 1
if b.CurCompletion >= len(b.Completions) {
b.CurCompletion = 0
} else if b.CurCompletion < 0 {
b.CurCompletion = len(b.Completions) - 1
}
c := b.GetActiveCursor()
start := c.Loc
end := c.Loc
if prevSuggestion < len(b.Suggestions) && prevSuggestion >= 0 {
start = end.Move(-util.CharacterCountInString(b.Completions[prevSuggestion]), b)
} else {
// end = start.Move(1, b)
// undo prev completion
if prevCompletion != -1 {
prev := b.Completions[prevCompletion]
for i := 0; i < len(prev.Edits); i++ {
if len(prev.Edits[i].Text) != 0 {
b.UndoOneEvent()
}
if !prev.Edits[i].Start.Equal(prev.Edits[i].End) {
b.UndoOneEvent()
}
}
}
b.Replace(start, end, b.Completions[b.CurSuggestion])
if len(b.Suggestions) > 1 {
// apply current completion
comp := b.Completions[b.CurCompletion]
b.ApplyDeltas(comp.Edits)
if len(b.Completions) > 1 {
b.HasSuggestions = true
}
}
@ -104,7 +118,7 @@ func GetArg(b *Buffer) (string, int) {
}
// FileComplete autocompletes filenames
func FileComplete(b *Buffer) ([]string, []string) {
func FileComplete(b *Buffer) []Completion {
c := b.GetActiveCursor()
input, argstart := GetArg(b)
@ -123,7 +137,7 @@ func FileComplete(b *Buffer) ([]string, []string) {
}
if err != nil {
return nil, nil
return nil
}
var suggestions []string
@ -149,16 +163,16 @@ func FileComplete(b *Buffer) ([]string, []string) {
completions[i] = util.SliceEndStr(complete, c.X-argstart)
}
return completions, suggestions
return ConvertCompletions(completions, suggestions, c)
}
// BufferComplete autocompletes based on previous words in the buffer
func BufferComplete(b *Buffer) ([]string, []string) {
func BufferComplete(b *Buffer) []Completion {
c := b.GetActiveCursor()
input, argstart := GetWord(b)
if argstart == -1 {
return []string{}, []string{}
return nil
}
inputLen := util.CharacterCount(input)
@ -201,5 +215,97 @@ func BufferComplete(b *Buffer) ([]string, []string) {
completions[i] = util.SliceEndStr(suggestions[i], c.X-argstart)
}
return completions, suggestions
return ConvertCompletions(completions, suggestions, c)
}
func LSPComplete(b *Buffer) []Completion {
if !b.HasLSP() {
return nil
}
c := b.GetActiveCursor()
pos := lsp.Position(c.X, c.Y)
items, err := b.Server.Completion(b.AbsPath, pos)
if err != nil {
return nil
}
completions := make([]Completion, len(items))
for i, item := range items {
completions[i] = Completion{
Label: item.Label,
Detail: item.Detail,
Kind: toKindStr(item.Kind),
Doc: getDoc(item.Documentation),
}
if item.TextEdit != nil && len(item.TextEdit.NewText) > 0 {
completions[i].Edits = []Delta{Delta{
Text: []byte(item.TextEdit.NewText),
Start: toLoc(item.TextEdit.Range.Start),
End: toLoc(item.TextEdit.Range.End),
}}
// for _, e := range item.AdditionalTextEdits {
// d := Delta{
// Text: []byte(e.NewText),
// Start: toLoc(e.Range.Start),
// End: toLoc(e.Range.End),
// }
// completions[i].Edits = append(completions[i].Edits, d)
// }
} else {
var t string
if len(item.InsertText) > 0 {
t = item.InsertText
} else {
t = item.Label
}
_, argstart := GetWord(b)
str := util.SliceEnd([]byte(t), c.X-argstart)
completions[i].Edits = []Delta{Delta{
Text: str,
Start: Loc{c.X, c.Y},
End: Loc{c.X, c.Y},
}}
}
}
return completions
}
// ConvertCompletions converts a list of insert text with suggestion labels
// to an array of completion objects ready for autocompletion
func ConvertCompletions(completions, suggestions []string, c *Cursor) []Completion {
comp := make([]Completion, len(completions))
for i := 0; i < len(completions); i++ {
comp[i] = Completion{
Label: suggestions[i],
}
comp[i].Edits = []Delta{Delta{
Text: []byte(completions[i]),
Start: Loc{c.X, c.Y},
End: Loc{c.X, c.Y},
}}
}
return comp
}
func toKindStr(k protocol.CompletionItemKind) string {
s := k.String()
return strings.ToLower(string(s[0]))
}
// returns documentation from a string | MarkupContent item
func getDoc(documentation interface{}) string {
var doc string
switch s := documentation.(type) {
case string:
doc = s
case protocol.MarkupContent:
doc = s.Value
}
return strings.Split(doc, "\n")[0]
}

View file

@ -10,23 +10,26 @@ import (
"io/ioutil"
"os"
"path"
gopath "path"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"time"
luar "layeh.com/gopher-luar"
dmp "github.com/sergi/go-diff/diffmatchpatch"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/lsp"
ulua "github.com/zyedidia/micro/v2/internal/lua"
"github.com/zyedidia/micro/v2/internal/screen"
"github.com/zyedidia/micro/v2/internal/util"
"github.com/zyedidia/micro/v2/pkg/highlight"
lspt "go.lsp.dev/protocol"
"golang.org/x/text/encoding/htmlindex"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
luar "layeh.com/gopher-luar"
)
const backupTime = 8000
@ -90,9 +93,8 @@ type SharedBuffer struct {
// Settings customized by the user
Settings map[string]interface{}
Suggestions []string
Completions []string
CurSuggestion int
Completions []Completion
CurCompletion int
Messages []*Message
@ -123,6 +125,9 @@ type SharedBuffer struct {
// Hash of the original buffer -- empty if fastdirty is on
origHash [md5.Size]byte
Server *lsp.Server
version uint64
}
func (b *SharedBuffer) insert(pos Loc, value []byte) {
@ -132,12 +137,37 @@ func (b *SharedBuffer) insert(pos Loc, value []byte) {
inslines := bytes.Count(value, []byte{'\n'})
b.MarkModified(pos.Y, pos.Y+inslines)
b.lspDidChange(pos, pos, string(value))
}
func (b *SharedBuffer) remove(start, end Loc) []byte {
b.isModified = true
b.HasSuggestions = false
defer b.MarkModified(start.Y, end.Y)
return b.LineArray.remove(start, end)
sub := b.LineArray.remove(start, end)
b.lspDidChange(start, end, "")
return sub
}
func (b *SharedBuffer) lspDidChange(start, end Loc, text string) {
b.version++
// TODO: convert to UTF16 codepoints
change := lspt.TextDocumentContentChangeEvent{
Range: &lspt.Range{
Start: lsp.Position(start.X, start.Y),
End: lsp.Position(end.X, end.Y),
},
Text: text,
}
if b.HasLSP() {
b.Server.DidChange(b.AbsPath, b.version, []lspt.TextDocumentContentChangeEvent{change})
}
}
// HasLSP returns whether this buffer is communicating with an LSP server
func (b *SharedBuffer) HasLSP() bool {
return b.Server != nil && b.Server.Active
}
// MarkModified marks the buffer as modified for this frame
@ -369,9 +399,40 @@ func NewBuffer(r io.Reader, size int64, path string, startcursor Loc, btype BufT
OpenBuffers = append(OpenBuffers, b)
if !found {
if btype == BTDefault && b.Settings["lsp"].(bool) {
b.lspInit()
}
}
return b
}
// initializes an LSP server if possible, or calls didOpen on an existing
// LSP server in this workspace
func (b *Buffer) lspInit() {
ft := lsp.Filetype(b.Settings["filetype"].(string))
l, ok := lsp.GetLanguage(ft)
if ok && l.Installed() {
b.Server = lsp.GetServer(l, gopath.Dir(b.AbsPath))
if b.Server == nil {
var err error
b.Server, err = lsp.StartServer(l)
if err == nil {
d, _ := os.Getwd()
b.Server.Initialize(d)
}
}
if b.HasLSP() {
bytes := b.Bytes()
if len(bytes) == 0 {
bytes = []byte{'\n'}
}
b.Server.DidOpen(b.AbsPath, ft, string(bytes), b.version)
}
}
}
// Close removes this buffer from the list of open buffers
func (b *Buffer) Close() {
for i, buf := range OpenBuffers {
@ -396,6 +457,10 @@ func (b *Buffer) Fini() {
if b.Type == BTStdout {
fmt.Fprint(util.Stdout, string(b.Bytes()))
}
if b.HasLSP() {
b.Server.DidClose(b.AbsPath)
}
}
// GetName returns the name that should be displayed in the statusline
@ -427,6 +492,7 @@ func (b *Buffer) Insert(start Loc, text string) {
b.EventHandler.Insert(start, text)
b.RequestBackup()
b.RelocateCursors()
}
}
@ -438,6 +504,68 @@ func (b *Buffer) Remove(start, end Loc) {
b.EventHandler.Remove(start, end)
b.RequestBackup()
b.RelocateCursors()
}
}
// 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 {
// insert/replace
b.Replace(toLoc(e.Range.Start), toLoc(e.Range.End), e.NewText)
}
}
func (b *Buffer) ApplyEdits(edits []lspt.TextEdit) {
if !b.Type.Readonly {
locs := make([]struct {
t string
start, end Loc
}, len(edits))
for i, e := range edits {
locs[i] = struct {
t string
start, end Loc
}{
t: e.NewText,
start: toLoc(e.Range.Start),
end: toLoc(e.Range.End),
}
}
// Since edit ranges are guaranteed by LSP to never overlap we can sort
// by last edit first and apply each edit in order
// Perhaps in the future we should make this more robust to a non-conforming
// server that sends overlapping ranges
sort.Slice(locs, func(i, j int) bool {
return locs[i].start.GreaterThan(locs[j].start)
})
for _, d := range locs {
if len(d.t) == 0 {
b.Remove(d.start, d.end)
} else {
b.Replace(d.start, d.end, d.t)
}
}
b.RelocateCursors()
}
}
func (b *Buffer) ApplyDeltas(deltas []Delta) {
if !b.Type.Readonly {
sort.Slice(deltas, func(i, j int) bool {
return deltas[i].Start.GreaterThan(deltas[j].Start)
})
for _, d := range deltas {
if len(d.Text) == 0 {
b.Remove(d.Start, d.End)
} else {
b.ReplaceBytes(d.Start, d.End, d.Text)
}
}
b.RelocateCursors()
}
}

View file

@ -2,6 +2,7 @@ package buffer
import (
"bytes"
"log"
"time"
dmp "github.com/sergi/go-diff/diffmatchpatch"
@ -52,6 +53,7 @@ func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) {
}
if len(t.Deltas) != 1 {
log.Println("Multiple deltas not supported")
return
}
@ -230,6 +232,12 @@ func (eh *EventHandler) Replace(start, end Loc, replace string) {
eh.Insert(start, replace)
}
// ReplaceBytes deletes from start to end and replaces it with the given string
func (eh *EventHandler) ReplaceBytes(start, end Loc, replace []byte) {
eh.Remove(start, end)
eh.InsertBytes(start, replace)
}
// Execute a textevent and add it to the undo stack
func (eh *EventHandler) Execute(t *TextEvent) {
if eh.RedoStack.Len() > 0 {

View file

@ -2,6 +2,7 @@ package buffer
import (
"github.com/zyedidia/micro/v2/internal/util"
"go.lsp.dev/protocol"
)
// Loc stores a location
@ -47,6 +48,11 @@ func (l Loc) LessEqual(b Loc) bool {
return l == b
}
// Equal returns true if two locs are equal
func (l Loc) Equal(b Loc) bool {
return l.Y == b.Y && l.X == b.X
}
// The following functions require a buffer to know where newlines are
// Diff returns the distance between two locations
@ -146,3 +152,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

@ -195,5 +195,10 @@ func (b *Buffer) saveToFile(filename string, withSudo bool) error {
b.AbsPath = absPath
b.isModified = false
b.UpdateRules()
if b.HasLSP() {
b.Server.DidSave(b.AbsPath)
}
return err
}

View file

@ -39,6 +39,12 @@ func (b *Buffer) SetOptionNative(option string, nativeValue interface{}) error {
b.isModified = true
} else if option == "readonly" && b.Type.Kind == BTDefault.Kind {
b.Type.Readonly = nativeValue.(bool)
} else if option == "lsp" && b.Type.Kind == BTDefault.Kind {
if nativeValue.(bool) && !b.HasLSP() {
b.lspInit()
} else if b.HasLSP() {
b.Server.Shutdown()
}
}
return nil

View file

@ -1265,7 +1265,7 @@ func runtimePluginsStatusHelpStatusMd() (*asset, error) {
return a, nil
}
var _runtimePluginsStatusStatusLua = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x94\xc1\x6b\xdb\x30\x14\xc6\xef\xfe\x2b\x84\x4e\x32\x24\x6a\x77\xd8\x65\x90\x43\xda\xa5\x69\xd9\x68\x47\x1c\xca\xae\xb2\xfd\x1c\x3f\x90\x25\x23\xc9\x61\xed\x61\x7f\xfb\x90\x64\xb7\x76\x42\xc0\x1b\xa3\xb9\xe9\xbd\xdf\xfb\xf2\xf9\xb3\x9e\x9f\x37\xbb\xec\xe1\xe9\x91\xac\x08\xfd\xc4\xaf\xf9\x35\x4d\x12\xa9\x0b\x21\x49\x83\x85\xd1\x64\x45\xb0\x69\xb5\x71\x8c\x86\x33\x4d\xfb\x6e\xde\x55\x15\x98\xd3\xf6\x55\x2c\xbf\x51\x85\x56\x15\x1e\xce\xa8\x58\x7e\xa3\xea\xae\x11\x0a\x5f\x61\xc4\x0d\x25\x9a\x26\x49\xd5\xa9\xc2\xa1\x56\x04\x15\x3a\x96\x26\x84\x90\x68\x8e\x67\xe0\x32\x27\x5c\x67\x1f\x54\xa5\xef\x14\xa3\x36\x9c\x78\x6e\x84\x2a\x6a\x3a\x07\xad\x85\x9d\x07\xb6\xc2\x3a\x98\x45\x1e\x0b\x2d\x67\x81\x12\x15\xd8\x59\x64\xfe\xe2\x66\x92\x36\x86\xe6\xc1\x98\x32\x5f\x97\xe5\xae\x53\x0e\x1b\xb8\x43\x09\x03\x48\x17\x43\x7f\xb7\xbf\x07\xd9\x2e\x08\xad\x41\xb6\x57\xbd\x4c\x53\xd2\x34\x01\x55\x8e\xd2\x0f\x6e\x59\x1e\xb5\x0d\xb8\xce\x28\xe2\xb4\x75\x06\xd5\x81\xe5\x5f\xbe\xfb\xf6\x63\xd7\xb0\xf4\x74\xd0\xe7\x71\x79\x6e\x0b\x6e\x5d\x38\x3c\xc2\x6d\x67\xac\x36\x2c\xf5\x95\x67\xb4\x9d\x90\x3f\xcf\xb5\x42\x10\x97\xc5\x32\x7c\x85\xf3\x21\x9f\xc9\xc9\xcc\x70\xbf\xf8\x4d\x14\xbc\x30\x19\x2f\xd2\x30\x8b\x15\xc9\xf9\xfe\xa5\x05\xfe\x0d\x55\x49\x7e\xaf\xfa\x2d\xe0\x37\x7b\xff\x16\x88\xab\x41\x05\xd0\xff\xe2\xd5\xb6\x35\x48\x79\x76\xff\x43\xb5\x7f\x4b\x23\x36\x3c\x85\x1d\xd1\x7d\xc5\x2f\xc1\x14\x8d\xbe\x16\x04\x8c\x5f\xc1\x20\xc7\x37\xbf\xa0\xb8\xd5\x4d\x23\x54\xc9\xe8\x01\x1d\x5d\x10\x6a\xe0\xb8\x6c\x85\xb1\xe0\x0f\xcb\xa5\xc8\x73\x5f\x31\x50\xf9\xf3\xfd\x66\xfd\x75\x64\x02\xab\x28\xb7\x22\x0a\xe5\xf4\x59\x46\xc1\xf5\x96\xf8\xde\x60\x93\xb5\xa2\x00\x16\xbd\xbc\xeb\xf8\x04\x4f\x86\x28\x4d\x86\xce\x34\x5f\xbf\x7d\x97\xd3\xfd\xfc\x81\x89\x7a\x27\x7f\x9d\xa7\xad\xb5\x71\xff\x31\x4a\x6f\xe2\xdf\x82\x0c\x5f\xa7\x51\x92\xfd\x6e\x6f\xc1\x6d\xa5\xce\x85\x7c\x6a\x3d\xc6\x68\xff\x15\x9b\x7a\x1a\xc4\x7f\xac\xb3\xfd\x86\xbc\xff\xc5\xf4\x8f\x7d\xe5\x4f\x00\x00\x00\xff\xff\xdc\xdb\xdf\x2a\x2d\x06\x00\x00"
var _runtimePluginsStatusStatusLua = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x95\x4f\x6b\xdc\x3c\x10\xc6\xef\xfb\x29\x84\x4e\x36\x6c\x94\xbc\x87\xf7\x12\xd8\xc3\x26\xdd\x6c\x42\x43\x12\xe2\x25\x14\x4a\x0e\xb2\x3d\x5e\x0f\x91\x25\x21\xc9\xa1\xc9\xa1\x9f\xbd\x48\xb2\x77\xbd\xff\xc0\x2d\xa5\x37\x6b\xf4\xcc\xe3\x99\x9f\x3c\xf2\xcb\xe2\x39\xbb\x7b\x7c\x20\x33\x42\xff\x63\x17\xec\x82\x4e\x26\x42\x15\x5c\x90\x06\x0b\xa3\xc8\x8c\x60\xa3\x95\x71\x09\x0d\x6b\x9a\x76\xbb\x79\x5b\x55\x60\xf6\xb7\xcf\x63\x78\xa3\x2a\x94\xac\x70\x7d\xa0\x8a\xe1\x8d\xaa\x6e\x1b\x2e\xf1\x13\x06\xba\x3e\x44\xd3\xc9\xa4\x6a\x65\xe1\x50\x49\x82\x12\x5d\x92\x4e\x08\x21\xb1\x38\x96\x81\xcb\x1c\x77\xad\xbd\x93\x95\xba\x91\x09\xb5\x61\xc5\x72\xc3\x65\x51\xd3\x31\xd2\x9a\xdb\x71\x42\xcd\xad\x83\x51\xca\xf7\x42\x89\x51\x42\x81\x12\xec\x28\x65\xfe\xe1\x46\x2a\x6d\x84\x36\xe2\xe5\x56\x77\xba\x78\x1a\x6c\x5e\x96\xcf\xad\x74\xd8\xc0\x0d\x0a\xe8\x75\x74\xda\xef\x3f\xaf\x6e\x41\xe8\x29\xa1\x35\x08\x7d\xde\xb9\x34\x25\x4d\x27\x20\xcb\xc1\x29\x85\xae\x92\x3c\x7a\x1b\x70\xad\x91\xc4\x29\xeb\x0c\xca\x75\x92\x5f\xde\xfb\xed\x87\xb6\x49\xd2\xfd\x44\xcf\xed\x74\xde\x12\xdc\xbc\x70\xf8\x0e\xd7\xad\xb1\xca\x24\xa9\x8f\xbc\xa0\x6d\xb9\xf8\x76\xe8\x15\x80\x9d\x36\xcb\xf0\x13\x0e\x93\x3c\xbb\xbd\x9c\xfe\x3b\x64\x57\xd1\xf0\x44\xa6\xb0\xba\x4f\xc4\x8a\x48\xe5\x48\xee\xc1\x3b\x94\x6b\xfb\x9d\x7a\xd4\xaf\xc4\xd5\x20\x83\x62\x60\x4f\x4b\xb4\x3c\x17\x50\xd2\xb0\xe3\x4d\x3b\x8f\xfc\xf2\x96\xdb\xfb\xec\x29\x49\x8f\x27\x2a\xb9\x4d\x09\x0f\x71\x94\x84\xd5\x07\xd3\xb6\x3d\xe9\x4e\x33\x25\xea\x8d\xcc\xbc\x96\x2d\xc1\xdd\x73\xb9\x6e\xf9\x1a\x92\x61\xc9\x15\x0a\x70\x1f\x1a\xe8\xeb\x4e\x57\xea\xed\x78\x35\xad\xb4\xad\xf6\xef\x3c\xd2\x89\xcf\x13\x97\x77\xd2\x3a\x2e\x04\x94\x27\x1a\x12\xec\x5a\x35\x0d\x97\x25\x61\x8c\xd0\x90\x84\x7d\xca\xae\xe5\x86\x40\x55\xd1\xfd\x53\x0f\x73\x3f\x38\x89\x9c\xad\x3e\x34\xb0\xaf\x28\x4b\xf2\x73\xd6\x5d\x5a\xec\x6a\xe5\x67\x61\xb7\x8c\x88\xc6\xd6\x20\xc4\x01\xc0\x10\xed\x10\x0e\xb4\xe1\x63\xb2\x03\x75\x17\xf1\x77\xd6\xae\x34\xd6\x35\x25\x60\xfc\x8d\x19\xec\xd8\xe2\x07\x14\x5d\xcb\x09\x5d\xa3\xa3\x53\x42\x0d\xbc\x9f\x69\x6e\x2c\xf8\xc5\xd9\x19\xcf\x73\x1f\x31\x50\xf9\xf5\xed\x62\xfe\x65\x50\x04\x56\xd1\x6e\x46\x24\x8a\xdd\x5e\x06\x94\xba\x92\xd8\xca\x60\x93\x69\x5e\x40\x12\x6b\xd9\xfa\xf4\x58\x87\x68\xb7\xc0\x77\xf9\xfa\xcb\xf2\x34\xdd\xff\xff\x21\x51\x5f\xc9\x6f\xf3\xb4\xb5\x32\xee\x2f\xa2\xf4\x45\xfc\x19\xc8\xf0\x33\x19\x90\xec\xae\xd8\x25\xb8\xa5\x50\x39\x17\x8f\xda\xcb\x12\xda\xfd\x74\x8e\x0f\xdd\xd3\x3c\x5b\x2d\xc8\xf1\xe1\x88\x93\xf1\x2b\x00\x00\xff\xff\xa5\x47\xb2\xb8\xdc\x07\x00\x00"
func runtimePluginsStatusStatusLuaBytes() ([]byte, error) {
return bindataRead(
@ -5525,7 +5525,7 @@ func runtimeSyntaxRustHdr() (*asset, error) {
return a, nil
}
var _runtimeSyntaxRustYaml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x52\x4f\x4f\x1b\x3f\x10\xbd\xe7\x53\x98\x0d\x07\x20\x4a\x96\x2b\x7b\xf9\xe9\x27\x4a\xa5\x1e\x5a\xa4\x96\x43\xd4\xec\x0a\x79\xbd\x63\x62\xe1\x3f\xab\xf1\x38\x40\x34\x1f\xbe\xf2\x26\x21\x90\x20\x51\xa9\x39\x38\xde\xf9\xf7\xde\x3c\x3f\x6d\x2c\xd0\x4b\x0f\x95\xc0\x14\x69\x34\xea\x80\x40\x51\x35\x12\x42\x88\x9c\xf3\xd2\x41\x25\x8a\xba\x9e\x61\x3c\x2d\x46\x23\x4c\x16\xe2\x26\x3d\x16\x3a\x79\x45\x26\x78\xd1\x81\x36\xde\xe4\xeb\x90\x99\x0a\xd3\x81\x27\xa3\x0d\x60\x25\x0a\xed\xc5\x42\x4e\xd7\x97\xd3\xab\xfb\x66\x52\x0c\x15\xb9\xfb\x27\x44\xc0\x15\x74\xe2\x29\x60\x17\xb7\x8d\x91\x24\x81\x03\x4f\x03\x68\x7b\x26\xdb\x48\x28\x15\xb1\xb4\xe6\xc1\x07\xcd\x32\x72\x0b\x2a\x38\xe0\x36\x3c\x73\x8b\x20\x1f\x59\x05\x1f\x29\x9f\x64\x7c\x02\x56\x28\x09\xb8\x0b\x0c\x36\x02\x83\x4f\x8e\xe1\x99\x00\x3d\x6b\x99\x23\xda\x78\x69\x59\x7b\xd6\x01\xd9\x68\x36\xae\xb7\x6c\x3c\x5b\x20\xb6\x21\xf4\xec\xa4\xc2\xc0\x4e\x92\x5a\xb2\x0b\x1d\xbb\xb0\x02\x76\x89\x38\x68\x1d\x81\x82\xe6\xb0\x02\x44\xd3\x01\xf7\x68\x56\xdc\xa7\x96\xfb\x84\xc0\x08\x9a\x11\x28\xa1\xe7\x68\xd6\x10\x34\xe7\x7d\x8c\xe2\x08\x36\xdf\x31\x29\xe2\x98\x7a\x40\x26\x4c\xc0\x84\xd2\x10\x67\xfd\x87\x23\x68\x4e\x3e\x4a\x0d\xf9\xcf\xac\xa1\xe3\x14\x81\x57\x06\x29\x49\xcb\x4f\x4b\x40\xe0\xa7\xa5\xb1\xc0\x2f\x06\x6c\x77\x5e\xd7\xed\x5e\xce\x81\xf4\xab\x8c\x3d\x28\x23\x6d\x25\x8a\xac\xfc\x7d\x33\x39\xd9\x17\x5e\x67\xb5\xa4\xa7\x5d\xad\xda\x7e\xe7\xe2\xff\xa7\xbf\x9b\x7c\xbc\x7b\xa8\x1f\xc9\xb5\x80\x87\xe5\x33\x3f\x84\x37\xef\xb4\xb8\x9c\x5e\x35\x93\x77\x7c\xee\xf2\x6e\xb1\xbc\xf1\xc9\xc5\xf2\xd7\xb0\x7a\x2c\xef\x5e\x7a\x88\x25\x90\x9a\x6d\xa7\x6d\xbc\xb7\x05\x96\xd3\x75\xc6\x3d\x04\x8a\x84\xc6\x3f\x54\xdb\xc9\x22\x7b\x04\x07\x7f\x14\xc5\x6b\x0c\x7c\x77\x10\x89\x8f\xa6\x1f\xc8\xd5\xf5\x6c\x1f\x7d\xe3\xdf\xdd\xef\x2d\xd2\x46\xb6\xeb\xa5\xc4\x7d\xeb\xdf\xd2\xc1\xf1\xe4\x23\x46\xe3\xc9\x21\xba\x58\x34\xfb\xa1\x6e\x30\xfb\xd1\xb0\xb2\x3c\x9c\x74\xfa\xc9\x12\x14\xba\x50\x89\xe2\xec\xee\xf6\xcb\x2d\xcf\xe7\x73\xfe\xfa\x6d\xfe\xfd\xe6\xbc\xfa\xaf\xf8\x1c\xac\xae\x2f\x8e\x88\xd7\x17\xe5\x3f\x23\xee\x6c\x78\x84\x38\x3e\xa9\xeb\xc5\x31\x64\xf3\xa1\x54\x7f\x02\x00\x00\xff\xff\x3f\xf7\x58\xfe\xa4\x04\x00\x00"
var _runtimeSyntaxRustYaml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x53\x41\x6f\xf3\x36\x0c\xbd\xe7\x57\xe8\x73\xbe\x43\xd2\x20\x49\xd7\x16\xc5\xea\xcb\xb0\x75\x1d\xb0\xc3\x56\x60\xeb\x21\x58\x1c\x14\xb2\x4d\x35\x44\x65\xc9\xa0\xa8\xa4\x29\xf8\xe3\x07\x39\x49\xd3\x26\x05\x3a\x60\x3e\xd0\x12\x25\xf2\x3d\x3e\x8a\x06\x2d\xf0\xa6\x85\x5c\x51\x0c\xdc\xeb\xd5\xc0\x50\x71\xde\x53\x4a\xa9\x74\xe6\x74\x03\xb9\xca\x8a\x62\x42\xe1\x7b\xd6\xeb\x51\xb4\x10\xb6\xc7\x7d\x65\xa2\xab\x18\xbd\x53\x35\x18\x74\x98\x96\xdd\xc9\x58\x61\x0d\x8e\xd1\x20\x50\xae\x32\xe3\xd4\x5c\x8f\x5f\xcf\xc7\x37\x8f\x8b\x51\xd6\xdd\x48\xd1\x7f\x41\x00\x5a\x41\xad\xd6\x9e\xea\xb0\x0b\x0c\xac\x19\x1a\x70\xdc\x81\x96\x03\x5d\x06\x26\x5d\xb1\x68\x8b\x4f\xce\x1b\xd1\x41\x4a\xa8\x7c\x03\x52\xfa\x17\x29\x09\xf4\xb3\x54\xde\x05\x4e\x96\xd1\x45\x90\x8a\x34\x83\xd4\x5e\xea\x8d\x13\xb0\x01\x04\x5c\x6c\x04\x5e\x18\xc8\x89\xd1\xc9\x63\xd0\x69\x2b\xc6\x89\xf1\x24\x68\x04\x9b\xd6\x0a\x3a\xb1\xc0\x62\xbd\x6f\xa5\xd1\x15\x79\x69\x34\x57\x4b\x69\x7c\x2d\x8d\x5f\x81\x34\x91\xc5\x1b\x13\x80\xbd\x11\xbf\x02\x22\xac\x41\x5a\xc2\x95\xb4\xb1\x94\x36\x12\x08\x81\x11\x02\x8e\xe4\x24\xe0\x2b\x78\x23\xa9\x26\xac\x24\x80\x4d\x6b\x8a\x15\x4b\x88\x2d\x90\x30\x45\x10\x26\x8d\x2c\xa9\x07\x9d\xf1\x46\xa2\x0b\xda\x40\xfa\xe1\x2b\xd4\x12\x03\xc8\x0a\x89\xa3\xb6\xb2\x5e\x02\x81\xac\x97\x68\x41\x36\x08\xb6\x1e\x16\x45\x79\x90\xb4\x23\xfd\x26\x65\x0b\x15\x6a\x9b\xab\x2c\xa9\xff\xb8\x18\x7d\x3b\x5c\xbc\x4d\x8a\x69\xc7\xfb\xbb\xd5\x6e\xbf\x55\x7d\xfe\xf3\xf8\x9f\x45\x32\x8f\xe7\xe3\x9b\xc5\xe8\x03\xc4\x9f\xb1\x29\x81\x8e\xe3\x26\xae\x73\xef\xc2\x4f\xa3\x7e\xf1\xde\x82\x76\x9f\xc3\x0d\x3a\x1d\xba\xbe\x7c\x2c\xe7\x21\x49\x13\xa6\x77\x2e\x36\x61\xfa\x77\xa7\x5c\x98\x3e\x6c\x5a\x08\x53\xe0\x6a\xb2\x4b\xb6\x7d\xbe\x6f\xbc\x47\xa9\xda\x3d\xf7\xb3\xb4\x39\x72\x7d\x24\x16\xd1\x32\xba\x2e\x49\x50\xbc\xd4\x9c\x9e\x20\xb1\x5a\x23\x2f\x95\xf5\x6b\xa0\x4a\x07\x38\xc5\x1a\x94\xde\xdb\xd4\x4e\xc1\xd4\x26\x89\x9d\x1d\x0c\x50\xe2\x70\xf0\xa3\xfc\x70\x2d\x97\x17\x72\x7d\x35\x1c\x8a\xb9\xbc\x10\x73\x7d\xb5\x2d\xed\x58\xb7\xc0\x84\xee\x29\xdf\xf1\x51\x5b\xf0\x84\x90\x65\x6f\x3e\x70\xf5\x91\x27\x3c\x63\xdb\xd1\x28\x8a\xc9\xc1\xfb\x6e\x36\xf7\xdf\x7b\xa4\xed\x73\xb8\x5d\x6a\x3a\x84\xfe\x57\x3a\xd4\x1f\x7d\xc6\xa8\x3f\x3a\x46\x57\xf3\xc5\x21\x69\xd3\x0d\xf2\x49\xb2\xe9\xf4\x38\xd3\xf7\x2f\x8a\x60\x5f\xfb\x5c\x65\x83\x87\xfb\x5f\xef\x65\x36\x9b\xc9\x6f\xbf\xcf\xfe\xb8\x1b\xe6\x3f\x65\x5f\x83\x15\xc5\xd9\x09\xf1\xe2\x6c\xfa\xbf\x11\xf7\xe3\x75\x82\xd8\xff\x56\x14\xf3\x53\xc8\xc5\xa7\x52\xfd\x1b\x00\x00\xff\xff\x73\x64\x84\x65\x80\x05\x00\x00"
func runtimeSyntaxRustYamlBytes() ([]byte, error) {
return bindataRead(

View file

@ -272,6 +272,7 @@ var defaultCommonSettings = map[string]interface{}{
"ignorecase": false,
"indentchar": " ",
"keepautoindent": false,
"lsp": true,
"matchbrace": true,
"mkparents": false,
"permbackup": false,

View file

@ -17,7 +17,8 @@ type BufWindow struct {
*View
// Buffer being shown in this window
Buf *buffer.Buffer
Buf *buffer.Buffer
completeBox buffer.Loc
active bool
@ -583,6 +584,13 @@ func (w *BufWindow) displayBuffer() {
screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, combc, style)
if w.Buf.HasSuggestions && len(w.Buf.Completions) > 0 {
compl := w.Buf.Completions[0].Edits[0].Start
if bloc.X == compl.X && bloc.Y == compl.Y {
w.completeBox = buffer.Loc{w.X + vloc.X, w.Y + vloc.Y}
}
}
if showcursor {
for _, c := range cursors {
if c.X == bloc.X && c.Y == bloc.Y && !c.HasSelection() {
@ -742,9 +750,60 @@ func (w *BufWindow) displayScrollBar() {
}
}
func (w *BufWindow) displayCompleteBox() {
if !w.Buf.HasSuggestions || w.Buf.NumCursors() > 1 {
return
}
labelw := 0
detailw := 0
kindw := 0
for _, comp := range w.Buf.Completions {
charcount := util.CharacterCountInString(comp.Label)
if charcount > labelw {
labelw = charcount
}
charcount = util.CharacterCountInString(comp.Detail)
if charcount > detailw {
detailw = charcount
}
charcount = util.CharacterCountInString(comp.Kind)
if charcount > kindw {
kindw = charcount
}
}
labelw++
kindw++
display := func(s string, width, x, y int, cur bool) {
for j := 0; j < width; j++ {
r := ' '
var combc []rune
var size int
if len(s) > 0 {
r, combc, size = util.DecodeCharacterInString(s)
s = s[size:]
}
st := config.DefStyle.Reverse(true)
if cur {
st = st.Reverse(false)
}
screen.SetContent(w.completeBox.X+x+j, w.completeBox.Y+y, r, combc, st)
}
}
for i, comp := range w.Buf.Completions {
cur := i == w.Buf.CurCompletion
display(comp.Label+" ", labelw, 0, i+1, cur)
display(comp.Kind+" ", kindw, labelw, i+1, cur)
display(comp.Detail, detailw, labelw+kindw, i+1, cur)
}
}
// Display displays the buffer and the statusline
func (w *BufWindow) Display() {
w.displayStatusLine()
w.displayScrollBar()
w.displayBuffer()
w.displayCompleteBox()
}

View file

@ -179,8 +179,8 @@ func (i *InfoWindow) displayKeyMenu() {
func (i *InfoWindow) totalSize() int {
sum := 0
for _, n := range i.Suggestions {
sum += runewidth.StringWidth(n) + 1
for _, n := range i.Completions {
sum += runewidth.StringWidth(n.Label) + 1
}
return sum
}
@ -189,9 +189,9 @@ func (i *InfoWindow) scrollToSuggestion() {
x := 0
s := i.totalSize()
for j, n := range i.Suggestions {
c := util.CharacterCountInString(n)
if j == i.CurSuggestion {
for j, n := range i.Completions {
c := util.CharacterCountInString(n.Label)
if j == i.CurCompletion {
if x+c >= i.hscroll+i.Width {
i.hscroll = util.Clamp(x+c+1-i.Width, 0, s-i.Width)
} else if x < i.hscroll {
@ -236,7 +236,7 @@ func (i *InfoWindow) Display() {
}
}
if i.HasSuggestions && len(i.Suggestions) > 1 {
if i.HasSuggestions && len(i.Completions) > 1 {
i.scrollToSuggestion()
x := -i.hscroll
@ -273,12 +273,12 @@ func (i *InfoWindow) Display() {
}
}
for j, s := range i.Suggestions {
for j, s := range i.Completions {
style := statusLineStyle
if i.CurSuggestion == j {
if i.CurCompletion == j {
style = style.Reverse(true)
}
for _, r := range s {
for _, r := range s.Label {
draw(r, style)
// screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style)
}

View file

@ -98,44 +98,6 @@ func (s *StatusLine) Display() {
// We'll draw the line at the lowest line in the window
y := s.win.Height + s.win.Y - 1
b := s.win.Buf
// autocomplete suggestions (for the buffer, not for the infowindow)
if b.HasSuggestions && len(b.Suggestions) > 1 {
statusLineStyle := config.DefStyle.Reverse(true)
if style, ok := config.Colorscheme["statusline"]; ok {
statusLineStyle = style
}
keymenuOffset := 0
if config.GetGlobalOption("keymenu").(bool) {
keymenuOffset = len(keydisplay)
}
x := 0
for j, sug := range b.Suggestions {
style := statusLineStyle
if b.CurSuggestion == j {
style = style.Reverse(true)
}
for _, r := range sug {
screen.SetContent(x, y-keymenuOffset, r, nil, style)
x++
if x >= s.win.Width {
return
}
}
screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
x++
if x >= s.win.Width {
return
}
}
for x < s.win.Width {
screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
x++
}
return
}
formatter := func(match []byte) []byte {
name := match[2 : len(match)-1]
if bytes.HasPrefix(name, []byte("opt")) {

94
internal/lsp/install.go Normal file
View file

@ -0,0 +1,94 @@
package lsp
import (
"errors"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/zyedidia/micro/v2/internal/config"
"gopkg.in/yaml.v2"
)
var ErrManualInstall = errors.New("Requires manual installation")
type Config struct {
Languages map[string]Language `yaml:"language"`
}
type Language struct {
Command string `yaml:"command"`
Args []string `yaml:"args"`
Install [][]string `yaml:"install"`
}
var conf *Config
func GetLanguage(lang string) (Language, bool) {
if conf != nil {
l, ok := conf.Languages[lang]
return l, ok
}
return Language{}, false
}
func Init() error {
var servers []byte
var err error
filename := filepath.Join(config.ConfigDir, "lsp.yaml")
if _, e := os.Stat(filename); e == nil {
servers, err = ioutil.ReadFile(filename)
if err != nil {
servers = servers_internal
}
} else {
err = ioutil.WriteFile(filename, servers_internal, 0644)
servers = servers_internal
}
conf, err = LoadConfig(servers)
return err
}
func LoadConfig(data []byte) (*Config, error) {
var conf Config
if err := yaml.Unmarshal(data, &conf); err != nil {
return nil, err
}
return &conf, nil
}
func (l Language) Installed() bool {
_, err := exec.LookPath(l.Command)
if err != nil {
return false
}
return true
}
func (l Language) DoInstall(w io.Writer) error {
if l.Installed() {
return nil
}
if len(l.Install) == 0 {
return ErrManualInstall
}
for _, c := range l.Install {
io.WriteString(w, strings.Join(c, " ")+"\n")
cmd := exec.Command(c[0], c[1:]...)
err := cmd.Run()
if err != nil {
return err
}
}
return nil
}

20
internal/lsp/languages.go Normal file
View file

@ -0,0 +1,20 @@
package lsp
// mappings for when micro filetypes don't match LSP language identifiers
var languages = map[string]string{
"batch": "bat",
"c++": "cpp",
"git-rebase-todo": "git-rebase",
"html4": "html",
"html5": "html",
"python2": "python",
"shell": "shellscript",
// "tex": "latex",
}
func Filetype(ft string) string {
if l, ok := languages[ft]; ok {
return l
}
return ft
}

View file

@ -0,0 +1,58 @@
package lsp
import (
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"
)
func (s *Server) DidOpen(filename, language, text string, version uint64) {
doc := lsp.TextDocumentItem{
URI: uri.File(filename),
LanguageID: lsp.LanguageIdentifier(language),
Version: float64(version), // not sure why this is a float on go.lsp.dev
Text: text,
}
params := lsp.DidOpenTextDocumentParams{
TextDocument: doc,
}
go s.sendNotification(lsp.MethodTextDocumentDidOpen, params)
}
func (s *Server) DidSave(filename string) {
doc := lsp.TextDocumentIdentifier{
URI: uri.File(filename),
}
params := lsp.DidSaveTextDocumentParams{
TextDocument: doc,
}
go s.sendNotification(lsp.MethodTextDocumentDidSave, params)
}
func (s *Server) DidChange(filename string, version uint64, changes []lsp.TextDocumentContentChangeEvent) {
doc := lsp.VersionedTextDocumentIdentifier{
TextDocumentIdentifier: lsp.TextDocumentIdentifier{
URI: uri.File(filename),
},
Version: &version,
}
params := lsp.DidChangeTextDocumentParams{
TextDocument: doc,
ContentChanges: changes,
}
go s.sendNotification(lsp.MethodTextDocumentDidChange, params)
}
func (s *Server) DidClose(filename string) {
doc := lsp.TextDocumentIdentifier{
URI: uri.File(filename),
}
params := lsp.DidCloseTextDocumentParams{
TextDocument: doc,
}
go s.sendNotification(lsp.MethodTextDocumentDidClose, params)
}

198
internal/lsp/requests.go Normal file
View file

@ -0,0 +1,198 @@
package lsp
import (
"encoding/json"
"errors"
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"
)
var ErrNotSupported = errors.New("Operation not supported by language server")
type RPCCompletion struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
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"`
// Range an optional range is a range inside a text document
// that is used to visualize a hover, e.g. by changing the background color.
Range lsp.Range `json:"range,omitempty"`
}
type RPCHoverAlternate struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
Result hoverAlternate `json:"result"`
}
func Position(x, y int) lsp.Position {
return lsp.Position{
Line: float64(y),
Character: float64(x),
}
}
func (s *Server) DocumentFormat(filename string, options lsp.FormattingOptions) ([]lsp.TextEdit, error) {
if !s.capabilities.DocumentFormattingProvider {
return nil, ErrNotSupported
}
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(filename string, r lsp.Range, options lsp.FormattingOptions) ([]lsp.TextEdit, error) {
if !s.capabilities.DocumentRangeFormattingProvider {
return nil, ErrNotSupported
}
doc := lsp.TextDocumentIdentifier{
URI: uri.File(filename),
}
params := lsp.DocumentRangeFormattingParams{
Options: options,
Range: r,
TextDocument: doc,
}
resp, err := s.sendRequest(lsp.MethodTextDocumentFormatting, params)
if err != nil {
return nil, err
}
var rpc RPCFormat
err = json.Unmarshal(resp, &rpc)
if err != nil {
return nil, err
}
return rpc.Result, nil
}
func (s *Server) Completion(filename string, pos lsp.Position) ([]lsp.CompletionItem, error) {
if s.capabilities.CompletionProvider == nil {
return nil, ErrNotSupported
}
cc := lsp.CompletionContext{
TriggerKind: lsp.Invoked,
}
docpos := lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{
URI: uri.File(filename),
},
Position: pos,
}
params := lsp.CompletionParams{
TextDocumentPositionParams: docpos,
Context: &cc,
}
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 ra.Result, nil
}
func (s *Server) CompletionResolve() {
}
func (s *Server) Hover(filename string, pos lsp.Position) (string, error) {
if !s.capabilities.HoverProvider {
return "", ErrNotSupported
}
params := lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{
URI: uri.File(filename),
},
Position: pos,
}
resp, err := s.sendRequest(lsp.MethodTextDocumentHover, params)
if err != nil {
return "", err
}
var r RPCHover
err = json.Unmarshal(resp, &r)
if err == nil {
return r.Result.Contents.Value, nil
}
var ra RPCHoverAlternate
err = json.Unmarshal(resp, &ra)
if err != nil {
return "", err
}
for _, c := range ra.Result.Contents {
switch t := c.(type) {
case string:
return t, nil
case map[string]interface{}:
s, ok := t["value"].(string)
if ok {
return s, nil
}
}
}
return "", nil
}

322
internal/lsp/server.go Normal file
View file

@ -0,0 +1,322 @@
package lsp
import (
"bufio"
"encoding/json"
"errors"
"io"
"log"
"os"
"os/exec"
"strconv"
"strings"
"sync"
"time"
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"
)
var activeServers map[string]*Server
var slock sync.Mutex
func init() {
activeServers = make(map[string]*Server)
}
func GetServer(l Language, dir string) *Server {
s, ok := activeServers[l.Command+"-"+dir]
if ok && s.Active {
return s
}
return nil
}
func ShutdownAllServers() {
for _, s := range activeServers {
if s.Active {
s.Shutdown()
}
}
}
type Server struct {
cmd *exec.Cmd
stdin io.WriteCloser
stdout *bufio.Reader
language *Language
capabilities lsp.ServerCapabilities
root string
lock sync.Mutex
Active bool
requestID int
responses map[int]chan ([]byte)
}
type RPCRequest struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
Method string `json:"method"`
Params interface{} `json:"params"`
}
type RPCNotification struct {
RPCVersion string `json:"jsonrpc"`
Method string `json:"method"`
Params interface{} `json:"params"`
}
type RPCInit struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id"`
Result lsp.InitializeResult `json:"result"`
}
type RPCResult struct {
RPCVersion string `json:"jsonrpc"`
ID int `json:"id,omitempty"`
Method string `json:"method,omitempty"`
}
func StartServer(l Language) (*Server, error) {
s := new(Server)
c := exec.Command(l.Command, l.Args...)
c.Stderr = log.Writer()
stdin, err := c.StdinPipe()
if err != nil {
log.Println("[micro-lsp]", err)
return nil, err
}
stdout, err := c.StdoutPipe()
if err != nil {
log.Println("[micro-lsp]", err)
return nil, err
}
err = c.Start()
if err != nil {
log.Println("[micro-lsp]", err)
return nil, err
}
s.cmd = c
s.stdin = stdin
s.stdout = bufio.NewReader(stdout)
s.language = &l
s.responses = make(map[int]chan []byte)
return s, nil
}
// Initialize performs the LSP initialization handshake
// The directory must be an absolute path
func (s *Server) Initialize(directory string) {
params := lsp.InitializeParams{
ProcessID: float64(os.Getpid()),
RootURI: uri.File(directory),
Capabilities: lsp.ClientCapabilities{
Workspace: &lsp.WorkspaceClientCapabilities{
WorkspaceEdit: &lsp.WorkspaceClientCapabilitiesWorkspaceEdit{
DocumentChanges: true,
ResourceOperations: []string{"create", "rename", "delete"},
},
ApplyEdit: true,
},
TextDocument: &lsp.TextDocumentClientCapabilities{
Formatting: &lsp.TextDocumentClientCapabilitiesFormatting{
DynamicRegistration: false,
},
Completion: &lsp.TextDocumentClientCapabilitiesCompletion{
DynamicRegistration: false,
CompletionItem: &lsp.TextDocumentClientCapabilitiesCompletionItem{
SnippetSupport: false,
CommitCharactersSupport: false,
DocumentationFormat: []lsp.MarkupKind{lsp.PlainText},
DeprecatedSupport: false,
PreselectSupport: false,
},
ContextSupport: false,
},
Hover: &lsp.TextDocumentClientCapabilitiesHover{
DynamicRegistration: false,
ContentFormat: []lsp.MarkupKind{lsp.PlainText},
},
},
},
}
activeServers[s.language.Command+"-"+directory] = s
s.Active = true
s.root = directory
go s.receive()
s.lock.Lock()
go func() {
resp, err := s.sendRequest(lsp.MethodInitialize, params)
if err != nil {
log.Println("[micro-lsp]", err)
s.Active = false
s.lock.Unlock()
return
}
// todo parse capabilities
log.Println("[micro-lsp] <<<", string(resp))
var r RPCInit
json.Unmarshal(resp, &r)
s.lock.Unlock()
err = s.sendNotification(lsp.MethodInitialized, struct{}{})
if err != nil {
log.Println("[micro-lsp]", err)
}
s.capabilities = r.Result.Capabilities
}()
}
func (s *Server) Shutdown() {
s.sendRequest(lsp.MethodShutdown, nil)
s.sendNotification(lsp.MethodExit, nil)
s.Active = false
}
func (s *Server) receive() {
for s.Active {
resp, err := s.receiveMessage()
if err == io.EOF {
log.Println("Received EOF, shutting down")
s.Active = false
return
}
if err != nil {
log.Println("[micro-lsp,error]", err)
continue
}
log.Println("[micro-lsp] <<<", string(resp))
var r RPCResult
err = json.Unmarshal(resp, &r)
if err != nil {
log.Println("[micro-lsp]", err)
continue
}
switch r.Method {
case lsp.MethodWindowLogMessage:
// TODO
case lsp.MethodTextDocumentPublishDiagnostics:
// TODO
case "":
// Response
if _, ok := s.responses[r.ID]; ok {
log.Println("[micro-lsp] Got response for", r.ID)
s.responses[r.ID] <- resp
}
}
}
}
func (s *Server) receiveMessage() ([]byte, error) {
n := -1
for {
b, err := s.stdout.ReadBytes('\n')
if err != nil {
return nil, err
}
headerline := strings.TrimSpace(string(b))
if len(headerline) == 0 {
break
}
if strings.HasPrefix(headerline, "Content-Length:") {
split := strings.Split(headerline, ":")
if len(split) <= 1 {
break
}
n, err = strconv.Atoi(strings.TrimSpace(split[1]))
if err != nil {
return nil, err
}
}
}
if n <= 0 {
return []byte{}, nil
}
bytes := make([]byte, n)
_, err := io.ReadFull(s.stdout, bytes)
if err != nil {
log.Println("[micro-lsp]", err)
}
return bytes, err
}
func (s *Server) sendNotification(method string, params interface{}) error {
m := RPCNotification{
RPCVersion: "2.0",
Method: method,
Params: params,
}
s.lock.Lock()
go s.sendMessageUnlock(m)
return nil
}
func (s *Server) sendRequest(method string, params interface{}) ([]byte, error) {
id := s.requestID
s.requestID++
r := make(chan []byte)
s.responses[id] = r
m := RPCRequest{
RPCVersion: "2.0",
ID: id,
Method: method,
Params: params,
}
err := s.sendMessage(m)
if err != nil {
return nil, err
}
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, err
}
func (s *Server) sendMessage(m interface{}) error {
msg, err := json.Marshal(m)
if err != nil {
return err
}
log.Println("[micro-lsp] >>>", string(msg))
// encode header and proper line endings
msg = append(msg, '\r', '\n')
header := []byte("Content-Length: " + strconv.Itoa(len(msg)) + "\r\n\r\n")
msg = append(header, msg...)
_, err = s.stdin.Write(msg)
return err
}
func (s *Server) sendMessageUnlock(m interface{}) error {
defer s.lock.Unlock()
return s.sendMessage(m)
}

View file

@ -0,0 +1,67 @@
package lsp
var servers_internal = []byte(`language:
rust:
command: rls
install: [["rustup", "update"], ["rustup", "component", "add", "rls", "rust-analysis", "rust-src"]]
javascript:
command: typescript-language-server
args: ["--stdio"]
install: [["npm", "install", "-g", "typescript-language-server"]]
typescript:
command: typescript-language-server
args: ["--stdio"]
install: [["npm", "install", "-g", "typescript-language-server"]]
html:
command: html-languageserver
args: ["--stdio"]
install: [["npm", "install", "-g", "vscode-html-languageserver-bin"]]
ocaml:
command: ocaml-language-server
args: ["--stdio"]
install: [["npm", "install", "-g", "ocaml-language-server"]]
python:
command: pyls
install: [["pip", "install", "python-language-server"]]
c:
command: clangd
args: []
cpp:
command: clangd
args: []
haskell:
command: hie
args: ["--lsp"]
go:
command: gopls
args: ["serve"]
install: [["go", "get", "-u", "golang.org/x/tools/gopls"]]
dart:
command: dart_language_server
install: [["pub", "global", "activate", "dart_language_server"]]
ruby:
command: solargraph
args: ["stdio"]
install: [["gem", "install", "solargraph"]]
css:
command: css-languageserver
args: ["--stdio"]
install: [["npm", "install", "-g", "vscode-css-languageserver-bin"]]
scss:
command: css-languageserver
args: ["--stdio"]
install: [["npm", "install", "-g", "vscode-css-languageserver-bin"]]
viml:
command: vim-language-server
args: ["--stdio"]
install: [["npm", "install", "-g", "vim-language-server"]]
purescript:
command: purescript-language-server
args: ["--stdio"]
install: [["npm", "install", "-g", "purescript-language-server"]]
verilog:
command: svls
install: [["cargo", "install", "svls"]]
d:
command: serve-d
`)

View file

@ -46,7 +46,8 @@ func init() {
fmt.Println("Invalid version: ", Version, err)
}
if runtime.GOOS == "windows" {
_, wt := os.LookupEnv("WT_SESSION")
if runtime.GOOS == "windows" && !wt {
FakeCursor = true
}
Stdout = new(bytes.Buffer)
@ -423,7 +424,7 @@ func IsNonAlphaNumeric(c rune) bool {
}
func IsAutocomplete(c rune) bool {
return c == '.' || !IsNonAlphaNumeric(c)
return !unicode.IsSpace(c) || !IsNonAlphaNumeric(c)
}
func ParseSpecial(s string) string {

View file

@ -13,6 +13,7 @@ function init()
micro.SetStatusInfoFn("status.lines")
micro.SetStatusInfoFn("status.bytes")
micro.SetStatusInfoFn("status.size")
micro.SetStatusInfoFn("status.lsp")
config.AddRuntimeFile("status", config.RTHelp, "help/status.md")
end
@ -32,6 +33,25 @@ function size(b)
return humanize.Bytes(b:Size())
end
function lsp(b)
if not b.Settings["lsp"] then
return "disabled"
end
if b:HasLSP() then
return "on"
end
local lsp = import("micro/lsp")
local l, ok = lsp.GetLanguage(b.Settings["filetype"])
if not ok then
return "unsupported"
end
if not l:Installed() then
return l.Command .. " not installed"
end
return "off"
end
function branch(b)
if b.Type.Kind ~= buffer.BTInfo then
local shell = import("micro/shell")