lsp workspace stuff (#1677)

* some lsp shit

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

* more stuffs

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

* on open send close and open events

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

* updates

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

* update the path

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

* updates

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

* updates

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

* send on close

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

* on close project

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

* update on close

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

* updates

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

* initpromise

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

* add to wasm.ts

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

* Update src/lang/wasm.ts

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>

* restart lsps on failure

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

* updates

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

* add panic hook

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

* updartes

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

* updates

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
This commit is contained in:
Jess Frazelle
2024-03-11 17:50:31 -07:00
committed by GitHub
parent cd158f8db0
commit db5657a298
17 changed files with 436 additions and 137 deletions

View File

@ -4,9 +4,6 @@ import ReactCodeMirror, {
ViewUpdate,
keymap,
} from '@uiw/react-codemirror'
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 { useCommandsContext } from 'hooks/useCommandsContext'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
@ -16,8 +13,6 @@ import { useEffect, useMemo, useRef } from 'react'
import { linter, lintGutter } from '@codemirror/lint'
import { useStore } from 'useStore'
import { processCodeMirrorRanges } from 'lib/selections'
import { LanguageServerClient } from 'editor/plugins/lsp'
import kclLanguage from 'editor/plugins/lsp/kcl/language'
import { EditorView, lineHighlightField } from 'editor/highlightextension'
import { roundOff } from 'lib/utils'
import { kclErrToDiagnostic } from 'lang/errors'
@ -26,14 +21,11 @@ import { useModelingContext } from 'hooks/useModelingContext'
import interact from '@replit/codemirror-interact'
import { engineCommandManager } from '../lang/std/engineConnection'
import { kclManager, useKclContext } from 'lang/KclSingleton'
import { useFileContext } from 'hooks/useFileContext'
import { ModelingMachineEvent } from 'machines/modelingMachine'
import { sceneInfra } from 'clientSideScene/sceneInfra'
import { copilotPlugin } from 'editor/plugins/lsp/copilot'
import { isTauri } from 'lib/isTauri'
import type * as LSP from 'vscode-languageserver-protocol'
import { NetworkHealthState, useNetworkStatus } from './NetworkHealthIndicator'
import { useHotkeys } from 'react-hotkeys-hook'
import { useLspContext } from './LspProvider'
export const editorShortcutMeta = {
formatCode: {
@ -46,41 +38,21 @@ export const editorShortcutMeta = {
},
}
function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
// We only use workspace folders in Tauri since that is where we use more than
// one file.
if (isTauri()) {
return [{ uri: 'file://', name: 'ProjectRoot' }]
}
return []
}
export const TextEditor = ({
theme,
}: {
theme: Themes.Light | Themes.Dark
}) => {
const {
editorView,
isKclLspServerReady,
isCopilotLspServerReady,
setEditorView,
setIsKclLspServerReady,
setIsCopilotLspServerReady,
isShiftDown,
} = useStore((s) => ({
const { editorView, setEditorView, isShiftDown } = useStore((s) => ({
editorView: s.editorView,
isKclLspServerReady: s.isKclLspServerReady,
isCopilotLspServerReady: s.isCopilotLspServerReady,
setEditorView: s.setEditorView,
setIsKclLspServerReady: s.setIsKclLspServerReady,
setIsCopilotLspServerReady: s.setIsCopilotLspServerReady,
isShiftDown: s.isShiftDown,
}))
const { code, errors } = useKclContext()
const lastEvent = useRef({ event: '', time: Date.now() })
const { overallState } = useNetworkStatus()
const isNetworkOkay = overallState === NetworkHealthState.Ok
const { copilotLSP, kclLSP } = useLspContext()
useEffect(() => {
if (typeof window === 'undefined') return
@ -108,92 +80,12 @@ export const TextEditor = ({
state,
} = useModelingContext()
const { settings, auth } = useSettingsAuthContext()
const { settings } = useSettingsAuthContext()
const textWrapping = settings.context?.textWrapping ?? 'On'
const { commandBarSend } = useCommandsContext()
const {
context: { project },
} = useFileContext()
const { enable: convertEnabled, handleClick: convertCallback } =
useConvertToVariable()
// So this is a bit weird, we need to initialize the lsp server and client.
// 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')
setIsKclLspServerReady(true)
})
}
const lspClient = new LanguageServerClient({ client, name: 'kcl' })
return { lspClient }
}, [setIsKclLspServerReady])
// Here we initialize the plugin which will start the client.
// Now that we have multi-file support the name of the file is a dep of
// this use memo, as well as the directory structure, which I think is
// a good setup because it will restart the client but not the server :)
// We do not want to restart the server, its just wasteful.
const kclLSP = useMemo(() => {
let plugin = null
if (isKclLspServerReady && !TEST) {
// Set up the lsp plugin.
const lsp = kclLanguage({
// When we have more than one file, we'll need to change this.
documentUri: `file:///we-just-have-one-file-for-now.kcl`,
workspaceFolders: getWorkspaceFolders(),
client: kclLspClient,
})
plugin = lsp
}
return plugin
}, [kclLspClient, isKclLspServerReady])
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) => {
const token = auth?.context?.token
lspServer.start('copilot', token)
setIsCopilotLspServerReady(true)
})
}
const lspClient = new LanguageServerClient({ client, name: 'copilot' })
return { lspClient }
}, [setIsCopilotLspServerReady])
// 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
// this use memo, as well as the directory structure, which I think is
// a good setup because it will restart the client but not the server :)
// We do not want to restart the server, its just wasteful.
const copilotLSP = useMemo(() => {
let plugin = null
if (isCopilotLspServerReady && !TEST) {
// Set up the lsp plugin.
const lsp = copilotPlugin({
// When we have more than one file, we'll need to change this.
documentUri: `file:///we-just-have-one-file-for-now.kcl`,
workspaceFolders: getWorkspaceFolders(),
client: copilotLspClient,
allowHTMLContent: true,
})
plugin = lsp
}
return plugin
}, [copilotLspClient, isCopilotLspServerReady, project])
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
const onChange = async (newCode: string) => {
if (isNetworkOkay) kclManager.setCodeAndExecute(newCode)