From 4ac7f88808f3958e1447782147b679aab69a6994 Mon Sep 17 00:00:00 2001 From: cartermp Date: Mon, 10 Oct 2022 10:34:54 -0700 Subject: [PATCH] Add codefix to convert C# using to F# open --- .../CodeFix/ConvertCSharpUsingToFSharpOpen.fs | 88 +++++++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/FSharp.Editor.resx | 3 + .../FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.de.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.es.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.it.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 5 ++ .../FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 5 ++ .../xlf/FSharp.Editor.zh-Hans.xlf | 5 ++ .../xlf/FSharp.Editor.zh-Hant.xlf | 5 ++ 16 files changed, 157 insertions(+) create mode 100644 vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpUsingToFSharpOpen.fs diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpUsingToFSharpOpen.fs b/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpUsingToFSharpOpen.fs new file mode 100644 index 0000000000..b0ba2163eb --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpUsingToFSharpOpen.fs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Composition +open System.Collections.Immutable + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.CodeFixes + +[] +type internal FSharpConvertCSharpUsingToFSharpOpen + [] + ( + ) = + inherit CodeFixProvider() + + let fixableDiagnosticIds = set ["FS0039"; "FS0201"] + let usingLength = "using".Length + + let isCSharpUsingShapeWithPos (context: CodeFixContext) (sourceText: SourceText) = + // Walk back until whitespace + let mutable pos = context.Span.Start - 1 + let mutable ch = sourceText.[pos] + while pos > 0 && not(Char.IsWhiteSpace(ch)) do + pos <- pos - 1 + ch <- sourceText.[pos] + + // Walk back whitespace + ch <- sourceText.[pos] + while pos > 0 && Char.IsWhiteSpace(ch) do + pos <- pos - 1 + ch <- sourceText.[pos] + + // Take 'using' slice and don't forget that offset because computer math is annoying + let start = pos - usingLength + 1 + let span = TextSpan(start, usingLength) + let slice = sourceText.GetSubText(span).ToString() + struct(slice = "using", start) + + let registerCodeFix (context: CodeFixContext) (diagnostics: ImmutableArray) (str: string) (span: TextSpan) = + let replacement = + let str = str.Replace("using", "open").Replace(";", "") + TextChange(span, str) + let title = SR.ConvertCSharpUsingToFSharpOpen() + let codeFix = + CodeFixHelpers.createTextChangeCodeFix( + title, + context, + (fun () -> asyncMaybe.Return [| replacement |])) + context.RegisterCodeFix(codeFix, diagnostics) + + override _.FixableDiagnosticIds = Seq.toImmutableArray fixableDiagnosticIds + + override _.RegisterCodeFixesAsync context = + asyncMaybe { + let diagnostics = + context.Diagnostics + |> Seq.filter (fun x -> fixableDiagnosticIds |> Set.contains x.Id) + |> Seq.toImmutableArray + + do! Option.guard(diagnostics.Length > 0) + + let! sourceText = context.Document.GetTextAsync(context.CancellationToken) + + // TODO: handle single-line case? + let statementWithSemicolonSpan = TextSpan(context.Span.Start, context.Span.Length + 1) + + do! Option.guard (sourceText.Length >= statementWithSemicolonSpan.End) + + let statementWithSemicolon = sourceText.GetSubText(statementWithSemicolonSpan).ToString() + + // Top of the file case -- entire line gets a diagnostic + if (statementWithSemicolon.StartsWith("using") && statementWithSemicolon.EndsWith(";")) then + registerCodeFix context diagnostics statementWithSemicolon statementWithSemicolonSpan + else + // Only the identifier being opened has a diagnostic, so we try to find the rest of the statement + let struct(isCSharpUsingShape, start) = isCSharpUsingShapeWithPos context sourceText + if isCSharpUsingShape then + let len = (context.Span.Start - start) + statementWithSemicolonSpan.Length + let fullSpan = TextSpan(start, len) + let str = sourceText.GetSubText(fullSpan).ToString() + registerCodeFix context diagnostics str fullSpan + } + |> Async.Ignore + |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 7021d1ae15..e3e4161836 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -95,6 +95,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 3e21fdd382..08d03219e0 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -291,4 +291,7 @@ Use triple quoted string interpolation. + + Convert C# 'using' to F# 'open' + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 06b2b49c48..663d54cd9c 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -27,6 +27,11 @@ Přidat anotaci typu + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Převést na anonymní záznam diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index 5f40d90c5c..98dea346d6 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -27,6 +27,11 @@ Typanmerkung hinzufügen + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record In anonymen Datensatz konvertieren diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 0785ddb6cd..7297f74d97 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -27,6 +27,11 @@ Agregar una anotación de tipo + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Convertir en registro anónimo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 987ba62cb9..89d59c5eb5 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -27,6 +27,11 @@ Ajouter une annotation de type + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Convertir en enregistrement anonyme diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index f98f73723c..4fdb51134a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -27,6 +27,11 @@ Aggiungere l'annotazione di tipo + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Converti in record anonimo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 9f2a57db53..1133171f8d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -27,6 +27,11 @@ 型の注釈の追加 + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record 匿名レコードに変換 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index fec27e0321..e36b4d4326 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -27,6 +27,11 @@ 형식 주석 추가 + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record 익명 레코드로 변환 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index b34a4b8643..7ccebad7b7 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -27,6 +27,11 @@ Dodaj adnotację typu + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Konwertuj na rekord anonimowy diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index 1b4cd66465..ed9a1be25d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -27,6 +27,11 @@ Adicionar uma anotação de tipo + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Converter em Registro Anônimo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 9fd0ef4bc6..2637d84c8d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -27,6 +27,11 @@ Добавить заметку типа + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Преобразовать в анонимную запись diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index 6c13e57124..e366fe6936 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -27,6 +27,11 @@ Tür ek açıklaması ekle + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record Anonim Kayda Dönüştür diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index c0a0e2ec55..2454379884 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -27,6 +27,11 @@ 添加类型注释 + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record 转换为匿名记录 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 487c5ea22c..5baec12654 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -27,6 +27,11 @@ 新增型別註解 + + Convert C# 'using' to F# 'open' + Convert C# 'using' to F# 'open' + + Convert to Anonymous Record 轉換為匿名記錄