{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Ide.Plugin.CodeRange (
descriptor
, Log
, findPosition
, findFoldingRanges
, createFoldingRange
) where
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Trans.Except (ExceptT, mapExceptT)
import Control.Monad.Trans.Maybe (MaybeT (MaybeT),
maybeToExceptT)
import Data.List.Extra (drop1)
import Data.Maybe (fromMaybe)
import Data.Vector (Vector)
import qualified Data.Vector as V
import Development.IDE (Action,
IdeState (shakeExtras),
Range (Range), Recorder,
WithPriority,
cmapWithPrio)
import Development.IDE.Core.PluginUtils
import Development.IDE.Core.PositionMapping (PositionMapping,
toCurrentRange)
import Ide.Logger (Pretty (..))
import Ide.Plugin.CodeRange.Rules (CodeRange (..),
GetCodeRange (..),
codeRangeRule, crkToFrk)
import qualified Ide.Plugin.CodeRange.Rules as Rules (Log)
import Ide.Plugin.Error
import Ide.PluginUtils (positionInRange)
import Ide.Types (PluginDescriptor (pluginHandlers, pluginRules),
PluginId,
PluginMethodHandler,
defaultPluginDescriptor,
mkPluginHandler)
import Language.LSP.Protocol.Message (Method (Method_TextDocumentFoldingRange, Method_TextDocumentSelectionRange),
SMethod (SMethod_TextDocumentFoldingRange, SMethod_TextDocumentSelectionRange))
import Language.LSP.Protocol.Types (FoldingRange (..),
FoldingRangeParams (..),
NormalizedFilePath, Null,
Position (..),
Range (_start),
SelectionRange (..),
SelectionRangeParams (..),
TextDocumentIdentifier (TextDocumentIdentifier),
Uri, type (|?) (InL))
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 ideState (m :: Method 'ClientToServer 'Request).
PluginRequestMethod m =>
SClientMethod m
-> PluginMethodHandler ideState m -> PluginHandlers ideState
mkPluginHandler SMethod 'Method_TextDocumentSelectionRange
SMethod_TextDocumentSelectionRange (Recorder (WithPriority Log)
-> PluginMethodHandler IdeState 'Method_TextDocumentSelectionRange
selectionRangeHandler Recorder (WithPriority Log)
recorder)
forall a. Semigroup a => a -> a -> a
<> forall ideState (m :: Method 'ClientToServer 'Request).
PluginRequestMethod m =>
SClientMethod m
-> PluginMethodHandler ideState m -> PluginHandlers ideState
mkPluginHandler SMethod 'Method_TextDocumentFoldingRange
SMethod_TextDocumentFoldingRange (Recorder (WithPriority Log)
-> PluginMethodHandler IdeState 'Method_TextDocumentFoldingRange
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
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
foldingRangeHandler :: Recorder (WithPriority Log) -> PluginMethodHandler IdeState 'Method_TextDocumentFoldingRange
foldingRangeHandler :: Recorder (WithPriority Log)
-> PluginMethodHandler IdeState 'Method_TextDocumentFoldingRange
foldingRangeHandler Recorder (WithPriority Log)
_ 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
NormalizedFilePath
filePath <- forall (m :: * -> *).
Monad m =>
Uri -> ExceptT PluginError m NormalizedFilePath
getNormalizedFilePathE Uri
uri
[FoldingRange]
foldingRanges <- forall (m :: * -> *) e a.
MonadIO m =>
String -> IdeState -> ExceptT e Action a -> ExceptT e m a
runActionE String
"FoldingRange" IdeState
ide forall a b. (a -> b) -> a -> b
$ NormalizedFilePath -> ExceptT PluginError 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 b. a -> a |? b
InL forall a b. (a -> b) -> a -> b
$ [FoldingRange]
foldingRanges
where
uri :: Uri
TextDocumentIdentifier Uri
uri = TextDocumentIdentifier
_textDocument
getFoldingRanges :: NormalizedFilePath -> ExceptT PluginError Action [FoldingRange]
getFoldingRanges :: NormalizedFilePath -> ExceptT PluginError Action [FoldingRange]
getFoldingRanges NormalizedFilePath
file = do
CodeRange
codeRange <- forall k v.
IdeRule k v =>
k -> NormalizedFilePath -> ExceptT PluginError Action v
useE 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) -> PluginMethodHandler IdeState 'Method_TextDocumentSelectionRange
selectionRangeHandler :: Recorder (WithPriority Log)
-> PluginMethodHandler IdeState 'Method_TextDocumentSelectionRange
selectionRangeHandler Recorder (WithPriority Log)
_ IdeState
ide PluginId
_ SelectionRangeParams{[Position]
Maybe ProgressToken
TextDocumentIdentifier
$sel:_workDoneToken:SelectionRangeParams :: SelectionRangeParams -> Maybe ProgressToken
$sel:_partialResultToken:SelectionRangeParams :: SelectionRangeParams -> Maybe ProgressToken
$sel:_textDocument:SelectionRangeParams :: SelectionRangeParams -> TextDocumentIdentifier
$sel:_positions:SelectionRangeParams :: SelectionRangeParams -> [Position]
_positions :: [Position]
_textDocument :: TextDocumentIdentifier
_partialResultToken :: Maybe ProgressToken
_workDoneToken :: Maybe ProgressToken
..} = do
do
NormalizedFilePath
filePath <- forall (m :: * -> *).
Monad m =>
Uri -> ExceptT PluginError m NormalizedFilePath
getNormalizedFilePathE Uri
uri
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 (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ IdeState
-> NormalizedFilePath
-> [Position]
-> ExceptT PluginError IO ([SelectionRange] |? Null)
getSelectionRanges IdeState
ide NormalizedFilePath
filePath [Position]
positions
where
uri :: Uri
TextDocumentIdentifier Uri
uri = TextDocumentIdentifier
_textDocument
positions :: [Position]
positions :: [Position]
positions = [Position]
_positions
getSelectionRanges :: IdeState -> NormalizedFilePath -> [Position] -> ExceptT PluginError IO ([SelectionRange] |? Null)
getSelectionRanges :: IdeState
-> NormalizedFilePath
-> [Position]
-> ExceptT PluginError IO ([SelectionRange] |? Null)
getSelectionRanges IdeState
ide NormalizedFilePath
file [Position]
positions = do
(CodeRange
codeRange, PositionMapping
positionMapping) <- forall (m :: * -> *) e a.
MonadIO m =>
String -> ShakeExtras -> ExceptT e IdeAction a -> ExceptT e m a
runIdeActionE String
"SelectionRange" (IdeState -> ShakeExtras
shakeExtras IdeState
ide) forall a b. (a -> b) -> a -> b
$ forall k v.
IdeRule k v =>
k
-> NormalizedFilePath
-> ExceptT PluginError IdeAction (v, PositionMapping)
useWithStaleFastE GetCodeRange
GetCodeRange NormalizedFilePath
file
[Position]
positions' <-
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (forall (m :: * -> *).
Monad m =>
PositionMapping -> Position -> ExceptT PluginError m Position
fromCurrentPositionE 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 ->
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
forall (m :: * -> *) e a.
Functor m =>
e -> MaybeT m a -> ExceptT e m a
maybeToExceptT (Text -> PluginError
PluginInvalidUserState Text
"toCurrentSelectionRange") 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 a b. a -> a |? b
InL forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f 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
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
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)
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
findFoldingRanges :: CodeRange -> [FoldingRange]
findFoldingRanges :: CodeRange -> [FoldingRange]
findFoldingRanges CodeRange
codeRange =
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
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
let frk :: FoldingRangeKind
frk = CodeRangeKind -> FoldingRangeKind
crkToFrk CodeRangeKind
ck
forall a. a -> Maybe a
Just (UInt
-> Maybe UInt
-> UInt
-> Maybe UInt
-> Maybe FoldingRangeKind
-> Maybe Text
-> 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) forall a. Maybe a
Nothing)
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
}