diff --git a/src/services/services.ts b/src/services/services.ts
index 8d233811c8151..8b20cdbe8ed3b 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2498,25 +2498,48 @@ module ts {
}
function isInStringOrRegularExpressionLiteral(previousToken: Node): boolean {
- if (previousToken.kind === SyntaxKind.StringLiteral) {
+ if (previousToken.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(previousToken.kind)) {
// The position has to be either: 1. entirely within the token text, or
// 2. at the end position, and the string literal is not terminated
+
var start = previousToken.getStart();
var end = previousToken.getEnd();
+
if (start < position && position < end) {
return true;
}
else if (position === end) {
var width = end - start;
var text = previousToken.getSourceFile().text;
- return width <= 1 ||
- text.charCodeAt(start) !== text.charCodeAt(end - 1) ||
- text.charCodeAt(end - 2) === CharacterCodes.backslash;
+
+ // If the token is a single character, or its second-to-last charcter indicates an escape code,
+ // then we can immediately say that we are in the middle of an unclosed string.
+ if (width <= 1 || text.charCodeAt(end - 2) === CharacterCodes.backslash) {
+ return true;
+ }
+
+ // Now check if the last character is a closing character for the token.
+ switch (previousToken.kind) {
+ case SyntaxKind.StringLiteral:
+ case SyntaxKind.NoSubstitutionTemplateLiteral:
+ return text.charCodeAt(start) !== text.charCodeAt(end - 1);
+
+ case SyntaxKind.TemplateHead:
+ case SyntaxKind.TemplateMiddle:
+ return text.charCodeAt(end - 1) !== CharacterCodes.openBrace
+ || text.charCodeAt(end - 2) !== CharacterCodes.$;
+
+ case SyntaxKind.TemplateTail:
+ return text.charCodeAt(end - 1) !== CharacterCodes.backtick;
+ }
+
+ return false;
}
}
else if (previousToken.kind === SyntaxKind.RegularExpressionLiteral) {
return previousToken.getStart() < position && position < previousToken.getEnd();
}
+
return false;
}
diff --git a/tests/cases/fourslash/completionListInTemplateLiteralParts1.ts b/tests/cases/fourslash/completionListInTemplateLiteralParts1.ts
new file mode 100644
index 0000000000000..a71584bdbdd2f
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTemplateLiteralParts1.ts
@@ -0,0 +1,11 @@
+///
+
+/////*0*/` $ { ${/*1*/ 10/*2*/ + 1.1/*3*/ /*4*/} 12312`/*5*/
+////
+/////*6*/`asdasd${/*7*/ 2 + 1.1 /*8*/} 12312 {
+
+test.markers().forEach(marker => {
+ goTo.position(marker.position);
+
+ verify.completionListItemsCountIsGreaterThan(0)
+}}
\ No newline at end of file
diff --git a/tests/cases/fourslash/completionListInTemplateLiteralPartsNegatives1.ts b/tests/cases/fourslash/completionListInTemplateLiteralPartsNegatives1.ts
new file mode 100644
index 0000000000000..1624192057b3f
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTemplateLiteralPartsNegatives1.ts
@@ -0,0 +1,11 @@
+///
+
+////`/*0*/ /*1*/$ /*2*/{ /*3*/$/*4*/{ 10 + 1.1 }/*5*/ 12312/*6*/`
+////
+////`asdasd$/*7*/{ 2 + 1.1 }/*8*/ 12312 /*9*/{/*10*/
+
+test.markers().forEach(marker => {
+ goTo.position(marker.position);
+
+ verify.completionListIsEmpty()
+}
\ No newline at end of file