{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-# OPTIONS_HADDOCK show-extensions #-}

-- |
-- Module      :  Yi.Mode.Haskell.Dollarify
-- License     :  GPL-2
-- Maintainer  :  yi-devel@googlegroups.com
-- Stability   :  experimental
-- Portability :  portable

module Yi.Mode.Haskell.Dollarify where

import           Control.Monad       (unless)
import           Data.Function       (on)
import           Data.List           (sortBy)
import           Data.Maybe          (fromMaybe)
import           Data.Monoid         ((<>))
import           Data.Text           ()
import           Yi.Buffer           hiding (Block)
import           Yi.Debug            (trace)
import           Yi.Lexer.Alex       (Tok (..), posnOfs)
import           Yi.Lexer.Haskell    (TT, Token (..), isComment)
import qualified Yi.Rope             as R (YiString, null)
import           Yi.String           (showT)
import qualified Yi.Syntax.Haskell   as H (Exp (..), Tree)
import           Yi.Syntax.Paren     (Expr, Tree (..))
import           Yi.Syntax.Tree      (getAllSubTrees, getFirstOffset, getLastOffset, getLastPath)

dollarify :: Tree TT -> BufferM ()
dollarify :: Tree TT -> BufferM ()
dollarify Tree TT
t = BufferM ()
-> (Tree TT -> BufferM ()) -> Maybe (Tree TT) -> BufferM ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> BufferM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) Tree TT -> BufferM ()
dollarifyWithin (Maybe (Tree TT) -> BufferM ())
-> (Region -> Maybe (Tree TT)) -> Region -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr TT -> Region -> Maybe (Tree TT)
selectedTree [Tree TT
t] (Region -> BufferM ()) -> BufferM Region -> BufferM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< BufferM Region
getSelectRegionB

dollarifyWithin :: Tree TT -> BufferM ()
dollarifyWithin :: Tree TT -> BufferM ()
dollarifyWithin = Text -> BufferM () -> BufferM ()
forall a. Text -> a -> a
trace (Text -> BufferM () -> BufferM ())
-> (Tree TT -> Text) -> Tree TT -> BufferM () -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"dollarifyWithin: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) (Text -> Text) -> (Tree TT -> Text) -> Tree TT -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree TT -> Text
forall a. Show a => a -> Text
showT (Tree TT -> BufferM () -> BufferM ())
-> (Tree TT -> BufferM ()) -> Tree TT -> BufferM ()
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [QueuedUpdate] -> BufferM ()
runQ ([QueuedUpdate] -> BufferM ())
-> (Tree TT -> [QueuedUpdate]) -> Tree TT -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Tree TT -> [QueuedUpdate]
dollarifyTop (Tree TT -> [QueuedUpdate]) -> Expr TT -> [QueuedUpdate]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) (Expr TT -> [QueuedUpdate])
-> (Tree TT -> Expr TT) -> Tree TT -> [QueuedUpdate]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree TT -> Expr TT
forall (tree :: * -> *) t. IsTree tree => tree t -> [tree t]
getAllSubTrees

