Web workers for the lsp servers (#2136)

* put the lsps into a web worker

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* remove extraneous logs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* remove trash toml lib

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* less logs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* less logs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes for tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* for playwright go back to the shitty lib

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-04-16 21:36:19 -07:00
committed by GitHub
parent 35c3103186
commit f0b9de2c1c
24 changed files with 412 additions and 167 deletions

View File

@ -2,9 +2,8 @@ import { LanguageServerClient } from 'editor/plugins/lsp'
import type * as LSP from 'vscode-languageserver-protocol'
import React, { createContext, useMemo, useEffect, useContext } from 'react'
import { FromServer, IntoServer } from 'editor/plugins/lsp/codec'
import Server from '../editor/plugins/lsp/server'
import Client from '../editor/plugins/lsp/client'
import { TEST } from 'env'
import { DEV, TEST } from 'env'
import kclLanguage from 'editor/plugins/lsp/kcl/language'
import { copilotPlugin } from 'editor/plugins/lsp/copilot'
import { useStore } from 'useStore'
@ -15,6 +14,13 @@ import { useNavigate } from 'react-router-dom'
import { paths } from 'lib/paths'
import { FileEntry } from 'lib/types'
import { NetworkHealthState, useNetworkStatus } from './NetworkHealthIndicator'
import Worker from 'editor/plugins/lsp/worker.ts?worker'
import {
LspWorkerEventType,
KclWorkerOptions,
CopilotWorkerOptions,
LspWorker,
} from 'editor/plugins/lsp/types'
const DEFAULT_FILE_NAME: string = 'main.kcl'
@ -87,20 +93,34 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
// But the server happens async so we break this into two parts.
// Below is the client and server promise.
const { lspClient: kclLspClient } = useMemo(() => {
const intoServer: IntoServer = new IntoServer()
const fromServer: FromServer = FromServer.create()
const client = new Client(fromServer, intoServer)
if (!TEST) {
Server.initialize(intoServer, fromServer).then((lspServer) => {
lspServer.start('kcl', token)
setIsKclLspServerReady(true)
})
if (!token || token === '' || TEST) {
return { lspClient: null }
}
const lspClient = new LanguageServerClient({ client, name: 'kcl' })
const lspWorker = new Worker({ name: 'kcl' })
const initEvent: KclWorkerOptions = {
token: token,
baseUnit: defaultUnit.current,
devMode: DEV,
}
lspWorker.postMessage({
worker: LspWorker.Kcl,
eventType: LspWorkerEventType.Init,
eventData: initEvent,
})
lspWorker.onmessage = function (e) {
fromServer.add(e.data)
}
const intoServer: IntoServer = new IntoServer(LspWorker.Kcl, lspWorker)
const fromServer: FromServer = FromServer.create()
const client = new Client(fromServer, intoServer)
setIsKclLspServerReady(true)
const lspClient = new LanguageServerClient({ client, name: LspWorker.Kcl })
return { lspClient }
}, [
setIsKclLspServerReady,
// We need a token for authenticating the server.
token,
])
@ -112,7 +132,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
// We do not want to restart the server, its just wasteful.
const kclLSP = useMemo(() => {
let plugin = null
if (isKclLspServerReady && !TEST) {
if (isKclLspServerReady && !TEST && kclLspClient) {
// Set up the lsp plugin.
const lsp = kclLanguage({
documentUri: `file:///${DEFAULT_FILE_NAME}`,
@ -127,10 +147,12 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
// Re-execute the scene when the units change.
useEffect(() => {
let plugins = kclLspClient.plugins
for (let plugin of plugins) {
if (plugin.updateUnits && isStreamReady && isNetworkOkay) {
plugin.updateUnits(defaultUnit.current)
if (kclLspClient) {
let plugins = kclLspClient.plugins
for (let plugin of plugins) {
if (plugin.updateUnits && isStreamReady && isNetworkOkay) {
plugin.updateUnits(defaultUnit.current)
}
}
}
}, [
@ -145,19 +167,36 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
])
const { lspClient: copilotLspClient } = useMemo(() => {
const intoServer: IntoServer = new IntoServer()
const fromServer: FromServer = FromServer.create()
const client = new Client(fromServer, intoServer)
if (!TEST) {
Server.initialize(intoServer, fromServer).then((lspServer) => {
lspServer.start('copilot', token)
setIsCopilotLspServerReady(true)
})
if (!token || token === '' || TEST) {
return { lspClient: null }
}
const lspClient = new LanguageServerClient({ client, name: 'copilot' })
const lspWorker = new Worker({ name: 'copilot' })
const initEvent: CopilotWorkerOptions = {
token: token,
devMode: DEV,
}
lspWorker.postMessage({
worker: LspWorker.Copilot,
eventType: LspWorkerEventType.Init,
eventData: initEvent,
})
lspWorker.onmessage = function (e) {
fromServer.add(e.data)
}
const intoServer: IntoServer = new IntoServer(LspWorker.Copilot, lspWorker)
const fromServer: FromServer = FromServer.create()
const client = new Client(fromServer, intoServer)
setIsCopilotLspServerReady(true)
const lspClient = new LanguageServerClient({
client,
name: LspWorker.Copilot,
})
return { lspClient }
}, [setIsCopilotLspServerReady, token])
}, [token])
// Here we initialize the plugin which will start the client.
// When we have multi-file support the name of the file will be a dep of
@ -166,7 +205,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
// We do not want to restart the server, its just wasteful.
const copilotLSP = useMemo(() => {
let plugin = null
if (isCopilotLspServerReady && !TEST) {
if (isCopilotLspServerReady && !TEST && copilotLspClient) {
// Set up the lsp plugin.
const lsp = copilotPlugin({
documentUri: `file:///${DEFAULT_FILE_NAME}`,
@ -180,7 +219,13 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
return plugin
}, [copilotLspClient, isCopilotLspServerReady])
const lspClients = [kclLspClient, copilotLspClient]
let lspClients: LanguageServerClient[] = []
if (kclLspClient) {
lspClients.push(kclLspClient)
}
if (copilotLspClient) {
lspClients.push(copilotLspClient)
}
const onProjectClose = (
file: FileEntry | null,