Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inlay hints: optimize grouping by visibility in editor #745

Merged
merged 4 commits into from
Dec 3, 2024
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 @@ -32,6 +32,7 @@
<Compile Include="src\ContextHighlighters\FSharpMatchingBraceContextHighlighter.fs" />
<Compile Include="src\QuickDoc\FSharpQuickDocProvider.fs" />
<Compile Include="src\Syntax\XmlDocSummaryHighlightingVisitor.fs" />
<Compile Include="src\Utils\VisibilityConsumer.fs" />
<Compile Include="src\Stages\FcsErrorsStageProcessBase.fs" />
<Compile Include="src\Stages\FSharpCompilerWarningProcessor.fs" />
<Compile Include="src\Stages\FSharpDaemonBehaviour.fs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ open JetBrains.Application.Settings
open JetBrains.DocumentModel
open JetBrains.ReSharper.Feature.Services.Daemon
open JetBrains.ReSharper.Plugins.FSharp.Psi.Daemon.Highlightings.FSharpTypeHintsBulbActionsProvider
open JetBrains.ReSharper.Plugins.FSharp.Psi.Daemon.Utils.VisibleRangeContainer
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Highlightings
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Stages
open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl
Expand All @@ -18,7 +19,11 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Services.Util.TypeAnnotationsUtil
open JetBrains.TextControl.DocumentMarkup.Adornments.IntraTextAdornments

type private NodesRequiringHints =
{ TopLevelNodes: List<ITreeNode>; LocalNodes: List<ITreeNode> }
{ TopLevelNodes: VisibilityConsumer<ITreeNode>; LocalNodes: VisibilityConsumer<ITreeNode> } with

member x.HasVisibleItems =
x.TopLevelNodes.HasVisibleItems ||
x.LocalNodes.HasVisibleItems

