diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 59fc2c23f5c79..d8b7c358a5548 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -1480,6 +1480,16 @@ module FourSlash {
return runningOffset;
}
+ public copyFormatOptions(): ts.FormatCodeOptions {
+ return ts.clone(this.formatCodeOptions);
+ }
+
+ public setFormatOptions(formatCodeOptions: ts.FormatCodeOptions): ts.FormatCodeOptions {
+ var oldFormatCodeOptions = this.formatCodeOptions;
+ this.formatCodeOptions = formatCodeOptions;
+ return oldFormatCodeOptions;
+ }
+
public formatDocument() {
this.scenarioActions.push('');
diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts
index 180ff0c9e9528..dd12b452b57f8 100644
--- a/src/services/formatting/formatting.ts
+++ b/src/services/formatting/formatting.ts
@@ -842,9 +842,9 @@ module ts.formatting {
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
var nonWhitespaceColumnInFirstPart =
- SmartIndenter.findFirstNonWhitespaceColumn(startLinePos, parts[0].pos, sourceFile, options);
+ SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(startLinePos, parts[0].pos, sourceFile, options);
- if (indentation === nonWhitespaceColumnInFirstPart) {
+ if (indentation === nonWhitespaceColumnInFirstPart.column) {
return;
}
@@ -855,21 +855,21 @@ module ts.formatting {
}
// shift all parts on the delta size
- var delta = indentation - nonWhitespaceColumnInFirstPart;
+ var delta = indentation - nonWhitespaceColumnInFirstPart.column;
for (var i = startIndex, len = parts.length; i < len; ++i, ++startLine) {
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
- var nonWhitespaceColumn =
+ var nonWhitespaceCharacterAndColumn =
i === 0
? nonWhitespaceColumnInFirstPart
- : SmartIndenter.findFirstNonWhitespaceColumn(parts[i].pos, parts[i].end, sourceFile, options);
+ : SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(parts[i].pos, parts[i].end, sourceFile, options);
- var newIndentation = nonWhitespaceColumn + delta;
+ var newIndentation = nonWhitespaceCharacterAndColumn.column + delta;
if (newIndentation > 0) {
var indentationString = getIndentationString(newIndentation, options);
- recordReplace(startLinePos, nonWhitespaceColumn, indentationString);
+ recordReplace(startLinePos, nonWhitespaceCharacterAndColumn.character, indentationString);
}
else {
- recordDelete(startLinePos, nonWhitespaceColumn);
+ recordDelete(startLinePos, nonWhitespaceCharacterAndColumn.character);
}
}
}
diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts
index 04849420e70ff..593e6163e297b 100644
--- a/src/services/formatting/smartIndenter.ts
+++ b/src/services/formatting/smartIndenter.ts
@@ -306,12 +306,20 @@ module ts.formatting {
return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options);
}
- export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions): number {
+ /*
+ Character is the actual index of the character since the beginning of the line.
+ Column - position of the character after expanding tabs to spaces
+ "0\t2$"
+ value of 'character' for '$' is 3
+ value of 'column' for '$' is 6 (assuming that tab size is 4)
+ */
+ export function findFirstNonWhitespaceCharacterAndColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions) {
+ var character = 0;
var column = 0;
for (var pos = startPos; pos < endPos; ++pos) {
var ch = sourceFile.text.charCodeAt(pos);
if (!isWhiteSpace(ch)) {
- return column;
+ break;
}
if (ch === CharacterCodes.tab) {
@@ -320,8 +328,14 @@ module ts.formatting {
else {
column++;
}
+
+ character++;
}
- return column;
+ return { column, character };
+ }
+
+ export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions): number {
+ return findFirstNonWhitespaceCharacterAndColumn(startPos, endPos, sourceFile, options).column;
}
function nodeContentIsAlwaysIndented(kind: SyntaxKind): boolean {
diff --git a/tests/cases/fourslash/formattingMultilineCommentsWithTabs1.ts b/tests/cases/fourslash/formattingMultilineCommentsWithTabs1.ts
new file mode 100644
index 0000000000000..967a0f1ee0da9
--- /dev/null
+++ b/tests/cases/fourslash/formattingMultilineCommentsWithTabs1.ts
@@ -0,0 +1,29 @@
+///
+
+////var f = function (j) {
+////
+//// switch (j) {
+//// case 1:
+/////*1*/ /* when current checkbox has focus, Firefox has changed check state already
+/////*2*/ on SPACE bar press only
+/////*3*/ IE does not have issue, use the CSS class
+/////*4*/ input:focus[type=checkbox] (z-index = 31290)
+/////*5*/ to determine whether checkbox has focus or not
+//// */
+//// break;
+//// case 2:
+//// break;
+//// }
+////}
+format.document();
+goTo.marker("1");
+verify.currentLineContentIs(" /* when current checkbox has focus, Firefox has changed check state already");
+goTo.marker("2");
+verify.currentLineContentIs(" on SPACE bar press only");
+goTo.marker("3");
+verify.currentLineContentIs(" IE does not have issue, use the CSS class");
+goTo.marker("4");
+verify.currentLineContentIs(" input:focus[type=checkbox] (z-index = 31290)");
+goTo.marker("5");
+verify.currentLineContentIs(" to determine whether checkbox has focus or not");
+
diff --git a/tests/cases/fourslash/formattingMultilineCommentsWithTabs2.ts b/tests/cases/fourslash/formattingMultilineCommentsWithTabs2.ts
new file mode 100644
index 0000000000000..e66934c6cebc7
--- /dev/null
+++ b/tests/cases/fourslash/formattingMultilineCommentsWithTabs2.ts
@@ -0,0 +1,36 @@
+///
+
+////var f = function (j) {
+////
+//// switch (j) {
+//// case 1:
+/////*1*/ /* when current checkbox has focus, Firefox has changed check state already
+/////*2*/ on SPACE bar press only
+/////*3*/ IE does not have issue, use the CSS class
+/////*4*/ input:focus[type=checkbox] (z-index = 31290)
+/////*5*/ to determine whether checkbox has focus or not
+//// */
+//// break;
+//// case 2:
+//// break;
+//// }
+////}
+var options = format.copyFormatOptions();
+options.ConvertTabsToSpaces = false;
+var oldOptions = format.setFormatOptions(options);
+try {
+ format.document();
+ goTo.marker("1");
+ verify.currentLineContentIs(" /* when current checkbox has focus, Firefox has changed check state already");
+ goTo.marker("2");
+ verify.currentLineContentIs(" on SPACE bar press only");
+ goTo.marker("3");
+ verify.currentLineContentIs(" IE does not have issue, use the CSS class");
+ goTo.marker("4");
+ verify.currentLineContentIs(" input:focus[type=checkbox] (z-index = 31290)");
+ goTo.marker("5");
+ verify.currentLineContentIs(" to determine whether checkbox has focus or not");
+}
+finally {
+ format.setFormatOptions(oldOptions);
+}
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 4091815ce5973..087c43786f0a6 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -49,6 +49,25 @@ module FourSlashInterface {
position: number;
data?: any;
}
+
+ export interface EditorOptions {
+ IndentSize: number;
+ TabSize: number;
+ NewLineCharacter: string;
+ ConvertTabsToSpaces: boolean;
+ }
+
+ export interface FormatCodeOptions extends EditorOptions {
+ InsertSpaceAfterCommaDelimiter: boolean;
+ InsertSpaceAfterSemicolonInForStatements: boolean;
+ InsertSpaceBeforeAndAfterBinaryOperators: boolean;
+ InsertSpaceAfterKeywordsInControlFlowStatements: boolean;
+ InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean;
+ InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean;
+ PlaceOpenBraceOnNewLineForFunctions: boolean;
+ PlaceOpenBraceOnNewLineForControlBlocks: boolean;
+ [s: string]: boolean | number| string;
+ }
export interface Range {
fileName: string;
@@ -541,6 +560,14 @@ module FourSlashInterface {
FourSlash.currentTestState.formatDocument();
}
+ public copyFormatOptions(): FormatCodeOptions {
+ return FourSlash.currentTestState.copyFormatOptions();
+ }
+
+ public setFormatOptions(options: FormatCodeOptions) {
+ return FourSlash.currentTestState.setFormatOptions(options);
+ }
+
public selection(startMarker: string, endMarker: string) {
FourSlash.currentTestState.formatSelection(FourSlash.currentTestState.getMarkerByName(startMarker).position, FourSlash.currentTestState.getMarkerByName(endMarker).position);
}