Skip to content

Commit

Permalink
Remove support for completion after ;.
Browse files Browse the repository at this point in the history
  • Loading branch information
nojaf committed Mar 28, 2023
1 parent dcb2637 commit 7ff1349
Show file tree
Hide file tree
Showing 10 changed files with 13 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,11 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Psi
open JetBrains.ReSharper.Psi.ExpectedTypes
open JetBrains.ReSharper.Psi.Resources
open JetBrains.ReSharper.Psi.Tree

[<Language(typeof<FSharpLanguage>)>]
type NamedUnionCaseFieldsPatRule() =
inherit ItemsProviderOfSpecificContext<FSharpCodeCompletionContext>()

// Find the parameterOwner `A` in `A()` or `A(a = a; )`
// Filter out the already used fields
let getFieldsFromParametersOwnerPat (parameterPat: IFSharpPattern) (filterFields: Set<string>) =
let parametersOwnerPat = ParametersOwnerPatNavigator.GetByParameter(parameterPat)
if isNull parametersOwnerPat then Array.empty else
// We need to figure out if `A` actually is a UnionCase.
let fcsUnionCase = parametersOwnerPat.ReferenceName.Reference.GetFcsSymbol().As<FSharpUnionCase>()
if isNull fcsUnionCase then Array.empty else

let fieldNames =
fcsUnionCase.Fields
|> Seq.choose (fun field -> if field.IsNameGenerated then None else Some field.Name)
|> Seq.toArray

// Only give auto completion to the fields only when all of them are named.
if fieldNames.Length <> fcsUnionCase.Fields.Count then Array.empty else
if Set.isEmpty filterFields then fieldNames else
fieldNames
|> Array.except filterFields

// The current scope is to have A({caret}) captured.
// A fake identifier will be inserted in the reparseContext.
let getFieldsFromReference (context: FSharpCodeCompletionContext) =
Expand All @@ -54,72 +33,26 @@ type NamedUnionCaseFieldsPatRule() =
let refPat = ReferencePatNavigator.GetByReferenceName(exprRefName)
// I'm assuming that the parent of the fake refPat is a IParenPat for now.
let parentPat = ParenPatNavigator.GetByPattern(refPat)
getFieldsFromParametersOwnerPat parentPat Set.empty

// Assumption: A(a = foo; {caret})
let getFieldsAfterSemicolon (context: FSharpCodeCompletionContext) =
let (|ParametersOwnerWithSingleParameter|_|) (pat: ITreeNode) =
match pat with
| :? IParametersOwnerPat as ownerPat when ownerPat.Parameters.Count = 1 ->
Some ownerPat.Parameters.[0]
| _ -> None

let potentialNamedUnionCaseFieldsPat =
if isSemicolon context.TokenBeforeCaret then
context.TokenBeforeCaret.Parent
elif isWhitespace context.TokenBeforeCaret then
// This is rather weird though
// I was expecting the PrevSibling to be the semicolon instead.
match context.TokenBeforeCaret.PrevSibling with
| ParametersOwnerWithSingleParameter pat -> pat
// Incomplete match clause without body
// For example: | A(a = a1;) ->
| :? IMatchClause as clause ->
match clause.Pattern with
| ParametersOwnerWithSingleParameter pat -> pat
| _ -> null
// Incomplete match expr
| :? ILetBindingsDeclaration as letBindings ->
match Seq.tryLast letBindings.Bindings with
| Some binding ->
match binding.Expression with
| :? IMatchExpr as matchExpr ->
match Seq.tryLast matchExpr.Clauses with
| Some clause ->
match clause.Pattern with
| ParametersOwnerWithSingleParameter pat -> pat
| _ -> null
| _ -> null
| _ -> null
| _ -> null
| _ -> null
else
null

if isNull potentialNamedUnionCaseFieldsPat then Array.empty else
match potentialNamedUnionCaseFieldsPat with
| :? INamedUnionCaseFieldsPat as namedUnionCaseFieldsPat ->
let usedFields =
namedUnionCaseFieldsPat.FieldPatterns
|> Seq.map (fun fieldPat -> fieldPat.ReferenceName.Identifier.Name)
|> set
let parametersOwnerPat = ParametersOwnerPatNavigator.GetByParameter(parentPat)
if isNull parametersOwnerPat then Array.empty else
// We need to figure out if `A` actually is a UnionCase.
let fcsUnionCase = parametersOwnerPat.ReferenceName.Reference.GetFcsSymbol().As<FSharpUnionCase>()
if isNull fcsUnionCase then Array.empty else

getFieldsFromParametersOwnerPat namedUnionCaseFieldsPat usedFields
| _ -> Array.empty
let fieldNames =
fcsUnionCase.Fields
|> Seq.choose (fun field -> if field.IsNameGenerated then None else Some field.Name)
|> Seq.toArray

let getFields context =
let fieldNames = getFieldsFromReference context
if not (Array.isEmpty fieldNames) then
fieldNames
else
getFieldsAfterSemicolon context
// Only give auto completion to the fields only when all of them are named.
if fieldNames.Length <> fcsUnionCase.Fields.Count then Array.empty else fieldNames

override this.IsAvailable(context) =
let fieldNames = getFields context
let fieldNames = getFieldsFromReference context
not (Array.isEmpty fieldNames)

override this.AddLookupItems(context, collector) =
let fieldNames = getFields context
let fieldNames = getFieldsFromReference context
assert (not (Array.isEmpty fieldNames))
for fieldName in fieldNames do
let info = TextualInfo(fieldName, fieldName, Ranges = context.Ranges)
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,6 @@ type FSharpCompletionTest() =
[<Test>] member x.``Interpolated string 03 - End``() = x.DoNamedTest()

[<Test>] member x.``NamedUnionCaseFieldsPat - 01`` () = x.DoNamedTest()
[<Test>] member x.``NamedUnionCaseFieldsPat - 02`` () = x.DoNamedTest()
[<Test>] member x.``NamedUnionCaseFieldsPat - 03`` () = x.DoNamedTest()
[<Test>] member x.``NamedUnionCaseFieldsPat - 04`` () = x.DoNamedTest()
[<Test>] member x.``NamedUnionCaseFieldsPat - 05`` () = x.DoNamedTest()

[<FSharpTest; FSharpExperimentalFeature(ExperimentalFeature.PostfixTemplates)>]
type FSharpPostfixCompletionTest() =
Expand Down

0 comments on commit 7ff1349

Please sign in to comment.