Skip to content

Commit

Permalink
Empty hidden editors (#14909)
Browse files Browse the repository at this point in the history
Clear model from editor when the editor is hidden

Fixes #14880

Contributed on behalf of STMicroelectronics

Signed-off-by: Thomas Mäder <[email protected]>
  • Loading branch information
tsmaeder authored Feb 14, 2025
1 parent 9891afd commit 72ca8ed
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 10 deletions.
8 changes: 6 additions & 2 deletions packages/core/src/browser/widgets/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,18 @@ export class BaseWidget extends Widget implements PreviewableWidget {
override setFlag(flag: Widget.Flag): void {
super.setFlag(flag);
if (flag === Widget.Flag.IsVisible) {
this.onDidChangeVisibilityEmitter.fire(this.isVisible);
this.handleVisiblityChanged(this.isVisible);
}
}

protected handleVisiblityChanged(isNowVisible: boolean): void {
this.onDidChangeVisibilityEmitter.fire(isNowVisible);
}

override clearFlag(flag: Widget.Flag): void {
super.clearFlag(flag);
if (flag === Widget.Flag.IsVisible) {
this.onDidChangeVisibilityEmitter.fire(this.isVisible);
this.handleVisiblityChanged(this.isVisible);
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions packages/editor/src/browser/editor-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ export class EditorWidget extends BaseWidget implements SaveableSource, Navigata
}
}

protected override handleVisiblityChanged(isNowVisible: boolean): void {
this.editor.handleVisibilityChanged(isNowVisible);
super.handleVisiblityChanged(isNowVisible);
}

get saveable(): Saveable {
return this.editor.document;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/browser/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ export interface TextEditor extends Disposable, TextEditorSelection, Navigatable
readonly onEncodingChanged: Event<string>;

shouldDisplayDirtyDiff(): boolean;

handleVisibilityChanged(nowVisible: boolean): void;
}

export interface Selection extends Range {
Expand Down
8 changes: 4 additions & 4 deletions packages/monaco/src/browser/monaco-editor-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
export const MonacoEditorFactory = Symbol('MonacoEditorFactory');
export interface MonacoEditorFactory {
readonly scheme: string;
create(model: MonacoEditorModel, defaultOptions: MonacoEditor.IOptions, defaultOverrides: EditorServiceOverrides): MonacoEditor;
create(model: MonacoEditorModel, defaultOptions: MonacoEditor.IOptions, defaultOverrides: EditorServiceOverrides): Promise<MonacoEditor>;
}

@injectable()
Expand Down Expand Up @@ -198,8 +198,8 @@ export class MonacoEditorProvider {
const options = this.createMonacoEditorOptions(model);
const factory = this.factories.getContributions().find(({ scheme }) => uri.scheme === scheme);
const editor = factory
? factory.create(model, options, override)
: new MonacoEditor(uri, model, document.createElement('div'), this.services, options, override);
? await factory.create(model, options, override)
: await MonacoEditor.create(uri, model, document.createElement('div'), this.services, options, override);
toDispose.push(this.editorPreferences.onPreferenceChanged(event => {
if (event.affects(uri.toString(), model.languageId)) {
this.updateMonacoEditorOptions(editor, event);
Expand Down Expand Up @@ -380,7 +380,7 @@ export class MonacoEditorProvider {
}, this.m2p, this.p2m);
toDispose.push(document);
const model = (await document.load()).textEditorModel;
return new MonacoEditor(
return await MonacoEditor.create(
uri,
document,
node,
Expand Down
40 changes: 39 additions & 1 deletion packages/monaco/src/browser/monaco-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import { ILanguageFeaturesService } from '@theia/monaco-editor-core/esm/vs/edito
import * as objects from '@theia/monaco-editor-core/esm/vs/base/common/objects';
import { Selection } from '@theia/editor/lib/browser/editor';
import { IHoverService } from '@theia/monaco-editor-core/esm/vs/platform/hover/browser/hover';
import { MonacoTextModelService } from './monaco-text-model-service';

export type ServicePair<T> = [ServiceIdentifier<T>, T];

Expand All @@ -81,13 +82,28 @@ export class MonacoEditorServices {
@inject(ContextKeyService)
protected readonly contextKeyService: ContextKeyService;

@inject(MonacoTextModelService)
protected readonly monacoModelService: MonacoTextModelService;

constructor(@unmanaged() services: MonacoEditorServices) {
Object.assign(this, services);
}
}

export class MonacoEditor extends MonacoEditorServices implements TextEditor {

static async create(uri: URI,
document: MonacoEditorModel,
node: HTMLElement,
services: MonacoEditorServices,
options?: MonacoEditor.IOptions,
override?: EditorServiceOverrides,
parentEditor?: MonacoEditor): Promise<MonacoEditor> {
const instance = new MonacoEditor(uri, document, node, services, options, override, parentEditor);
await instance.init();
return instance;
}

protected readonly toDispose = new DisposableCollection();

protected readonly autoSizing: boolean;
Expand All @@ -109,8 +125,10 @@ export class MonacoEditor extends MonacoEditorServices implements TextEditor {
readonly onDidResize = this.onResizeEmitter.event;

readonly documents = new Set<MonacoEditorModel>();
protected model: monaco.editor.ITextModel | null;
savedViewState: monaco.editor.ICodeEditorViewState | null;

constructor(
protected constructor(
readonly uri: URI,
readonly document: MonacoEditorModel,
readonly node: HTMLElement,
Expand Down Expand Up @@ -140,6 +158,10 @@ export class MonacoEditor extends MonacoEditorServices implements TextEditor {
this.addHandlers(this.editor);
}

protected async init(): Promise<void> {
this.toDispose.push(await this.monacoModelService.createModelReference(this.uri));
}

getEncoding(): string {
return this.document.getEncoding() || UTF8;
}
Expand Down Expand Up @@ -228,6 +250,22 @@ export class MonacoEditor extends MonacoEditorServices implements TextEditor {
}));
}

handleVisibilityChanged(nowVisible: boolean): void {
if (nowVisible) {
if (this.model) {
this.editor.setModel(this.model);
this.editor.restoreViewState(this.savedViewState);
this.editor.focus();
}
} else {
this.model = this.editor.getModel();
this.savedViewState = this.editor.saveViewState();

// eslint-disable-next-line no-null/no-null
this.editor.setModel(null); // workaround for https://github.com/eclipse-theia/theia/issues/14880
}
}

getVisibleRanges(): Range[] {
return this.editor.getVisibleRanges().map(range => this.m2p.asRange(range));
}
Expand Down
9 changes: 8 additions & 1 deletion packages/monaco/src/browser/monaco-to-protocol-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,14 @@ export class MonacoToProtocolConverter {
}
}

asSelection(selection: monaco.Selection): Selection {
asSelection(selection: monaco.Selection | null): Selection {
if (!selection) {
return {
start: { line: 0, character: 0 },
end: { line: 0, character: 0 },
direction: 'ltr'
};
}
const start = this.asPosition(selection.selectionStartLineNumber, selection.selectionStartColumn);
const end = this.asPosition(selection.positionLineNumber, selection.positionColumn);
return {
Expand Down
4 changes: 2 additions & 2 deletions packages/output/src/browser/output-editor-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ export class OutputEditorFactory implements MonacoEditorFactory {

readonly scheme: string = OutputUri.SCHEME;

create(model: MonacoEditorModel, defaultsOptions: MonacoEditor.IOptions): MonacoEditor {
create(model: MonacoEditorModel, defaultsOptions: MonacoEditor.IOptions): Promise<MonacoEditor> {
const uri = new URI(model.uri);
const options = this.createOptions(model, defaultsOptions);
const overrides = this.createOverrides(model);
return new MonacoEditor(uri, model, document.createElement('div'), this.services, options, overrides);
return MonacoEditor.create(uri, model, document.createElement('div'), this.services, options, overrides);
}

protected createOptions(model: MonacoEditorModel, defaultOptions: MonacoEditor.IOptions): MonacoEditor.IOptions {
Expand Down

0 comments on commit 72ca8ed

Please sign in to comment.