|
| 1 | +package handler |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + "io" |
| 7 | + "os" |
| 8 | + "strings" |
| 9 | + |
| 10 | + "github.com/arduino/arduino-cli/executils" |
| 11 | + "github.com/arduino/arduino-language-server/streams" |
| 12 | + "github.com/arduino/go-paths-helper" |
| 13 | + "go.bug.st/json" |
| 14 | + "go.bug.st/lsp" |
| 15 | + "go.bug.st/lsp/jsonrpc" |
| 16 | +) |
| 17 | + |
| 18 | +type ClangdClient struct { |
| 19 | + conn *lsp.Client |
| 20 | + handler *INOLanguageServer |
| 21 | +} |
| 22 | + |
| 23 | +func NewClangdClient(logger jsonrpc.FunctionLogger, |
| 24 | + buildPath, buildSketchCpp, dataFolder *paths.Path, |
| 25 | + connectionClosedCB func(), |
| 26 | + inoLanguageServer *INOLanguageServer, |
| 27 | +) *ClangdClient { |
| 28 | + clangdStdout, clangdStdin, clangdStderr := startClangd(logger, buildPath, buildSketchCpp, dataFolder) |
| 29 | + clangdStdio := streams.NewReadWriteCloser(clangdStdin, clangdStdout) |
| 30 | + if enableLogging { |
| 31 | + clangdStdio = streams.LogReadWriteCloserAs(clangdStdio, "inols-clangd.log") |
| 32 | + go io.Copy(streams.OpenLogFileAs("inols-clangd-err.log"), clangdStderr) |
| 33 | + } else { |
| 34 | + go io.Copy(os.Stderr, clangdStderr) |
| 35 | + } |
| 36 | + |
| 37 | + client := &ClangdClient{ |
| 38 | + handler: inoLanguageServer, |
| 39 | + } |
| 40 | + client.conn = lsp.NewClient(clangdStdio, clangdStdio, client) |
| 41 | + client.conn.SetLogger(&LSPLogger{IncomingPrefix: "IDE LS <-- Clangd", OutgoingPrefix: "IDE LS --> Clangd"}) |
| 42 | + go func() { |
| 43 | + defer streams.CatchAndLogPanic() |
| 44 | + client.conn.Run() |
| 45 | + connectionClosedCB() |
| 46 | + }() |
| 47 | + |
| 48 | + return client |
| 49 | +} |
| 50 | + |
| 51 | +func startClangd(logger jsonrpc.FunctionLogger, compileCommandsDir, sketchCpp, dataFolder *paths.Path) (io.WriteCloser, io.ReadCloser, io.ReadCloser) { |
| 52 | + // Start clangd |
| 53 | + args := []string{ |
| 54 | + globalClangdPath, |
| 55 | + "-log=verbose", |
| 56 | + fmt.Sprintf(`--compile-commands-dir=%s`, compileCommandsDir), |
| 57 | + } |
| 58 | + if dataFolder != nil { |
| 59 | + args = append(args, fmt.Sprintf("-query-driver=%s", dataFolder.Join("packages", "**"))) |
| 60 | + } |
| 61 | + logger.Logf(" Starting clangd: %s", strings.Join(args, " ")) |
| 62 | + if clangdCmd, err := executils.NewProcess(args...); err != nil { |
| 63 | + panic("starting clangd: " + err.Error()) |
| 64 | + } else if clangdIn, err := clangdCmd.StdinPipe(); err != nil { |
| 65 | + panic("getting clangd stdin: " + err.Error()) |
| 66 | + } else if clangdOut, err := clangdCmd.StdoutPipe(); err != nil { |
| 67 | + panic("getting clangd stdout: " + err.Error()) |
| 68 | + } else if clangdErr, err := clangdCmd.StderrPipe(); err != nil { |
| 69 | + panic("getting clangd stderr: " + err.Error()) |
| 70 | + } else if err := clangdCmd.Start(); err != nil { |
| 71 | + panic("running clangd: " + err.Error()) |
| 72 | + } else { |
| 73 | + return clangdIn, clangdOut, clangdErr |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +func (client *ClangdClient) Close() { |
| 78 | + panic("unimplemented") |
| 79 | +} |
| 80 | + |
| 81 | +// The following are events incoming from Clangd |
| 82 | + |
| 83 | +func (client *ClangdClient) WindowShowMessageRequest(context.Context, jsonrpc.FunctionLogger, *lsp.ShowMessageRequestParams) (*lsp.MessageActionItem, *jsonrpc.ResponseError) { |
| 84 | + panic("unimplemented") |
| 85 | +} |
| 86 | + |
| 87 | +func (client *ClangdClient) WindowShowDocument(context.Context, jsonrpc.FunctionLogger, *lsp.ShowDocumentParams) (*lsp.ShowDocumentResult, *jsonrpc.ResponseError) { |
| 88 | + panic("unimplemented") |
| 89 | +} |
| 90 | + |
| 91 | +func (client *ClangdClient) WindowWorkDoneProgressCreate(ctx context.Context, logger jsonrpc.FunctionLogger, params *lsp.WorkDoneProgressCreateParams) *jsonrpc.ResponseError { |
| 92 | + return client.handler.WindowWorkDoneProgressCreateFromClangd(ctx, logger, params) |
| 93 | +} |
| 94 | + |
| 95 | +func (client *ClangdClient) ClientRegisterCapability(context.Context, jsonrpc.FunctionLogger, *lsp.RegistrationParams) *jsonrpc.ResponseError { |
| 96 | + panic("unimplemented") |
| 97 | +} |
| 98 | + |
| 99 | +func (client *ClangdClient) ClientUnregisterCapability(context.Context, jsonrpc.FunctionLogger, *lsp.UnregistrationParams) *jsonrpc.ResponseError { |
| 100 | + panic("unimplemented") |
| 101 | +} |
| 102 | + |
| 103 | +func (client *ClangdClient) WorkspaceWorkspaceFolders(context.Context, jsonrpc.FunctionLogger) ([]lsp.WorkspaceFolder, *jsonrpc.ResponseError) { |
| 104 | + panic("unimplemented") |
| 105 | +} |
| 106 | + |
| 107 | +func (client *ClangdClient) WorkspaceConfiguration(context.Context, jsonrpc.FunctionLogger, *lsp.ConfigurationParams) ([]json.RawMessage, *jsonrpc.ResponseError) { |
| 108 | + panic("unimplemented") |
| 109 | +} |
| 110 | + |
| 111 | +func (client *ClangdClient) WorkspaceApplyEdit(context.Context, jsonrpc.FunctionLogger, *lsp.ApplyWorkspaceEditParams) (*lsp.ApplyWorkspaceEditResult, *jsonrpc.ResponseError) { |
| 112 | + panic("unimplemented") |
| 113 | +} |
| 114 | + |
| 115 | +func (client *ClangdClient) WorkspaceCodeLensRefresh(context.Context, jsonrpc.FunctionLogger) *jsonrpc.ResponseError { |
| 116 | + panic("unimplemented") |
| 117 | +} |
| 118 | + |
| 119 | +func (client *ClangdClient) Progress(logger jsonrpc.FunctionLogger, progress *lsp.ProgressParams) { |
| 120 | + client.handler.ProgressFromClangd(logger, progress) |
| 121 | +} |
| 122 | + |
| 123 | +func (client *ClangdClient) LogTrace(jsonrpc.FunctionLogger, *lsp.LogTraceParams) { |
| 124 | + panic("unimplemented") |
| 125 | +} |
| 126 | + |
| 127 | +func (client *ClangdClient) WindowShowMessage(jsonrpc.FunctionLogger, *lsp.ShowMessageParams) { |
| 128 | + panic("unimplemented") |
| 129 | +} |
| 130 | + |
| 131 | +func (client *ClangdClient) WindowLogMessage(jsonrpc.FunctionLogger, *lsp.LogMessageParams) { |
| 132 | + panic("unimplemented") |
| 133 | +} |
| 134 | + |
| 135 | +func (client *ClangdClient) TelemetryEvent(jsonrpc.FunctionLogger, json.RawMessage) { |
| 136 | + panic("unimplemented") |
| 137 | +} |
| 138 | + |
| 139 | +func (client *ClangdClient) TextDocumentPublishDiagnostics(logger jsonrpc.FunctionLogger, params *lsp.PublishDiagnosticsParams) { |
| 140 | + client.handler.PublishDiagnosticsFromClangd(logger, params) |
| 141 | +} |
0 commit comments