@@ -18,6 +18,7 @@ import Control.Concurrent.STM.Stats (atomically)
18
18
import Control.DeepSeq (rwhnf )
19
19
import Control.Lens ((?~) , (^.) )
20
20
import Control.Monad (mzero )
21
+ import Control.Monad.Except (ExceptT )
21
22
import Control.Monad.Extra (whenMaybe )
22
23
import Control.Monad.IO.Class (MonadIO (liftIO ))
23
24
import Control.Monad.Trans.Class (MonadTrans (lift ))
@@ -26,6 +27,7 @@ import qualified Data.Aeson.Types as A
26
27
import Data.Generics (GenericQ , everything ,
27
28
extQ , mkQ , something )
28
29
import Data.List (find )
30
+ import qualified Data.Map as M
29
31
import qualified Data.Map as Map
30
32
import Data.Maybe (catMaybes , fromMaybe ,
31
33
mapMaybe , maybeToList )
@@ -79,15 +81,14 @@ import Language.LSP.Protocol.Message (Method (..),
79
81
SMethod (.. ))
80
82
import Language.LSP.Protocol.Types (ApplyWorkspaceEditParams (ApplyWorkspaceEditParams ),
81
83
CodeLens (.. ),
82
- CodeLensParams (CodeLensParams , _textDocument ),
84
+ CodeLensParams (.. ),
83
85
Command , Diagnostic (.. ),
84
86
InlayHint (.. ),
85
87
InlayHintParams (InlayHintParams ),
86
88
Null (Null ),
87
89
TextDocumentIdentifier (TextDocumentIdentifier ),
88
90
TextEdit (TextEdit ),
89
91
WorkspaceEdit (WorkspaceEdit ),
90
- isSubrangeOf ,
91
92
type (|? ) (.. ))
92
93
import Text.Regex.TDFA ((=~) )
93
94
@@ -107,6 +108,7 @@ descriptor recorder plId =
107
108
{ pluginHandlers = mkPluginHandler SMethod_TextDocumentCodeLens codeLensProvider
108
109
<> mkResolveHandler SMethod_CodeLensResolve codeLensResolveProvider
109
110
<> mkPluginHandler SMethod_TextDocumentInlayHint localBindingInlayHints
111
+ <> mkPluginHandler SMethod_TextDocumentCodeLens localBindingCodeLens
110
112
, pluginCommands = [PluginCommand typeLensCommandId " adds a signature" commandHandler]
111
113
, pluginRules = globalBindingRules recorder *> localBindingRules recorder
112
114
, pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
@@ -512,54 +514,85 @@ findBindingsQ = something (mkQ Nothing findBindings)
512
514
findSigIds (unLoc -> (TypeSig _ names _)) = map unLoc names
513
515
findSigIds _ = []
514
516
515
- -- | Provide code lens for local bindings.
516
- localBindingInlayHints :: PluginMethodHandler IdeState Method_TextDocumentInlayHint
517
- localBindingInlayHints state plId (InlayHintParams _ (TextDocumentIdentifier uri) visibleRange) = do
518
- enabled <- liftIO $ runAction " inlayHint.config" state $ usePropertyAction # localBindingInlayHintOn plId properties
519
- if not enabled then pure $ InL [] else do
517
+ type LocalBindingHintRenderer a = Id -> T. Text -> Range -> Int -> a
518
+
519
+ generateWhereInlayHints :: LocalBindingHintRenderer InlayHint
520
+ generateWhereInlayHints name ty range offset =
521
+ let edit = makeEdit range ((T. pack $ printName (idName name)) <> " :: " <> ty) offset
522
+ in InlayHint { _textEdits = Just [edit]
523
+ , _paddingRight = Nothing
524
+ , _paddingLeft = Just True
525
+ , _tooltip = Nothing
526
+ , _position = _end range
527
+ , _kind = Nothing
528
+ , _label = InL $ " :: " <> ty
529
+ , _data_ = Nothing
530
+ }
531
+ where
532
+ makeEdit :: Range -> T. Text -> Int -> TextEdit
533
+ makeEdit range text offset =
534
+ let startPos = range ^. L. start
535
+ -- Subtract the offset to align with the whole binding expression
536
+ insertChar = _character startPos - fromIntegral offset
537
+ startPos' = startPos { _character = insertChar }
538
+ insertRange = Range startPos' startPos'
539
+ in TextEdit insertRange (text <> " \n " <> T. replicate (fromIntegral insertChar) " " )
540
+
541
+ generateWhereLens :: PluginId -> Uri -> Id -> T. Text -> Range -> Int -> CodeLens
542
+ generateWhereLens plId uri _ title range _ = CodeLens range (Just cmd) Nothing
543
+ where
544
+ cmd = mkLspCommand plId typeLensCommandId title (Just [A. toJSON (makeEdit range title)])
545
+ makeEdit :: Range -> T. Text -> WorkspaceEdit
546
+ makeEdit range text =
547
+ let startPos = range ^. L. start
548
+ insertChar = startPos ^. L. character
549
+ insertRange = Range startPos startPos
550
+ in WorkspaceEdit
551
+ (Just $ M. fromList [(uri, [TextEdit insertRange (text <> " \n " <> T. replicate (fromIntegral insertChar) " " )])])
552
+ Nothing
553
+ Nothing
554
+
555
+
556
+ bindingToHints :: LocalBindingHintRenderer a -> Id -> Maybe String -> Range -> Int -> Maybe a
557
+ bindingToHints render id (Just sig) range offset = Just $ render id (T. pack sig) range offset
558
+ bindingToHints _ _ Nothing _ _ = Nothing
559
+
560
+ renderLocalHints :: MonadIO m => LocalBindingHintRenderer a -> Uri -> IdeState -> ExceptT PluginError m ([a ] |? b )
561
+ renderLocalHints render uri state = do
520
562
nfp <- getNormalizedFilePathE uri
521
563
(LocalBindingTypeSigsResult (localBindings, sigMap), pm)
522
- <- runActionE " InlayHint.GetWhereBindingTypeSigs" state $ useWithStaleE GetLocalBindingTypeSigs nfp
523
- let bindingToInlayHints :: Id -> Maybe String -> Range -> Int -> Maybe InlayHint
524
- bindingToInlayHints id (Just sig) range offset =
525
- Just $ generateWhereInlayHints (T. pack $ printName (idName id )) (T. pack sig) range offset
526
- bindingToInlayHints _ Nothing _ _ = Nothing
527
-
528
- -- | Note there may multi ids for one binding,
529
- -- like @(a, b) = (42, True)@, there are `a` and `b`
530
- -- in one binding.
531
- inlayHints = catMaybes
532
- [ bindingToInlayHints bindingId bindingSig bindingRange offset
533
- | LocalBindings {.. } <- localBindings
534
- , let sigSpans = getSrcSpan <$> existingSigNames
535
- , LocalBinding {.. } <- bindings
536
- , let bindingSpan = getSrcSpan (idName bindingId)
537
- , let bindingSig = Map. lookup bindingId sigMap
538
- , bindingSpan `notElem` sigSpans
539
- , Just bindingRange <- maybeToList $ toCurrentRange pm <$> srcSpanToRange bindingLoc
540
- -- Show inlay hints only within visible range
541
- , isSubrangeOf bindingRange visibleRange
542
- ]
543
- pure $ InL inlayHints
544
- where
545
- generateWhereInlayHints :: T. Text -> T. Text -> Range -> Int -> InlayHint
546
- generateWhereInlayHints name ty range offset =
547
- let edit = makeEdit range (name <> " :: " <> ty) offset
548
- in InlayHint { _textEdits = Just [edit]
549
- , _paddingRight = Nothing
550
- , _paddingLeft = Just True
551
- , _tooltip = Nothing
552
- , _position = _end range
553
- , _kind = Nothing
554
- , _label = InL $ " :: " <> ty
555
- , _data_ = Nothing
556
- }
557
-
558
- makeEdit :: Range -> T. Text -> Int -> TextEdit
559
- makeEdit range text offset =
560
- let startPos = range ^. L. start
561
- -- Subtract the offset to align with the whole binding expression
562
- insertChar = _character startPos - fromIntegral offset
563
- startPos' = startPos { _character = insertChar }
564
- insertRange = Range startPos' startPos'
565
- in TextEdit insertRange (text <> " \n " <> T. replicate (fromIntegral insertChar) " " )
564
+ <- runActionE " InlayHint.GetWhereBindingTypeSigs" state $ useWithStaleE GetLocalBindingTypeSigs nfp
565
+
566
+ -- | Note there may multi ids for one binding,
567
+ -- like @(a, b) = (42, True)@, there are `a` and `b`
568
+ -- in one binding.
569
+ let hints = catMaybes
570
+ [ bindingToHints render bindingId bindingSig bindingRange offset
571
+ | LocalBindings {.. } <- localBindings
572
+ , let sigSpans = getSrcSpan <$> existingSigNames
573
+ , LocalBinding {.. } <- bindings
574
+ , let bindingSpan = getSrcSpan (idName bindingId)
575
+ , let bindingSig = Map. lookup bindingId sigMap
576
+ , bindingSpan `notElem` sigSpans
577
+ , Just bindingRange <- maybeToList $ toCurrentRange pm <$> srcSpanToRange bindingLoc
578
+ -- Show inlay hints only within visible range
579
+ -- TODO: there's no "visibleRange" on CodeLens'
580
+ -- , isSubrangeOf bindingRange visibleRange
581
+ ]
582
+ pure $ InL hints
583
+
584
+ localBindingCodeLens :: PluginMethodHandler IdeState Method_TextDocumentCodeLens
585
+ localBindingCodeLens state plId (CodeLensParams {.. }) = do
586
+ enabled <- liftIO $ runAction " inlayHint.config" state $ usePropertyAction # localBindingInlayHintOn plId properties
587
+ let uri = _textDocument ^. L. uri
588
+ if enabled
589
+ then pure $ InL []
590
+ else renderLocalHints (generateWhereLens plId uri) uri state
591
+
592
+ -- | Provide inlay hints for local bindings
593
+ localBindingInlayHints :: PluginMethodHandler IdeState Method_TextDocumentInlayHint
594
+ localBindingInlayHints state plId (InlayHintParams _ (TextDocumentIdentifier uri) _) = do
595
+ enabled <- liftIO $ runAction " inlayHint.config" state $ usePropertyAction # localBindingInlayHintOn plId properties
596
+ if not enabled
597
+ then pure $ InL []
598
+ else renderLocalHints generateWhereInlayHints uri state
0 commit comments