data QueuedUpdate = QueuedUpdate { QueuedUpdate -> Point
qUpdatePoint :: Point
                                 , QueuedUpdate -> YiString
qInsert      :: R.YiString
                                 , QueuedUpdate -> Int
qDelete      :: Int
                                 } deriving (QueuedUpdate -> QueuedUpdate -> Bool
(QueuedUpdate -> QueuedUpdate -> Bool)
-> (QueuedUpdate -> QueuedUpdate -> Bool) -> Eq QueuedUpdate
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: QueuedUpdate -> QueuedUpdate -> Bool
$c/= :: QueuedUpdate -> QueuedUpdate -> Bool
== :: QueuedUpdate -> QueuedUpdate -> Bool
$c== :: QueuedUpdate -> QueuedUpdate -> Bool
Eq, Eq QueuedUpdate
Eq QueuedUpdate
-> (QueuedUpdate -> QueuedUpdate -> Ordering)
-> (QueuedUpdate -> QueuedUpdate -> Bool)
-> (QueuedUpdate -> QueuedUpdate -> Bool)
-> (QueuedUpdate -> QueuedUpdate -> Bool)
-> (QueuedUpdate -> QueuedUpdate -> Bool)
-> (QueuedUpdate -> QueuedUpdate -> QueuedUpdate)
-> (QueuedUpdate -> QueuedUpdate -> QueuedUpdate)
-> Ord QueuedUpdate
QueuedUpdate -> QueuedUpdate -> Bool
QueuedUpdate -> QueuedUpdate -> Ordering
QueuedUpdate -> QueuedUpdate -> QueuedUpdate
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: QueuedUpdate -> QueuedUpdate -> QueuedUpdate
$cmin :: QueuedUpdate -> QueuedUpdate -> QueuedUpdate
max :: QueuedUpdate -> QueuedUpdate -> QueuedUpdate
$cmax :: QueuedUpdate -> QueuedUpdate -> QueuedUpdate
>= :: QueuedUpdate -> QueuedUpdate -> Bool
$c>= :: QueuedUpdate -> QueuedUpdate -> Bool
> :: QueuedUpdate -> QueuedUpdate -> Bool
$c> :: QueuedUpdate -> QueuedUpdate -> Bool
<= :: QueuedUpdate -> QueuedUpdate -> Bool
$c<= :: QueuedUpdate -> QueuedUpdate -> Bool
< :: QueuedUpdate -> QueuedUpdate -> Bool
$c< :: QueuedUpdate -> QueuedUpdate -> Bool
compare :: QueuedUpdate -> QueuedUpdate -> Ordering
$ccompare :: QueuedUpdate -> QueuedUpdate -> Ordering
$cp1Ord :: Eq QueuedUpdate
Ord, Int -> QueuedUpdate -> ShowS
[QueuedUpdate] -> ShowS
QueuedUpdate -> String
(Int -> QueuedUpdate -> ShowS)
-> (QueuedUpdate -> String)
-> ([QueuedUpdate] -> ShowS)
-> Show QueuedUpdate
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [QueuedUpdate] -> ShowS
$cshowList :: [QueuedUpdate] -> ShowS
show :: QueuedUpdate -> String
$cshow :: QueuedUpdate -> String
showsPrec :: Int -> QueuedUpdate -> ShowS
$cshowsPrec :: Int -> QueuedUpdate -> ShowS
Show)

runQ :: [QueuedUpdate] -> BufferM ()
runQ :: [QueuedUpdate] -> BufferM ()
runQ = Text -> BufferM () -> BufferM ()
forall a. Text -> a -> a
trace (Text -> BufferM () -> BufferM ())
-> ([QueuedUpdate] -> Text)
-> [QueuedUpdate]
-> BufferM ()
-> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"runQ: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) (Text -> Text)
-> ([QueuedUpdate] -> Text) -> [QueuedUpdate] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [QueuedUpdate] -> Text
forall a. Show a => a -> Text
showT ([QueuedUpdate] -> BufferM () -> BufferM ())
-> ([QueuedUpdate] -> BufferM ()) -> [QueuedUpdate] -> BufferM ()
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (QueuedUpdate -> BufferM ()) -> [QueuedUpdate] -> BufferM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ QueuedUpdate -> BufferM ()
run1Q ([QueuedUpdate] -> BufferM ())
-> ([QueuedUpdate] -> [QueuedUpdate])
-> [QueuedUpdate]
-> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (QueuedUpdate -> QueuedUpdate -> Ordering)
-> [QueuedUpdate] -> [QueuedUpdate]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy ((QueuedUpdate -> QueuedUpdate -> Ordering)
-> QueuedUpdate -> QueuedUpdate -> Ordering
forall a b c. (a -> b -> c) -> b -> a -> c
flip QueuedUpdate -> QueuedUpdate -> Ordering
forall a. Ord a => a -> a -> Ordering
compare)
    where
       run1Q :: QueuedUpdate -> BufferM ()
       run1Q :: QueuedUpdate -> BufferM ()
run1Q (QueuedUpdate { qUpdatePoint :: QueuedUpdate -> Point
qUpdatePoint = Point
p, qInsert :: QueuedUpdate -> YiString
qInsert = YiString
i, qDelete :: QueuedUpdate -> Int
qDelete = Int
d })
              = do Direction -> Int -> Point -> BufferM ()
