From 9dbef6d971125e043304944b4b89c78ec99209c6 Mon Sep 17 00:00:00 2001 From: Sara Itani Date: Wed, 16 Sep 2015 08:49:31 -0700 Subject: [PATCH 1/3] #462 completions should not be displayed after funciton, let, const keywords - ignore additional keywords when providing completions and update unit tests --- .../Nodejs/Intellisense/VsProjectAnalyzer.cs | 31 ++++++------ Nodejs/Tests/Core.UI/BasicIntellisense.cs | 49 ++++++++++--------- 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs b/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs index 9e5d62882..34f0cf82f 100644 --- a/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs +++ b/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs @@ -91,6 +91,9 @@ sealed partial class VsProjectAnalyzer : IDisposable { private readonly TaskProvider _defaultTaskProvider = CreateDefaultTaskProvider(); + internal static readonly string[] _emptyCompletionContextKeywords = new string[] { + "var", "function", "const", "let" + }; #if FALSE private readonly UnresolvedImportSquiggleProvider _unresolvedSquiggles; #endif @@ -154,12 +157,12 @@ private void CreateNewAnalyzer(AnalysisLimits limits) { _analysisQueue = new AnalysisQueue(this); } _fullyLoaded = true; + } + + private bool ShouldEnqueue() { + return _analysisLevel != AnalysisLevel.None && _analysisLevel != AnalysisLevel.Preview; } - private bool ShouldEnqueue() { - return _analysisLevel != AnalysisLevel.None && _analysisLevel != AnalysisLevel.Preview; - } - #region Public API public bool SaveToDisk { @@ -257,7 +260,7 @@ public void RemoveBuffer(ITextBuffer buffer) { } BufferParser bufferParser; - if (!buffer.Properties.TryGetProperty(typeof(BufferParser), out bufferParser)) { + if (!buffer.Properties.TryGetProperty(typeof(BufferParser), out bufferParser)) { return; } @@ -322,8 +325,8 @@ private void AnalyzeFile(string path, bool reportErrors, ProjectItem originating } else { if (!reportErrors) { TaskProvider.Clear(item.Entry, ParserTaskMoniker); - } - + } + if ((_reparseDateTime != null && new FileInfo(path).LastWriteTime > _reparseDateTime.Value) || (reportErrors && !item.ReportErrors) || (item.Entry.Module == null || item.Entry.Unit == null)) { @@ -1207,19 +1210,19 @@ private static CompletionAnalysis TrySpecialCompletions(ITextSnapshot snapshot, if (tokens.Count > 0) { // Check for context-sensitive intellisense var lastClass = tokens[tokens.Count - 1]; - if (lastClass.ClassificationType == classifier.Provider.Comment || lastClass.ClassificationType == classifier.Provider.StringLiteral || - (lastClass.ClassificationType == classifier.Provider.Keyword && lastClass.Span.GetText() == "var")) { - // No completions in comments, strings, or directly after "var" keywords. + (lastClass.ClassificationType == classifier.Provider.Keyword && + _emptyCompletionContextKeywords.Contains(lastClass.Span.GetText()))) { + // No completions in comments, strings, or directly after certain keywords. return CompletionAnalysis.EmptyCompletionContext; } return null; } return null; - } - + } + private static CompletionAnalysis GetNormalCompletionContext(ITextSnapshot snapshot, ITrackingSpan applicableSpan, ITrackingPoint point) { var span = applicableSpan.GetSpan(snapshot); @@ -1287,8 +1290,8 @@ private void OnErrorRemoved(string path) { private void ClearParserTasks(IProjectEntry entry) { if (entry != null) { - TaskProvider.Clear(entry, ParserTaskMoniker); - + TaskProvider.Clear(entry, ParserTaskMoniker); + bool changed; lock (_hasParseErrors) { changed = _hasParseErrors.Remove(entry); diff --git a/Nodejs/Tests/Core.UI/BasicIntellisense.cs b/Nodejs/Tests/Core.UI/BasicIntellisense.cs index c9f126369..f8d0977b6 100644 --- a/Nodejs/Tests/Core.UI/BasicIntellisense.cs +++ b/Nodejs/Tests/Core.UI/BasicIntellisense.cs @@ -23,6 +23,7 @@ using TestUtilities; using TestUtilities.UI; using Key = System.Windows.Input.Key; +using Microsoft.NodejsTools.Intellisense; namespace Microsoft.Nodejs.Tests.UI { [TestClass] @@ -272,29 +273,31 @@ public void IntellisenseAfterMultiLineComment() { /// [TestMethod, Priority(0), TestCategory("Core")] [HostType("VSTestHost")] - public void IntellisenseAfterVarKeyword() { - var project = Project("IntellisenseAfterVarKeywordTest", - Compile("server", "var c \r\nexports.var = 3; exports.var ") - ); - - using (var solution = project.Generate().ToVs()) { - var server = solution.OpenItem("IntellisenseAfterVarKeywordTest", "server.js"); - - server.MoveCaret(1, 4); - Keyboard.Type(Keyboard.CtrlSpace.ToString()); - using (var sh = server.WaitForSession(true)) { } - - server.MoveCaret(1, 6); - Keyboard.Type(Keyboard.CtrlSpace.ToString()); - server.AssertNoIntellisenseSession(); - - server.MoveCaret(1, 7); - Keyboard.Type(Keyboard.CtrlSpace.ToString()); - using (var sh = server.WaitForSession(true)) { } - - server.MoveCaret(2, 30); - Keyboard.Type(Keyboard.CtrlSpace.ToString()); - using (var sh = server.WaitForSession(true)) { } + public void IntellisenseAfterEmptyCompletionContextKeywords() { + foreach (var keyword in VsProjectAnalyzer._emptyCompletionContextKeywords) { + var project = Project("IntellisenseAfterEmptyCompletionContextKeywordTest", + Compile("server", String.Format("{0} c \r\nexports.{0} = 3; exports.{0} ", keyword)) + ); + + using (var solution = project.Generate().ToVs()) { + var server = solution.OpenItem("IntellisenseAfterEmptyCompletionContextKeywordTest", "server.js"); + + server.MoveCaret(1, keyword.Length + 1); + Keyboard.Type(Keyboard.CtrlSpace.ToString()); + using (var sh = server.WaitForSession(true)) { } + + server.MoveCaret(1, keyword.Length + 3); + Keyboard.Type(Keyboard.CtrlSpace.ToString()); + server.AssertNoIntellisenseSession(); + + server.MoveCaret(1, keyword.Length + 4); + Keyboard.Type(Keyboard.CtrlSpace.ToString()); + using (var sh = server.WaitForSession(true)) { } + + server.MoveCaret(2, keyword.Length*2 + 24); + Keyboard.Type(Keyboard.CtrlSpace.ToString()); + using (var sh = server.WaitForSession(true)) { } + } } } From 3c6000661e1e6a477d3410b611e19a69fff2a0da Mon Sep 17 00:00:00 2001 From: Sara Itani Date: Wed, 16 Sep 2015 09:01:00 -0700 Subject: [PATCH 2/3] sort usings --- Nodejs/Tests/Core.UI/BasicIntellisense.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nodejs/Tests/Core.UI/BasicIntellisense.cs b/Nodejs/Tests/Core.UI/BasicIntellisense.cs index f8d0977b6..17ea0091c 100644 --- a/Nodejs/Tests/Core.UI/BasicIntellisense.cs +++ b/Nodejs/Tests/Core.UI/BasicIntellisense.cs @@ -17,13 +17,13 @@ using System; using System.Linq; using System.Windows; +using Microsoft.NodejsTools.Intellisense; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.Text; using TestUtilities; using TestUtilities.UI; using Key = System.Windows.Input.Key; -using Microsoft.NodejsTools.Intellisense; namespace Microsoft.Nodejs.Tests.UI { [TestClass] From f1cad8575a1f8e7724e07e74c15f38e3b4d2412e Mon Sep 17 00:00:00 2001 From: Sara Itani Date: Wed, 16 Sep 2015 09:07:38 -0700 Subject: [PATCH 3/3] fixed formatting and line endings --- .../Nodejs/Intellisense/VsProjectAnalyzer.cs | 79 ++++++++++--------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs b/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs index 34f0cf82f..956f0bc28 100644 --- a/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs +++ b/Nodejs/Product/Nodejs/Intellisense/VsProjectAnalyzer.cs @@ -91,8 +91,8 @@ sealed partial class VsProjectAnalyzer : IDisposable { private readonly TaskProvider _defaultTaskProvider = CreateDefaultTaskProvider(); - internal static readonly string[] _emptyCompletionContextKeywords = new string[] { - "var", "function", "const", "let" + internal static readonly string[] _emptyCompletionContextKeywords = new string[] { + "var", "function", "const", "let" }; #if FALSE private readonly UnresolvedImportSquiggleProvider _unresolvedSquiggles; @@ -157,10 +157,10 @@ private void CreateNewAnalyzer(AnalysisLimits limits) { _analysisQueue = new AnalysisQueue(this); } _fullyLoaded = true; - } - - private bool ShouldEnqueue() { - return _analysisLevel != AnalysisLevel.None && _analysisLevel != AnalysisLevel.Preview; + } + + private bool ShouldEnqueue() { + return _analysisLevel != AnalysisLevel.None && _analysisLevel != AnalysisLevel.Preview; } #region Public API @@ -260,7 +260,7 @@ public void RemoveBuffer(ITextBuffer buffer) { } BufferParser bufferParser; - if (!buffer.Properties.TryGetProperty(typeof(BufferParser), out bufferParser)) { + if (!buffer.Properties.TryGetProperty(typeof(BufferParser), out bufferParser)) { return; } @@ -325,8 +325,8 @@ private void AnalyzeFile(string path, bool reportErrors, ProjectItem originating } else { if (!reportErrors) { TaskProvider.Clear(item.Entry, ParserTaskMoniker); - } - + } + if ((_reparseDateTime != null && new FileInfo(path).LastWriteTime > _reparseDateTime.Value) || (reportErrors && !item.ReportErrors) || (item.Entry.Module == null || item.Entry.Unit == null)) { @@ -381,21 +381,21 @@ public void AddPackageJson(string packageJsonPath) { AddPackageJson(packageJsonPath, (string)mainFile, dependencyList); } } - } - - private static List GetDependencyListFromJson(Dictionary json, params string[] dependencyTypes) { - var allDependencies = new List(); - foreach (var type in dependencyTypes) { - object dependencies; - json.TryGetValue(type, out dependencies); - var dep = dependencies as Dictionary; - if (dep != null) { - allDependencies.AddRange(dep.Keys.ToList()); - } - } - return allDependencies; - } - + } + + private static List GetDependencyListFromJson(Dictionary json, params string[] dependencyTypes) { + var allDependencies = new List(); + foreach (var type in dependencyTypes) { + object dependencies; + json.TryGetValue(type, out dependencies); + var dep = dependencies as Dictionary; + if (dep != null) { + allDependencies.AddRange(dep.Keys.ToList()); + } + } + return allDependencies; + } + public void AddPackageJson(string path, string mainFile, List dependencies) { if (!_fullyLoaded) { lock (_loadingDeltas) { @@ -1194,22 +1194,23 @@ private static CompletionAnalysis TrySpecialCompletions(ITextSnapshot snapshot, if (range != null) { start = range.Value.Start; } - } - - // Get the classifiers from beginning of the line to the beginning of snapSpan. - // The contents of snapSpan differ depending on what is determined in - // CompletionSource.GetApplicableSpan. - // - // In the case of: - // var myIdentifier - // the applicable span will be "myIdentifier", so GetClassificationSpans will operate on "var " - // - // In the case of comments and string literals, the applicable span will be empty, + } + + // Get the classifiers from beginning of the line to the beginning of snapSpan. + // The contents of snapSpan differ depending on what is determined in + // CompletionSource.GetApplicableSpan. + // + // In the case of: + // var myIdentifier + // the applicable span will be "myIdentifier", so GetClassificationSpans will operate on "var " + // + // In the case of comments and string literals, the applicable span will be empty, // so snapSpan.Start will occur at the current cursor position. var tokens = classifier.GetClassificationSpans(new SnapshotSpan(start.GetContainingLine().Start, snapSpan.Start)); if (tokens.Count > 0) { // Check for context-sensitive intellisense var lastClass = tokens[tokens.Count - 1]; + if (lastClass.ClassificationType == classifier.Provider.Comment || lastClass.ClassificationType == classifier.Provider.StringLiteral || (lastClass.ClassificationType == classifier.Provider.Keyword && @@ -1221,8 +1222,8 @@ private static CompletionAnalysis TrySpecialCompletions(ITextSnapshot snapshot, } return null; - } - + } + private static CompletionAnalysis GetNormalCompletionContext(ITextSnapshot snapshot, ITrackingSpan applicableSpan, ITrackingPoint point) { var span = applicableSpan.GetSpan(snapshot); @@ -1290,8 +1291,8 @@ private void OnErrorRemoved(string path) { private void ClearParserTasks(IProjectEntry entry) { if (entry != null) { - TaskProvider.Clear(entry, ParserTaskMoniker); - + TaskProvider.Clear(entry, ParserTaskMoniker); + bool changed; lock (_hasParseErrors) { changed = _hasParseErrors.Remove(entry);