mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
SQL Operations Studio Public Preview 1 (0.23) release source code
This commit is contained in:
174
src/vs/editor/contrib/comment/common/blockCommentCommand.ts
Normal file
174
src/vs/editor/contrib/comment/common/blockCommentCommand.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { ICommentsConfiguration, LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
export class BlockCommentCommand implements editorCommon.ICommand {
|
||||
|
||||
private _selection: Selection;
|
||||
private _usedEndToken: string;
|
||||
|
||||
constructor(selection: Selection) {
|
||||
this._selection = selection;
|
||||
this._usedEndToken = null;
|
||||
}
|
||||
|
||||
public static _haystackHasNeedleAtOffset(haystack: string, needle: string, offset: number): boolean {
|
||||
if (offset < 0) {
|
||||
return false;
|
||||
}
|
||||
var needleLength = needle.length;
|
||||
var haystackLength = haystack.length;
|
||||
if (offset + needleLength > haystackLength) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < needleLength; i++) {
|
||||
if (haystack.charCodeAt(offset + i) !== needle.charCodeAt(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private _createOperationsForBlockComment(selection: Range, config: ICommentsConfiguration, model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void {
|
||||
var startLineNumber = selection.startLineNumber;
|
||||
var startColumn = selection.startColumn;
|
||||
var endLineNumber = selection.endLineNumber;
|
||||
var endColumn = selection.endColumn;
|
||||
|
||||
var startToken = config.blockCommentStartToken;
|
||||
var endToken = config.blockCommentEndToken;
|
||||
|
||||
var startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startColumn - 1 + startToken.length);
|
||||
var endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, endColumn - 1 - endToken.length);
|
||||
|
||||
var ops: editorCommon.IIdentifiedSingleEditOperation[];
|
||||
|
||||
if (startTokenIndex !== -1 && endTokenIndex !== -1) {
|
||||
var endTokenBeforeCursorIndex = model.getLineContent(startLineNumber).lastIndexOf(endToken, startColumn - 1 + endToken.length);
|
||||
if (endTokenBeforeCursorIndex > startTokenIndex + startToken.length - 1) {
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken);
|
||||
this._usedEndToken = ops.length === 1 ? endToken : null;
|
||||
} else {
|
||||
// We have to adjust to possible inner white space
|
||||
// For Space after startToken, add Space to startToken - range math will work out
|
||||
if (model.getLineContent(startLineNumber).charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {
|
||||
startToken += ' ';
|
||||
}
|
||||
// For Space before endToken, add Space before endToken and shift index one left
|
||||
if (model.getLineContent(endLineNumber).charCodeAt(endTokenIndex - 1) === CharCode.Space) {
|
||||
endToken = ' ' + endToken;
|
||||
endTokenIndex -= 1;
|
||||
}
|
||||
ops = BlockCommentCommand._createRemoveBlockCommentOperations(
|
||||
new Range(startLineNumber, startTokenIndex + 1 + startToken.length, endLineNumber, endTokenIndex + 1), startToken, endToken
|
||||
);
|
||||
}
|
||||
} else {
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken);
|
||||
this._usedEndToken = ops.length === 1 ? endToken : null;
|
||||
}
|
||||
|
||||
for (var i = 0; i < ops.length; i++) {
|
||||
builder.addTrackedEditOperation(ops[i].range, ops[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
public static _createRemoveBlockCommentOperations(r: Range, startToken: string, endToken: string): editorCommon.IIdentifiedSingleEditOperation[] {
|
||||
var res: editorCommon.IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
if (!Range.isEmpty(r)) {
|
||||
// Remove block comment start
|
||||
res.push(EditOperation.delete(new Range(
|
||||
r.startLineNumber, r.startColumn - startToken.length,
|
||||
r.startLineNumber, r.startColumn
|
||||
)));
|
||||
|
||||
// Remove block comment end
|
||||
res.push(EditOperation.delete(new Range(
|
||||
r.endLineNumber, r.endColumn,
|
||||
r.endLineNumber, r.endColumn + endToken.length
|
||||
)));
|
||||
} else {
|
||||
// Remove both continuously
|
||||
res.push(EditOperation.delete(new Range(
|
||||
r.startLineNumber, r.startColumn - startToken.length,
|
||||
r.endLineNumber, r.endColumn + endToken.length
|
||||
)));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static _createAddBlockCommentOperations(r: Range, startToken: string, endToken: string): editorCommon.IIdentifiedSingleEditOperation[] {
|
||||
var res: editorCommon.IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
if (!Range.isEmpty(r)) {
|
||||
// Insert block comment start
|
||||
res.push(EditOperation.insert(new Position(r.startLineNumber, r.startColumn), startToken + ' '));
|
||||
|
||||
// Insert block comment end
|
||||
res.push(EditOperation.insert(new Position(r.endLineNumber, r.endColumn), ' ' + endToken));
|
||||
} else {
|
||||
// Insert both continuously
|
||||
res.push(EditOperation.replace(new Range(
|
||||
r.startLineNumber, r.startColumn,
|
||||
r.endLineNumber, r.endColumn
|
||||
), startToken + ' ' + endToken));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void {
|
||||
var startLineNumber = this._selection.startLineNumber;
|
||||
var startColumn = this._selection.startColumn;
|
||||
var endLineNumber = this._selection.endLineNumber;
|
||||
var endColumn = this._selection.endColumn;
|
||||
|
||||
model.tokenizeIfCheap(startLineNumber);
|
||||
let languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn);
|
||||
let config = LanguageConfigurationRegistry.getComments(languageId);
|
||||
if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) {
|
||||
// Mode does not support block comments
|
||||
return;
|
||||
}
|
||||
|
||||
this._createOperationsForBlockComment(
|
||||
new Range(startLineNumber, startColumn, endLineNumber, endColumn), config, model, builder
|
||||
);
|
||||
}
|
||||
|
||||
public computeCursorState(model: editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData): Selection {
|
||||
var inverseEditOperations = helper.getInverseEditOperations();
|
||||
if (inverseEditOperations.length === 2) {
|
||||
var startTokenEditOperation = inverseEditOperations[0];
|
||||
var endTokenEditOperation = inverseEditOperations[1];
|
||||
|
||||
return new Selection(
|
||||
startTokenEditOperation.range.endLineNumber,
|
||||
startTokenEditOperation.range.endColumn,
|
||||
endTokenEditOperation.range.startLineNumber,
|
||||
endTokenEditOperation.range.startColumn
|
||||
);
|
||||
} else {
|
||||
var srcRange = inverseEditOperations[0].range;
|
||||
var deltaColumn = this._usedEndToken ? -this._usedEndToken.length - 1 : 0; // minus 1 space before endToken
|
||||
return new Selection(
|
||||
srcRange.endLineNumber,
|
||||
srcRange.endColumn + deltaColumn,
|
||||
srcRange.endLineNumber,
|
||||
srcRange.endColumn + deltaColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
122
src/vs/editor/contrib/comment/common/comment.ts
Normal file
122
src/vs/editor/contrib/comment/common/comment.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { ICommand, ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { editorAction, IActionOptions, EditorAction, ServicesAccessor } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { BlockCommentCommand } from './blockCommentCommand';
|
||||
import { LineCommentCommand, Type } from './lineCommentCommand';
|
||||
|
||||
abstract class CommentLineAction extends EditorAction {
|
||||
|
||||
private _type: Type;
|
||||
|
||||
constructor(type: Type, opts: IActionOptions) {
|
||||
super(opts);
|
||||
this._type = type;
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
let model = editor.getModel();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
var commands: ICommand[] = [];
|
||||
var selections = editor.getSelections();
|
||||
var opts = model.getOptions();
|
||||
|
||||
for (var i = 0; i < selections.length; i++) {
|
||||
commands.push(new LineCommentCommand(selections[i], opts.tabSize, this._type));
|
||||
}
|
||||
|
||||
editor.pushUndoStop();
|
||||
editor.executeCommands(this.id, commands);
|
||||
editor.pushUndoStop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class ToggleCommentLineAction extends CommentLineAction {
|
||||
constructor() {
|
||||
super(Type.Toggle, {
|
||||
id: 'editor.action.commentLine',
|
||||
label: nls.localize('comment.line', "Toggle Line Comment"),
|
||||
alias: 'Toggle Line Comment',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.US_SLASH
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class AddLineCommentAction extends CommentLineAction {
|
||||
constructor() {
|
||||
super(Type.ForceAdd, {
|
||||
id: 'editor.action.addCommentLine',
|
||||
label: nls.localize('comment.line.add', "Add Line Comment"),
|
||||
alias: 'Add Line Comment',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_C)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class RemoveLineCommentAction extends CommentLineAction {
|
||||
constructor() {
|
||||
super(Type.ForceRemove, {
|
||||
id: 'editor.action.removeCommentLine',
|
||||
label: nls.localize('comment.line.remove', "Remove Line Comment"),
|
||||
alias: 'Remove Line Comment',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_U)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class BlockCommentAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.blockComment',
|
||||
label: nls.localize('comment.block', "Toggle Block Comment"),
|
||||
alias: 'Toggle Block Comment',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_A,
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_A }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
var commands: ICommand[] = [];
|
||||
var selections = editor.getSelections();
|
||||
|
||||
for (var i = 0; i < selections.length; i++) {
|
||||
commands.push(new BlockCommentCommand(selections[i]));
|
||||
}
|
||||
|
||||
editor.pushUndoStop();
|
||||
editor.executeCommands(this.id, commands);
|
||||
editor.pushUndoStop();
|
||||
}
|
||||
}
|
||||
447
src/vs/editor/contrib/comment/common/lineCommentCommand.ts
Normal file
447
src/vs/editor/contrib/comment/common/lineCommentCommand.ts
Normal file
@@ -0,0 +1,447 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { BlockCommentCommand } from './blockCommentCommand';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
export interface IInsertionPoint {
|
||||
ignore: boolean;
|
||||
commentStrOffset: number;
|
||||
}
|
||||
|
||||
export interface ILinePreflightData {
|
||||
ignore: boolean;
|
||||
commentStr: string;
|
||||
commentStrOffset: number;
|
||||
commentStrLength: number;
|
||||
}
|
||||
|
||||
export interface IPreflightData {
|
||||
supported: boolean;
|
||||
shouldRemoveComments: boolean;
|
||||
lines: ILinePreflightData[];
|
||||
}
|
||||
|
||||
export interface ISimpleModel {
|
||||
getLineContent(lineNumber: number): string;
|
||||
}
|
||||
|
||||
export const enum Type {
|
||||
Toggle = 0,
|
||||
ForceAdd = 1,
|
||||
ForceRemove = 2
|
||||
}
|
||||
|
||||
export class LineCommentCommand implements editorCommon.ICommand {
|
||||
|
||||
private _selection: Selection;
|
||||
private _selectionId: string;
|
||||
private _deltaColumn: number;
|
||||
private _moveEndPositionDown: boolean;
|
||||
private _tabSize: number;
|
||||
private _type: Type;
|
||||
|
||||
constructor(selection: Selection, tabSize: number, type: Type) {
|
||||
this._selection = selection;
|
||||
this._tabSize = tabSize;
|
||||
this._type = type;
|
||||
this._deltaColumn = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do an initial pass over the lines and gather info about the line comment string.
|
||||
* Returns null if any of the lines doesn't support a line comment string.
|
||||
*/
|
||||
public static _gatherPreflightCommentStrings(model: editorCommon.ITokenizedModel, startLineNumber: number, endLineNumber: number): ILinePreflightData[] {
|
||||
|
||||
model.tokenizeIfCheap(startLineNumber);
|
||||
const languageId = model.getLanguageIdAtPosition(startLineNumber, 1);
|
||||
|
||||
const config = LanguageConfigurationRegistry.getComments(languageId);
|
||||
const commentStr = (config ? config.lineCommentToken : null);
|
||||
if (!commentStr) {
|
||||
// Mode does not support line comments
|
||||
return null;
|
||||
}
|
||||
|
||||
let lines: ILinePreflightData[] = [];
|
||||
for (let i = 0, lineCount = endLineNumber - startLineNumber + 1; i < lineCount; i++) {
|
||||
lines[i] = {
|
||||
ignore: false,
|
||||
commentStr: commentStr,
|
||||
commentStrOffset: 0,
|
||||
commentStrLength: commentStr.length
|
||||
};
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze lines and decide which lines are relevant and what the toggle should do.
|
||||
* Also, build up several offsets and lengths useful in the generation of editor operations.
|
||||
*/
|
||||
public static _analyzeLines(type: Type, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number): IPreflightData {
|
||||
var lineData: ILinePreflightData,
|
||||
lineContentStartOffset: number,
|
||||
commentStrEndOffset: number,
|
||||
i: number,
|
||||
lineCount: number,
|
||||
lineNumber: number,
|
||||
shouldRemoveComments: boolean,
|
||||
lineContent: string,
|
||||
onlyWhitespaceLines = true;
|
||||
|
||||
if (type === Type.Toggle) {
|
||||
shouldRemoveComments = true;
|
||||
} else if (type === Type.ForceAdd) {
|
||||
shouldRemoveComments = false;
|
||||
} else {
|
||||
shouldRemoveComments = true;
|
||||
}
|
||||
|
||||
for (i = 0, lineCount = lines.length; i < lineCount; i++) {
|
||||
lineData = lines[i];
|
||||
lineNumber = startLineNumber + i;
|
||||
|
||||
lineContent = model.getLineContent(lineNumber);
|
||||
lineContentStartOffset = strings.firstNonWhitespaceIndex(lineContent);
|
||||
|
||||
if (lineContentStartOffset === -1) {
|
||||
// Empty or whitespace only line
|
||||
if (type === Type.Toggle) {
|
||||
lineData.ignore = true;
|
||||
} else if (type === Type.ForceAdd) {
|
||||
lineData.ignore = true;
|
||||
} else {
|
||||
lineData.ignore = true;
|
||||
}
|
||||
lineData.commentStrOffset = lineContent.length;
|
||||
continue;
|
||||
}
|
||||
|
||||
onlyWhitespaceLines = false;
|
||||
lineData.ignore = false;
|
||||
lineData.commentStrOffset = lineContentStartOffset;
|
||||
|
||||
if (shouldRemoveComments && !BlockCommentCommand._haystackHasNeedleAtOffset(lineContent, lineData.commentStr, lineContentStartOffset)) {
|
||||
if (type === Type.Toggle) {
|
||||
// Every line so far has been a line comment, but this one is not
|
||||
shouldRemoveComments = false;
|
||||
} else if (type === Type.ForceAdd) {
|
||||
// Will not happen
|
||||
} else {
|
||||
lineData.ignore = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldRemoveComments) {
|
||||
commentStrEndOffset = lineContentStartOffset + lineData.commentStrLength;
|
||||
if (commentStrEndOffset < lineContent.length && lineContent.charCodeAt(commentStrEndOffset) === CharCode.Space) {
|
||||
lineData.commentStrLength += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type === Type.Toggle && onlyWhitespaceLines) {
|
||||
// For only whitespace lines, we insert comments
|
||||
shouldRemoveComments = false;
|
||||
|
||||
// Also, no longer ignore them
|
||||
for (i = 0, lineCount = lines.length; i < lineCount; i++) {
|
||||
lines[i].ignore = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
supported: true,
|
||||
shouldRemoveComments: shouldRemoveComments,
|
||||
lines: lines
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze all lines and decide exactly what to do => not supported | insert line comments | remove line comments
|
||||
*/
|
||||
public static _gatherPreflightData(type: Type, model: editorCommon.ITokenizedModel, startLineNumber: number, endLineNumber: number): IPreflightData {
|
||||
var lines = LineCommentCommand._gatherPreflightCommentStrings(model, startLineNumber, endLineNumber);
|
||||
if (lines === null) {
|
||||
return {
|
||||
supported: false,
|
||||
shouldRemoveComments: false,
|
||||
lines: null
|
||||
};
|
||||
}
|
||||
|
||||
return LineCommentCommand._analyzeLines(type, model, lines, startLineNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a successful analysis, execute either insert line comments, either remove line comments
|
||||
*/
|
||||
private _executeLineComments(model: ISimpleModel, builder: editorCommon.IEditOperationBuilder, data: IPreflightData, s: Selection): void {
|
||||
|
||||
var ops: editorCommon.IIdentifiedSingleEditOperation[];
|
||||
|
||||
if (data.shouldRemoveComments) {
|
||||
ops = LineCommentCommand._createRemoveLineCommentsOperations(data.lines, s.startLineNumber);
|
||||
} else {
|
||||
LineCommentCommand._normalizeInsertionPoint(model, data.lines, s.startLineNumber, this._tabSize);
|
||||
ops = LineCommentCommand._createAddLineCommentsOperations(data.lines, s.startLineNumber);
|
||||
}
|
||||
|
||||
var cursorPosition = new Position(s.positionLineNumber, s.positionColumn);
|
||||
|
||||
for (var i = 0, len = ops.length; i < len; i++) {
|
||||
builder.addEditOperation(ops[i].range, ops[i].text);
|
||||
if (ops[i].range.isEmpty() && ops[i].range.getStartPosition().equals(cursorPosition)) {
|
||||
this._deltaColumn = ops[i].text.length;
|
||||
}
|
||||
}
|
||||
|
||||
this._selectionId = builder.trackSelection(s);
|
||||
}
|
||||
|
||||
private _attemptRemoveBlockComment(model: editorCommon.ITokenizedModel, s: Selection, startToken: string, endToken: string): editorCommon.IIdentifiedSingleEditOperation[] {
|
||||
let startLineNumber = s.startLineNumber;
|
||||
let endLineNumber = s.endLineNumber;
|
||||
|
||||
let startTokenAllowedBeforeColumn = endToken.length + Math.max(
|
||||
model.getLineFirstNonWhitespaceColumn(s.startLineNumber),
|
||||
s.startColumn
|
||||
);
|
||||
|
||||
let startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startTokenAllowedBeforeColumn - 1);
|
||||
let endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, s.endColumn - 1 - startToken.length);
|
||||
|
||||
if (startTokenIndex !== -1 && endTokenIndex === -1) {
|
||||
endTokenIndex = model.getLineContent(startLineNumber).indexOf(endToken, startTokenIndex + startToken.length);
|
||||
endLineNumber = startLineNumber;
|
||||
}
|
||||
|
||||
if (startTokenIndex === -1 && endTokenIndex !== -1) {
|
||||
startTokenIndex = model.getLineContent(endLineNumber).lastIndexOf(startToken, endTokenIndex);
|
||||
startLineNumber = endLineNumber;
|
||||
}
|
||||
|
||||
if (s.isEmpty() && (startTokenIndex === -1 || endTokenIndex === -1)) {
|
||||
startTokenIndex = model.getLineContent(startLineNumber).indexOf(startToken);
|
||||
if (startTokenIndex !== -1) {
|
||||
endTokenIndex = model.getLineContent(startLineNumber).indexOf(endToken, startTokenIndex + startToken.length);
|
||||
}
|
||||
}
|
||||
|
||||
// We have to adjust to possible inner white space.
|
||||
// For Space after startToken, add Space to startToken - range math will work out.
|
||||
if (startTokenIndex !== -1 && model.getLineContent(startLineNumber).charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {
|
||||
startToken += ' ';
|
||||
}
|
||||
|
||||
// For Space before endToken, add Space before endToken and shift index one left.
|
||||
if (endTokenIndex !== -1 && model.getLineContent(endLineNumber).charCodeAt(endTokenIndex - 1) === CharCode.Space) {
|
||||
endToken = ' ' + endToken;
|
||||
endTokenIndex -= 1;
|
||||
}
|
||||
|
||||
if (startTokenIndex !== -1 && endTokenIndex !== -1) {
|
||||
return BlockCommentCommand._createRemoveBlockCommentOperations(
|
||||
new Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an unsuccessful analysis, delegate to the block comment command
|
||||
*/
|
||||
private _executeBlockComment(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder, s: Selection): void {
|
||||
model.tokenizeIfCheap(s.startLineNumber);
|
||||
let languageId = model.getLanguageIdAtPosition(s.startLineNumber, s.startColumn);
|
||||
let config = LanguageConfigurationRegistry.getComments(languageId);
|
||||
if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) {
|
||||
// Mode does not support block comments
|
||||
return;
|
||||
}
|
||||
|
||||
var startToken = config.blockCommentStartToken;
|
||||
var endToken = config.blockCommentEndToken;
|
||||
|
||||
var ops = this._attemptRemoveBlockComment(model, s, startToken, endToken);
|
||||
if (!ops) {
|
||||
if (s.isEmpty()) {
|
||||
var lineContent = model.getLineContent(s.startLineNumber);
|
||||
var firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);
|
||||
if (firstNonWhitespaceIndex === -1) {
|
||||
// Line is empty or contains only whitespace
|
||||
firstNonWhitespaceIndex = lineContent.length;
|
||||
}
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(
|
||||
new Range(s.startLineNumber, firstNonWhitespaceIndex + 1, s.startLineNumber, lineContent.length + 1), startToken, endToken
|
||||
);
|
||||
} else {
|
||||
ops = BlockCommentCommand._createAddBlockCommentOperations(
|
||||
new Range(s.startLineNumber, model.getLineFirstNonWhitespaceColumn(s.startLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)), startToken, endToken
|
||||
);
|
||||
}
|
||||
|
||||
if (ops.length === 1) {
|
||||
// Leave cursor after token and Space
|
||||
this._deltaColumn = startToken.length + 1;
|
||||
}
|
||||
}
|
||||
this._selectionId = builder.trackSelection(s);
|
||||
for (var i = 0; i < ops.length; i++) {
|
||||
builder.addEditOperation(ops[i].range, ops[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void {
|
||||
|
||||
var s = this._selection;
|
||||
this._moveEndPositionDown = false;
|
||||
|
||||
if (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {
|
||||
this._moveEndPositionDown = true;
|
||||
s = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));
|
||||
}
|
||||
|
||||
var data = LineCommentCommand._gatherPreflightData(this._type, model, s.startLineNumber, s.endLineNumber);
|
||||
if (data.supported) {
|
||||
return this._executeLineComments(model, builder, data, s);
|
||||
}
|
||||
|
||||
return this._executeBlockComment(model, builder, s);
|
||||
}
|
||||
|
||||
public computeCursorState(model: editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData): Selection {
|
||||
var result = helper.getTrackedSelection(this._selectionId);
|
||||
|
||||
if (this._moveEndPositionDown) {
|
||||
result = result.setEndPosition(result.endLineNumber + 1, 1);
|
||||
}
|
||||
|
||||
return new Selection(
|
||||
result.startLineNumber,
|
||||
result.startColumn + this._deltaColumn,
|
||||
result.endLineNumber,
|
||||
result.endColumn + this._deltaColumn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate edit operations in the remove line comment case
|
||||
*/
|
||||
public static _createRemoveLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): editorCommon.IIdentifiedSingleEditOperation[] {
|
||||
var i: number,
|
||||
len: number,
|
||||
lineData: ILinePreflightData,
|
||||
res: editorCommon.IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
for (i = 0, len = lines.length; i < len; i++) {
|
||||
lineData = lines[i];
|
||||
|
||||
if (lineData.ignore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
res.push(EditOperation.delete(new Range(
|
||||
startLineNumber + i, lineData.commentStrOffset + 1,
|
||||
startLineNumber + i, lineData.commentStrOffset + lineData.commentStrLength + 1
|
||||
)));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate edit operations in the add line comment case
|
||||
*/
|
||||
public static _createAddLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): editorCommon.IIdentifiedSingleEditOperation[] {
|
||||
var i: number,
|
||||
len: number,
|
||||
lineData: ILinePreflightData,
|
||||
res: editorCommon.IIdentifiedSingleEditOperation[] = [];
|
||||
|
||||
for (i = 0, len = lines.length; i < len; i++) {
|
||||
lineData = lines[i];
|
||||
|
||||
if (lineData.ignore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
res.push(EditOperation.insert(new Position(startLineNumber + i, lineData.commentStrOffset + 1), lineData.commentStr + ' '));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// TODO@Alex -> duplicated in characterHardWrappingLineMapper
|
||||
private static nextVisibleColumn(currentVisibleColumn: number, tabSize: number, isTab: boolean, columnSize: number): number {
|
||||
if (isTab) {
|
||||
return currentVisibleColumn + (tabSize - (currentVisibleColumn % tabSize));
|
||||
}
|
||||
return currentVisibleColumn + columnSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust insertion points to have them vertically aligned in the add line comment case
|
||||
*/
|
||||
public static _normalizeInsertionPoint(model: ISimpleModel, lines: IInsertionPoint[], startLineNumber: number, tabSize: number): void {
|
||||
var minVisibleColumn = Number.MAX_VALUE,
|
||||
i: number,
|
||||
len: number,
|
||||
lineContent: string,
|
||||
j: number,
|
||||
lenJ: number,
|
||||
currentVisibleColumn: number;
|
||||
|
||||
for (i = 0, len = lines.length; i < len; i++) {
|
||||
if (lines[i].ignore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lineContent = model.getLineContent(startLineNumber + i);
|
||||
|
||||
currentVisibleColumn = 0;
|
||||
for (j = 0, lenJ = lines[i].commentStrOffset; currentVisibleColumn < minVisibleColumn && j < lenJ; j++) {
|
||||
currentVisibleColumn = LineCommentCommand.nextVisibleColumn(currentVisibleColumn, tabSize, lineContent.charCodeAt(j) === CharCode.Tab, 1);
|
||||
}
|
||||
|
||||
if (currentVisibleColumn < minVisibleColumn) {
|
||||
minVisibleColumn = currentVisibleColumn;
|
||||
}
|
||||
}
|
||||
|
||||
minVisibleColumn = Math.floor(minVisibleColumn / tabSize) * tabSize;
|
||||
|
||||
for (i = 0, len = lines.length; i < len; i++) {
|
||||
if (lines[i].ignore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lineContent = model.getLineContent(startLineNumber + i);
|
||||
|
||||
currentVisibleColumn = 0;
|
||||
for (j = 0, lenJ = lines[i].commentStrOffset; currentVisibleColumn < minVisibleColumn && j < lenJ; j++) {
|
||||
currentVisibleColumn = LineCommentCommand.nextVisibleColumn(currentVisibleColumn, tabSize, lineContent.charCodeAt(j) === CharCode.Tab, 1);
|
||||
}
|
||||
|
||||
if (currentVisibleColumn > minVisibleColumn) {
|
||||
lines[i].commentStrOffset = j - 1;
|
||||
} else {
|
||||
lines[i].commentStrOffset = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { BlockCommentCommand } from 'vs/editor/contrib/comment/common/blockCommentCommand';
|
||||
import { testCommand } from 'vs/editor/test/common/commands/commandTestUtils';
|
||||
import { CommentMode } from 'vs/editor/test/common/commentMode';
|
||||
|
||||
function testBlockCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<0', '0>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new BlockCommentCommand(sel), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
suite('Editor Contrib - Block Comment Command', () => {
|
||||
|
||||
test('empty selection wraps itself', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 3, 1, 3),
|
||||
[
|
||||
'fi<0 0>rst',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 6, 1, 6)
|
||||
);
|
||||
});
|
||||
|
||||
test('invisible selection ignored', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 1, 1, 1),
|
||||
[
|
||||
'<0 first',
|
||||
' 0>\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 4, 2, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('bug9511', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 6, 1, 1),
|
||||
[
|
||||
'<0 first 0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 4, 1, 9)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0first0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 8, 1, 3),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 6)
|
||||
);
|
||||
});
|
||||
|
||||
test('one line selection', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 6, 1, 3),
|
||||
[
|
||||
'fi<0 rst 0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 6, 1, 9)
|
||||
);
|
||||
});
|
||||
|
||||
test('one line selection toggle', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 6, 1, 3),
|
||||
[
|
||||
'fi<0 rst 0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 6, 1, 9)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'fi<0rst0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 8, 1, 5),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 3, 1, 6)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0 first 0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 10, 1, 1),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 6)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0 first0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 9, 1, 1),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 6)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0first 0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 9, 1, 1),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 6)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'fi<0rst0>',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 8, 1, 5),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 3, 1, 6)
|
||||
);
|
||||
});
|
||||
|
||||
test('multi line selection', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 1),
|
||||
[
|
||||
'<0 first',
|
||||
'\tse 0>cond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 4, 2, 4)
|
||||
);
|
||||
});
|
||||
|
||||
test('multi line selection toggle', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 1),
|
||||
[
|
||||
'<0 first',
|
||||
'\tse 0>cond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 4, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0first',
|
||||
'\tse0>cond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 3),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0 first',
|
||||
'\tse0>cond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 3),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0first',
|
||||
'\tse 0>cond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 3),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0 first',
|
||||
'\tse 0>cond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 3),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 2, 4)
|
||||
);
|
||||
});
|
||||
|
||||
test('fuzzy removes', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'asd <0 qwe',
|
||||
'asd 0> qwe'
|
||||
],
|
||||
new Selection(2, 5, 1, 7),
|
||||
[
|
||||
'asd qwe',
|
||||
'asd qwe'
|
||||
],
|
||||
new Selection(1, 5, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'asd <0 qwe',
|
||||
'asd 0> qwe'
|
||||
],
|
||||
new Selection(2, 5, 1, 6),
|
||||
[
|
||||
'asd qwe',
|
||||
'asd qwe'
|
||||
],
|
||||
new Selection(1, 5, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'asd <0 qwe',
|
||||
'asd 0> qwe'
|
||||
],
|
||||
new Selection(2, 5, 1, 5),
|
||||
[
|
||||
'asd qwe',
|
||||
'asd qwe'
|
||||
],
|
||||
new Selection(1, 5, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'asd <0 qwe',
|
||||
'asd 0> qwe'
|
||||
],
|
||||
new Selection(2, 5, 1, 11),
|
||||
[
|
||||
'asd qwe',
|
||||
'asd qwe'
|
||||
],
|
||||
new Selection(1, 5, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'asd <0 qwe',
|
||||
'asd 0> qwe'
|
||||
],
|
||||
new Selection(2, 1, 1, 11),
|
||||
[
|
||||
'asd qwe',
|
||||
'asd qwe'
|
||||
],
|
||||
new Selection(1, 5, 2, 4)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'asd <0 qwe',
|
||||
'asd 0> qwe'
|
||||
],
|
||||
new Selection(2, 7, 1, 11),
|
||||
[
|
||||
'asd qwe',
|
||||
'asd qwe'
|
||||
],
|
||||
new Selection(1, 5, 2, 4)
|
||||
);
|
||||
});
|
||||
|
||||
test('bug #30358', function () {
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0 start 0> middle end',
|
||||
],
|
||||
new Selection(1, 20, 1, 23),
|
||||
[
|
||||
'<0 start 0> middle <0 end 0>'
|
||||
],
|
||||
new Selection(1, 23, 1, 26)
|
||||
);
|
||||
|
||||
testBlockCommentCommand(
|
||||
[
|
||||
'<0 start 0> middle <0 end 0>'
|
||||
],
|
||||
new Selection(1, 13, 1, 19),
|
||||
[
|
||||
'<0 start 0> <0 middle 0> <0 end 0>'
|
||||
],
|
||||
new Selection(1, 16, 1, 22)
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,940 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ILinePreflightData, IPreflightData, ISimpleModel, LineCommentCommand, Type } from 'vs/editor/contrib/comment/common/lineCommentCommand';
|
||||
import { testCommand } from 'vs/editor/test/common/commands/commandTestUtils';
|
||||
import { CommentMode } from 'vs/editor/test/common/commentMode';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { NULL_STATE } from 'vs/editor/common/modes/nullMode';
|
||||
import { TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
|
||||
import { CommentRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
|
||||
suite('Editor Contrib - Line Comment Command', () => {
|
||||
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<!@#', '#@!>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
function testAddLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<!@#', '#@!>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
test('comment single line', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'some text',
|
||||
'\tsome more text'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'!@# some text',
|
||||
'\tsome more text'
|
||||
],
|
||||
new Selection(1, 9, 1, 9)
|
||||
);
|
||||
});
|
||||
|
||||
function createSimpleModel(lines: string[]): ISimpleModel {
|
||||
return {
|
||||
getLineContent: (lineNumber: number) => {
|
||||
return lines[lineNumber - 1];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createBasicLinePreflightData(commentTokens: string[]): ILinePreflightData[] {
|
||||
return commentTokens.map((commentString) => {
|
||||
var r: ILinePreflightData = {
|
||||
ignore: false,
|
||||
commentStr: commentString,
|
||||
commentStrOffset: 0,
|
||||
commentStrLength: commentString.length
|
||||
};
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
test('_analyzeLines', function () {
|
||||
var r: IPreflightData;
|
||||
|
||||
r = LineCommentCommand._analyzeLines(Type.Toggle, createSimpleModel([
|
||||
'\t\t',
|
||||
' ',
|
||||
' c',
|
||||
'\t\td'
|
||||
]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1);
|
||||
|
||||
assert.equal(r.shouldRemoveComments, false);
|
||||
|
||||
// Does not change `commentStr`
|
||||
assert.equal(r.lines[0].commentStr, '//');
|
||||
assert.equal(r.lines[1].commentStr, 'rem');
|
||||
assert.equal(r.lines[2].commentStr, '!@#');
|
||||
assert.equal(r.lines[3].commentStr, '!@#');
|
||||
|
||||
// Fills in `isWhitespace`
|
||||
assert.equal(r.lines[0].ignore, true);
|
||||
assert.equal(r.lines[1].ignore, true);
|
||||
assert.equal(r.lines[2].ignore, false);
|
||||
assert.equal(r.lines[3].ignore, false);
|
||||
|
||||
// Fills in `commentStrOffset`
|
||||
assert.equal(r.lines[0].commentStrOffset, 2);
|
||||
assert.equal(r.lines[1].commentStrOffset, 4);
|
||||
assert.equal(r.lines[2].commentStrOffset, 4);
|
||||
assert.equal(r.lines[3].commentStrOffset, 2);
|
||||
|
||||
|
||||
r = LineCommentCommand._analyzeLines(Type.Toggle, createSimpleModel([
|
||||
'\t\t',
|
||||
' rem ',
|
||||
' !@# c',
|
||||
'\t\t!@#d'
|
||||
]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1);
|
||||
|
||||
assert.equal(r.shouldRemoveComments, true);
|
||||
|
||||
// Does not change `commentStr`
|
||||
assert.equal(r.lines[0].commentStr, '//');
|
||||
assert.equal(r.lines[1].commentStr, 'rem');
|
||||
assert.equal(r.lines[2].commentStr, '!@#');
|
||||
assert.equal(r.lines[3].commentStr, '!@#');
|
||||
|
||||
// Fills in `isWhitespace`
|
||||
assert.equal(r.lines[0].ignore, true);
|
||||
assert.equal(r.lines[1].ignore, false);
|
||||
assert.equal(r.lines[2].ignore, false);
|
||||
assert.equal(r.lines[3].ignore, false);
|
||||
|
||||
// Fills in `commentStrOffset`
|
||||
assert.equal(r.lines[0].commentStrOffset, 2);
|
||||
assert.equal(r.lines[1].commentStrOffset, 4);
|
||||
assert.equal(r.lines[2].commentStrOffset, 4);
|
||||
assert.equal(r.lines[3].commentStrOffset, 2);
|
||||
|
||||
// Fills in `commentStrLength`
|
||||
assert.equal(r.lines[0].commentStrLength, 2);
|
||||
assert.equal(r.lines[1].commentStrLength, 4);
|
||||
assert.equal(r.lines[2].commentStrLength, 4);
|
||||
assert.equal(r.lines[3].commentStrLength, 3);
|
||||
});
|
||||
|
||||
test('_normalizeInsertionPoint', function () {
|
||||
|
||||
var runTest = (mixedArr: any[], tabSize: number, expected: number[], testName: string) => {
|
||||
var model = createSimpleModel(mixedArr.filter((item, idx) => idx % 2 === 0));
|
||||
var offsets = mixedArr.filter((item, idx) => idx % 2 === 1).map(offset => {
|
||||
return {
|
||||
commentStrOffset: offset,
|
||||
ignore: false
|
||||
};
|
||||
});
|
||||
LineCommentCommand._normalizeInsertionPoint(model, offsets, 1, tabSize);
|
||||
var actual = offsets.map(item => item.commentStrOffset);
|
||||
assert.deepEqual(actual, expected, testName);
|
||||
};
|
||||
|
||||
// Bug 16696:[comment] comments not aligned in this case
|
||||
runTest([
|
||||
' XX', 2,
|
||||
' YY', 4
|
||||
], 4, [0, 0], 'Bug 16696');
|
||||
|
||||
runTest([
|
||||
'\t\t\tXX', 3,
|
||||
' \tYY', 5,
|
||||
' ZZ', 8,
|
||||
'\t\tTT', 2
|
||||
], 4, [2, 5, 8, 2], 'Test1');
|
||||
|
||||
runTest([
|
||||
'\t\t\t XX', 6,
|
||||
' \t\t\t\tYY', 8,
|
||||
' ZZ', 8,
|
||||
'\t\t TT', 6
|
||||
], 4, [2, 5, 8, 2], 'Test2');
|
||||
|
||||
runTest([
|
||||
'\t\t', 2,
|
||||
'\t\t\t', 3,
|
||||
'\t\t\t\t', 4,
|
||||
'\t\t\t', 3
|
||||
], 4, [2, 2, 2, 2], 'Test3');
|
||||
|
||||
runTest([
|
||||
'\t\t', 2,
|
||||
'\t\t\t', 3,
|
||||
'\t\t\t\t', 4,
|
||||
'\t\t\t', 3,
|
||||
' ', 4
|
||||
], 2, [2, 2, 2, 2, 4], 'Test4');
|
||||
|
||||
runTest([
|
||||
'\t\t', 2,
|
||||
'\t\t\t', 3,
|
||||
'\t\t\t\t', 4,
|
||||
'\t\t\t', 3,
|
||||
' ', 4
|
||||
], 4, [1, 1, 1, 1, 4], 'Test5');
|
||||
|
||||
runTest([
|
||||
' \t', 2,
|
||||
' \t', 3,
|
||||
' \t', 4,
|
||||
' ', 4,
|
||||
'\t', 1
|
||||
], 4, [2, 3, 4, 4, 1], 'Test6');
|
||||
|
||||
runTest([
|
||||
' \t\t', 3,
|
||||
' \t\t', 4,
|
||||
' \t\t', 5,
|
||||
' \t', 5,
|
||||
'\t', 1
|
||||
], 4, [2, 3, 4, 4, 1], 'Test7');
|
||||
|
||||
runTest([
|
||||
'\t', 1,
|
||||
' ', 4
|
||||
], 4, [1, 4], 'Test8:4');
|
||||
runTest([
|
||||
'\t', 1,
|
||||
' ', 3
|
||||
], 4, [0, 0], 'Test8:3');
|
||||
runTest([
|
||||
'\t', 1,
|
||||
' ', 2
|
||||
], 4, [0, 0], 'Test8:2');
|
||||
runTest([
|
||||
'\t', 1,
|
||||
' ', 1
|
||||
], 4, [0, 0], 'Test8:1');
|
||||
runTest([
|
||||
'\t', 1,
|
||||
'', 0
|
||||
], 4, [0, 0], 'Test8:0');
|
||||
});
|
||||
|
||||
test('detects indentation', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\tsome text',
|
||||
'\tsome more text'
|
||||
],
|
||||
new Selection(2, 2, 1, 1),
|
||||
[
|
||||
'\t!@# some text',
|
||||
'\t!@# some more text'
|
||||
],
|
||||
new Selection(1, 1, 2, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('detects mixed indentation', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\tsome text',
|
||||
' some more text'
|
||||
],
|
||||
new Selection(2, 2, 1, 1),
|
||||
[
|
||||
'\t!@# some text',
|
||||
' !@# some more text'
|
||||
],
|
||||
new Selection(1, 1, 2, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('ignores whitespace lines', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\tsome text',
|
||||
'\t ',
|
||||
'',
|
||||
'\tsome more text'
|
||||
],
|
||||
new Selection(4, 2, 1, 1),
|
||||
[
|
||||
'\t!@# some text',
|
||||
'\t ',
|
||||
'',
|
||||
'\t!@# some more text'
|
||||
],
|
||||
new Selection(1, 1, 4, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('removes its own', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t!@# some text',
|
||||
'\t ',
|
||||
'\t\t!@# some more text'
|
||||
],
|
||||
new Selection(3, 2, 1, 1),
|
||||
[
|
||||
'\tsome text',
|
||||
'\t ',
|
||||
'\t\tsome more text'
|
||||
],
|
||||
new Selection(1, 1, 3, 2)
|
||||
);
|
||||
});
|
||||
|
||||
test('works in only whitespace', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t ',
|
||||
'\t',
|
||||
'\t\tsome more text'
|
||||
],
|
||||
new Selection(3, 1, 1, 1),
|
||||
[
|
||||
'\t!@# ',
|
||||
'\t!@# ',
|
||||
'\t\tsome more text'
|
||||
],
|
||||
new Selection(1, 1, 3, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('bug 9697 - whitespace before comment token', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t !@#first',
|
||||
'\tsecond line'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'\t first',
|
||||
'\tsecond line'
|
||||
],
|
||||
new Selection(1, 1, 1, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('bug 10162 - line comment before caret', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first!@#',
|
||||
'\tsecond line'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'!@# first!@#',
|
||||
'\tsecond line'
|
||||
],
|
||||
new Selection(1, 9, 1, 9)
|
||||
);
|
||||
});
|
||||
|
||||
test('comment single line - leading whitespace', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first!@#',
|
||||
'\tsecond line'
|
||||
],
|
||||
new Selection(2, 3, 2, 1),
|
||||
[
|
||||
'first!@#',
|
||||
'\t!@# second line'
|
||||
],
|
||||
new Selection(2, 1, 2, 7)
|
||||
);
|
||||
});
|
||||
|
||||
test('ignores invisible selection', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 1, 1, 1),
|
||||
[
|
||||
'!@# first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 9, 2, 5)
|
||||
);
|
||||
});
|
||||
|
||||
test('multiple lines', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 1),
|
||||
[
|
||||
'!@# first',
|
||||
'!@# \tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 9, 2, 12)
|
||||
);
|
||||
});
|
||||
|
||||
test('multiple modes on multiple lines', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(4, 4, 3, 1),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'!@# third line',
|
||||
'!@# fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(3, 9, 4, 12)
|
||||
);
|
||||
});
|
||||
|
||||
test('toggle single line', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'!@# first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 9, 1, 9)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'!@# first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 4, 1, 4),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('toggle multiple lines', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 4, 1, 1),
|
||||
[
|
||||
'!@# first',
|
||||
'!@# \tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 9, 2, 12)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'!@# first',
|
||||
'!@# \tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(2, 7, 1, 4),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 2, 3)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #2837 "Add Line Comment" fault when blank lines involved', function () {
|
||||
testAddLineCommentCommand(
|
||||
[
|
||||
' if displayName == "":',
|
||||
' displayName = groupName',
|
||||
' description = getAttr(attributes, "description")',
|
||||
' mailAddress = getAttr(attributes, "mail")',
|
||||
'',
|
||||
' print "||Group name|%s|" % displayName',
|
||||
' print "||Description|%s|" % description',
|
||||
' print "||Email address|[mailto:%s]|" % mailAddress`',
|
||||
],
|
||||
new Selection(1, 1, 8, 56),
|
||||
[
|
||||
' !@# if displayName == "":',
|
||||
' !@# displayName = groupName',
|
||||
' !@# description = getAttr(attributes, "description")',
|
||||
' !@# mailAddress = getAttr(attributes, "mail")',
|
||||
'',
|
||||
' !@# print "||Group name|%s|" % displayName',
|
||||
' !@# print "||Description|%s|" % description',
|
||||
' !@# print "||Email address|[mailto:%s]|" % mailAddress`',
|
||||
],
|
||||
new Selection(1, 1, 8, 60)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Editor Contrib - Line Comment As Block Comment', () => {
|
||||
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: '', blockComment: ['(', ')'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
test('fall back to block comment command', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'( first )',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 3, 1, 3)
|
||||
);
|
||||
});
|
||||
|
||||
test('fall back to block comment command - toggle', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'(first)',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 7, 1, 2),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 6)
|
||||
);
|
||||
});
|
||||
|
||||
test('bug 9513 - expand single line to uncomment auto block', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'( first )',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 3, 1, 3)
|
||||
);
|
||||
});
|
||||
|
||||
test('bug 9691 - always expand selection to line boundaries', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(3, 2, 1, 3),
|
||||
[
|
||||
'( first',
|
||||
'\tsecond line',
|
||||
'third line )',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 5, 3, 2)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'(first',
|
||||
'\tsecond line',
|
||||
'third line)',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(3, 11, 1, 2),
|
||||
[
|
||||
'first',
|
||||
'\tsecond line',
|
||||
'third line',
|
||||
'fourth line',
|
||||
'fifth'
|
||||
],
|
||||
new Selection(1, 1, 3, 11)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Editor Contrib - Line Comment As Block Comment 2', () => {
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let mode = new CommentMode({ lineComment: null, blockComment: ['<!@#', '#@!>'] });
|
||||
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection);
|
||||
mode.dispose();
|
||||
}
|
||||
|
||||
test('no selection => uses indentation', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'\t\t<!@# first\t #@!>',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(1, 1, 1, 1)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\t<!@#first\t #@!>',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(1, 1, 1, 1),
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(1, 1, 1, 1)
|
||||
);
|
||||
});
|
||||
|
||||
test('can remove', function () {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(5, 1, 5, 1),
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\tfifth\t\t'
|
||||
],
|
||||
new Selection(5, 1, 5, 1)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(5, 3, 5, 3),
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\tfifth\t\t'
|
||||
],
|
||||
new Selection(5, 3, 5, 3)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(5, 4, 5, 4),
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\tfifth\t\t'
|
||||
],
|
||||
new Selection(5, 3, 5, 3)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(5, 16, 5, 3),
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\tfifth\t\t'
|
||||
],
|
||||
new Selection(5, 3, 5, 8)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(5, 12, 5, 7),
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\tfifth\t\t'
|
||||
],
|
||||
new Selection(5, 3, 5, 8)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\t<!@#fifth#@!>\t\t'
|
||||
],
|
||||
new Selection(5, 18, 5, 18),
|
||||
[
|
||||
'\t\tfirst\t ',
|
||||
'\t\tsecond line',
|
||||
'\tthird line',
|
||||
'fourth line',
|
||||
'\t\tfifth\t\t'
|
||||
],
|
||||
new Selection(5, 10, 5, 10)
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #993: Remove comment does not work consistently in HTML', () => {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
' asd qwe',
|
||||
' asd qwe',
|
||||
''
|
||||
],
|
||||
new Selection(1, 1, 3, 1),
|
||||
[
|
||||
' <!@# asd qwe',
|
||||
' asd qwe #@!>',
|
||||
''
|
||||
],
|
||||
new Selection(1, 1, 3, 1)
|
||||
);
|
||||
|
||||
testLineCommentCommand(
|
||||
[
|
||||
' <!@#asd qwe',
|
||||
' asd qwe#@!>',
|
||||
''
|
||||
],
|
||||
new Selection(1, 1, 3, 1),
|
||||
[
|
||||
' asd qwe',
|
||||
' asd qwe',
|
||||
''
|
||||
],
|
||||
new Selection(1, 1, 3, 1)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Editor Contrib - Line Comment in mixed modes', () => {
|
||||
|
||||
const OUTER_LANGUAGE_ID = new modes.LanguageIdentifier('outerMode', 3);
|
||||
const INNER_LANGUAGE_ID = new modes.LanguageIdentifier('innerMode', 4);
|
||||
|
||||
class OuterMode extends MockMode {
|
||||
constructor(commentsConfig: CommentRule) {
|
||||
super(OUTER_LANGUAGE_ID);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
|
||||
comments: commentsConfig
|
||||
}));
|
||||
|
||||
this._register(modes.TokenizationRegistry.register(this.getLanguageIdentifier().language, {
|
||||
getInitialState: (): modes.IState => NULL_STATE,
|
||||
tokenize: undefined,
|
||||
tokenize2: (line: string, state: modes.IState): TokenizationResult2 => {
|
||||
let languageId = (/^ /.test(line) ? INNER_LANGUAGE_ID : OUTER_LANGUAGE_ID);
|
||||
|
||||
let tokens = new Uint32Array(1 << 1);
|
||||
tokens[(0 << 1)] = 0;
|
||||
tokens[(0 << 1) + 1] = (
|
||||
(modes.ColorId.DefaultForeground << modes.MetadataConsts.FOREGROUND_OFFSET)
|
||||
| (languageId.id << modes.MetadataConsts.LANGUAGEID_OFFSET)
|
||||
);
|
||||
return new TokenizationResult2(tokens, state);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
class InnerMode extends MockMode {
|
||||
constructor(commentsConfig: CommentRule) {
|
||||
super(INNER_LANGUAGE_ID);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
|
||||
comments: commentsConfig
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
|
||||
let outerMode = new OuterMode({ lineComment: '//', blockComment: ['/*', '*/'] });
|
||||
let innerMode = new InnerMode({ lineComment: null, blockComment: ['{/*', '*/}'] });
|
||||
testCommand(
|
||||
lines,
|
||||
outerMode.getLanguageIdentifier(),
|
||||
selection,
|
||||
(sel) => new LineCommentCommand(sel, 4, Type.Toggle),
|
||||
expectedLines,
|
||||
expectedSelection
|
||||
);
|
||||
innerMode.dispose();
|
||||
outerMode.dispose();
|
||||
}
|
||||
|
||||
test('issue #24047 (part 1): Commenting code in JSX files', () => {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'import React from \'react\';',
|
||||
'const Loader = () => (',
|
||||
' <div>',
|
||||
' Loading...',
|
||||
' </div>',
|
||||
');',
|
||||
'export default Loader;'
|
||||
],
|
||||
new Selection(1, 1, 7, 22),
|
||||
[
|
||||
'// import React from \'react\';',
|
||||
'// const Loader = () => (',
|
||||
'// <div>',
|
||||
'// Loading...',
|
||||
'// </div>',
|
||||
'// );',
|
||||
'// export default Loader;'
|
||||
],
|
||||
new Selection(1, 4, 7, 25),
|
||||
);
|
||||
});
|
||||
|
||||
test('issue #24047 (part 2): Commenting code in JSX files', () => {
|
||||
testLineCommentCommand(
|
||||
[
|
||||
'import React from \'react\';',
|
||||
'const Loader = () => (',
|
||||
' <div>',
|
||||
' Loading...',
|
||||
' </div>',
|
||||
');',
|
||||
'export default Loader;'
|
||||
],
|
||||
new Selection(3, 4, 3, 4),
|
||||
[
|
||||
'import React from \'react\';',
|
||||
'const Loader = () => (',
|
||||
' {/* <div> */}',
|
||||
' Loading...',
|
||||
' </div>',
|
||||
');',
|
||||
'export default Loader;'
|
||||
],
|
||||
new Selection(3, 8, 3, 8),
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user