go-language-server / protocol

Package protocol implements Language Server Protocol specification in Go
https://pkg.go.dev/go.lsp.dev/protocol
BSD 3-Clause "New" or "Revised" License
97 stars 15 forks source link

How to implement #1

Open kirides opened 5 years ago

kirides commented 5 years ago

How do you implement a language server using this repository?

I tried the following and it creates nilpointer exceptions because "Server" is empty

func NewLangServer(logger *zap.Logger) *LangServer {
    server := new(LangServer)

    return server
}
type LangServer struct {
    protocol.Server
}

Initialized like this:

f, _ := os.Create("lsp-log.txt")
logr, _ := zap.NewDevelopment(zap.ErrorOutput(f))
srv := NewLangServer(logr)
conn, cl := protocol.NewServer(ctx,
                                srv,
                                jsonrpc2.NewStream(os.Stdin, os.Stdout),
                                logr,
                                jsonrpc2.WithLogger(logr))
if err := conn.Run(ctx); err != nil {
    // ...
}
if err := cl.Run(ctx); err != nil {
    // ...
}

produces

2019-06-22T14:57:45.363+0200    DEBUG   jsonrpc2/jsonrpc2.go:346    deliver
panic: runtime error: invalid memory address or nil pointer dereference

which happens in server_json.go

func ServerHandler(ctx context.Context, server ServerInterface, logger *zap.Logger) jsonrpc2.Handler {
    return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) {
        dec := json.NewDecoder(bytes.NewReader(*r.Params))

        switch r.Method {
        case MethodInitialize:
            var params InitializeParams
            if err := dec.Decode(&params); err != nil {
                ReplyError(ctx, err, conn, r, logger)
                return
            }
            // error here: server....
            resp, err := server.Initialize(ctx, &params)
            if err := conn.Reply(ctx, r, resp, err); err != nil {
                logger.Error(MethodInitialize, zap.Error(err))
            }
            // .... more
        }
    }
}
zchee commented 5 years ago

@Kirides I'll describe later :)

zchee commented 5 years ago

@Kirides BTW, Now I develop client side (still private) So I didn't checks server side code for now, sorry :(

But I planned asm-language-server using this package, so I'll adding more testcase and checks server side code correctly.

a-h commented 3 years ago

Did you get any further on developing this?

I'm interested in developing a language server for a language that's implemented in Go. Having a base platform would be very useful.

zchee commented 3 years ago

@a-h will reply, and write example as much as possible :)

a-h commented 3 years ago

Thanks, I did find something that worked for me, so don't feel any pressure! I've put together an example here in case it's useful for you: https://github.com/a-h/qt-lsp

It's my first attempt at getting an LSP going.

zchee commented 3 years ago

@a-h for now, I'll invite you to my private repository which is lsp client side.

kirides commented 3 years ago

Did you get any further on developing this?

I'm interested in developing a language server for a language that's implemented in Go. Having a base platform would be very useful.

You can take a look at my language server implementation for daedalus (a scripting language) https://github.com/Kirides/DaedalusLanguageServer

the important code for initialization and handling of commands is in

initialization: https://github.com/Kirides/DaedalusLanguageServer/blob/master/main.go handling commands: https://github.com/Kirides/DaedalusLanguageServer/blob/master/langserver/lsphandler.go

This approach works fine for my current use case

gebv commented 3 years ago

@Kirides Hi! Will you continue to support a low-level interface jsonrpc2.StreamServer? I want to get jsonrpc2.Conn in order that send notification\request from server to the client. My LSP server is remote, hacks to sync files.

I initialize the server like this.

srv := &myServer{}
err := jsonrpc2.ListenAndServe(ctx, "tcp", "127.0.0.1:10001", jsonrpc2.HandlerServer(srv.Handler), 0)
...
type myServer struct {}
func (s *myServer) Handler(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error { ... }

But I has to convert into anything... I haven’t come up with a beautiful solution yet. Please advice for get jsonrpc2.Conn into handler?

kirides commented 3 years ago

@gebv in my current implementation, you could take connectLanguageServers return value (the underlying *jsonrpc2.Conn and store that in your handler for further use. (if that works, haven't checked that)