wip

上级 3f1a2f69
......@@ -40,8 +40,8 @@
"[yaml]": {
"editor.insertSpaces": true,
"editor.tabSize": 2,
"editor.autoIndent": false
"editor.autoIndent": "advanced"
}
}
}
}
\ No newline at end of file
}
......@@ -256,6 +256,13 @@ function migrateOptions(options: IEditorOptions): void {
enabled: false
};
}
const autoIndent = options.autoIndent;
if (<any>autoIndent === true) {
options.autoIndent = 'full';
} else if (<any>autoIndent === false) {
options.autoIndent = 'advanced';
}
}
function deepCloneAndMigrateOptions(_options: IEditorOptions): IEditorOptions {
......
......@@ -31,6 +31,18 @@ export type EditorAutoSurroundStrategy = 'languageDefined' | 'quotes' | 'bracket
*/
export type EditorAutoClosingOvertypeStrategy = 'always' | 'auto' | 'never';
/**
* Configuration options for auto indentation in the editor
* @internal
*/
export const enum EditorAutoIndentStrategy {
None = 0,
Keep = 1,
Brackets = 2,
Advanced = 3,
Full = 4
}
/**
* Configuration options for the editor.
*/
......@@ -364,7 +376,7 @@ export interface IEditorOptions {
* Enable auto indentation adjustment.
* Defaults to false.
*/
autoIndent?: boolean;
autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';
/**
* Enable format on type.
* Defaults to false.
......@@ -915,6 +927,20 @@ class EditorEnumOption<K1 extends EditorOption, T extends string, V> extends Bas
//#endregion
//#region autoIndent
function _autoIndentFromString(autoIndent: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'): EditorAutoIndentStrategy {
switch (autoIndent) {
case 'none': return EditorAutoIndentStrategy.None;
case 'keep': return EditorAutoIndentStrategy.Keep;
case 'brackets': return EditorAutoIndentStrategy.Brackets;
case 'advanced': return EditorAutoIndentStrategy.Advanced;
case 'full': return EditorAutoIndentStrategy.Full;
}
}
//#endregion
//#region accessibilitySupport
class EditorAccessibilitySupport extends BaseEditorOption<EditorOption.accessibilitySupport, AccessibilitySupport> {
......@@ -3146,9 +3172,21 @@ export const EditorOptions = {
description: nls.localize('autoClosingQuotes', "Controls whether the editor should automatically close quotes after the user adds an opening quote.")
}
)),
autoIndent: register(new EditorBooleanOption(
EditorOption.autoIndent, 'autoIndent', true,
{ description: nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste or move lines. Extensions with indentation rules of the language must be available.") }
autoIndent: register(new EditorEnumOption(
EditorOption.autoIndent, 'autoIndent',
EditorAutoIndentStrategy.Full, 'full',
['none', 'keep', 'brackets', 'advanced', 'full'],
_autoIndentFromString,
{
enumDescriptions: [
nls.localize('editor.autoIndent.none', "The editor will not insert indentation automatically."),
nls.localize('editor.autoIndent.keep', "The editor will keep the current line's indentation."),
nls.localize('editor.autoIndent.brackets', "The editor will keep the current line's indentation and honor language defined brackets."),
nls.localize('editor.autoIndent.advanced', "The editor will keep the current line's indentation, honor language defined brackets and invoke special onEnterRules defined by languages."),
nls.localize('editor.autoIndent.full', "The editor will keep the current line's indentation, honor language defined brackets, invoke special onEnterRules defined by languages, and honor indentationRules defined by languages."),
],
description: nls.localize('autoIndent', "Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.")
}
)),
automaticLayout: register(new EditorBooleanOption(
EditorOption.automaticLayout, 'automaticLayout', false,
......
......@@ -6,7 +6,7 @@
import { CharCode } from 'vs/base/common/charCode';
import { onUnexpectedError } from 'vs/base/common/errors';
import * as strings from 'vs/base/common/strings';
import { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, ConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy, EditorOption } from 'vs/editor/common/config/editorOptions';
import { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, ConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy, EditorOption, EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
......@@ -103,7 +103,7 @@ export class CursorConfiguration {
public readonly autoClosingQuotes: EditorAutoClosingStrategy;
public readonly autoClosingOvertype: EditorAutoClosingOvertypeStrategy;
public readonly autoSurround: EditorAutoSurroundStrategy;
public readonly autoIndent: boolean;
public readonly autoIndent2: EditorAutoIndentStrategy;
public readonly autoClosingPairsOpen2: Map<string, StandardAutoClosingPairConditional[]>;
public readonly autoClosingPairsClose2: Map<string, StandardAutoClosingPairConditional[]>;
public readonly surroundingPairs: CharacterMap;
......@@ -155,7 +155,7 @@ export class CursorConfiguration {
this.autoClosingQuotes = options.get(EditorOption.autoClosingQuotes);
this.autoClosingOvertype = options.get(EditorOption.autoClosingOvertype);
this.autoSurround = options.get(EditorOption.autoSurround);
this.autoIndent = options.get(EditorOption.autoIndent);
this.autoIndent2 = options.get(EditorOption.autoIndent);
this.autoClosingPairsOpen2 = new Map<string, StandardAutoClosingPairConditional[]>();
this.autoClosingPairsClose2 = new Map<string, StandardAutoClosingPairConditional[]>();
......
......@@ -19,6 +19,7 @@ import { ITextModel } from 'vs/editor/common/model';
import { EnterAction, IndentAction, StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { IElectricAction } from 'vs/editor/common/modes/supports/electricCharacter';
import { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';
export class TypeOperations {
......@@ -289,12 +290,17 @@ export class TypeOperations {
}
private static _enter(config: CursorConfiguration, model: ITextModel, keepPosition: boolean, range: Range): ICommand {
if (!model.isCheapToTokenize(range.getStartPosition().lineNumber)) {
if (config.autoIndent2 === EditorAutoIndentStrategy.None) {
return TypeOperations._typeCommand(range, '\n', keepPosition);
}
if (!model.isCheapToTokenize(range.getStartPosition().lineNumber) || config.autoIndent2 === EditorAutoIndentStrategy.Keep) {
let lineText = model.getLineContent(range.startLineNumber);
let indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1);
return TypeOperations._typeCommand(range, '\n' + config.normalizeIndentation(indentation), keepPosition);
}
const autoIndent = config.autoIndent2;
let r = LanguageConfigurationRegistry.getEnterAction(model, range);
if (r) {
let enterAction = r.enterAction;
......
......@@ -19,6 +19,7 @@ import { BracketElectricCharacterSupport, IElectricAction } from 'vs/editor/comm
import { IndentConsts, IndentRulesSupport } from 'vs/editor/common/modes/supports/indentRules';
import { IOnEnterSupportOptions, OnEnterSupport } from 'vs/editor/common/modes/supports/onEnter';
import { RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
import { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';
/**
* Interface used to support insertion of mode specific comments.
......@@ -539,12 +540,12 @@ export class LanguageConfigurationRegistryImpl {
return null;
}
public getIndentForEnter(model: ITextModel, range: Range, indentConverter: IIndentConverter, autoIndent: boolean): { beforeEnter: string, afterEnter: string } | null {
public getIndentForEnter(autoIndent2: EditorAutoIndentStrategy, model: ITextModel, range: Range, indentConverter: IIndentConverter): { beforeEnter: string, afterEnter: string } | null {
model.forceTokenization(range.startLineNumber);
let lineTokens = model.getLineTokens(range.startLineNumber);
let beforeEnterText;
let afterEnterText;
let beforeEnterText: string;
let afterEnterText: string;
let scopedLineTokens = createScopedLineTokens(lineTokens, range.startColumn - 1);
let scopedLineText = scopedLineTokens.getLineContent();
......@@ -709,20 +710,19 @@ export class LanguageConfigurationRegistryImpl {
return r ? r.enterAction : null;
}
public getEnterAction(model: ITextModel, range: Range): { enterAction: EnterAction; indentation: string; } | null {
public getEnterAction(autoIndent: EditorAutoIndentStrategy.Brackets | EditorAutoIndentStrategy.Advanced | EditorAutoIndentStrategy.Full, model: ITextModel, range: Range): { enterAction: EnterAction; indentation: string; } | null {
let indentation = this.getIndentationAtPosition(model, range.startLineNumber, range.startColumn);
let scopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber, range.startColumn);
let onEnterSupport = this._getOnEnterSupport(scopedLineTokens.languageId);
const scopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber, range.startColumn);
const onEnterSupport = this._getOnEnterSupport(scopedLineTokens.languageId);
if (!onEnterSupport) {
return null;
}
let scopedLineText = scopedLineTokens.getLineContent();
let beforeEnterText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);
let afterEnterText;
const scopedLineText = scopedLineTokens.getLineContent();
const beforeEnterText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);
// selection support
let afterEnterText: string;
if (range.isEmpty()) {
afterEnterText = scopedLineText.substr(range.startColumn - 1 - scopedLineTokens.firstCharOffset);
} else {
......@@ -730,12 +730,10 @@ export class LanguageConfigurationRegistryImpl {
afterEnterText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);
}
let lineNumber = range.startLineNumber;
let oneLineAboveText = '';
if (lineNumber > 1 && scopedLineTokens.firstCharOffset === 0) {
if (range.startLineNumber > 1 && scopedLineTokens.firstCharOffset === 0) {
// This is not the first line and the entire line belongs to this mode
let oneLineAboveScopedLineTokens = this.getScopedLineTokens(model, lineNumber - 1);
const oneLineAboveScopedLineTokens = this.getScopedLineTokens(model, range.startLineNumber - 1);
if (oneLineAboveScopedLineTokens.languageId === scopedLineTokens.languageId) {
// The line above ends with text belonging to the same mode
oneLineAboveText = oneLineAboveScopedLineTokens.getLineContent();
......@@ -744,7 +742,7 @@ export class LanguageConfigurationRegistryImpl {
let enterResult: EnterAction | null = null;
try {
enterResult = onEnterSupport.onEnter(oneLineAboveText, beforeEnterText, afterEnterText);
enterResult = onEnterSupport.onEnter(autoIndent, oneLineAboveText, beforeEnterText, afterEnterText);
} catch (e) {
onUnexpectedError(e);
}
......
......@@ -6,6 +6,7 @@
import { onUnexpectedError } from 'vs/base/common/errors';
import * as strings from 'vs/base/common/strings';
import { CharacterPair, EnterAction, IndentAction, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';
export interface IOnEnterSupportOptions {
brackets?: CharacterPair[];
......@@ -48,46 +49,51 @@ export class OnEnterSupport {
this._regExpRules = opts.regExpRules || [];
}
public onEnter(oneLineAboveText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
public onEnter(autoIndent: EditorAutoIndentStrategy, oneLineAboveText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
// (1): `regExpRules`
for (let i = 0, len = this._regExpRules.length; i < len; i++) {
let rule = this._regExpRules[i];
const regResult = [{
reg: rule.beforeText,
text: beforeEnterText
}, {
reg: rule.afterText,
text: afterEnterText
}, {
reg: rule.oneLineAboveText,
text: oneLineAboveText
}].every((obj): boolean => {
return obj.reg ? obj.reg.test(obj.text) : true;
});
if (regResult) {
return rule.action;
if (autoIndent >= EditorAutoIndentStrategy.Advanced) {
for (let i = 0, len = this._regExpRules.length; i < len; i++) {
let rule = this._regExpRules[i];
const regResult = [{
reg: rule.beforeText,
text: beforeEnterText
}, {
reg: rule.afterText,
text: afterEnterText
}, {
reg: rule.oneLineAboveText,
text: oneLineAboveText
}].every((obj): boolean => {
return obj.reg ? obj.reg.test(obj.text) : true;
});
if (regResult) {
return rule.action;
}
}
}
// (2): Special indent-outdent
if (beforeEnterText.length > 0 && afterEnterText.length > 0) {
for (let i = 0, len = this._brackets.length; i < len; i++) {
let bracket = this._brackets[i];
if (bracket.openRegExp.test(beforeEnterText) && bracket.closeRegExp.test(afterEnterText)) {
return { indentAction: IndentAction.IndentOutdent };
if (autoIndent >= EditorAutoIndentStrategy.Brackets) {
if (beforeEnterText.length > 0 && afterEnterText.length > 0) {
for (let i = 0, len = this._brackets.length; i < len; i++) {
let bracket = this._brackets[i];
if (bracket.openRegExp.test(beforeEnterText) && bracket.closeRegExp.test(afterEnterText)) {
return { indentAction: IndentAction.IndentOutdent };
}
}
}
}
// (4): Open bracket based logic
if (beforeEnterText.length > 0) {
for (let i = 0, len = this._brackets.length; i < len; i++) {
let bracket = this._brackets[i];
if (bracket.openRegExp.test(beforeEnterText)) {
return { indentAction: IndentAction.Indent };
if (autoIndent >= EditorAutoIndentStrategy.Brackets) {
if (beforeEnterText.length > 0) {
for (let i = 0, len = this._brackets.length; i < len; i++) {
let bracket = this._brackets[i];
if (bracket.openRegExp.test(beforeEnterText)) {
return { indentAction: IndentAction.Indent };
}
}
}
}
......
......@@ -22,7 +22,7 @@ import { IndentConsts } from 'vs/editor/common/modes/supports/indentRules';
import { IModelService } from 'vs/editor/common/services/modelService';
import * as indentUtils from 'vs/editor/contrib/indentation/indentUtils';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { EditorOption, EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';
export function getReindentEditOperations(model: ITextModel, startLineNumber: number, endLineNumber: number, inheritedIndent?: string): IIdentifiedSingleEditOperation[] {
if (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {
......@@ -442,7 +442,7 @@ export class AutoIndentOnPaste implements IEditorContribution {
this.callOnModel.clear();
// we are disabled
if (!this.editor.getOption(EditorOption.autoIndent) || this.editor.getOption(EditorOption.formatOnPaste)) {
if (this.editor.getOption(EditorOption.autoIndent) < EditorAutoIndentStrategy.Full || this.editor.getOption(EditorOption.formatOnPaste)) {
return;
}
......
......@@ -13,18 +13,19 @@ import { IndentAction } from 'vs/editor/common/modes/languageConfiguration';
import { IIndentConverter, LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { IndentConsts } from 'vs/editor/common/modes/supports/indentRules';
import * as indentUtils from 'vs/editor/contrib/indentation/indentUtils';
import { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';
export class MoveLinesCommand implements ICommand {
private readonly _selection: Selection;
private readonly _isMovingDown: boolean;
private readonly _autoIndent: boolean;
private readonly _autoIndent: EditorAutoIndentStrategy;
private _selectionId: string | null;
private _moveEndPositionDown?: boolean;
private _moveEndLineSelectionShrink: boolean;
constructor(selection: Selection, isMovingDown: boolean, autoIndent: boolean) {
constructor(selection: Selection, isMovingDown: boolean, autoIndent: EditorAutoIndentStrategy) {
this._selection = selection;
this._isMovingDown = isMovingDown;
this._autoIndent = autoIndent;
......@@ -288,7 +289,7 @@ export class MoveLinesCommand implements ICommand {
}
private shouldAutoIndent(model: ITextModel, selection: Selection) {
if (!this._autoIndent) {
if (this._autoIndent < EditorAutoIndentStrategy.Full) {
return false;
}
// if it's not easy to tokenize, we stop auto indent.
......
......@@ -13,7 +13,7 @@ const global: any = self;
// Set defaults for standalone editor
(<any>EditorOptions.wrappingIndent).defaultValue = WrappingIndent.None;
(<any>EditorOptions.glyphMargin).defaultValue = false;
(<any>EditorOptions.autoIndent).defaultValue = false;
(<any>EditorOptions.autoIndent).defaultValue = 'advanced';
(<any>EditorOptions.overviewRulerLanes).defaultValue = 2;
const api = createMonacoBaseAPI();
......
......@@ -2834,7 +2834,7 @@ suite('Editor Controller - Indentation Rules', () => {
],
languageIdentifier: mode.getLanguageIdentifier(),
modelOpts: { insertSpaces: false },
editorOpts: { autoIndent: true }
editorOpts: { autoIndent: 'full' }
}, (model, cursor) => {
moveTo(cursor, 1, 12, false);
assertCursor(cursor, new Selection(1, 12, 1, 12));
......@@ -2857,7 +2857,7 @@ suite('Editor Controller - Indentation Rules', () => {
'\t'
],
languageIdentifier: mode.getLanguageIdentifier(),
editorOpts: { autoIndent: true }
editorOpts: { autoIndent: 'full' }
}, (model, cursor) => {
moveTo(cursor, 2, 2, false);
assertCursor(cursor, new Selection(2, 2, 2, 2));
......@@ -2876,7 +2876,7 @@ suite('Editor Controller - Indentation Rules', () => {
],
languageIdentifier: mode.getLanguageIdentifier(),
modelOpts: { insertSpaces: false },
editorOpts: { autoIndent: true }
editorOpts: { autoIndent: 'full' }
}, (model, cursor) => {
moveTo(cursor, 2, 15, false);
assertCursor(cursor, new Selection(2, 15, 2, 15));
......@@ -2896,7 +2896,7 @@ suite('Editor Controller - Indentation Rules', () => {
],
languageIdentifier: mode.getLanguageIdentifier(),
modelOpts: { insertSpaces: false },
editorOpts: { autoIndent: true }
editorOpts: { autoIndent: 'full' }
}, (model, cursor) => {
moveTo(cursor, 2, 14, false);
assertCursor(cursor, new Selection(2, 14, 2, 14));
......@@ -2924,7 +2924,7 @@ suite('Editor Controller - Indentation Rules', () => {
mode.getLanguageIdentifier()
);
withTestCodeEditor(null, { model: model, autoIndent: true }, (editor, cursor) => {
withTestCodeEditor(null, { model: model, autoIndent: 'full' }, (editor, cursor) => {
moveTo(cursor, 2, 11, false);
assertCursor(cursor, new Selection(2, 11, 2, 11));
......@@ -2948,7 +2948,7 @@ suite('Editor Controller - Indentation Rules', () => {
'}}'
],
languageIdentifier: mode.getLanguageIdentifier(),
editorOpts: { autoIndent: true }
editorOpts: { autoIndent: 'full' }
}, (model, cursor) => {
moveTo(cursor, 3, 13, false);
assertCursor(cursor, new Selection(3, 13, 3, 13));
......@@ -3084,7 +3084,7 @@ suite('Editor Controller - Indentation Rules', () => {
],
languageIdentifier: mode.getLanguageIdentifier(),
modelOpts: { insertSpaces: false },
editorOpts: { autoIndent: true }
editorOpts: { autoIndent: 'full' }
}, (model, cursor) => {
moveTo(cursor, 5, 4, false);
assertCursor(cursor, new Selection(5, 4, 5, 4));
......@@ -3554,7 +3554,7 @@ suite('Editor Controller - Indentation Rules', () => {
rubyMode.getLanguageIdentifier()
);
withTestCodeEditor(null, { model: model, autoIndent: true }, (editor, cursor) => {
withTestCodeEditor(null, { model: model, autoIndent: 'full' }, (editor, cursor) => {
moveTo(cursor, 4, 7, false);
assertCursor(cursor, new Selection(4, 7, 4, 7));
......@@ -3615,7 +3615,7 @@ suite('Editor Controller - Indentation Rules', () => {
'\t\t'
],
languageIdentifier: mode.getLanguageIdentifier(),
editorOpts: { autoIndent: true }
editorOpts: { autoIndent: 'full' }
}, (model, cursor) => {
moveTo(cursor, 3, 3, false);
assertCursor(cursor, new Selection(3, 3, 3, 3));
......@@ -3664,7 +3664,7 @@ suite('Editor Controller - Indentation Rules', () => {
mode.getLanguageIdentifier()
);
withTestCodeEditor(null, { model: model, autoIndent: false }, (editor, cursor) => {
withTestCodeEditor(null, { model: model, autoIndent: 'advanced' }, (editor, cursor) => {
moveTo(cursor, 7, 6, false);
assertCursor(cursor, new Selection(7, 6, 7, 6));
......@@ -3728,7 +3728,7 @@ suite('Editor Controller - Indentation Rules', () => {
mode.getLanguageIdentifier()
);
withTestCodeEditor(null, { model: model, autoIndent: false }, (editor, cursor) => {
withTestCodeEditor(null, { model: model, autoIndent: 'advanced' }, (editor, cursor) => {
moveTo(cursor, 8, 1, false);
assertCursor(cursor, new Selection(8, 1, 8, 1));
......@@ -3791,7 +3791,7 @@ suite('Editor Controller - Indentation Rules', () => {
mode.getLanguageIdentifier()
);
withTestCodeEditor(null, { model: model, autoIndent: true }, (editor, cursor) => {
withTestCodeEditor(null, { model: model, autoIndent: 'full' }, (editor, cursor) => {
moveTo(cursor, 3, 19, false);
assertCursor(cursor, new Selection(3, 19, 3, 19));
......
......@@ -2775,7 +2775,7 @@ declare namespace monaco.editor {
* Enable auto indentation adjustment.
* Defaults to false.
*/
autoIndent?: boolean;
autoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';
/**
* Enable format on type.
* Defaults to false.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册