Compare commits
28 commits
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 |
28 changed files with 1460 additions and 121 deletions
|
@ -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
|
||||
|
@ -664,6 +666,13 @@ func (h *BufPane) Autocomplete() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// if there is an existing completion, always cycle it
|
||||
if b.HasSuggestions {
|
||||
h.cycleAutocomplete(true)
|
||||
return true
|
||||
}
|
||||
|
||||
// don't start a new completion unless the correct conditions are met
|
||||
if h.Cursor.X == 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -673,12 +682,14 @@ func (h *BufPane) Autocomplete() bool {
|
|||
// don't autocomplete if cursor is on alpha numeric character (middle of a word)
|
||||
return false
|
||||
}
|
||||
|
||||
if b.HasSuggestions {
|
||||
b.CycleAutocomplete(true)
|
||||
return true
|
||||
ret := true
|
||||
if !b.Autocomplete(buffer.LSPComplete) {
|
||||
ret = b.Autocomplete(buffer.BufferComplete)
|
||||
}
|
||||
return b.Autocomplete(buffer.BufferComplete)
|
||||
if ret {
|
||||
h.displayCompletionDoc()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// CycleAutocompleteBack cycles back in the autocomplete suggestion list
|
||||
|
@ -688,12 +699,24 @@ func (h *BufPane) CycleAutocompleteBack() bool {
|
|||
}
|
||||
|
||||
if h.Buf.HasSuggestions {
|
||||
h.Buf.CycleAutocomplete(false)
|
||||
h.cycleAutocomplete(false)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *BufPane) cycleAutocomplete(forward bool) {
|
||||
h.Buf.CycleAutocomplete(forward)
|
||||
h.displayCompletionDoc()
|
||||
}
|
||||
|
||||
func (h *BufPane) displayCompletionDoc() {
|
||||
c := h.Buf.CurCompletion
|
||||
if c >= 0 && c < len(h.Buf.Completions) {
|
||||
InfoBar.Message(h.Buf.Completions[c].Doc)
|
||||
}
|
||||
}
|
||||
|
||||
// InsertTab inserts a tab or spaces
|
||||
func (h *BufPane) InsertTab() bool {
|
||||
b := h.Buf
|
||||
|
@ -1814,6 +1837,52 @@ func (h *BufPane) RemoveAllMultiCursors() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// SemanticInfo returns information about the identifier the cursor is on and
|
||||
// displays the information in the infobar
|
||||
// The information is fetched using the LSP server (must be enabled)
|
||||
func (h *BufPane) SemanticInfo() bool {
|
||||
info, err := h.Buf.Server.Hover(h.Buf.AbsPath, lsp.Position(h.Cursor.X, h.Cursor.Y))
|
||||
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
info = strings.Split(info, "\n")[0]
|
||||
|
||||
InfoBar.Message(info)
|
||||
return true
|
||||
}
|
||||
|
||||
// AutoFormat automatically formats the document using LSP
|
||||
func (h *BufPane) AutoFormat() bool {
|
||||
var err error
|
||||
var edits []protocol.TextEdit
|
||||
|
||||
if h.Cursor.HasSelection() {
|
||||
edits, err = h.Buf.Server.DocumentRangeFormat(h.Buf.AbsPath, protocol.Range{
|
||||
Start: lsp.Position(h.Cursor.CurSelection[0].X, h.Cursor.CurSelection[0].Y),
|
||||
End: lsp.Position(h.Cursor.CurSelection[1].X, h.Cursor.CurSelection[1].Y),
|
||||
}, protocol.FormattingOptions{
|
||||
InsertSpaces: h.Buf.Settings["tabstospaces"].(bool),
|
||||
TabSize: h.Buf.Settings["tabsize"].(float64),
|
||||
})
|
||||
} else {
|
||||
edits, err = h.Buf.Server.DocumentFormat(h.Buf.AbsPath, protocol.FormattingOptions{
|
||||
InsertSpaces: h.Buf.Settings["tabstospaces"].(bool),
|
||||
TabSize: h.Buf.Settings["tabsize"].(float64),
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
InfoBar.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
h.Buf.ApplyEdits(edits)
|
||||
return true
|
||||
}
|
||||
|
||||
// None is an action that does nothing
|
||||
func (h *BufPane) None() bool {
|
||||
return true
|
||||
|
|
|
@ -688,6 +688,8 @@ var BufKeyActions = map[string]BufKeyAction{
|
|||
"JumpLine": (*BufPane).JumpLine,
|
||||
"Deselect": (*BufPane).Deselect,
|
||||
"ClearInfo": (*BufPane).ClearInfo,
|
||||
"SemanticInfo": (*BufPane).SemanticInfo,
|
||||
"AutoFormat": (*BufPane).AutoFormat,
|
||||
"None": (*BufPane).None,
|
||||
|
||||
// This was changed to InsertNewline but I don't want to break backwards compatibility
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1265,7 +1265,7 @@ func runtimePluginsStatusHelpStatusMd() (*asset, error) {
|
|||
return a, nil
|
||||
}
|
||||
|
||||
var _runtimePluginsStatusStatusLua = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x94\xc1\x6b\xdb\x30\x14\xc6\xef\xfe\x2b\x84\x4e\x32\x24\x6a\x77\xd8\x65\x90\x43\xda\xa5\x69\xd9\x68\x47\x1c\xca\xae\xb2\xfd\x1c\x3f\x90\x25\x23\xc9\x61\xed\x61\x7f\xfb\x90\x64\xb7\x76\x42\xc0\x1b\xa3\xb9\xe9\xbd\xdf\xfb\xf2\xf9\xb3\x9e\x9f\x37\xbb\xec\xe1\xe9\x91\xac\x08\xfd\xc4\xaf\xf9\x35\x4d\x12\xa9\x0b\x21\x49\x83\x85\xd1\x64\x45\xb0\x69\xb5\x71\x8c\x86\x33\x4d\xfb\x6e\xde\x55\x15\x98\xd3\xf6\x55\x2c\xbf\x51\x85\x56\x15\x1e\xce\xa8\x58\x7e\xa3\xea\xae\x11\x0a\x5f\x61\xc4\x0d\x25\x9a\x26\x49\xd5\xa9\xc2\xa1\x56\x04\x15\x3a\x96\x26\x84\x90\x68\x8e\x67\xe0\x32\x27\x5c\x67\x1f\x54\xa5\xef\x14\xa3\x36\x9c\x78\x6e\x84\x2a\x6a\x3a\x07\xad\x85\x9d\x07\xb6\xc2\x3a\x98\x45\x1e\x0b\x2d\x67\x81\x12\x15\xd8\x59\x64\xfe\xe2\x66\x92\x36\x86\xe6\xc1\x98\x32\x5f\x97\xe5\xae\x53\x0e\x1b\xb8\x43\x09\x03\x48\x17\x43\x7f\xb7\xbf\x07\xd9\x2e\x08\xad\x41\xb6\x57\xbd\x4c\x53\xd2\x34\x01\x55\x8e\xd2\x0f\x6e\x59\x1e\xb5\x0d\xb8\xce\x28\xe2\xb4\x75\x06\xd5\x81\xe5\x5f\xbe\xfb\xf6\x63\xd7\xb0\xf4\x74\xd0\xe7\x71\x79\x6e\x0b\x6e\x5d\x38\x3c\xc2\x6d\x67\xac\x36\x2c\xf5\x95\x67\xb4\x9d\x90\x3f\xcf\xb5\x42\x10\x97\xc5\x32\x7c\x85\xf3\x21\x9f\xc9\xc9\xcc\x70\xbf\xf8\x4d\x14\xbc\x30\x19\x2f\xd2\x30\x8b\x15\xc9\xf9\xfe\xa5\x05\xfe\x0d\x55\x49\x7e\xaf\xfa\x2d\xe0\x37\x7b\xff\x16\x88\xab\x41\x05\xd0\xff\xe2\xd5\xb6\x35\x48\x79\x76\xff\x43\xb5\x7f\x4b\x23\x36\x3c\x85\x1d\xd1\x7d\xc5\x2f\xc1\x14\x8d\xbe\x16\x04\x8c\x5f\xc1\x20\xc7\x37\xbf\xa0\xb8\xd5\x4d\x23\x54\xc9\xe8\x01\x1d\x5d\x10\x6a\xe0\xb8\x6c\x85\xb1\xe0\x0f\xcb\xa5\xc8\x73\x5f\x31\x50\xf9\xf3\xfd\x66\xfd\x75\x64\x02\xab\x28\xb7\x22\x0a\xe5\xf4\x59\x46\xc1\xf5\x96\xf8\xde\x60\x93\xb5\xa2\x00\x16\xbd\xbc\xeb\xf8\x04\x4f\x86\x28\x4d\x86\xce\x34\x5f\xbf\x7d\x97\xd3\xfd\xfc\x81\x89\x7a\x27\x7f\x9d\xa7\xad\xb5\x71\xff\x31\x4a\x6f\xe2\xdf\x82\x0c\x5f\xa7\x51\x92\xfd\x6e\x6f\xc1\x6d\xa5\xce\x85\x7c\x6a\x3d\xc6\x68\xff\x15\x9b\x7a\x1a\xc4\x7f\xac\xb3\xfd\x86\xbc\xff\xc5\xf4\x8f\x7d\xe5\x4f\x00\x00\x00\xff\xff\xdc\xdb\xdf\x2a\x2d\x06\x00\x00"
|
||||
var _runtimePluginsStatusStatusLua = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x95\x4f\x6b\xdc\x3c\x10\xc6\xef\xfb\x29\x84\x4e\x36\x6c\x94\xbc\x87\xf7\x12\xd8\xc3\x26\xdd\x6c\x42\x43\x12\xe2\x25\x14\x4a\x0e\xb2\x3d\x5e\x0f\x91\x25\x21\xc9\xa1\xc9\xa1\x9f\xbd\x48\xb2\x77\xbd\xff\xc0\x2d\xa5\x37\x6b\xf4\xcc\xe3\x99\x9f\x3c\xf2\xcb\xe2\x39\xbb\x7b\x7c\x20\x33\x42\xff\x63\x17\xec\x82\x4e\x26\x42\x15\x5c\x90\x06\x0b\xa3\xc8\x8c\x60\xa3\x95\x71\x09\x0d\x6b\x9a\x76\xbb\x79\x5b\x55\x60\xf6\xb7\xcf\x63\x78\xa3\x2a\x94\xac\x70\x7d\xa0\x8a\xe1\x8d\xaa\x6e\x1b\x2e\xf1\x13\x06\xba\x3e\x44\xd3\xc9\xa4\x6a\x65\xe1\x50\x49\x82\x12\x5d\x92\x4e\x08\x21\xb1\x38\x96\x81\xcb\x1c\x77\xad\xbd\x93\x95\xba\x91\x09\xb5\x61\xc5\x72\xc3\x65\x51\xd3\x31\xd2\x9a\xdb\x71\x42\xcd\xad\x83\x51\xca\xf7\x42\x89\x51\x42\x81\x12\xec\x28\x65\xfe\xe1\x46\x2a\x6d\x84\x36\xe2\xe5\x56\x77\xba\x78\x1a\x6c\x5e\x96\xcf\xad\x74\xd8\xc0\x0d\x0a\xe8\x75\x74\xda\xef\x3f\xaf\x6e\x41\xe8\x29\xa1\x35\x08\x7d\xde\xb9\x34\x25\x4d\x27\x20\xcb\xc1\x29\x85\xae\x92\x3c\x7a\x1b\x70\xad\x91\xc4\x29\xeb\x0c\xca\x75\x92\x5f\xde\xfb\xed\x87\xb6\x49\xd2\xfd\x44\xcf\xed\x74\xde\x12\xdc\xbc\x70\xf8\x0e\xd7\xad\xb1\xca\x24\xa9\x8f\xbc\xa0\x6d\xb9\xf8\x76\xe8\x15\x80\x9d\x36\xcb\xf0\x13\x0e\x93\x3c\xbb\xbd\x9c\xfe\x3b\x64\x57\xd1\xf0\x44\xa6\xb0\xba\x4f\xc4\x8a\x48\xe5\x48\xee\xc1\x3b\x94\x6b\xfb\x9d\x7a\xd4\xaf\xc4\xd5\x20\x83\x62\x60\x4f\x4b\xb4\x3c\x17\x50\xd2\xb0\xe3\x4d\x3b\x8f\xfc\xf2\x96\xdb\xfb\xec\x29\x49\x8f\x27\x2a\xb9\x4d\x09\x0f\x71\x94\x84\xd5\x07\xd3\xb6\x3d\xe9\x4e\x33\x25\xea\x8d\xcc\xbc\x96\x2d\xc1\xdd\x73\xb9\x6e\xf9\x1a\x92\x61\xc9\x15\x0a\x70\x1f\x1a\xe8\xeb\x4e\x57\xea\xed\x78\x35\xad\xb4\xad\xf6\xef\x3c\xd2\x89\xcf\x13\x97\x77\xd2\x3a\x2e\x04\x94\x27\x1a\x12\xec\x5a\x35\x0d\x97\x25\x61\x8c\xd0\x90\x84\x7d\xca\xae\xe5\x86\x40\x55\xd1\xfd\x53\x0f\x73\x3f\x38\x89\x9c\xad\x3e\x34\xb0\xaf\x28\x4b\xf2\x73\xd6\x5d\x5a\xec\x6a\xe5\x67\x61\xb7\x8c\x88\xc6\xd6\x20\xc4\x01\xc0\x10\xed\x10\x0e\xb4\xe1\x63\xb2\x03\x75\x17\xf1\x77\xd6\xae\x34\xd6\x35\x25\x60\xfc\x8d\x19\xec\xd8\xe2\x07\x14\x5d\xcb\x09\x5d\xa3\xa3\x53\x42\x0d\xbc\x9f\x69\x6e\x2c\xf8\xc5\xd9\x19\xcf\x73\x1f\x31\x50\xf9\xf5\xed\x62\xfe\x65\x50\x04\x56\xd1\x6e\x46\x24\x8a\xdd\x5e\x06\x94\xba\x92\xd8\xca\x60\x93\x69\x5e\x40\x12\x6b\xd9\xfa\xf4\x58\x87\x68\xb7\xc0\x77\xf9\xfa\xcb\xf2\x34\xdd\xff\xff\x21\x51\x5f\xc9\x6f\xf3\xb4\xb5\x32\xee\x2f\xa2\xf4\x45\xfc\x19\xc8\xf0\x33\x19\x90\xec\xae\xd8\x25\xb8\xa5\x50\x39\x17\x8f\xda\xcb\x12\xda\xfd\x74\x8e\x0f\xdd\xd3\x3c\x5b\x2d\xc8\xf1\xe1\x88\x93\xf1\x2b\x00\x00\xff\xff\xa5\x47\xb2\xb8\xdc\x07\x00\x00"
|
||||
|
||||
func runtimePluginsStatusStatusLuaBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
|
@ -5525,7 +5525,7 @@ func runtimeSyntaxRustHdr() (*asset, error) {
|
|||
return a, nil
|
||||
}
|
||||
|
||||
var _runtimeSyntaxRustYaml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x52\x4f\x4f\x1b\x3f\x10\xbd\xe7\x53\x98\x0d\x07\x20\x4a\x96\x2b\x7b\xf9\xe9\x27\x4a\xa5\x1e\x5a\xa4\x96\x43\xd4\xec\x0a\x79\xbd\x63\x62\xe1\x3f\xab\xf1\x38\x40\x34\x1f\xbe\xf2\x26\x21\x90\x20\x51\xa9\x39\x38\xde\xf9\xf7\xde\x3c\x3f\x6d\x2c\xd0\x4b\x0f\x95\xc0\x14\x69\x34\xea\x80\x40\x51\x35\x12\x42\x88\x9c\xf3\xd2\x41\x25\x8a\xba\x9e\x61\x3c\x2d\x46\x23\x4c\x16\xe2\x26\x3d\x16\x3a\x79\x45\x26\x78\xd1\x81\x36\xde\xe4\xeb\x90\x99\x0a\xd3\x81\x27\xa3\x0d\x60\x25\x0a\xed\xc5\x42\x4e\xd7\x97\xd3\xab\xfb\x66\x52\x0c\x15\xb9\xfb\x27\x44\xc0\x15\x74\xe2\x29\x60\x17\xb7\x8d\x91\x24\x81\x03\x4f\x03\x68\x7b\x26\xdb\x48\x28\x15\xb1\xb4\xe6\xc1\x07\xcd\x32\x72\x0b\x2a\x38\xe0\x36\x3c\x73\x8b\x20\x1f\x59\x05\x1f\x29\x9f\x64\x7c\x02\x56\x28\x09\xb8\x0b\x0c\x36\x02\x83\x4f\x8e\xe1\x99\x00\x3d\x6b\x99\x23\xda\x78\x69\x59\x7b\xd6\x01\xd9\x68\x36\xae\xb7\x6c\x3c\x5b\x20\xb6\x21\xf4\xec\xa4\xc2\xc0\x4e\x92\x5a\xb2\x0b\x1d\xbb\xb0\x02\x76\x89\x38\x68\x1d\x81\x82\xe6\xb0\x02\x44\xd3\x01\xf7\x68\x56\xdc\xa7\x96\xfb\x84\xc0\x08\x9a\x11\x28\xa1\xe7\x68\xd6\x10\x34\xe7\x7d\x8c\xe2\x08\x36\xdf\x31\x29\xe2\x98\x7a\x40\x26\x4c\xc0\x84\xd2\x10\x67\xfd\x87\x23\x68\x4e\x3e\x4a\x0d\xf9\xcf\xac\xa1\xe3\x14\x81\x57\x06\x29\x49\xcb\x4f\x4b\x40\xe0\xa7\xa5\xb1\xc0\x2f\x06\x6c\x77\x5e\xd7\xed\x5e\xce\x81\xf4\xab\x8c\x3d\x28\x23\x6d\x25\x8a\xac\xfc\x7d\x33\x39\xd9\x17\x5e\x67\xb5\xa4\xa7\x5d\xad\xda\x7e\xe7\xe2\xff\xa7\xbf\x9b\x7c\xbc\x7b\xa8\x1f\xc9\xb5\x80\x87\xe5\x33\x3f\x84\x37\xef\xb4\xb8\x9c\x5e\x35\x93\x77\x7c\xee\xf2\x6e\xb1\xbc\xf1\xc9\xc5\xf2\xd7\xb0\x7a\x2c\xef\x5e\x7a\x88\x25\x90\x9a\x6d\xa7\x6d\xbc\xb7\x05\x96\xd3\x75\xc6\x3d\x04\x8a\x84\xc6\x3f\x54\xdb\xc9\x22\x7b\x04\x07\x7f\x14\xc5\x6b\x0c\x7c\x77\x10\x89\x8f\xa6\x1f\xc8\xd5\xf5\x6c\x1f\x7d\xe3\xdf\xdd\xef\x2d\xd2\x46\xb6\xeb\xa5\xc4\x7d\xeb\xdf\xd2\xc1\xf1\xe4\x23\x46\xe3\xc9\x21\xba\x58\x34\xfb\xa1\x6e\x30\xfb\xd1\xb0\xb2\x3c\x9c\x74\xfa\xc9\x12\x14\xba\x50\x89\xe2\xec\xee\xf6\xcb\x2d\xcf\xe7\x73\xfe\xfa\x6d\xfe\xfd\xe6\xbc\xfa\xaf\xf8\x1c\xac\xae\x2f\x8e\x88\xd7\x17\xe5\x3f\x23\xee\x6c\x78\x84\x38\x3e\xa9\xeb\xc5\x31\x64\xf3\xa1\x54\x7f\x02\x00\x00\xff\xff\x3f\xf7\x58\xfe\xa4\x04\x00\x00"
|
||||
var _runtimeSyntaxRustYaml = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x53\x41\x6f\xf3\x36\x0c\xbd\xe7\x57\xe8\x73\xbe\x43\xd2\x20\x49\xd7\x16\xc5\xea\xcb\xb0\x75\x1d\xb0\xc3\x56\x60\xeb\x21\x58\x1c\x14\xb2\x4d\x35\x44\x65\xc9\xa0\xa8\xa4\x29\xf8\xe3\x07\x39\x49\xd3\x26\x05\x3a\x60\x3e\xd0\x12\x25\xf2\x3d\x3e\x8a\x06\x2d\xf0\xa6\x85\x5c\x51\x0c\xdc\xeb\xd5\xc0\x50\x71\xde\x53\x4a\xa9\x74\xe6\x74\x03\xb9\xca\x8a\x62\x42\xe1\x7b\xd6\xeb\x51\xb4\x10\xb6\xc7\x7d\x65\xa2\xab\x18\xbd\x53\x35\x18\x74\x98\x96\xdd\xc9\x58\x61\x0d\x8e\xd1\x20\x50\xae\x32\xe3\xd4\x5c\x8f\x5f\xcf\xc7\x37\x8f\x8b\x51\xd6\xdd\x48\xd1\x7f\x41\x00\x5a\x41\xad\xd6\x9e\xea\xb0\x0b\x0c\xac\x19\x1a\x70\xdc\x81\x96\x03\x5d\x06\x26\x5d\xb1\x68\x8b\x4f\xce\x1b\xd1\x41\x4a\xa8\x7c\x03\x52\xfa\x17\x29\x09\xf4\xb3\x54\xde\x05\x4e\x96\xd1\x45\x90\x8a\x34\x83\xd4\x5e\xea\x8d\x13\xb0\x01\x04\x5c\x6c\x04\x5e\x18\xc8\x89\xd1\xc9\x63\xd0\x69\x2b\xc6\x89\xf1\x24\x68\x04\x9b\xd6\x0a\x3a\xb1\xc0\x62\xbd\x6f\xa5\xd1\x15\x79\x69\x34\x57\x4b\x69\x7c\x2d\x8d\x5f\x81\x34\x91\xc5\x1b\x13\x80\xbd\x11\xbf\x02\x22\xac\x41\x5a\xc2\x95\xb4\xb1\x94\x36\x12\x08\x81\x11\x02\x8e\xe4\x24\xe0\x2b\x78\x23\xa9\x26\xac\x24\x80\x4d\x6b\x8a\x15\x4b\x88\x2d\x90\x30\x45\x10\x26\x8d\x2c\xa9\x07\x9d\xf1\x46\xa2\x0b\xda\x40\xfa\xe1\x2b\xd4\x12\x03\xc8\x0a\x89\xa3\xb6\xb2\x5e\x02\x81\xac\x97\x68\x41\x36\x08\xb6\x1e\x16\x45\x79\x90\xb4\x23\xfd\x26\x65\x0b\x15\x6a\x9b\xab\x2c\xa9\xff\xb8\x18\x7d\x3b\x5c\xbc\x4d\x8a\x69\xc7\xfb\xbb\xd5\x6e\xbf\x55\x7d\xfe\xf3\xf8\x9f\x45\x32\x8f\xe7\xe3\x9b\xc5\xe8\x03\xc4\x9f\xb1\x29\x81\x8e\xe3\x26\xae\x73\xef\xc2\x4f\xa3\x7e\xf1\xde\x82\x76\x9f\xc3\x0d\x3a\x1d\xba\xbe\x7c\x2c\xe7\x21\x49\x13\xa6\x77\x2e\x36\x61\xfa\x77\xa7\x5c\x98\x3e\x6c\x5a\x08\x53\xe0\x6a\xb2\x4b\xb6\x7d\xbe\x6f\xbc\x47\xa9\xda\x3d\xf7\xb3\xb4\x39\x72\x7d\x24\x16\xd1\x32\xba\x2e\x49\x50\xbc\xd4\x9c\x9e\x20\xb1\x5a\x23\x2f\x95\xf5\x6b\xa0\x4a\x07\x38\xc5\x1a\x94\xde\xdb\xd4\x4e\xc1\xd4\x26\x89\x9d\x1d\x0c\x50\xe2\x70\xf0\xa3\xfc\x70\x2d\x97\x17\x72\x7d\x35\x1c\x8a\xb9\xbc\x10\x73\x7d\xb5\x2d\xed\x58\xb7\xc0\x84\xee\x29\xdf\xf1\x51\x5b\xf0\x84\x90\x65\x6f\x3e\x70\xf5\x91\x27\x3c\x63\xdb\xd1\x28\x8a\xc9\xc1\xfb\x6e\x36\xf7\xdf\x7b\xa4\xed\x73\xb8\x5d\x6a\x3a\x84\xfe\x57\x3a\xd4\x1f\x7d\xc6\xa8\x3f\x3a\x46\x57\xf3\xc5\x21\x69\xd3\x0d\xf2\x49\xb2\xe9\xf4\x38\xd3\xf7\x2f\x8a\x60\x5f\xfb\x5c\x65\x83\x87\xfb\x5f\xef\x65\x36\x9b\xc9\x6f\xbf\xcf\xfe\xb8\x1b\xe6\x3f\x65\x5f\x83\x15\xc5\xd9\x09\xf1\xe2\x6c\xfa\xbf\x11\xf7\xe3\x75\x82\xd8\xff\x56\x14\xf3\x53\xc8\xc5\xa7\x52\xfd\x1b\x00\x00\xff\xff\x73\x64\x84\x65\x80\x05\x00\x00"
|
||||
|
||||
func runtimeSyntaxRustYamlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
|
|
|
@ -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
|
||||
`)
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in a new issue