Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,10 @@ type FSharpScriptOptions =
module FSharpExperimentalFeatures =
let [<Literal>] postfixTemplates = "Enable postfix templates"
let [<Literal>] redundantParenAnalysis = "Enable redundant paren analysis"
let [<Literal>] formatter = "Enable F# code formatter"
let [<Literal>] formatter = "Prefer ReSharper code formatter"
let [<Literal>] fsiInteractiveEditor = "Enable analysis of F# Interactive editor"
let [<Literal>] outOfProcessTypeProviders = "Host type providers out-of-process"
let [<Literal>] generativeTypeProvidersInMemoryAnalysis = "Enable generative type providers analysis in C#/VB.NET projects"
let [<Literal>] tryRecoverFcsProjects = "Try to reuse FCS results on project changes"


[<SettingsKey(typeof<FSharpOptions>, "F# experimental features")>]
Expand All @@ -109,10 +108,7 @@ type FSharpExperimentalFeatures =
mutable OutOfProcessTypeProviders: bool

[<SettingsEntry(true, FSharpExperimentalFeatures.generativeTypeProvidersInMemoryAnalysis); DefaultValue>]
mutable GenerativeTypeProvidersInMemoryAnalysis: bool

[<SettingsEntry(false, FSharpExperimentalFeatures.tryRecoverFcsProjects); DefaultValue>]
mutable TryRecoverFcsProjects: bool }
mutable GenerativeTypeProvidersInMemoryAnalysis: bool }


