Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #5294: 1. reopen file with another encoding; 2. set default encod… #5371

Merged
merged 1 commit into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/core/src/common/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ export interface Resource extends Disposable {
saveContents?(content: string, options?: { encoding?: string }): Promise<void>;
saveContentChanges?(changes: TextDocumentContentChangeEvent[], options?: { encoding?: string }): Promise<void>;
readonly onDidChangeContents?: Event<void>;
guessEncoding?(): Promise<string | undefined>
}
export namespace Resource {
export interface SaveContext {
content: string
changes?: TextDocumentContentChangeEvent[]
options?: { encoding?: string }
options?: { encoding?: string, overwriteEncoding?: string }
}
export async function save(resource: Resource, context: SaveContext, token?: CancellationToken): Promise<void> {
if (!resource.saveContents) {
Expand Down
93 changes: 93 additions & 0 deletions packages/editor/src/browser/editor-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import URI from '@theia/core/lib/common/uri';
import { CommonCommands, PreferenceService, QuickPickItem, QuickPickService, LabelProvider, QuickPickValue } from '@theia/core/lib/browser';
import { Languages, Language } from '@theia/languages/lib/browser';
import { EditorManager } from './editor-manager';
import { EncodingMode } from './editor';
import { EditorPreferences } from './editor-preferences';
import { SUPPORTED_ENCODINGS } from './supported-encodings';
import { ResourceProvider, MessageService } from '@theia/core';

export namespace EditorCommands {

Expand Down Expand Up @@ -59,6 +63,11 @@ export namespace EditorCommands {
category: EDITOR_CATEGORY,
label: 'Change Language Mode'
};
export const CHANGE_ENCODING: Command = {
id: 'textEditor.change.encoding',
category: EDITOR_CATEGORY,
label: 'Change File Encoding'
};

/**
* Command for going back to the last editor navigation location.
Expand Down Expand Up @@ -118,9 +127,14 @@ export class EditorCommandContribution implements CommandContribution {
@inject(PreferenceService)
protected readonly preferencesService: PreferenceService;

@inject(EditorPreferences)
protected readonly editorPreferences: EditorPreferences;

@inject(QuickPickService)
protected readonly quickPick: QuickPickService;

@inject(MessageService) protected readonly messageService: MessageService;

@inject(LabelProvider)
protected readonly labelProvider: LabelProvider;

Expand All @@ -130,6 +144,9 @@ export class EditorCommandContribution implements CommandContribution {
@inject(EditorManager)
protected readonly editorManager: EditorManager;

@inject(ResourceProvider)
protected readonly resourceProvider: ResourceProvider;

registerCommands(registry: CommandRegistry): void {
registry.registerCommand(EditorCommands.SHOW_REFERENCES);
registry.registerCommand(EditorCommands.CONFIG_INDENTATION);
Expand All @@ -141,6 +158,11 @@ export class EditorCommandContribution implements CommandContribution {
isVisible: () => this.canConfigureLanguage(),
execute: () => this.configureLanguage()
});
registry.registerCommand(EditorCommands.CHANGE_ENCODING, {
isEnabled: () => this.canConfigureEncoding(),
isVisible: () => this.canConfigureEncoding(),
execute: () => this.configureEncoding()
});

registry.registerCommand(EditorCommands.GO_BACK);
registry.registerCommand(EditorCommands.GO_FORWARD);
Expand Down Expand Up @@ -182,6 +204,77 @@ export class EditorCommandContribution implements CommandContribution {
editor.setLanguage(selected.id);
}
}

protected canConfigureEncoding(): boolean {
const widget = this.editorManager.currentEditor;
const editor = widget && widget.editor;
return !!editor;
}
protected async configureEncoding(): Promise<void> {
const widget = this.editorManager.currentEditor;
const editor = widget && widget.editor;
if (!editor) {
return;
}
const reopenWithEncodingPick = { label: 'Reopen with Encoding', value: 'reopen' };
const saveWithEncodingPick = { label: 'Save with Encoding', value: 'save' };
const actionItems: QuickPickItem<string>[] = [
reopenWithEncodingPick,
saveWithEncodingPick
];
const action = await this.quickPick.show(actionItems, {
placeholder: 'Select Action'
});
if (!action) {
return;
}
const isReopenWithEncoding = (action === reopenWithEncodingPick.value);

const configuredEncoding = this.editorPreferences.get('files.encoding');

const resource = await this.resourceProvider(editor.uri);
const guessedEncoding = resource.guessEncoding ? await resource.guessEncoding() : undefined;
resource.dispose();

const encodingItems: QuickPickItem<{ id: string, description: string }>[] = Object.keys(SUPPORTED_ENCODINGS)
.sort((k1, k2) => {
if (k1 === configuredEncoding) {
return -1;
} else if (k2 === configuredEncoding) {
return 1;
}
return SUPPORTED_ENCODINGS[k1].order - SUPPORTED_ENCODINGS[k2].order;
})
.filter(k => {
if (k === guessedEncoding && guessedEncoding !== configuredEncoding) {
return false; // do not show encoding if it is the guessed encoding that does not match the configured
}

return !isReopenWithEncoding || !SUPPORTED_ENCODINGS[k].encodeOnly; // hide those that can only be used for encoding if we are about to decode
})
.map(key => ({ label: SUPPORTED_ENCODINGS[key].labelLong, value: { id: key, description: key } }));

// Insert guessed encoding
if (guessedEncoding && configuredEncoding !== guessedEncoding && SUPPORTED_ENCODINGS[guessedEncoding]) {
encodingItems.unshift({
label: `Guessed from content: ${SUPPORTED_ENCODINGS[guessedEncoding].labelLong}`,
value: { id: guessedEncoding, description: guessedEncoding }
});
}
const encoding = await this.quickPick.show(encodingItems, {
placeholder: isReopenWithEncoding ? 'Select File Encoding to Reopen File' : 'Select File Encoding to Save with'
});
if (!encoding) {
return;
}
if (editor.document.dirty && isReopenWithEncoding) {
this.messageService.info('The file is dirty. Please save it first before reopening it with another encoding.');
return;
} else {
editor.setEncoding(encoding.id, isReopenWithEncoding ? EncodingMode.Decode : EncodingMode.Encode);
}
}

protected async toQuickPickLanguage(value: Language, current: string): Promise<QuickPickValue<Language>> {
const languageUri = this.toLanguageUri(value);
const iconClass = await this.labelProvider.getIcon(languageUri) + ' file-icon';
Expand Down
16 changes: 16 additions & 0 deletions packages/editor/src/browser/editor-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { EditorCommands } from './editor-command';
import { EditorQuickOpenService } from './editor-quick-open-service';
import { CommandRegistry, CommandContribution } from '@theia/core/lib/common';
import { KeybindingRegistry, KeybindingContribution, QuickOpenContribution, QuickOpenHandlerRegistry } from '@theia/core/lib/browser';
import { SUPPORTED_ENCODINGS } from './supported-encodings';

@injectable()
export class EditorContribution implements FrontendApplicationContribution, CommandContribution, KeybindingContribution, QuickOpenContribution {
Expand Down Expand Up @@ -89,10 +90,12 @@ export class EditorContribution implements FrontendApplicationContribution, Comm
const widget = this.editorManager.currentEditor;
const editor = widget && widget.editor;
this.updateLanguageStatus(editor);
this.updateEncodingStatus(editor);
this.setCursorPositionStatus(editor);
if (editor) {
this.toDisposeOnCurrentEditorChanged.pushAll([
editor.onLanguageChanged(() => this.updateLanguageStatus(editor)),
editor.onEncodingChanged(() => this.updateEncodingStatus(editor)),
editor.onCursorPositionChanged(() => this.setCursorPositionStatus(editor))
]);
}
Expand All @@ -113,6 +116,19 @@ export class EditorContribution implements FrontendApplicationContribution, Comm
});
}

protected updateEncodingStatus(editor: TextEditor | undefined): void {
if (!editor) {
this.statusBar.removeElement('editor-status-encoding');
return;
}
this.statusBar.setElement('editor-status-encoding', {
text: SUPPORTED_ENCODINGS[editor.getEncoding()].labelShort,
alignment: StatusBarAlignment.RIGHT,
priority: 10,
command: EditorCommands.CHANGE_ENCODING.id
});
}

protected setCursorPositionStatus(editor: TextEditor | undefined): void {
if (!editor) {
this.statusBar.removeElement('editor-status-cursor-position');
Expand Down
7 changes: 7 additions & 0 deletions packages/editor/src/browser/editor-preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
PreferenceChangeEvent
} from '@theia/core/lib/browser/preferences';
import { isWindows, isOSX } from '@theia/core/lib/common/os';
import { SUPPORTED_ENCODINGS } from './supported-encodings';

const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace';
const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace';
Expand Down Expand Up @@ -518,6 +519,11 @@ export const editorPreferenceSchema: PreferenceSchema = {
],
'default': 'auto',
'description': 'The default end of line character.'
},
'files.encoding': {
'enum': Object.keys(SUPPORTED_ENCODINGS).sort(),
'default': 'utf8',
'description': 'The default character set encoding to use when reading and writing files.'
}
}
};
Expand Down Expand Up @@ -597,6 +603,7 @@ export interface EditorConfiguration {
'diffEditor.ignoreCharChanges'?: boolean
'diffEditor.alwaysRevealFirst'?: boolean
'files.eol': EndOfLinePreference
'files.encoding': string
}
export type EndOfLinePreference = '\n' | '\r\n' | 'auto';

Expand Down
25 changes: 25 additions & 0 deletions packages/editor/src/browser/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,19 @@ export interface EditorMouseEvent {
readonly target: MouseTarget;
}

export const enum EncodingMode {

/**
* Instructs the encoding support to encode the current input with the provided encoding
*/
Encode,

/**
* Instructs the encoding support to decode the current input with the provided encoding
*/
Decode
}

export interface TextEditor extends Disposable, TextEditorSelection, Navigatable {
readonly node: HTMLElement;

Expand Down Expand Up @@ -219,6 +232,18 @@ export interface TextEditor extends Disposable, TextEditorSelection, Navigatable
detectLanguage(): void;
setLanguage(languageId: string): void;
readonly onLanguageChanged: Event<string>;

/**
* Gets the encoding of the input if known.
*/
getEncoding(): string;

/**
* Sets the encoding for the input for saving.
*/
setEncoding(encoding: string, mode: EncodingMode): void;

readonly onEncodingChanged: Event<string>;
}

export interface Dimension {
Expand Down
Loading