deleteNAt Direction
Forward Int
d Point
p
                   Bool -> BufferM () -> BufferM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (YiString -> Bool
R.null YiString
i) (BufferM () -> BufferM ()) -> BufferM () -> BufferM ()
forall a b. (a -> b) -> a -> b
$ YiString -> Point -> BufferM ()
insertNAt YiString
i Point
p

openParen, closeParen :: Token
openParen :: Token
openParen = Char -> Token
Special Char
'('
closeParen :: Token
closeParen = Char -> Token
Special Char
')'

isNormalParen :: Tree TT -> Bool
isNormalParen :: Tree TT -> Bool
isNormalParen (Paren TT
t1 Expr TT
xs TT
t2) =
  TT -> Token
forall t. Tok t -> t
tokT TT
t1 Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Token
openParen Bool -> Bool -> Bool
&& TT -> Token
forall t. Tok t -> t
tokT TT
t2 Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Token
closeParen Bool -> Bool -> Bool
&& Bool -> Bool
not ((Tree TT -> Bool) -> Expr TT -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Tree TT -> Bool
isTuple Expr TT
xs)
isNormalParen Tree TT
_               = Bool
False

isTuple ::Tree TT -> Bool
isTuple :: Tree TT -> Bool
isTuple (Atom TT
t) = TT -> Token
forall t. Tok t -> t
tokT TT
t Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Token
Special Char
','
isTuple Tree TT
_ = Bool
False

-- Assumes length of token is one character
queueDelete :: TT -> QueuedUpdate
queueDelete :: TT -> QueuedUpdate
queueDelete = YiString -> TT -> QueuedUpdate
queueReplaceWith YiString
""

-- Assumes length of token is one character
queueReplaceWith :: R.YiString -> TT -> QueuedUpdate
queueReplaceWith :: YiString -> TT -> QueuedUpdate
queueReplaceWith YiString
s TT
t = QueuedUpdate :: Point -> YiString -> Int -> QueuedUpdate
QueuedUpdate { qUpdatePoint :: Point
qUpdatePoint = Posn -> Point
posnOfs (Posn -> Point) -> Posn -> Point
forall a b. (a -> b) -> a -> b
$ TT -> Posn
forall t. Tok t -> Posn
tokPosn TT
t
                                    , qInsert :: YiString
qInsert = YiString
s
                                    , qDelete :: Int
qDelete = Int
1
                                    }

-- Only strips comments from the top level
stripComments :: Expr TT -> Expr TT
stripComments :: Expr TT -> Expr TT
stripComments = (Tree TT -> Bool) -> Expr TT -> Expr TT
forall a. (a -> Bool) -> [a] -> [a]
filter ((Tree TT -> Bool) -> Expr TT -> Expr TT)
-> (Tree TT -> Bool) -> Expr TT -> Expr TT
forall a b. (a -> b) -> a -> b
$ \Tree TT
t -> case Tree TT
t of { (Atom TT
x) -> Bool -> Bool
not (Token -> Bool
isComment (Token -> Bool) -> Token -> Bool
forall a b. (a -> b) -> a -> b
$ TT -> Token
forall t. Tok t -> t
tokT TT
x); Tree TT
_ -> Bool
True }

dollarifyTop :: Tree TT -> [QueuedUpdate]
dollarifyTop :: Tree TT -> [QueuedUpdate]
dollarifyTop p :: Tree TT
p@(Paren TT
t1 Expr TT
e TT
t2)
   | Tree TT -> Bool
isNormalParen Tree TT
p = case Expr TT -> Expr TT
stripComments Expr TT
e of
       [Paren{}] -> [TT -> QueuedUpdate
queueDelete TT
t2, TT -> QueuedUpdate
queueDelete TT
t1]
       Expr TT
e'        -> Expr TT -> [QueuedUpdate]
dollarifyExpr Expr TT
e'
dollarifyTop (Block Expr TT
blk) = Expr TT -> [QueuedUpdate]
dollarifyExpr (Expr TT -> [QueuedUpdate])
-> (Expr TT -> Expr TT) -> Expr TT -> [QueuedUpdate]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr TT -> Expr TT
stripComments (Expr TT -> [QueuedUpdate]) -> [Expr TT] -> [QueuedUpdate]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [Expr TT
x | Expr Expr TT
x <- Expr TT
blk]
dollarifyTop Tree TT
_ = []

