Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
DedSec256 committed Feb 23, 2023
1 parent 520c914 commit 2ad070a
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Fantomas.Core;
using FSharp.Compiler.Text;
using JetBrains.Diagnostics;
using JetBrains.Extension;
using JetBrains.ReSharper.Plugins.FSharp.Fantomas.Protocol;
Expand All @@ -24,6 +26,7 @@ internal static class FantomasCodeFormatter

private static readonly Version Version45 = Version.Parse("4.5");
private static readonly Version Version46 = Version.Parse("4.6");
private static readonly Version Version60 = Version.Parse("6.0");

private static Type GetCodeFormatter() =>
FantomasAssembly
Expand Down Expand Up @@ -100,12 +103,18 @@ private static Type GetFSharpParsingOptions()
return Type.GetType(qualifiedName).NotNull($"{qualifiedName} must exist");
}

private static Type GetFormatConfigType() =>
FantomasAssembly
private static Type GetFormatConfigType()
{
var formatConfig = FantomasAssembly
.GetType($"{FantomasAssemblyName}.FormatConfig")
.NotNull("FormatConfig must exist")
.GetNestedType("FormatConfig")
.NotNull();
.NotNull("FormatConfig must exist");

return CurrentVersion >= Version60
? formatConfig
: formatConfig
.GetNestedType("FormatConfig")
.NotNull();
}

private static readonly Type CodeFormatterType = GetCodeFormatter();
private static readonly Type FSharpParsingOptionsType = GetFSharpParsingOptions();
Expand All @@ -119,8 +128,8 @@ private static readonly ConstructorInfo
CreateFSharpParsingOptions = FSharpParsingOptionsType?.GetConstructors().Single();

private static readonly MethodInfo FormatSelectionMethod = CodeFormatterType.GetMethod("FormatSelectionAsync");
private static readonly MethodInfo FormatDocumentMethod = CodeFormatterType.GetMethod("FormatDocumentAsync");
private static readonly MethodInfo MakeRangeMethod = CodeFormatterType.GetMethod("MakeRange");
private static readonly MethodInfo MakePositionMethod = CodeFormatterType.GetMethod("MakePosition");
private static readonly MethodInfo SourceOriginConstructor = GetSourceOriginStringConstructor();

private static readonly MethodInfo CreateOptionMethod =
Expand Down Expand Up @@ -173,14 +182,41 @@ public static string FormatSelection(RdFantomasFormatSelectionArgs args)
.Result.Replace("\r\n", args.NewLineText);
}

public static string FormatDocument(RdFantomasFormatDocumentArgs args) =>
FSharpAsync.StartAsTask(
FormatDocumentMethod.Invoke(null, GetFormatDocumentOptions(args)) as FSharpAsync<string>,
null, null)
.Result.Replace("\r\n", args.NewLineText);
public static RdFormatResult FormatDocument(RdFantomasFormatDocumentArgs args)
{
var formatDocumentOptions = GetFormatDocumentOptions(args);
var formatDocumentAsync = CodeFormatterType.InvokeMember("FormatDocumentAsync",
BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public, Type.DefaultBinder, null,
formatDocumentOptions);
var formatResult = FSharpAsync.StartAsTask((dynamic)formatDocumentAsync, null, null).Result;

if (CurrentVersion < Version60)
return new RdFormatResult(formatResult.Replace("\r\n", args.NewLineText), null);

var formattedCode = formatResult.Code;
var newCursorPosition = formatResult.Cursor == null
? null
: new RdFcsPos(formatResult.Cursor.Value.Line - 1, formatResult.Cursor.Value.Column);
return new RdFormatResult(formattedCode.Replace("\r\n", args.NewLineText), newCursorPosition);
}

