SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View 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
);
}
}
}

View 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();
}
}

View 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;
}
}
}
}

View File

@@ -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)
);
});
});

View File

@@ -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),
);
});
});