[<AllowNullLiteral>]
Expand Down Expand Up @@ -148,7 +144,6 @@ type FSharpExperimentalFeaturesProvider(lifetime, solution: ISolution, settings,
member val Formatter = base.GetValueProperty<bool>("Formatter")
member val OutOfProcessTypeProviders = base.GetValueProperty<bool>("OutOfProcessTypeProviders")
member val GenerativeTypeProvidersInMemoryAnalysis = base.GetValueProperty<bool>("GenerativeTypeProvidersInMemoryAnalysis")
member val TryRecoverFcsProjects = base.GetValueProperty<bool>("TryRecoverFcsProjects")


[<SolutionInstanceComponent(Instantiation.DemandAnyThreadSafe)>]
Expand Down Expand Up @@ -227,11 +222,11 @@ type FSharpOptionsPage(lifetime: Lifetime, optionsPageContext, settings,

this.AddBoolOptionWithComment((fun key -> key.NonFSharpProjectInMemoryReferences), nonFSharpProjectInMemoryReferences, "Requires restart") |> ignore

this.AddHeader("Experimental features")
this.AddBoolOption((fun key -> key.Formatter), RichText(FSharpExperimentalFeatures.formatter), null) |> ignore
if configurations.IsInternalMode() then
this.AddHeader("Experimental features")
this.AddBoolOption((fun key -> key.PostfixTemplates), RichText(FSharpExperimentalFeatures.postfixTemplates), null) |> ignore
this.AddBoolOption((fun key -> key.RedundantParensAnalysis), RichText(FSharpExperimentalFeatures.redundantParenAnalysis), null) |> ignore
this.AddBoolOption((fun key -> key.Formatter), RichText(FSharpExperimentalFeatures.formatter), null) |> ignore


[<ShellComponent>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ type ExperimentalFeature =
| PostfixTemplates = 2
| RedundantParenAnalysis = 3
| AssemblyReaderShim = 4
| TryRecoverFcsProjects = 5

type FSharpExperimentalFeatureCookie(feature: ExperimentalFeature) =
static let cookies = OneToListMap<ExperimentalFeature, IDisposable>()
Expand Down Expand Up @@ -51,7 +50,6 @@ type FSharpExperimentalFeatures() =
| ExperimentalFeature.Formatter -> experimentalFeatures.RedundantParensAnalysis.Value
| ExperimentalFeature.PostfixTemplates -> experimentalFeatures.EnablePostfixTemplates.Value
| ExperimentalFeature.RedundantParenAnalysis -> experimentalFeatures.RedundantParensAnalysis.Value
| ExperimentalFeature.TryRecoverFcsProjects -> experimentalFeatures.TryRecoverFcsProjects.Value
| _ -> failwith $"Unexpected feature: {feature}"

[<Extension>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,10 @@ type InterpolatedStringCandidateAnalyzer() =

if anyDisallowedExprs then () else

let formatSpecsAndExprs =
appliedExprs
|> Seq.rev
|> Seq.zip matchingFormatSpecsAndArity
|> Seq.map (fun ((r, _), expr) -> r, expr)
|> List.ofSeq
let exprs = appliedExprs |> Seq.rev |> Array.ofSeq
let formatSpecs = matchingFormatSpecsAndArity |> Seq.map fst
let offsets = formatSpecs |> Seq.map (fun range -> range.EndOffset.Offset - literalExpr.GetDocumentStartOffset().Offset) |> Array.ofSeq
let formatSpecs = formatSpecs |> Seq.map _.GetText() |> Array.ofSeq

InterpolatedStringCandidateWarning(literalExpr, prefixAppExpr, outerPrefixAppExpr, formatSpecsAndExprs)
InterpolatedStringCandidateWarning(literalExpr, prefixAppExpr, outerPrefixAppExpr, formatSpecs, offsets, exprs)
|> consumer.AddHighlighting
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type RecordExprAnalyzer() =

if isNull innerFieldBinding.Expression then ()
elif not (innerFieldBinding.ReferenceName.Reference.GetFcsSymbol() :? FSharpField) then () else
let qualifiedFieldName = qualifiedFieldNameReversed |> List.rev
let qualifiedFieldName = qualifiedFieldNameReversed |> Array.ofList |> Array.rev
consumer.AddHighlighting(NestedRecordUpdateCanBeSimplifiedWarning(outerFieldBinding, innerFieldBinding, qualifiedFieldName))

let rec compareReferenceExprs (x: IReferenceExpr) (y: IReferenceExpr) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Services.Formatter

open JetBrains.Application.Infra
open JetBrains.Application.Parts
open JetBrains.Application.Progress
open JetBrains.Diagnostics
open JetBrains.DocumentModel
open JetBrains.DocumentModel.Impl
Expand All @@ -10,6 +11,7 @@ open JetBrains.ProjectModel
open JetBrains.ReSharper.Feature.Services.CodeCleanup
open JetBrains.ReSharper.Plugins.FSharp.Psi
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Resources
open JetBrains.ReSharper.Plugins.FSharp.Settings
open JetBrains.ReSharper.Plugins.FSharp.Util
open JetBrains.ReSharper.Psi
open JetBrains.ReSharper.Psi.CodeStyle
Expand All @@ -25,10 +27,79 @@ type FSharpReformatCode(textControlManager: ITextControlManager) =
"FSharpReformatCode",
CodeCleanupLanguage("F#", 2),
CodeCleanupOptionDescriptor.ReformatGroup,
typeof<Strings>)
typeof<Strings>, displayName = "F#")

let language = FSharpLanguage.Instance

let reformatWithReSharper (sourceFile: IPsiSourceFile) (rangeMarker: IRangeMarker) (profile: CodeCleanupProfile)
(progressIndicator: IProgressIndicator) =
let solution = sourceFile.GetSolution()
let codeFormatProfile = profile.GetSetting(ReformatOptions.CODE_FORMATER_PROFILE_DESCRIPTOR)
let formatter = language.Formatter().NotNull()

sourceFile.GetPsiServices().Transactions.Execute("F# Reformat code", fun () ->
if isNotNull rangeMarker then
CodeFormatterHelper.Format(language, solution, rangeMarker.DocumentRange, codeFormatProfile, true,
false, progressIndicator)
else
formatter.FormatFile(sourceFile.FSharpFile, codeFormatProfile, progressIndicator)
) |> ignore

let reformatWithFantomas (sourceFile: IPsiSourceFile) (rangeMarker: IRangeMarker) =
let fsFile = sourceFile.FSharpFile
if isNull fsFile then () else

match fsFile.ParseTree with
| None -> ()
| Some _ ->

let filePath = sourceFile.GetLocation().FullPath
let document = sourceFile.Document :?> DocumentBase
let text = document.GetText()

let solution = fsFile.GetSolution()
let settingsStore = sourceFile.GetSettingsStoreWithEditorConfig()
let formatter = fsFile.Language.LanguageServiceNotNull().CodeFormatter
let settings = formatter.GetFormatterSettings(solution, sourceFile, settingsStore, false) :?> _
let fantomasHost = solution.GetComponent<FantomasHost>()

let stamp = document.LastModificationStamp
let modificationSide = TextModificationSide.NotSpecified
let newLineText = sourceFile.DetectLineEnding().GetPresentation()
let parsingOptions = fsFile.CheckerService.FcsProjectProvider.GetParsingOptions(sourceFile)

try
if isNotNull rangeMarker then
let range = ofDocumentRange rangeMarker.DocumentRange
let formatted = fantomasHost.FormatSelection(filePath, range, text, settings, parsingOptions, newLineText, settingsStore)
let offset = rangeMarker.DocumentRange.StartOffset.Offset
let oldLength = rangeMarker.DocumentRange.Length
let documentChange = DocumentChange(document, offset, oldLength, formatted, stamp, modificationSide)
use _ = WriteLockCookie.Create()
document.ChangeDocument(documentChange, TimeStamp.NextValue)
sourceFile.GetPsiServices().Files.CommitAllDocuments()
else
let textControl = textControlManager.VisibleTextControls
|> Seq.tryFind (fun c -> c.Document == document && c.Window.IsFocused.Value)
let cursorPosition = textControl |> Option.map (fun c -> c.Caret.Position.Value.ToDocLineColumn())
let formatResult = fantomasHost.FormatDocument(filePath, text, settings, parsingOptions, newLineText, cursorPosition, settingsStore)
let newCursorPosition = formatResult.CursorPosition

document.ReplaceText(document.DocumentRange, formatResult.Code)
sourceFile.GetPsiServices().Files.CommitAllDocuments()

if isNull textControl || isNull newCursorPosition then () else

// move cursor after current document transaction
let moveCursorLifetime = new LifetimeDefinition()
let codeCleanupService = solution.GetComponent<CodeCleanupService>()
codeCleanupService.WholeFileCleanupCompletedAfterSave.Advise(moveCursorLifetime.Lifetime, fun _ ->
moveCursorLifetime.Terminate()
textControl.Value.Caret.MoveTo(docLine newCursorPosition.Row,
docColumn newCursorPosition.Column,
CaretVisualPlacement.Generic))
with _ -> ()

interface IReformatCodeCleanupModule with
member x.Name = Strings.FSharpReformatCode_Name_Reformat_FSharp
member x.LanguageType = language
Expand All @@ -50,64 +121,12 @@ type FSharpReformatCode(textControlManager: ITextControlManager) =
profile.GetSetting(REFORMAT_CODE_DESCRIPTOR)

member x.Process(sourceFile, rangeMarker, profile, progressIndicator, _) =
// let solution = sourceFile.GetSolution()
// let codeFormatProfile = profile.GetSetting(ReformatOptions.CODE_FORMATER_PROFILE_DESCRIPTOR)
//
// sourceFile.GetPsiServices().Transactions.Execute("F# Reformat code", fun () ->
// CodeFormatterHelper.Format(language, solution, rangeMarker.DocumentRange, codeFormatProfile, true,
// false, progressIndicator)
// ) |> ignore

let fsFile = sourceFile.FSharpFile
if isNull fsFile then () else

match fsFile.ParseTree with
| None -> ()
| Some _ ->

let filePath = sourceFile.GetLocation().FullPath
let document = sourceFile.Document :?> DocumentBase
let text = document.GetText()

let solution = fsFile.GetSolution()
let settingsStore = sourceFile.GetSettingsStoreWithEditorConfig()
let formatter = fsFile.Language.LanguageServiceNotNull().CodeFormatter
let settings = formatter.GetFormatterSettings(solution, sourceFile, settingsStore, false) :?> _
let fantomasHost = solution.GetComponent<FantomasHost>()

let stamp = document.LastModificationStamp
let modificationSide = TextModificationSide.NotSpecified
let newLineText = sourceFile.DetectLineEnding().GetPresentation()
let parsingOptions = fsFile.CheckerService.FcsProjectProvider.GetParsingOptions(sourceFile)

try
if isNotNull rangeMarker then
let range = ofDocumentRange rangeMarker.DocumentRange
let formatted = fantomasHost.FormatSelection(filePath, range, text, settings, parsingOptions, newLineText, settingsStore)
let offset = rangeMarker.DocumentRange.StartOffset.Offset
let oldLength = rangeMarker.DocumentRange.Length
let documentChange = DocumentChange(document, offset, oldLength, formatted, stamp, modificationSide)
use _ = WriteLockCookie.Create()
document.ChangeDocument(documentChange, TimeStamp.NextValue)
sourceFile.GetPsiServices().Files.CommitAllDocuments()
else
let textControl = textControlManager.VisibleTextControls
|> Seq.tryFind (fun c -> c.Document == document && c.Window.IsFocused.Value)
let cursorPosition = textControl |> Option.map (fun c -> c.Caret.Position.Value.ToDocLineColumn())
let formatResult = fantomasHost.FormatDocument(filePath, text, settings, parsingOptions, newLineText, cursorPosition, settingsStore)
let newCursorPosition = formatResult.CursorPosition

document.ReplaceText(document.DocumentRange, formatResult.Code)
sourceFile.GetPsiServices().Files.CommitAllDocuments()

if isNull textControl || isNull newCursorPosition then () else

// move cursor after current document transaction
let moveCursorLifetime = new LifetimeDefinition()
let codeCleanupService = solution.GetComponent<CodeCleanupService>()
codeCleanupService.WholeFileCleanupCompletedAfterSave.Advise(moveCursorLifetime.Lifetime, fun _ ->
moveCursorLifetime.Terminate()
textControl.Value.Caret.MoveTo(docLine newCursorPosition.Row,
docColumn newCursorPosition.Column,
CaretVisualPlacement.Generic))
with _ -> ()
let useReSharperFormatter () =
sourceFile
.GetSolution()
.GetSolutionInstanceComponent<FSharpExperimentalFeaturesProvider>().Formatter.Value

if isNotNull rangeMarker || useReSharperFormatter () then
reformatWithReSharper sourceFile rangeMarker profile progressIndicator
else
reformatWithFantomas sourceFile rangeMarker
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.PostfixTemplates

open JetBrains.ReSharper.Feature.Services.BulbActions
open JetBrains.ReSharper.Feature.Services.CodeCompletion.Settings
open JetBrains.ReSharper.Feature.Services.PostfixTemplates
open JetBrains.ReSharper.Feature.Services.PostfixTemplates.Contexts
open JetBrains.ReSharper.Plugins.FSharp.Psi
Expand Down Expand Up @@ -64,6 +66,7 @@ and MatchPostfixTemplateBehavior(info) =
matchExpr :> ITreeNode
)

override x.AfterComplete(textControl, node, _) =
textControl.Caret.MoveTo(node.GetDocumentEndOffset() + 1, CaretVisualPlacement.DontScrollIfVisible)
textControl.RescheduleCompletion(node.GetSolution())
override this.AfterComplete(textControl, node, _) =
let offset = node.GetDocumentEndOffset() + 1
let command = BulbActionCommands.ShowCodeCompletionPopup(offset, FSharpLanguage.Instance, AutopopupType.SoftAutopopup)
this.RunAndForget(command, textControl)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate
open JetBrains.ReSharper.Plugins.FSharp.Psi.Services.Util.ObjExprUtil
open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Psi.ExtensionsAPI
open JetBrains.ReSharper.Psi.Transactions
open JetBrains.ReSharper.Resources.Shell

Expand Down Expand Up @@ -47,5 +46,5 @@ and NewObjPostfixTemplateBehavior(info) =
)

