Fixes #24047: Use the first select line as the source for the comment line token

This commit is contained in:
Alex Dima
2017-05-10 22:49:40 +02:00
parent 5596132647
commit 1ab29cdbcf
2 changed files with 123 additions and 22 deletions
@@ -63,34 +63,25 @@ export class LineCommentCommand implements editorCommon.ICommand {
* 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[] {
let commentStrForLanguage: string[] = [];
model.forceTokenization(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++) {
let lineNumber = startLineNumber + i;
model.forceTokenization(lineNumber);
let languageId = model.getLanguageIdAtPosition(lineNumber, 1);
// Find the commentStr for this line, if none is found then bail out: we cannot do line comments
let commentStr: string;
if (commentStrForLanguage[languageId]) {
commentStr = commentStrForLanguage[languageId];
} else {
let config = LanguageConfigurationRegistry.getComments(languageId);
commentStr = (config ? config.lineCommentToken : null);
if (!commentStr) {
// Mode does not support line comments
return null;
}
commentStrForLanguage[languageId] = commentStr;
}
lines.push({
lines[i] = {
ignore: false,
commentStr: commentStr,
commentStrOffset: 0,
commentStrLength: commentStr.length
});
};
}
return lines;
@@ -9,6 +9,12 @@ 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', () => {
@@ -827,4 +833,108 @@ suite('Editor Contrib - Line Comment As Block Comment 2', () => {
});
});
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, 7, 3, 7),
);
});
});