diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92eb646f480..5de2bd87e63 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ Your pull request should: * Tests should include reasonable permutations of the target fix/change * Include baseline changes with your change * All changed code must have 100% code coverage -* Follow the code conventions descriped in [Coding guidlines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidlines) +* Follow the code conventions descriped in [Coding guidelines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines) * To avoid line ending issues, set `autocrlf = input` and `whitespace = cr-at-eol` in your git configuration ## Running the Tests diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index bde4cec3f3f..d6cf4c1a141 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5299,7 +5299,7 @@ module ts { break; } - let range = { pos: triviaScanner.getTokenPos(), end: triviaScanner.getTextPos() }; + let range = { pos: triviaScanner.getTokenPos(), end: triviaScanner.getTextPos(), kind: triviaScanner.getToken() }; let comment = sourceText.substring(range.pos, range.end); let referencePathMatchResult = getFileReferenceFromReferencePath(comment, range); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 3a208698c25..a568667d182 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -523,6 +523,7 @@ module ts { let nextChar = text.charCodeAt(pos + 1); let hasTrailingNewLine = false; if (nextChar === CharacterCodes.slash || nextChar === CharacterCodes.asterisk) { + let kind = nextChar === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia : SyntaxKind.MultiLineCommentTrivia; let startPos = pos; pos += 2; if (nextChar === CharacterCodes.slash) { @@ -548,7 +549,7 @@ module ts { result = []; } - result.push({ pos: startPos, end: pos, hasTrailingNewLine: hasTrailingNewLine }); + result.push({ pos: startPos, end: pos, hasTrailingNewLine, kind }); } continue; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 74777057963..34eb86440f4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -985,6 +985,7 @@ module ts { export interface CommentRange extends TextRange { hasTrailingNewLine?: boolean; + kind: SyntaxKind; } // Source files are declarations when they are external modules. diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index 4c9dcedc7a4..13ed3d3ea69 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -1,18 +1,3 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - module ts { export module OutliningElementsCollector { export function collectElements(sourceFile: SourceFile): OutliningSpan[] { @@ -31,6 +16,66 @@ module ts { } } + function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) { + if (commentSpan) { + let span: OutliningSpan = { + textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + bannerText: collapseText, + autoCollapse: autoCollapse + }; + elements.push(span); + } + } + + function addOutliningForLeadingCommentsForNode(n: Node) { + let comments = ts.getLeadingCommentRangesOfNode(n, sourceFile); + + if (comments) { + let firstSingleLineCommentStart = -1; + let lastSingleLineCommentEnd = -1; + let isFirstSingleLineComment = true; + let singleLineCommentCount = 0; + + for (let currentComment of comments) { + + // For single line comments, combine consecutive ones (2 or more) into + // a single span from the start of the first till the end of the last + if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) { + if (isFirstSingleLineComment) { + firstSingleLineCommentStart = currentComment.pos; + } + isFirstSingleLineComment = false; + lastSingleLineCommentEnd = currentComment.end; + singleLineCommentCount++; + } + else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) { + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + addOutliningSpanComments(currentComment, /*autoCollapse*/ false); + + singleLineCommentCount = 0; + lastSingleLineCommentEnd = -1; + isFirstSingleLineComment = true; + } + } + + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + } + } + + function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) { + // Only outline spans of two or more consecutive single line comments + if (count > 1) { + let multipleSingleLineComments = { + pos: start, + end: end, + kind: SyntaxKind.SingleLineCommentTrivia + } + + addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false); + } + } + function autoCollapse(node: Node) { return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction; } @@ -41,6 +86,11 @@ module ts { if (depth > maxDepth) { return; } + + if (isDeclaration(n)) { + addOutliningForLeadingCommentsForNode(n); + } + switch (n.kind) { case SyntaxKind.Block: if (!isFunctionBlock(n)) { @@ -93,7 +143,7 @@ module ts { }); break; } - // Fallthrough. + // Fallthrough. case SyntaxKind.ModuleBlock: { let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); diff --git a/tests/cases/fourslash/getOutliningForBlockComments.ts b/tests/cases/fourslash/getOutliningForBlockComments.ts new file mode 100644 index 00000000000..66838d0db75 --- /dev/null +++ b/tests/cases/fourslash/getOutliningForBlockComments.ts @@ -0,0 +1,105 @@ +/// + +////[|/* +//// Block comment at the beginning of the file before module: +//// line one of the comment +//// line two of the comment +//// line three +//// line four +//// line five +////*/|] +////module Sayings[| { +//// [|/* +//// Comment before class: +//// line one of the comment +//// line two of the comment +//// line three +//// line four +//// line five +//// */|] +//// export class Greeter[| { +//// [|/* +//// Comment before a string identifier +//// line two of the comment +//// */|] +//// greeting: string; +//// [|/* +//// constructor +//// parameter message as a string +//// */|] +//// +//// [|/* +//// Multiple comments should be collapsed individually +//// */|] +//// constructor(message: string /* do not collapse this */)[| { +//// this.greeting = message; +//// }|] +//// [|/* +//// method of a class +//// */|] +//// greet()[| { +//// return "Hello, " + this.greeting; +//// }|] +//// }|] +////}|] +//// +////[|/* +//// Block comment for interface. The ending can be on the same line as the declaration. +////*/|]interface IFoo[| { +//// [|/* +//// Multiple block comments +//// */|] +//// +//// [|/* +//// should be collapsed +//// */|] +//// +//// [|/* +//// individually +//// */|] +//// +//// [|/* +//// this comment has trailing space before /* and after *-/ signs +//// */|] +//// +//// [|/** +//// * +//// * +//// * +//// */|] +//// +//// [|/* +//// */|] +//// +//// [|/* +//// */|] +//// // single line comments in the middle should not have an effect +//// [|/* +//// */|] +//// +//// [|/* +//// */|] +//// +//// [|/* +//// this block comment ends +//// on the same line */|] [|/* where the following comment starts +//// should be collapsed separately +//// */|] +//// +//// getDist(): number; +////}|] +//// +////var x =[|{ +//// a:1, +//// b: 2, +//// [|/* +//// Over a function in an object literal +//// */|] +//// get foo()[| { +//// return 1; +//// }|] +////}|] + +verify.outliningSpansInCurrentFile(test.ranges()); + + diff --git a/tests/cases/fourslash/getOutliningForSingleLineComments.ts b/tests/cases/fourslash/getOutliningForSingleLineComments.ts new file mode 100644 index 00000000000..903b1c55494 --- /dev/null +++ b/tests/cases/fourslash/getOutliningForSingleLineComments.ts @@ -0,0 +1,78 @@ +/// + +////[|// Single line comments at the start of the file +////// line 2 +////// line 3 +////// line 4|] +////module Sayings[| { +//// +//// [|/* +//// */|] +//// [|// A sequence of +//// // single line|] +//// [|/* +//// and block +//// */|] +//// [|// comments +//// //|] +//// export class Sample[| { +//// }|] +////}|] +//// +////interface IFoo[| { +//// [|// all consecutive single line comments should be in one block regardless of their number or empty lines/spaces inbetween +//// +//// // comment 2 +//// // comment 3 +//// +//// //comment 4 +//// /// comment 5 +//// ///// comment 6 +//// +//// //comment 7 +//// ///comment 8 +//// // comment 9 +//// // //comment 10 +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// +//// // // //comment 11 +//// // comment 12 +//// // comment 13 +//// // comment 14 +//// // comment 15 +//// +//// // comment 16 +//// // comment 17 +//// // comment 18 +//// // comment 19 +//// // comment 20 +//// // comment 21|] +//// +//// getDist(): number; // One single line comment should not be collapsed +////}|] +//// +////// One single line comment should not be collapsed +////class WithOneSingleLineComment[| { +////}|] + +verify.outliningSpansInCurrentFile(test.ranges()); + +