-- Expression must not contain comments
dollarifyExpr :: Expr TT -> [QueuedUpdate]
dollarifyExpr :: Expr TT -> [QueuedUpdate]
dollarifyExpr e :: Expr TT
e@(Tree TT
_:Expr TT
_)
    | p :: Tree TT
p@(Paren TT
t Expr TT
e2 TT
t2) <- Expr TT -> Tree TT
forall a. [a] -> a
last Expr TT
e
    , Tree TT -> Bool
isNormalParen Tree TT
p
    , (Tree TT -> Bool) -> Expr TT -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Tree TT -> Bool
isSimple Expr TT
e
    = let dollarifyLoop :: Expr TT -> [QueuedUpdate]
          dollarifyLoop :: Expr TT -> [QueuedUpdate]
dollarifyLoop [] = []
          dollarifyLoop e3 :: Expr TT
e3@[Paren{}] = Expr TT -> [QueuedUpdate]
dollarifyExpr Expr TT
e3
          dollarifyLoop Expr TT
e3 = if Expr TT -> Bool
isCollapsible Expr TT
e3 then [TT -> QueuedUpdate
queueDelete TT
t2, YiString -> TT -> QueuedUpdate
queueReplaceWith YiString
"$ " TT
t] else []
          in Expr TT -> [QueuedUpdate]
dollarifyLoop (Expr TT -> [QueuedUpdate]) -> Expr TT -> [QueuedUpdate]
forall a b. (a -> b) -> a -> b
$ Expr TT -> Expr TT
stripComments Expr TT
e2
dollarifyExpr Expr TT
_ = []

isSimple :: Tree TT -> Bool
isSimple :: Tree TT -> Bool
isSimple (Paren{}) = Bool
True
isSimple (Block{}) = Bool
False
isSimple (Atom TT
t)  = TT -> Token
forall t. Tok t -> t
tokT TT
t Token -> [Token] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Token
Number, Token
CharTok, Token
StringTok, Token
VarIdent, Token
ConsIdent]
isSimple Tree TT
_         = Bool
False

-- Expression must not contain comments
isCollapsible :: Expr TT -> Bool
isCollapsible :: Expr TT -> Bool
isCollapsible = (Bool -> Bool -> Bool
(&&) (Bool -> Bool -> Bool)
-> (Tree TT -> Bool) -> Tree TT -> Tree TT -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Tree TT -> Bool
isSimple) (Tree TT -> Tree TT -> Bool)
-> (Expr TT -> Tree TT) -> Expr TT -> Tree TT -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr TT -> Tree TT
forall a. [a] -> a
head (Expr TT -> Tree TT -> Bool)
-> (Expr TT -> Tree TT) -> Expr TT -> Bool
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expr TT -> Tree TT
forall a. [a] -> a
last

selectedTree :: Expr TT -> Region -> Maybe (Tree TT)
selectedTree :: Expr TT -> Region -> Maybe (Tree TT)
selectedTree Expr TT
e Region
r = Region -> Expr TT -> Tree TT
findLargestWithin Region
r (Expr TT -> Tree TT) -> Maybe (Expr TT) -> Maybe (Tree TT)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expr TT -> Point -> Maybe (Expr TT)
forall (tree :: * -> *) t.
IsTree tree =>
[tree (Tok t)] -> Point -> Maybe [tree (Tok t)]
getLastPath Expr TT
e (Region -> Point
regionLast Region
r)

-- List must be non-empty
findLargestWithin :: Region -> [Tree TT] -> Tree TT
findLargestWithin :: Region -> Expr TT -> Tree TT
findLargestWithin Region
r = Tree TT -> Maybe (Tree TT) -> Tree TT
forall a. a -> Maybe a -> a
fromMaybe (Tree TT -> Maybe (Tree TT) -> Tree TT)
-> (Expr TT -> Tree TT) -> Expr TT -> Maybe (Tree TT) -> Tree TT
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr TT -> Tree TT
forall a. [a] -> a
head (Expr TT -> Maybe (Tree TT) -> Tree TT)
-> (Expr TT -> Maybe (Tree TT)) -> Expr TT -> Tree TT
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expr TT -> Maybe (Tree TT)
forall a. [a] -> Maybe a
safeLast (Expr TT -> Maybe (Tree TT))
-> (Expr TT -> Expr TT) -> Expr TT -> Maybe (Tree TT)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Tree TT -> Bool) -> Expr TT -> Expr TT
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Region -> Tree TT -> Bool
within Region
r)

