提交 920d80e2 编写于 作者: B Benjamin Pasero

files - improve readonly handling

上级 bbfa966c
......@@ -52,6 +52,9 @@ export interface ITextEditorModel extends IEditorModel {
createSnapshot(this: IResolvedTextEditorModel): ITextSnapshot;
createSnapshot(this: ITextEditorModel): ITextSnapshot | null;
/**
* Signals if this model is readonly or not.
*/
isReadonly(): boolean;
}
......
......@@ -220,7 +220,6 @@ export class FileService extends Disposable implements IFileService {
isFile: (stat.type & FileType.File) !== 0,
isDirectory: (stat.type & FileType.Directory) !== 0,
isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0,
isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly),
mtime: stat.mtime,
ctime: stat.ctime,
size: stat.size,
......
......@@ -615,11 +615,6 @@ interface IBaseStat {
* it is optional.
*/
etag?: string;
/**
* The resource is readonly.
*/
isReadonly?: boolean;
}
export interface IBaseStatWithMetadata extends IBaseStat {
......
......@@ -89,26 +89,26 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
//#region Events
private readonly _onDidLayout: Emitter<Dimension> = this._register(new Emitter<Dimension>());
readonly onDidLayout: Event<Dimension> = this._onDidLayout.event;
private readonly _onDidLayout = this._register(new Emitter<Dimension>());
readonly onDidLayout = this._onDidLayout.event;
private readonly _onDidActiveGroupChange: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidActiveGroupChange: Event<IEditorGroupView> = this._onDidActiveGroupChange.event;
private readonly _onDidActiveGroupChange = this._register(new Emitter<IEditorGroupView>());
readonly onDidActiveGroupChange = this._onDidActiveGroupChange.event;
private readonly _onDidGroupIndexChange: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidGroupIndexChange: Event<IEditorGroupView> = this._onDidGroupIndexChange.event;
private readonly _onDidGroupIndexChange = this._register(new Emitter<IEditorGroupView>());
readonly onDidGroupIndexChange = this._onDidGroupIndexChange.event;
private readonly _onDidActivateGroup: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidActivateGroup: Event<IEditorGroupView> = this._onDidActivateGroup.event;
private readonly _onDidActivateGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidActivateGroup = this._onDidActivateGroup.event;
private readonly _onDidAddGroup: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidAddGroup: Event<IEditorGroupView> = this._onDidAddGroup.event;
private readonly _onDidAddGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidAddGroup = this._onDidAddGroup.event;
private readonly _onDidRemoveGroup: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidRemoveGroup: Event<IEditorGroupView> = this._onDidRemoveGroup.event;
private readonly _onDidRemoveGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidRemoveGroup = this._onDidRemoveGroup.event;
private readonly _onDidMoveGroup: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidMoveGroup: Event<IEditorGroupView> = this._onDidMoveGroup.event;
private readonly _onDidMoveGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidMoveGroup = this._onDidMoveGroup.event;
private onDidSetGridWidget = this._register(new Emitter<{ width: number; height: number; } | undefined>());
private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>());
......
......@@ -56,7 +56,7 @@ export class SideBySideEditor extends BaseEditor {
private onDidCreateEditors = this._register(new Emitter<{ width: number; height: number; } | undefined>());
private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>());
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined> = Event.any(this.onDidCreateEditors.event, this._onDidSizeConstraintsChange.event);
readonly onDidSizeConstraintsChange = Event.any(this.onDidCreateEditors.event, this._onDidSizeConstraintsChange.event);
constructor(
@ITelemetryService telemetryService: ITelemetryService,
......
......@@ -39,7 +39,7 @@ export interface IEditorConfiguration {
*/
export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
private editorControl: IEditor | undefined;
private _editorContainer: HTMLElement | undefined;
private editorContainer: HTMLElement | undefined;
private hasPendingConfigurationChange: boolean | undefined;
private lastAppliedEditorOptions?: IEditorOptions;
private editorMemento: IEditorMemento<IEditorViewState>;
......@@ -121,20 +121,17 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
}
protected getConfigurationOverrides(): IEditorOptions {
const overrides = {};
assign(overrides, {
return {
overviewRulerLanes: 3,
lineNumbersMinChars: 3,
fixedOverflowWidgets: true
});
return overrides;
};
}
protected createEditor(parent: HTMLElement): void {
// Editor for Text
this._editorContainer = parent;
this.editorContainer = parent;
this.editorControl = this._register(this.createEditorControl(parent, this.computeConfiguration(this.configurationService.getValue<IEditorConfiguration>(this.getResource()))));
// Model & Language changes
......@@ -200,7 +197,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
// editor input specific options (e.g. an ARIA label depending on the input showing)
this.updateEditorConfiguration();
const editorContainer = assertIsDefined(this._editorContainer);
const editorContainer = assertIsDefined(this.editorContainer);
editorContainer.setAttribute('aria-label', this.computeAriaLabel());
}
......
......@@ -119,12 +119,10 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
}
protected getAriaLabel(): string {
const input = this.input;
const isReadonly = !(this.input instanceof UntitledTextEditorInput);
let ariaLabel: string;
const inputName = input?.getName();
if (isReadonly) {
const inputName = this.input?.getName();
if (this.input?.isReadonly()) {
ariaLabel = inputName ? nls.localize('readonlyEditorWithInputAriaLabel', "{0}. Readonly text editor.", inputName) : nls.localize('readonlyEditorAriaLabel', "Readonly text editor.");
} else {
ariaLabel = inputName ? nls.localize('untitledFileEditorWithInputAriaLabel', "{0}. Untitled file text editor.", inputName) : nls.localize('untitledFileEditorAriaLabel', "Untitled file text editor.");
......
......@@ -21,10 +21,6 @@ export class ResourceEditorModel extends BaseTextEditorModel {
super(modelService, modeService, resource);
}
isReadonly(): boolean {
return true;
}
dispose(): void {
// TODO@Joao: force this class to dispose the underlying model
......
......@@ -16,7 +16,7 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
/**
* The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated.
*/
export abstract class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport {
export class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport {
protected textEditorModelHandle: URI | null = null;
......@@ -61,7 +61,9 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd
return this.textEditorModelHandle ? this.modelService.getModel(this.textEditorModelHandle) : null;
}
abstract isReadonly(): boolean;
isReadonly(): boolean {
return true;
}
setMode(mode: string): void {
if (!this.isResolved()) {
......
......@@ -243,8 +243,7 @@ export class TextFileEditor extends BaseTextEditor {
}
protected getAriaLabel(): string {
const input = this.input;
const inputName = input?.getName();
const inputName = this.input?.getName();
let ariaLabel: string;
if (inputName) {
......
......@@ -216,7 +216,7 @@ export class FileEditorInput extends TextEditorInput implements IFileEditorInput
return localize('orphanedFile', "{0} (deleted)", label);
}
if (model?.isReadonly()) {
if (this.isReadonly()) {
return localize('readonlyFile', "{0} (read-only)", label);
}
......
......@@ -8,7 +8,7 @@ import { isEqual } from 'vs/base/common/extpath';
import { posix } from 'vs/base/common/path';
import * as resources from 'vs/base/common/resources';
import { ResourceMap } from 'vs/base/common/map';
import { IFileStat, IFileService } from 'vs/platform/files/common/files';
import { IFileStat, IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
import { rtrim, startsWithIgnoreCase, startsWith, equalsIgnoreCase } from 'vs/base/common/strings';
import { coalesce } from 'vs/base/common/arrays';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
......@@ -154,8 +154,8 @@ export class ExplorerItem {
return this === this.root;
}
static create(raw: IFileStat, parent: ExplorerItem | undefined, resolveTo?: readonly URI[]): ExplorerItem {
const stat = new ExplorerItem(raw.resource, parent, raw.isDirectory, raw.isSymbolicLink, raw.isReadonly, raw.name, raw.mtime);
static create(service: IFileService, raw: IFileStat, parent: ExplorerItem | undefined, resolveTo?: readonly URI[]): ExplorerItem {
const stat = new ExplorerItem(raw.resource, parent, raw.isDirectory, raw.isSymbolicLink, service.hasCapability(raw.resource, FileSystemProviderCapabilities.Readonly), raw.name, raw.mtime);
// Recursively add children if present
if (stat.isDirectory) {
......@@ -170,7 +170,7 @@ export class ExplorerItem {
// Recurse into children
if (raw.children) {
for (let i = 0, len = raw.children.length; i < len; i++) {
const child = ExplorerItem.create(raw.children[i], stat, resolveTo);
const child = ExplorerItem.create(service, raw.children[i], stat, resolveTo);
stat.addChild(child);
}
}
......@@ -260,7 +260,7 @@ export class ExplorerItem {
const resolveMetadata = explorerService.sortOrder === 'modified';
try {
const stat = await fileService.resolve(this.resource, { resolveSingleChildDescendants: true, resolveMetadata });
const resolved = ExplorerItem.create(stat, this);
const resolved = ExplorerItem.create(fileService, stat, this);
ExplorerItem.mergeLocalWithDisk(resolved, this);
} catch (e) {
this.isError = true;
......
......@@ -186,7 +186,7 @@ export class ExplorerService implements IExplorerService {
const stat = await this.fileService.resolve(rootUri, options);
// Convert to model
const modelStat = ExplorerItem.create(stat, undefined, options.resolveTo);
const modelStat = ExplorerItem.create(this.fileService, stat, undefined, options.resolveTo);
// Update Input with disk Stat
ExplorerItem.mergeLocalWithDisk(modelStat, root);
const item = root.find(resource);
......@@ -230,11 +230,11 @@ export class ExplorerService implements IExplorerService {
const thenable: Promise<IFileStat | undefined> = p.isDirectoryResolved ? Promise.resolve(undefined) : this.fileService.resolve(p.resource, { resolveMetadata });
thenable.then(stat => {
if (stat) {
const modelStat = ExplorerItem.create(stat, p.parent);
const modelStat = ExplorerItem.create(this.fileService, stat, p.parent);
ExplorerItem.mergeLocalWithDisk(modelStat, p);
}
const childElement = ExplorerItem.create(addedElement, p.parent);
const childElement = ExplorerItem.create(this.fileService, addedElement, p.parent);
// Make sure to remove any previous version of the file if any
p.removeChild(childElement);
p.addChild(childElement);
......
......@@ -15,7 +15,7 @@ import { ITextFileService, ModelState, ITextFileEditorModel, ISaveErrorHandler,
import { EncodingMode, IRevertOptions, SaveReason } from 'vs/workbench/common/editor';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, ETAG_DISABLED } from 'vs/platform/files/common/files';
import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, ETAG_DISABLED, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
......@@ -340,8 +340,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
size: resolvedBackup.meta ? resolvedBackup.meta.size : 0,
etag: resolvedBackup.meta ? resolvedBackup.meta.etag : ETAG_DISABLED, // etag disabled if unknown!
value: resolvedBackup.value,
encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding,
isReadonly: false
encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding
}, options, true /* from backup */);
// Restore orphaned flag based on state
......@@ -426,8 +425,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
etag: content.etag,
isFile: true,
isDirectory: false,
isSymbolicLink: false,
isReadonly: content.isReadonly
isSymbolicLink: false
});
// Keep the original encoding to not loose it when saving
......@@ -1030,7 +1028,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
}
isReadonly(): boolean {
return !!(this.lastResolvedFileStat && this.lastResolvedFileStat.isReadonly);
return this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly);
}
isDisposed(): boolean {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册