Open definitions in new column

This commit is contained in:
Quinten Kock 2025-12-06 22:22:10 +01:00
parent 4a245fbe9e
commit b058ae8a6f
7 changed files with 88 additions and 7 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "miller",
"version": "0.2.2",
"version": "0.2.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "miller",
"version": "0.2.2",
"version": "0.2.3",
"license": "GPL-3.0-or-later",
"dependencies": {
"chokidar": "^5.0.0",

View File

@ -1,7 +1,7 @@
{
"name": "miller",
"productName": "miller",
"version": "0.2.2",
"version": "0.2.3",
"description": "Column-based code editor",
"main": ".vite/build/main.js",
"scripts": {

View File

@ -41,9 +41,9 @@ import { OpenFile } from "./filestate";
import {
findReferencesKeymap,
formatKeymap,
jumpToDefinitionKeymap,
renameKeymap,
} from "@codemirror/lsp-client";
import { jumpToDefinitionKeymap } from "./lsp/definition";
const fixedHeightEditor = EditorView.theme({
"&": {

View File

@ -77,10 +77,11 @@ const EditorWrapper = (
const editors: Displayable[][] = vanX.reactive([[]]);
const currentTab = van.state(0);
export function addEditor(file: OpenFile) {
export function addEditor(file: OpenFile): Editor {
const editor = file.createEditor();
editors[currentTab.val].push(vanX.noreactive(editor));
editor.focus();
return editor;
}
export function addTab() {

View File

@ -1,7 +1,7 @@
// Minimal LSP integration helper for the editor.
// Keeps all LSP-specific logic in one place so it's easy to review.
import { Extension, ChangeSet, TransactionSpec } from "@codemirror/state";
import { Extension, TransactionSpec } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import {

81
src/app/lsp/definition.ts Normal file
View File

@ -0,0 +1,81 @@
import type * as lsp from "vscode-languageserver-protocol"
import { EditorView, Command, KeyBinding } from "@codemirror/view"
import { LSPPlugin } from "@codemirror/lsp-client";
import { addEditor } from "../editorgrid";
import { OpenFile } from "../filestate";
function getDefinition(plugin: LSPPlugin, pos: number) {
return plugin.client.request<lsp.DefinitionParams, lsp.Location | lsp.Location[] | null>("textDocument/definition", {
textDocument: { uri: plugin.uri },
position: plugin.toPosition(pos)
})
}
function getDeclaration(plugin: LSPPlugin, pos: number) {
return plugin.client.request<lsp.DeclarationParams, lsp.Location | lsp.Location[] | null>("textDocument/declaration", {
textDocument: { uri: plugin.uri },
position: plugin.toPosition(pos)
})
}
function getTypeDefinition(plugin: LSPPlugin, pos: number) {
return plugin.client.request<lsp.TypeDefinitionParams, lsp.Location | lsp.Location[] | null>("textDocument/typeDefinition", {
textDocument: { uri: plugin.uri },
position: plugin.toPosition(pos)
})
}
function getImplementation(plugin: LSPPlugin, pos: number) {
return plugin.client.request<lsp.ImplementationParams, lsp.Location | lsp.Location[] | null>("textDocument/implementation", {
textDocument: { uri: plugin.uri },
position: plugin.toPosition(pos)
})
}
function jumpToOrigin(view: EditorView, type: { get: typeof getDefinition, capability: keyof lsp.ServerCapabilities }): boolean {
const plugin = LSPPlugin.get(view);
const hasCapability = plugin.client.serverCapabilities ? !!plugin.client.serverCapabilities[type.capability] : null;
if (!plugin || !hasCapability) return false
plugin.client.sync()
plugin.client.withMapping(mapping => type.get(plugin, view.state.selection.main.head).then(async response => {
if (!response) return
let loc = Array.isArray(response) ? response[0] : response;
const path = new URL(loc.uri).pathname;
const target = addEditor(await OpenFile.openFile(path));
const pos = mapping.getMapping(loc.uri) ? mapping.mapPosition(loc.uri, loc.range.start) : plugin.fromPosition(loc.range.start, target.view.state.doc);
target.view.dispatch({selection: {anchor: pos}, scrollIntoView: true, userEvent: "select.definition"});
}, error => plugin.reportError("Find definition failed", error)))
return true
}
/// Jump to the definition of the symbol at the cursor. To support
/// cross-file jumps, you'll need to implement
/// [`Workspace.displayFile`](#lsp-client.Workspace.displayFile).
export const jumpToDefinition: Command = view => jumpToOrigin(view, {
get: getDefinition,
capability: "definitionProvider"
})
/// Jump to the declaration of the symbol at the cursor.
export const jumpToDeclaration: Command = view => jumpToOrigin(view, {
get: getDeclaration,
capability: "declarationProvider"
})
/// Jump to the type definition of the symbol at the cursor.
export const jumpToTypeDefinition: Command = view => jumpToOrigin(view, {
get: getTypeDefinition,
capability: "typeDefinitionProvider"
})
/// Jump to the implementation of the symbol at the cursor.
export const jumpToImplementation: Command = view => jumpToOrigin(view, {
get: getImplementation,
capability: "implementationProvider"
})
/// Binds F12 to [`jumpToDefinition`](#lsp-client.jumpToDefinition).
export const jumpToDefinitionKeymap: readonly KeyBinding[] = [
{ key: "F12", run: jumpToDefinition, preventDefault: true },
]

View File

@ -1,5 +1,4 @@
import type * as lsp from "vscode-languageserver-protocol";
import { ChangeSet } from "@codemirror/state";
import { ViewPlugin, ViewUpdate } from "@codemirror/view";
import { LSPPlugin, LSPClientExtension } from "@codemirror/lsp-client";
import { OpenFile } from "../filestate";