feat(workspace): add external file change detection, conflict resolution UI, and diff editor

This commit is contained in:
2026-01-01 11:32:01 +00:00
parent 3a7c2fe781
commit a20d9ff138
7 changed files with 648 additions and 2 deletions

View File

@@ -242,4 +242,53 @@ export class DeesWorkspaceMonaco extends DeesElement {
this.monacoThemeSubscription = null;
}
}
/**
* Update content from external source with optional cursor preservation.
* Use this when the file content changes externally (e.g., file changed on disk).
* @param newContent The new content to set
* @param preserveCursor Whether to preserve cursor/scroll position (default: true)
*/
public async setContentExternal(
newContent: string,
preserveCursor: boolean = true
): Promise<void> {
const editor = await this.editorDeferred.promise;
const currentValue = editor.getValue();
if (currentValue === newContent) return;
// Save cursor state if preserving
const position = preserveCursor ? editor.getPosition() : null;
const selections = preserveCursor ? editor.getSelections() : null;
const scrollTop = preserveCursor ? editor.getScrollTop() : 0;
const scrollLeft = preserveCursor ? editor.getScrollLeft() : 0;
// Update content
this.isUpdatingFromExternal = true;
editor.setValue(newContent);
this.isUpdatingFromExternal = false;
// Restore cursor state if preserving
if (preserveCursor) {
if (position) {
// Clamp position to valid range
const model = editor.getModel();
const lineCount = model?.getLineCount() || 1;
const clampedLine = Math.min(position.lineNumber, lineCount);
const lineLength = model?.getLineMaxColumn(clampedLine) || 1;
const clampedColumn = Math.min(position.column, lineLength);
editor.setPosition({ lineNumber: clampedLine, column: clampedColumn });
}
if (selections && selections.length > 0) {
// Selections may be invalid after content change, wrap in try-catch
try {
editor.setSelections(selections);
} catch {
// Ignore invalid selections
}
}
editor.setScrollPosition({ scrollTop, scrollLeft });
}
}
}