1
+ {-# LANGUAGE RankNTypes #-}
1
2
module Development.IDE.Plugin.SelectionRange
2
3
( descriptor
3
4
) where
4
5
5
- import Control.Monad.IO.Class (liftIO )
6
- import Development.IDE (IdeState (shakeExtras ),
7
- runIdeAction ,
8
- toNormalizedFilePath' ,
9
- uriToFilePath' )
10
- import Development.IDE.Core.Actions (getSelectionRanges )
11
- import Ide.Types (PluginDescriptor (pluginHandlers ),
12
- PluginId ,
13
- defaultPluginDescriptor ,
14
- mkPluginHandler )
15
- import Language.LSP.Server (LspM )
16
- import Language.LSP.Types (List (List ), ResponseError ,
17
- SMethod (STextDocumentSelectionRange ),
18
- SelectionRange ,
19
- SelectionRangeParams (.. ),
20
- TextDocumentIdentifier (TextDocumentIdentifier ))
6
+ import Control.Monad.IO.Class (liftIO )
7
+ import Control.Monad.Trans.Maybe (MaybeT (MaybeT ), runMaybeT )
8
+ import Data.Foldable (find )
9
+ import qualified Data.Map.Strict as Map
10
+ import Data.Maybe (fromMaybe , mapMaybe )
11
+ import Development.IDE (GetHieAst (GetHieAst ),
12
+ HieAstResult (HAR , hieAst ),
13
+ IdeAction ,
14
+ IdeState (shakeExtras ),
15
+ Range (Range ),
16
+ fromNormalizedFilePath ,
17
+ realSrcSpanToRange ,
18
+ runIdeAction ,
19
+ toNormalizedFilePath' ,
20
+ uriToFilePath' )
21
+ import Development.IDE.Core.Actions (useE )
22
+ import Development.IDE.GHC.Compat (HieAST (Node ), Span , getAsts )
23
+ import Development.IDE.GHC.Compat.Util (mkFastString )
24
+ import Ide.Types (PluginDescriptor (pluginHandlers ),
25
+ PluginId ,
26
+ defaultPluginDescriptor ,
27
+ mkPluginHandler )
28
+ import Language.LSP.Server (LspM )
29
+ import Language.LSP.Types (List (List ),
30
+ NormalizedFilePath , Position ,
31
+ ResponseError ,
32
+ SMethod (STextDocumentSelectionRange ),
33
+ SelectionRange (.. ),
34
+ SelectionRangeParams (.. ),
35
+ TextDocumentIdentifier (TextDocumentIdentifier ))
21
36
22
37
descriptor :: PluginId -> PluginDescriptor IdeState
23
38
descriptor plId = (defaultPluginDescriptor plId)
@@ -34,3 +49,29 @@ selectionRangeHandler ide _ SelectionRangeParams{..} = do
34
49
let (List positions) = _positions
35
50
selectionRanges <- runIdeAction " SelectionRange" (shakeExtras ide) $ getSelectionRanges filePath positions
36
51
pure . Right . List $ selectionRanges
52
+
53
+ getSelectionRanges :: NormalizedFilePath -> [Position ] -> IdeAction [SelectionRange ]
54
+ getSelectionRanges file positions = fmap (fromMaybe [] ) <$> runMaybeT $ do
55
+ (HAR {hieAst}, _) <- useE GetHieAst file
56
+ ast <- MaybeT . pure $ getAsts hieAst Map. !? (mkFastString . fromNormalizedFilePath) file
57
+ pure $ findSelectionRangesByPositions (astPathsLeafToRoot ast) positions
58
+
59
+ -- | build all paths from ast leaf to root
60
+ astPathsLeafToRoot :: HieAST a -> [SelectionRange ]
61
+ astPathsLeafToRoot = mapMaybe spansToSelectionRange . go [[] ]
62
+ where
63
+ go acc (Node _ span [] ) = fmap (span : ) acc
64
+ go acc (Node _ span children) = concatMap (go (fmap (span : ) acc)) children
65
+
66
+ spansToSelectionRange :: [Span ] -> Maybe SelectionRange
67
+ spansToSelectionRange [] = Nothing
68
+ spansToSelectionRange (span : spans) = Just $
69
+ SelectionRange {_range = realSrcSpanToRange span , _parent = spansToSelectionRange spans}
70
+
71
+ findSelectionRangesByPositions :: [SelectionRange ] -> [Position ] -> [SelectionRange ]
72
+ findSelectionRangesByPositions selectionRanges = fmap findByPosition
73
+ where
74
+ findByPosition p = fromMaybe SelectionRange {_range = Range p p, _parent = Nothing } $
75
+ find (isPositionInSelectionRange p) selectionRanges
76
+ isPositionInSelectionRange p SelectionRange {_range} =
77
+ let Range sp ep = _range in sp <= p && p <= ep
0 commit comments