onlycode 1.18.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -146
- package/src/account/account.ts +0 -463
- package/src/account/repo.ts +0 -173
- package/src/account/schema.ts +0 -99
- package/src/account/url.ts +0 -8
- package/src/acp/agent.ts +0 -95
- package/src/acp/config-option.ts +0 -203
- package/src/acp/content.ts +0 -250
- package/src/acp/directory.ts +0 -210
- package/src/acp/error.ts +0 -90
- package/src/acp/event.ts +0 -342
- package/src/acp/permission.ts +0 -124
- package/src/acp/profile.ts +0 -42
- package/src/acp/service.ts +0 -1048
- package/src/acp/session.ts +0 -231
- package/src/acp/tool.ts +0 -367
- package/src/acp/usage.ts +0 -232
- package/src/agent/agent.ts +0 -459
- package/src/agent/generate.txt +0 -75
- package/src/agent/prompt/compaction.txt +0 -9
- package/src/agent/prompt/explore.txt +0 -18
- package/src/agent/prompt/summary.txt +0 -11
- package/src/agent/prompt/title.txt +0 -44
- package/src/agent/subagent-permissions.ts +0 -27
- package/src/audio.d.ts +0 -14
- package/src/auth/index.ts +0 -99
- package/src/background/job.ts +0 -39
- package/src/bus/global.ts +0 -22
- package/src/cli/bootstrap.ts +0 -11
- package/src/cli/cmd/account.ts +0 -264
- package/src/cli/cmd/acp.ts +0 -73
- package/src/cli/cmd/agent.ts +0 -259
- package/src/cli/cmd/attach.ts +0 -97
- package/src/cli/cmd/cmd.ts +0 -7
- package/src/cli/cmd/db.ts +0 -62
- package/src/cli/cmd/debug/agent.handler.ts +0 -193
- package/src/cli/cmd/debug/agent.ts +0 -27
- package/src/cli/cmd/debug/config.ts +0 -14
- package/src/cli/cmd/debug/file.ts +0 -73
- package/src/cli/cmd/debug/index.ts +0 -87
- package/src/cli/cmd/debug/lsp.ts +0 -50
- package/src/cli/cmd/debug/ripgrep.ts +0 -79
- package/src/cli/cmd/debug/scrap.ts +0 -15
- package/src/cli/cmd/debug/skill.ts +0 -15
- package/src/cli/cmd/debug/snapshot.ts +0 -50
- package/src/cli/cmd/debug/startup.ts +0 -11
- package/src/cli/cmd/debug/v2.ts +0 -44
- package/src/cli/cmd/export.ts +0 -292
- package/src/cli/cmd/generate.ts +0 -54
- package/src/cli/cmd/github.handler.ts +0 -1593
- package/src/cli/cmd/github.shared.ts +0 -30
- package/src/cli/cmd/github.ts +0 -42
- package/src/cli/cmd/import.ts +0 -224
- package/src/cli/cmd/mcp.ts +0 -849
- package/src/cli/cmd/models.ts +0 -66
- package/src/cli/cmd/plug.ts +0 -230
- package/src/cli/cmd/pr.ts +0 -115
- package/src/cli/cmd/prompt-display.ts +0 -1
- package/src/cli/cmd/providers.ts +0 -534
- package/src/cli/cmd/run/demo.ts +0 -1274
- package/src/cli/cmd/run/entry.body.ts +0 -205
- package/src/cli/cmd/run/footer.command.tsx +0 -1064
- package/src/cli/cmd/run/footer.menu.tsx +0 -351
- package/src/cli/cmd/run/footer.permission.tsx +0 -472
- package/src/cli/cmd/run/footer.prompt.tsx +0 -1306
- package/src/cli/cmd/run/footer.question.tsx +0 -573
- package/src/cli/cmd/run/footer.subagent.tsx +0 -173
- package/src/cli/cmd/run/footer.ts +0 -1129
- package/src/cli/cmd/run/footer.view.tsx +0 -943
- package/src/cli/cmd/run/footer.width.ts +0 -27
- package/src/cli/cmd/run/permission.shared.ts +0 -256
- package/src/cli/cmd/run/prompt.editor.ts +0 -157
- package/src/cli/cmd/run/prompt.shared.ts +0 -153
- package/src/cli/cmd/run/question.shared.ts +0 -340
- package/src/cli/cmd/run/runtime.boot.ts +0 -202
- package/src/cli/cmd/run/runtime.lifecycle.ts +0 -406
- package/src/cli/cmd/run/runtime.queue.ts +0 -349
- package/src/cli/cmd/run/runtime.shared.ts +0 -17
- package/src/cli/cmd/run/runtime.stdin.ts +0 -37
- package/src/cli/cmd/run/runtime.ts +0 -814
- package/src/cli/cmd/run/scrollback.shared.ts +0 -92
- package/src/cli/cmd/run/scrollback.surface.ts +0 -431
- package/src/cli/cmd/run/scrollback.writer.tsx +0 -352
- package/src/cli/cmd/run/session-data.ts +0 -1113
- package/src/cli/cmd/run/session-replay.ts +0 -374
- package/src/cli/cmd/run/session.shared.ts +0 -196
- package/src/cli/cmd/run/splash.ts +0 -275
- package/src/cli/cmd/run/stream.transport.ts +0 -1462
- package/src/cli/cmd/run/stream.ts +0 -175
- package/src/cli/cmd/run/subagent-data.ts +0 -876
- package/src/cli/cmd/run/theme.ts +0 -690
- package/src/cli/cmd/run/tool.ts +0 -1489
- package/src/cli/cmd/run/trace.ts +0 -94
- package/src/cli/cmd/run/turn-summary.ts +0 -47
- package/src/cli/cmd/run/types.ts +0 -350
- package/src/cli/cmd/run/variant.shared.ts +0 -215
- package/src/cli/cmd/run.ts +0 -894
- package/src/cli/cmd/serve.ts +0 -24
- package/src/cli/cmd/session.ts +0 -147
- package/src/cli/cmd/stats.ts +0 -393
- package/src/cli/cmd/tui.ts +0 -224
- package/src/cli/cmd/uninstall.ts +0 -353
- package/src/cli/cmd/upgrade.ts +0 -74
- package/src/cli/cmd/web.ts +0 -84
- package/src/cli/effect/prompt.ts +0 -37
- package/src/cli/effect-cmd.ts +0 -96
- package/src/cli/error.ts +0 -130
- package/src/cli/heap.ts +0 -45
- package/src/cli/logo-pixel.ts +0 -35
- package/src/cli/logo.ts +0 -1
- package/src/cli/network.ts +0 -64
- package/src/cli/tui/layer.ts +0 -7
- package/src/cli/tui/validate-session.ts +0 -29
- package/src/cli/tui/worker.ts +0 -71
- package/src/cli/ui.ts +0 -148
- package/src/cli/upgrade.ts +0 -53
- package/src/command/index.ts +0 -184
- package/src/command/template/initialize.txt +0 -66
- package/src/command/template/review.txt +0 -101
- package/src/config/agent.ts +0 -59
- package/src/config/command.ts +0 -39
- package/src/config/config.ts +0 -686
- package/src/config/entry-name.ts +0 -19
- package/src/config/managed.ts +0 -69
- package/src/config/markdown.ts +0 -36
- package/src/config/parse.ts +0 -79
- package/src/config/paths.ts +0 -45
- package/src/config/plugin.ts +0 -79
- package/src/config/tui-cwd.ts +0 -5
- package/src/config/tui-host-attention.ts +0 -21
- package/src/config/tui-migrate.ts +0 -132
- package/src/config/tui.ts +0 -274
- package/src/config/variable.ts +0 -91
- package/src/control-plane/adapters/index.ts +0 -41
- package/src/control-plane/adapters/worktree.ts +0 -96
- package/src/control-plane/dev/README.md +0 -19
- package/src/control-plane/dev/debug-workspace-plugin.ts +0 -73
- package/src/control-plane/types.ts +0 -59
- package/src/control-plane/util.ts +0 -39
- package/src/control-plane/workspace-adapter-runtime.ts +0 -51
- package/src/control-plane/workspace-context.ts +0 -26
- package/src/control-plane/workspace.ts +0 -989
- package/src/effect/app-runtime.ts +0 -132
- package/src/effect/bootstrap-runtime.ts +0 -23
- package/src/effect/bridge.ts +0 -84
- package/src/effect/config-service.ts +0 -67
- package/src/effect/instance-ref.ts +0 -11
- package/src/effect/instance-registry.ts +0 -12
- package/src/effect/instance-state.ts +0 -69
- package/src/effect/promise.ts +0 -17
- package/src/effect/run-service.ts +0 -47
- package/src/effect/runner.ts +0 -217
- package/src/effect/runtime-flags.ts +0 -79
- package/src/env/index.ts +0 -43
- package/src/event-v2-bridge.ts +0 -79
- package/src/format/formatter.ts +0 -404
- package/src/format/index.ts +0 -205
- package/src/git/index.ts +0 -350
- package/src/id/id.ts +0 -80
- package/src/ide/index.ts +0 -61
- package/src/image/image.ts +0 -174
- package/src/index.ts +0 -142
- package/src/installation/index.ts +0 -350
- package/src/lsp/client.ts +0 -650
- package/src/lsp/diagnostic.ts +0 -29
- package/src/lsp/language.ts +0 -121
- package/src/lsp/launch.ts +0 -21
- package/src/lsp/lsp.ts +0 -511
- package/src/lsp/server.ts +0 -1983
- package/src/markdown.d.ts +0 -4
- package/src/mcp/auth.ts +0 -174
- package/src/mcp/catalog.ts +0 -153
- package/src/mcp/index.ts +0 -953
- package/src/mcp/oauth-callback.ts +0 -233
- package/src/mcp/oauth-provider.ts +0 -206
- package/src/node.ts +0 -4
- package/src/patch/index.ts +0 -686
- package/src/permission/arity.ts +0 -163
- package/src/permission/evaluate.ts +0 -1
- package/src/permission/index.ts +0 -230
- package/src/plugin/azure.ts +0 -26
- package/src/plugin/cloudflare.ts +0 -76
- package/src/plugin/digitalocean.ts +0 -383
- package/src/plugin/github-copilot/copilot.ts +0 -414
- package/src/plugin/github-copilot/models.ts +0 -246
- package/src/plugin/index.ts +0 -316
- package/src/plugin/install.ts +0 -439
- package/src/plugin/loader.ts +0 -237
- package/src/plugin/meta.ts +0 -188
- package/src/plugin/openai/README.md +0 -31
- package/src/plugin/openai/codex.ts +0 -641
- package/src/plugin/openai/ws-pool.ts +0 -270
- package/src/plugin/openai/ws.ts +0 -381
- package/src/plugin/pty-environment.ts +0 -24
- package/src/plugin/shared.ts +0 -323
- package/src/plugin/snowflake-cortex.ts +0 -529
- package/src/plugin/tui/internal.ts +0 -10
- package/src/plugin/tui/runtime.ts +0 -1130
- package/src/plugin/xai.ts +0 -716
- package/src/project/bootstrap-service.ts +0 -9
- package/src/project/bootstrap.ts +0 -76
- package/src/project/instance-context.ts +0 -24
- package/src/project/instance-layer.ts +0 -11
- package/src/project/instance-runtime.ts +0 -16
- package/src/project/instance-store.ts +0 -209
- package/src/project/project.ts +0 -519
- package/src/project/vcs.ts +0 -431
- package/src/provider/auth.ts +0 -233
- package/src/provider/error.ts +0 -188
- package/src/provider/model-status.ts +0 -8
- package/src/provider/provider.ts +0 -1975
- package/src/provider/transform.ts +0 -1543
- package/src/question/index.ts +0 -229
- package/src/question/schema.ts +0 -10
- package/src/server/auth.ts +0 -48
- package/src/server/event.ts +0 -13
- package/src/server/global-lifecycle.ts +0 -28
- package/src/server/init-projectors.ts +0 -3
- package/src/server/mdns.ts +0 -47
- package/src/server/projectors.ts +0 -1
- package/src/server/proxy-util.ts +0 -48
- package/src/server/routes/instance/httpapi/AGENTS.md +0 -39
- package/src/server/routes/instance/httpapi/api.ts +0 -78
- package/src/server/routes/instance/httpapi/errors.ts +0 -193
- package/src/server/routes/instance/httpapi/groups/config.ts +0 -65
- package/src/server/routes/instance/httpapi/groups/control-plane.ts +0 -35
- package/src/server/routes/instance/httpapi/groups/control.ts +0 -76
- package/src/server/routes/instance/httpapi/groups/event.ts +0 -29
- package/src/server/routes/instance/httpapi/groups/experimental.ts +0 -275
- package/src/server/routes/instance/httpapi/groups/file.ts +0 -185
- package/src/server/routes/instance/httpapi/groups/global.ts +0 -138
- package/src/server/routes/instance/httpapi/groups/instance.ts +0 -206
- package/src/server/routes/instance/httpapi/groups/mcp.ts +0 -156
- package/src/server/routes/instance/httpapi/groups/metadata.ts +0 -18
- package/src/server/routes/instance/httpapi/groups/permission.ts +0 -61
- package/src/server/routes/instance/httpapi/groups/project-copy.ts +0 -32
- package/src/server/routes/instance/httpapi/groups/project.ts +0 -93
- package/src/server/routes/instance/httpapi/groups/provider.ts +0 -101
- package/src/server/routes/instance/httpapi/groups/pty.ts +0 -172
- package/src/server/routes/instance/httpapi/groups/query.ts +0 -12
- package/src/server/routes/instance/httpapi/groups/question.ts +0 -74
- package/src/server/routes/instance/httpapi/groups/session.ts +0 -462
- package/src/server/routes/instance/httpapi/groups/sync.ts +0 -113
- package/src/server/routes/instance/httpapi/groups/tui.ts +0 -208
- package/src/server/routes/instance/httpapi/groups/workspace.ts +0 -141
- package/src/server/routes/instance/httpapi/handlers/config.ts +0 -34
- package/src/server/routes/instance/httpapi/handlers/control-plane.ts +0 -37
- package/src/server/routes/instance/httpapi/handlers/control.ts +0 -43
- package/src/server/routes/instance/httpapi/handlers/event.ts +0 -99
- package/src/server/routes/instance/httpapi/handlers/experimental.ts +0 -192
- package/src/server/routes/instance/httpapi/handlers/file.ts +0 -139
- package/src/server/routes/instance/httpapi/handlers/global.ts +0 -156
- package/src/server/routes/instance/httpapi/handlers/instance.ts +0 -110
- package/src/server/routes/instance/httpapi/handlers/mcp.ts +0 -111
- package/src/server/routes/instance/httpapi/handlers/permission.ts +0 -41
- package/src/server/routes/instance/httpapi/handlers/project-copy.ts +0 -83
- package/src/server/routes/instance/httpapi/handlers/project.ts +0 -63
- package/src/server/routes/instance/httpapi/handlers/provider.ts +0 -113
- package/src/server/routes/instance/httpapi/handlers/pty.ts +0 -273
- package/src/server/routes/instance/httpapi/handlers/question.ts +0 -54
- package/src/server/routes/instance/httpapi/handlers/session-errors.ts +0 -21
- package/src/server/routes/instance/httpapi/handlers/session.ts +0 -440
- package/src/server/routes/instance/httpapi/handlers/sync.ts +0 -89
- package/src/server/routes/instance/httpapi/handlers/tui.ts +0 -131
- package/src/server/routes/instance/httpapi/handlers/workspace.ts +0 -102
- package/src/server/routes/instance/httpapi/lifecycle.ts +0 -54
- package/src/server/routes/instance/httpapi/middleware/authorization.ts +0 -150
- package/src/server/routes/instance/httpapi/middleware/compression.ts +0 -64
- package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +0 -29
- package/src/server/routes/instance/httpapi/middleware/error.ts +0 -43
- package/src/server/routes/instance/httpapi/middleware/fence.ts +0 -25
- package/src/server/routes/instance/httpapi/middleware/instance-context.ts +0 -43
- package/src/server/routes/instance/httpapi/middleware/proxy.ts +0 -108
- package/src/server/routes/instance/httpapi/middleware/schema-error.ts +0 -41
- package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +0 -250
- package/src/server/routes/instance/httpapi/public.ts +0 -535
- package/src/server/routes/instance/httpapi/server.ts +0 -298
- package/src/server/routes/instance/httpapi/websocket-tracker.ts +0 -57
- package/src/server/server.ts +0 -225
- package/src/server/shared/fence.ts +0 -60
- package/src/server/shared/pty-ticket.ts +0 -15
- package/src/server/shared/public-ui.ts +0 -12
- package/src/server/shared/tui-control.ts +0 -28
- package/src/server/shared/ui.ts +0 -108
- package/src/server/shared/workspace-routing.ts +0 -38
- package/src/server/tui-event.ts +0 -53
- package/src/session/compaction.ts +0 -620
- package/src/session/instruction.ts +0 -241
- package/src/session/llm/AGENTS.md +0 -90
- package/src/session/llm/ai-sdk.ts +0 -288
- package/src/session/llm/native-request.ts +0 -196
- package/src/session/llm/native-runtime.ts +0 -195
- package/src/session/llm/request.ts +0 -216
- package/src/session/llm.ts +0 -415
- package/src/session/message-error.ts +0 -14
- package/src/session/message-v2.ts +0 -747
- package/src/session/message.ts +0 -148
- package/src/session/overflow.ts +0 -34
- package/src/session/processor.ts +0 -1084
- package/src/session/prompt/anthropic.txt +0 -109
- package/src/session/prompt/beast.txt +0 -151
- package/src/session/prompt/build-switch.txt +0 -9
- package/src/session/prompt/codex.txt +0 -83
- package/src/session/prompt/copilot-gpt-5.txt +0 -147
- package/src/session/prompt/default.txt +0 -99
- package/src/session/prompt/gemini.txt +0 -159
- package/src/session/prompt/gpt.txt +0 -111
- package/src/session/prompt/kimi.txt +0 -99
- package/src/session/prompt/plan-mode.txt +0 -74
- package/src/session/prompt/plan-reminder-anthropic.txt +0 -71
- package/src/session/prompt/plan.txt +0 -30
- package/src/session/prompt/trinity.txt +0 -101
- package/src/session/prompt.ts +0 -1707
- package/src/session/reminders.ts +0 -92
- package/src/session/retry.ts +0 -201
- package/src/session/revert.ts +0 -160
- package/src/session/run-state.ts +0 -156
- package/src/session/schema.ts +0 -26
- package/src/session/session.ts +0 -1119
- package/src/session/status.ts +0 -97
- package/src/session/summary.ts +0 -165
- package/src/session/system.ts +0 -117
- package/src/session/todo.ts +0 -90
- package/src/session/tools.ts +0 -207
- package/src/share/session.ts +0 -61
- package/src/share/share-next.ts +0 -385
- package/src/skill/discovery.ts +0 -109
- package/src/skill/index.ts +0 -366
- package/src/snapshot/index.ts +0 -808
- package/src/sql.d.ts +0 -4
- package/src/storage/schema.ts +0 -5
- package/src/storage/storage.ts +0 -329
- package/src/sync/README.md +0 -179
- package/src/sync/schema.ts +0 -11
- package/src/temporary.ts +0 -31
- package/src/tool/apply_patch.ts +0 -315
- package/src/tool/apply_patch.txt +0 -33
- package/src/tool/apply_patch.zh.txt +0 -33
- package/src/tool/description.ts +0 -100
- package/src/tool/edit.ts +0 -739
- package/src/tool/edit.txt +0 -10
- package/src/tool/edit.zh.txt +0 -10
- package/src/tool/external-directory.ts +0 -49
- package/src/tool/glob.ts +0 -78
- package/src/tool/glob.txt +0 -6
- package/src/tool/glob.zh.txt +0 -6
- package/src/tool/grep.ts +0 -114
- package/src/tool/grep.txt +0 -8
- package/src/tool/grep.zh.txt +0 -8
- package/src/tool/invalid.ts +0 -21
- package/src/tool/json-schema.ts +0 -164
- package/src/tool/lsp.ts +0 -115
- package/src/tool/lsp.txt +0 -24
- package/src/tool/lsp.zh.txt +0 -24
- package/src/tool/mcp-websearch.ts +0 -96
- package/src/tool/plan-enter.txt +0 -14
- package/src/tool/plan-enter.zh.txt +0 -14
- package/src/tool/plan-exit.txt +0 -13
- package/src/tool/plan-exit.zh.txt +0 -13
- package/src/tool/plan.ts +0 -81
- package/src/tool/question.ts +0 -46
- package/src/tool/question.txt +0 -10
- package/src/tool/question.zh.txt +0 -10
- package/src/tool/read.ts +0 -388
- package/src/tool/read.txt +0 -14
- package/src/tool/read.zh.txt +0 -14
- package/src/tool/registry.ts +0 -440
- package/src/tool/schema.ts +0 -14
- package/src/tool/shell/id.ts +0 -19
- package/src/tool/shell/prompt.ts +0 -307
- package/src/tool/shell/shell.txt +0 -21
- package/src/tool/shell.ts +0 -657
- package/src/tool/skill.ts +0 -73
- package/src/tool/skill.txt +0 -5
- package/src/tool/skill.zh.txt +0 -5
- package/src/tool/task.ts +0 -348
- package/src/tool/task.txt +0 -19
- package/src/tool/task.zh.txt +0 -19
- package/src/tool/todo.ts +0 -59
- package/src/tool/todowrite.txt +0 -44
- package/src/tool/todowrite.zh.txt +0 -44
- package/src/tool/tool.ts +0 -183
- package/src/tool/truncate.ts +0 -158
- package/src/tool/truncation-dir.ts +0 -4
- package/src/tool/webfetch.ts +0 -194
- package/src/tool/webfetch.txt +0 -13
- package/src/tool/webfetch.zh.txt +0 -13
- package/src/tool/websearch.ts +0 -145
- package/src/tool/websearch.txt +0 -14
- package/src/tool/websearch.zh.txt +0 -14
- package/src/tool/write.ts +0 -106
- package/src/tool/write.txt +0 -8
- package/src/tool/write.zh.txt +0 -8
- package/src/util/archive.ts +0 -17
- package/src/util/bom.ts +0 -27
- package/src/util/data-url.ts +0 -9
- package/src/util/defer.ts +0 -10
- package/src/util/effect-http-client.ts +0 -11
- package/src/util/error.ts +0 -1
- package/src/util/filesystem.ts +0 -251
- package/src/util/html.ts +0 -8
- package/src/util/iife.ts +0 -3
- package/src/util/lazy.ts +0 -20
- package/src/util/local-context.ts +0 -25
- package/src/util/locale.ts +0 -2
- package/src/util/media.ts +0 -26
- package/src/util/process.ts +0 -177
- package/src/util/proxy-env.ts +0 -72
- package/src/util/queue.ts +0 -32
- package/src/util/record.ts +0 -1
- package/src/util/repository.ts +0 -232
- package/src/util/rpc.ts +0 -66
- package/src/util/signal.ts +0 -12
- package/src/util/timeout.ts +0 -13
- package/src/util/token.ts +0 -1
- package/src/util/wildcard.ts +0 -59
- package/src/worktree/index.ts +0 -654
package/src/lsp/server.ts
DELETED
|
@@ -1,1983 +0,0 @@
|
|
|
1
|
-
import type { ChildProcessWithoutNullStreams } from "child_process"
|
|
2
|
-
import path from "path"
|
|
3
|
-
import os from "os"
|
|
4
|
-
import { Global } from "@opencode-ai/core/global"
|
|
5
|
-
import { text } from "node:stream/consumers"
|
|
6
|
-
import fs from "fs/promises"
|
|
7
|
-
import { Filesystem } from "@/util/filesystem"
|
|
8
|
-
import type { InstanceContext } from "../project/instance-context"
|
|
9
|
-
import { Archive } from "@/util/archive"
|
|
10
|
-
import { Process } from "@/util/process"
|
|
11
|
-
import { which } from "@opencode-ai/core/util/which"
|
|
12
|
-
import { Module } from "@opencode-ai/core/util/module"
|
|
13
|
-
import { spawn } from "./launch"
|
|
14
|
-
import { Npm } from "@opencode-ai/core/npm"
|
|
15
|
-
import type { RuntimeFlags } from "@/effect/runtime-flags"
|
|
16
|
-
|
|
17
|
-
const pathExists = async (p: string) =>
|
|
18
|
-
fs
|
|
19
|
-
.stat(p)
|
|
20
|
-
.then(() => true)
|
|
21
|
-
.catch(() => false)
|
|
22
|
-
const run = (cmd: string[], opts: Process.RunOptions = {}) => Process.run(cmd, { ...opts, nothrow: true })
|
|
23
|
-
const output = (cmd: string[], opts: Process.RunOptions = {}) => Process.text(cmd, { ...opts, nothrow: true })
|
|
24
|
-
|
|
25
|
-
export interface Handle {
|
|
26
|
-
process: ChildProcessWithoutNullStreams
|
|
27
|
-
initialization?: Record<string, any>
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
type RootFunction = (file: string, ctx: InstanceContext) => Promise<string | undefined>
|
|
31
|
-
|
|
32
|
-
const NearestRoot = (includePatterns: string[], excludePatterns?: string[]): RootFunction => {
|
|
33
|
-
return async (file, ctx) => {
|
|
34
|
-
if (excludePatterns) {
|
|
35
|
-
const excludedFiles = Filesystem.up({
|
|
36
|
-
targets: excludePatterns,
|
|
37
|
-
start: path.dirname(file),
|
|
38
|
-
stop: ctx.directory,
|
|
39
|
-
})
|
|
40
|
-
const excluded = await excludedFiles.next()
|
|
41
|
-
await excludedFiles.return()
|
|
42
|
-
if (excluded.value) return undefined
|
|
43
|
-
}
|
|
44
|
-
const files = Filesystem.up({
|
|
45
|
-
targets: includePatterns,
|
|
46
|
-
start: path.dirname(file),
|
|
47
|
-
stop: ctx.directory,
|
|
48
|
-
})
|
|
49
|
-
const first = await files.next()
|
|
50
|
-
await files.return()
|
|
51
|
-
if (!first.value) return ctx.directory
|
|
52
|
-
return path.dirname(first.value)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const StrictNearestRoot = (includePatterns: string[], excludePatterns?: string[]): RootFunction => {
|
|
57
|
-
return async (file, ctx) => {
|
|
58
|
-
if (excludePatterns) {
|
|
59
|
-
const excludedFiles = Filesystem.up({
|
|
60
|
-
targets: excludePatterns,
|
|
61
|
-
start: path.dirname(file),
|
|
62
|
-
stop: ctx.directory,
|
|
63
|
-
})
|
|
64
|
-
const excluded = await excludedFiles.next()
|
|
65
|
-
await excludedFiles.return()
|
|
66
|
-
if (excluded.value) return undefined
|
|
67
|
-
}
|
|
68
|
-
const files = Filesystem.up({
|
|
69
|
-
targets: includePatterns,
|
|
70
|
-
start: path.dirname(file),
|
|
71
|
-
stop: ctx.directory,
|
|
72
|
-
})
|
|
73
|
-
const first = await files.next()
|
|
74
|
-
await files.return()
|
|
75
|
-
if (!first.value) return undefined
|
|
76
|
-
return path.dirname(first.value)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export interface Info {
|
|
81
|
-
id: string
|
|
82
|
-
extensions: string[]
|
|
83
|
-
global?: boolean
|
|
84
|
-
root: RootFunction
|
|
85
|
-
spawn(root: string, ctx: InstanceContext, flags: RuntimeFlags.Info): Promise<Handle | undefined>
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export const Deno: Info = {
|
|
89
|
-
id: "deno",
|
|
90
|
-
root: async (file, ctx) => {
|
|
91
|
-
const files = Filesystem.up({
|
|
92
|
-
targets: ["deno.json", "deno.jsonc"],
|
|
93
|
-
start: path.dirname(file),
|
|
94
|
-
stop: ctx.directory,
|
|
95
|
-
})
|
|
96
|
-
const first = await files.next()
|
|
97
|
-
await files.return()
|
|
98
|
-
if (!first.value) return undefined
|
|
99
|
-
return path.dirname(first.value)
|
|
100
|
-
},
|
|
101
|
-
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"],
|
|
102
|
-
async spawn(root) {
|
|
103
|
-
const deno = which("deno")
|
|
104
|
-
if (!deno) {
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
process: spawn(deno, ["lsp"], {
|
|
109
|
-
cwd: root,
|
|
110
|
-
}),
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export const Typescript: Info = {
|
|
116
|
-
id: "typescript",
|
|
117
|
-
root: NearestRoot(
|
|
118
|
-
["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"],
|
|
119
|
-
["deno.json", "deno.jsonc"],
|
|
120
|
-
),
|
|
121
|
-
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
|
|
122
|
-
async spawn(root, ctx) {
|
|
123
|
-
const tsserver = Module.resolve("typescript/lib/tsserver.js", ctx.directory)
|
|
124
|
-
if (!tsserver) return
|
|
125
|
-
const bin = await Npm.which("typescript-language-server")
|
|
126
|
-
if (!bin) return
|
|
127
|
-
const proc = spawn(bin, ["--stdio"], {
|
|
128
|
-
cwd: root,
|
|
129
|
-
env: {
|
|
130
|
-
...process.env,
|
|
131
|
-
},
|
|
132
|
-
})
|
|
133
|
-
return {
|
|
134
|
-
process: proc,
|
|
135
|
-
initialization: {
|
|
136
|
-
tsserver: {
|
|
137
|
-
path: tsserver,
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export const Vue: Info = {
|
|
145
|
-
id: "vue",
|
|
146
|
-
extensions: [".vue"],
|
|
147
|
-
root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]),
|
|
148
|
-
async spawn(root, _ctx, flags) {
|
|
149
|
-
let binary = which("vue-language-server")
|
|
150
|
-
const args: string[] = []
|
|
151
|
-
if (!binary) {
|
|
152
|
-
if (flags.disableLspDownload) return
|
|
153
|
-
const resolved = await Npm.which("@vue/language-server")
|
|
154
|
-
if (!resolved) return
|
|
155
|
-
binary = resolved
|
|
156
|
-
}
|
|
157
|
-
args.push("--stdio")
|
|
158
|
-
const proc = spawn(binary, args, {
|
|
159
|
-
cwd: root,
|
|
160
|
-
env: {
|
|
161
|
-
...process.env,
|
|
162
|
-
},
|
|
163
|
-
})
|
|
164
|
-
return {
|
|
165
|
-
process: proc,
|
|
166
|
-
initialization: {
|
|
167
|
-
// Leave empty; the server will auto-detect workspace TypeScript.
|
|
168
|
-
},
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export const ESLint: Info = {
|
|
174
|
-
id: "eslint",
|
|
175
|
-
root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]),
|
|
176
|
-
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"],
|
|
177
|
-
async spawn(root, ctx, flags) {
|
|
178
|
-
const eslint = Module.resolve("eslint", ctx.directory)
|
|
179
|
-
if (!eslint) return
|
|
180
|
-
const serverPath = path.join(Global.Path.bin, "vscode-eslint", "server", "out", "eslintServer.js")
|
|
181
|
-
if (!(await Filesystem.exists(serverPath))) {
|
|
182
|
-
if (flags.disableLspDownload) return
|
|
183
|
-
const response = await fetch("https://github.com/microsoft/vscode-eslint/archive/refs/heads/main.zip")
|
|
184
|
-
if (!response.ok) return
|
|
185
|
-
|
|
186
|
-
const zipPath = path.join(Global.Path.bin, "vscode-eslint.zip")
|
|
187
|
-
if (response.body) await Filesystem.writeStream(zipPath, response.body)
|
|
188
|
-
|
|
189
|
-
const ok = await Archive.extractZip(zipPath, Global.Path.bin)
|
|
190
|
-
.then(() => true)
|
|
191
|
-
.catch((error) => {
|
|
192
|
-
return false
|
|
193
|
-
})
|
|
194
|
-
if (!ok) return
|
|
195
|
-
await fs.rm(zipPath, { force: true })
|
|
196
|
-
|
|
197
|
-
const extractedPath = path.join(Global.Path.bin, "vscode-eslint-main")
|
|
198
|
-
const finalPath = path.join(Global.Path.bin, "vscode-eslint")
|
|
199
|
-
|
|
200
|
-
const stats = await fs.stat(finalPath).catch(() => undefined)
|
|
201
|
-
if (stats) {
|
|
202
|
-
await fs.rm(finalPath, { force: true, recursive: true })
|
|
203
|
-
}
|
|
204
|
-
await fs.rename(extractedPath, finalPath)
|
|
205
|
-
|
|
206
|
-
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm"
|
|
207
|
-
await Process.run([npmCmd, "install"], { cwd: finalPath })
|
|
208
|
-
await Process.run([npmCmd, "run", "compile"], { cwd: finalPath })
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const proc = spawn("node", [serverPath, "--stdio"], {
|
|
212
|
-
cwd: root,
|
|
213
|
-
env: {
|
|
214
|
-
...process.env,
|
|
215
|
-
},
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
process: proc,
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export const Oxlint: Info = {
|
|
225
|
-
id: "oxlint",
|
|
226
|
-
root: NearestRoot([
|
|
227
|
-
".oxlintrc.json",
|
|
228
|
-
"package-lock.json",
|
|
229
|
-
"bun.lockb",
|
|
230
|
-
"bun.lock",
|
|
231
|
-
"pnpm-lock.yaml",
|
|
232
|
-
"yarn.lock",
|
|
233
|
-
"package.json",
|
|
234
|
-
]),
|
|
235
|
-
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue", ".astro", ".svelte"],
|
|
236
|
-
async spawn(root, ctx) {
|
|
237
|
-
const ext = process.platform === "win32" ? ".cmd" : ""
|
|
238
|
-
|
|
239
|
-
const serverTarget = path.join("node_modules", ".bin", "oxc_language_server" + ext)
|
|
240
|
-
const lintTarget = path.join("node_modules", ".bin", "oxlint" + ext)
|
|
241
|
-
|
|
242
|
-
const resolveBin = async (target: string) => {
|
|
243
|
-
const localBin = path.join(root, target)
|
|
244
|
-
if (await Filesystem.exists(localBin)) return localBin
|
|
245
|
-
|
|
246
|
-
const candidates = Filesystem.up({
|
|
247
|
-
targets: [target],
|
|
248
|
-
start: root,
|
|
249
|
-
stop: ctx.worktree,
|
|
250
|
-
})
|
|
251
|
-
const first = await candidates.next()
|
|
252
|
-
await candidates.return()
|
|
253
|
-
if (first.value) return first.value
|
|
254
|
-
|
|
255
|
-
return undefined
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
let lintBin = await resolveBin(lintTarget)
|
|
259
|
-
if (!lintBin) {
|
|
260
|
-
const found = which("oxlint")
|
|
261
|
-
if (found) lintBin = found
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (lintBin) {
|
|
265
|
-
const proc = spawn(lintBin, ["--help"])
|
|
266
|
-
await proc.exited
|
|
267
|
-
if (proc.stdout) {
|
|
268
|
-
const help = await text(proc.stdout)
|
|
269
|
-
if (help.includes("--lsp")) {
|
|
270
|
-
return {
|
|
271
|
-
process: spawn(lintBin, ["--lsp"], {
|
|
272
|
-
cwd: root,
|
|
273
|
-
}),
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
let serverBin = await resolveBin(serverTarget)
|
|
280
|
-
if (!serverBin) {
|
|
281
|
-
const found = which("oxc_language_server")
|
|
282
|
-
if (found) serverBin = found
|
|
283
|
-
}
|
|
284
|
-
if (serverBin) {
|
|
285
|
-
return {
|
|
286
|
-
process: spawn(serverBin, [], {
|
|
287
|
-
cwd: root,
|
|
288
|
-
}),
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
return
|
|
293
|
-
},
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export const Biome: Info = {
|
|
297
|
-
id: "biome",
|
|
298
|
-
root: NearestRoot([
|
|
299
|
-
"biome.json",
|
|
300
|
-
"biome.jsonc",
|
|
301
|
-
"package-lock.json",
|
|
302
|
-
"bun.lockb",
|
|
303
|
-
"bun.lock",
|
|
304
|
-
"pnpm-lock.yaml",
|
|
305
|
-
"yarn.lock",
|
|
306
|
-
]),
|
|
307
|
-
extensions: [
|
|
308
|
-
".ts",
|
|
309
|
-
".tsx",
|
|
310
|
-
".js",
|
|
311
|
-
".jsx",
|
|
312
|
-
".mjs",
|
|
313
|
-
".cjs",
|
|
314
|
-
".mts",
|
|
315
|
-
".cts",
|
|
316
|
-
".json",
|
|
317
|
-
".jsonc",
|
|
318
|
-
".vue",
|
|
319
|
-
".astro",
|
|
320
|
-
".svelte",
|
|
321
|
-
".css",
|
|
322
|
-
".graphql",
|
|
323
|
-
".gql",
|
|
324
|
-
".html",
|
|
325
|
-
],
|
|
326
|
-
async spawn(root) {
|
|
327
|
-
const localBin = path.join(root, "node_modules", ".bin", "biome")
|
|
328
|
-
let bin: string | undefined
|
|
329
|
-
if (await Filesystem.exists(localBin)) bin = localBin
|
|
330
|
-
if (!bin) {
|
|
331
|
-
const found = which("biome")
|
|
332
|
-
if (found) bin = found
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
let args = ["lsp-proxy", "--stdio"]
|
|
336
|
-
|
|
337
|
-
if (!bin) {
|
|
338
|
-
const resolved = Module.resolve("biome", root)
|
|
339
|
-
if (!resolved) return
|
|
340
|
-
bin = await Npm.which("biome")
|
|
341
|
-
if (!bin) return
|
|
342
|
-
args = ["lsp-proxy", "--stdio"]
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const proc = spawn(bin, args, {
|
|
346
|
-
cwd: root,
|
|
347
|
-
env: {
|
|
348
|
-
...process.env,
|
|
349
|
-
},
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
return {
|
|
353
|
-
process: proc,
|
|
354
|
-
}
|
|
355
|
-
},
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
export const Gopls: Info = {
|
|
359
|
-
id: "gopls",
|
|
360
|
-
root: async (file, ctx) => {
|
|
361
|
-
const work = await NearestRoot(["go.work"])(file, ctx)
|
|
362
|
-
if (work) return work
|
|
363
|
-
return NearestRoot(["go.mod", "go.sum"])(file, ctx)
|
|
364
|
-
},
|
|
365
|
-
extensions: [".go"],
|
|
366
|
-
async spawn(root, _ctx, flags) {
|
|
367
|
-
let bin = which("gopls")
|
|
368
|
-
if (!bin) {
|
|
369
|
-
if (!which("go")) return
|
|
370
|
-
if (flags.disableLspDownload) return
|
|
371
|
-
|
|
372
|
-
const proc = Process.spawn(["go", "install", "golang.org/x/tools/gopls@latest"], {
|
|
373
|
-
env: { ...process.env, GOBIN: Global.Path.bin },
|
|
374
|
-
stdout: "pipe",
|
|
375
|
-
stderr: "pipe",
|
|
376
|
-
stdin: "pipe",
|
|
377
|
-
})
|
|
378
|
-
const exit = await proc.exited
|
|
379
|
-
if (exit !== 0) {
|
|
380
|
-
return
|
|
381
|
-
}
|
|
382
|
-
bin = path.join(Global.Path.bin, "gopls" + (process.platform === "win32" ? ".exe" : ""))
|
|
383
|
-
}
|
|
384
|
-
return {
|
|
385
|
-
process: spawn(bin!, {
|
|
386
|
-
cwd: root,
|
|
387
|
-
}),
|
|
388
|
-
}
|
|
389
|
-
},
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
export const Rubocop: Info = {
|
|
393
|
-
id: "ruby-lsp",
|
|
394
|
-
root: NearestRoot(["Gemfile"]),
|
|
395
|
-
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
|
396
|
-
async spawn(root, _ctx, flags) {
|
|
397
|
-
let bin = which("rubocop")
|
|
398
|
-
if (!bin) {
|
|
399
|
-
const ruby = which("ruby")
|
|
400
|
-
const gem = which("gem")
|
|
401
|
-
if (!ruby || !gem) {
|
|
402
|
-
return
|
|
403
|
-
}
|
|
404
|
-
if (flags.disableLspDownload) return
|
|
405
|
-
const proc = Process.spawn(["gem", "install", "rubocop", "--bindir", Global.Path.bin], {
|
|
406
|
-
stdout: "pipe",
|
|
407
|
-
stderr: "pipe",
|
|
408
|
-
stdin: "pipe",
|
|
409
|
-
})
|
|
410
|
-
const exit = await proc.exited
|
|
411
|
-
if (exit !== 0) {
|
|
412
|
-
return
|
|
413
|
-
}
|
|
414
|
-
bin = path.join(Global.Path.bin, "rubocop" + (process.platform === "win32" ? ".exe" : ""))
|
|
415
|
-
}
|
|
416
|
-
return {
|
|
417
|
-
process: spawn(bin!, ["--lsp"], {
|
|
418
|
-
cwd: root,
|
|
419
|
-
}),
|
|
420
|
-
}
|
|
421
|
-
},
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
export const Ty: Info = {
|
|
425
|
-
id: "ty",
|
|
426
|
-
extensions: [".py", ".pyi"],
|
|
427
|
-
root: NearestRoot([
|
|
428
|
-
"pyproject.toml",
|
|
429
|
-
"ty.toml",
|
|
430
|
-
"setup.py",
|
|
431
|
-
"setup.cfg",
|
|
432
|
-
"requirements.txt",
|
|
433
|
-
"Pipfile",
|
|
434
|
-
"pyrightconfig.json",
|
|
435
|
-
]),
|
|
436
|
-
async spawn(root, _ctx, flags) {
|
|
437
|
-
if (!flags.experimentalLspTy) {
|
|
438
|
-
return undefined
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
let binary = which("ty")
|
|
442
|
-
|
|
443
|
-
const initialization: Record<string, string> = {}
|
|
444
|
-
|
|
445
|
-
const potentialVenvPaths = [process.env["VIRTUAL_ENV"], path.join(root, ".venv"), path.join(root, "venv")].filter(
|
|
446
|
-
(p): p is string => p !== undefined,
|
|
447
|
-
)
|
|
448
|
-
for (const venvPath of potentialVenvPaths) {
|
|
449
|
-
const isWindows = process.platform === "win32"
|
|
450
|
-
const potentialPythonPath = isWindows
|
|
451
|
-
? path.join(venvPath, "Scripts", "python.exe")
|
|
452
|
-
: path.join(venvPath, "bin", "python")
|
|
453
|
-
if (await Filesystem.exists(potentialPythonPath)) {
|
|
454
|
-
initialization["pythonPath"] = potentialPythonPath
|
|
455
|
-
break
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (!binary) {
|
|
460
|
-
for (const venvPath of potentialVenvPaths) {
|
|
461
|
-
const isWindows = process.platform === "win32"
|
|
462
|
-
const potentialTyPath = isWindows ? path.join(venvPath, "Scripts", "ty.exe") : path.join(venvPath, "bin", "ty")
|
|
463
|
-
if (await Filesystem.exists(potentialTyPath)) {
|
|
464
|
-
binary = potentialTyPath
|
|
465
|
-
break
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (!binary) {
|
|
471
|
-
return
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
const proc = spawn(binary, ["server"], {
|
|
475
|
-
cwd: root,
|
|
476
|
-
})
|
|
477
|
-
|
|
478
|
-
return {
|
|
479
|
-
process: proc,
|
|
480
|
-
initialization,
|
|
481
|
-
}
|
|
482
|
-
},
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
export const Pyright: Info = {
|
|
486
|
-
id: "pyright",
|
|
487
|
-
extensions: [".py", ".pyi"],
|
|
488
|
-
root: NearestRoot(["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "pyrightconfig.json"]),
|
|
489
|
-
async spawn(root, _ctx, flags) {
|
|
490
|
-
let binary = which("pyright-langserver")
|
|
491
|
-
const args = []
|
|
492
|
-
if (!binary) {
|
|
493
|
-
if (flags.disableLspDownload) return
|
|
494
|
-
const resolved = await Npm.which("pyright", "pyright-langserver")
|
|
495
|
-
if (!resolved) return
|
|
496
|
-
binary = resolved
|
|
497
|
-
}
|
|
498
|
-
args.push("--stdio")
|
|
499
|
-
|
|
500
|
-
const initialization: Record<string, string> = {}
|
|
501
|
-
|
|
502
|
-
const potentialVenvPaths = [process.env["VIRTUAL_ENV"], path.join(root, ".venv"), path.join(root, "venv")].filter(
|
|
503
|
-
(p): p is string => p !== undefined,
|
|
504
|
-
)
|
|
505
|
-
for (const venvPath of potentialVenvPaths) {
|
|
506
|
-
const isWindows = process.platform === "win32"
|
|
507
|
-
const potentialPythonPath = isWindows
|
|
508
|
-
? path.join(venvPath, "Scripts", "python.exe")
|
|
509
|
-
: path.join(venvPath, "bin", "python")
|
|
510
|
-
if (await Filesystem.exists(potentialPythonPath)) {
|
|
511
|
-
initialization["pythonPath"] = potentialPythonPath
|
|
512
|
-
break
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const proc = spawn(binary, args, {
|
|
517
|
-
cwd: root,
|
|
518
|
-
env: {
|
|
519
|
-
...process.env,
|
|
520
|
-
},
|
|
521
|
-
})
|
|
522
|
-
return {
|
|
523
|
-
process: proc,
|
|
524
|
-
initialization,
|
|
525
|
-
}
|
|
526
|
-
},
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
export const ElixirLS: Info = {
|
|
530
|
-
id: "elixir-ls",
|
|
531
|
-
extensions: [".ex", ".exs"],
|
|
532
|
-
root: NearestRoot(["mix.exs", "mix.lock"]),
|
|
533
|
-
async spawn(root, _ctx, flags) {
|
|
534
|
-
let binary = which("elixir-ls")
|
|
535
|
-
if (!binary) {
|
|
536
|
-
const elixirLsPath = path.join(Global.Path.bin, "elixir-ls")
|
|
537
|
-
binary = path.join(
|
|
538
|
-
Global.Path.bin,
|
|
539
|
-
"elixir-ls-master",
|
|
540
|
-
"release",
|
|
541
|
-
process.platform === "win32" ? "language_server.bat" : "language_server.sh",
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
if (!(await Filesystem.exists(binary))) {
|
|
545
|
-
const elixir = which("elixir")
|
|
546
|
-
if (!elixir) {
|
|
547
|
-
return
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
if (flags.disableLspDownload) return
|
|
551
|
-
|
|
552
|
-
const response = await fetch("https://github.com/elixir-lsp/elixir-ls/archive/refs/heads/master.zip")
|
|
553
|
-
if (!response.ok) return
|
|
554
|
-
const zipPath = path.join(Global.Path.bin, "elixir-ls.zip")
|
|
555
|
-
if (response.body) await Filesystem.writeStream(zipPath, response.body)
|
|
556
|
-
|
|
557
|
-
const ok = await Archive.extractZip(zipPath, Global.Path.bin)
|
|
558
|
-
.then(() => true)
|
|
559
|
-
.catch((error) => {
|
|
560
|
-
return false
|
|
561
|
-
})
|
|
562
|
-
if (!ok) return
|
|
563
|
-
|
|
564
|
-
await fs.rm(zipPath, {
|
|
565
|
-
force: true,
|
|
566
|
-
recursive: true,
|
|
567
|
-
})
|
|
568
|
-
|
|
569
|
-
const cwd = path.join(Global.Path.bin, "elixir-ls-master")
|
|
570
|
-
const env = { MIX_ENV: "prod", ...process.env }
|
|
571
|
-
await Process.run(["mix", "deps.get"], { cwd, env })
|
|
572
|
-
await Process.run(["mix", "compile"], { cwd, env })
|
|
573
|
-
await Process.run(["mix", "elixir_ls.release2", "-o", "release"], { cwd, env })
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
return {
|
|
578
|
-
process: spawn(binary, {
|
|
579
|
-
cwd: root,
|
|
580
|
-
}),
|
|
581
|
-
}
|
|
582
|
-
},
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
export const Zls: Info = {
|
|
586
|
-
id: "zls",
|
|
587
|
-
extensions: [".zig", ".zon"],
|
|
588
|
-
root: NearestRoot(["build.zig"]),
|
|
589
|
-
async spawn(root, _ctx, flags) {
|
|
590
|
-
let bin = which("zls")
|
|
591
|
-
|
|
592
|
-
if (!bin) {
|
|
593
|
-
const zig = which("zig")
|
|
594
|
-
if (!zig) {
|
|
595
|
-
return
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
if (flags.disableLspDownload) return
|
|
599
|
-
|
|
600
|
-
const releaseResponse = await fetch("https://api.github.com/repos/zigtools/zls/releases/latest")
|
|
601
|
-
if (!releaseResponse.ok) {
|
|
602
|
-
return
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
const release = (await releaseResponse.json()) as {
|
|
606
|
-
assets?: { name?: string; browser_download_url?: string }[]
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
const platform = process.platform
|
|
610
|
-
const arch = process.arch
|
|
611
|
-
let assetName = ""
|
|
612
|
-
|
|
613
|
-
let zlsArch: string = arch
|
|
614
|
-
if (arch === "arm64") zlsArch = "aarch64"
|
|
615
|
-
else if (arch === "x64") zlsArch = "x86_64"
|
|
616
|
-
else if (arch === "ia32") zlsArch = "x86"
|
|
617
|
-
|
|
618
|
-
let zlsPlatform: string = platform
|
|
619
|
-
if (platform === "darwin") zlsPlatform = "macos"
|
|
620
|
-
else if (platform === "win32") zlsPlatform = "windows"
|
|
621
|
-
|
|
622
|
-
const ext = platform === "win32" ? "zip" : "tar.xz"
|
|
623
|
-
|
|
624
|
-
assetName = `zls-${zlsArch}-${zlsPlatform}.${ext}`
|
|
625
|
-
|
|
626
|
-
const supportedCombos = [
|
|
627
|
-
"zls-x86_64-linux.tar.xz",
|
|
628
|
-
"zls-x86_64-macos.tar.xz",
|
|
629
|
-
"zls-x86_64-windows.zip",
|
|
630
|
-
"zls-aarch64-linux.tar.xz",
|
|
631
|
-
"zls-aarch64-macos.tar.xz",
|
|
632
|
-
"zls-aarch64-windows.zip",
|
|
633
|
-
"zls-x86-linux.tar.xz",
|
|
634
|
-
"zls-x86-windows.zip",
|
|
635
|
-
]
|
|
636
|
-
|
|
637
|
-
if (!supportedCombos.includes(assetName)) {
|
|
638
|
-
return
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
const asset = release.assets?.find((a) => a.name === assetName)
|
|
642
|
-
if (!asset?.browser_download_url) {
|
|
643
|
-
return
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
const downloadUrl = asset.browser_download_url
|
|
647
|
-
const downloadResponse = await fetch(downloadUrl)
|
|
648
|
-
if (!downloadResponse.ok) {
|
|
649
|
-
return
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
const tempPath = path.join(Global.Path.bin, assetName)
|
|
653
|
-
if (downloadResponse.body) await Filesystem.writeStream(tempPath, downloadResponse.body)
|
|
654
|
-
|
|
655
|
-
if (ext === "zip") {
|
|
656
|
-
const ok = await Archive.extractZip(tempPath, Global.Path.bin)
|
|
657
|
-
.then(() => true)
|
|
658
|
-
.catch((error) => {
|
|
659
|
-
return false
|
|
660
|
-
})
|
|
661
|
-
if (!ok) return
|
|
662
|
-
} else {
|
|
663
|
-
await run(["tar", "-xf", tempPath], { cwd: Global.Path.bin })
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
await fs.rm(tempPath, { force: true })
|
|
667
|
-
|
|
668
|
-
bin = path.join(Global.Path.bin, "zls" + (platform === "win32" ? ".exe" : ""))
|
|
669
|
-
|
|
670
|
-
if (!(await Filesystem.exists(bin))) {
|
|
671
|
-
return
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
if (platform !== "win32") {
|
|
675
|
-
await fs.chmod(bin, 0o755).catch(() => {})
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
return {
|
|
680
|
-
process: spawn(bin, {
|
|
681
|
-
cwd: root,
|
|
682
|
-
}),
|
|
683
|
-
}
|
|
684
|
-
},
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
export const CSharp: Info = {
|
|
688
|
-
id: "csharp",
|
|
689
|
-
root: NearestRoot([".slnx", ".sln", ".csproj", "global.json"]),
|
|
690
|
-
extensions: [".cs", ".csx"],
|
|
691
|
-
async spawn(root, _ctx, flags) {
|
|
692
|
-
const bin = await getRoslynLanguageServer(flags.disableLspDownload)
|
|
693
|
-
if (!bin) return
|
|
694
|
-
|
|
695
|
-
return {
|
|
696
|
-
process: spawn(bin, ["--stdio", "--autoLoadProjects"], {
|
|
697
|
-
cwd: root,
|
|
698
|
-
}),
|
|
699
|
-
}
|
|
700
|
-
},
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
export const Razor: Info = {
|
|
704
|
-
id: "razor",
|
|
705
|
-
root: NearestRoot([".slnx", ".sln", ".csproj", "global.json"]),
|
|
706
|
-
extensions: [".razor", ".cshtml"],
|
|
707
|
-
async spawn(root, _ctx, flags) {
|
|
708
|
-
const bin = await getRoslynLanguageServer(flags.disableLspDownload)
|
|
709
|
-
if (!bin) return
|
|
710
|
-
|
|
711
|
-
const razor = await findVscodeRazorExtension()
|
|
712
|
-
if (!razor) {
|
|
713
|
-
return
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
return {
|
|
717
|
-
process: spawn(
|
|
718
|
-
bin,
|
|
719
|
-
[
|
|
720
|
-
"--stdio",
|
|
721
|
-
"--autoLoadProjects",
|
|
722
|
-
`--razorSourceGenerator=${razor.compiler}`,
|
|
723
|
-
`--razorDesignTimePath=${razor.targets}`,
|
|
724
|
-
"--extension",
|
|
725
|
-
razor.extension,
|
|
726
|
-
],
|
|
727
|
-
{
|
|
728
|
-
cwd: root,
|
|
729
|
-
},
|
|
730
|
-
),
|
|
731
|
-
}
|
|
732
|
-
},
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
let roslynLanguageServerInstall: Promise<string | undefined> | undefined
|
|
736
|
-
|
|
737
|
-
async function getRoslynLanguageServer(disableLspDownload: boolean) {
|
|
738
|
-
const existing = which("roslyn-language-server")
|
|
739
|
-
if (existing) return existing
|
|
740
|
-
|
|
741
|
-
const global = await roslynLanguageServerGlobalPath()
|
|
742
|
-
if (global) return global
|
|
743
|
-
|
|
744
|
-
roslynLanguageServerInstall ||= installRoslynLanguageServer(disableLspDownload).finally(() => {
|
|
745
|
-
roslynLanguageServerInstall = undefined
|
|
746
|
-
})
|
|
747
|
-
return roslynLanguageServerInstall
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
async function installRoslynLanguageServer(disableLspDownload: boolean) {
|
|
751
|
-
if (!which("dotnet")) {
|
|
752
|
-
return
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
if (disableLspDownload) return
|
|
756
|
-
const proc = Process.spawn(["dotnet", "tool", "install", "--global", "roslyn-language-server", "--prerelease"], {
|
|
757
|
-
stdout: "pipe",
|
|
758
|
-
stderr: "pipe",
|
|
759
|
-
stdin: "pipe",
|
|
760
|
-
})
|
|
761
|
-
const exit = await proc.exited
|
|
762
|
-
if (exit !== 0) {
|
|
763
|
-
return
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
const resolved = which("roslyn-language-server")
|
|
767
|
-
if (resolved) {
|
|
768
|
-
return resolved
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
const global = await roslynLanguageServerGlobalPath()
|
|
772
|
-
if (global) {
|
|
773
|
-
return global
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
async function roslynLanguageServerGlobalPath() {
|
|
778
|
-
const bin = path.join(
|
|
779
|
-
process.env.DOTNET_CLI_HOME ?? os.homedir(),
|
|
780
|
-
".dotnet",
|
|
781
|
-
"tools",
|
|
782
|
-
"roslyn-language-server" + (process.platform === "win32" ? ".cmd" : ""),
|
|
783
|
-
)
|
|
784
|
-
return (await pathExists(bin)) ? bin : undefined
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
async function findVscodeRazorExtension() {
|
|
788
|
-
const roots = [
|
|
789
|
-
process.env.VSCODE_EXTENSIONS,
|
|
790
|
-
path.join(os.homedir(), ".vscode", "extensions"),
|
|
791
|
-
path.join(os.homedir(), ".vscode-insiders", "extensions"),
|
|
792
|
-
path.join(os.homedir(), ".vscode-server", "extensions"),
|
|
793
|
-
path.join(os.homedir(), ".vscode-server-insiders", "extensions"),
|
|
794
|
-
].filter((item) => item !== undefined)
|
|
795
|
-
|
|
796
|
-
for (const root of [...new Set(roots)]) {
|
|
797
|
-
const entries = await fs.readdir(root, { withFileTypes: true }).catch(() => [])
|
|
798
|
-
const candidates = await Promise.all(
|
|
799
|
-
entries
|
|
800
|
-
.filter((entry) => entry.isDirectory() && entry.name.startsWith("ms-dotnettools.csharp-"))
|
|
801
|
-
.map(async (entry) => ({
|
|
802
|
-
path: path.join(root, entry.name, ".razorExtension"),
|
|
803
|
-
modified: (await fs.stat(path.join(root, entry.name)).catch(() => undefined))?.mtimeMs ?? 0,
|
|
804
|
-
})),
|
|
805
|
-
)
|
|
806
|
-
for (const entry of candidates.sort((a, b) => b.modified - a.modified).map((candidate) => candidate.path)) {
|
|
807
|
-
const result = {
|
|
808
|
-
compiler: path.join(entry, "Microsoft.CodeAnalysis.Razor.Compiler.dll"),
|
|
809
|
-
targets: path.join(entry, "Targets", "Microsoft.NET.Sdk.Razor.DesignTime.targets"),
|
|
810
|
-
extension: path.join(entry, "Microsoft.VisualStudioCode.RazorExtension.dll"),
|
|
811
|
-
}
|
|
812
|
-
if (
|
|
813
|
-
(await pathExists(result.compiler)) &&
|
|
814
|
-
(await pathExists(result.targets)) &&
|
|
815
|
-
(await pathExists(result.extension))
|
|
816
|
-
) {
|
|
817
|
-
return result
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
export const FSharp: Info = {
|
|
824
|
-
id: "fsharp",
|
|
825
|
-
root: NearestRoot([".slnx", ".sln", ".fsproj", "global.json"]),
|
|
826
|
-
extensions: [".fs", ".fsi", ".fsx", ".fsscript"],
|
|
827
|
-
async spawn(root, _ctx, flags) {
|
|
828
|
-
let bin = which("fsautocomplete")
|
|
829
|
-
if (!bin) {
|
|
830
|
-
if (!which("dotnet")) {
|
|
831
|
-
return
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
if (flags.disableLspDownload) return
|
|
835
|
-
const proc = Process.spawn(["dotnet", "tool", "install", "fsautocomplete", "--tool-path", Global.Path.bin], {
|
|
836
|
-
stdout: "pipe",
|
|
837
|
-
stderr: "pipe",
|
|
838
|
-
stdin: "pipe",
|
|
839
|
-
})
|
|
840
|
-
const exit = await proc.exited
|
|
841
|
-
if (exit !== 0) {
|
|
842
|
-
return
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
bin = path.join(Global.Path.bin, "fsautocomplete" + (process.platform === "win32" ? ".exe" : ""))
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
return {
|
|
849
|
-
process: spawn(bin, {
|
|
850
|
-
cwd: root,
|
|
851
|
-
}),
|
|
852
|
-
}
|
|
853
|
-
},
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
export const SourceKit: Info = {
|
|
857
|
-
id: "sourcekit-lsp",
|
|
858
|
-
extensions: [".swift", ".objc", "objcpp"],
|
|
859
|
-
root: NearestRoot(["Package.swift", "*.xcodeproj", "*.xcworkspace"]),
|
|
860
|
-
async spawn(root) {
|
|
861
|
-
// Check if sourcekit-lsp is available in the PATH
|
|
862
|
-
// This is installed with the Swift toolchain
|
|
863
|
-
const sourcekit = which("sourcekit-lsp")
|
|
864
|
-
if (sourcekit) {
|
|
865
|
-
return {
|
|
866
|
-
process: spawn(sourcekit, {
|
|
867
|
-
cwd: root,
|
|
868
|
-
}),
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// If sourcekit-lsp not found, check if xcrun is available
|
|
873
|
-
// This is specific to macOS where sourcekit-lsp is typically installed with Xcode
|
|
874
|
-
if (!which("xcrun")) return
|
|
875
|
-
|
|
876
|
-
const lspLoc = await output(["xcrun", "--find", "sourcekit-lsp"])
|
|
877
|
-
|
|
878
|
-
if (lspLoc.code !== 0) return
|
|
879
|
-
|
|
880
|
-
const bin = lspLoc.text.trim()
|
|
881
|
-
|
|
882
|
-
return {
|
|
883
|
-
process: spawn(bin, {
|
|
884
|
-
cwd: root,
|
|
885
|
-
}),
|
|
886
|
-
}
|
|
887
|
-
},
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
export const RustAnalyzer: Info = {
|
|
891
|
-
id: "rust",
|
|
892
|
-
root: async (file, ctx) => {
|
|
893
|
-
const crateRoot = await NearestRoot(["Cargo.toml", "Cargo.lock"])(file, ctx)
|
|
894
|
-
if (crateRoot === undefined) {
|
|
895
|
-
return undefined
|
|
896
|
-
}
|
|
897
|
-
let currentDir = crateRoot
|
|
898
|
-
|
|
899
|
-
while (currentDir !== path.dirname(currentDir)) {
|
|
900
|
-
// Stop at filesystem root
|
|
901
|
-
const cargoTomlPath = path.join(currentDir, "Cargo.toml")
|
|
902
|
-
try {
|
|
903
|
-
const cargoTomlContent = await Filesystem.readText(cargoTomlPath)
|
|
904
|
-
if (cargoTomlContent.includes("[workspace]")) {
|
|
905
|
-
return currentDir
|
|
906
|
-
}
|
|
907
|
-
} catch {
|
|
908
|
-
// File doesn't exist or can't be read, continue searching up
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
const parentDir = path.dirname(currentDir)
|
|
912
|
-
if (parentDir === currentDir) break // Reached filesystem root
|
|
913
|
-
currentDir = parentDir
|
|
914
|
-
|
|
915
|
-
// Stop if we've gone above the app root
|
|
916
|
-
if (!currentDir.startsWith(ctx.worktree)) break
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
return crateRoot
|
|
920
|
-
},
|
|
921
|
-
extensions: [".rs"],
|
|
922
|
-
async spawn(root) {
|
|
923
|
-
const bin = which("rust-analyzer")
|
|
924
|
-
if (!bin) {
|
|
925
|
-
return
|
|
926
|
-
}
|
|
927
|
-
return {
|
|
928
|
-
process: spawn(bin, {
|
|
929
|
-
cwd: root,
|
|
930
|
-
}),
|
|
931
|
-
}
|
|
932
|
-
},
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
export const Clangd: Info = {
|
|
936
|
-
id: "clangd",
|
|
937
|
-
root: NearestRoot(["compile_commands.json", "compile_flags.txt", ".clangd"]),
|
|
938
|
-
extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"],
|
|
939
|
-
async spawn(root, _ctx, flags) {
|
|
940
|
-
const args = ["--background-index", "--clang-tidy"]
|
|
941
|
-
const fromPath = which("clangd")
|
|
942
|
-
if (fromPath) {
|
|
943
|
-
return {
|
|
944
|
-
process: spawn(fromPath, args, {
|
|
945
|
-
cwd: root,
|
|
946
|
-
}),
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
const ext = process.platform === "win32" ? ".exe" : ""
|
|
951
|
-
const direct = path.join(Global.Path.bin, "clangd" + ext)
|
|
952
|
-
if (await Filesystem.exists(direct)) {
|
|
953
|
-
return {
|
|
954
|
-
process: spawn(direct, args, {
|
|
955
|
-
cwd: root,
|
|
956
|
-
}),
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
const entries = await fs.readdir(Global.Path.bin, { withFileTypes: true }).catch(() => [])
|
|
961
|
-
for (const entry of entries) {
|
|
962
|
-
if (!entry.isDirectory()) continue
|
|
963
|
-
if (!entry.name.startsWith("clangd_")) continue
|
|
964
|
-
const candidate = path.join(Global.Path.bin, entry.name, "bin", "clangd" + ext)
|
|
965
|
-
if (await Filesystem.exists(candidate)) {
|
|
966
|
-
return {
|
|
967
|
-
process: spawn(candidate, args, {
|
|
968
|
-
cwd: root,
|
|
969
|
-
}),
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
if (flags.disableLspDownload) return
|
|
975
|
-
|
|
976
|
-
const releaseResponse = await fetch("https://api.github.com/repos/clangd/clangd/releases/latest")
|
|
977
|
-
if (!releaseResponse.ok) {
|
|
978
|
-
return
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
const release: {
|
|
982
|
-
tag_name?: string
|
|
983
|
-
assets?: { name?: string; browser_download_url?: string }[]
|
|
984
|
-
} = await releaseResponse.json()
|
|
985
|
-
|
|
986
|
-
const tag = release.tag_name
|
|
987
|
-
if (!tag) {
|
|
988
|
-
return
|
|
989
|
-
}
|
|
990
|
-
const platform = process.platform
|
|
991
|
-
const tokens: Record<string, string> = {
|
|
992
|
-
darwin: "mac",
|
|
993
|
-
linux: "linux",
|
|
994
|
-
win32: "windows",
|
|
995
|
-
}
|
|
996
|
-
const token = tokens[platform]
|
|
997
|
-
if (!token) {
|
|
998
|
-
return
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
const assets = release.assets ?? []
|
|
1002
|
-
const valid = (item: { name?: string; browser_download_url?: string }) => {
|
|
1003
|
-
if (!item.name) return false
|
|
1004
|
-
if (!item.browser_download_url) return false
|
|
1005
|
-
if (!item.name.includes(token)) return false
|
|
1006
|
-
return item.name.includes(tag)
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
const asset =
|
|
1010
|
-
assets.find((item) => valid(item) && item.name?.endsWith(".zip")) ??
|
|
1011
|
-
assets.find((item) => valid(item) && item.name?.endsWith(".tar.xz")) ??
|
|
1012
|
-
assets.find((item) => valid(item))
|
|
1013
|
-
if (!asset?.name || !asset.browser_download_url) {
|
|
1014
|
-
return
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
const name = asset.name
|
|
1018
|
-
const downloadResponse = await fetch(asset.browser_download_url)
|
|
1019
|
-
if (!downloadResponse.ok) {
|
|
1020
|
-
return
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
const archive = path.join(Global.Path.bin, name)
|
|
1024
|
-
const buf = await downloadResponse.arrayBuffer()
|
|
1025
|
-
if (buf.byteLength === 0) {
|
|
1026
|
-
return
|
|
1027
|
-
}
|
|
1028
|
-
await Filesystem.write(archive, Buffer.from(buf))
|
|
1029
|
-
|
|
1030
|
-
const zip = name.endsWith(".zip")
|
|
1031
|
-
const tar = name.endsWith(".tar.xz")
|
|
1032
|
-
if (!zip && !tar) {
|
|
1033
|
-
return
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
if (zip) {
|
|
1037
|
-
const ok = await Archive.extractZip(archive, Global.Path.bin)
|
|
1038
|
-
.then(() => true)
|
|
1039
|
-
.catch((error) => {
|
|
1040
|
-
return false
|
|
1041
|
-
})
|
|
1042
|
-
if (!ok) return
|
|
1043
|
-
}
|
|
1044
|
-
if (tar) {
|
|
1045
|
-
await run(["tar", "-xf", archive], { cwd: Global.Path.bin })
|
|
1046
|
-
}
|
|
1047
|
-
await fs.rm(archive, { force: true })
|
|
1048
|
-
|
|
1049
|
-
const bin = path.join(Global.Path.bin, "clangd_" + tag, "bin", "clangd" + ext)
|
|
1050
|
-
if (!(await Filesystem.exists(bin))) {
|
|
1051
|
-
return
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
if (platform !== "win32") {
|
|
1055
|
-
await fs.chmod(bin, 0o755).catch(() => {})
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
await fs.unlink(path.join(Global.Path.bin, "clangd")).catch(() => {})
|
|
1059
|
-
await fs.symlink(bin, path.join(Global.Path.bin, "clangd")).catch(() => {})
|
|
1060
|
-
|
|
1061
|
-
return {
|
|
1062
|
-
process: spawn(bin, args, {
|
|
1063
|
-
cwd: root,
|
|
1064
|
-
}),
|
|
1065
|
-
}
|
|
1066
|
-
},
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
export const Svelte: Info = {
|
|
1070
|
-
id: "svelte",
|
|
1071
|
-
extensions: [".svelte"],
|
|
1072
|
-
root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]),
|
|
1073
|
-
async spawn(root, _ctx, flags) {
|
|
1074
|
-
let binary = which("svelteserver")
|
|
1075
|
-
const args: string[] = []
|
|
1076
|
-
if (!binary) {
|
|
1077
|
-
if (flags.disableLspDownload) return
|
|
1078
|
-
const resolved = await Npm.which("svelte-language-server")
|
|
1079
|
-
if (!resolved) return
|
|
1080
|
-
binary = resolved
|
|
1081
|
-
}
|
|
1082
|
-
args.push("--stdio")
|
|
1083
|
-
const proc = spawn(binary, args, {
|
|
1084
|
-
cwd: root,
|
|
1085
|
-
env: {
|
|
1086
|
-
...process.env,
|
|
1087
|
-
},
|
|
1088
|
-
})
|
|
1089
|
-
return {
|
|
1090
|
-
process: proc,
|
|
1091
|
-
initialization: {},
|
|
1092
|
-
}
|
|
1093
|
-
},
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
export const Astro: Info = {
|
|
1097
|
-
id: "astro",
|
|
1098
|
-
extensions: [".astro"],
|
|
1099
|
-
root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]),
|
|
1100
|
-
async spawn(root, ctx, flags) {
|
|
1101
|
-
const tsserver = Module.resolve("typescript/lib/tsserver.js", ctx.directory)
|
|
1102
|
-
if (!tsserver) {
|
|
1103
|
-
return
|
|
1104
|
-
}
|
|
1105
|
-
const tsdk = path.dirname(tsserver)
|
|
1106
|
-
|
|
1107
|
-
let binary = which("astro-ls")
|
|
1108
|
-
const args: string[] = []
|
|
1109
|
-
if (!binary) {
|
|
1110
|
-
if (flags.disableLspDownload) return
|
|
1111
|
-
const resolved = await Npm.which("@astrojs/language-server")
|
|
1112
|
-
if (!resolved) return
|
|
1113
|
-
binary = resolved
|
|
1114
|
-
}
|
|
1115
|
-
args.push("--stdio")
|
|
1116
|
-
const proc = spawn(binary, args, {
|
|
1117
|
-
cwd: root,
|
|
1118
|
-
env: {
|
|
1119
|
-
...process.env,
|
|
1120
|
-
},
|
|
1121
|
-
})
|
|
1122
|
-
return {
|
|
1123
|
-
process: proc,
|
|
1124
|
-
initialization: {
|
|
1125
|
-
typescript: {
|
|
1126
|
-
tsdk,
|
|
1127
|
-
},
|
|
1128
|
-
},
|
|
1129
|
-
}
|
|
1130
|
-
},
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
function isModuleOf(pomContent: string, modulePath: string): boolean {
|
|
1134
|
-
const normalized = modulePath.replace(/\\/g, "/").replace(/\/$/, "")
|
|
1135
|
-
if (!normalized) return false
|
|
1136
|
-
const modulesBlocks = pomContent.match(/<modules>([\s\S]*?)<\/modules>/g) ?? []
|
|
1137
|
-
for (const block of modulesBlocks) {
|
|
1138
|
-
const stripped = block.replace(/<!--[\s\S]*?-->/g, "")
|
|
1139
|
-
for (const m of stripped.matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
|
|
1140
|
-
const decl = m[1].replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "")
|
|
1141
|
-
if (decl === normalized) return true
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
return false
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
export const JDTLS: Info = {
|
|
1148
|
-
id: "jdtls",
|
|
1149
|
-
root: async (file, ctx) => {
|
|
1150
|
-
const settingsMarkers = ["settings.gradle", "settings.gradle.kts"]
|
|
1151
|
-
const gradleMarkers = ["gradlew", "gradlew.bat"]
|
|
1152
|
-
// 1. Gradle (unchanged from original logic)
|
|
1153
|
-
const [wrapperRoot, settingsRoot] = await Promise.all([
|
|
1154
|
-
StrictNearestRoot(gradleMarkers, settingsMarkers)(file, ctx),
|
|
1155
|
-
StrictNearestRoot(settingsMarkers)(file, ctx),
|
|
1156
|
-
])
|
|
1157
|
-
if (wrapperRoot) return wrapperRoot
|
|
1158
|
-
if (settingsRoot) return settingsRoot
|
|
1159
|
-
|
|
1160
|
-
// 2. Gradle single-project fallback (build.gradle without settings.gradle)
|
|
1161
|
-
const buildRoot = await StrictNearestRoot(["build.gradle", "build.gradle.kts"])(file, ctx)
|
|
1162
|
-
if (buildRoot) return buildRoot
|
|
1163
|
-
|
|
1164
|
-
// 3. Maven: walk up pom.xml chain verifying <module> relationships
|
|
1165
|
-
const pomFiles = await Filesystem.findUp("pom.xml", path.dirname(file), ctx.directory)
|
|
1166
|
-
if (pomFiles.length > 0) {
|
|
1167
|
-
let root = path.dirname(pomFiles[0])
|
|
1168
|
-
for (let i = 1; i < pomFiles.length; i++) {
|
|
1169
|
-
const parentDir = path.dirname(pomFiles[i])
|
|
1170
|
-
const rel = path.relative(parentDir, root)
|
|
1171
|
-
const content = await fs.readFile(pomFiles[i], "utf-8").catch(() => null)
|
|
1172
|
-
if (content && isModuleOf(content, rel)) {
|
|
1173
|
-
root = parentDir
|
|
1174
|
-
} else {
|
|
1175
|
-
break
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
return root
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
// 4. Eclipse native project fallback
|
|
1182
|
-
const eclipseRoot = await StrictNearestRoot([".project", ".classpath"])(file, ctx)
|
|
1183
|
-
if (eclipseRoot) return eclipseRoot
|
|
1184
|
-
|
|
1185
|
-
return undefined
|
|
1186
|
-
},
|
|
1187
|
-
extensions: [".java"],
|
|
1188
|
-
async spawn(root, _ctx, flags) {
|
|
1189
|
-
const java = which("java")
|
|
1190
|
-
if (!java) {
|
|
1191
|
-
return
|
|
1192
|
-
}
|
|
1193
|
-
const javaMajorVersion = await run(["java", "-version"]).then((result) => {
|
|
1194
|
-
const m = /"(\d+)\.\d+\.\d+"/.exec(result.stderr.toString())
|
|
1195
|
-
return !m ? undefined : parseInt(m[1])
|
|
1196
|
-
})
|
|
1197
|
-
if (javaMajorVersion == null || javaMajorVersion < 21) {
|
|
1198
|
-
return
|
|
1199
|
-
}
|
|
1200
|
-
const distPath = path.join(Global.Path.bin, "jdtls")
|
|
1201
|
-
const launcherDir = path.join(distPath, "plugins")
|
|
1202
|
-
const installed = await pathExists(launcherDir)
|
|
1203
|
-
if (!installed) {
|
|
1204
|
-
if (flags.disableLspDownload) return
|
|
1205
|
-
await fs.mkdir(distPath, { recursive: true })
|
|
1206
|
-
const releaseURL =
|
|
1207
|
-
"https://www.eclipse.org/downloads/download.php?file=/jdtls/snapshots/jdt-language-server-latest.tar.gz"
|
|
1208
|
-
const archiveName = "release.tar.gz"
|
|
1209
|
-
|
|
1210
|
-
const download = await fetch(releaseURL)
|
|
1211
|
-
if (!download.ok || !download.body) {
|
|
1212
|
-
return
|
|
1213
|
-
}
|
|
1214
|
-
await Filesystem.writeStream(path.join(distPath, archiveName), download.body)
|
|
1215
|
-
|
|
1216
|
-
const tarResult = await run(["tar", "-xzf", archiveName], { cwd: distPath })
|
|
1217
|
-
if (tarResult.code !== 0) {
|
|
1218
|
-
return
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
await fs.rm(path.join(distPath, archiveName), { force: true })
|
|
1222
|
-
}
|
|
1223
|
-
const jarFileName =
|
|
1224
|
-
(await fs.readdir(launcherDir).catch(() => []))
|
|
1225
|
-
.find((item) => /^org\.eclipse\.equinox\.launcher_.*\.jar$/.test(item))
|
|
1226
|
-
?.trim() ?? ""
|
|
1227
|
-
const launcherJar = path.join(launcherDir, jarFileName)
|
|
1228
|
-
if (!(await pathExists(launcherJar))) {
|
|
1229
|
-
return
|
|
1230
|
-
}
|
|
1231
|
-
const configFile = path.join(
|
|
1232
|
-
distPath,
|
|
1233
|
-
(() => {
|
|
1234
|
-
switch (process.platform) {
|
|
1235
|
-
case "darwin":
|
|
1236
|
-
return "config_mac"
|
|
1237
|
-
case "linux":
|
|
1238
|
-
return "config_linux"
|
|
1239
|
-
case "win32":
|
|
1240
|
-
return "config_win"
|
|
1241
|
-
default:
|
|
1242
|
-
return "config_linux"
|
|
1243
|
-
}
|
|
1244
|
-
})(),
|
|
1245
|
-
)
|
|
1246
|
-
const dataDir = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-jdtls-data"))
|
|
1247
|
-
return {
|
|
1248
|
-
process: spawn(
|
|
1249
|
-
java,
|
|
1250
|
-
[
|
|
1251
|
-
"-jar",
|
|
1252
|
-
launcherJar,
|
|
1253
|
-
"-configuration",
|
|
1254
|
-
configFile,
|
|
1255
|
-
"-data",
|
|
1256
|
-
dataDir,
|
|
1257
|
-
"-Declipse.application=org.eclipse.jdt.ls.core.id1",
|
|
1258
|
-
"-Dosgi.bundles.defaultStartLevel=4",
|
|
1259
|
-
"-Declipse.product=org.eclipse.jdt.ls.core.product",
|
|
1260
|
-
"-Dlog.level=ALL",
|
|
1261
|
-
"--add-modules=ALL-SYSTEM",
|
|
1262
|
-
"--add-opens java.base/java.util=ALL-UNNAMED",
|
|
1263
|
-
"--add-opens java.base/java.lang=ALL-UNNAMED",
|
|
1264
|
-
],
|
|
1265
|
-
{
|
|
1266
|
-
cwd: root,
|
|
1267
|
-
},
|
|
1268
|
-
),
|
|
1269
|
-
}
|
|
1270
|
-
},
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
export const KotlinLS: Info = {
|
|
1274
|
-
id: "kotlin-ls",
|
|
1275
|
-
extensions: [".kt", ".kts"],
|
|
1276
|
-
root: async (file, ctx) => {
|
|
1277
|
-
// 1) Nearest Gradle root (multi-project or included build)
|
|
1278
|
-
const settingsRoot = await NearestRoot(["settings.gradle.kts", "settings.gradle"])(file, ctx)
|
|
1279
|
-
if (settingsRoot) return settingsRoot
|
|
1280
|
-
// 2) Gradle wrapper (strong root signal)
|
|
1281
|
-
const wrapperRoot = await NearestRoot(["gradlew", "gradlew.bat"])(file, ctx)
|
|
1282
|
-
if (wrapperRoot) return wrapperRoot
|
|
1283
|
-
// 3) Single-project or module-level build
|
|
1284
|
-
const buildRoot = await NearestRoot(["build.gradle.kts", "build.gradle"])(file, ctx)
|
|
1285
|
-
if (buildRoot) return buildRoot
|
|
1286
|
-
// 4) Maven fallback
|
|
1287
|
-
return NearestRoot(["pom.xml"])(file, ctx)
|
|
1288
|
-
},
|
|
1289
|
-
async spawn(root, _ctx, flags) {
|
|
1290
|
-
const distPath = path.join(Global.Path.bin, "kotlin-ls")
|
|
1291
|
-
const launcherScript =
|
|
1292
|
-
process.platform === "win32" ? path.join(distPath, "kotlin-lsp.cmd") : path.join(distPath, "kotlin-lsp.sh")
|
|
1293
|
-
const installed = await Filesystem.exists(launcherScript)
|
|
1294
|
-
if (!installed) {
|
|
1295
|
-
if (flags.disableLspDownload) return
|
|
1296
|
-
|
|
1297
|
-
const releaseResponse = await fetch("https://api.github.com/repos/Kotlin/kotlin-lsp/releases/latest")
|
|
1298
|
-
if (!releaseResponse.ok) {
|
|
1299
|
-
return
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
const release = await releaseResponse.json()
|
|
1303
|
-
const version = release.name?.replace(/^v/, "")
|
|
1304
|
-
|
|
1305
|
-
if (!version) {
|
|
1306
|
-
return
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
const platform = process.platform
|
|
1310
|
-
const arch = process.arch
|
|
1311
|
-
|
|
1312
|
-
let kotlinArch: string = arch
|
|
1313
|
-
if (arch === "arm64") kotlinArch = "aarch64"
|
|
1314
|
-
else if (arch === "x64") kotlinArch = "x64"
|
|
1315
|
-
|
|
1316
|
-
let kotlinPlatform: string = platform
|
|
1317
|
-
if (platform === "darwin") kotlinPlatform = "mac"
|
|
1318
|
-
else if (platform === "linux") kotlinPlatform = "linux"
|
|
1319
|
-
else if (platform === "win32") kotlinPlatform = "win"
|
|
1320
|
-
|
|
1321
|
-
const supportedCombos = ["mac-x64", "mac-aarch64", "linux-x64", "linux-aarch64", "win-x64", "win-aarch64"]
|
|
1322
|
-
|
|
1323
|
-
const combo = `${kotlinPlatform}-${kotlinArch}`
|
|
1324
|
-
|
|
1325
|
-
if (!supportedCombos.includes(combo)) {
|
|
1326
|
-
return
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
const assetName = `kotlin-lsp-${version}-${kotlinPlatform}-${kotlinArch}.zip`
|
|
1330
|
-
const releaseURL = `https://download-cdn.jetbrains.com/kotlin-lsp/${version}/${assetName}`
|
|
1331
|
-
|
|
1332
|
-
await fs.mkdir(distPath, { recursive: true })
|
|
1333
|
-
const archivePath = path.join(distPath, "kotlin-ls.zip")
|
|
1334
|
-
const download = await fetch(releaseURL)
|
|
1335
|
-
if (!download.ok || !download.body) {
|
|
1336
|
-
return
|
|
1337
|
-
}
|
|
1338
|
-
await Filesystem.writeStream(archivePath, download.body)
|
|
1339
|
-
const ok = await Archive.extractZip(archivePath, distPath)
|
|
1340
|
-
.then(() => true)
|
|
1341
|
-
.catch((error) => {
|
|
1342
|
-
return false
|
|
1343
|
-
})
|
|
1344
|
-
if (!ok) return
|
|
1345
|
-
await fs.rm(archivePath, { force: true })
|
|
1346
|
-
if (process.platform !== "win32") {
|
|
1347
|
-
await fs.chmod(launcherScript, 0o755).catch(() => {})
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
if (!(await Filesystem.exists(launcherScript))) {
|
|
1351
|
-
return
|
|
1352
|
-
}
|
|
1353
|
-
return {
|
|
1354
|
-
process: spawn(launcherScript, ["--stdio"], {
|
|
1355
|
-
cwd: root,
|
|
1356
|
-
}),
|
|
1357
|
-
}
|
|
1358
|
-
},
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
export const YamlLS: Info = {
|
|
1362
|
-
id: "yaml-ls",
|
|
1363
|
-
extensions: [".yaml", ".yml"],
|
|
1364
|
-
root: NearestRoot(["package-lock.json", "bun.lockb", "bun.lock", "pnpm-lock.yaml", "yarn.lock"]),
|
|
1365
|
-
async spawn(root, _ctx, flags) {
|
|
1366
|
-
let binary = which("yaml-language-server")
|
|
1367
|
-
const args: string[] = []
|
|
1368
|
-
if (!binary) {
|
|
1369
|
-
if (flags.disableLspDownload) return
|
|
1370
|
-
const resolved = await Npm.which("yaml-language-server")
|
|
1371
|
-
if (!resolved) return
|
|
1372
|
-
binary = resolved
|
|
1373
|
-
}
|
|
1374
|
-
args.push("--stdio")
|
|
1375
|
-
const proc = spawn(binary, args, {
|
|
1376
|
-
cwd: root,
|
|
1377
|
-
env: {
|
|
1378
|
-
...process.env,
|
|
1379
|
-
},
|
|
1380
|
-
})
|
|
1381
|
-
return {
|
|
1382
|
-
process: proc,
|
|
1383
|
-
}
|
|
1384
|
-
},
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
export const LuaLS: Info = {
|
|
1388
|
-
id: "lua-ls",
|
|
1389
|
-
root: NearestRoot([
|
|
1390
|
-
".luarc.json",
|
|
1391
|
-
".luarc.jsonc",
|
|
1392
|
-
".luacheckrc",
|
|
1393
|
-
".stylua.toml",
|
|
1394
|
-
"stylua.toml",
|
|
1395
|
-
"selene.toml",
|
|
1396
|
-
"selene.yml",
|
|
1397
|
-
]),
|
|
1398
|
-
extensions: [".lua"],
|
|
1399
|
-
async spawn(root, _ctx, flags) {
|
|
1400
|
-
let bin = which("lua-language-server")
|
|
1401
|
-
|
|
1402
|
-
if (!bin) {
|
|
1403
|
-
if (flags.disableLspDownload) return
|
|
1404
|
-
|
|
1405
|
-
const releaseResponse = await fetch("https://api.github.com/repos/LuaLS/lua-language-server/releases/latest")
|
|
1406
|
-
if (!releaseResponse.ok) {
|
|
1407
|
-
return
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
const release = await releaseResponse.json()
|
|
1411
|
-
|
|
1412
|
-
const platform = process.platform
|
|
1413
|
-
const arch = process.arch
|
|
1414
|
-
let assetName = ""
|
|
1415
|
-
|
|
1416
|
-
let lualsArch: string = arch
|
|
1417
|
-
if (arch === "arm64") lualsArch = "arm64"
|
|
1418
|
-
else if (arch === "x64") lualsArch = "x64"
|
|
1419
|
-
else if (arch === "ia32") lualsArch = "ia32"
|
|
1420
|
-
|
|
1421
|
-
let lualsPlatform: string = platform
|
|
1422
|
-
if (platform === "darwin") lualsPlatform = "darwin"
|
|
1423
|
-
else if (platform === "linux") lualsPlatform = "linux"
|
|
1424
|
-
else if (platform === "win32") lualsPlatform = "win32"
|
|
1425
|
-
|
|
1426
|
-
const ext = platform === "win32" ? "zip" : "tar.gz"
|
|
1427
|
-
|
|
1428
|
-
assetName = `lua-language-server-${release.tag_name}-${lualsPlatform}-${lualsArch}.${ext}`
|
|
1429
|
-
|
|
1430
|
-
const supportedCombos = [
|
|
1431
|
-
"darwin-arm64.tar.gz",
|
|
1432
|
-
"darwin-x64.tar.gz",
|
|
1433
|
-
"linux-x64.tar.gz",
|
|
1434
|
-
"linux-arm64.tar.gz",
|
|
1435
|
-
"win32-x64.zip",
|
|
1436
|
-
"win32-ia32.zip",
|
|
1437
|
-
]
|
|
1438
|
-
|
|
1439
|
-
const assetSuffix = `${lualsPlatform}-${lualsArch}.${ext}`
|
|
1440
|
-
if (!supportedCombos.includes(assetSuffix)) {
|
|
1441
|
-
return
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
const asset = release.assets.find((a: any) => a.name === assetName)
|
|
1445
|
-
if (!asset) {
|
|
1446
|
-
return
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
const downloadUrl = asset.browser_download_url
|
|
1450
|
-
const downloadResponse = await fetch(downloadUrl)
|
|
1451
|
-
if (!downloadResponse.ok) {
|
|
1452
|
-
return
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
const tempPath = path.join(Global.Path.bin, assetName)
|
|
1456
|
-
if (downloadResponse.body) await Filesystem.writeStream(tempPath, downloadResponse.body)
|
|
1457
|
-
|
|
1458
|
-
// Unlike zls which is a single self-contained binary,
|
|
1459
|
-
// lua-language-server needs supporting files (meta/, locale/, etc.)
|
|
1460
|
-
// Extract entire archive to dedicated directory to preserve all files
|
|
1461
|
-
const installDir = path.join(Global.Path.bin, `lua-language-server-${lualsArch}-${lualsPlatform}`)
|
|
1462
|
-
|
|
1463
|
-
// Remove old installation if exists
|
|
1464
|
-
const stats = await fs.stat(installDir).catch(() => undefined)
|
|
1465
|
-
if (stats) {
|
|
1466
|
-
await fs.rm(installDir, { force: true, recursive: true })
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
await fs.mkdir(installDir, { recursive: true })
|
|
1470
|
-
|
|
1471
|
-
if (ext === "zip") {
|
|
1472
|
-
const ok = await Archive.extractZip(tempPath, installDir)
|
|
1473
|
-
.then(() => true)
|
|
1474
|
-
.catch((error) => {
|
|
1475
|
-
return false
|
|
1476
|
-
})
|
|
1477
|
-
if (!ok) return
|
|
1478
|
-
} else {
|
|
1479
|
-
const ok = await run(["tar", "-xzf", tempPath, "-C", installDir])
|
|
1480
|
-
.then((result) => result.code === 0)
|
|
1481
|
-
.catch((error: unknown) => {
|
|
1482
|
-
return false
|
|
1483
|
-
})
|
|
1484
|
-
if (!ok) return
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
|
-
await fs.rm(tempPath, { force: true })
|
|
1488
|
-
|
|
1489
|
-
// Binary is located in bin/ subdirectory within the extracted archive
|
|
1490
|
-
bin = path.join(installDir, "bin", "lua-language-server" + (platform === "win32" ? ".exe" : ""))
|
|
1491
|
-
|
|
1492
|
-
if (!(await Filesystem.exists(bin))) {
|
|
1493
|
-
return
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
if (platform !== "win32") {
|
|
1497
|
-
const ok = await fs
|
|
1498
|
-
.chmod(bin, 0o755)
|
|
1499
|
-
.then(() => true)
|
|
1500
|
-
.catch((error: unknown) => {
|
|
1501
|
-
return false
|
|
1502
|
-
})
|
|
1503
|
-
if (!ok) return
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
return {
|
|
1508
|
-
process: spawn(bin, {
|
|
1509
|
-
cwd: root,
|
|
1510
|
-
}),
|
|
1511
|
-
}
|
|
1512
|
-
},
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
export const PHPIntelephense: Info = {
|
|
1516
|
-
id: "php intelephense",
|
|
1517
|
-
extensions: [".php"],
|
|
1518
|
-
root: NearestRoot(["composer.json", "composer.lock", ".php-version"]),
|
|
1519
|
-
async spawn(root, _ctx, flags) {
|
|
1520
|
-
let binary = which("intelephense")
|
|
1521
|
-
const args: string[] = []
|
|
1522
|
-
if (!binary) {
|
|
1523
|
-
if (flags.disableLspDownload) return
|
|
1524
|
-
const resolved = await Npm.which("intelephense")
|
|
1525
|
-
if (!resolved) return
|
|
1526
|
-
binary = resolved
|
|
1527
|
-
}
|
|
1528
|
-
args.push("--stdio")
|
|
1529
|
-
const proc = spawn(binary, args, {
|
|
1530
|
-
cwd: root,
|
|
1531
|
-
env: {
|
|
1532
|
-
...process.env,
|
|
1533
|
-
},
|
|
1534
|
-
})
|
|
1535
|
-
return {
|
|
1536
|
-
process: proc,
|
|
1537
|
-
initialization: {
|
|
1538
|
-
telemetry: {
|
|
1539
|
-
enabled: false,
|
|
1540
|
-
},
|
|
1541
|
-
},
|
|
1542
|
-
}
|
|
1543
|
-
},
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
export const Prisma: Info = {
|
|
1547
|
-
id: "prisma",
|
|
1548
|
-
extensions: [".prisma"],
|
|
1549
|
-
root: NearestRoot(["schema.prisma", "prisma/schema.prisma", "prisma"], ["package.json"]),
|
|
1550
|
-
async spawn(root) {
|
|
1551
|
-
const prisma = which("prisma")
|
|
1552
|
-
if (!prisma) {
|
|
1553
|
-
return
|
|
1554
|
-
}
|
|
1555
|
-
return {
|
|
1556
|
-
process: spawn(prisma, ["language-server"], {
|
|
1557
|
-
cwd: root,
|
|
1558
|
-
}),
|
|
1559
|
-
}
|
|
1560
|
-
},
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
export const Dart: Info = {
|
|
1564
|
-
id: "dart",
|
|
1565
|
-
extensions: [".dart"],
|
|
1566
|
-
root: NearestRoot(["pubspec.yaml", "analysis_options.yaml"]),
|
|
1567
|
-
async spawn(root) {
|
|
1568
|
-
const dart = which("dart")
|
|
1569
|
-
if (!dart) {
|
|
1570
|
-
return
|
|
1571
|
-
}
|
|
1572
|
-
return {
|
|
1573
|
-
process: spawn(dart, ["language-server", "--lsp"], {
|
|
1574
|
-
cwd: root,
|
|
1575
|
-
}),
|
|
1576
|
-
}
|
|
1577
|
-
},
|
|
1578
|
-
}
|
|
1579
|
-
|
|
1580
|
-
export const Ocaml: Info = {
|
|
1581
|
-
id: "ocaml-lsp",
|
|
1582
|
-
extensions: [".ml", ".mli"],
|
|
1583
|
-
root: NearestRoot(["dune-project", "dune-workspace", ".merlin", "opam"]),
|
|
1584
|
-
async spawn(root) {
|
|
1585
|
-
const bin = which("ocamllsp")
|
|
1586
|
-
if (!bin) {
|
|
1587
|
-
return
|
|
1588
|
-
}
|
|
1589
|
-
return {
|
|
1590
|
-
process: spawn(bin, {
|
|
1591
|
-
cwd: root,
|
|
1592
|
-
}),
|
|
1593
|
-
}
|
|
1594
|
-
},
|
|
1595
|
-
}
|
|
1596
|
-
export const BashLS: Info = {
|
|
1597
|
-
id: "bash",
|
|
1598
|
-
extensions: [".sh", ".bash", ".zsh", ".ksh"],
|
|
1599
|
-
root: async (_file, ctx) => ctx.directory,
|
|
1600
|
-
async spawn(root, _ctx, flags) {
|
|
1601
|
-
let binary = which("bash-language-server")
|
|
1602
|
-
const args: string[] = []
|
|
1603
|
-
if (!binary) {
|
|
1604
|
-
if (flags.disableLspDownload) return
|
|
1605
|
-
const resolved = await Npm.which("bash-language-server")
|
|
1606
|
-
if (!resolved) return
|
|
1607
|
-
binary = resolved
|
|
1608
|
-
}
|
|
1609
|
-
args.push("start")
|
|
1610
|
-
const proc = spawn(binary, args, {
|
|
1611
|
-
cwd: root,
|
|
1612
|
-
env: {
|
|
1613
|
-
...process.env,
|
|
1614
|
-
},
|
|
1615
|
-
})
|
|
1616
|
-
return {
|
|
1617
|
-
process: proc,
|
|
1618
|
-
}
|
|
1619
|
-
},
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
export const TerraformLS: Info = {
|
|
1623
|
-
id: "terraform",
|
|
1624
|
-
extensions: [".tf", ".tfvars"],
|
|
1625
|
-
root: NearestRoot([".terraform.lock.hcl", "terraform.tfstate", "*.tf"]),
|
|
1626
|
-
async spawn(root, _ctx, flags) {
|
|
1627
|
-
let bin = which("terraform-ls")
|
|
1628
|
-
|
|
1629
|
-
if (!bin) {
|
|
1630
|
-
if (flags.disableLspDownload) return
|
|
1631
|
-
|
|
1632
|
-
const releaseResponse = await fetch("https://api.releases.hashicorp.com/v1/releases/terraform-ls/latest")
|
|
1633
|
-
if (!releaseResponse.ok) {
|
|
1634
|
-
return
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
const release = (await releaseResponse.json()) as {
|
|
1638
|
-
version?: string
|
|
1639
|
-
builds?: { arch?: string; os?: string; url?: string }[]
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
const platform = process.platform
|
|
1643
|
-
const arch = process.arch
|
|
1644
|
-
|
|
1645
|
-
const tfArch = arch === "arm64" ? "arm64" : "amd64"
|
|
1646
|
-
const tfPlatform = platform === "win32" ? "windows" : platform
|
|
1647
|
-
|
|
1648
|
-
const builds = release.builds ?? []
|
|
1649
|
-
const build = builds.find((b) => b.arch === tfArch && b.os === tfPlatform)
|
|
1650
|
-
if (!build?.url) {
|
|
1651
|
-
return
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
const downloadResponse = await fetch(build.url)
|
|
1655
|
-
if (!downloadResponse.ok) {
|
|
1656
|
-
return
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
const tempPath = path.join(Global.Path.bin, "terraform-ls.zip")
|
|
1660
|
-
if (downloadResponse.body) await Filesystem.writeStream(tempPath, downloadResponse.body)
|
|
1661
|
-
|
|
1662
|
-
const ok = await Archive.extractZip(tempPath, Global.Path.bin)
|
|
1663
|
-
.then(() => true)
|
|
1664
|
-
.catch((error) => {
|
|
1665
|
-
return false
|
|
1666
|
-
})
|
|
1667
|
-
if (!ok) return
|
|
1668
|
-
await fs.rm(tempPath, { force: true })
|
|
1669
|
-
|
|
1670
|
-
bin = path.join(Global.Path.bin, "terraform-ls" + (platform === "win32" ? ".exe" : ""))
|
|
1671
|
-
|
|
1672
|
-
if (!(await Filesystem.exists(bin))) {
|
|
1673
|
-
return
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
if (platform !== "win32") {
|
|
1677
|
-
await fs.chmod(bin, 0o755).catch(() => {})
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
return {
|
|
1682
|
-
process: spawn(bin, ["serve"], {
|
|
1683
|
-
cwd: root,
|
|
1684
|
-
}),
|
|
1685
|
-
initialization: {
|
|
1686
|
-
experimentalFeatures: {
|
|
1687
|
-
prefillRequiredFields: true,
|
|
1688
|
-
validateOnSave: true,
|
|
1689
|
-
},
|
|
1690
|
-
},
|
|
1691
|
-
}
|
|
1692
|
-
},
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
export const TexLab: Info = {
|
|
1696
|
-
id: "texlab",
|
|
1697
|
-
extensions: [".tex", ".bib"],
|
|
1698
|
-
root: NearestRoot([".latexmkrc", "latexmkrc", ".texlabroot", "texlabroot"]),
|
|
1699
|
-
async spawn(root, _ctx, flags) {
|
|
1700
|
-
let bin = which("texlab")
|
|
1701
|
-
|
|
1702
|
-
if (!bin) {
|
|
1703
|
-
if (flags.disableLspDownload) return
|
|
1704
|
-
|
|
1705
|
-
const response = await fetch("https://api.github.com/repos/latex-lsp/texlab/releases/latest")
|
|
1706
|
-
if (!response.ok) {
|
|
1707
|
-
return
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
const release = (await response.json()) as {
|
|
1711
|
-
tag_name?: string
|
|
1712
|
-
assets?: { name?: string; browser_download_url?: string }[]
|
|
1713
|
-
}
|
|
1714
|
-
const version = release.tag_name?.replace("v", "")
|
|
1715
|
-
if (!version) {
|
|
1716
|
-
return
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
|
-
const platform = process.platform
|
|
1720
|
-
const arch = process.arch
|
|
1721
|
-
|
|
1722
|
-
const texArch = arch === "arm64" ? "aarch64" : "x86_64"
|
|
1723
|
-
const texPlatform = platform === "darwin" ? "macos" : platform === "win32" ? "windows" : "linux"
|
|
1724
|
-
const ext = platform === "win32" ? "zip" : "tar.gz"
|
|
1725
|
-
const assetName = `texlab-${texArch}-${texPlatform}.${ext}`
|
|
1726
|
-
|
|
1727
|
-
const assets = release.assets ?? []
|
|
1728
|
-
const asset = assets.find((a) => a.name === assetName)
|
|
1729
|
-
if (!asset?.browser_download_url) {
|
|
1730
|
-
return
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
const downloadResponse = await fetch(asset.browser_download_url)
|
|
1734
|
-
if (!downloadResponse.ok) {
|
|
1735
|
-
return
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
const tempPath = path.join(Global.Path.bin, assetName)
|
|
1739
|
-
if (downloadResponse.body) await Filesystem.writeStream(tempPath, downloadResponse.body)
|
|
1740
|
-
|
|
1741
|
-
if (ext === "zip") {
|
|
1742
|
-
const ok = await Archive.extractZip(tempPath, Global.Path.bin)
|
|
1743
|
-
.then(() => true)
|
|
1744
|
-
.catch((error) => {
|
|
1745
|
-
return false
|
|
1746
|
-
})
|
|
1747
|
-
if (!ok) return
|
|
1748
|
-
}
|
|
1749
|
-
if (ext === "tar.gz") {
|
|
1750
|
-
await run(["tar", "-xzf", tempPath], { cwd: Global.Path.bin })
|
|
1751
|
-
}
|
|
1752
|
-
|
|
1753
|
-
await fs.rm(tempPath, { force: true })
|
|
1754
|
-
|
|
1755
|
-
bin = path.join(Global.Path.bin, "texlab" + (platform === "win32" ? ".exe" : ""))
|
|
1756
|
-
|
|
1757
|
-
if (!(await Filesystem.exists(bin))) {
|
|
1758
|
-
return
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
if (platform !== "win32") {
|
|
1762
|
-
await fs.chmod(bin, 0o755).catch(() => {})
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1766
|
-
return {
|
|
1767
|
-
process: spawn(bin, {
|
|
1768
|
-
cwd: root,
|
|
1769
|
-
}),
|
|
1770
|
-
}
|
|
1771
|
-
},
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
export const DockerfileLS: Info = {
|
|
1775
|
-
id: "dockerfile",
|
|
1776
|
-
extensions: [".dockerfile", "Dockerfile"],
|
|
1777
|
-
root: async (_file, ctx) => ctx.directory,
|
|
1778
|
-
async spawn(root, _ctx, flags) {
|
|
1779
|
-
let binary = which("docker-langserver")
|
|
1780
|
-
const args: string[] = []
|
|
1781
|
-
if (!binary) {
|
|
1782
|
-
if (flags.disableLspDownload) return
|
|
1783
|
-
const resolved = await Npm.which("dockerfile-language-server-nodejs")
|
|
1784
|
-
if (!resolved) return
|
|
1785
|
-
binary = resolved
|
|
1786
|
-
}
|
|
1787
|
-
args.push("--stdio")
|
|
1788
|
-
const proc = spawn(binary, args, {
|
|
1789
|
-
cwd: root,
|
|
1790
|
-
env: {
|
|
1791
|
-
...process.env,
|
|
1792
|
-
},
|
|
1793
|
-
})
|
|
1794
|
-
return {
|
|
1795
|
-
process: proc,
|
|
1796
|
-
}
|
|
1797
|
-
},
|
|
1798
|
-
}
|
|
1799
|
-
|
|
1800
|
-
export const Gleam: Info = {
|
|
1801
|
-
id: "gleam",
|
|
1802
|
-
extensions: [".gleam"],
|
|
1803
|
-
root: NearestRoot(["gleam.toml"]),
|
|
1804
|
-
async spawn(root) {
|
|
1805
|
-
const gleam = which("gleam")
|
|
1806
|
-
if (!gleam) {
|
|
1807
|
-
return
|
|
1808
|
-
}
|
|
1809
|
-
return {
|
|
1810
|
-
process: spawn(gleam, ["lsp"], {
|
|
1811
|
-
cwd: root,
|
|
1812
|
-
}),
|
|
1813
|
-
}
|
|
1814
|
-
},
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
|
-
export const Clojure: Info = {
|
|
1818
|
-
id: "clojure-lsp",
|
|
1819
|
-
extensions: [".clj", ".cljs", ".cljc", ".edn"],
|
|
1820
|
-
root: NearestRoot(["deps.edn", "project.clj", "shadow-cljs.edn", "bb.edn", "build.boot"]),
|
|
1821
|
-
async spawn(root) {
|
|
1822
|
-
let bin = which("clojure-lsp")
|
|
1823
|
-
if (!bin && process.platform === "win32") {
|
|
1824
|
-
bin = which("clojure-lsp.exe")
|
|
1825
|
-
}
|
|
1826
|
-
if (!bin) {
|
|
1827
|
-
return
|
|
1828
|
-
}
|
|
1829
|
-
return {
|
|
1830
|
-
process: spawn(bin, ["listen"], {
|
|
1831
|
-
cwd: root,
|
|
1832
|
-
}),
|
|
1833
|
-
}
|
|
1834
|
-
},
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
|
-
export const Nixd: Info = {
|
|
1838
|
-
id: "nixd",
|
|
1839
|
-
extensions: [".nix"],
|
|
1840
|
-
root: async (file, ctx) => {
|
|
1841
|
-
// First, look for flake.nix - the most reliable Nix project root indicator
|
|
1842
|
-
const flakeRoot = await NearestRoot(["flake.nix"])(file, ctx)
|
|
1843
|
-
if (flakeRoot && flakeRoot !== ctx.directory) return flakeRoot
|
|
1844
|
-
|
|
1845
|
-
// If no flake.nix, fall back to git repository root
|
|
1846
|
-
if (ctx.worktree && ctx.worktree !== ctx.directory) return ctx.worktree
|
|
1847
|
-
|
|
1848
|
-
// Finally, use the instance directory as fallback
|
|
1849
|
-
return ctx.directory
|
|
1850
|
-
},
|
|
1851
|
-
async spawn(root) {
|
|
1852
|
-
const nixd = which("nixd")
|
|
1853
|
-
if (!nixd) {
|
|
1854
|
-
return
|
|
1855
|
-
}
|
|
1856
|
-
return {
|
|
1857
|
-
process: spawn(nixd, [], {
|
|
1858
|
-
cwd: root,
|
|
1859
|
-
env: {
|
|
1860
|
-
...process.env,
|
|
1861
|
-
},
|
|
1862
|
-
}),
|
|
1863
|
-
}
|
|
1864
|
-
},
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
export const Tinymist: Info = {
|
|
1868
|
-
id: "tinymist",
|
|
1869
|
-
extensions: [".typ", ".typc"],
|
|
1870
|
-
root: NearestRoot(["typst.toml"]),
|
|
1871
|
-
async spawn(root, _ctx, flags) {
|
|
1872
|
-
let bin = which("tinymist")
|
|
1873
|
-
|
|
1874
|
-
if (!bin) {
|
|
1875
|
-
if (flags.disableLspDownload) return
|
|
1876
|
-
|
|
1877
|
-
const response = await fetch("https://api.github.com/repos/Myriad-Dreamin/tinymist/releases/latest")
|
|
1878
|
-
if (!response.ok) {
|
|
1879
|
-
return
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
const release = (await response.json()) as {
|
|
1883
|
-
tag_name?: string
|
|
1884
|
-
assets?: { name?: string; browser_download_url?: string }[]
|
|
1885
|
-
}
|
|
1886
|
-
|
|
1887
|
-
const platform = process.platform
|
|
1888
|
-
const arch = process.arch
|
|
1889
|
-
|
|
1890
|
-
const tinymistArch = arch === "arm64" ? "aarch64" : "x86_64"
|
|
1891
|
-
let tinymistPlatform: string
|
|
1892
|
-
let ext: string
|
|
1893
|
-
|
|
1894
|
-
if (platform === "darwin") {
|
|
1895
|
-
tinymistPlatform = "apple-darwin"
|
|
1896
|
-
ext = "tar.gz"
|
|
1897
|
-
} else if (platform === "win32") {
|
|
1898
|
-
tinymistPlatform = "pc-windows-msvc"
|
|
1899
|
-
ext = "zip"
|
|
1900
|
-
} else {
|
|
1901
|
-
tinymistPlatform = "unknown-linux-gnu"
|
|
1902
|
-
ext = "tar.gz"
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
|
-
const assetName = `tinymist-${tinymistArch}-${tinymistPlatform}.${ext}`
|
|
1906
|
-
|
|
1907
|
-
const assets = release.assets ?? []
|
|
1908
|
-
const asset = assets.find((a) => a.name === assetName)
|
|
1909
|
-
if (!asset?.browser_download_url) {
|
|
1910
|
-
return
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
const downloadResponse = await fetch(asset.browser_download_url)
|
|
1914
|
-
if (!downloadResponse.ok) {
|
|
1915
|
-
return
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
|
-
const tempPath = path.join(Global.Path.bin, assetName)
|
|
1919
|
-
if (downloadResponse.body) await Filesystem.writeStream(tempPath, downloadResponse.body)
|
|
1920
|
-
|
|
1921
|
-
if (ext === "zip") {
|
|
1922
|
-
const ok = await Archive.extractZip(tempPath, Global.Path.bin)
|
|
1923
|
-
.then(() => true)
|
|
1924
|
-
.catch((error) => {
|
|
1925
|
-
return false
|
|
1926
|
-
})
|
|
1927
|
-
if (!ok) return
|
|
1928
|
-
} else {
|
|
1929
|
-
await run(["tar", "-xzf", tempPath, "--strip-components=1"], { cwd: Global.Path.bin })
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
|
-
await fs.rm(tempPath, { force: true })
|
|
1933
|
-
|
|
1934
|
-
bin = path.join(Global.Path.bin, "tinymist" + (platform === "win32" ? ".exe" : ""))
|
|
1935
|
-
|
|
1936
|
-
if (!(await Filesystem.exists(bin))) {
|
|
1937
|
-
return
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
if (platform !== "win32") {
|
|
1941
|
-
await fs.chmod(bin, 0o755).catch(() => {})
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
|
-
return {
|
|
1946
|
-
process: spawn(bin, { cwd: root }),
|
|
1947
|
-
}
|
|
1948
|
-
},
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
export const HLS: Info = {
|
|
1952
|
-
id: "haskell-language-server",
|
|
1953
|
-
extensions: [".hs", ".lhs"],
|
|
1954
|
-
root: NearestRoot(["stack.yaml", "cabal.project", "hie.yaml", "*.cabal"]),
|
|
1955
|
-
async spawn(root) {
|
|
1956
|
-
const bin = which("haskell-language-server-wrapper")
|
|
1957
|
-
if (!bin) {
|
|
1958
|
-
return
|
|
1959
|
-
}
|
|
1960
|
-
return {
|
|
1961
|
-
process: spawn(bin, ["--lsp"], {
|
|
1962
|
-
cwd: root,
|
|
1963
|
-
}),
|
|
1964
|
-
}
|
|
1965
|
-
},
|
|
1966
|
-
}
|
|
1967
|
-
|
|
1968
|
-
export const JuliaLS: Info = {
|
|
1969
|
-
id: "julials",
|
|
1970
|
-
extensions: [".jl"],
|
|
1971
|
-
root: NearestRoot(["Project.toml", "Manifest.toml", "*.jl"]),
|
|
1972
|
-
async spawn(root) {
|
|
1973
|
-
const julia = which("julia")
|
|
1974
|
-
if (!julia) {
|
|
1975
|
-
return
|
|
1976
|
-
}
|
|
1977
|
-
return {
|
|
1978
|
-
process: spawn(julia, ["--startup-file=no", "--history-file=no", "-e", "using LanguageServer; runserver()"], {
|
|
1979
|
-
cwd: root,
|
|
1980
|
-
}),
|
|
1981
|
-
}
|
|
1982
|
-
},
|
|
1983
|
-
}
|