within :: Region -> Tree TT -> Bool
within :: Region -> Tree TT -> Bool
within Region
r Tree TT
t = Region -> Region -> Bool
includedRegion ((Point -> Point -> Region
mkRegion (Point -> Point -> Region)
-> (Tree TT -> Point) -> Tree TT -> Point -> Region
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree TT -> Point
forall (t :: * -> *) t1. Foldable t => t (Tok t1) -> Point
getFirstOffset (Tree TT -> Point -> Region)
-> (Tree TT -> Point) -> Tree TT -> Region
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Tree TT -> Point
forall (t :: * -> *) t1. Foldable t => t (Tok t1) -> Point
getLastOffset) Tree TT
t) Region
r

safeLast :: [a] -> Maybe a
safeLast :: [a] -> Maybe a
safeLast [] = Maybe a
forall a. Maybe a
Nothing
safeLast [a]
s  = a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ [a] -> a
forall a. [a] -> a
last [a]
s

-- Here follows code for the precise haskell mode

dollarifyP :: H.Tree TT -> BufferM ()
dollarifyP :: Tree TT -> BufferM ()
dollarifyP Tree TT
e = BufferM ()
-> (Tree TT -> BufferM ()) -> Maybe (Tree TT) -> BufferM ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> BufferM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) Tree TT -> BufferM ()
dollarifyWithinP (Maybe (Tree TT) -> BufferM ())
-> (Region -> Maybe (Tree TT)) -> Region -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Tree TT] -> Region -> Maybe (Tree TT)
selectedTreeP [Tree TT
e] (Region -> BufferM ()) -> BufferM Region -> BufferM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< BufferM Region
getSelectRegionB

dollarifyWithinP :: H.Exp TT -> BufferM ()
dollarifyWithinP :: Tree TT -> BufferM ()
dollarifyWithinP = Text -> BufferM () -> BufferM ()
forall a. Text -> a -> a
trace (Text -> BufferM () -> BufferM ())
-> (Tree TT -> Text) -> Tree TT -> BufferM () -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"dollarifyWithin: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) (Text -> Text) -> (Tree TT -> Text) -> Tree TT -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree TT -> Text
forall a. Show a => a -> Text
showT (Tree TT -> BufferM () -> BufferM ())
-> (Tree TT -> BufferM ()) -> Tree TT -> BufferM ()
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [QueuedUpdate] -> BufferM ()
runQ ([QueuedUpdate] -> BufferM ())
-> (Tree TT -> [QueuedUpdate]) -> Tree TT -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Tree TT -> [QueuedUpdate]
dollarifyTopP (Tree TT -> [QueuedUpdate]) -> [Tree TT] -> [QueuedUpdate]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) ([Tree TT] -> [QueuedUpdate])
-> (Tree TT -> [Tree TT]) -> Tree TT -> [QueuedUpdate]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree TT -> [Tree TT]
forall (tree :: * -> *) t. IsTree tree => tree t -> [tree t]
getAllSubTrees

isNormalParenP :: H.Exp TT -> Bool
isNormalParenP :: Tree TT -> Bool
isNormalParenP (H.Paren (H.PAtom TT
r [TT]
_) [Tree TT]
xs (H.PAtom TT
r' [TT]
_)) =
  TT -> Token
forall t. Tok t -> t
tokT TT
r Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Token
openParen Bool -> Bool -> Bool
&& TT -> Token
forall t. Tok t -> t
tokT TT
r' Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Token
closeParen Bool -> Bool -> Bool
&& Bool -> Bool
not ((Tree TT -> Bool) -> [Tree TT] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Tree TT -> Bool
isTupleP [Tree TT]
xs)
isNormalParenP Tree TT
_               = Bool
False

