From 6cb3fbc8b71f5c30aa860d60be4b327a3f658d54 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sat, 8 Oct 2022 13:28:46 +0200 Subject: [PATCH] feat: add go LSP (#699) * lsp * progress * 1.36.0 --- backend/openapi.yaml | 31 +++++++++++++++++--- backend/src/worker.rs | 7 ++++- frontend/CaddyfileLsp | 14 +++++++++ frontend/src/lib/components/Editor.svelte | 16 ++++++++-- frontend/src/lib/components/EditorBar.svelte | 4 ++- frontend/src/lib/editorUtils.ts | 2 ++ frontend/src/lib/script_helpers.ts | 8 +++-- lsp/Dockerfile | 5 ++++ lsp/pyls_launcher.py | 14 +++++++++ python-client/build.sh | 2 +- 10 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 frontend/CaddyfileLsp diff --git a/backend/openapi.yaml b/backend/openapi.yaml index a0faf96052..61d3faf19b 100644 --- a/backend/openapi.yaml +++ b/backend/openapi.yaml @@ -2565,7 +2565,13 @@ paths: schema: type: object responses: - "201" + "201": + description: job resumed + content: + text/plain: + schema: + type: string + post: summary: resume a job for a suspended flow operationId: resumeSuspendedJob @@ -2580,7 +2586,12 @@ paths: schema: type: object responses: - "201" + "201": + description: job resumed + content: + text/plain: + schema: + type: string /w/{workspace}/jobs/cancel/{id}: get: @@ -2596,7 +2607,13 @@ paths: schema: type: object responses: - "201" + "201": + description: job resumed + content: + text/plain: + schema: + type: string + post: summary: cancel a job for a suspended flow operationId: cancelSuspendedJob @@ -2611,7 +2628,13 @@ paths: schema: type: object responses: - "201" + "201": + description: job resumed + content: + text/plain: + schema: + type: string + /schedules/preview: post: diff --git a/backend/src/worker.rs b/backend/src/worker.rs index 84fe440a15..b87db0e393 100644 --- a/backend/src/worker.rs +++ b/backend/src/worker.rs @@ -1378,7 +1378,12 @@ async fn install_go_dependencies( } async fn gen_go_mymod(code: &str, job_dir: &str) -> error::Result<()> { - let code = &format!("package inner; {code}").replace("func main(", "func Inner_main("); + let code = if code.trim_start().starts_with("package") { + code.to_string() + } else { + format!("package inner; {code}") + }; + let code = code.replace("func main(", "func Inner_main("); let mymod_dir = format!("{job_dir}/inner"); DirBuilder::new() diff --git a/frontend/CaddyfileLsp b/frontend/CaddyfileLsp new file mode 100644 index 0000000000..eb86cda7e2 --- /dev/null +++ b/frontend/CaddyfileLsp @@ -0,0 +1,14 @@ +http://localhost { + bind {$ADDRESS} + reverse_proxy /api/* https://app.windmill.dev { + header_up Host {http.reverse_proxy.upstream.hostport} + } + reverse_proxy /* http://localhost:3000 +} + + +https://localhost { + bind {$ADDRESS} + reverse_proxy /ws/* http://localhost:3001 +} + diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index af64618731..7eb1289a73 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -58,7 +58,7 @@ export let cmdEnterAction: (() => void) | undefined = undefined export let formatAction: (() => void) | undefined = undefined export let automaticLayout = true - export let websocketAlive = { pyright: false, black: false, deno: false } + export let websocketAlive = { pyright: false, black: false, deno: false, go: false } export let shouldBindKey: boolean = true let websockets: [MonacoLanguageClient, WebSocket][] = [] @@ -68,7 +68,7 @@ let disposeMethod: () => void | undefined const dispatch = createEventDispatcher() - const uri = `file:///${hash}.${langToExt(lang)}` + const uri = `file:///tmp/monaco/${hash}.${langToExt(lang)}` if (browser) { if (dev) { @@ -311,6 +311,10 @@ python: 'black' } }) + } else if (lang === 'go') { + connectToLanguageServer(`wss://${$page.url.host}/ws/go`, 'go', { + 'build.allowImplicitNetworkAccess': true + }) } websocketInterval && clearInterval(websocketInterval) @@ -320,7 +324,12 @@ !lastWsAttempt || (new Date().getTime() - lastWsAttempt.getTime() > 60000 && nbWsAttempt < 2) ) { - if (!websocketAlive.black && !websocketAlive.deno && !websocketAlive.pyright) { + if ( + !websocketAlive.black && + !websocketAlive.deno && + !websocketAlive.pyright && + !websocketAlive.go + ) { console.log('reconnecting to language servers') lastWsAttempt = new Date() nbWsAttempt++ @@ -393,6 +402,7 @@ !websocketAlive.black && !websocketAlive.deno && !websocketAlive.pyright && + !websocketAlive.go && !websocketInterval ) { reloadWebsocket() diff --git a/frontend/src/lib/components/EditorBar.svelte b/frontend/src/lib/components/EditorBar.svelte index 7a4a694a52..e169d5eff8 100644 --- a/frontend/src/lib/components/EditorBar.svelte +++ b/frontend/src/lib/components/EditorBar.svelte @@ -24,7 +24,7 @@ export let lang: 'python3' | 'deno' | 'go' export let editor: Editor - export let websocketAlive: { pyright: boolean; black: boolean; deno: boolean } + export let websocketAlive: { pyright: boolean; black: boolean; deno: boolean; go: boolean } export let iconOnly: boolean = false let contextualVariablePicker: ItemPicker @@ -282,6 +282,8 @@ {#if lang == 'deno'} (Deno) + {:else if lang == 'go'} + (Go) {:else if lang == 'python3'} (Pyright Black) diff --git a/frontend/src/lib/editorUtils.ts b/frontend/src/lib/editorUtils.ts index 82b9823154..6653c05bd6 100644 --- a/frontend/src/lib/editorUtils.ts +++ b/frontend/src/lib/editorUtils.ts @@ -41,6 +41,8 @@ export function langToExt(lang: string): string { return 'ts' case 'python': return 'py' + case 'go': + return 'go' default: return 'unknown' } diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index 9769ab9526..08f9c28f10 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -49,7 +49,9 @@ export async function main( } ` -export const GO_INIT_CODE = `import ( +export const GO_INIT_CODE = `package inner + +import ( "fmt" "rsc.io/quote" ) @@ -61,7 +63,9 @@ func main(x string) (interface{}, error) { } ` -export const GO_FAILURE_MODULE_CODE = `import ( +export const GO_FAILURE_MODULE_CODE = `package inner + +import ( "fmt" "os" ) diff --git a/lsp/Dockerfile b/lsp/Dockerfile index 1015c538aa..33774bc0ed 100644 --- a/lsp/Dockerfile +++ b/lsp/Dockerfile @@ -2,6 +2,11 @@ FROM nikolaik/python-nodejs RUN yarn global add diagnostic-languageserver RUN yarn global add pyright +RUN wget https://golang.org/dl/go1.19.1.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.19.1.linux-amd64.tar.gz +ENV PATH="${PATH}:/usr/local/go/bin:/root/go/bin" +ENV GO_PATH=/usr/local/go/bin/go +ENV GOROOT=/usr/local/go +RUN go install -v golang.org/x/tools/gopls@latest RUN pip3 install black tornado python-lsp-jsonrpc COPY --from=denoland/deno:latest /usr/bin/deno /usr/bin/deno diff --git a/lsp/pyls_launcher.py b/lsp/pyls_launcher.py index b6387773cc..b25c2839dc 100644 --- a/lsp/pyls_launcher.py +++ b/lsp/pyls_launcher.py @@ -75,12 +75,26 @@ class DenoLS(LanguageServerWebSocketHandler): procargs = ["deno", "lsp"] +class GoLS(LanguageServerWebSocketHandler): + procargs = ["gopls", "serve"] + + if __name__ == "__main__": + + monaco_path = '/tmp/monaco' + os.makedirs(monaco_path, exist_ok=True) + print("The monaco directory is created!") + go_mod_path = os.path.join(monaco_path, 'go.mod') + if not os.path.exists(go_mod_path): + f = open(go_mod_path, "w") + f.write("module mymod\ngo 1.19") + f.close() port = int(os.environ.get("PORT", "3001")) app = web.Application([ (r"/ws/pyright", PyrightLS), (r"/ws/black", DiagnosticLS), (r"/ws/deno", DenoLS), + (r"/ws/go", GoLS), ]) app.listen(port, address="0.0.0.0") ioloop.IOLoop.current().start() diff --git a/python-client/build.sh b/python-client/build.sh index 21b25ea6a5..649c330da0 100755 --- a/python-client/build.sh +++ b/python-client/build.sh @@ -3,7 +3,7 @@ set -e #TODO: remove once openapi-python-client supports recursive values cp ../openflow.openapi.yaml ../openflow.openapi.yaml.tmp -sed -z 's/ ForloopFlow:\n type: object\n properties:\n value:\n $ref: "#\/components\/schemas\/FlowValue"/ ForloopFlow:\n type: object\n properties:/' ../openflow.openapi.yaml > ../openflow.openapi.yaml.new +sed -z 's/ ForloopFlow:\n type: object\n properties:\n modules:\n type: array\n items:\n $ref: "#\/components\/schemas\/FlowModule"/ ForloopFlow:\n type: object\n properties:/' ../openflow.openapi.yaml > ../openflow.openapi.yaml.new mv ../openflow.openapi.yaml.new ../openflow.openapi.yaml cp ../backend/openapi.yaml openapi.yaml