private static object[] GetFormatDocumentOptions(RdFantomasFormatDocumentArgs args)
{
if (CurrentVersion >= Version60)
{
var cursorPosition = args.CursorPosition is { } pos
? MakePositionMethod.Invoke(null, new object[] { pos.Row + 1, pos.Column })
: null;

return new[]
{
args.FileName.EndsWith(".fsi"), // isSignature
args.Source,
cursorPosition,
ConvertToFormatConfig(args.FormatConfig),
};
}

if (CurrentVersion >= FantomasProtocolConstants.Fantomas5Version)
return new[]
{
Expand Down Expand Up @@ -234,6 +270,7 @@ private static object ConvertToFormatConfig(string[] riderFormatConfigValues)

var formatConfig = FSharpValue.MakeRecord(FormatConfigType, formatConfigValues, null);

if (CurrentVersion >= Version60) return formatConfig;
return CurrentVersion >= FantomasProtocolConstants.Fantomas5Version
? CreateOptionMethod.Invoke(null, new[] { formatConfig }) //FSharpOption<FormatConfig>
: formatConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private static string[] GetFormatConfigFields(Unit _) =>
private static string FormatSelection(RdFantomasFormatSelectionArgs args) =>
FantomasCodeFormatter.FormatSelection(args);

private static string FormatDocument(RdFantomasFormatDocumentArgs args) =>
private static RdFormatResult FormatDocument(RdFantomasFormatDocumentArgs args) =>
FantomasCodeFormatter.FormatDocument(args);

protected override void Run(Lifetime lifetime, RdSimpleDispatcher dispatcher) => dispatcher.Run();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ open JetBrains.Application.Infra
open JetBrains.Diagnostics
open JetBrains.DocumentModel
open JetBrains.DocumentModel.Impl
open JetBrains.Lifetimes
open JetBrains.ProjectModel
open JetBrains.ReSharper.Feature.Services.CodeCleanup
open JetBrains.ReSharper.Plugins.FSharp.Psi
open JetBrains.ReSharper.Plugins.FSharp.Util
open JetBrains.ReSharper.Psi
open JetBrains.ReSharper.Psi.Tree
open JetBrains.ReSharper.Psi.Util
open JetBrains.ReSharper.Resources.Shell
open JetBrains.TextControl
open JetBrains.Util.Text
open JetBrains.TextControl.CodeWithMe
open JetBrains.Util.dataStructures.TypedIntrinsics

[<CodeCleanupModule>]
type FSharpReformatCode() =
type FSharpReformatCode(textControlManager: ITextControlManager, codeCleanupService: CodeCleanupService) =
let REFORMAT_CODE_DESCRIPTOR = CodeCleanupOptionDescriptor<bool>(
"FSReformatCode",
CodeCleanupLanguage("F#", 2),
Expand Down Expand Up @@ -64,24 +67,32 @@ type FSharpReformatCode() =
let modificationSide = TextModificationSide.NotSpecified
let newLineText = sourceFile.DetectLineEnding().GetPresentation()
let parsingOptions = fsFile.CheckerService.FcsProjectProvider.GetParsingOptions(sourceFile)
let textControl = textControlManager.LastFocusedTextControlPerClient.ForCurrentClient().NotNull()

let change =
if isNotNull rangeMarker then
try
let range = ofDocumentRange rangeMarker.DocumentRange
let formatted =
fantomasHost.FormatSelection(filePath, range, text, settings, parsingOptions, newLineText)
let offset = rangeMarker.DocumentRange.StartOffset.Offset
let oldLength = rangeMarker.DocumentRange.Length
Some(DocumentChange(document, offset, oldLength, formatted, stamp, modificationSide))
with _ -> None
else
let formatted = fantomasHost.FormatDocument(filePath, text, settings, parsingOptions, newLineText)
Some(DocumentChange(document, 0, text.Length, formatted, stamp, modificationSide))
if isNotNull rangeMarker then
try
let range = ofDocumentRange rangeMarker.DocumentRange
let formatted = fantomasHost.FormatSelection(filePath, range, text, settings, parsingOptions, newLineText)
let offset = rangeMarker.DocumentRange.StartOffset.Offset
let oldLength = rangeMarker.DocumentRange.Length
let documentChange = DocumentChange(document, offset, oldLength, formatted, stamp, modificationSide)
document.ChangeDocument(documentChange, TimeStamp.NextValue)
sourceFile.GetPsiServices().Files.CommitAllDocuments()
with _ -> ()
else
let cursorPosition = textControl.Caret.Position.Value.ToDocLineColumn();
let formatResult = fantomasHost.FormatDocument(filePath, text, settings, parsingOptions, newLineText, cursorPosition)
let newCursorPosition = formatResult.CursorPosition

match change with
| Some(change) ->
use cookie = WriteLockCookie.Create()
document.ChangeDocument(change, TimeStamp.NextValue)
document.ReplaceText(document.DocumentRange, formatResult.Code)
sourceFile.GetPsiServices().Files.CommitAllDocuments()
| _ -> ()

if isNull newCursorPosition then () else

// move cursor after current document transaction
let moveCursorLifetime = new LifetimeDefinition()
codeCleanupService.WholeFileCleanupCompletedAfterSave.Advise(moveCursorLifetime.Lifetime, fun _ ->
moveCursorLifetime.Terminate()
textControl.Caret.MoveTo(Int32<DocLine>.op_Explicit(newCursorPosition.Row),
Int32<DocColumn>.op_Explicit(newCursorPosition.Column),
CaretVisualPlacement.Generic))
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Text
open JetBrains.Application.Settings
open JetBrains.Core
open JetBrains.DocumentModel
open JetBrains.Lifetimes
open JetBrains.ProjectModel
open JetBrains.Rd.Tasks
Expand Down Expand Up @@ -49,6 +50,9 @@ type FantomasHost(solution: ISolution, fantomasFactory: FantomasProcessFactory,
let toRdFcsRange (range: range) =
RdFcsRange(range.FileName, range.StartLine, range.StartColumn, range.EndLine, range.EndColumn)

let toRdFcsPos (caretPosition: DocumentCoords) =
RdFcsPos(int caretPosition.Line, int caretPosition.Column)

let toRdFormatSettings (settings: FSharpFormatSettingsKey) =
[| for field in formatConfigFields ->
let fieldName =
Expand Down Expand Up @@ -79,15 +83,15 @@ type FantomasHost(solution: ISolution, fantomasFactory: FantomasProcessFactory,
connect()
let args =
RdFantomasFormatSelectionArgs(toRdFcsRange range, filePath, source, toRdFormatSettings settings,
toRdFcsParsingOptions options, newLineText)
toRdFcsParsingOptions options, newLineText, null)

connection.Execute(fun () -> connection.ProtocolModel.FormatSelection.Sync(args, RpcTimeouts.Maximal))

member x.FormatDocument(filePath, source, settings, options, newLineText) =
member x.FormatDocument(filePath, source, settings, options, newLineText, cursorPosition: DocumentCoords) =
connect()
let args =
RdFantomasFormatDocumentArgs(filePath, source, toRdFormatSettings settings, toRdFcsParsingOptions options,
newLineText)
newLineText, toRdFcsPos cursorPosition)

connection.Execute(fun () -> connection.ProtocolModel.FormatDocument.Sync(args, RpcTimeouts.Maximal))

Expand Down
13 changes: 12 additions & 1 deletion rider-fsharp/protocol/src/kotlin/model/RdFantomasModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,28 @@ object RdFantomasModel : Root() {
field("endCol", int)
}

private val rdFcsPos = structdef {
field("row", int)
field("column", int)
}

private val rdFormatResult = structdef {
field("code", string)
field("cursorPosition", rdFcsPos.nullable)
}

private val rdFantomasFormatArgs = basestruct {
field("fileName", string)
field("source", string)
field("formatConfig", array(string))
field("parsingOptions", rdFcsParsingOptions)
field("newLineText", string)
field("cursorPosition", rdFcsPos.nullable)
}

init {
call("getFormatConfigFields", void, array(string))
call("formatDocument", structdef("rdFantomasFormatDocumentArgs") extends rdFantomasFormatArgs {}, string)
call("formatDocument", structdef("rdFantomasFormatDocumentArgs") extends rdFantomasFormatArgs {}, rdFormatResult)
call("formatSelection", structdef("rdFantomasFormatSelectionArgs") extends rdFantomasFormatArgs {
field("range", rdFcsRange)
}, string)
Expand Down

0 comments on commit 2ad070a

Please sign in to comment.