module Development.IDE.Plugin.CodeAction.PositionIndexed
( PositionIndexed
, PositionIndexedString
, indexedByPosition
, indexedByPositionStartingFrom
, extendAllToIncludeCommaIfPossible
, extendToIncludePreviousNewlineIfPossible
, mergeRanges
)
where
import Data.Char
import Data.List
import Language.Haskell.LSP.Types
type PositionIndexed a = [(Position, a)]
type PositionIndexedString = PositionIndexed Char
indexedByPositionStartingFrom :: Position -> String -> PositionIndexedString
indexedByPositionStartingFrom :: Position -> String -> PositionIndexedString
indexedByPositionStartingFrom Position
initialPos = ((Position, String)
-> Maybe ((Position, Char), (Position, String)))
-> (Position, String) -> PositionIndexedString
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr (Position, String) -> Maybe ((Position, Char), (Position, String))
f ((Position, String) -> PositionIndexedString)
-> (String -> (Position, String))
-> String
-> PositionIndexedString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Position
initialPos, ) where
f :: (Position, String) -> Maybe ((Position, Char), (Position, String))
f (Position
_, []) = Maybe ((Position, Char), (Position, String))
forall a. Maybe a
Nothing
f (p :: Position
p@(Position Int
l Int
_), Char
'\n' : String
rest) =
((Position, Char), (Position, String))
-> Maybe ((Position, Char), (Position, String))
forall a. a -> Maybe a
Just ((Position
p, Char
'\n'), (Int -> Int -> Position
Position (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
0, String
rest))
f (p :: Position
p@(Position Int
l Int
c), Char
x : String
rest) = ((Position, Char), (Position, String))
-> Maybe ((Position, Char), (Position, String))
forall a. a -> Maybe a
Just ((Position
p, Char
x), (Int -> Int -> Position
Position Int
l (Int
c Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1), String
rest))
indexedByPosition :: String -> PositionIndexedString
indexedByPosition :: String -> PositionIndexedString
indexedByPosition = Position -> String -> PositionIndexedString
indexedByPositionStartingFrom (Int -> Int -> Position
Position Int
0 Int
0)
unconsRange
:: Range
-> PositionIndexed a
-> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
unconsRange :: Range
-> PositionIndexed a
-> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
unconsRange Range {Position
_start :: Range -> Position
_end :: Range -> Position
_end :: Position
_start :: Position
..} PositionIndexed a
indexedString
| (PositionIndexed a
before, rest :: PositionIndexed a
rest@((Position, a)
_ : PositionIndexed a
_)) <- ((Position, a) -> Bool)
-> PositionIndexed a -> (PositionIndexed a, PositionIndexed a)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span ((Position -> Position -> Bool
forall a. Eq a => a -> a -> Bool
/= Position
_start) (Position -> Bool)
-> ((Position, a) -> Position) -> (Position, a) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Position, a) -> Position
forall a b. (a, b) -> a
fst) PositionIndexed a
indexedString
, (PositionIndexed a
mid, after :: PositionIndexed a
after@((Position, a)
_ : PositionIndexed a
_)) <- ((Position, a) -> Bool)
-> PositionIndexed a -> (PositionIndexed a, PositionIndexed a)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span ((Position -> Position -> Bool
forall a. Eq a => a -> a -> Bool
/= Position
_end) (Position -> Bool)
-> ((Position, a) -> Position) -> (Position, a) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Position, a) -> Position
forall a b. (a, b) -> a
fst) PositionIndexed a
rest
= (PositionIndexed a, PositionIndexed a, PositionIndexed a)
-> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
forall a. a -> Maybe a
Just (PositionIndexed a
before, PositionIndexed a
mid, PositionIndexed a
after)
| Bool
otherwise
= Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
forall a. Maybe a
Nothing
stripRange :: Range -> PositionIndexed a -> Maybe (PositionIndexed a)
stripRange :: Range -> PositionIndexed a -> Maybe (PositionIndexed a)
stripRange Range
r PositionIndexed a
s = case Range
-> PositionIndexed a
-> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
forall a.
Range
-> PositionIndexed a
-> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
unconsRange Range
r PositionIndexed a
s of
Just (PositionIndexed a
b, PositionIndexed a
_, PositionIndexed a
a) -> PositionIndexed a -> Maybe (PositionIndexed a)
forall a. a -> Maybe a
Just (PositionIndexed a
b PositionIndexed a -> PositionIndexed a -> PositionIndexed a
forall a. [a] -> [a] -> [a]
++ PositionIndexed a
a)
Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
Nothing -> Maybe (PositionIndexed a)
forall a. Maybe a
Nothing
mergeRanges :: [Range] -> [Range]
mergeRanges :: [Range] -> [Range]
mergeRanges (Range
r : Range
r' : [Range]
rest)
|
Range -> Position
_end Range
r Position -> Position -> Bool
forall a. Ord a => a -> a -> Bool
> Range -> Position
_end Range
r' = [Range] -> [Range]
mergeRanges (Range
r Range -> [Range] -> [Range]
forall a. a -> [a] -> [a]
: [Range]
rest)
|
Range -> Position
_end Range
r Position -> Position -> Bool
forall a. Ord a => a -> a -> Bool
> Range -> Position
_start Range
r' = [Range] -> [Range]
mergeRanges (Range
r { _end :: Position
_end = Range -> Position
_end Range
r' } Range -> [Range] -> [Range]
forall a. a -> [a] -> [a]
: [Range]
rest)
| Bool
otherwise = Range
r Range -> [Range] -> [Range]
forall a. a -> [a] -> [a]
: [Range] -> [Range]
mergeRanges (Range
r' Range -> [Range] -> [Range]
forall a. a -> [a] -> [a]
: [Range]
rest)
mergeRanges [Range]
other = [Range]
other
extendAllToIncludeCommaIfPossible :: PositionIndexedString -> [Range] -> [Range]
extendAllToIncludeCommaIfPossible :: PositionIndexedString -> [Range] -> [Range]
extendAllToIncludeCommaIfPossible PositionIndexedString
indexedString =
[Range] -> [Range]
mergeRanges ([Range] -> [Range]) -> ([Range] -> [Range]) -> [Range] -> [Range]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PositionIndexedString -> [Range] -> [Range]
go PositionIndexedString
indexedString ([Range] -> [Range]) -> ([Range] -> [Range]) -> [Range] -> [Range]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Range -> Position) -> [Range] -> [Range]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn Range -> Position
_start
where
go :: PositionIndexedString -> [Range] -> [Range]
go PositionIndexedString
_ [] = []
go PositionIndexedString
input (Range
r : [Range]
rr)
| Range
r' : [Range]
_ <- PositionIndexedString -> Range -> [Range]
extendToIncludeCommaIfPossible PositionIndexedString
input Range
r
, Just PositionIndexedString
input' <- Range -> PositionIndexedString -> Maybe PositionIndexedString
forall a. Range -> PositionIndexed a -> Maybe (PositionIndexed a)
stripRange Range
r' PositionIndexedString
input
= Range
r' Range -> [Range] -> [Range]
forall a. a -> [a] -> [a]
: PositionIndexedString -> [Range] -> [Range]
go PositionIndexedString
input' [Range]
rr
| Bool
otherwise
= PositionIndexedString -> [Range] -> [Range]
go PositionIndexedString
input [Range]
rr
extendToIncludeCommaIfPossible :: PositionIndexedString -> Range -> [Range]
extendToIncludeCommaIfPossible :: PositionIndexedString -> Range -> [Range]
extendToIncludeCommaIfPossible PositionIndexedString
indexedString Range
range
| Just (PositionIndexedString
before, PositionIndexedString
_, PositionIndexedString
after) <- Range
-> PositionIndexedString
-> Maybe
(PositionIndexedString, PositionIndexedString,
PositionIndexedString)
forall a.
Range
-> PositionIndexed a
-> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
unconsRange Range
range PositionIndexedString
indexedString
, PositionIndexedString
after' <- ((Position, Char) -> Bool)
-> PositionIndexedString -> PositionIndexedString
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Bool
isSpace (Char -> Bool)
-> ((Position, Char) -> Char) -> (Position, Char) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Position, Char) -> Char
forall a b. (a, b) -> b
snd) PositionIndexedString
after
, PositionIndexedString
before' <- ((Position, Char) -> Bool)
-> PositionIndexedString -> PositionIndexedString
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Bool
isSpace (Char -> Bool)
-> ((Position, Char) -> Char) -> (Position, Char) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Position, Char) -> Char
forall a b. (a, b) -> b
snd) (PositionIndexedString -> PositionIndexedString
forall a. [a] -> [a]
reverse PositionIndexedString
before)
=
[ Range
range { _start :: Position
_start = Position
start' } | (Position
start', Char
',') : PositionIndexedString
_ <- [PositionIndexedString
before'] ]
[Range] -> [Range] -> [Range]
forall a. [a] -> [a] -> [a]
++
[ Range
range { _end :: Position
_end = Position
end' }
| (Position
_, Char
',') : PositionIndexedString
rest <- [PositionIndexedString
after']
, (Position
end', Char
_) : PositionIndexedString
_ <- PositionIndexedString -> [PositionIndexedString]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PositionIndexedString -> [PositionIndexedString])
-> PositionIndexedString -> [PositionIndexedString]
forall a b. (a -> b) -> a -> b
$ ((Position, Char) -> Bool)
-> PositionIndexedString -> PositionIndexedString
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Bool
isSpace (Char -> Bool)
-> ((Position, Char) -> Char) -> (Position, Char) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Position, Char) -> Char
forall a b. (a, b) -> b
snd) PositionIndexedString
rest
]
| Bool
otherwise
= [Range
range]
extendToIncludePreviousNewlineIfPossible :: PositionIndexedString -> Range -> Range
extendToIncludePreviousNewlineIfPossible :: PositionIndexedString -> Range -> Range
extendToIncludePreviousNewlineIfPossible PositionIndexedString
indexedString Range
range
| Just (PositionIndexedString
before, PositionIndexedString
_, PositionIndexedString
_) <- Range
-> PositionIndexedString
-> Maybe
(PositionIndexedString, PositionIndexedString,
PositionIndexedString)
forall a.
Range
-> PositionIndexed a
-> Maybe (PositionIndexed a, PositionIndexed a, PositionIndexed a)
unconsRange Range
range PositionIndexedString
indexedString
, Maybe Position
maybeFirstSpacePos <- PositionIndexedString -> Maybe Position
lastSpacePos (PositionIndexedString -> Maybe Position)
-> PositionIndexedString -> Maybe Position
forall a b. (a -> b) -> a -> b
$ PositionIndexedString -> PositionIndexedString
forall a. [a] -> [a]
reverse PositionIndexedString
before
= case Maybe Position
maybeFirstSpacePos of
Maybe Position
Nothing -> Range
range
Just Position
pos -> Range
range { _start :: Position
_start = Position
pos }
| Bool
otherwise = Range
range
where
lastSpacePos :: PositionIndexedString -> Maybe Position
lastSpacePos :: PositionIndexedString -> Maybe Position
lastSpacePos [] = Maybe Position
forall a. Maybe a
Nothing
lastSpacePos ((Position
pos, Char
c):PositionIndexedString
xs) =
if Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Char -> Bool
isSpace Char
c
then Maybe Position
forall a. Maybe a
Nothing
else case PositionIndexedString
xs of
((Position, Char)
y:PositionIndexedString
ys) | Char -> Bool
isSpace (Char -> Bool) -> Char -> Bool
forall a b. (a -> b) -> a -> b
$ (Position, Char) -> Char
forall a b. (a, b) -> b
snd (Position, Char)
y -> PositionIndexedString -> Maybe Position
lastSpacePos ((Position, Char)
y(Position, Char) -> PositionIndexedString -> PositionIndexedString
forall a. a -> [a] -> [a]
:PositionIndexedString
ys)
PositionIndexedString
_ -> Position -> Maybe Position
forall a. a -> Maybe a
Just Position
pos