Fix state sync

This commit is contained in:
Quinten Kock 2025-12-01 12:52:42 +01:00
parent 9f3befdb61
commit aecff9f546
4 changed files with 38 additions and 51 deletions

32
package-lock.json generated
View File

@ -1,15 +1,15 @@
{ {
"name": "miller", "name": "miller",
"version": "0.1.0", "version": "0.2.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "miller", "name": "miller",
"version": "0.1.0", "version": "0.2.1",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"dependencies": { "dependencies": {
"chokidar": "^4.0.3", "chokidar": "^5.0.0",
"electron-squirrel-startup": "^1.0.1", "electron-squirrel-startup": "^1.0.1",
"node-pty": "^1.1.0-beta39" "node-pty": "^1.1.0-beta39"
}, },
@ -37,7 +37,7 @@
"@xterm/addon-fit": "^0.10.0", "@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0", "@xterm/xterm": "^5.5.0",
"codemirror": "^6.0.2", "codemirror": "^6.0.2",
"electron": "39.1.1", "electron": "39.2.4",
"eslint": "^9.39.1", "eslint": "^9.39.1",
"eslint-plugin-import": "^2.32.0", "eslint-plugin-import": "^2.32.0",
"globals": "^16.5.0", "globals": "^16.5.0",
@ -4723,15 +4723,15 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/chokidar": { "node_modules/chokidar": {
"version": "4.0.3", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"readdirp": "^4.0.1" "readdirp": "^5.0.0"
}, },
"engines": { "engines": {
"node": ">= 14.16.0" "node": ">= 20.19.0"
}, },
"funding": { "funding": {
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
@ -5253,9 +5253,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron": { "node_modules/electron": {
"version": "39.1.1", "version": "39.2.4",
"resolved": "https://registry.npmjs.org/electron/-/electron-39.1.1.tgz", "resolved": "https://registry.npmjs.org/electron/-/electron-39.2.4.tgz",
"integrity": "sha512-VuFEI1yQ7BH3RYI5VZtwFlzGp4rpPRd5oEc26ZQIItVLcLTbXt4/O7o4hs+1fyg9Q3NvGAifgX5Vp5EBOIFpAg==", "integrity": "sha512-KxPtwpFceQKSxRtUY39piHLYhJMMyHfOhc70e6zRnKGrbRdK6hzEqssth8IGjlKOdkeT4KCvIEngnNraYk39+g==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
@ -9921,12 +9921,12 @@
} }
}, },
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "4.1.2", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 14.18.0" "node": ">= 20.19.0"
}, },
"funding": { "funding": {
"type": "individual", "type": "individual",

View File

@ -1,7 +1,7 @@
{ {
"name": "miller", "name": "miller",
"productName": "miller", "productName": "miller",
"version": "0.1.0", "version": "0.2.1",
"description": "Column-based code editor", "description": "Column-based code editor",
"main": ".vite/build/main.js", "main": ".vite/build/main.js",
"scripts": { "scripts": {
@ -42,7 +42,7 @@
"@xterm/addon-fit": "^0.10.0", "@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0", "@xterm/xterm": "^5.5.0",
"codemirror": "^6.0.2", "codemirror": "^6.0.2",
"electron": "39.1.1", "electron": "39.2.4",
"eslint": "^9.39.1", "eslint": "^9.39.1",
"eslint-plugin-import": "^2.32.0", "eslint-plugin-import": "^2.32.0",
"globals": "^16.5.0", "globals": "^16.5.0",
@ -55,7 +55,7 @@
"vite": "^7.2.2" "vite": "^7.2.2"
}, },
"dependencies": { "dependencies": {
"chokidar": "^4.0.3", "chokidar": "^5.0.0",
"electron-squirrel-startup": "^1.0.1", "electron-squirrel-startup": "^1.0.1",
"node-pty": "^1.1.0-beta39" "node-pty": "^1.1.0-beta39"
} }

View File

@ -5,6 +5,7 @@ import {
StateEffect, StateEffect,
Text, Text,
Transaction, Transaction,
ChangeSet,
} from "@codemirror/state"; } from "@codemirror/state";
import { history } from "@codemirror/commands"; import { history } from "@codemirror/commands";
import { Editor } from "./editor"; import { Editor } from "./editor";
@ -159,10 +160,11 @@ export class OpenFile implements WorkspaceFile {
const transaction = this.rootState.val.update(trs); const transaction = this.rootState.val.update(trs);
this.rootState.val = transaction.state; this.rootState.val = transaction.state;
// If the transaction introduced document changes, increment version
if (transaction.changes && !transaction.changes.empty) { if (transaction.changes && !transaction.changes.empty) {
this.version = (this.version || 0) + 1; if (this.changes === undefined) {
// TODO: call LSP didChange notification helper here this.changes = ChangeSet.empty(this.rootState.val.doc.length);
}
this.changes = this.changes.compose(transaction.changes);
} }
if (origin) { if (origin) {
@ -200,9 +202,8 @@ export class OpenFile implements WorkspaceFile {
get languageId(): string { get languageId(): string {
return inferLanguageFromPath(this.filePath.val || "") || ""; return inferLanguageFromPath(this.filePath.val || "") || "";
} }
get doc(): Text { doc: Text;
return this.rootState.val.doc; changes: ChangeSet;
}
// Return an EditorView to be used by the LSP Workspace for position mapping. // 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 // If `main` is provided and belongs to this open file, return it. Otherwise
// return the first available editor view, or null if none exist. // return the first available editor view, or null if none exist.

View File

@ -8,8 +8,6 @@ import {
LSPClient, LSPClient,
languageServerExtensions, languageServerExtensions,
Workspace, Workspace,
WorkspaceFile,
LSPPlugin,
} from "@codemirror/lsp-client"; } from "@codemirror/lsp-client";
import { OpenFile } from "./filestate"; 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. // based on the editor views or the OpenFile state when no view exists.
// TODO: fix (cause vibe coding is useless) // TODO: fix (cause vibe coding is useless)
syncFiles() { syncFiles() {
let result: any[] = []; const result = [];
for (let file of this.files) { for (const file of this.files) {
const view = file.getView?.(); const prevDoc = file.doc;
if (view) { // TODO: get changes from rootState (tracked in OpenFile) rather than the view's LSPPlugin.
const plugin = LSPPlugin.get(view); const changes = file.changes;
if (!plugin) continue; if (changes && !changes.empty) {
const changes = plugin.unsyncedChanges; result.push({ file, prevDoc, changes });
if (!changes.empty) { file.doc = file.rootState.val.doc;
result.push({ file, prevDoc: file.doc, changes }); file.version = this.nextFileVersion(file.uri);
file.doc = view.state.doc; file.changes = ChangeSet.empty(file.doc.length);
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);
}
} }
} }
return result; return result;
@ -139,6 +123,7 @@ class OpenFileWorkspace extends Workspace {
console.warn("LSP: attempted to open unknown file", uri); console.warn("LSP: attempted to open unknown file", uri);
return; return;
} }
of.doc = view.state.doc;
this.files.push(of); this.files.push(of);
this.client.didOpen(of); this.client.didOpen(of);
} }
@ -149,6 +134,7 @@ class OpenFileWorkspace extends Workspace {
console.warn("LSP: attempted to update unknown file", uri); console.warn("LSP: attempted to update unknown file", uri);
return; return;
} }
// TODO: maybe couple undos across editors for things like LSP rename?
file.dispatch(update); file.dispatch(update);
} }