Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
674 changes: 0 additions & 674 deletions LICENSE

This file was deleted.

2 changes: 0 additions & 2 deletions README.md

This file was deleted.

52 changes: 52 additions & 0 deletions server/DocumentStore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package server

import (
"sync"

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


type DocumentStore struct {
documents sync.Map
}

func NewDocumentStore() *DocumentStore {
return &DocumentStore{
documents: sync.Map{},
}
}

func (s *DocumentStore) didOpen(params *lsp.DidOpenTextDocumentParams) (*HareSourceDocument, error) {
uri := params.TextDocument.URI
path := uri.Filename()
doc := NewHareSourceDocument(uri, []byte(params.TextDocument.Text), true)

s.documents.Store(path, doc)

return doc, nil
}

func (s *DocumentStore) didClose(params *lsp.DidCloseTextDocumentParams) error {
uri := params.TextDocument.URI
path := uri.Filename()

s.documents.Delete(path)

return nil
}

func (s *DocumentStore) CloseAll() {
s.documents.Clear()
}

func (s *DocumentStore) GetSyncDocument(uri uri.URI) (DocumentInterface, bool) {
path := uri.Filename()
d, ok := s.documents.Load(path)
if !ok {
return nil, false
}
doc, ok := d.(DocumentInterface)
return doc, ok
}
61 changes: 61 additions & 0 deletions server/document.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package server

import (
"bytes"
"strings"

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

type Document struct {
URI lsp.DocumentURI
Path string
Content []byte
lines []string
IsOpen bool
}

type TextDocument interface {
ApplyChanges([]lsp.TextDocumentContentChangeEvent)
}

func NewDocument(fileURI uri.URI, content []byte, isOpen bool) *Document {
return &Document{
URI: fileURI,
Path: fileURI.Filename(),
Content: content,
IsOpen: isOpen,
}
}

func PositionToIndex(pos lsp.Position, content []byte) int {
index := 0
for i := 0; i < int(pos.Line); i++ {
if i < int(pos.Line) {
index = index + strings.Index(string(content[index:]), "\n") + 1
}
}

index = index + int(pos.Character)
return index
}

// ApplyChanges updates the content of the document from LSP textDocument/didChange events.
func (d *Document) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) {

content := d.Content

for _, change := range changes {
start, end := PositionToIndex(change.Range.Start, content), PositionToIndex(change.Range.End, content)

var buf bytes.Buffer
buf.Write(content[:start])
buf.Write([]byte(change.Text))
buf.Write(content[end:])
content = buf.Bytes()
}

d.Content = content
d.lines = nil
}
18 changes: 18 additions & 0 deletions server/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module harels/server/m

go 1.26.1

require (
go.lsp.dev/jsonrpc2 v0.10.0
go.lsp.dev/protocol v0.12.0
go.lsp.dev/uri v0.3.0
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.1
)

require (
github.com/segmentio/asm v1.1.3 // indirect
github.com/segmentio/encoding v0.3.4 // indirect
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
)
35 changes: 35 additions & 0 deletions server/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc=
github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
github.com/segmentio/encoding v0.3.4 h1:WM4IBnxH8B9TakiM2QD5LyNl9JSndh88QbHqVC+Pauc=
github.com/segmentio/encoding v0.3.4/go.mod h1:n0JeuIqEQrQoPDGsjo8UNd1iA0U8d8+oHAA4E3G3OxM=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
go.lsp.dev/jsonrpc2 v0.10.0 h1:Pr/YcXJoEOTMc/b6OTmcR1DPJ3mSWl/SWiU1Cct6VmI=
go.lsp.dev/jsonrpc2 v0.10.0/go.mod h1:fmEzIdXPi/rf6d4uFcayi8HpFP1nBF99ERP1htC72Ac=
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 h1:hCzQgh6UcwbKgNSRurYWSqh8MufqRRPODRBblutn4TE=
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2/go.mod h1:gtSHRuYfbCT0qnbLnovpie/WEmqyJ7T4n6VXiFMBtcw=
go.lsp.dev/protocol v0.12.0 h1:tNprUI9klQW5FAFVM4Sa+AbPFuVQByWhP1ttNUAjIWg=
go.lsp.dev/protocol v0.12.0/go.mod h1:Qb11/HgZQ72qQbeyPfJbu3hZBH23s1sr4st8czGeDMQ=
go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo=
go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
57 changes: 57 additions & 0 deletions server/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package server

import (
"context"
"os"

lsp "go.lsp.dev/protocol"
"go.uber.org/zap"
)

type ServerHandler struct {
lsp.Server
log *zap.Logger
storedDocuments *DocumentStore
}


func newHandler(ctx context.Context, server lsp.Server, logger *zap.Logger) (*ServerHandler, context.Context, error) {
storedDocuments := NewDocumentStore()
handler := &ServerHandler{
Server: server,
log: logger,
storedDocuments: storedDocuments,
}

_, err := os.Getwd()
if err != nil {
handler.log.Error("Error getting current directory")
}

return handler, ctx, nil
}

func (h ServerHandler) Initialize(ctx context.Context, params *lsp.InitializeParams) (*lsp.InitializeResult, error) {
return &lsp.InitializeResult{
Capabilities: lsp.ServerCapabilities{
TextDocumentSync: lsp.TextDocumentSyncOptions {
Change: lsp.TextDocumentSyncKindIncremental,
OpenClose: true,
},
},
ServerInfo: &lsp.ServerInfo{
Name: "hare-ls",
Version: "0.1.0",
},
}, nil
}

func (h *ServerHandler) Exit(ctx context.Context) (err error) {
return nil
}

func (h *ServerHandler) Shutdown(ctx context.Context) (err error) {
h.storedDocuments.CloseAll()
return lsp.Server.Shutdown(h, ctx)
}

25 changes: 25 additions & 0 deletions server/hareSourceDocument.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package server

import (
lsp "go.lsp.dev/protocol"
"go.lsp.dev/uri"
)

type HareSourceDocument struct {
Document
}

func NewHareSourceDocument(fileURI uri.URI, content []byte, isOpen bool) *HareSourceDocument {
return &HareSourceDocument{
Document: *NewDocument(fileURI, content, isOpen),
}
}

// ApplyChanges updates the content of the document from LSP textDocument/didChange events.
func (d *HareSourceDocument) ApplyChanges(changes []lsp.TextDocumentContentChangeEvent) {
d.Document.ApplyChanges(changes)
}

func IsHareSourceDocumentLangID(langID lsp.LanguageIdentifier) bool {
return langID == "hare"
}
55 changes: 55 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package server

import (
"context"
"io"
"os"

"go.lsp.dev/jsonrpc2"
"go.lsp.dev/protocol"
"go.uber.org/multierr"
"go.uber.org/zap"
)



// StartServer starts the language server.
func StartServer(logger *zap.Logger) {
conn := jsonrpc2.NewConn(jsonrpc2.NewStream(&readWriteCloser{
reader: os.Stdin,
writer: os.Stdout,
}))

handler, ctx, err := newHandler(
context.Background(),
protocol.ServerDispatcher(conn, logger),
logger,
)

if err != nil {
logger.Sugar().Fatalf("while initializing handler: %w", err)
}

conn.Go(ctx, protocol.ServerHandler(
handler, jsonrpc2.MethodNotFoundHandler,
))
<-conn.Done()
}

type readWriteCloser struct {
reader io.ReadCloser
writer io.WriteCloser
}

func (r *readWriteCloser) Read(b []byte) (int, error) {
n, err := r.reader.Read(b)
return n, err
}

func (r *readWriteCloser) Write(b []byte) (int, error) {
return r.writer.Write(b)
}

func (r *readWriteCloser) Close() error {
return multierr.Append(r.reader.Close(), r.writer.Close())
}
44 changes: 44 additions & 0 deletions server/textDocument.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package harels

import (
"context"
"errors"
"fmt"

lsp "go.lsp.dev/protocol"
)

func (h *ServerHandler) didOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) {
_, err = h.storedDocuments.didOpen(params)

if err != nil {
return err
}

lsp.Server.DidOpen(ctx, params)

return nil
}

func (h *ServerHandler) didClose(ctx context.Context, params *lsp.DidCloseTextDocumentParams) (err error) {
err = h.storedDocuments.didClose(params)

if err != nil {
return err
}

lsp.Server.DidClose(ctx, params)

return nil
}

func (h *ServerHandler) didChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) {
doc, ok := h.storedDocuments.GetSyncDocument(params.TextDocument.URI)
if !ok {
return errors.New("Could not get document: " + params.TextDocument.URI.Filename())
}

doc.ApplyChanges(params.ContentChanges)

return lsp.Server.DidChange(ctx, params)
}