indent block comments according to first line

This commit is contained in:
Arthur Ozga 2017-06-08 17:08:07 -07:00
parent a819e4ed17
commit 8f28a0264f
13 changed files with 81 additions and 70 deletions

View File

@ -2427,16 +2427,6 @@ namespace FourSlash {
}
}
public verifyIsInMultiLineComment(negative: boolean) {
const expected = !negative;
const position = this.currentCaretPosition;
const fileName = this.activeFile.fileName;
const actual = this.languageService.getIsInMultiLineComment(fileName, position);
if (expected !== actual) {
this.raiseError(`verifyIsInDocComment failed: at position '${position}' in '${fileName}', expected '${expected}'.`);
}
}
private clarifyNewlines(str: string) {
return str.replace(/\r?\n/g, lineEnding => {
const representation = lineEnding === "\r\n" ? "CRLF" : "LF";
@ -2510,6 +2500,16 @@ namespace FourSlash {
}
}
public verifyisInMultiLineCommentAtPosition(negative: boolean) {
const expected = !negative;
const position = this.currentCaretPosition;
const fileName = this.activeFile.fileName;
const actual = this.languageService.getisInMultiLineCommentAtPosition(fileName, position);
if (expected !== actual) {
this.raiseError(`verifyIsInDocComment failed: at position '${position}' in '${fileName}', expected '${expected}'.`);
}
}
/*
Check number of navigationItems which match both searchValue and matchKind,
if a filename is passed in, limit the results to that file.
@ -3583,12 +3583,12 @@ namespace FourSlashInterface {
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
}
public codeFixAvailable() {
this.state.verifyCodeFixAvailable(this.negative);
public isInMultiLineCommentAtPosition() {
this.state.verifyisInMultiLineCommentAtPosition(this.negative);
}
public isInMultiLineComment() {
this.state.verifyIsInMultiLineComment(this.negative);
public codeFixAvailable() {
this.state.verifyCodeFixAvailable(this.negative);
}
public applicableRefactorAvailableAtMarker(markerName: string) {

View File

@ -483,12 +483,12 @@ namespace Harness.LanguageService {
getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion {
return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position));
}
getIsInMultiLineComment(fileName: string, position: number): boolean {
return unwrapJSONCallResult(this.shim.getIsInMultiLineComment(fileName, position));
}
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace));
}
getisInMultiLineCommentAtPosition(fileName: string, position: number): boolean {
return unwrapJSONCallResult(this.shim.getisInMultiLineCommentAtPosition(fileName, position));
}
getCodeFixesAtPosition(): ts.CodeAction[] {
throw new Error("Not supported on the shim.");
}

View File

@ -672,11 +672,11 @@ namespace ts.server {
return notImplemented();
}
getIsInMultiLineComment(_fileName: string, _position: number): boolean {
isValidBraceCompletionAtPosition(_fileName: string, _position: number, _openingBrace: number): boolean {
return notImplemented();
}
isValidBraceCompletionAtPosition(_fileName: string, _position: number, _openingBrace: number): boolean {
getisInMultiLineCommentAtPosition(_fileName: string, _position: number): boolean {
return notImplemented();
}

View File

@ -8,6 +8,7 @@ namespace ts.server.protocol {
/* @internal */
BraceFull = "brace-full",
BraceCompletion = "braceCompletion",
isInMultiLineComment = "isInMultiLineComment",
Change = "change",
Close = "close",
Completions = "completions",
@ -85,7 +86,6 @@ namespace ts.server.protocol {
TodoComments = "todoComments",
Indentation = "indentation",
DocCommentTemplate = "docCommentTemplate",
IsInMultiLineComment = "isInMultiLineComment",
/* @internal */
CompilerOptionsDiagnosticsFull = "compilerOptionsDiagnostics-full",
/* @internal */
@ -242,15 +242,8 @@ namespace ts.server.protocol {
/**
* A request to determine if the caret is inside a multi-line comment.
*/
export interface IsInMultiLineCommentRequest extends FileLocationRequest {
command: CommandTypes.IsInMultiLineComment;
}
/**
* Response for TodoCommentRequest request.
*/
export interface IsInMultiLineCommentResponse extends Response {
body?: { isInMultiLineComment: boolean };
export interface IsInMultiLineCommentAtPositionRequest extends FileLocationRequest {
command: CommandTypes.isInMultiLineComment;
}
/**

View File

@ -961,11 +961,11 @@ namespace ts.server {
return project.getLanguageService(/*ensureSynchronized*/ false).getDocCommentTemplateAtPosition(file, position);
}
private getIsInMultiLineComment(args: protocol.FileLocationRequestArgs) {
private getisInMultiLineCommentAtPosition(args: protocol.FileLocationRequestArgs) {
const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
const position = this.getPosition(args, scriptInfo);
return project.getLanguageService(/*ensureSynchronized*/ false).getIsInMultiLineComment(file, position);
return project.getLanguageService(/*ensureSynchronized*/ false).getisInMultiLineCommentAtPosition(file, position);
}
private getIndentation(args: protocol.IndentationRequestArgs) {
@ -1701,8 +1701,8 @@ namespace ts.server {
[CommandNames.DocCommentTemplate]: (request: protocol.DocCommentTemplateRequest) => {
return this.requiredResponse(this.getDocCommentTemplate(request.arguments));
},
[CommandNames.IsInMultiLineComment]: (request: protocol.IsInMultiLineCommentRequest) => {
return this.requiredResponse(this.getIsInMultiLineComment(request.arguments));
[CommandNames.isInMultiLineComment]: (request: protocol.IsInMultiLineCommentAtPositionRequest) => {
return this.requiredResponse(this.getisInMultiLineCommentAtPosition(request.arguments));
},
[CommandNames.Format]: (request: protocol.FormatRequest) => {
return this.requiredResponse(this.getFormattingEditsForRange(request.arguments));

View File

@ -1117,6 +1117,27 @@ namespace ts.formatting {
}
}
/**
* @returns -1 iff the position is not in a multi-line comment.
*/
export function getIndentationOfEnclosingMultiLineComment(sourceFile: SourceFile, position: number): number {
const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false);
const leadingCommentRanges = getLeadingCommentRangesOfNode(token, sourceFile);
if (leadingCommentRanges) {
loop: for (const range of leadingCommentRanges) {
// We need to extend the range when in an unclosed multi-line comment.
if (range.pos < position && (position < range.end || position === range.end && position === sourceFile.getFullWidth())) {
if (range.kind === SyntaxKind.MultiLineCommentTrivia) {
return range.pos - getLineStartPositionForPosition(range.pos, sourceFile);
}
break loop;
}
}
}
return -1;
}
function getOpenTokenForList(node: Node, list: Node[]) {
switch (node.kind) {
case SyntaxKind.Constructor:

View File

@ -38,12 +38,17 @@ namespace ts.formatting {
// no indentation in string \regex\template literals
const precedingTokenIsLiteral = isStringOrRegularExpressionOrTemplateLiteral(precedingToken.kind);
if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && precedingToken.end > position) {
if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && position < precedingToken.end) {
return 0;
}
const lineAtPosition = sourceFile.getLineAndCharacterOfPosition(position).line;
const indentationOfEnclosingMultiLineComment = getIndentationOfEnclosingMultiLineComment(sourceFile, position);
if (indentationOfEnclosingMultiLineComment !== -1) {
return indentationOfEnclosingMultiLineComment;
}
// indentation is first non-whitespace character in a previous line
// for block indentation, we should look for a line which contains something that's not
// whitespace.

View File

@ -1789,21 +1789,6 @@ namespace ts {
return JsDoc.getDocCommentTemplateAtPosition(getNewLineOrDefaultFromHost(host), syntaxTreeCache.getCurrentSourceFile(fileName), position);
}
function getIsInMultiLineComment(_fileName: string, position: number): boolean {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(_fileName);
const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false);
const leadingCommentRanges = getLeadingCommentRangesOfNode(token, sourceFile);
for (const range of leadingCommentRanges) {
// We need to extend the range when in an unclosed multi-line comment.
if (range.pos < position && (position < range.end || position === range.end && position === sourceFile.getFullWidth())) {
return range.kind === SyntaxKind.MultiLineCommentTrivia;
}
}
return false;
}
function isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
// '<' is currently not supported, figuring out if we're in a Generic Type vs. a comparison is too
// expensive to do during typing scenarios
@ -1833,6 +1818,11 @@ namespace ts {
return true;
}
function getisInMultiLineCommentAtPosition(fileName: string, position: number): boolean {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
return ts.formatting.getIndentationOfEnclosingMultiLineComment(sourceFile, position) !== -1;
}
function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] {
// Note: while getting todo comments seems like a syntactic operation, we actually
// treat it as a semantic operation here. This is because we expect our host to call
@ -2054,8 +2044,8 @@ namespace ts {
getFormattingEditsForDocument,
getFormattingEditsAfterKeystroke,
getDocCommentTemplateAtPosition,
getIsInMultiLineComment,
isValidBraceCompletionAtPosition,
getisInMultiLineCommentAtPosition,
getCodeFixesAtPosition,
getEmitOutput,
getNonBoundSourceFile,

View File

@ -247,11 +247,6 @@ namespace ts {
*/
getDocCommentTemplateAtPosition(fileName: string, position: number): string;
/**
* Returns JSON-encoded value of the type TextInsertion.
*/
getIsInMultiLineComment(fileName: string, position: number): string;
/**
* Returns JSON-encoded boolean to indicate whether we should support brace location
* at the current position.
@ -259,6 +254,11 @@ namespace ts {
*/
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): string;
/**
* Returns JSON-encoded boolean to indicate whether the caret at the current position is in a multi-line comment.
*/
getisInMultiLineCommentAtPosition(fileName: string, position: number): string;
getEmitOutput(fileName: string): string;
getEmitOutputObject(fileName: string): EmitOutput;
}
@ -840,6 +840,14 @@ namespace ts {
);
}
/// GET IS IN MULTI-LINE COMMENT
public getisInMultiLineCommentAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
`getisInMultiLineCommentAtPosition('${fileName}', ${position})`,
() => this.languageService.getisInMultiLineCommentAtPosition(fileName, position)
);
}
/// GET SMART INDENT
public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string {
return this.forwardJSONCall(
@ -940,13 +948,6 @@ namespace ts {
);
}
public getIsInMultiLineComment(fileName: string, position: number): string {
return this.forwardJSONCall(
`getIsInMultiLineComment('${fileName}', ${position})`,
() => this.languageService.getIsInMultiLineComment(fileName, position)
);
}
/// NAVIGATE TO
/** Return a list of symbols that are interesting to navigate to */

View File

@ -257,10 +257,11 @@ namespace ts {
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[];
getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion;
getIsInMultiLineComment(fileName: string, position: number): boolean;
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
getisInMultiLineCommentAtPosition(fileName: string, position: number): boolean;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[];
getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[];
getRefactorCodeActions(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string): CodeAction[] | undefined;

View File

@ -149,8 +149,8 @@ declare namespace FourSlashInterface {
typeDefinitionCountIs(expectedCount: number): void;
implementationListIsEmpty(): void;
isValidBraceCompletionAtPosition(openingBrace?: string): void;
isInMultiLineCommentAtPosition(): void;
codeFixAvailable(): void;
isInMultiLineComment(): void;
applicableRefactorAvailableAtMarker(markerName: string): void;
codeFixDiagnosticsAvailableAtMarkers(markerNames: string[], diagnosticCode?: number): void;
applicableRefactorAvailableForRange(): void;

View File

@ -8,29 +8,29 @@
for (let i = 1; i < 7; ++i) {
goTo.position(i);
verify.isInMultiLineComment();
verify.isInMultiLineCommentAtPosition();
}
for (let i = 0; i < 2; ++i) {
goTo.position(i * 7);
verify.not.isInMultiLineComment();
verify.not.isInMultiLineCommentAtPosition();
}
const jsDocStart = 8;
for (let i = 1; i < 8; ++i) {
goTo.position(jsDocStart + i);
verify.isInMultiLineComment();
verify.isInMultiLineCommentAtPosition();
}
for (let i = 0; i < 2; ++i) {
goTo.position(jsDocStart + i * 8);
verify.not.isInMultiLineComment();
verify.not.isInMultiLineCommentAtPosition();
}
const singleLineCommentStart = 17;
for (let i = 0; i < 5; ++i) {
goTo.position(singleLineCommentStart + i);
verify.not.isInMultiLineComment();
verify.not.isInMultiLineCommentAtPosition();
}

View File

@ -8,5 +8,5 @@
for (let i = 0; i < 4; ++i) {
goTo.marker(`${i}`);
verify.isInMultiLineComment();
verify.isInMultiLineCommentAtPosition();
}