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());
+
+