diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2025-01-11 19:52:31 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2025-01-11 19:52:31 +0100 |
| commit | d22499ba966d2c2c8bb0cd4aee8ced52b986ed74 (patch) | |
| tree | f58615f9bbcf3392292b25c06ffdd3227c6e0dfd | |
| parent | 88a91d1328c9b48b45f97e3dc8a03f7767ef8162 (diff) | |
| parent | eec5781241a4127488e1606fdfb6672cd193a948 (diff) | |
Merge branch 'master' of https://github.com/DanielGavin/ols
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | README.md | 53 | ||||
| -rwxr-xr-x | build.sh | 3 | ||||
| -rw-r--r-- | editors/vscode/package.json | 12 | ||||
| -rw-r--r-- | editors/vscode/src/extension.ts | 107 | ||||
| -rw-r--r-- | editors/vscode/src/toolchain.ts | 2 | ||||
| -rw-r--r-- | misc/ols.schema.json | 2 | ||||
| -rw-r--r-- | src/common/ast.odin | 1 | ||||
| -rw-r--r-- | src/main.odin | 5 | ||||
| -rw-r--r-- | src/server/build.odin | 1 | ||||
| -rw-r--r-- | src/server/completion.odin | 1 | ||||
| -rw-r--r-- | src/server/hover.odin | 1 | ||||
| -rw-r--r-- | src/server/requests.odin | 1 | ||||
| -rw-r--r-- | src/server/snippets.odin | 1 |
14 files changed, 142 insertions, 51 deletions
@@ -15,4 +15,5 @@ /odinfmt tests/tests ols.json -.vscode/
\ No newline at end of file +.vscode/ +deno.lock @@ -228,24 +228,65 @@ require'lspconfig'.ols.setup { ### Emacs +For Emacs, there are two packages available for LSP; lsp-mode and eglot. + +The latter is built-in, spec-compliant and favours built-in Emacs functionality and the former offers richer UI elements and automatic installation for some of the servers. + +In either case, you'll also need an associated major mode. + +Pick either of the below, the former is likely to be more stable but the latter will allow you to take advantage of tree-sitter and other packages that integrate with it. + +The `use-package` statements below assume you're using a package manager like Straight or Elpaca and as such should be taken as references rather than guaranteed copy/pasteable. If you're using `package.el` or another package manager then you'll have to look into instructions for that yourself. + ```elisp ;; Enable odin-mode and configure OLS as the language server -(use-package! odin-mode - :mode ("\\.odin\\'" . odin-mode) - :hook (odin-mode . lsp)) +(use-package odin-mode + :ensure (:host github :repo "mattt-b/odin-mode") + :mode ("\\.odin\\'" . odin-mode)) + +;; Or use the WIP tree-sitter mode +(use-package odin-ts-mode + :ensure (:host github :repo "Sampie159/odin-ts-mode") + :mode ("\\.odin\\'" . odin-ts-mode)) +``` + +And then choose either the built-in `eglot` or `lsp-mode` packages below. Both should work very similarly. + +#### lsp-mode + +```elisp +;; Pull the lsp-mode package +(use-package lsp-mode + :commands (lsp lsp-deferred)) ;; Set up OLS as the language server for Odin, ensuring lsp-mode is loaded first (with-eval-after-load 'lsp-mode (setq-default lsp-auto-guess-root t) ;; Helps find the ols.json file with Projectile or project.el - (setq lsp-language-id-configuration (cons '(odin-mode . "odin") lsp-language-id-configuration)) + (add-to-list 'lsp-language-id-configuration '(odin-mode . "odin")) + (add-to-list 'lsp-language-id-configuration '(odin-ts-mode . "odin")) (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection "/path/to/ols/executable") ;; Adjust the path here - :major-modes '(odin-mode) + :major-modes '(odin-mode odin-ts-mode) :server-id 'ols :multi-root t))) ;; Ensures lsp-mode sends "workspaceFolders" to the server -(add-hook 'odin-mode-hook #'lsp) +;; Add a hook to autostart OLS +(add-hook 'odin-mode-hook #'lsp-deferred) +(add-hook 'odin-ts-mode-hook #'lsp-deferred) ;; If you're using the TS mode +``` + +#### eglot + +```elisp +;; Add OLS to the list of available programs +;; NOTE: As of Emacs 30, this is not needed. +(with-eval-after-load 'eglot + (add-to-list 'eglot-server-programs '((odin-mode odin-ts-mode) . ("ols")))) + +;; Add a hook to autostart OLS +(add-hook 'odin-mode-hook #'eglot-ensure) +(add-hook 'odin-ts-mode-hook #'eglot-ensure) ;; If you're using the TS mode ``` ### Helix @@ -46,5 +46,8 @@ then exit 0 fi +version="$(git describe --tags --abbrev=7)" +version="${version%-*}:${version##*-}" +sed "s|VERSION :: .*|VERSION :: \"${version}\"|g" src/main.odin > /tmp/main.odin.build && mv -f /tmp/main.odin.build src/main.odin odin build src/ -show-timings -collection:src=src -out:ols -microarch:native -no-bounds-check -o:speed $@ diff --git a/editors/vscode/package.json b/editors/vscode/package.json index 82bdbc7..f431984 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -14,9 +14,6 @@ "categories": [ "Programming Languages" ], - "activationEvents": [ - "onLanguage:odin" - ], "icon": "images/emblem.png", "main": "./out/extension.js", "contributes": { @@ -37,8 +34,13 @@ "category": "Odin Language Server" }, { - "command": "ols.createOls", - "title": "Create ols.json file in project", + "command": "ols.editProjectConfig", + "title": "Edit per-project config file (ols.json), creating it if necessary", + "category": "Odin Language Server" + }, + { + "command": "ols.editUserConfig", + "title": "Edit per-user config file (ols.json), creating it if necessary", "category": "Odin Language Server" } ], diff --git a/editors/vscode/src/extension.ts b/editors/vscode/src/extension.ts index e3a8f4f..ae776f8 100644 --- a/editors/vscode/src/extension.ts +++ b/editors/vscode/src/extension.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import * as path from "path"; import * as os from "os"; -import { promises as fs, PathLike, constants, writeFileSync } from "fs"; +import { promises as fs, constants, writeFileSync} from "fs"; var AdmZip = require('adm-zip'); @@ -20,13 +20,24 @@ import { RunnableCodeLensProvider } from "./run"; import { PersistentState } from './persistent_state'; import { Config } from './config'; import { fetchRelease, download } from './net'; -import { getPathForExecutable, isOdinInstalled } from './toolchain'; +import { isOdinInstalled } from './toolchain'; import { Ctx } from './ctx'; import { runDebugTest, runTest } from './commands'; import { watchOlsConfigFile } from './watch'; const onDidChange: vscode.EventEmitter<void> = new vscode.EventEmitter<void>(); +const defaultConfig = JSON.stringify( + { + $schema: "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json", + enable_document_symbols: true, + enable_hover: true, + enable_snippets: true + }, + null, + 4, +); + let ctx: Ctx; export async function activate(context: vscode.ExtensionContext) { @@ -102,32 +113,40 @@ export async function activate(context: vscode.ExtensionContext) { ctx.registerCommand("runDebugTest", runDebugTest); ctx.registerCommand("runTest", runTest); - const olsFile = path.join(workspaceFolder.uri.fsPath, "ols.json"); - - fs.access(olsFile, constants.F_OK).catch(async err => { - if (err) { + const projectConfigPath = path.join(workspaceFolder.uri.fsPath, "ols.json"); + const userConfigPath = path.join(path.dirname(serverPath), "ols.json"); + fs.access(projectConfigPath, constants.F_OK).catch(async (_e1) => { + fs.access(userConfigPath, constants.F_OK).catch( async (_e2) => { if (!config.askCreateOLS) { return; } const userResponse = await vscode.window.showInformationMessage( - "No ols config file in the workspace root folder. Do you wish to create one?", + "No ols config file found. Do you wish to create one?", "Yes", "No", - "Don't ask again" + "Don't ask again", ); if (userResponse === "Yes") { - createOlsConfig(ctx); + const clarification = await vscode.window.showInformationMessage( + "should it be specific to this project or to all your odin projects?", + "This project", + "All projects", + ); + if (clarification == "This project") { + createOrEditProjectConfig(); + parseOlsFile(config, projectConfigPath); + } else { + createOrEditUserConfig(serverPath); + parseOlsFile(config, userConfigPath); + } } else if (userResponse === "Don't ask again") { config.updateAskCreateOLS(false); return; } - - } - - parseOlsFile(config, olsFile); + }) }); if(!isOdinInstalled()) { @@ -147,14 +166,18 @@ export async function activate(context: vscode.ExtensionContext) { client.start(); }); - vscode.commands.registerCommand("ols.createOls", async() => { - createOlsConfig(ctx); + vscode.commands.registerCommand("ols.editProjectConfig", async() => { + createOrEditProjectConfig(); + }); + + vscode.commands.registerCommand("ols.editUserConfig", async () => { + createOrEditUserConfig(serverPath); }); client.start(); - parseOlsFile(config, olsFile); - watchOlsConfigFile(ctx, olsFile); + parseOlsFile(config, projectConfigPath); + watchOlsConfigFile(ctx, projectConfigPath); } async function bootstrap(config: Config, state: PersistentState): Promise<string> { @@ -219,35 +242,45 @@ async function removeOldServers(config: Config, state: PersistentState): Promise } } -export function createOlsConfig(ctx: Ctx) { - const odinPath = getPathForExecutable("odin"); - - const corePath = path.resolve(path.join(path.dirname(odinPath), "core")); - - const config = { - $schema: "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json", - enable_document_symbols: true, - enable_hover: true, - enable_snippets: true - }; - - const olsPath = vscode.workspace.workspaceFolders![0].uri.fsPath; +export function createOrEditProjectConfig() { + const projectConfigPath = vscode.workspace.workspaceFolders![0].uri.fsPath; + openFileAndCreateIfNotExists("ols.json", projectConfigPath, defaultConfig); +} - const edit = new vscode.WorkspaceEdit(); +export function createOrEditUserConfig(serverPath: string) { + const userConfigPath = path.dirname(serverPath); + openFileAndCreateIfNotExists("ols.json", userConfigPath, defaultConfig); +} - const content = JSON.stringify(config, null, 4); +function openFileAndCreateIfNotExists(file: string, folder: string, defaultContents: string) { + const filePath = path.join(folder, file); + console.log(filePath); - writeFileSync(path.join(olsPath, "ols.json"), content); + vscode.workspace.openTextDocument(filePath).then( + (document) => { vscode.window.showTextDocument(document) }, + () => { + writeFileSync(filePath, defaultContents); + vscode.workspace.openTextDocument(filePath).then( + (document) => { vscode.window.showTextDocument(document) } + ); + } + ); + } export async function parseOlsFile(config: Config, file: string) { /* We have to parse the collections that they have specificed through the json(This will be changed when odin gets it's own builder files) */ - fs.readFile(file).then((data) => { - const conf = JSON.parse(data.toString()); - config.collections = conf.collections; - }); + fs.readFile(file).then( + (data) => { + const conf = JSON.parse(data.toString()); + config.collections = conf.collections; + }, + (error) => { + console.info("no ols.json found in workspace"); + }, + ); } function serverPath(config: Config): string | null { diff --git a/editors/vscode/src/toolchain.ts b/editors/vscode/src/toolchain.ts index 21957ed..3a559de 100644 --- a/editors/vscode/src/toolchain.ts +++ b/editors/vscode/src/toolchain.ts @@ -45,7 +45,7 @@ function lookupInPath(exec: string): string | undefined { return pathToOdin; } } catch (realpathError) { - console.error("realpathError:", realpathError) + console.debug("couldn't find odin at", candidates[i], "on account of", realpathError) } } diff --git a/misc/ols.schema.json b/misc/ols.schema.json index 8093dc9..1ce278c 100644 --- a/misc/ols.schema.json +++ b/misc/ols.schema.json @@ -106,7 +106,7 @@ }, "exclude_path": { "type": "array", - "description": "List of paths that will be exldued from workspace symbol searches.", + "description": "List of paths that will be excluded from workspace symbol searches.", "items": { "type": "string" } diff --git a/src/common/ast.odin b/src/common/ast.odin index 4a576d7..b9033b0 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package common import "core:fmt" diff --git a/src/main.odin b/src/main.odin index 6e91583..26cf701 100644 --- a/src/main.odin +++ b/src/main.odin @@ -19,6 +19,7 @@ import "core:sys/windows" import "src:common" import "src:server" +VERSION :: "dev-2024-11-9:g584f01b" os_read :: proc(handle: rawptr, data: []byte) -> (int, int) { ptr := cast(^os.Handle)handle @@ -101,6 +102,10 @@ end :: proc() { } main :: proc() { + if len(os.args) > 1 && os.args[1] == "version" { + fmt.println("ols version", VERSION) + os.exit(0) + } reader := server.make_reader(os_read, cast(rawptr)&os.stdin) writer := server.make_writer(os_write, cast(rawptr)&os.stdout) diff --git a/src/server/build.odin b/src/server/build.odin index e3478ae..a681201 100644 --- a/src/server/build.odin +++ b/src/server/build.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package server import "base:runtime" diff --git a/src/server/completion.odin b/src/server/completion.odin index 75d0d64..130cc1a 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package server import "core:fmt" diff --git a/src/server/hover.odin b/src/server/hover.odin index ad9a9c6..2edc331 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package server import "core:fmt" diff --git a/src/server/requests.odin b/src/server/requests.odin index d9581ee..f884b0d 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package server import "base:intrinsics" diff --git a/src/server/snippets.odin b/src/server/snippets.odin index 1ab01a1..3dbbc29 100644 --- a/src/server/snippets.odin +++ b/src/server/snippets.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package server Snippet_Info :: struct { |