{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE OverloadedStrings         #-}
{-# LANGUAGE RecordWildCards           #-}
{-# LANGUAGE ScopedTypeVariables       #-}

module Ide.Plugin.CodeRange (
    descriptor
    , Log

    -- * Internal
    , findPosition
    , findFoldingRanges
    , createFoldingRange
    ) where

import           Control.Monad.Except                 (ExceptT (ExceptT),
                                                       mapExceptT)
import           Control.Monad.IO.Class               (liftIO)
import           Control.Monad.Trans.Maybe            (MaybeT (MaybeT),
                                                       maybeToExceptT)
import           Data.Either.Extra                    (maybeToEither)
import           Data.List.Extra                      (drop1)
import           Data.Maybe                           (fromMaybe)
import           Data.Vector                          (Vector)
import qualified Data.Vector                          as V
import           Development.IDE                      (Action, IdeAction,
                                                       IdeState (shakeExtras),
                                                       Range (Range), Recorder,
                                                       WithPriority,
                                                       cmapWithPrio, runAction,
                                                       runIdeAction,
                                                       toNormalizedFilePath',
                                                       uriToFilePath', use,
                                                       useWithStaleFast)
import           Development.IDE.Core.PositionMapping (PositionMapping,
                                                       fromCurrentPosition,
                                                       toCurrentRange)
import           Development.IDE.Types.Logger         (Pretty (..),
                                                       Priority (Warning),
                                                       logWith)
import           Ide.Plugin.CodeRange.Rules           (CodeRange (..),
                                                       GetCodeRange (..),
                                                       codeRangeRule, crkToFrk)
import qualified Ide.Plugin.CodeRange.Rules           as Rules (Log)
import           Ide.PluginUtils                      (pluginResponse,
                                                       positionInRange)
import           Ide.Types                            (PluginDescriptor (pluginHandlers, pluginRules),
                                                       PluginId,
                                                       defaultPluginDescriptor,
                                                       mkPluginHandler)
import           Language.LSP.Server                  (LspM, LspT)
import           Language.LSP.Types                   (FoldingRange (..),
                                                       FoldingRangeParams (..),
                                                       List (List),
                                                       NormalizedFilePath,
                                                       Position (..),
                                                       Range (_start),
                                                       ResponseError,
                                                       SMethod (STextDocumentFoldingRange, STextDocumentSelectionRange),
                                                       SelectionRange (..),
                                                       SelectionRangeParams (..),
                                                       TextDocumentIdentifier (TextDocumentIdentifier),
                                                       Uri)
import           Prelude                              hiding (log, span)

descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState
descriptor :: Recorder (WithPriority Log)
-> PluginId -> PluginDescriptor IdeState
descriptor Recorder (WithPriority Log)
recorder PluginId
plId = (forall ideState. PluginId -> PluginDescriptor ideState
defaultPluginDescriptor PluginId
plId)
    { pluginHandlers :: PluginHandlers IdeState
pluginHandlers = forall (m :: Method 'FromClient 'Request) ideState.
PluginRequestMethod m =>
SClientMethod m
-> PluginMethodHandler ideState m -> PluginHandlers ideState
mkPluginHandler SMethod 'TextDocumentSelectionRange
STextDocumentSelectionRange (forall c.
Recorder (WithPriority Log)
-> IdeState
-> PluginId
-> SelectionRangeParams
-> LspM c (Either ResponseError (List SelectionRange))
selectionRangeHandler Recorder (WithPriority Log)
recorder)
    forall a. Semigroup a => a -> a -> a
<> forall (m :: Method 'FromClient 'Request) ideState.
PluginRequestMethod m =>
SClientMethod m
-> PluginMethodHandler ideState m -> PluginHandlers ideState
mkPluginHandler SMethod 'TextDocumentFoldingRange
STextDocumentFoldingRange (forall c.
Recorder (WithPriority Log)
-> IdeState
-> PluginId
-> FoldingRangeParams
-> LspM c (Either ResponseError (List FoldingRange))
foldingRangeHandler Recorder (WithPriority Log)
recorder)
    , pluginRules :: Rules ()
pluginRules = Recorder (WithPriority Log) -> Rules ()
codeRangeRule (forall a b.
(a -> b) -> Recorder (WithPriority b) -> Recorder (WithPriority a)
cmapWithPrio Log -> Log
LogRules Recorder (WithPriority Log)
recorder)
    }

data Log = LogRules Rules.Log
         | forall rule. Show rule => LogBadDependency rule

instance Pretty Log where
    pretty :: forall ann. Log -> Doc ann
pretty Log
log = case Log
log of
        LogRules Log
codeRangeLog -> forall a ann. Pretty a => a -> Doc ann
pretty Log
codeRangeLog
        LogBadDependency rule
rule -> forall a ann. Pretty a => a -> Doc ann
pretty forall a b. (a -> b) -> a -> b
$ String
"bad dependency: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show rule
rule

foldingRangeHandler :: Recorder (WithPriority Log) -> IdeState -> PluginId -> FoldingRangeParams -> LspM c (Either ResponseError (List FoldingRange))
foldingRangeHandler :: forall c.
Recorder (WithPriority Log)
-> IdeState
-> PluginId
-> FoldingRangeParams
-> LspM c (Either ResponseError (List FoldingRange))
foldingRangeHandler Recorder (WithPriority Log)
recorder IdeState
ide PluginId
_ FoldingRangeParams{Maybe ProgressToken
TextDocumentIdentifier
$sel:_workDoneToken:FoldingRangeParams :: FoldingRangeParams -> Maybe ProgressToken
$sel:_partialResultToken:FoldingRangeParams :: FoldingRangeParams -> Maybe ProgressToken
$sel:_textDocument:FoldingRangeParams :: FoldingRangeParams -> TextDocumentIdentifier
_textDocument :: TextDocumentIdentifier
_partialResultToken :: Maybe ProgressToken
_workDoneToken :: Maybe ProgressToken
..} = do
    forall (m :: * -> *) a.
Monad m =>
ExceptT String m a -> m (Either ResponseError a)
pluginResponse forall a b. (a -> b) -> a -> b
$ do
        NormalizedFilePath
filePath <- forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Maybe b -> Either a b
maybeToEither String
"fail to convert uri to file path" forall a b. (a -> b) -> a -> b
$
                String -> NormalizedFilePath
toNormalizedFilePath' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Uri -> Maybe String
uriToFilePath' Uri
uri
        [FoldingRange]
foldingRanges <- forall (m :: * -> *) e a (n :: * -> *) e' b.
(m (Either e a) -> n (Either e' b))
-> ExceptT e m a -> ExceptT e' n b
mapExceptT forall c.
Action (Either FoldingRangeError [FoldingRange])
-> LspT c IO (Either String [FoldingRange])
runAction' forall a b. (a -> b) -> a -> b
$
            NormalizedFilePath
-> ExceptT FoldingRangeError Action [FoldingRange]
getFoldingRanges NormalizedFilePath
filePath
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> List a
List forall a b. (a -> b) -> a -> b
$ [FoldingRange]
foldingRanges
  where
    uri :: Uri
    TextDocumentIdentifier Uri
uri = TextDocumentIdentifier
_textDocument

    runAction' :: Action (Either FoldingRangeError [FoldingRange]) -> LspT c IO (Either String [FoldingRange])
    runAction' :: forall c.
Action (Either FoldingRangeError [FoldingRange])
-> LspT c IO (Either String [FoldingRange])
runAction' Action (Either FoldingRangeError [FoldingRange])
action = do
        Either FoldingRangeError [FoldingRange]
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. String -> IdeState -> Action a -> IO a
runAction String
"FoldingRange" IdeState
ide Action (Either FoldingRangeError [FoldingRange])
action
        case Either FoldingRangeError [FoldingRange]
result of
            Left FoldingRangeError
err -> case FoldingRangeError
err of
                FoldingRangeBadDependency rule
rule -> do
                    forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Warning forall a b. (a -> b) -> a -> b
$ forall rule. Show rule => rule -> Log
LogBadDependency rule
rule
                    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right []
            Right [FoldingRange]
list -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right [FoldingRange]
list

data FoldingRangeError = forall rule. Show rule => FoldingRangeBadDependency rule

getFoldingRanges :: NormalizedFilePath -> ExceptT FoldingRangeError Action [FoldingRange]
getFoldingRanges :: NormalizedFilePath
-> ExceptT FoldingRangeError Action [FoldingRange]
getFoldingRanges NormalizedFilePath
file = do
    CodeRange
codeRange <- forall (m :: * -> *) e a.
Functor m =>
e -> MaybeT m a -> ExceptT e m a
maybeToExceptT (forall rule. Show rule => rule -> FoldingRangeError
FoldingRangeBadDependency GetCodeRange
GetCodeRange) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT forall a b. (a -> b) -> a -> b
$ forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> Action (Maybe v)
use GetCodeRange
GetCodeRange NormalizedFilePath
file
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ CodeRange -> [FoldingRange]
findFoldingRanges CodeRange
codeRange

selectionRangeHandler :: Recorder (WithPriority Log) -> IdeState -> PluginId -> SelectionRangeParams -> LspM c (Either ResponseError (List SelectionRange))
selectionRangeHandler :: forall c.
Recorder (WithPriority Log)
-> IdeState
-> PluginId
-> SelectionRangeParams
-> LspM c (Either ResponseError (List SelectionRange))
selectionRangeHandler Recorder (WithPriority Log)
recorder IdeState
ide PluginId
_ SelectionRangeParams{Maybe ProgressToken
List Position
TextDocumentIdentifier
$sel:_workDoneToken:SelectionRangeParams :: SelectionRangeParams -> Maybe ProgressToken
$sel:_partialResultToken:SelectionRangeParams :: SelectionRangeParams -> Maybe ProgressToken
$sel:_textDocument:SelectionRangeParams :: SelectionRangeParams -> TextDocumentIdentifier
$sel:_positions:SelectionRangeParams :: SelectionRangeParams -> List Position
_positions :: List Position
_textDocument :: TextDocumentIdentifier
_partialResultToken :: Maybe ProgressToken
_workDoneToken :: Maybe ProgressToken
..} = do
    forall (m :: * -> *) a.
Monad m =>
ExceptT String m a -> m (Either ResponseError a)
pluginResponse forall a b. (a -> b) -> a -> b
$ do
        NormalizedFilePath
filePath <- forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Maybe b -> Either a b
maybeToEither String
"fail to convert uri to file path" forall a b. (a -> b) -> a -> b
$
                String -> NormalizedFilePath
toNormalizedFilePath' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Uri -> Maybe String
uriToFilePath' Uri
uri
        forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. [a] -> List a
List forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) e a (n :: * -> *) e' b.
(m (Either e a) -> n (Either e' b))
-> ExceptT e m a -> ExceptT e' n b
mapExceptT forall c.
IdeAction (Either SelectionRangeError [SelectionRange])
-> LspT c IO (Either String [SelectionRange])
runIdeAction' forall b c a. (b -> c) -> (a -> b) -> a -> c
. NormalizedFilePath
-> [Position]
-> ExceptT SelectionRangeError IdeAction [SelectionRange]
getSelectionRanges NormalizedFilePath
filePath forall a b. (a -> b) -> a -> b
$ [Position]
positions
  where
    uri :: Uri
    TextDocumentIdentifier Uri
uri = TextDocumentIdentifier
_textDocument

    positions :: [Position]
    List [Position]
positions = List Position
_positions

    runIdeAction' :: IdeAction (Either SelectionRangeError [SelectionRange]) -> LspT c IO (Either String [SelectionRange])
    runIdeAction' :: forall c.
IdeAction (Either SelectionRangeError [SelectionRange])
-> LspT c IO (Either String [SelectionRange])
runIdeAction' IdeAction (Either SelectionRangeError [SelectionRange])
action = do
        Either SelectionRangeError [SelectionRange]
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall a. String -> ShakeExtras -> IdeAction a -> IO a
runIdeAction String
"SelectionRange" (IdeState -> ShakeExtras
shakeExtras IdeState
ide) IdeAction (Either SelectionRangeError [SelectionRange])
action
        case Either SelectionRangeError [SelectionRange]
result of
            Left SelectionRangeError
err   -> case SelectionRangeError
err of
                SelectionRangeBadDependency rule
rule -> do
                    forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Warning forall a b. (a -> b) -> a -> b
$ forall rule. Show rule => rule -> Log
LogBadDependency rule
rule
                    -- This might happen if the HieAst is not ready,
                    -- so we give it a default value instead of throwing an error
                    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right []
                SelectionRangeError
SelectionRangeInputPositionMappingFailure -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
                    forall a b. a -> Either a b
Left String
"failed to apply position mapping to input positions"
                SelectionRangeError
SelectionRangeOutputPositionMappingFailure -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
                    forall a b. a -> Either a b
Left String
"failed to apply position mapping to output positions"
            Right [SelectionRange]
list -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right [SelectionRange]
list

data SelectionRangeError = forall rule. Show rule => SelectionRangeBadDependency rule
                         | SelectionRangeInputPositionMappingFailure
                         | SelectionRangeOutputPositionMappingFailure

getSelectionRanges :: NormalizedFilePath -> [Position] -> ExceptT SelectionRangeError IdeAction [SelectionRange]
getSelectionRanges :: NormalizedFilePath
-> [Position]
-> ExceptT SelectionRangeError IdeAction [SelectionRange]
getSelectionRanges NormalizedFilePath
file [Position]
positions = do
    (CodeRange
codeRange, PositionMapping
positionMapping) <- forall (m :: * -> *) e a.
Functor m =>
e -> MaybeT m a -> ExceptT e m a
maybeToExceptT (forall rule. Show rule => rule -> SelectionRangeError
SelectionRangeBadDependency GetCodeRange
GetCodeRange) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT forall a b. (a -> b) -> a -> b
$
        forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> IdeAction (Maybe (v, PositionMapping))
useWithStaleFast GetCodeRange
GetCodeRange NormalizedFilePath
file
    -- 'positionMapping' should be applied to the input before using them
    [Position]
positions' <- forall (m :: * -> *) e a.
Functor m =>
e -> MaybeT m a -> ExceptT e m a
maybeToExceptT SelectionRangeError
SelectionRangeInputPositionMappingFailure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
        forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (PositionMapping -> Position -> Maybe Position
fromCurrentPosition PositionMapping
positionMapping) [Position]
positions

    let selectionRanges :: [SelectionRange]
selectionRanges = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Position]
positions' forall a b. (a -> b) -> a -> b
$ \Position
pos ->
            -- We need a default selection range if the lookup fails,
            -- so that other positions can still have valid results.
            let defaultSelectionRange :: SelectionRange
defaultSelectionRange = Range -> Maybe SelectionRange -> SelectionRange
SelectionRange (Position -> Position -> Range
Range Position
pos Position
pos) forall a. Maybe a
Nothing
             in forall a. a -> Maybe a -> a
fromMaybe SelectionRange
defaultSelectionRange forall b c a. (b -> c) -> (a -> b) -> a -> c
. Position -> CodeRange -> Maybe SelectionRange
findPosition Position
pos forall a b. (a -> b) -> a -> b
$ CodeRange
codeRange

    -- 'positionMapping' should be applied to the output ranges before returning them
    forall (m :: * -> *) e a.
Functor m =>
e -> MaybeT m a -> ExceptT e m a
maybeToExceptT SelectionRangeError
SelectionRangeOutputPositionMappingFailure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
         forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (PositionMapping -> SelectionRange -> Maybe SelectionRange
toCurrentSelectionRange PositionMapping
positionMapping) [SelectionRange]
selectionRanges

-- | Find 'Position' in 'CodeRange'. This can fail, if the given position is not covered by the 'CodeRange'.
findPosition :: Position -> CodeRange -> Maybe SelectionRange
findPosition :: Position -> CodeRange -> Maybe SelectionRange
findPosition Position
pos CodeRange
root = Maybe SelectionRange -> CodeRange -> Maybe SelectionRange
go forall a. Maybe a
Nothing CodeRange
root
  where
    -- Helper function for recursion. The range list is built top-down
    go :: Maybe SelectionRange -> CodeRange -> Maybe SelectionRange
    go :: Maybe SelectionRange -> CodeRange -> Maybe SelectionRange
go Maybe SelectionRange
acc CodeRange
node =
        if Position -> Range -> Bool
positionInRange Position
pos Range
range
        then forall b a. b -> (a -> b) -> Maybe a -> b
maybe Maybe SelectionRange
acc' (Maybe SelectionRange -> CodeRange -> Maybe SelectionRange
go Maybe SelectionRange
acc') (Vector CodeRange -> Maybe CodeRange
binarySearchPos Vector CodeRange
children)
        -- If all children doesn't contain pos, acc' will be returned.
        -- acc' will be Nothing only if we are in the root level.
        else forall a. Maybe a
Nothing
      where
        range :: Range
range = CodeRange -> Range
_codeRange_range CodeRange
node
        children :: Vector CodeRange
children = CodeRange -> Vector CodeRange
_codeRange_children CodeRange
node
        acc' :: Maybe SelectionRange
acc' = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Range -> Maybe SelectionRange -> SelectionRange
SelectionRange Range
range forall a. Maybe a
Nothing) (Range -> Maybe SelectionRange -> SelectionRange
SelectionRange Range
range forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just) Maybe SelectionRange
acc

    binarySearchPos :: Vector CodeRange -> Maybe CodeRange
    binarySearchPos :: Vector CodeRange -> Maybe CodeRange
binarySearchPos Vector CodeRange
v
        | forall a. Vector a -> Bool
V.null Vector CodeRange
v = forall a. Maybe a
Nothing
        | forall a. Vector a -> Int
V.length Vector CodeRange
v forall a. Eq a => a -> a -> Bool
== Int
1,
            Just CodeRange
r <- forall (m :: * -> *) a. Monad m => Vector a -> m a
V.headM Vector CodeRange
v = if Position -> Range -> Bool
positionInRange Position
pos (CodeRange -> Range
_codeRange_range CodeRange
r) then forall a. a -> Maybe a
Just CodeRange
r else forall a. Maybe a
Nothing
        | Bool
otherwise = do
            let (Vector CodeRange
left, Vector CodeRange
right) = forall a. Int -> Vector a -> (Vector a, Vector a)
V.splitAt (forall a. Vector a -> Int
V.length Vector CodeRange
v forall a. Integral a => a -> a -> a
`div` Int
2) Vector CodeRange
v
            Position
startOfRight <- Range -> Position
_start forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodeRange -> Range
_codeRange_range forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a. Monad m => Vector a -> m a
V.headM Vector CodeRange
right
            if Position
pos forall a. Ord a => a -> a -> Bool
< Position
startOfRight then Vector CodeRange -> Maybe CodeRange
binarySearchPos Vector CodeRange
left else Vector CodeRange -> Maybe CodeRange
binarySearchPos Vector CodeRange
right

-- | Traverses through the code range and it children to a folding ranges.
--
-- It starts with the root node, converts that into a folding range then moves towards the children.
-- It converts each child of each root node and parses it to folding range and moves to its children.
--
-- Two cases to that are assumed to be taken care on the client side are:
--
--      1. When a folding range starts and ends on the same line, it is upto the client if it wants to
--      fold a single line folding or not.
--
--      2. As we are converting nodes of the ast into folding ranges, there are multiple nodes starting from a single line.
--      A single line of code doesn't mean a single node in AST, so this function removes all the nodes that have a duplicate
--      start line, ie. they start from the same line.
--      Eg. A multi-line function that also has a multi-line if statement starting from the same line should have the folding
--      according to the function.
--
-- We think the client can handle this, if not we could change to remove these in future
--
-- Discussion reference: https://github.com/haskell/haskell-language-server/pull/3058#discussion_r973737211
findFoldingRanges :: CodeRange -> [FoldingRange]
findFoldingRanges :: CodeRange -> [FoldingRange]
findFoldingRanges CodeRange
codeRange =
    -- removing the first node because it folds the entire file
    forall a. [a] -> [a]
drop1 forall a b. (a -> b) -> a -> b
$ CodeRange -> [FoldingRange]
findFoldingRangesRec CodeRange
codeRange

findFoldingRangesRec :: CodeRange -> [FoldingRange]
findFoldingRangesRec :: CodeRange -> [FoldingRange]
findFoldingRangesRec r :: CodeRange
r@(CodeRange Range
_ Vector CodeRange
children CodeRangeKind
_) =
    let [FoldingRange]
frChildren :: [FoldingRange] = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall a b. (a -> b) -> a -> b
$ forall a. Vector a -> [a]
V.toList forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CodeRange -> [FoldingRange]
findFoldingRangesRec Vector CodeRange
children
    in case CodeRange -> Maybe FoldingRange
createFoldingRange CodeRange
r of
        Just FoldingRange
x  -> FoldingRange
xforall a. a -> [a] -> [a]
:[FoldingRange]
frChildren
        Maybe FoldingRange
Nothing -> [FoldingRange]
frChildren

-- | Parses code range to folding range
createFoldingRange :: CodeRange -> Maybe FoldingRange
createFoldingRange :: CodeRange -> Maybe FoldingRange
createFoldingRange (CodeRange (Range (Position UInt
lineStart UInt
charStart) (Position UInt
lineEnd UInt
charEnd)) Vector CodeRange
_ CodeRangeKind
ck) = do
    -- Type conversion of codeRangeKind to FoldingRangeKind
    let frk :: FoldingRangeKind
frk = CodeRangeKind -> FoldingRangeKind
crkToFrk CodeRangeKind
ck
    forall a. a -> Maybe a
Just (UInt
-> Maybe UInt
-> UInt
-> Maybe UInt
-> Maybe FoldingRangeKind
-> FoldingRange
FoldingRange UInt
lineStart (forall a. a -> Maybe a
Just UInt
charStart) UInt
lineEnd (forall a. a -> Maybe a
Just UInt
charEnd) (forall a. a -> Maybe a
Just FoldingRangeKind
frk))

-- | Likes 'toCurrentPosition', but works on 'SelectionRange'
toCurrentSelectionRange :: PositionMapping -> SelectionRange -> Maybe SelectionRange
toCurrentSelectionRange :: PositionMapping -> SelectionRange -> Maybe SelectionRange
toCurrentSelectionRange PositionMapping
positionMapping SelectionRange{Maybe SelectionRange
Range
$sel:_range:SelectionRange :: SelectionRange -> Range
$sel:_parent:SelectionRange :: SelectionRange -> Maybe SelectionRange
_parent :: Maybe SelectionRange
_range :: Range
..} = do
    Range
newRange <- PositionMapping -> Range -> Maybe Range
toCurrentRange PositionMapping
positionMapping Range
_range
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ SelectionRange {
        $sel:_range:SelectionRange :: Range
_range = Range
newRange,
        $sel:_parent:SelectionRange :: Maybe SelectionRange
_parent = Maybe SelectionRange
_parent forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= PositionMapping -> SelectionRange -> Maybe SelectionRange
toCurrentSelectionRange PositionMapping
positionMapping
    }