1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/binaryeditor';
import { localize } from 'vs/nls';
import { Emitter } from 'vs/base/common/event';
import { IEditorOpenContext } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Dimension, size, clearNode } from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
import { ByteSize } from 'vs/platform/files/common/files';
import { IEditorOptions } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Link } from 'vs/platform/opener/browser/link';
export interface IOpenCallbacks {
openInternal: (input: EditorInput, options: IEditorOptions | undefined) => Promise<void>;
}
/*
* This class is only intended to be subclassed and not instantiated.
*/
export abstract class BaseBinaryResourceEditor extends EditorPane {
private readonly _onDidChangeMetadata = this._register(new Emitter<void>());
readonly onDidChangeMetadata = this._onDidChangeMetadata.event;
private readonly _onDidOpenInPlace = this._register(new Emitter<void>());
readonly onDidOpenInPlace = this._onDidOpenInPlace.event;
private metadata: string | undefined;
private binaryContainer: HTMLElement | undefined;
private scrollbar: DomScrollableElement | undefined;
private inputDisposable = this._register(new MutableDisposable());
constructor(
id: string,
private readonly callbacks: IOpenCallbacks,
telemetryService: ITelemetryService,
themeService: IThemeService,
@IStorageService storageService: IStorageService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super(id, telemetryService, themeService, storageService);
}
override getTitle(): string {
return this.input ? this.input.getName() : localize('binaryEditor', "Binary Viewer");
}
protected createEditor(parent: HTMLElement): void {
// Container for Binary
this.binaryContainer = document.createElement('div');
this.binaryContainer.className = 'monaco-binary-resource-editor';
this.binaryContainer.style.outline = 'none';
this.binaryContainer.tabIndex = 0; // enable focus support from the editor part (do not remove)
// Custom Scrollbars
this.scrollbar = this._register(new DomScrollableElement(this.binaryContainer, { horizontal: ScrollbarVisibility.Auto, vertical: ScrollbarVisibility.Auto }));
parent.appendChild(this.scrollbar.getDomNode());
}
override async setInput(input: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
await super.setInput(input, options, context, token);
const model = await input.resolve();
// Check for cancellation
if (token.isCancellationRequested) {
return;
}
// Assert Model instance
if (!(model instanceof BinaryEditorModel)) {
throw new Error('Unable to open file as binary');
}
// Render Input
this.inputDisposable.value = this.renderInput(input, options, model);
}
private renderInput(input: EditorInput, options: IEditorOptions | undefined, model: BinaryEditorModel): IDisposable {
const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar);
clearNode(binaryContainer);
const disposables = new DisposableStore();
const label = document.createElement('p');
label.textContent = localize('nativeBinaryError', "The file is not displayed in the editor because it is either binary or uses an unsupported text encoding.");
binaryContainer.appendChild(label);
this._register(this.instantiationService.createInstance(Link, label, {
label: localize('openAsText', "Do you want to open it anyway?"),
href: ''
}, {
opener: async () => {
// Open in place
await this.callbacks.openInternal(input, options);
// Signal to listeners that the binary editor has been opened in-place
this._onDidOpenInPlace.fire();
}
}));
scrollbar.scanDomNode();
// Update metadata
const size = model.getSize();
this.handleMetadataChanged(typeof size === 'number' ? ByteSize.formatSize(size) : '');
return disposables;
}
private handleMetadataChanged(meta: string | undefined): void {
this.metadata = meta;
this._onDidChangeMetadata.fire();
}
getMetadata(): string | undefined {
return this.metadata;
}
override clearInput(): void {
// Clear Meta
this.handleMetadataChanged(undefined);
// Clear the rest
if (this.binaryContainer) {
clearNode(this.binaryContainer);
}
this.inputDisposable.clear();
super.clearInput();
}
layout(dimension: Dimension): void {
// Pass on to Binary Container
const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar);
size(binaryContainer, dimension.width, dimension.height);
scrollbar.scanDomNode();
}
override focus(): void {
const binaryContainer = assertIsDefined(this.binaryContainer);
binaryContainer.focus();
}
override dispose(): void {
this.binaryContainer?.remove();
super.dispose();
}
}
|