isTupleP :: H.Exp TT -> Bool
isTupleP :: Tree TT -> Bool
isTupleP (H.PAtom TT
t [TT]
_) = TT -> Token
forall t. Tok t -> t
tokT TT
t Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Token
Special Char
','
isTupleP Tree TT
_ = Bool
False

-- Only strips comments from the top level
stripCommentsP :: [H.Exp TT] -> [H.Exp TT]
stripCommentsP :: [Tree TT] -> [Tree TT]
stripCommentsP = (Tree TT -> Bool) -> [Tree TT] -> [Tree TT]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Tree TT -> Bool) -> [Tree TT] -> [Tree TT])
-> (Tree TT -> Bool) -> [Tree TT] -> [Tree TT]
forall a b. (a -> b) -> a -> b
$ \Tree TT
t -> case Tree TT
t of { (H.PAtom TT
x [TT]
_) -> Bool -> Bool
not (Token -> Bool
isComment (Token -> Bool) -> Token -> Bool
forall a b. (a -> b) -> a -> b
$ TT -> Token
forall t. Tok t -> t
tokT TT
x); Tree TT
_ -> Bool
True }

dollarifyTopP :: H.Exp TT -> [QueuedUpdate]
dollarifyTopP :: Tree TT -> [QueuedUpdate]
dollarifyTopP p :: Tree TT
p@(H.Paren (H.PAtom TT
t1 [TT]
_) [Tree TT]
e (H.PAtom TT
t2 [TT]
_))
   | Tree TT -> Bool
isNormalParenP Tree TT
p = case [Tree TT] -> [Tree TT]
stripCommentsP [Tree TT]
e of
       [H.Paren{}] -> [TT -> QueuedUpdate
queueDelete TT
t2, TT -> QueuedUpdate
queueDelete TT
t1]
       [Tree TT]
e'          -> [Tree TT] -> [QueuedUpdate]
dollarifyExprP [Tree TT]
e'
dollarifyTopP (H.Block [Tree TT]
bList) = [Tree TT] -> [QueuedUpdate]
dollarifyExprP ([Tree TT] -> [QueuedUpdate])
-> ([Tree TT] -> [Tree TT]) -> [Tree TT] -> [QueuedUpdate]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Tree TT] -> [Tree TT]
stripCommentsP ([Tree TT] -> [QueuedUpdate]) -> [Tree TT] -> [QueuedUpdate]
forall a b. (a -> b) -> a -> b
$ [Tree TT]
bList
dollarifyTopP Tree TT
_ = []

-- Expression must not contain comments
dollarifyExprP :: [H.Exp TT] -> [QueuedUpdate]
dollarifyExprP :: [Tree TT] -> [QueuedUpdate]
dollarifyExprP e :: [Tree TT]
e@(Tree TT
_:[Tree TT]
_)
    | p :: Tree TT
p@(H.Paren (H.PAtom TT
t [TT]
_) [Tree TT]
e2 (H.PAtom TT
t2 [TT]
_)) <- [Tree TT] -> Tree TT
forall a. [a] -> a
last [Tree TT]
e
    , Tree TT -> Bool
isNormalParenP Tree TT
p
    , (Tree TT -> Bool) -> [Tree TT] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Tree TT -> Bool
isSimpleP [Tree TT]
e
    = let dollarifyLoop :: [H.Exp TT] -> [QueuedUpdate]
          dollarifyLoop :: [Tree TT] -> [QueuedUpdate]
dollarifyLoop [] = []
          dollarifyLoop e3 :: [Tree TT]
e3@[H.Paren{}] = [Tree TT] -> [QueuedUpdate]
dollarifyExprP [Tree TT]
e3
          dollarifyLoop [Tree TT]
e3 = if [Tree TT] -> Bool
isCollapsibleP [Tree TT]
e3 then [TT -> QueuedUpdate
queueDelete TT
t2, YiString -> TT -> QueuedUpdate
queueReplaceWith YiString
"$ " TT
t] else []
          in [Tree TT] -> [QueuedUpdate]
dollarifyLoop ([Tree TT] -> [QueuedUpdate]) -> [Tree TT] -> [QueuedUpdate]
forall a b. (a -> b) -> a -> b
$ [Tree TT] -> [Tree TT]
stripCommentsP [Tree TT]
e2
dollarifyExprP [Tree TT]
_ = []

