Fix undo cursor jumps and formatting
This commit is contained in:
parent
a570acf962
commit
4a3e78e56c
|
|
@ -17,8 +17,8 @@ export abstract class Displayable {
|
|||
private shortcuts = new Map<string, KeyHandler>();
|
||||
|
||||
constructor() {
|
||||
// Attempt to install handlers shortly after construction. If `dom` is not
|
||||
// available yet, retry a few times.
|
||||
// Attempt to install handlers shortly after construction.
|
||||
// If `dom` is not available yet, retry a few times.
|
||||
setTimeout(() => this.installHandlers(0), 0);
|
||||
|
||||
// Add general shortcuts
|
||||
|
|
|
|||
|
|
@ -167,10 +167,7 @@ export class OpenFile implements WorkspaceFile {
|
|||
this.rootState.val = transaction.state;
|
||||
|
||||
if (transaction.changes && !transaction.changes.empty) {
|
||||
if (this.changes === undefined) {
|
||||
this.changes = ChangeSet.empty(this.rootState.val.doc.length);
|
||||
}
|
||||
this.changes = this.changes.compose(transaction.changes);
|
||||
this.changeSet = this.changes.compose(transaction.changes);
|
||||
}
|
||||
|
||||
if (origin) {
|
||||
|
|
@ -178,7 +175,12 @@ export class OpenFile implements WorkspaceFile {
|
|||
es.forEach((e) => e.dispatch(e.view.state.update(trs), true));
|
||||
} else {
|
||||
this.editors.forEach((e) => {
|
||||
e.dispatch(e.view.state.update(trs), true);
|
||||
const changes = transaction.changes;
|
||||
const userEvent = transaction.annotation(Transaction.userEvent);
|
||||
const annotations = userEvent
|
||||
? [Transaction.userEvent.of(userEvent)]
|
||||
: [];
|
||||
e.dispatch(e.view.state.update({ changes, annotations }), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -203,8 +205,16 @@ export class OpenFile implements WorkspaceFile {
|
|||
get languageId(): string {
|
||||
return inferLanguageFromPath(this.filePath.val || "") || "";
|
||||
}
|
||||
|
||||
doc: Text;
|
||||
changes: ChangeSet;
|
||||
private changeSet: ChangeSet;
|
||||
get changes(): ChangeSet {
|
||||
if (!this.changeSet) {
|
||||
this.changeSet = ChangeSet.empty(this.rootState.val.doc.length);
|
||||
}
|
||||
return this.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.
|
||||
|
|
|
|||
|
|
@ -1,52 +1,76 @@
|
|||
import type * as lsp from "vscode-languageserver-protocol"
|
||||
import {ViewPlugin, ViewUpdate} from "@codemirror/view"
|
||||
import {LSPPlugin, LSPClientExtension} from "@codemirror/lsp-client"
|
||||
import {OpenFile} from "../filestate"
|
||||
import { Text } from "@codemirror/state"
|
||||
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";
|
||||
import { Text } from "@codemirror/state";
|
||||
|
||||
function toSeverity(sev: lsp.DiagnosticSeverity) {
|
||||
return sev == 1 ? "error" : sev == 2 ? "warning" : sev == 3 ? "info" : "hint"
|
||||
return sev == 1
|
||||
? "error"
|
||||
: sev == 2
|
||||
? "warning"
|
||||
: sev == 3
|
||||
? "info"
|
||||
: "hint";
|
||||
}
|
||||
|
||||
const autoSync = ViewPlugin.fromClass(class {
|
||||
pending: any | null = null
|
||||
update(update: ViewUpdate) {
|
||||
if (update.docChanged) {
|
||||
if (this.pending != null) clearTimeout(this.pending)
|
||||
this.pending = setTimeout(() => {
|
||||
this.pending = null
|
||||
const plugin = LSPPlugin.get(update.view)
|
||||
if (plugin) plugin.client.sync()
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
destroy() {
|
||||
if (this.pending != null) clearTimeout(this.pending)
|
||||
}
|
||||
})
|
||||
const autoSync = ViewPlugin.fromClass(
|
||||
class {
|
||||
pending: any | null = null;
|
||||
update(update: ViewUpdate) {
|
||||
if (update.docChanged) {
|
||||
if (this.pending != null) clearTimeout(this.pending);
|
||||
this.pending = setTimeout(() => {
|
||||
this.pending = null;
|
||||
const plugin = LSPPlugin.get(update.view);
|
||||
if (plugin) plugin.client.sync();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
destroy() {
|
||||
if (this.pending != null) clearTimeout(this.pending);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function fromPosition(doc: Text, pos: lsp.Position): number {
|
||||
const line = doc.line(pos.line + 1)
|
||||
return line.from + pos.character
|
||||
const line = doc.line(pos.line + 1);
|
||||
return line.from + pos.character;
|
||||
}
|
||||
|
||||
export function serverDiagnostics(): LSPClientExtension {
|
||||
return {
|
||||
clientCapabilities: {textDocument: {publishDiagnostics: {versionSupport: true}}},
|
||||
notificationHandlers: {
|
||||
"textDocument/publishDiagnostics": (client, params: lsp.PublishDiagnosticsParams) => {
|
||||
const file = client.workspace.getFile(params.uri) as OpenFile;
|
||||
if (!file || params.version != null && params.version != file.version) return false;
|
||||
const mapPos = (p: number) => file.changes ? file.changes.mapPos(p) : p;
|
||||
file.setDiagnostics(params.diagnostics.map(item => ({
|
||||
from: mapPos(fromPosition(file.doc, item.range.start)),
|
||||
to: mapPos(fromPosition(file.doc, item.range.end)),
|
||||
severity: toSeverity(item.severity ?? 1),
|
||||
message: item.message,
|
||||
})));
|
||||
return true
|
||||
}
|
||||
},
|
||||
editorExtension: autoSync
|
||||
}
|
||||
return {
|
||||
clientCapabilities: {
|
||||
textDocument: { publishDiagnostics: { versionSupport: true } },
|
||||
},
|
||||
notificationHandlers: {
|
||||
"textDocument/publishDiagnostics": (
|
||||
client,
|
||||
params: lsp.PublishDiagnosticsParams,
|
||||
) => {
|
||||
const file = client.workspace.getFile(params.uri) as OpenFile;
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
if (params.version != null && params.version != file.version) {
|
||||
return false;
|
||||
}
|
||||
file.setDiagnostics(
|
||||
params.diagnostics.map((item) => ({
|
||||
from: file.changes.mapPos(
|
||||
fromPosition(file.doc, item.range.start),
|
||||
),
|
||||
to: file.changes.mapPos(
|
||||
fromPosition(file.doc, item.range.end),
|
||||
),
|
||||
severity: toSeverity(item.severity ?? 1),
|
||||
message: item.message,
|
||||
})),
|
||||
);
|
||||
return true;
|
||||
},
|
||||
},
|
||||
editorExtension: autoSync,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ let currentWorkspaceRoot: string | null = null;
|
|||
let watcher: chokidar.FSWatcher | null = null;
|
||||
|
||||
export function getCurrentWorkspaceRoot(): string | null {
|
||||
return currentWorkspaceRoot;
|
||||
return currentWorkspaceRoot;
|
||||
}
|
||||
|
||||
// Helper to (re)create watcher and wire up IPC notifications to renderer
|
||||
|
|
|
|||
|
|
@ -86,7 +86,9 @@ function ensureLspForKey(
|
|||
const len = parseInt(m[1], 10);
|
||||
const totalLen = headerEnd + 4 + len;
|
||||
if (entry.buffer.length < totalLen) break; // wait for more
|
||||
const body = entry.buffer.subarray(headerEnd + 4, totalLen).toString();
|
||||
const body = entry.buffer
|
||||
.subarray(headerEnd + 4, totalLen)
|
||||
.toString();
|
||||
// Forward body to all attached ports
|
||||
try {
|
||||
entry.ports.forEach((p) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue