Skip to content
This repository has been archived by the owner on May 29, 2024. It is now read-only.

Commit

Permalink
Handle didOpen didClose didChange didDave
Browse files Browse the repository at this point in the history
  • Loading branch information
harry-hov committed Sep 22, 2023
1 parent 4914686 commit eac5918
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 0 deletions.
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ go 1.21.1

require (
github.com/google/go-github v17.0.0+incompatible
github.com/orcaman/concurrent-map/v2 v2.0.1
github.com/spf13/cobra v1.5.0
go.lsp.dev/jsonrpc2 v0.10.0
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2
go.lsp.dev/protocol v0.12.0
golang.org/x/mod v0.12.0
mvdan.cc/gofumpt v0.4.0
)

require (
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/segmentio/asm v1.1.3 // indirect
github.com/segmentio/encoding v0.3.4 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand All @@ -23,4 +28,5 @@ require (
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/tools v0.6.0 // indirect
)
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ 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/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
Expand All @@ -16,8 +20,14 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c=
github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.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/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc=
github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
Expand Down Expand Up @@ -52,8 +62,12 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
75 changes: 75 additions & 0 deletions internal/lsp/general.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package lsp

import (
"context"
"encoding/json"
"errors"
"log/slog"

"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
)

func (s *server) DidOpen(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
var params protocol.DidOpenTextDocumentParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}

uri := params.TextDocument.URI
file := &GnoFile{
URI: uri,
Src: []byte(params.TextDocument.Text),
}
s.snapshot.file.Set(uri.Filename(), file)

slog.Info("open " + string(params.TextDocument.URI.Filename()))
return reply(ctx, nil, nil)
}

func (s *server) DidClose(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
var params protocol.DidChangeTextDocumentParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}

slog.Info("close" + string(params.TextDocument.URI.Filename()))
return reply(ctx, s.conn.Notify(ctx, protocol.MethodTextDocumentDidClose, nil), nil)
}

func (s *server) DidChange(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
var params protocol.DidChangeTextDocumentParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}

uri := params.TextDocument.URI
_, ok := s.snapshot.Get(uri.Filename())
if !ok {
return reply(ctx, nil, errors.New("snapshot not found"))
}

file := &GnoFile{
URI: uri,
Src: []byte(params.ContentChanges[0].Text),
}
s.snapshot.file.Set(uri.Filename(), file)

slog.Info("change " + string(params.TextDocument.URI.Filename()))
return reply(ctx, nil, nil)
}

func (s *server) DidSave(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
var params protocol.DidSaveTextDocumentParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}

uri := params.TextDocument.URI
file, ok := s.snapshot.Get(uri.Filename())
if !ok {
return reply(ctx, nil, errors.New("snapshot not found"))
}

slog.Info("save " + string(uri.Filename()))
}
14 changes: 14 additions & 0 deletions internal/lsp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ type server struct {
conn jsonrpc2.Conn
env *env.Env

snapshot *Snapshot

formatOpt tools.FormattingOption
}

func BuildServerHandler(conn jsonrpc2.Conn, env *env.Env) jsonrpc2.Handler {
Expand All @@ -31,6 +34,9 @@ func BuildServerHandler(conn jsonrpc2.Conn, env *env.Env) jsonrpc2.Handler {

env: env,

snapshot: NewSnapshot(),

formatOpt: tools.Gofumpt,
}

return jsonrpc2.ReplyHandler(server.ServerHandler)
Expand All @@ -46,6 +52,14 @@ func (s *server) ServerHandler(ctx context.Context, reply jsonrpc2.Replier, req
return s.Initialized(ctx, reply, req)
case "shutdown":
return s.Shutdown(ctx, reply, req)
case "textDocument/didChange":
return s.DidChange(ctx, reply, req)
case "textDocument/didClose":
return s.DidClose(ctx, reply, req)
case "textDocument/didOpen":
return s.DidOpen(ctx, reply, req)
case "textDocument/didSave":
return s.DidSave(ctx, reply, req)
default:
return jsonrpc2.MethodNotFoundHandler(ctx, reply, req)
}
Expand Down
124 changes: 124 additions & 0 deletions internal/lsp/snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package lsp

import (
"context"
"errors"
"fmt"
"go/ast"
"go/parser"
"go/token"
"log/slog"
"strings"
"unicode/utf8"

"go.lsp.dev/protocol"
"golang.org/x/mod/modfile"

cmap "github.com/orcaman/concurrent-map/v2"
)

type Snapshot struct {
file cmap.ConcurrentMap[string, *GnoFile]
}

func NewSnapshot() *Snapshot {
return &Snapshot{
file: cmap.New[*GnoFile](),
}
}

func (s *Snapshot) Get(filePath string) (*GnoFile, bool) {
return s.file.Get(filePath)
}

// contains gno file.
type GnoFile struct {
URI protocol.DocumentURI
Src []byte
}

// contains parsed gno file.
type ParsedGnoFile struct {
URI protocol.DocumentURI
File *ast.File

Src []byte
}

func (f *GnoFile) ParseGno(ctx context.Context) (*ParsedGnoFile, error) {
fset := token.NewFileSet()
ast, err := parser.ParseFile(fset, f.URI.Filename(), nil, parser.ParseComments)
if err != nil {
return nil, err
}

pgf := &ParsedGnoFile{
URI: f.URI,

File: ast,
Src: f.Src,
}

return pgf, nil
}

// contains parsed gno.mod file.
type ParsedGnoMod struct {
URI string
File *modfile.File
}

func (f *GnoFile) TokenAt(pos protocol.Position) (*HoveredToken, error) {
lines := strings.SplitAfter(string(f.Src), "\n")

size := uint32(len(lines))
if pos.Line >= size {
return nil, errors.New("line out of range")
}

line := lines[pos.Line]
lineLen := uint32(len(line))

// TODO: fix it. should not happen?
if len(line) == 0 {
return nil, errors.New("no token found")
}

index := pos.Character
start := index
// TODO: fix it. should not happen?
if lineLen < start {
return nil, errors.New("start is greater than len")
}
for start > 0 && line[start-1] != ' ' {
start--
}

end := index
slog.Info(fmt.Sprintf("end: %d", end))
for end < lineLen && line[end] != ' ' {
end++
}

if start == end {
return nil, errors.New("no token found")
}

return &HoveredToken{
Text: line[start:end],
Start: int(start),
End: int(end),
}, nil
}

func (f *GnoFile) PositionToOffset(pos protocol.Position) int {
lines := strings.SplitAfter(string(f.Src), "\n")
offset := 0
for i, l := range lines {
if i == int(pos.Line) {
break
}
offset += utf8.RuneCountInString(l)
}
return offset + int(pos.Character)
}
9 changes: 9 additions & 0 deletions internal/tools/format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tools

type FormattingOption int

const (
Gofmt FormattingOption = iota
Gofumpt
)

0 comments on commit eac5918

Please sign in to comment.