Skip to content

Commit

Permalink
Add support for recognizing word locales in word operations (microsof…
Browse files Browse the repository at this point in the history
  • Loading branch information
yutotnh committed Jan 27, 2024
1 parent 39804fa commit bc776b1
Show file tree
Hide file tree
Showing 9 changed files with 409 additions and 182 deletions.
2 changes: 1 addition & 1 deletion src/vs/editor/browser/widget/codeEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
if (!this._modelData) {
return null;
}
return WordOperations.getWordAtPosition(this._modelData.model, this._configuration.options.get(EditorOption.wordSeparators), position);
return WordOperations.getWordAtPosition(this._modelData.model, this._configuration.options.get(EditorOption.wordSeparators), position, this._configuration.options.get(EditorOption.recognizeWordLocales));
}

public getValue(options: { preserveBOM: boolean; lineEnding: string } | null = null): string {
Expand Down
53 changes: 53 additions & 0 deletions src/vs/editor/common/config/editorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ export interface IEditorOptions {
* The message to display when the editor is readonly.
*/
readOnlyMessage?: IMarkdownString;
/**
* Locales that recognizes word separators when doing word related navigations or operations.
*
* Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.). If you specify more than one, separate them with a comma.
* If the default setting is blank, or if all specified BCP 47 language tags are not supported, the word will not be recognized.
*/
recognizeWordLocales?: string;
/**
* Should the textarea used for input use the DOM `readonly` attribute.
* Defaults to false.
Expand Down Expand Up @@ -3564,6 +3571,50 @@ class ReadonlyMessage extends BaseEditorOption<EditorOption.readOnlyMessage, IMa
}
}

//#endregion

//#region readonly

/**
* Locales that recognizes word separators when doing word related navigations or operations.
*
* Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.). If you specify more than one, separate them with a comma.
* If the default setting is blank, or if all specified BCP 47 language tags are not supported, the word will not be recognized.
*/
class RecognizeWordLocales extends BaseEditorOption<EditorOption.recognizeWordLocales, string, string[]> {
constructor() {
const defaults: string[] = [];

super(
EditorOption.recognizeWordLocales, 'recognizeWordLocales', defaults,
{
type: 'string',
description: nls.localize('recognizeWordLocales', "Locales that recognizes word separators when doing word related navigations or operations. Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.). If you specify more than one, separate them with a comma.If the default setting is blank, or if all specified BCP 47 language tags are not supported, the word will not be recognized."),
}
);
}

public validate(input: any): string[] {
if (typeof input === 'string') {
const input_locales = input.split(',').map((item) => item.trim());
const valid_locales: string[] = [];
for (const locale of input_locales) {
try {
if (Intl.Segmenter.supportedLocalesOf(locale).length > 0) {
valid_locales.push(locale);
}
} catch (_) {
// ignore invalid locales
}
}
return valid_locales;
}

return this.defaultValue;
}
}


//#endregion

//#region scrollbar
Expand Down Expand Up @@ -5161,6 +5212,7 @@ export const enum EditorOption {
quickSuggestionsDelay,
readOnly,
readOnlyMessage,
recognizeWordLocales,
renameOnType,
renderControlCharacters,
renderFinalNewline,
Expand Down Expand Up @@ -5699,6 +5751,7 @@ export const EditorOptions = {
EditorOption.readOnly, 'readOnly', false,
)),
readOnlyMessage: register(new ReadonlyMessage()),
recognizeWordLocales: register(new RecognizeWordLocales()),
renameOnType: register(new EditorBooleanOption(
EditorOption.renameOnType, 'renameOnType', false,
{ description: nls.localize('renameOnType', "Controls whether the editor auto renames on type."), markdownDeprecationMessage: nls.localize('renameOnTypeDeprecate', "Deprecated, use `editor.linkedEditing` instead.") }
Expand Down
179 changes: 130 additions & 49 deletions src/vs/editor/common/cursor/cursorWordOperations.ts

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/vs/editor/common/cursorCommon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export class CursorConfiguration {
public readonly surroundingPairs: CharacterMap;
public readonly blockCommentStartToken: string | null;
public readonly shouldAutoCloseBefore: { quote: (ch: string) => boolean; bracket: (ch: string) => boolean; comment: (ch: string) => boolean };
public readonly recognizeWordLocales: string[];

private readonly _languageId: string;
private _electricChars: { [key: string]: boolean } | null;
Expand All @@ -97,6 +98,7 @@ export class CursorConfiguration {
|| e.hasChanged(EditorOption.useTabStops)
|| e.hasChanged(EditorOption.fontInfo)
|| e.hasChanged(EditorOption.readOnly)
|| e.hasChanged(EditorOption.recognizeWordLocales)
);
}

Expand Down Expand Up @@ -134,6 +136,7 @@ export class CursorConfiguration {
this.autoClosingOvertype = options.get(EditorOption.autoClosingOvertype);
this.autoSurround = options.get(EditorOption.autoSurround);
this.autoIndent = options.get(EditorOption.autoIndent);
this.recognizeWordLocales = options.get(EditorOption.recognizeWordLocales);

this.surroundingPairs = {};
this._electricChars = null;
Expand Down
113 changes: 57 additions & 56 deletions src/vs/editor/common/standalone/standaloneEnums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,62 +265,63 @@ export enum EditorOption {
quickSuggestionsDelay = 89,
readOnly = 90,
readOnlyMessage = 91,
renameOnType = 92,
renderControlCharacters = 93,
renderFinalNewline = 94,
renderLineHighlight = 95,
renderLineHighlightOnlyWhenFocus = 96,
renderValidationDecorations = 97,
renderWhitespace = 98,
revealHorizontalRightPadding = 99,
roundedSelection = 100,
rulers = 101,
scrollbar = 102,
scrollBeyondLastColumn = 103,
scrollBeyondLastLine = 104,
scrollPredominantAxis = 105,
selectionClipboard = 106,
selectionHighlight = 107,
selectOnLineNumbers = 108,
showFoldingControls = 109,
showUnused = 110,
snippetSuggestions = 111,
smartSelect = 112,
smoothScrolling = 113,
stickyScroll = 114,
stickyTabStops = 115,
stopRenderingLineAfter = 116,
suggest = 117,
suggestFontSize = 118,
suggestLineHeight = 119,
suggestOnTriggerCharacters = 120,
suggestSelection = 121,
tabCompletion = 122,
tabIndex = 123,
unicodeHighlighting = 124,
unusualLineTerminators = 125,
useShadowDOM = 126,
useTabStops = 127,
wordBreak = 128,
wordSeparators = 129,
wordWrap = 130,
wordWrapBreakAfterCharacters = 131,
wordWrapBreakBeforeCharacters = 132,
wordWrapColumn = 133,
wordWrapOverride1 = 134,
wordWrapOverride2 = 135,
wrappingIndent = 136,
wrappingStrategy = 137,
showDeprecated = 138,
inlayHints = 139,
editorClassName = 140,
pixelRatio = 141,
tabFocusMode = 142,
layoutInfo = 143,
wrappingInfo = 144,
defaultColorDecorators = 145,
colorDecoratorsActivatedOn = 146,
inlineCompletionsAccessibilityVerbose = 147
recognizeWordLocales = 92,
renameOnType = 93,
renderControlCharacters = 94,
renderFinalNewline = 95,
renderLineHighlight = 96,
renderLineHighlightOnlyWhenFocus = 97,
renderValidationDecorations = 98,
renderWhitespace = 99,
revealHorizontalRightPadding = 100,
roundedSelection = 101,
rulers = 102,
scrollbar = 103,
scrollBeyondLastColumn = 104,
scrollBeyondLastLine = 105,
scrollPredominantAxis = 106,
selectionClipboard = 107,
selectionHighlight = 108,
selectOnLineNumbers = 109,
showFoldingControls = 110,
showUnused = 111,
snippetSuggestions = 112,
smartSelect = 113,
smoothScrolling = 114,
stickyScroll = 115,
stickyTabStops = 116,
stopRenderingLineAfter = 117,
suggest = 118,
suggestFontSize = 119,
suggestLineHeight = 120,
suggestOnTriggerCharacters = 121,
suggestSelection = 122,
tabCompletion = 123,
tabIndex = 124,
unicodeHighlighting = 125,
unusualLineTerminators = 126,
useShadowDOM = 127,
useTabStops = 128,
wordBreak = 129,
wordSeparators = 130,
wordWrap = 131,
wordWrapBreakAfterCharacters = 132,
wordWrapBreakBeforeCharacters = 133,
wordWrapColumn = 134,
wordWrapOverride1 = 135,
wordWrapOverride2 = 136,
wrappingIndent = 137,
wrappingStrategy = 138,
showDeprecated = 139,
inlayHints = 140,
editorClassName = 141,
pixelRatio = 142,
tabFocusMode = 143,
layoutInfo = 144,
wrappingInfo = 145,
defaultColorDecorators = 146,
colorDecoratorsActivatedOn = 147,
inlineCompletionsAccessibilityVerbose = 148
}

/**
Expand Down
35 changes: 19 additions & 16 deletions src/vs/editor/contrib/wordOperations/browser/wordOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ export abstract class MoveWordCommand extends EditorCommand {
const wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators));
const model = editor.getModel();
const selections = editor.getSelections();
const recognizeWordLocales = editor.getOption(EditorOption.recognizeWordLocales);

const result = selections.map((sel) => {
const inPosition = new Position(sel.positionLineNumber, sel.positionColumn);
const outPosition = this._move(wordSeparators, model, inPosition, this._wordNavigationType);
const outPosition = this._move(wordSeparators, model, inPosition, this._wordNavigationType, recognizeWordLocales);
return this._moveTo(sel, outPosition, this._inSelectionMode);
});

Expand Down Expand Up @@ -83,18 +84,18 @@ export abstract class MoveWordCommand extends EditorCommand {
}
}

protected abstract _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position;
protected abstract _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType, recognizeWordLocales: string[]): Position;
}

export class WordLeftCommand extends MoveWordCommand {
protected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return WordOperations.moveWordLeft(wordSeparators, model, position, wordNavigationType);
protected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType, recognizeWordLocales: string[]): Position {
return WordOperations.moveWordLeft(wordSeparators, model, position, wordNavigationType, recognizeWordLocales);
}
}

export class WordRightCommand extends MoveWordCommand {
protected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return WordOperations.moveWordRight(wordSeparators, model, position, wordNavigationType);
protected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType, recognizeWordLocales: string[]): Position {
return WordOperations.moveWordRight(wordSeparators, model, position, wordNavigationType, recognizeWordLocales);
}
}

Expand Down Expand Up @@ -187,8 +188,8 @@ export class CursorWordAccessibilityLeft extends WordLeftCommand {
});
}

protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);
protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType, recognizeWordLocales: string[]): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType, recognizeWordLocales);
}
}

Expand All @@ -202,8 +203,8 @@ export class CursorWordAccessibilityLeftSelect extends WordLeftCommand {
});
}

protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);
protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType, recognizeWordLocales: string[]): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType, recognizeWordLocales);
}
}

Expand Down Expand Up @@ -295,8 +296,8 @@ export class CursorWordAccessibilityRight extends WordRightCommand {
});
}

protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);
protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType, recognizeWordLocales: string[]): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType, recognizeWordLocales);
}
}

Expand All @@ -310,8 +311,8 @@ export class CursorWordAccessibilityRightSelect extends WordRightCommand {
});
}

protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType);
protected override _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType, recognizeWordLocales: string[]): Position {
return super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue), model, position, wordNavigationType, recognizeWordLocales);
}
}

Expand Down Expand Up @@ -354,7 +355,8 @@ export abstract class DeleteWordCommand extends EditorCommand {
autoClosingBrackets,
autoClosingQuotes,
autoClosingPairs,
autoClosedCharacters: viewModel.getCursorAutoClosedCharacters()
autoClosedCharacters: viewModel.getCursorAutoClosedCharacters(),
recognizeWordLocales: editor.getOption(EditorOption.recognizeWordLocales)
}, this._wordNavigationType);
return new ReplaceCommand(deleteRange, '');
});
Expand Down Expand Up @@ -485,9 +487,10 @@ export class DeleteInsideWord extends EditorAction {
const wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators));
const model = editor.getModel();
const selections = editor.getSelections();
const recognizeWordLocales = editor.getOption(EditorOption.recognizeWordLocales);

const commands = selections.map((sel) => {
const deleteRange = WordOperations.deleteInsideWord(wordSeparators, model, sel);
const deleteRange = WordOperations.deleteInsideWord(wordSeparators, model, sel, recognizeWordLocales);
return new ReplaceCommand(deleteRange, '');
});

Expand Down
Loading

0 comments on commit bc776b1

Please sign in to comment.