module Yi.Keymap.Vim.Ex.Commands.Quit (parse) where
import Control.Applicative
import Control.Lens
import Control.Monad
import Data.Foldable (find)
import Data.List.NonEmpty (NonEmpty(..))
import Data.Monoid
import qualified Data.Text as T
import qualified Text.ParserCombinators.Parsec as P
import Yi.Buffer
import Yi.Core (quitEditor, errorEditor, closeWindow)
import Yi.Editor
import Yi.File
import Yi.Keymap
import Yi.Keymap.Vim.Common
import qualified Yi.Keymap.Vim.Ex.Commands.Common as Common
import Yi.Keymap.Vim.Ex.Types
import Yi.Monad
import Yi.String (showT)
import Yi.Window (bufkey)
parse :: EventString -> Maybe ExCommand
parse = Common.parse $ P.choice
[ do
_ <- (P.try ( P.string "xit") <|> P.string "x")
bangs <- P.many (P.char '!')
return (quit True (not $ null bangs) False)
, do
ws <- P.many (P.char 'w')
void $ P.try ( P.string "quit") <|> P.string "q"
as <- P.many (P.try ( P.string "all") <|> P.string "a")
bangs <- P.many (P.char '!')
return $! quit (not $ null ws) (not $ null bangs) (not $ null as)
]
quit :: Bool -> Bool -> Bool -> ExCommand
quit w f a = Common.impureExCommand {
cmdShow = (if w then "w" else "")
`T.append` "quit"
`T.append` (if a then "all" else "")
`T.append` (if f then "!" else "")
, cmdAction = YiA $ action w f a
}
action :: Bool -> Bool -> Bool -> YiM ()
action False False False = quitWindowE
action False False True = quitAllE
action True False False = viWrite >> closeWindow
action True False True = saveAndQuitAllE
action False True False = closeWindow
action False True True = quitEditor
action True True False = viWrite >> closeWindow
action True True True = saveAndQuitAllE
quitWindowE :: YiM ()
quitWindowE = do
nw <- withCurrentBuffer needsAWindowB
ws <- withEditor $ use currentWindowA >>= windowsOnBufferE . bufkey
if length ws == 1 && nw
then errorEditor "No write since last change (add ! to override)"
else closeWindow
quitAllE :: YiM ()
quitAllE = do
a :| as <- readEditor bufferStack
let needsWindow b = (b,) <$> withEditor (withGivenBuffer b needsAWindowB)
bs <- mapM needsWindow (a:as)
case find snd bs of
Nothing -> quitEditor
Just (b, _) -> do
bufferName <- withEditor $ withGivenBuffer b $ gets file
errorEditor $ "No write since last change for buffer "
<> showT bufferName
<> " (add ! to override)"
saveAndQuitAllE :: YiM ()
saveAndQuitAllE = Common.forAllBuffers fwriteBufferE >> quitEditor
needsAWindowB :: BufferM Bool
needsAWindowB = do
isWorthless <- gets (^. identA) >>= return . \case
MemBuffer _ -> True
FileBuffer _ -> False
canClose <- gets isUnchangedBuffer
return (not (isWorthless || canClose))