Skip to content

Commit

Permalink
feat: Write types and helper functions for implementing LSP
Browse files Browse the repository at this point in the history
  • Loading branch information
taichimaeda committed Oct 14, 2023
1 parent 8849d66 commit cba9dd6
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 0 deletions.
101 changes: 101 additions & 0 deletions internal/wire/lsp/lsp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package lsp

import (
"bufio"
"encoding/json"
"fmt"
"io"
"os"
"strconv"
"strings"
)

func ReadBuffer(reader *bufio.Reader) ([]byte, bool) {
var length int
for {
header, err := reader.ReadString('\n')
if err != nil {
fmt.Fprintf(os.Stderr, "error reading header: %v\n", err)
return nil, false
}
if header == "\r\n" {
break
}
// TODO: trim the remaining \r also
header = strings.TrimSpace(header)
switch {
case strings.HasPrefix(header, "Content-Length: "):
value := strings.TrimPrefix(header, "Content-Length: ")
length, err = strconv.Atoi(value)
if err != nil {
fmt.Fprintf(os.Stderr, "Content-Length is not a valid integer: %v\n", err)
return nil, false
}
case strings.HasPrefix(header, "Content-Type: "):
value := strings.TrimPrefix(header, "Content-Type: ")
if value != "application/vscode-jsonrpc; charset=utf-8" {
fmt.Fprintf(os.Stderr, "Content-Type is invalid: %v\n", value)
return nil, false
}
default:
fmt.Fprintf(os.Stderr, "header field name is invalid: %v", header)
return nil, false
}
}
// Read len bytes of content
buf := make([]byte, length)
n, err := io.ReadFull(reader, buf)
if err != nil {
fmt.Fprintf(os.Stderr, "error reading content %v\n", err)
return nil, false
}
if n != length {
fmt.Fprintln(os.Stderr, "Content-Length and content length do not match")
return nil, false
}
return buf, true
}

func ParseMessage(buf []byte) (map[string]interface{}, bool) {
in := make(map[string]interface{})
if err := json.Unmarshal(buf, &in); err != nil {
fmt.Fprintf(os.Stderr, "error deserializing request: %v\n", err)
return nil, false
}
return in, true
}

func ParseRequest(buf []byte, req interface{}) bool {
if err := json.Unmarshal(buf, req); err != nil {
fmt.Fprintf(os.Stderr, "Error parsing request: %v\n", err)
return false
}
return true
}

func StringifyResponse(res interface{}) bool {
bytes, err := json.Marshal(res)
if err != nil {
fmt.Fprintf(os.Stderr, "error serializing response: %v\n", err)
return false
}
fmt.Printf("Content-Length: %d\r\n", len(bytes))
fmt.Printf("\r\n")
// TODO: \r\n at the end is redundant
fmt.Print(string(bytes) + "\r\n")
return true
}

// func calculatePos(fset *token.FileSet, path string, line int, char int) token.Pos {
// var file *token.File
// fset.Iterate(func(f *token.File) bool {
// if f.Name() == path {
// file = f
// return false
// }
// return true
// })
// offset := int(file.LineStart(line)) - int(file.Base())
// offset += char
// return file.Pos(offset)
// }
80 changes: 80 additions & 0 deletions internal/wire/lsp/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package lsp

type InitializeRequest struct {
Jsonrpc string `json:"jsonrpc"`
Id int `json:"id"`
Method string `json:"method"`
Params InitializeParams `json:"params"`
}

type InitializeParams struct {
Capabilities ClientCapabilities `json:"capabilities"`
}

type ClientCapabilities struct {
Workspace WorkspaceClientCapabilities `json:"workspace"`
}

type WorkspaceClientCapabilities struct {
Configuration bool `json:"configuration"`
WorkspaceFolders bool `json:"workspaceFolders"`
}

type InitializeResponse struct {
Jsonrpc string `json:"jsonrpc"`
Id int `json:"id"`
Result InitializeResult `json:"result"`
}
type InitializeResult struct {
Capabilities ServerCapabilities `json:"capabilities"`
}

type ServerCapabilities struct {
TextDocumentSync int `json:"textDocumentSync"`
HoverProvider bool `json:"hoverProvider"`
Workspace WorkspaceServerCapabilities `json:"workspace"`
}

type WorkspaceServerCapabilities struct {
WorkspaceFolders WorkspaceFoldersServerCapabilities `json:"workspaceFolders"`
}

type WorkspaceFoldersServerCapabilities struct {
Supported bool `json:"supported"`
}

type HoverRequest struct {
Jsonrpc string `json:"jsonrpc"`
Id int `json:"id"`
Method string `json:"method"`
Params HoverParams `json:"Params"`
}

type HoverParams struct {
TextDocument TextDocumentIdentifier `json:"textDocument"`
Position Position `json:"position"`
}

type TextDocumentIdentifier struct {
Uri string `json:"uri"`
}

type Position struct {
Line int `json:"line"`
Character int `json:"character"`
}

type HoverResponse struct {
Jsonrpc string `json:"jsonrpc"`
Id int `json:"id"`
Result HoverResult `json:"result"`
}

type HoverResult struct {
Contents MarkupContent `json:"contents"`
}

type MarkupContent struct {
Kind string `json:"kind"`
Value string `json:"value"`
}

0 comments on commit cba9dd6

Please sign in to comment.