override this.AfterComplete(textControl, node, _) =
let objExpr = node :?> IObjExpr
GenerateOverrides.selectObjExprMemberOrCallCompletion objExpr textControl
let command = GenerateOverrides.selectObjExprMemberOrCallCompletion (downcast node)
this.RunAndForget(command, textControl)
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.PostfixTemplates

open JetBrains.Application.Parts
open JetBrains.Application.Settings
open JetBrains.Diagnostics
open JetBrains.DocumentModel
open JetBrains.ProjectModel
open JetBrains.ReSharper.Feature.Services.BulbActions
open JetBrains.ReSharper.Feature.Services.CodeCompletion.PostfixTemplates
open JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots
open JetBrains.ReSharper.Feature.Services.LiveTemplates.LiveTemplates
Expand Down Expand Up @@ -291,6 +291,9 @@ type FSharpPostfixTemplateBehaviorBase(info) =
let node = context.Expression :?> IFSharpTreeNode
FSharpPostfixTemplates.removeTemplateAndGetParentExpression node

member this.RunAndForget(command: IBulbActionCommand, textControl) =
command.RunAndForget(info.ExecutionContext.Solution, textControl, info.Text)


[<AbstractClass>]
type FSharpPostfixTemplateBase() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.PostfixTemplates

open JetBrains.Application.Threading
open JetBrains.ProjectModel
open JetBrains.ReSharper.Feature.Services.BulbActions
open JetBrains.ReSharper.Feature.Services.CodeCompletion.Settings
open JetBrains.ReSharper.Feature.Services.Navigation.CustomHighlighting
open JetBrains.ReSharper.Feature.Services.PostfixTemplates
open JetBrains.ReSharper.Feature.Services.PostfixTemplates.Contexts
open JetBrains.ReSharper.Feature.Services.Refactorings.WorkflowOccurrences
open JetBrains.ReSharper.Plugins.FSharp.Psi
open JetBrains.ReSharper.Plugins.FSharp.Psi.Services.Util.FSharpCompletionUtil
open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Plugins.FSharp.Psi.Util
open JetBrains.ReSharper.Plugins.FSharp.Util
Expand All @@ -16,7 +17,6 @@ open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree
open JetBrains.ReSharper.Psi.Transactions
open JetBrains.ReSharper.Psi.Tree
open JetBrains.ReSharper.Resources.Shell
open JetBrains.TextControl
open JetBrains.UI.RichText

module WithPostfixTemplate =
Expand Down Expand Up @@ -152,6 +152,8 @@ and WithPostfixTemplateBehavior(info) =

let innermostExpr = WithPostfixTemplate.getInnermostRecordExpr recordExpr
let range = innermostExpr.GetDocumentRange()
textControl.Caret.MoveTo(range.EndOffset - 2, CaretVisualPlacement.DontScrollIfVisible)
textControl.RescheduleCompletion(solution)

let offset = range.EndOffset - 2
let command = BulbActionCommands.ShowCodeCompletionPopup(offset, FSharpLanguage.Instance, AutopopupType.SoftAutopopup)
x.RunAndForget(command, textControl)
) |> ignore
Loading
Loading