mirror of
https://github.com/zyedidia/micro.git
synced 2026-04-03 00:19:50 +09:00
Compare commits
36 Commits
keybinding
...
lsp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afd50e40c2 | ||
|
|
38f63ae432 | ||
|
|
188b579b22 | ||
|
|
01f55a6c79 | ||
|
|
98b3ed0eec | ||
|
|
724cedd37b | ||
|
|
132630a9a5 | ||
|
|
9999ef643f | ||
|
|
68270773dd | ||
|
|
3821a7a075 | ||
|
|
a26dd63d93 | ||
|
|
25f65a5f7b | ||
|
|
c822a16596 | ||
|
|
eb5c123674 | ||
|
|
8f6f336b6c | ||
|
|
0b49ffd7cb | ||
|
|
3c50ac1666 | ||
|
|
c1621086a2 | ||
|
|
08f772b7d0 | ||
|
|
5ea8bd3aa1 | ||
|
|
e3689ffbd8 | ||
|
|
4af1dfcbd8 | ||
|
|
a4148d069a | ||
|
|
f0b1158ab6 | ||
|
|
c344f1bfce | ||
|
|
053134af1c | ||
|
|
f6ba76424a | ||
|
|
26442bdbbe | ||
|
|
c5bafbc1c5 | ||
|
|
6b80870dfd | ||
|
|
5cb618c466 | ||
|
|
a87370b111 | ||
|
|
352f57cf11 | ||
|
|
1e83e666fb | ||
|
|
c837a7d0b7 | ||
|
|
63d45bc9c5 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
2
go.mod
@@ -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
194
go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
@@ -92,6 +94,7 @@ func (h *BufPane) MousePress(e *tcell.EventMouse) bool {
|
||||
|
||||
h.Cursor.StoreVisualX()
|
||||
h.lastLoc = mouseLoc
|
||||
h.Relocate()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -663,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
|
||||
}
|
||||
@@ -672,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
|
||||
@@ -687,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
|
||||
@@ -1813,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
|
||||
|
||||
@@ -30,8 +30,6 @@ func createBindingsIfNotExist(fname string) {
|
||||
|
||||
// InitBindings intializes the bindings map by reading from bindings.json
|
||||
func InitBindings() {
|
||||
config.Bindings = DefaultBindings("buffer")
|
||||
|
||||
var parsed map[string]interface{}
|
||||
|
||||
filename := filepath.Join(config.ConfigDir, "bindings.json")
|
||||
@@ -82,8 +80,11 @@ func BindKey(k, v string, bind func(e Event, a string)) {
|
||||
event, err := findEvent(k)
|
||||
if err != nil {
|
||||
screen.TermMessage(err)
|
||||
return
|
||||
}
|
||||
|
||||
config.Bindings[event.Name()] = v
|
||||
|
||||
bind(event, v)
|
||||
|
||||
// switch e := event.(type) {
|
||||
|
||||
@@ -484,9 +484,7 @@ func (h *BufPane) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool {
|
||||
binds := h.Bindings()
|
||||
action, _ := binds.NextEvent(e, te)
|
||||
if action != nil {
|
||||
if action(h) {
|
||||
h.Relocate()
|
||||
}
|
||||
action(h)
|
||||
binds.ResetEvents()
|
||||
return true
|
||||
}
|
||||
@@ -690,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
|
||||
|
||||
@@ -641,7 +641,12 @@ func (h *BufPane) ShowKeyCmd(args []string) {
|
||||
return
|
||||
}
|
||||
|
||||
if action, ok := config.Bindings[args[0]]; ok {
|
||||
event, err := findEvent(args[0])
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
return
|
||||
}
|
||||
if action, ok := config.Bindings[event.Name()]; ok {
|
||||
InfoBar.Message(action)
|
||||
} else {
|
||||
InfoBar.Message(args[0], " has no binding")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -141,13 +141,14 @@ func (k *KeyTree) RegisterMouseBinding(e Event, a PaneMouseAction) {
|
||||
|
||||
func (k *KeyTree) registerBinding(e Event, a TreeAction) {
|
||||
switch ev := e.(type) {
|
||||
case KeyEvent, MouseEvent:
|
||||
case KeyEvent, MouseEvent, RawEvent:
|
||||
newNode, ok := k.root.children[e]
|
||||
if !ok {
|
||||
newNode = NewKeyTreeNode()
|
||||
k.root.children[e] = newNode
|
||||
}
|
||||
newNode.actions = append(newNode.actions, a)
|
||||
// newNode.actions = append(newNode.actions, a)
|
||||
newNode.actions = []TreeAction{a}
|
||||
case KeySequenceEvent:
|
||||
n := k.root
|
||||
for _, key := range ev.keys {
|
||||
@@ -159,7 +160,8 @@ func (k *KeyTree) registerBinding(e Event, a TreeAction) {
|
||||
|
||||
n = newNode
|
||||
}
|
||||
n.actions = append(n.actions, a)
|
||||
// n.actions = append(n.actions, a)
|
||||
n.actions = []TreeAction{a}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,3 +5,7 @@ const (
|
||||
)
|
||||
|
||||
var Bindings map[string]string
|
||||
|
||||
func init() {
|
||||
Bindings = make(map[string]string)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -272,6 +272,7 @@ var defaultCommonSettings = map[string]interface{}{
|
||||
"ignorecase": false,
|
||||
"indentchar": " ",
|
||||
"keepautoindent": false,
|
||||
"lsp": true,
|
||||
"matchbrace": true,
|
||||
"mkparents": false,
|
||||
"permbackup": false,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
94
internal/lsp/install.go
Normal 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
20
internal/lsp/languages.go
Normal 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
|
||||
}
|
||||
58
internal/lsp/notifications.go
Normal file
58
internal/lsp/notifications.go
Normal 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
198
internal/lsp/requests.go
Normal 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
322
internal/lsp/server.go
Normal 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)
|
||||
}
|
||||
67
internal/lsp/servers_yaml.go
Normal file
67
internal/lsp/servers_yaml.go
Normal 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
|
||||
`)
|
||||
@@ -37,6 +37,12 @@ type CallbackFile struct {
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
// Job stores the executing command for the job, and the stdin pipe
|
||||
type Job struct {
|
||||
*exec.Cmd
|
||||
Stdin io.WriteCloser
|
||||
}
|
||||
|
||||
func (f *CallbackFile) Write(data []byte) (int, error) {
|
||||
// This is either stderr or stdout
|
||||
// In either case we create a new job function callback and put it in the jobs channel
|
||||
@@ -47,13 +53,13 @@ func (f *CallbackFile) Write(data []byte) (int, error) {
|
||||
|
||||
// JobStart starts a shell command in the background with the given callbacks
|
||||
// It returns an *exec.Cmd as the job id
|
||||
func JobStart(cmd string, onStdout, onStderr, onExit func(string, []interface{}), userargs ...interface{}) *exec.Cmd {
|
||||
func JobStart(cmd string, onStdout, onStderr, onExit func(string, []interface{}), userargs ...interface{}) *Job {
|
||||
return JobSpawn("sh", []string{"-c", cmd}, onStdout, onStderr, onExit, userargs...)
|
||||
}
|
||||
|
||||
// JobSpawn starts a process with args in the background with the given callbacks
|
||||
// It returns an *exec.Cmd as the job id
|
||||
func JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onExit func(string, []interface{}), userargs ...interface{}) *exec.Cmd {
|
||||
func JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onExit func(string, []interface{}), userargs ...interface{}) *Job {
|
||||
// Set up everything correctly if the functions have been provided
|
||||
proc := exec.Command(cmdName, cmdArgs...)
|
||||
var outbuf bytes.Buffer
|
||||
@@ -67,6 +73,7 @@ func JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onExit func(
|
||||
} else {
|
||||
proc.Stderr = &outbuf
|
||||
}
|
||||
stdin, _ := proc.StdinPipe()
|
||||
|
||||
go func() {
|
||||
// Run the process in the background and create the onExit callback
|
||||
@@ -75,20 +82,15 @@ func JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onExit func(
|
||||
Jobs <- jobFunc
|
||||
}()
|
||||
|
||||
return proc
|
||||
return &Job{proc, stdin}
|
||||
}
|
||||
|
||||
// JobStop kills a job
|
||||
func JobStop(cmd *exec.Cmd) {
|
||||
cmd.Process.Kill()
|
||||
func JobStop(j *Job) {
|
||||
j.Process.Kill()
|
||||
}
|
||||
|
||||
// JobSend sends the given data into the job's stdin stream
|
||||
func JobSend(cmd *exec.Cmd, data string) {
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stdin.Write([]byte(data))
|
||||
func JobSend(j *Job, data string) {
|
||||
j.Stdin.Write([]byte(data))
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -394,6 +394,84 @@ Any option you set in the editor will be saved to the file
|
||||
created for you. If you'd like to take your configuration with you to another
|
||||
machine, simply copy the settings.json to the other machine.
|
||||
|
||||
## Settings.json file
|
||||
|
||||
The settings.json file should go in your configuration directory (by default
|
||||
at `~/.config/micro`), and should contain only options which have been modified
|
||||
from their default setting. Here is the full list of options in json format,
|
||||
so that you can see what the formatting should look like.
|
||||
|
||||
```json
|
||||
{
|
||||
"autoclose": true,
|
||||
"autoindent": true,
|
||||
"autosave": 0,
|
||||
"autosu": false,
|
||||
"backup": true,
|
||||
"backupdir": "",
|
||||
"basename": false,
|
||||
"clipboard": "external",
|
||||
"colorcolumn": 0,
|
||||
"colorscheme": "default",
|
||||
"comment": true,
|
||||
"cursorline": true,
|
||||
"diff": true,
|
||||
"diffgutter": false,
|
||||
"divchars": "|-",
|
||||
"divreverse": true,
|
||||
"encoding": "utf-8",
|
||||
"eofnewline": true,
|
||||
"fastdirty": false,
|
||||
"fileformat": "unix",
|
||||
"filetype": "unknown",
|
||||
"ftoptions": true,
|
||||
"ignorecase": false,
|
||||
"indentchar": " ",
|
||||
"infobar": true,
|
||||
"initlua": true,
|
||||
"keepautoindent": false,
|
||||
"keymenu": false,
|
||||
"linter": true,
|
||||
"literate": true,
|
||||
"matchbrace": true,
|
||||
"mkparents": false,
|
||||
"mouse": true,
|
||||
"parsecursor": false,
|
||||
"paste": false,
|
||||
"permbackup": false,
|
||||
"pluginchannels": [
|
||||
"https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"
|
||||
],
|
||||
"pluginrepos": [],
|
||||
"readonly": false,
|
||||
"relativeruler": false,
|
||||
"rmtrailingws": false,
|
||||
"ruler": true,
|
||||
"savecursor": false,
|
||||
"savehistory": true,
|
||||
"saveundo": false,
|
||||
"scrollbar": false,
|
||||
"scrollmargin": 3,
|
||||
"scrollspeed": 2,
|
||||
"smartpaste": true,
|
||||
"softwrap": false,
|
||||
"splitbottom": true,
|
||||
"splitright": true,
|
||||
"status": true,
|
||||
"statusformatl": "$(filename) $(modified)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)",
|
||||
"statusformatr": "$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help",
|
||||
"statusline": true,
|
||||
"sucmd": "sudo",
|
||||
"syntax": true,
|
||||
"tabmovement": false,
|
||||
"tabsize": 4,
|
||||
"tabstospaces": false,
|
||||
"test": true,
|
||||
"useprimary": true,
|
||||
"xterm": false
|
||||
}
|
||||
```
|
||||
|
||||
## Global and local settings
|
||||
|
||||
You can set these settings either globally or locally. Locally means that the
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -7,15 +7,19 @@ rules:
|
||||
# function definition
|
||||
- identifier: "fn [a-z0-9_]+"
|
||||
# Reserved words
|
||||
- statement: "\\b(abstract|alignof|as|become|box|break|const|continue|crate|do|else|enum|extern|false|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|offsetof|override|priv|pub|pure|ref|return|sizeof|static|self|struct|super|true|trait|type|typeof|unsafe|unsized|use|virtual|where|while|yield)\\b"
|
||||
- statement: "\\b(abstract|alignof|as|become|box|break|const|continue|crate|do|dyn|else|enum|extern|false|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|offsetof|override|priv|pub|pure|ref|return|sizeof|static|self|struct|super|true|trait|type|typeof|unsafe|unsized|use|virtual|where|while|yield)\\b"
|
||||
# macros
|
||||
- special: "[a-z_]+!"
|
||||
# Constants
|
||||
- constant: "[A-Z][A-Z_]+"
|
||||
- constant: "\\b[A-Z][A-Z_0-9]+\\b"
|
||||
# Numbers
|
||||
- constant.number: "\\b[0-9]+\\b"
|
||||
# Booleans
|
||||
- constant: "\\b(true|false)\\b"
|
||||
# Traits/Enums/Structs/Types/etc.
|
||||
- type: "[A-Z][a-z]+"
|
||||
- type: "\\b[A-Z]+[a-zA-Z_0-9]*[a-z]+[a-zA-Z_0-9]*\\b"
|
||||
# Builtin types that start with lowercase.
|
||||
- type: "\\b(bool|str|isize|usize|((i|u)(8|16|32|64))|f32|f64)\\b"
|
||||
|
||||
- constant.string:
|
||||
start: "\""
|
||||
|
||||
Reference in New Issue
Block a user