diff --git a/Commands/HelpContextService.fs b/Commands/HelpContextService.fs index 99bcd091c91..b8f8ac4c4c9 100644 --- a/Commands/HelpContextService.fs +++ b/Commands/HelpContextService.fs @@ -10,6 +10,7 @@ open Microsoft.CodeAnalysis.Classification open Microsoft.VisualStudio.FSharp.LanguageService open Microsoft.VisualStudio.LanguageServices.Implementation.F1Help open Microsoft.CodeAnalysis.Host.Mef +open Microsoft.FSharp.Compiler open Microsoft.FSharp.Compiler.Range open Microsoft.FSharp.Compiler.SourceCodeServices diff --git a/Common/AssemblyInfo.fs b/Common/AssemblyInfo.fs index 27ec6cf2ad3..b876bf86820 100644 --- a/Common/AssemblyInfo.fs +++ b/Common/AssemblyInfo.fs @@ -4,10 +4,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.Shell -[] -[] -[] - [] [] [] diff --git a/Completion/CompletionProvider.fs b/Completion/CompletionProvider.fs index e30c0322b47..b3c7448a0c9 100644 --- a/Completion/CompletionProvider.fs +++ b/Completion/CompletionProvider.fs @@ -55,9 +55,23 @@ type internal FSharpCompletionProvider let xmlMemberIndexService = serviceProvider.GetService(typeof) :?> IVsXMLMemberIndexService let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(xmlMemberIndexService, serviceProvider.DTE) - + static let noCommitOnSpaceRules = - CompletionItemRules.Default.WithCommitCharacterRule(CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, ' ', '=', ',', '.', '<', '>', '(', ')', '!', ':')) + // These are important. They make sure we don't _commit_ autocompletion when people don't expect them to. Some examples: + // + // * type Foo() = + // member val a = 12 with get, <<---- Don't commit autocomplete! + // + // * type MyRecord = { name: <<---- Don't commit autocomplete! + // + // * type My< <<---- Don't commit autocomplete! + // + // * let myClassInstance = MyClass(Date= <<---- Don't commit autocomplete! + // + // * let xs = [1..10] <<---- Don't commit autocomplete! (same for arrays) + let noCommitChars = [|' '; '='; ','; '.'; '<'; '>'; '('; ')'; '!'; ':'; '['; ']'; '|'|].ToImmutableArray() + + CompletionItemRules.Default.WithCommitCharacterRule(CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, noCommitChars)) static let getRules() = if Settings.IntelliSense.ShowAfterCharIsTyped then noCommitOnSpaceRules else CompletionItemRules.Default @@ -100,14 +114,14 @@ type internal FSharpCompletionProvider let caretLine = textLines.GetLineFromPosition(caretPosition) let fcsCaretLineNumber = Line.fromZ caretLinePos.Line // Roslyn line numbers are zero-based, FSharp.Compiler.Service line numbers are 1-based let caretLineColumn = caretLinePos.Character - let qualifyingNames, partialName = QuickParse.GetPartialLongNameEx(caretLine.ToString(), caretLineColumn - 1) + let partialName = QuickParse.GetPartialLongNameEx(caretLine.ToString(), caretLineColumn - 1) let getAllSymbols() = - getAllSymbols() |> List.filter (fun entity -> entity.FullName.Contains "." && not (PrettyNaming.IsOperatorName entity.Symbol.DisplayName)) + getAllSymbols() + |> List.filter (fun entity -> entity.FullName.Contains "." && not (PrettyNaming.IsOperatorName entity.Symbol.DisplayName)) - let! declarations = - checkFileResults.GetDeclarationListInfo(Some(parseResults), fcsCaretLineNumber, caretLineColumn, caretLine.ToString(), qualifyingNames, partialName, getAllSymbols, userOpName=userOpName) |> liftAsync - + let! declarations = checkFileResults.GetDeclarationListInfo(Some(parseResults), fcsCaretLineNumber, caretLine.ToString(), + partialName, getAllSymbols, userOpName=userOpName) |> liftAsync let results = List() let getKindPriority = function @@ -186,7 +200,7 @@ type internal FSharpCompletionProvider declarationItemsCache.Add(completionItem.DisplayText, declItem) results.Add(completionItem)) - if results.Count > 0 && not declarations.IsForType && not declarations.IsError && List.isEmpty qualifyingNames then + if results.Count > 0 && not declarations.IsForType && not declarations.IsError && List.isEmpty partialName.QualifyingIdents then let lineStr = textLines.[caretLinePos.Line].ToString() match UntypedParseImpl.TryGetCompletionContext(Pos.fromZ caretLinePos.Line caretLinePos.Character, Some parseResults, lineStr) with | None -> results.AddRange(keywordCompletionItems) diff --git a/Debugging/LanguageDebugInfoService.fs b/Debugging/LanguageDebugInfoService.fs index 02ccfc1e6e8..432b0431052 100644 --- a/Debugging/LanguageDebugInfoService.fs +++ b/Debugging/LanguageDebugInfoService.fs @@ -14,7 +14,7 @@ open Microsoft.CodeAnalysis.Editor.Implementation.Debugging open Microsoft.CodeAnalysis.Host.Mef open Microsoft.CodeAnalysis.Text -open Microsoft.VisualStudio.FSharp.LanguageService +open Microsoft.FSharp.Compiler [] [, FSharpConstants.FSharpLanguageName)>] diff --git a/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs b/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs index b0b25ca6ead..ace07bf57f2 100644 --- a/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs +++ b/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs @@ -69,11 +69,11 @@ type internal SimplifyNameDiagnosticAnalyzer() = |> Array.Parallel.map (fun symbolUse -> let lineStr = sourceText.Lines.[Line.toZ symbolUse.RangeAlternate.StartLine].ToString() // for `System.DateTime.Now` it returns ([|"System"; "DateTime"|], "Now") - let plid, name = QuickParse.GetPartialLongNameEx(lineStr, symbolUse.RangeAlternate.EndColumn - 1) + let partialName = QuickParse.GetPartialLongNameEx(lineStr, symbolUse.RangeAlternate.EndColumn - 1) // `symbolUse.RangeAlternate.Start` does not point to the start of plid, it points to start of `name`, // so we have to calculate plid's start ourselves. - let plidStartCol = symbolUse.RangeAlternate.EndColumn - name.Length - (getPlidLength plid) - symbolUse, plid, plidStartCol, name) + let plidStartCol = symbolUse.RangeAlternate.EndColumn - partialName.PartialIdent.Length - (getPlidLength partialName.QualifyingIdents) + symbolUse, partialName.QualifyingIdents, plidStartCol, partialName.PartialIdent) |> Array.filter (fun (_, plid, _, name) -> name <> "" && not (List.isEmpty plid)) |> Array.groupBy (fun (symbolUse, _, plidStartCol, _) -> symbolUse.RangeAlternate.StartLine, plidStartCol) |> Array.map (fun (_, xs) -> xs |> Array.maxBy (fun (symbolUse, _, _, _) -> symbolUse.RangeAlternate.EndColumn)) diff --git a/FSharp.Editor.fsproj b/FSharp.Editor.fsproj index 25c8ea30208..5bb2b7d613c 100644 --- a/FSharp.Editor.fsproj +++ b/FSharp.Editor.fsproj @@ -28,6 +28,11 @@ true true + + + + + true diff --git a/LanguageService/Tokenizer.fs b/LanguageService/Tokenizer.fs index 2ef32dd1941..840138c00b3 100644 --- a/LanguageService/Tokenizer.fs +++ b/LanguageService/Tokenizer.fs @@ -532,7 +532,7 @@ module internal Tokenizer = | _ -> false) |> Option.orElseWith (fun _ -> tokensUnderCursor |> List.tryFind (fun { DraftToken.Kind = k } -> k = LexerSymbolKind.Operator)) |> Option.map (fun token -> - let plid, _ = QuickParse.GetPartialLongNameEx(lineStr, token.RightColumn) + let partialName = QuickParse.GetPartialLongNameEx(lineStr, token.RightColumn) let identStr = lineStr.Substring(token.Token.LeftColumn, token.Token.FullMatchedLength) { Kind = token.Kind Ident = @@ -541,7 +541,7 @@ module internal Tokenizer = fileName (Range.mkPos (linePos.Line + 1) token.Token.LeftColumn) (Range.mkPos (linePos.Line + 1) (token.RightColumn + 1))) - FullIsland = plid @ [identStr] }) + FullIsland = partialName.QualifyingIdents @ [identStr] }) let private getCachedSourceLineData(documentKey: DocumentId, sourceText: SourceText, position: int, fileName: string, defines: string list) = let textLine = sourceText.Lines.GetLineFromPosition(position) diff --git a/Options/EditorOptions.fs b/Options/EditorOptions.fs index faf5230a7cd..0f4409a99d1 100644 --- a/Options/EditorOptions.fs +++ b/Options/EditorOptions.fs @@ -13,7 +13,7 @@ module DefaultTuning = let UnusedDeclarationsAnalyzerInitialDelay = 0 (* 1000 *) (* milliseconds *) let UnusedOpensAnalyzerInitialDelay = 0 (* 2000 *) (* milliseconds *) let SimplifyNameInitialDelay = 2000 (* milliseconds *) - let SimplifyNameEachItemDelay = 5 (* milliseconds *) + let SimplifyNameEachItemDelay = 0 (* milliseconds *) // CLIMutable to make the record work also as a view model []