diff --git a/package-lock.json b/package-lock.json index 9974355..7d665ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "miller", - "version": "0.1.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "miller", - "version": "0.1.0", + "version": "0.2.1", "license": "GPL-3.0-or-later", "dependencies": { - "chokidar": "^4.0.3", + "chokidar": "^5.0.0", "electron-squirrel-startup": "^1.0.1", "node-pty": "^1.1.0-beta39" }, @@ -37,7 +37,7 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "codemirror": "^6.0.2", - "electron": "39.1.1", + "electron": "39.2.4", "eslint": "^9.39.1", "eslint-plugin-import": "^2.32.0", "globals": "^16.5.0", @@ -4723,15 +4723,15 @@ "license": "MIT" }, "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -5253,9 +5253,9 @@ "license": "MIT" }, "node_modules/electron": { - "version": "39.1.1", - "resolved": "https://registry.npmjs.org/electron/-/electron-39.1.1.tgz", - "integrity": "sha512-VuFEI1yQ7BH3RYI5VZtwFlzGp4rpPRd5oEc26ZQIItVLcLTbXt4/O7o4hs+1fyg9Q3NvGAifgX5Vp5EBOIFpAg==", + "version": "39.2.4", + "resolved": "https://registry.npmjs.org/electron/-/electron-39.2.4.tgz", + "integrity": "sha512-KxPtwpFceQKSxRtUY39piHLYhJMMyHfOhc70e6zRnKGrbRdK6hzEqssth8IGjlKOdkeT4KCvIEngnNraYk39+g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -9921,12 +9921,12 @@ } }, "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", diff --git a/package.json b/package.json index 005f38d..50f8e69 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "miller", "productName": "miller", - "version": "0.1.0", + "version": "0.2.1", "description": "Column-based code editor", "main": ".vite/build/main.js", "scripts": { @@ -42,7 +42,7 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "codemirror": "^6.0.2", - "electron": "39.1.1", + "electron": "39.2.4", "eslint": "^9.39.1", "eslint-plugin-import": "^2.32.0", "globals": "^16.5.0", @@ -55,7 +55,7 @@ "vite": "^7.2.2" }, "dependencies": { - "chokidar": "^4.0.3", + "chokidar": "^5.0.0", "electron-squirrel-startup": "^1.0.1", "node-pty": "^1.1.0-beta39" } diff --git a/src/app/filestate.ts b/src/app/filestate.ts index 526e743..343b17e 100644 --- a/src/app/filestate.ts +++ b/src/app/filestate.ts @@ -5,6 +5,7 @@ import { StateEffect, Text, Transaction, + ChangeSet, } from "@codemirror/state"; import { history } from "@codemirror/commands"; import { Editor } from "./editor"; @@ -159,10 +160,11 @@ export class OpenFile implements WorkspaceFile { const transaction = this.rootState.val.update(trs); this.rootState.val = transaction.state; - // If the transaction introduced document changes, increment version if (transaction.changes && !transaction.changes.empty) { - this.version = (this.version || 0) + 1; - // TODO: call LSP didChange notification helper here + if (this.changes === undefined) { + this.changes = ChangeSet.empty(this.rootState.val.doc.length); + } + this.changes = this.changes.compose(transaction.changes); } if (origin) { @@ -200,9 +202,8 @@ export class OpenFile implements WorkspaceFile { get languageId(): string { return inferLanguageFromPath(this.filePath.val || "") || ""; } - get doc(): Text { - return this.rootState.val.doc; - } + doc: Text; + changes: ChangeSet; // Return an EditorView to be used by the LSP Workspace for position mapping. // If `main` is provided and belongs to this open file, return it. Otherwise // return the first available editor view, or null if none exist. diff --git a/src/app/lsp.ts b/src/app/lsp.ts index 9540f73..e378b54 100644 --- a/src/app/lsp.ts +++ b/src/app/lsp.ts @@ -8,8 +8,6 @@ import { LSPClient, languageServerExtensions, Workspace, - WorkspaceFile, - LSPPlugin, } from "@codemirror/lsp-client"; import { OpenFile } from "./filestate"; @@ -100,30 +98,16 @@ class OpenFileWorkspace extends Workspace { // based on the editor views or the OpenFile state when no view exists. // TODO: fix (cause vibe coding is useless) syncFiles() { - let result: any[] = []; - for (let file of this.files) { - const view = file.getView?.(); - if (view) { - const plugin = LSPPlugin.get(view); - if (!plugin) continue; - const changes = plugin.unsyncedChanges; - if (!changes.empty) { - result.push({ file, prevDoc: file.doc, changes }); - file.doc = view.state.doc; - file.version = this.nextFileVersion(file.uri); - plugin.clear(); - } - } else { - // No view; try to find a corresponding OpenFile and update - const path = file.uri.replace(/^file:\/\//, ""); - const of = OpenFile.findOpenFile(path); - if (of && of.doc.toString() !== file.doc.toString()) { - const prev = file.doc; - const changes = ChangeSet.empty(prev.length); - result.push({ file, prevDoc: prev, changes }); - file.doc = of.doc; - file.version = this.nextFileVersion(file.uri); - } + const result = []; + for (const file of this.files) { + const prevDoc = file.doc; + // TODO: get changes from rootState (tracked in OpenFile) rather than the view's LSPPlugin. + const changes = file.changes; + if (changes && !changes.empty) { + result.push({ file, prevDoc, changes }); + file.doc = file.rootState.val.doc; + file.version = this.nextFileVersion(file.uri); + file.changes = ChangeSet.empty(file.doc.length); } } return result; @@ -139,6 +123,7 @@ class OpenFileWorkspace extends Workspace { console.warn("LSP: attempted to open unknown file", uri); return; } + of.doc = view.state.doc; this.files.push(of); this.client.didOpen(of); } @@ -149,6 +134,7 @@ class OpenFileWorkspace extends Workspace { console.warn("LSP: attempted to update unknown file", uri); return; } + // TODO: maybe couple undos across editors for things like LSP rename? file.dispatch(update); }