Skip to content

Commit 1c65a91

Browse files
committed
Working base
1 parent e66271c commit 1c65a91

8 files changed

Lines changed: 135 additions & 62 deletions

File tree

cmd/lspdev/main.go

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ import (
55
"encoding/json"
66
"fmt"
77
"io"
8+
"net"
89
"os"
9-
"os/exec"
1010
"strconv"
1111
"strings"
1212
"sync"
13+
"time"
14+
15+
"github.com/gopher-fleece/gleece/v2/internal/lsp/server"
16+
"github.com/gopher-fleece/gleece/v2/internal/lsp/server/ipc"
17+
protocol "github.com/tliron/glsp/protocol_3_16"
1318
)
1419

1520
type lspRequest struct {
@@ -27,39 +32,18 @@ type lspResponse struct {
2732
}
2833

2934
type LSPClient struct {
30-
stdin io.WriteCloser
31-
stdout io.ReadCloser
32-
stderr io.ReadCloser
35+
conn io.ReadWriteCloser
36+
reader *bufio.Reader
3337
mu sync.Mutex
3438
nextID int64
3539
}
3640

37-
func newLSPClient(cmd *exec.Cmd) (*LSPClient, error) {
38-
stdin, err := cmd.StdinPipe()
39-
if err != nil {
40-
return nil, err
41-
}
42-
43-
stdout, err := cmd.StdoutPipe()
44-
if err != nil {
45-
return nil, err
46-
}
47-
48-
stderr, err := cmd.StderrPipe()
49-
if err != nil {
50-
return nil, err
51-
}
52-
53-
if err := cmd.Start(); err != nil {
54-
return nil, err
55-
}
56-
41+
func newLSPClient(conn io.ReadWriteCloser) *LSPClient {
5742
return &LSPClient{
58-
stdin: stdin,
59-
stdout: stdout,
60-
stderr: stderr,
43+
conn: conn,
44+
reader: bufio.NewReader(conn),
6145
nextID: 1,
62-
}, nil
46+
}
6347
}
6448

6549
func (c *LSPClient) Send(method string, params any) (*lspResponse, error) {
@@ -81,18 +65,16 @@ func (c *LSPClient) Send(method string, params any) (*lspResponse, error) {
8165
return nil, err
8266
}
8367

84-
if _, err := fmt.Fprintf(c.stdin, "Content-Length: %d\r\n\r\n", len(payload)); err != nil {
68+
if _, err := fmt.Fprintf(c.conn, "Content-Length: %d\r\n\r\n", len(payload)); err != nil {
8569
return nil, err
8670
}
87-
if _, err := c.stdin.Write(payload); err != nil {
71+
if _, err := c.conn.Write(payload); err != nil {
8872
return nil, err
8973
}
9074

91-
reader := bufio.NewReader(c.stdout)
92-
9375
contentLength := 0
9476
for {
95-
line, err := reader.ReadString('\n')
77+
line, err := c.reader.ReadString('\n')
9678
if err != nil {
9779
return nil, err
9880
}
@@ -112,7 +94,7 @@ func (c *LSPClient) Send(method string, params any) (*lspResponse, error) {
11294
}
11395

11496
body := make([]byte, contentLength)
115-
if _, err := io.ReadFull(reader, body); err != nil {
97+
if _, err := io.ReadFull(c.reader, body); err != nil {
11698
return nil, err
11799
}
118100

@@ -124,16 +106,36 @@ func (c *LSPClient) Send(method string, params any) (*lspResponse, error) {
124106
return &resp, nil
125107
}
126108

109+
func (c *LSPClient) Close() error {
110+
return c.conn.Close()
111+
}
112+
127113
func runLsp() *LSPClient {
128-
// Replace this with the actual server executable entrypoint you want to launch.
129-
cmd := exec.Command(os.Args[0])
114+
const address = "127.0.0.1:43891"
130115

131-
client, err := newLSPClient(cmd)
116+
langServer, err := server.NewLanguageServer(ipc.TcpOptions{
117+
Address: address,
118+
})
132119
if err != nil {
133120
panic(err)
134121
}
135122

136-
return client
123+
go func() {
124+
if err := langServer.Run(); err != nil {
125+
panic(err)
126+
}
127+
}()
128+
129+
var conn net.Conn
130+
for range 20 {
131+
conn, err = net.Dial("tcp", address)
132+
if err == nil {
133+
return newLSPClient(conn)
134+
}
135+
time.Sleep(50 * time.Millisecond)
136+
}
137+
138+
panic(fmt.Errorf("failed to connect to lsp server at %s: %w", address, err))
137139
}
138140

139141
func sendInit(client *LSPClient) {
@@ -146,16 +148,35 @@ func sendInit(client *LSPClient) {
146148
panic(err)
147149
}
148150

149-
fmt.Println(string(resp.Result))
151+
fmt.Printf("Current PID: %v, Resp: %v", os.Getpid(), string(resp.Result))
152+
}
153+
154+
func sendDidChangeTextDocument(client *LSPClient, uri string) {
155+
body := protocol.DidChangeTextDocumentParams{
156+
TextDocument: protocol.VersionedTextDocumentIdentifier{
157+
TextDocumentIdentifier: protocol.TextDocumentIdentifier{
158+
URI: uri,
159+
},
160+
},
161+
}
162+
163+
resp, err := client.Send("textDocument/didChange", body)
164+
if err != nil {
165+
panic(err)
166+
}
167+
168+
fmt.Printf("Current PID: %v, Resp: %v", os.Getpid(), string(resp.Result))
150169
}
151170

152171
func main() {
153172
client := runLsp()
154173
defer func() {
155-
_ = client.stdin.Close()
156-
_ = client.stdout.Close()
157-
_ = client.stderr.Close()
174+
_ = client.Close()
158175
}()
159176

160177
sendInit(client)
178+
sendDidChangeTextDocument(
179+
client,
180+
"/mnt/7e91759c-6dd7-4c99-8d38-e6422452a469/git/gleece/test/sanity/sanity.controller.go",
181+
)
161182
}

internal/lsp/core/analyzer/analyzer.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55

66
"github.com/gopher-fleece/gleece/v2/core/pipeline"
7+
"github.com/gopher-fleece/gleece/v2/core/validators/diagnostics"
78
"github.com/gopher-fleece/gleece/v2/definitions"
89
"github.com/gopher-fleece/gleece/v2/gast"
910
"github.com/tliron/glsp"
@@ -52,14 +53,18 @@ func (analyzer *GleeceAnalyzer) invalidateFile(ctx *glsp.Context, filePath strin
5253
return pipeErr
5354
}
5455

55-
go ctx.Notify(
56-
protocol.ServerTextDocumentPublishDiagnostics,
57-
protocol.PublishDiagnosticsParams{
58-
URI: filePath,
59-
Diagnostics: entityDiagsToLsp(diags),
60-
},
61-
)
56+
analyzer.pushDiagnosticsAsync(ctx, filePath, diags)
6257
}
6358

6459
return nil
6560
}
61+
62+
func (analyzer *GleeceAnalyzer) pushDiagnosticsAsync(ctx *glsp.Context, fileUri string, diagnostics []diagnostics.EntityDiagnostic) {
63+
go ctx.Notify(
64+
protocol.ServerTextDocumentPublishDiagnostics,
65+
protocol.PublishDiagnosticsParams{
66+
URI: fileUri,
67+
Diagnostics: entityDiagsToLsp(diagnostics),
68+
},
69+
)
70+
}

internal/lsp/handlers/initialization.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
package handlers
22

33
import (
4+
"github.com/gopher-fleece/gleece/v2/cmd"
45
"github.com/gopher-fleece/gleece/v2/internal/lsp/common"
6+
"github.com/gopher-fleece/gleece/v2/internal/lsp/core/analyzer"
57
"github.com/tliron/glsp"
68
protocol "github.com/tliron/glsp/protocol_3_16"
79
)
810

911
func (h *ProtocolHandler) initialize(ctx *glsp.Context, params *protocol.InitializeParams) (any, error) {
12+
config, err := cmd.LoadGleeceConfig("/mnt/7e91759c-6dd7-4c99-8d38-e6422452a469/git/gleece/gleece.config.json")
13+
if err != nil {
14+
return nil, err
15+
}
16+
17+
analyzerInstance, err := analyzer.NewGleeceAnalyzer(config)
18+
if err != nil {
19+
return nil, err
20+
}
21+
22+
h.state.Analyzer = analyzerInstance
23+
1024
return protocol.InitializeResult{
1125
Capabilities: protocol.ServerCapabilities{
1226
TextDocumentSync: protocol.TextDocumentSyncKindFull,
@@ -18,5 +32,10 @@ func (h *ProtocolHandler) initialize(ctx *glsp.Context, params *protocol.Initial
1832
}
1933

2034
func (h *ProtocolHandler) initialized(ctx *glsp.Context, params *protocol.InitializedParams) error {
35+
err := h.state.Analyzer.Pipeline.GenerateGraph()
36+
if err != nil {
37+
return err
38+
}
39+
2140
return nil
2241
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package server
1+
package ipc
22

33
type LangServerIpcType string
44

internal/lsp/server/ipc/stdio.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package ipc
2+
3+
type StdIoOptions struct{}
4+
5+
func (StdIoOptions) IpcType() LangServerIpcType { return LangServerIpcStdIo }
6+
func (StdIoOptions) Validate() error { return nil }

internal/lsp/server/ipc/tcp.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package ipc
2+
3+
import "fmt"
4+
5+
type TcpOptions struct {
6+
Address string
7+
}
8+
9+
func (TcpOptions) IpcType() LangServerIpcType { return LangServerIpcTcp }
10+
11+
func (o TcpOptions) Validate() error {
12+
if o.Address == "" {
13+
return fmt.Errorf("address is required for tcp ipc type")
14+
}
15+
return nil
16+
}

internal/lsp/server/server.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,43 @@ import (
55

66
"github.com/gopher-fleece/gleece/v2/internal/lsp/common"
77
"github.com/gopher-fleece/gleece/v2/internal/lsp/handlers"
8+
"github.com/gopher-fleece/gleece/v2/internal/lsp/server/ipc"
89
"github.com/gopher-fleece/gleece/v2/internal/lsp/state"
910
"github.com/tliron/glsp/server"
1011
)
1112

12-
type LangServerOptions struct {
13-
Ipc LangServerIpcType
13+
type LangServerOptions interface {
14+
IpcType() ipc.LangServerIpcType
15+
Validate() error
1416
}
1517

1618
type LanguageServer struct {
17-
ipcType LangServerIpcType
19+
options LangServerOptions
1820
}
1921

2022
func NewLanguageServer(opts LangServerOptions) (*LanguageServer, error) {
21-
if opts.Ipc == "" || (opts.Ipc != LangServerIpcStdIo) {
22-
return nil, fmt.Errorf("ipc type '%s' is not currently supported", opts.Ipc)
23+
if opts == nil {
24+
return nil, fmt.Errorf("options are required")
2325
}
2426

25-
return &LanguageServer{
26-
ipcType: opts.Ipc,
27-
}, nil
27+
if err := opts.Validate(); err != nil {
28+
return nil, err
29+
}
30+
31+
return &LanguageServer{options: opts}, nil
2832
}
2933

3034
func (s *LanguageServer) Run() error {
3135
state := state.WorkspaceState{}
3236
handler := handlers.GetProtocolHandler(&state)
3337
srv := server.NewServer(&handler, common.LangSrvName, false)
3438

35-
switch s.ipcType {
36-
case LangServerIpcStdIo:
39+
switch opts := s.options.(type) {
40+
case ipc.StdIoOptions:
3741
return srv.RunStdio()
42+
case ipc.TcpOptions:
43+
return srv.RunTCP(opts.Address)
3844
default:
39-
return fmt.Errorf("unknown or unsupported ipc type '%s'", s.ipcType)
45+
return fmt.Errorf("unknown or unsupported ipc type '%s'", opts.IpcType())
4046
}
4147
}

internal/lsp/state/workspace.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package state
33
import "github.com/gopher-fleece/gleece/v2/internal/lsp/core/analyzer"
44

55
type WorkspaceState struct {
6-
Analyzer analyzer.GleeceAnalyzer
6+
Analyzer *analyzer.GleeceAnalyzer
77
Documents DocumentsState
88
Config ExtensionConfig
99
}

0 commit comments

Comments
 (0)