mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd (#5074)
* Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd * fix tests
This commit is contained in:
@@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, IRawTextContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { EncodingMode } from 'vs/workbench/common/editor';
|
||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
@@ -266,14 +266,14 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
|
||||
// If we have a backup, continue loading with it
|
||||
if (!!backup) {
|
||||
const content: IRawTextContent = {
|
||||
const content: ITextFileStreamContent = {
|
||||
resource: this.resource,
|
||||
name: basename(this.resource),
|
||||
mtime: Date.now(),
|
||||
size: 0,
|
||||
etag: etag(Date.now(), 0),
|
||||
value: createTextBufferFactory(''), /* will be filled later from backup */
|
||||
encoding: this.fileService.encoding.getWriteEncoding(this.resource, this.preferredEncoding).encoding,
|
||||
encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding,
|
||||
isReadonly: false
|
||||
};
|
||||
|
||||
@@ -306,7 +306,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
|
||||
// Resolve Content
|
||||
try {
|
||||
const content = await this.textFileService.resolve(this.resource, { acceptTextOnly: !allowBinary, etag, encoding: this.preferredEncoding });
|
||||
const content = await this.textFileService.readStream(this.resource, { acceptTextOnly: !allowBinary, etag, encoding: this.preferredEncoding });
|
||||
|
||||
// Clear orphaned state when loading was successful
|
||||
this.setOrphaned(false);
|
||||
@@ -346,34 +346,33 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
}
|
||||
}
|
||||
|
||||
private loadWithContent(content: IRawTextContent, options?: ILoadOptions, backup?: URI): Promise<TextFileEditorModel> {
|
||||
return this.doLoadWithContent(content, backup).then(model => {
|
||||
private async loadWithContent(content: ITextFileStreamContent, options?: ILoadOptions, backup?: URI): Promise<TextFileEditorModel> {
|
||||
const model = await this.doLoadWithContent(content, backup);
|
||||
|
||||
// Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype
|
||||
const settingsType = this.getTypeIfSettings();
|
||||
if (settingsType) {
|
||||
/* __GDPR__
|
||||
"settingsRead" : {
|
||||
"settingsType": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('settingsRead', { settingsType }); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data
|
||||
} else {
|
||||
/* __GDPR__
|
||||
"fileGet" : {
|
||||
"${include}": [
|
||||
"${FileTelemetryData}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('fileGet', this.getTelemetryData(options && options.reason ? options.reason : LoadReason.OTHER));
|
||||
}
|
||||
// Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype
|
||||
const settingsType = this.getTypeIfSettings();
|
||||
if (settingsType) {
|
||||
/* __GDPR__
|
||||
"settingsRead" : {
|
||||
"settingsType": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('settingsRead', { settingsType }); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data
|
||||
} else {
|
||||
/* __GDPR__
|
||||
"fileGet" : {
|
||||
"${include}": [
|
||||
"${FileTelemetryData}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('fileGet', this.getTelemetryData(options && options.reason ? options.reason : LoadReason.OTHER));
|
||||
}
|
||||
|
||||
return model;
|
||||
});
|
||||
return model;
|
||||
}
|
||||
|
||||
private doLoadWithContent(content: IRawTextContent, backup?: URI): Promise<TextFileEditorModel> {
|
||||
private doLoadWithContent(content: ITextFileStreamContent, backup?: URI): Promise<TextFileEditorModel> {
|
||||
this.logService.trace('load() - resolved content', this.resource);
|
||||
|
||||
// Update our resolved disk stat model
|
||||
|
||||
@@ -154,6 +154,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
||||
// Model does not exist
|
||||
else {
|
||||
const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined);
|
||||
model = newModel;
|
||||
modelPromise = model.load(options);
|
||||
|
||||
// Install state change listener
|
||||
@@ -208,7 +209,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
||||
} catch (error) {
|
||||
|
||||
// Free resources of this invalid model
|
||||
if (model) {
|
||||
if (model && typeof model.dispose === 'function') { // workaround for https://github.com/Microsoft/vscode/issues/72404
|
||||
model.dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, IWillMoveEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, IWillMoveEvent, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor';
|
||||
import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IFileService, IResolveContentOptions, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, ITextSnapshot, IWriteTextFileOptions, IFileStatWithMetadata, toBufferOrReadable, ICreateFileOptions } from 'vs/platform/files/common/files';
|
||||
import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions } from 'vs/platform/files/common/files';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
@@ -37,11 +37,13 @@ import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { trim } from 'vs/base/common/strings';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ITextSnapshot } from 'vs/editor/common/model';
|
||||
|
||||
/**
|
||||
* The workbench file service implementation implements the raw file service spec and adds additional methods on top.
|
||||
*/
|
||||
export class TextFileService extends Disposable implements ITextFileService {
|
||||
export abstract class TextFileService extends Disposable implements ITextFileService {
|
||||
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
|
||||
@@ -57,6 +59,8 @@ export class TextFileService extends Disposable implements ITextFileService {
|
||||
private _models: TextFileEditorModelManager;
|
||||
get models(): ITextFileEditorModelManager { return this._models; }
|
||||
|
||||
abstract get encoding(): IResourceEncodings;
|
||||
|
||||
private currentFilesAssociationConfig: { [key: string]: string; };
|
||||
private configuredAutoSaveDelay?: number;
|
||||
private configuredAutoSaveOnFocusChange: boolean;
|
||||
@@ -364,24 +368,62 @@ export class TextFileService extends Disposable implements ITextFileService {
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region primitives (resolve, create, move, delete, update)
|
||||
//#region primitives (read, create, move, delete, update)
|
||||
|
||||
async resolve(resource: URI, options?: IResolveContentOptions): Promise<IRawTextContent> {
|
||||
const streamContent = await this.fileService.resolveStreamContent(resource, options);
|
||||
const value = await createTextBufferFactoryFromStream(streamContent.value);
|
||||
async read(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileContent> {
|
||||
const content = await this.fileService.readFile(resource, options);
|
||||
|
||||
// in case of acceptTextOnly: true, we check the first
|
||||
// chunk for possibly being binary by looking for 0-bytes
|
||||
// we limit this check to the first 512 bytes
|
||||
this.validateBinary(content.value, options);
|
||||
|
||||
return {
|
||||
resource: streamContent.resource,
|
||||
name: streamContent.name,
|
||||
mtime: streamContent.mtime,
|
||||
etag: streamContent.etag,
|
||||
encoding: streamContent.encoding,
|
||||
isReadonly: streamContent.isReadonly,
|
||||
size: streamContent.size,
|
||||
value
|
||||
...content,
|
||||
encoding: 'utf8',
|
||||
value: content.value.toString()
|
||||
};
|
||||
}
|
||||
|
||||
async readStream(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileStreamContent> {
|
||||
const stream = await this.fileService.readFileStream(resource, options);
|
||||
|
||||
// in case of acceptTextOnly: true, we check the first
|
||||
// chunk for possibly being binary by looking for 0-bytes
|
||||
// we limit this check to the first 512 bytes
|
||||
let checkedForBinary = false;
|
||||
const throwOnBinary = (data: VSBuffer): Error | undefined => {
|
||||
if (!checkedForBinary) {
|
||||
checkedForBinary = true;
|
||||
|
||||
this.validateBinary(data, options);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
return {
|
||||
...stream,
|
||||
encoding: 'utf8',
|
||||
value: await createTextBufferFactoryFromStream(stream.value, undefined, options && options.acceptTextOnly ? throwOnBinary : undefined)
|
||||
};
|
||||
}
|
||||
|
||||
private validateBinary(buffer: VSBuffer, options?: IReadTextFileOptions): void {
|
||||
if (!options || !options.acceptTextOnly) {
|
||||
return; // no validation needed
|
||||
}
|
||||
|
||||
// in case of acceptTextOnly: true, we check the first
|
||||
// chunk for possibly being binary by looking for 0-bytes
|
||||
// we limit this check to the first 512 bytes
|
||||
for (let i = 0; i < buffer.byteLength && i < 512; i++) {
|
||||
if (buffer.readUInt8(i) === 0) {
|
||||
throw new TextFileOperationError(nls.localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), TextFileOperationResult.FILE_IS_BINARY, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async create(resource: URI, value?: string | ITextSnapshot, options?: ICreateFileOptions): Promise<IFileStatWithMetadata> {
|
||||
const stat = await this.doCreate(resource, value, options);
|
||||
|
||||
@@ -844,7 +886,10 @@ export class TextFileService extends Disposable implements ITextFileService {
|
||||
} catch (error) {
|
||||
|
||||
// binary model: delete the file and run the operation again
|
||||
if ((<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_IS_BINARY || (<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE) {
|
||||
if (
|
||||
(<TextFileOperationError>error).textFileOperationResult === TextFileOperationResult.FILE_IS_BINARY ||
|
||||
(<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE
|
||||
) {
|
||||
await this.fileService.del(target);
|
||||
|
||||
return this.doSaveTextFileAs(sourceModel, resource, target, options);
|
||||
|
||||
@@ -7,274 +7,24 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IEncodingSupport, ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor';
|
||||
import { IResolveContentOptions, ITextSnapshot, IBaseStatWithMetadata, IWriteTextFileOptions, IFileStatWithMetadata } from 'vs/platform/files/common/files';
|
||||
import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { ITextBufferFactory, ITextModel } from 'vs/editor/common/model';
|
||||
import { ITextBufferFactory, ITextModel, ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer';
|
||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
|
||||
/**
|
||||
* The save error handler can be installed on the text file editor model to install code that executes when save errors occur.
|
||||
*/
|
||||
export interface ISaveErrorHandler {
|
||||
|
||||
/**
|
||||
* Called whenever a save fails.
|
||||
*/
|
||||
onSaveError(error: Error, model: ITextFileEditorModel): void;
|
||||
}
|
||||
|
||||
export interface ISaveParticipant {
|
||||
|
||||
/**
|
||||
* Participate in a save of a model. Allows to change the model before it is being saved to disk.
|
||||
*/
|
||||
participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* States the text file editor model can be in.
|
||||
*/
|
||||
export const enum ModelState {
|
||||
SAVED,
|
||||
DIRTY,
|
||||
PENDING_SAVE,
|
||||
|
||||
/**
|
||||
* A model is in conflict mode when changes cannot be saved because the
|
||||
* underlying file has changed. Models in conflict mode are always dirty.
|
||||
*/
|
||||
CONFLICT,
|
||||
|
||||
/**
|
||||
* A model is in orphan state when the underlying file has been deleted.
|
||||
*/
|
||||
ORPHAN,
|
||||
|
||||
/**
|
||||
* Any error that happens during a save that is not causing the CONFLICT state.
|
||||
* Models in error mode are always diry.
|
||||
*/
|
||||
ERROR
|
||||
}
|
||||
|
||||
export const enum StateChange {
|
||||
DIRTY,
|
||||
SAVING,
|
||||
SAVE_ERROR,
|
||||
SAVED,
|
||||
REVERTED,
|
||||
ENCODING,
|
||||
CONTENT_CHANGE,
|
||||
ORPHANED_CHANGE
|
||||
}
|
||||
|
||||
export class TextFileModelChangeEvent {
|
||||
private _resource: URI;
|
||||
private _kind: StateChange;
|
||||
|
||||
constructor(model: ITextFileEditorModel, kind: StateChange) {
|
||||
this._resource = model.getResource();
|
||||
this._kind = kind;
|
||||
}
|
||||
|
||||
get resource(): URI {
|
||||
return this._resource;
|
||||
}
|
||||
|
||||
get kind(): StateChange {
|
||||
return this._kind;
|
||||
}
|
||||
}
|
||||
|
||||
export const TEXT_FILE_SERVICE_ID = 'textFileService';
|
||||
export const AutoSaveContext = new RawContextKey<string>('config.files.autoSave', undefined);
|
||||
|
||||
export interface ITextFileOperationResult {
|
||||
results: IResult[];
|
||||
}
|
||||
|
||||
export interface IResult {
|
||||
source: URI;
|
||||
target?: URI;
|
||||
success?: boolean;
|
||||
}
|
||||
|
||||
export interface IAutoSaveConfiguration {
|
||||
autoSaveDelay?: number;
|
||||
autoSaveFocusChange: boolean;
|
||||
autoSaveApplicationChange: boolean;
|
||||
}
|
||||
|
||||
export const enum AutoSaveMode {
|
||||
OFF,
|
||||
AFTER_SHORT_DELAY,
|
||||
AFTER_LONG_DELAY,
|
||||
ON_FOCUS_CHANGE,
|
||||
ON_WINDOW_CHANGE
|
||||
}
|
||||
|
||||
export const enum SaveReason {
|
||||
EXPLICIT = 1,
|
||||
AUTO = 2,
|
||||
FOCUS_CHANGE = 3,
|
||||
WINDOW_CHANGE = 4
|
||||
}
|
||||
|
||||
export const enum LoadReason {
|
||||
EDITOR = 1,
|
||||
REFERENCE = 2,
|
||||
OTHER = 3
|
||||
}
|
||||
|
||||
export const ITextFileService = createDecorator<ITextFileService>(TEXT_FILE_SERVICE_ID);
|
||||
|
||||
export interface IRawTextContent extends IBaseStatWithMetadata {
|
||||
|
||||
/**
|
||||
* The line grouped content of a text file.
|
||||
*/
|
||||
value: ITextBufferFactory;
|
||||
|
||||
/**
|
||||
* The encoding of the content if known.
|
||||
*/
|
||||
encoding: string;
|
||||
}
|
||||
|
||||
export interface IModelLoadOrCreateOptions {
|
||||
|
||||
/**
|
||||
* Context why the model is being loaded or created.
|
||||
*/
|
||||
reason?: LoadReason;
|
||||
|
||||
/**
|
||||
* The encoding to use when resolving the model text content.
|
||||
*/
|
||||
encoding?: string;
|
||||
|
||||
/**
|
||||
* If the model was already loaded before, allows to trigger
|
||||
* a reload of it to fetch the latest contents:
|
||||
* - async: loadOrCreate() will return immediately and trigger
|
||||
* a reload that will run in the background.
|
||||
* - sync: loadOrCreate() will only return resolved when the
|
||||
* model has finished reloading.
|
||||
*/
|
||||
reload?: {
|
||||
async: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow to load a model even if we think it is a binary file.
|
||||
*/
|
||||
allowBinary?: boolean;
|
||||
}
|
||||
|
||||
export interface ITextFileEditorModelManager {
|
||||
|
||||
onModelDisposed: Event<URI>;
|
||||
onModelContentChanged: Event<TextFileModelChangeEvent>;
|
||||
onModelEncodingChanged: Event<TextFileModelChangeEvent>;
|
||||
|
||||
onModelDirty: Event<TextFileModelChangeEvent>;
|
||||
onModelSaveError: Event<TextFileModelChangeEvent>;
|
||||
onModelSaved: Event<TextFileModelChangeEvent>;
|
||||
onModelReverted: Event<TextFileModelChangeEvent>;
|
||||
onModelOrphanedChanged: Event<TextFileModelChangeEvent>;
|
||||
|
||||
onModelsDirty: Event<TextFileModelChangeEvent[]>;
|
||||
onModelsSaveError: Event<TextFileModelChangeEvent[]>;
|
||||
onModelsSaved: Event<TextFileModelChangeEvent[]>;
|
||||
onModelsReverted: Event<TextFileModelChangeEvent[]>;
|
||||
|
||||
get(resource: URI): ITextFileEditorModel | undefined;
|
||||
|
||||
getAll(resource?: URI): ITextFileEditorModel[];
|
||||
|
||||
loadOrCreate(resource: URI, options?: IModelLoadOrCreateOptions): Promise<ITextFileEditorModel>;
|
||||
|
||||
disposeModel(model: ITextFileEditorModel): void;
|
||||
}
|
||||
|
||||
export interface ISaveOptions {
|
||||
force?: boolean;
|
||||
reason?: SaveReason;
|
||||
overwriteReadonly?: boolean;
|
||||
overwriteEncoding?: boolean;
|
||||
skipSaveParticipants?: boolean;
|
||||
writeElevated?: boolean;
|
||||
}
|
||||
|
||||
export interface ILoadOptions {
|
||||
|
||||
/**
|
||||
* Go to disk bypassing any cache of the model if any.
|
||||
*/
|
||||
forceReadFromDisk?: boolean;
|
||||
|
||||
/**
|
||||
* Allow to load a model even if we think it is a binary file.
|
||||
*/
|
||||
allowBinary?: boolean;
|
||||
|
||||
/**
|
||||
* Context why the model is being loaded.
|
||||
*/
|
||||
reason?: LoadReason;
|
||||
}
|
||||
|
||||
export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport {
|
||||
|
||||
onDidContentChange: Event<StateChange>;
|
||||
onDidStateChange: Event<StateChange>;
|
||||
|
||||
getVersionId(): number;
|
||||
|
||||
getResource(): URI;
|
||||
|
||||
hasState(state: ModelState): boolean;
|
||||
|
||||
getETag(): string | null;
|
||||
|
||||
updatePreferredEncoding(encoding: string): void;
|
||||
|
||||
save(options?: ISaveOptions): Promise<void>;
|
||||
|
||||
load(options?: ILoadOptions): Promise<ITextFileEditorModel>;
|
||||
|
||||
revert(soft?: boolean): Promise<void>;
|
||||
|
||||
createSnapshot(): ITextSnapshot | null;
|
||||
|
||||
isDirty(): boolean;
|
||||
|
||||
isResolved(): boolean;
|
||||
|
||||
isDisposed(): boolean;
|
||||
}
|
||||
|
||||
export interface IResolvedTextFileEditorModel extends ITextFileEditorModel {
|
||||
readonly textEditorModel: ITextModel;
|
||||
|
||||
createSnapshot(): ITextSnapshot;
|
||||
}
|
||||
|
||||
|
||||
export interface IWillMoveEvent {
|
||||
oldResource: URI;
|
||||
newResource: URI;
|
||||
|
||||
waitUntil(p: Promise<unknown>): void;
|
||||
}
|
||||
export const ITextFileService = createDecorator<ITextFileService>('textFileService');
|
||||
|
||||
export interface ITextFileService extends IDisposable {
|
||||
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
|
||||
readonly onWillMove: Event<IWillMoveEvent>;
|
||||
|
||||
readonly onAutoSaveConfigurationChange: Event<IAutoSaveConfiguration>;
|
||||
|
||||
readonly onFilesAssociationChange: Event<void>;
|
||||
|
||||
readonly isHotExitEnabled: boolean;
|
||||
@@ -284,6 +34,11 @@ export interface ITextFileService extends IDisposable {
|
||||
*/
|
||||
readonly models: ITextFileEditorModelManager;
|
||||
|
||||
/**
|
||||
* Helper to determine encoding for resources.
|
||||
*/
|
||||
readonly encoding: IResourceEncodings;
|
||||
|
||||
/**
|
||||
* A resource is dirty if it has unsaved changes or is an untitled file not yet saved.
|
||||
*
|
||||
@@ -348,9 +103,14 @@ export interface ITextFileService extends IDisposable {
|
||||
create(resource: URI, contents?: string | ITextSnapshot, options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Resolve the contents of a file identified by the resource.
|
||||
* Read the contents of a file identified by the resource.
|
||||
*/
|
||||
resolve(resource: URI, options?: IResolveContentOptions): Promise<IRawTextContent>;
|
||||
read(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileContent>;
|
||||
|
||||
/**
|
||||
* Read the contents of a file identified by the resource as stream.
|
||||
*/
|
||||
readStream(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileStreamContent>;
|
||||
|
||||
/**
|
||||
* Update a file with given contents.
|
||||
@@ -385,3 +145,659 @@ export interface ITextFileService extends IDisposable {
|
||||
*/
|
||||
getAutoSaveConfiguration(): IAutoSaveConfiguration;
|
||||
}
|
||||
|
||||
export interface IReadTextFileOptions extends IReadFileOptions {
|
||||
|
||||
/**
|
||||
* The optional acceptTextOnly parameter allows to fail this request early if the file
|
||||
* contents are not textual.
|
||||
*/
|
||||
acceptTextOnly?: boolean;
|
||||
|
||||
/**
|
||||
* The optional encoding parameter allows to specify the desired encoding when resolving
|
||||
* the contents of the file.
|
||||
*/
|
||||
encoding?: string;
|
||||
|
||||
/**
|
||||
* The optional guessEncoding parameter allows to guess encoding from content of the file.
|
||||
*/
|
||||
autoGuessEncoding?: boolean;
|
||||
}
|
||||
|
||||
export interface IWriteTextFileOptions extends IWriteFileOptions {
|
||||
|
||||
/**
|
||||
* The encoding to use when updating a file.
|
||||
*/
|
||||
encoding?: string;
|
||||
|
||||
/**
|
||||
* If set to true, will enforce the selected encoding and not perform any detection using BOMs.
|
||||
*/
|
||||
overwriteEncoding?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to overwrite a file even if it is readonly.
|
||||
*/
|
||||
overwriteReadonly?: boolean;
|
||||
|
||||
/**
|
||||
* Wether to write to the file as elevated (admin) user. When setting this option a prompt will
|
||||
* ask the user to authenticate as super user.
|
||||
*/
|
||||
writeElevated?: boolean;
|
||||
}
|
||||
|
||||
export const enum TextFileOperationResult {
|
||||
FILE_IS_BINARY
|
||||
}
|
||||
|
||||
export class TextFileOperationError extends FileOperationError {
|
||||
constructor(message: string, public textFileOperationResult: TextFileOperationResult, public options?: IReadTextFileOptions & IWriteTextFileOptions) {
|
||||
super(message, FileOperationResult.FILE_OTHER_ERROR);
|
||||
}
|
||||
|
||||
static isTextFileOperationError(obj: unknown): obj is TextFileOperationError {
|
||||
return obj instanceof Error && !isUndefinedOrNull((obj as TextFileOperationError).textFileOperationResult);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IResourceEncodings {
|
||||
getPreferredWriteEncoding(resource: URI, preferredEncoding?: string): IResourceEncoding;
|
||||
}
|
||||
|
||||
export interface IResourceEncoding {
|
||||
encoding: string;
|
||||
hasBOM: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The save error handler can be installed on the text file editor model to install code that executes when save errors occur.
|
||||
*/
|
||||
export interface ISaveErrorHandler {
|
||||
|
||||
/**
|
||||
* Called whenever a save fails.
|
||||
*/
|
||||
onSaveError(error: Error, model: ITextFileEditorModel): void;
|
||||
}
|
||||
|
||||
export interface ISaveParticipant {
|
||||
|
||||
/**
|
||||
* Participate in a save of a model. Allows to change the model before it is being saved to disk.
|
||||
*/
|
||||
participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* States the text file editor model can be in.
|
||||
*/
|
||||
export const enum ModelState {
|
||||
|
||||
/**
|
||||
* A model is saved.
|
||||
*/
|
||||
SAVED,
|
||||
|
||||
/**
|
||||
* A model is dirty.
|
||||
*/
|
||||
DIRTY,
|
||||
|
||||
/**
|
||||
* A model is transitioning from dirty to saved.
|
||||
*/
|
||||
PENDING_SAVE,
|
||||
|
||||
/**
|
||||
* A model is in conflict mode when changes cannot be saved because the
|
||||
* underlying file has changed. Models in conflict mode are always dirty.
|
||||
*/
|
||||
CONFLICT,
|
||||
|
||||
/**
|
||||
* A model is in orphan state when the underlying file has been deleted.
|
||||
*/
|
||||
ORPHAN,
|
||||
|
||||
/**
|
||||
* Any error that happens during a save that is not causing the CONFLICT state.
|
||||
* Models in error mode are always diry.
|
||||
*/
|
||||
ERROR
|
||||
}
|
||||
|
||||
export const enum StateChange {
|
||||
DIRTY,
|
||||
SAVING,
|
||||
SAVE_ERROR,
|
||||
SAVED,
|
||||
REVERTED,
|
||||
ENCODING,
|
||||
CONTENT_CHANGE,
|
||||
ORPHANED_CHANGE
|
||||
}
|
||||
|
||||
export class TextFileModelChangeEvent {
|
||||
private _resource: URI;
|
||||
|
||||
constructor(model: ITextFileEditorModel, private _kind: StateChange) {
|
||||
this._resource = model.getResource();
|
||||
}
|
||||
|
||||
get resource(): URI {
|
||||
return this._resource;
|
||||
}
|
||||
|
||||
get kind(): StateChange {
|
||||
return this._kind;
|
||||
}
|
||||
}
|
||||
|
||||
export const AutoSaveContext = new RawContextKey<string>('config.files.autoSave', undefined);
|
||||
|
||||
export interface ITextFileOperationResult {
|
||||
results: IResult[];
|
||||
}
|
||||
|
||||
export interface IResult {
|
||||
source: URI;
|
||||
target?: URI;
|
||||
success?: boolean;
|
||||
}
|
||||
|
||||
export interface IAutoSaveConfiguration {
|
||||
autoSaveDelay?: number;
|
||||
autoSaveFocusChange: boolean;
|
||||
autoSaveApplicationChange: boolean;
|
||||
}
|
||||
|
||||
export const enum AutoSaveMode {
|
||||
OFF,
|
||||
AFTER_SHORT_DELAY,
|
||||
AFTER_LONG_DELAY,
|
||||
ON_FOCUS_CHANGE,
|
||||
ON_WINDOW_CHANGE
|
||||
}
|
||||
|
||||
export const enum SaveReason {
|
||||
EXPLICIT = 1,
|
||||
AUTO = 2,
|
||||
FOCUS_CHANGE = 3,
|
||||
WINDOW_CHANGE = 4
|
||||
}
|
||||
|
||||
export const enum LoadReason {
|
||||
EDITOR = 1,
|
||||
REFERENCE = 2,
|
||||
OTHER = 3
|
||||
}
|
||||
|
||||
interface IBaseTextFileContent extends IBaseStatWithMetadata {
|
||||
|
||||
/**
|
||||
* The encoding of the content if known.
|
||||
*/
|
||||
encoding: string;
|
||||
}
|
||||
|
||||
export interface ITextFileContent extends IBaseTextFileContent {
|
||||
|
||||
/**
|
||||
* The content of a text file.
|
||||
*/
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ITextFileStreamContent extends IBaseTextFileContent {
|
||||
|
||||
/**
|
||||
* The line grouped content of a text file.
|
||||
*/
|
||||
value: ITextBufferFactory;
|
||||
}
|
||||
|
||||
export interface IModelLoadOrCreateOptions {
|
||||
|
||||
/**
|
||||
* Context why the model is being loaded or created.
|
||||
*/
|
||||
reason?: LoadReason;
|
||||
|
||||
/**
|
||||
* The encoding to use when resolving the model text content.
|
||||
*/
|
||||
encoding?: string;
|
||||
|
||||
/**
|
||||
* If the model was already loaded before, allows to trigger
|
||||
* a reload of it to fetch the latest contents:
|
||||
* - async: loadOrCreate() will return immediately and trigger
|
||||
* a reload that will run in the background.
|
||||
* - sync: loadOrCreate() will only return resolved when the
|
||||
* model has finished reloading.
|
||||
*/
|
||||
reload?: {
|
||||
async: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow to load a model even if we think it is a binary file.
|
||||
*/
|
||||
allowBinary?: boolean;
|
||||
}
|
||||
|
||||
export interface ITextFileEditorModelManager {
|
||||
|
||||
readonly onModelDisposed: Event<URI>;
|
||||
readonly onModelContentChanged: Event<TextFileModelChangeEvent>;
|
||||
readonly onModelEncodingChanged: Event<TextFileModelChangeEvent>;
|
||||
|
||||
readonly onModelDirty: Event<TextFileModelChangeEvent>;
|
||||
readonly onModelSaveError: Event<TextFileModelChangeEvent>;
|
||||
readonly onModelSaved: Event<TextFileModelChangeEvent>;
|
||||
readonly onModelReverted: Event<TextFileModelChangeEvent>;
|
||||
readonly onModelOrphanedChanged: Event<TextFileModelChangeEvent>;
|
||||
|
||||
readonly onModelsDirty: Event<TextFileModelChangeEvent[]>;
|
||||
readonly onModelsSaveError: Event<TextFileModelChangeEvent[]>;
|
||||
readonly onModelsSaved: Event<TextFileModelChangeEvent[]>;
|
||||
readonly onModelsReverted: Event<TextFileModelChangeEvent[]>;
|
||||
|
||||
get(resource: URI): ITextFileEditorModel | undefined;
|
||||
|
||||
getAll(resource?: URI): ITextFileEditorModel[];
|
||||
|
||||
loadOrCreate(resource: URI, options?: IModelLoadOrCreateOptions): Promise<ITextFileEditorModel>;
|
||||
|
||||
disposeModel(model: ITextFileEditorModel): void;
|
||||
}
|
||||
|
||||
export interface ISaveOptions {
|
||||
force?: boolean;
|
||||
reason?: SaveReason;
|
||||
overwriteReadonly?: boolean;
|
||||
overwriteEncoding?: boolean;
|
||||
skipSaveParticipants?: boolean;
|
||||
writeElevated?: boolean;
|
||||
}
|
||||
|
||||
export interface ILoadOptions {
|
||||
|
||||
/**
|
||||
* Go to disk bypassing any cache of the model if any.
|
||||
*/
|
||||
forceReadFromDisk?: boolean;
|
||||
|
||||
/**
|
||||
* Allow to load a model even if we think it is a binary file.
|
||||
*/
|
||||
allowBinary?: boolean;
|
||||
|
||||
/**
|
||||
* Context why the model is being loaded.
|
||||
*/
|
||||
reason?: LoadReason;
|
||||
}
|
||||
|
||||
export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport {
|
||||
|
||||
readonly onDidContentChange: Event<StateChange>;
|
||||
readonly onDidStateChange: Event<StateChange>;
|
||||
|
||||
getVersionId(): number;
|
||||
|
||||
getResource(): URI;
|
||||
|
||||
hasState(state: ModelState): boolean;
|
||||
|
||||
getETag(): string | null;
|
||||
|
||||
updatePreferredEncoding(encoding: string): void;
|
||||
|
||||
save(options?: ISaveOptions): Promise<void>;
|
||||
|
||||
load(options?: ILoadOptions): Promise<ITextFileEditorModel>;
|
||||
|
||||
revert(soft?: boolean): Promise<void>;
|
||||
|
||||
createSnapshot(): ITextSnapshot | null;
|
||||
|
||||
isDirty(): boolean;
|
||||
|
||||
isResolved(): boolean;
|
||||
|
||||
isDisposed(): boolean;
|
||||
}
|
||||
|
||||
export interface IResolvedTextFileEditorModel extends ITextFileEditorModel {
|
||||
readonly textEditorModel: ITextModel;
|
||||
|
||||
createSnapshot(): ITextSnapshot;
|
||||
}
|
||||
|
||||
export interface IWillMoveEvent {
|
||||
oldResource: URI;
|
||||
newResource: URI;
|
||||
|
||||
waitUntil(p: Promise<unknown>): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert a snapshot into its full string form.
|
||||
*/
|
||||
export function snapshotToString(snapshot: ITextSnapshot): string {
|
||||
const chunks: string[] = [];
|
||||
|
||||
let chunk: string | null;
|
||||
while (typeof (chunk = snapshot.read()) === 'string') {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
return chunks.join('');
|
||||
}
|
||||
|
||||
export function stringToSnapshot(value: string): ITextSnapshot {
|
||||
let done = false;
|
||||
|
||||
return {
|
||||
read(): string | null {
|
||||
if (!done) {
|
||||
done = true;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class TextSnapshotReadable implements VSBufferReadable {
|
||||
private preambleHandled: boolean;
|
||||
|
||||
constructor(private snapshot: ITextSnapshot, private preamble?: string) { }
|
||||
|
||||
read(): VSBuffer | null {
|
||||
let value = this.snapshot.read();
|
||||
|
||||
// Handle preamble if provided
|
||||
if (!this.preambleHandled) {
|
||||
this.preambleHandled = true;
|
||||
|
||||
if (typeof this.preamble === 'string') {
|
||||
if (typeof value === 'string') {
|
||||
value = this.preamble + value;
|
||||
} else {
|
||||
value = this.preamble;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return VSBuffer.fromString(value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function toBufferOrReadable(value: string): VSBuffer;
|
||||
export function toBufferOrReadable(value: ITextSnapshot): VSBufferReadable;
|
||||
export function toBufferOrReadable(value: string | ITextSnapshot): VSBuffer | VSBufferReadable;
|
||||
export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined;
|
||||
export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined {
|
||||
if (typeof value === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return VSBuffer.fromString(value);
|
||||
}
|
||||
|
||||
return new TextSnapshotReadable(value);
|
||||
}
|
||||
|
||||
export const SUPPORTED_ENCODINGS: { [encoding: string]: { labelLong: string; labelShort: string; order: number; encodeOnly?: boolean; alias?: string } } = {
|
||||
utf8: {
|
||||
labelLong: 'UTF-8',
|
||||
labelShort: 'UTF-8',
|
||||
order: 1,
|
||||
alias: 'utf8bom'
|
||||
},
|
||||
utf8bom: {
|
||||
labelLong: 'UTF-8 with BOM',
|
||||
labelShort: 'UTF-8 with BOM',
|
||||
encodeOnly: true,
|
||||
order: 2,
|
||||
alias: 'utf8'
|
||||
},
|
||||
utf16le: {
|
||||
labelLong: 'UTF-16 LE',
|
||||
labelShort: 'UTF-16 LE',
|
||||
order: 3
|
||||
},
|
||||
utf16be: {
|
||||
labelLong: 'UTF-16 BE',
|
||||
labelShort: 'UTF-16 BE',
|
||||
order: 4
|
||||
},
|
||||
windows1252: {
|
||||
labelLong: 'Western (Windows 1252)',
|
||||
labelShort: 'Windows 1252',
|
||||
order: 5
|
||||
},
|
||||
iso88591: {
|
||||
labelLong: 'Western (ISO 8859-1)',
|
||||
labelShort: 'ISO 8859-1',
|
||||
order: 6
|
||||
},
|
||||
iso88593: {
|
||||
labelLong: 'Western (ISO 8859-3)',
|
||||
labelShort: 'ISO 8859-3',
|
||||
order: 7
|
||||
},
|
||||
iso885915: {
|
||||
labelLong: 'Western (ISO 8859-15)',
|
||||
labelShort: 'ISO 8859-15',
|
||||
order: 8
|
||||
},
|
||||
macroman: {
|
||||
labelLong: 'Western (Mac Roman)',
|
||||
labelShort: 'Mac Roman',
|
||||
order: 9
|
||||
},
|
||||
cp437: {
|
||||
labelLong: 'DOS (CP 437)',
|
||||
labelShort: 'CP437',
|
||||
order: 10
|
||||
},
|
||||
windows1256: {
|
||||
labelLong: 'Arabic (Windows 1256)',
|
||||
labelShort: 'Windows 1256',
|
||||
order: 11
|
||||
},
|
||||
iso88596: {
|
||||
labelLong: 'Arabic (ISO 8859-6)',
|
||||
labelShort: 'ISO 8859-6',
|
||||
order: 12
|
||||
},
|
||||
windows1257: {
|
||||
labelLong: 'Baltic (Windows 1257)',
|
||||
labelShort: 'Windows 1257',
|
||||
order: 13
|
||||
},
|
||||
iso88594: {
|
||||
labelLong: 'Baltic (ISO 8859-4)',
|
||||
labelShort: 'ISO 8859-4',
|
||||
order: 14
|
||||
},
|
||||
iso885914: {
|
||||
labelLong: 'Celtic (ISO 8859-14)',
|
||||
labelShort: 'ISO 8859-14',
|
||||
order: 15
|
||||
},
|
||||
windows1250: {
|
||||
labelLong: 'Central European (Windows 1250)',
|
||||
labelShort: 'Windows 1250',
|
||||
order: 16
|
||||
},
|
||||
iso88592: {
|
||||
labelLong: 'Central European (ISO 8859-2)',
|
||||
labelShort: 'ISO 8859-2',
|
||||
order: 17
|
||||
},
|
||||
cp852: {
|
||||
labelLong: 'Central European (CP 852)',
|
||||
labelShort: 'CP 852',
|
||||
order: 18
|
||||
},
|
||||
windows1251: {
|
||||
labelLong: 'Cyrillic (Windows 1251)',
|
||||
labelShort: 'Windows 1251',
|
||||
order: 19
|
||||
},
|
||||
cp866: {
|
||||
labelLong: 'Cyrillic (CP 866)',
|
||||
labelShort: 'CP 866',
|
||||
order: 20
|
||||
},
|
||||
iso88595: {
|
||||
labelLong: 'Cyrillic (ISO 8859-5)',
|
||||
labelShort: 'ISO 8859-5',
|
||||
order: 21
|
||||
},
|
||||
koi8r: {
|
||||
labelLong: 'Cyrillic (KOI8-R)',
|
||||
labelShort: 'KOI8-R',
|
||||
order: 22
|
||||
},
|
||||
koi8u: {
|
||||
labelLong: 'Cyrillic (KOI8-U)',
|
||||
labelShort: 'KOI8-U',
|
||||
order: 23
|
||||
},
|
||||
iso885913: {
|
||||
labelLong: 'Estonian (ISO 8859-13)',
|
||||
labelShort: 'ISO 8859-13',
|
||||
order: 24
|
||||
},
|
||||
windows1253: {
|
||||
labelLong: 'Greek (Windows 1253)',
|
||||
labelShort: 'Windows 1253',
|
||||
order: 25
|
||||
},
|
||||
iso88597: {
|
||||
labelLong: 'Greek (ISO 8859-7)',
|
||||
labelShort: 'ISO 8859-7',
|
||||
order: 26
|
||||
},
|
||||
windows1255: {
|
||||
labelLong: 'Hebrew (Windows 1255)',
|
||||
labelShort: 'Windows 1255',
|
||||
order: 27
|
||||
},
|
||||
iso88598: {
|
||||
labelLong: 'Hebrew (ISO 8859-8)',
|
||||
labelShort: 'ISO 8859-8',
|
||||
order: 28
|
||||
},
|
||||
iso885910: {
|
||||
labelLong: 'Nordic (ISO 8859-10)',
|
||||
labelShort: 'ISO 8859-10',
|
||||
order: 29
|
||||
},
|
||||
iso885916: {
|
||||
labelLong: 'Romanian (ISO 8859-16)',
|
||||
labelShort: 'ISO 8859-16',
|
||||
order: 30
|
||||
},
|
||||
windows1254: {
|
||||
labelLong: 'Turkish (Windows 1254)',
|
||||
labelShort: 'Windows 1254',
|
||||
order: 31
|
||||
},
|
||||
iso88599: {
|
||||
labelLong: 'Turkish (ISO 8859-9)',
|
||||
labelShort: 'ISO 8859-9',
|
||||
order: 32
|
||||
},
|
||||
windows1258: {
|
||||
labelLong: 'Vietnamese (Windows 1258)',
|
||||
labelShort: 'Windows 1258',
|
||||
order: 33
|
||||
},
|
||||
gbk: {
|
||||
labelLong: 'Simplified Chinese (GBK)',
|
||||
labelShort: 'GBK',
|
||||
order: 34
|
||||
},
|
||||
gb18030: {
|
||||
labelLong: 'Simplified Chinese (GB18030)',
|
||||
labelShort: 'GB18030',
|
||||
order: 35
|
||||
},
|
||||
cp950: {
|
||||
labelLong: 'Traditional Chinese (Big5)',
|
||||
labelShort: 'Big5',
|
||||
order: 36
|
||||
},
|
||||
big5hkscs: {
|
||||
labelLong: 'Traditional Chinese (Big5-HKSCS)',
|
||||
labelShort: 'Big5-HKSCS',
|
||||
order: 37
|
||||
},
|
||||
shiftjis: {
|
||||
labelLong: 'Japanese (Shift JIS)',
|
||||
labelShort: 'Shift JIS',
|
||||
order: 38
|
||||
},
|
||||
eucjp: {
|
||||
labelLong: 'Japanese (EUC-JP)',
|
||||
labelShort: 'EUC-JP',
|
||||
order: 39
|
||||
},
|
||||
euckr: {
|
||||
labelLong: 'Korean (EUC-KR)',
|
||||
labelShort: 'EUC-KR',
|
||||
order: 40
|
||||
},
|
||||
windows874: {
|
||||
labelLong: 'Thai (Windows 874)',
|
||||
labelShort: 'Windows 874',
|
||||
order: 41
|
||||
},
|
||||
iso885911: {
|
||||
labelLong: 'Latin/Thai (ISO 8859-11)',
|
||||
labelShort: 'ISO 8859-11',
|
||||
order: 42
|
||||
},
|
||||
koi8ru: {
|
||||
labelLong: 'Cyrillic (KOI8-RU)',
|
||||
labelShort: 'KOI8-RU',
|
||||
order: 43
|
||||
},
|
||||
koi8t: {
|
||||
labelLong: 'Tajik (KOI8-T)',
|
||||
labelShort: 'KOI8-T',
|
||||
order: 44
|
||||
},
|
||||
gb2312: {
|
||||
labelLong: 'Simplified Chinese (GB 2312)',
|
||||
labelShort: 'GB 2312',
|
||||
order: 45
|
||||
},
|
||||
cp865: {
|
||||
labelLong: 'Nordic DOS (CP 865)',
|
||||
labelShort: 'CP 865',
|
||||
order: 46
|
||||
},
|
||||
cp850: {
|
||||
labelLong: 'Western European DOS (CP 850)',
|
||||
labelShort: 'CP 850',
|
||||
order: 47
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user