Skip to content

Commit

Permalink
Handle deleted files in open editors widget
Browse files Browse the repository at this point in the history
  • Loading branch information
kenneth-marut-work committed Nov 1, 2021
1 parent bca6eda commit 5b72c8f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 11 deletions.
7 changes: 4 additions & 3 deletions packages/editor-preview/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
"version": "1.19.0",
"description": "Theia - Editor Preview Extension",
"dependencies": {
"@theia/core": "1.19.0",
"@theia/editor": "1.19.0",
"@theia/navigator": "1.19.0"
"@theia/core": "1.18.0",
"@theia/editor": "1.18.0",
"@theia/filesystem": "1.18.0",
"@theia/navigator": "1.18.0"
},
"publishConfig": {
"access": "public"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,29 @@ import { Emitter } from '@theia/core/lib/common/event';
import { Tree } from '@theia/core/lib/browser/tree/tree';
import {
ApplicationShell,
CorePreferences,
DepthFirstTreeIterator,
FrontendApplication,
FrontendApplicationContribution,
NavigatableWidget,
Saveable,
Widget,
} from '@theia/core/lib/browser';
import { Disposable } from '@theia/core/lib/common';
import { Disposable, MaybeArray } from '@theia/core/lib/common';
import { OpenEditorNode } from '@theia/navigator/lib/browser/open-editors-widget/navigator-open-editors-tree-model';
import { EditorPreviewWidget } from './editor-preview-widget';
import { EditorPreviewManager } from './editor-preview-manager';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { FileChangesEvent } from '@theia/filesystem/lib/common/files';

@injectable()
export class EditorPreviewTreeDecorator implements TreeDecorator, FrontendApplicationContribution {
@inject(EditorPreviewManager) protected readonly editorPreviewManager: EditorPreviewManager;
@inject(ApplicationShell) protected readonly shell: ApplicationShell;
@inject(CorePreferences) protected readonly corePreferences: CorePreferences;
@inject(FileService) protected readonly fileService: FileService;

protected deletedEditorIds = new Set<string>();

readonly id = 'theia-open-editors-file-decorator';
protected decorationsMap = new Map<string, TreeDecoration.Data>();
Expand All @@ -49,6 +56,35 @@ export class EditorPreviewTreeDecorator implements TreeDecorator, FrontendApplic
this.shell.onDidAddWidget(widget => this.registerEditorListeners(widget));
this.shell.onDidRemoveWidget(widget => this.unregisterEditorListeners(widget));
this.editorWidgets.forEach(widget => this.registerEditorListeners(widget));
this.fileService.onDidFilesChange(async (event: FileChangesEvent) => {
if (!this.corePreferences['workbench.editor.closeOnFileDelete']) {
await this.checkForEditorDeleted(event);
this.fireDidChangeDecorations((tree: Tree) => this.collectDecorators(tree));
}
});
}

protected async checkForEditorDeleted(event: FileChangesEvent): Promise<void[] | undefined> {
// this implementation to check for deleted files is necessary since the gotDeleted check is not always reliable
const fileExistPromises: Promise<void>[] = [];
this.editorWidgets.forEach(editor => {
const editorURI = editor.getResourceUri();
if (editorURI && event.contains(editorURI)) {
const fileExistsPromise = this.fileService.exists(editorURI)
.then(doesExist => {
if (doesExist) {
this.deletedEditorIds.delete(editor.id);
} else {
this.deletedEditorIds.add(editor.id);
}
});
fileExistPromises.push(fileExistsPromise);
}
});
if (!fileExistPromises.length) {
return;
}
return Promise.all(fileExistPromises);
}

protected registerEditorListeners(widget: Widget): void {
Expand Down Expand Up @@ -93,13 +129,18 @@ export class EditorPreviewTreeDecorator implements TreeDecorator, FrontendApplic
return result;
}
for (const node of new DepthFirstTreeIterator(tree.root)) {
if (OpenEditorNode.is(node)) {
if (OpenEditorNode.is(node) && NavigatableWidget.is(node.widget)) {
const { widget } = node;
const isPreviewWidget = widget instanceof EditorPreviewWidget && widget.isPreview;
const decorations: TreeDecoration.Data = {
fontData: { style: isPreviewWidget ? 'italic' : undefined }
};
result.set(node.id, decorations);
const deleted = this.deletedEditorIds.has(widget.id);
const style: MaybeArray<TreeDecoration.FontStyle> = [];
if (isPreviewWidget) {
style.push('italic');
}
if (deleted) {
style.push('line-through');
}
result.set(node.id, { fontData: { style } });
}
}
return result;
Expand Down
6 changes: 6 additions & 0 deletions packages/editor-preview/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
},
{
"path": "../editor"
},
{
"path": "../filesystem"
},
{
"path": "../navigator"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
import { WorkspaceService } from '@theia/workspace/lib/browser';
import debounce = require('@theia/core/shared/lodash.debounce');
import { DisposableCollection } from '@theia/core/lib/common';
import { FileStat } from '@theia/filesystem/lib/common/files';

export interface OpenEditorNode extends FileStatNode {
widget: Widget;
};
Expand Down Expand Up @@ -60,6 +62,8 @@ export class OpenEditorsModel extends FileTreeModel {
// Last collection of editors before a layout modification, used to detect changes in widget ordering
protected _lastEditorWidgetsByArea = new Map<ApplicationShell.Area, NavigatableWidget[]>();

protected cachedFileStats = new Map<string, FileStat>();

get editorWidgets(): NavigatableWidget[] {
const editorWidgets: NavigatableWidget[] = [];
this._editorWidgetsByArea.forEach(widgets => editorWidgets.push(...widgets));
Expand All @@ -84,7 +88,15 @@ export class OpenEditorsModel extends FileTreeModel {
this.selectNode(nodeToSelect);
}
}));
this.toDispose.push(this.applicationShell.onDidAddWidget(() => this.updateOpenWidgets()));
this.toDispose.push(this.applicationShell.onDidAddWidget(async () => {
await this.updateOpenWidgets();
const existingWidgetIds = this.editorWidgets.map(widget => widget.id);
this.cachedFileStats.forEach((_fileStat, id) => {
if (!existingWidgetIds.includes(id)) {
this.cachedFileStats.delete(id);
}
});
}));
this.toDispose.push(this.applicationShell.onDidRemoveWidget(() => this.updateOpenWidgets()));
// Check for tabs rearranged in main and bottom
this.applicationShell.mainPanel.layoutModified.connect(() => this.doUpdateOpenWidgets('main'));
Expand Down Expand Up @@ -187,7 +199,19 @@ export class OpenEditorsModel extends FileTreeModel {
for (const widget of widgetsInArea) {
const uri = widget.getResourceUri();
if (uri) {
const fileStat = await this.fileService.resolve(uri);
let fileStat: FileStat;
try {
fileStat = await this.fileService.resolve(uri);
this.cachedFileStats.set(widget.id, fileStat);
} catch {
const cachedStat = this.cachedFileStats.get(widget.id);
if (cachedStat) {
fileStat = cachedStat;
} else {
continue;
}
}

const openEditorNode: OpenEditorNode = {
id: widget.id,
fileStat,
Expand Down

0 comments on commit 5b72c8f

Please sign in to comment.