isSimpleP :: H.Exp TT -> Bool
isSimpleP :: Tree TT -> Bool
isSimpleP (H.Paren{})   = Bool
True
isSimpleP (H.Block{})   = Bool
False
isSimpleP (H.PAtom TT
t [TT]
_) = TT -> Token
forall t. Tok t -> t
tokT TT
t Token -> [Token] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Token
Number, Token
CharTok, Token
StringTok, Token
VarIdent, Token
ConsIdent]
isSimpleP Tree TT
_             = Bool
False

-- Expression must not contain comments
isCollapsibleP :: [H.Exp TT] -> Bool
isCollapsibleP :: [Tree TT] -> Bool
isCollapsibleP = (Bool -> Bool -> Bool
(&&) (Bool -> Bool -> Bool)
-> (Tree TT -> Bool) -> Tree TT -> Tree TT -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Tree TT -> Bool
isSimpleP) (Tree TT -> Tree TT -> Bool)
-> ([Tree TT] -> Tree TT) -> [Tree TT] -> Tree TT -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Tree TT] -> Tree TT
forall a. [a] -> a
head ([Tree TT] -> Tree TT -> Bool)
-> ([Tree TT] -> Tree TT) -> [Tree TT] -> Bool
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Tree TT] -> Tree TT
forall a. [a] -> a
last

selectedTreeP :: [H.Exp TT] -> Region -> Maybe (H.Exp TT)
selectedTreeP :: [Tree TT] -> Region -> Maybe (Tree TT)
selectedTreeP [Tree TT]
e Region
r = Region -> [Tree TT] -> Tree TT
findLargestWithinP Region
r ([Tree TT] -> Tree TT) -> Maybe [Tree TT] -> Maybe (Tree TT)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Tree TT] -> Point -> Maybe [Tree TT]
forall (tree :: * -> *) t.
IsTree tree =>
[tree (Tok t)] -> Point -> Maybe [tree (Tok t)]
getLastPath [Tree TT]
e (Region -> Point
regionLast Region
r)

-- List must be non-empty
findLargestWithinP :: Region -> [H.Exp TT] -> H.Exp TT
findLargestWithinP :: Region -> [Tree TT] -> Tree TT
findLargestWithinP Region
r = Tree TT -> Maybe (Tree TT) -> Tree TT
forall a. a -> Maybe a -> a
fromMaybe (Tree TT -> Maybe (Tree TT) -> Tree TT)
-> ([Tree TT] -> Tree TT)
-> [Tree TT]
-> Maybe (Tree TT)
-> Tree TT
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Tree TT] -> Tree TT
forall a. [a] -> a
head ([Tree TT] -> Maybe (Tree TT) -> Tree TT)
-> ([Tree TT] -> Maybe (Tree TT)) -> [Tree TT] -> Tree TT
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Tree TT] -> Maybe (Tree TT)
forall a. [a] -> Maybe a
safeLast ([Tree TT] -> Maybe (Tree TT))
-> ([Tree TT] -> [Tree TT]) -> [Tree TT] -> Maybe (Tree TT)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Tree TT -> Bool) -> [Tree TT] -> [Tree TT]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Region -> Tree TT -> Bool
withinP Region
r)

withinP :: Region -> H.Exp TT -> Bool
withinP :: Region -> Tree TT -> Bool
withinP Region
r Tree TT
t = Region -> Region -> Bool
includedRegion ((Point -> Point -> Region
mkRegion (Point -> Point -> Region)
-> (Tree TT -> Point) -> Tree TT -> Point -> Region
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree TT -> Point
forall (t :: * -> *) t1. Foldable t => t (Tok t1) -> Point
getFirstOffset (Tree TT -> Point -> Region)
-> (Tree TT -> Point) -> Tree TT -> Region
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Tree TT -> Point
forall (t :: * -> *) t1. Foldable t => t (Tok t1) -> Point
getLastOffset) Tree TT
t) Region
r

safeLastP :: [a] -> Maybe a
safeLastP :: [a] -> Maybe a
safeLastP [] = Maybe a
forall a. Maybe a
Nothing
safeLastP [a]
s  = a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ [a] -> a
forall a. [a] -> a
last [a]
s