type private FSharpTypeHintSettings =
{ TopLevelMembers: PushToHintMode; LocalBindings: PushToHintMode } with
Expand Down Expand Up @@ -184,7 +189,7 @@ type private PatternsHighlightingProcess(fsFile, settingsStore: IContextBoundSet

| _ -> ValueNone

let adornNodes (topLevelNodes : ITreeNode array) (localNodes : ITreeNode array) =
let adornNodes (topLevelNodes : ITreeNode ICollection) (localNodes : ITreeNode ICollection) =
let highlightingConsumer = FilteringHighlightingConsumer(daemonProcess.SourceFile, fsFile, settingsStore)

let inline adornNodes nodes pushToHintMode actionsProvider =
Expand All @@ -201,35 +206,26 @@ type private PatternsHighlightingProcess(fsFile, settingsStore: IContextBoundSet
highlightingConsumer.CollectHighlightings()

override x.Execute(committer) =
let consumer = { TopLevelNodes = List(); LocalNodes = List() }
fsFile.Accept(MembersVisitor(settings), consumer)

let topLevelNodes = consumer.TopLevelNodes |> Array.ofSeq
let localNodes = consumer.LocalNodes |> Array.ofSeq

// Visible range may be larger than document range by 1 char
// Intersect them to ensure commit doesn't throw
let documentRange = daemonProcess.Document.GetDocumentRange()
let visibleRange = daemonProcess.VisibleRange.Intersect(&documentRange)
let consumer = { TopLevelNodes = VisibilityConsumer(visibleRange, _.GetNavigationRange())
LocalNodes = VisibilityConsumer(visibleRange, _.GetNavigationRange()) }
fsFile.Accept(MembersVisitor(settings), consumer)

let partition (nodes: ITreeNode array) visibleRange =
nodes
|> Array.partition _.GetNavigationRange().IntersectsOrContacts(&visibleRange)
let topLevelNodes = consumer.TopLevelNodes
let localNodes = consumer.LocalNodes

// Partition the expressions to adorn by whether they're visible in the viewport or not
let remainingHighlightings =
if visibleRange.IsValid() then
// Partition the expressions to adorn by whether they're visible in the viewport or not
let topLevelVisible, topLevelNotVisible = partition topLevelNodes visibleRange
let localNodesVisible, localNodesNotVisible = partition localNodes visibleRange

if consumer.HasVisibleItems then
// Adorn visible expressions first
let visibleHighlightings = adornNodes topLevelVisible localNodesVisible
let visibleHighlightings = adornNodes topLevelNodes.VisibleItems localNodes.VisibleItems
committer.Invoke(DaemonStageResult(visibleHighlightings, visibleRange))

// Finally adorn expressions that aren't visible in the viewport
adornNodes topLevelNotVisible localNodesNotVisible
else
adornNodes topLevelNodes localNodes
// Finally adorn expressions that aren't visible in the viewport
adornNodes topLevelNodes.NonVisibleItems localNodes.NonVisibleItems

committer.Invoke(DaemonStageResult remainingHighlightings)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ open JetBrains.Application.Settings
open JetBrains.DocumentModel
open JetBrains.ReSharper.Feature.Services.Daemon
open JetBrains.ReSharper.Plugins.FSharp.Psi
open JetBrains.ReSharper.Plugins.FSharp.Psi.Daemon.Utils.VisibleRangeContainer
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Highlightings
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Daemon.Stages
open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Util
Expand All @@ -25,7 +26,7 @@ type SameLinePipeHints =
| Hide

type PipeOperatorVisitor(sameLinePipeHints: SameLinePipeHints) =
inherit TreeNodeVisitor<List<IReferenceExpr * ITreeNode * bool>>()
inherit TreeNodeVisitor<VisibilityConsumer<IReferenceExpr * ITreeNode * bool>>()

let showSameLineHints =
match sameLinePipeHints with
Expand All @@ -35,7 +36,7 @@ type PipeOperatorVisitor(sameLinePipeHints: SameLinePipeHints) =
let isApplicable binaryAppExpr =
isPredefinedInfixOpApp "|>" binaryAppExpr

let visitBinaryAppExpr binaryAppExpr (context: List<IReferenceExpr * ITreeNode * bool>) =
let visitBinaryAppExpr binaryAppExpr (context: VisibilityConsumer<IReferenceExpr * ITreeNode * bool>) =
if not (isApplicable binaryAppExpr) then () else

let opExpr = binaryAppExpr.Operator
Expand Down Expand Up @@ -117,7 +118,7 @@ type PipeChainHighlightingProcess(fsFile, settings: IContextBoundSettingsStore,
|> not
| None -> false

let adornExprs (exprs : (IReferenceExpr * ITreeNode * bool)[]) =
let adornExprs (exprs : (IReferenceExpr * ITreeNode * bool) ICollection) =
let highlightingConsumer = FilteringHighlightingConsumer(daemonProcess.SourceFile, fsFile, settings)

for refExpr, exprToAdorn, isLeft in exprs do
Expand All @@ -143,32 +144,24 @@ type PipeChainHighlightingProcess(fsFile, settings: IContextBoundSettingsStore,
else
SameLinePipeHints.Show

let consumer = List()
fsFile.Accept(PipeOperatorVisitor(sameLinePipeHints), consumer)
let allHighlightings = Array.ofSeq consumer

// Visible range may be larger than document range by 1 char
// Intersect them to ensure commit doesn't throw
let documentRange = daemonProcess.Document.GetDocumentRange()
let visibleRange = daemonProcess.VisibleRange.Intersect(&documentRange)
let consumer =
VisibilityConsumer(visibleRange, fun (_, exprToAdorn: ITreeNode, _) -> exprToAdorn.GetNavigationRange())

fsFile.Accept(PipeOperatorVisitor(sameLinePipeHints), consumer)

let remainingHighlightings =
if visibleRange.IsValid() then
if consumer.HasVisibleItems then
// Partition the expressions to adorn by whether they're visible in the viewport or not
let visible, notVisible =
allHighlightings
|> Array.partition (fun (_, exprToAdorn, _) ->
exprToAdorn.GetNavigationRange().IntersectsOrContacts(&visibleRange)
)

// Adorn visible expressions first
let visibleHighlightings = adornExprs visible
let visibleHighlightings = adornExprs consumer.VisibleItems
committer.Invoke(DaemonStageResult(visibleHighlightings, visibleRange))

// Finally adorn expressions that aren't visible in the viewport
adornExprs notVisible
else
adornExprs allHighlightings
// Finally adorn expressions that aren't visible in the viewport
adornExprs consumer.NonVisibleItems

committer.Invoke(DaemonStageResult remainingHighlightings)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module JetBrains.ReSharper.Plugins.FSharp.Psi.Daemon.Utils.VisibleRangeContainer

open System.Collections.Generic
open JetBrains.DocumentModel
open JetBrains.Util

type VisibilityConsumer<'a>(visibleRange: DocumentRange, getRange: 'a -> DocumentRange) =
let visible: ICollection<'a> = if visibleRange.IsValid() then List() else EmptyList.Instance
let notVisible: ICollection<'a> = List()
let getContainer item =
let itemRange = getRange item
if visibleRange.IntersectsOrContacts(&itemRange) then visible else notVisible

member x.Add(item) =
let listToAdd = getContainer item
listToAdd.Add(item)

member x.AddRange(items) =
for item in items do x.Add(item)

member x.HasVisibleItems = visible.Count > 0
member x.VisibleItems = visible
member x.NonVisibleItems = notVisible
Loading