module Yavie.Keybind.Vi ( defaultKeybind , defaultCmdbind , defaultRomode , defaultInsertmode ) where import Control.EventDriven ( EventMonad, bind, unbind, runEvent, delegate, copyContainer, removeContainer ) import Yavie.Editor ( Editor, multi, needDeleteThisEditor, deleteThisEditor, cursorUp, cursorDown, cursorToTop, cursorToLine, cursorToLinePercent, cursorToHead, cursorToMiddle, cursorToLast, cursorLeft, cursorRight, cursorTopOfLineNotSpace, cursorTopOfLine, cursorEndOfLine, cursorFindChar, cursorFindCharBack, cursorWord, cursorWordEnd, cursorBackWord, resetStrForSearch, addStrForSearch, cursorSearchStr, cursorSearchStrBack, cursorNextSearchStr, cursorNextSearchStrBack, scrollUp, scrollDown, scrollUpPage, scrollDownPage, scrollUpHPage, scrollDownHPage, scrollForCursorHead, scrollForCursorMiddle, scrollForCursorLast, resetYank, deleteUp, deleteDown, deleteLine, deleteLeft, deleteRight, deleteChar, deleteCursorToBegin, deleteCursorToEnd, deleteWord, deleteWordEnd, deleteBackWord, deleteFind, deleteFindMore, concatTwoLines, yankLines, insertChar, insertNL, flipCase, inInsertMode, outInsertMode, pasteYanked, pasteYankedAfter, setVisualBeginY, resetVisualmode, deleteInLargeVmode, yankInLargeVmode, resizeDisplay, saveToHistory, undo, redo, resetTimes, addTimes, resetStatus, setStatus, addStatus, bsStatus, resetExCmd, addExCmd, getExCmd, bsExCmd, saveToFile, saveToTmpFile, isModified, saveToEditor, fileName, replaceModeOn, replaceModeOff ) import Control.Monad.State ( modify, gets, when ) import Data.Char ( isDigit ) import Yavie.Keybind saveHistory :: EventMonad Event ( Editor c ) () -> EventMonad Event ( Editor c ) () saveHistory = (modify saveToHistory >>) key :: Char -> EventMonad Event ( Editor c ) () key ch = runEvent ( EvKey ( KASCII ch ) [ ] ) toInsertmode :: EventMonad Event ( Editor c ) () toInsertmode = saveHistory $ modify ( setStatus "insert mode" ) >> modify inInsertMode >> bind insertmode >> modify saveToTmpFile deleteEditorIfNeed :: EventMonad Event ( Editor c ) () deleteEditorIfNeed = do d <- gets needDeleteThisEditor when d removeContainer defaultRomode :: Keybind c defaultRomode ( EvKey ( KASCII c ) [ ] ) | c `elem` "iIaArRdDcCsSoO" = return () defaultRomode e = defaultKeybind defaultCmdbind e defaultKeybind :: Cmdbind c -> Keybind c defaultKeybind _ EvExpose = return () defaultKeybind _ ( EvKey ( KASCII 'u' ) [ ] ) = modify undo defaultKeybind _ ( EvKey ( KASCII 'r' ) [ MCtrl ] ) = modify redo defaultKeybind _ ( EvKey ( KASCII 'j' ) [ ] ) = modify $ multi cursorDown defaultKeybind _ ( EvKey ( KASCII 'k' ) [ ] ) = modify $ multi cursorUp defaultKeybind _ ( EvKey ( KASCII 'H' ) [ ] ) = modify cursorToHead defaultKeybind _ ( EvKey ( KASCII 'M' ) [ ] ) = modify cursorToMiddle defaultKeybind _ ( EvKey ( KASCII 'L' ) [ ] ) = modify cursorToLast defaultKeybind _ ( EvKey ( KASCII 'l' ) [ ] ) = modify $ multi cursorRight defaultKeybind _ ( EvKey ( KASCII 'h' ) [ ] ) = modify $ multi cursorLeft defaultKeybind _ ( EvKey ( KASCII '$' ) [ ] ) = modify cursorEndOfLine defaultKeybind _ ( EvKey ( KASCII '0' ) [ ] ) = modify cursorTopOfLine defaultKeybind _ ( EvKey ( KASCII '^' ) [ ] ) = modify cursorTopOfLineNotSpace defaultKeybind _ ( EvKey ( KASCII 'w' ) [ ] ) = modify $ multi cursorWord defaultKeybind _ ( EvKey ( KASCII 'b' ) [ ] ) = modify $ multi cursorBackWord defaultKeybind _ ( EvKey ( KASCII 'e' ) [ ] ) = modify $ multi cursorWordEnd defaultKeybind _ ( EvKey ( KASCII 'f' ) [ ] ) = bind findmode defaultKeybind _ ( EvKey ( KASCII 'F' ) [ ] ) = bind findbackmode defaultKeybind _ ( EvKey ( KASCII 'e' ) [ MCtrl ] ) = modify $ multi scrollDown defaultKeybind _ ( EvKey ( KASCII 'y' ) [ MCtrl ] ) = modify $ multi scrollUp defaultKeybind _ ( EvKey ( KASCII 'f' ) [ MCtrl ] ) = modify $ multi scrollDownPage defaultKeybind _ ( EvKey ( KASCII 'b' ) [ MCtrl ] ) = modify $ multi scrollUpPage defaultKeybind _ ( EvKey ( KASCII 'd' ) [ MCtrl ] ) = modify $ multi scrollDownHPage defaultKeybind _ ( EvKey ( KASCII 'u' ) [ MCtrl ] ) = modify $ multi scrollUpHPage defaultKeybind _ ( EvKey ( KASCII 'x' ) [ ] ) = saveHistory $ modify resetYank >> modify ( multi deleteChar ) defaultKeybind _ ( EvKey ( KASCII 'X' ) [ ] ) = saveHistory $ modify $ multi ( deleteChar . cursorLeft ) defaultKeybind _ ( EvKey ( KASCII 'i' ) [ ] ) = toInsertmode defaultKeybind _ ( EvKey ( KASCII 'I' ) [ ] ) = modify cursorTopOfLineNotSpace >> key 'i' defaultKeybind _ ( EvKey ( KASCII 'a' ) [ ] ) = toInsertmode >> modify cursorRight defaultKeybind _ ( EvKey ( KASCII 'A' ) [ ] ) = toInsertmode >> modify cursorEndOfLine >> modify cursorRight defaultKeybind _ ( EvKey ( KASCII 'o' ) [ ] ) = toInsertmode >> modify cursorEndOfLine >> modify cursorRight >> modify insertNL defaultKeybind _ ( EvKey ( KASCII 'O' ) [ ] ) = modify cursorTopOfLine >> modify insertNL >> modify cursorUp >> toInsertmode defaultKeybind _ ( EvKey ( KASCII 'r' ) [ ] ) = saveHistory $ bind replacemodeOne defaultKeybind _ ( EvKey ( KASCII '~' ) [ ] ) = saveHistory $ modify flipCase >> key 'l' defaultKeybind _ ( EvKey ( KASCII 'R' ) [ ] ) = saveHistory $ modify inInsertMode >> modify replaceModeOn >> bind replacemode defaultKeybind _ ( EvKey ( KASCII 's' ) [ ] ) = toInsertmode >> modify ( multi deleteChar ) defaultKeybind _ ( EvKey ( KASCII 'S' ) [ ] ) = modify cursorTopOfLine >> modify deleteCursorToEnd >> toInsertmode defaultKeybind _ ( EvKey ( KASCII 'J' ) [ ] ) = saveHistory $ modify cursorEndOfLine >> modify concatTwoLines defaultKeybind _ ( EvKey ( KASCII 'D' ) [ ] ) = saveHistory $ modify deleteCursorToEnd defaultKeybind _ ( EvKey ( KASCII 'd' ) [ ] ) = saveHistory $ modify resetYank >> bind deletemode defaultKeybind _ ( EvKey ( KASCII 'C' ) [ ] ) = saveHistory $ modify inInsertMode >> modify deleteCursorToEnd >> key 'i' defaultKeybind _ ( EvKey ( KASCII 'c' ) [ ] ) = saveHistory $ bind changemode defaultKeybind _ ( EvKey ( KASCII 'y' ) [ ] ) = bind yankmode defaultKeybind _ ( EvKey ( KASCII 'p' ) [ ] ) = saveHistory $ modify pasteYankedAfter defaultKeybind _ ( EvKey ( KASCII 'P' ) [ ] ) = saveHistory $ modify pasteYanked defaultKeybind _ ( EvKey ( KASCII 'G' ) [ ] ) = modify cursorToLine defaultKeybind _ ( EvKey ( KASCII '%' ) [ ] ) = modify cursorToLinePercent defaultKeybind _ ( EvKey ( KASCII 'g' ) [ ] ) = bind gomode defaultKeybind cb ( EvKey ( KASCII 'Z' ) [ ] ) = bind $ lzmode cb defaultKeybind _ ( EvKey ( KASCII 'z' ) [ ] ) = bind zmode defaultKeybind _ ( EvKey ( KASCII c ) [ ] ) | isDigit c = do modify resetTimes modify $ addTimes c bind digitmode defaultKeybind _ ( EvKey ( KASCII 'V' ) [ ] ) = do modify setVisualBeginY modify $ setStatus "V mode" bind visualVmode defaultKeybind cb ( EvKey ( KASCII ':' ) [ ] ) = do modify resetStatus modify $ addStatus ':' modify resetExCmd bind $ exmode cb defaultKeybind _ ( EvKey ( KASCII 'n' ) [ ] ) = modify cursorNextSearchStr defaultKeybind _ ( EvKey ( KASCII 'N' ) [ ] ) = modify cursorNextSearchStrBack defaultKeybind _ ( EvKey ( KASCII '/' ) [ ] ) = do modify resetStatus modify $ addStatus '/' modify resetStrForSearch bind $ searchmode False defaultKeybind _ ( EvKey ( KASCII '?' ) [ ] ) = do modify resetStatus modify $ addStatus '?' modify resetStrForSearch bind $ searchmode True defaultKeybind _ ( EvResize w h ) = modify $ resizeDisplay w $ h - 1 defaultKeybind _ EvDeleteEditor = deleteEditorIfNeed defaultKeybind _ _ = return () searchmode :: Bool -> Event -> EventMonad Event ( Editor c ) () searchmode _ ( EvKey ( KASCII c ) [ MMeta ] ) = do _ <- runEvent $ EvKey KEsc [ ] runEvent $ EvKey ( KASCII c ) [ ] searchmode _ ( EvKey KEsc [ ] ) = do _ <- unbind modify resetStatus searchmode _ ( EvKey KEnter [ ] ) = do _ <- unbind modify resetStatus searchmode d ( EvKey ( KASCII c ) [ ] ) = do modify $ addStrForSearch c modify $ addStatus c modify $ if d then cursorSearchStrBack else cursorSearchStr searchmode _ _ = delegate findmode, findbackmode :: Event -> EventMonad Event ( Editor c ) () findmode ( EvKey ( KASCII c ) [ ] ) = unbind >> modify ( multi $ cursorFindChar c ) findmode _ = return () findbackmode ( EvKey ( KASCII c ) [ ] ) = unbind >> modify ( multi $ cursorFindCharBack c ) findbackmode _ = return () defaultInsertmode, insertmode, replacemodeOne, replacemode :: Keybind c defaultInsertmode = insertmode insertmode ( EvKey ( KASCII c ) [ MMeta ] ) = runEvent ( EvKey KEsc [ ] ) >> runEvent ( EvKey ( KASCII c ) [ ] ) insertmode ( EvKey KEsc [ ] ) = modify resetStatus >> unbind >> modify cursorLeft >> modify outInsertMode insertmode ( EvKey ( KASCII c ) [ ] ) = modify ( insertChar c ) insertmode ( EvKey KEnter [ ] ) = modify insertNL insertmode _ = delegate replacemodeOne ( EvKey ( KASCII c ) [ ] ) = modify inInsertMode >> modify ( multi $ insertChar c . deleteChar ) >> unbind >> modify cursorLeft >> modify outInsertMode replacemodeOne _ = return () replacemode ( EvKey ( KASCII c ) [ MMeta ] ) = runEvent ( EvKey KEsc [ ] ) >> key c replacemode ( EvKey KEsc [ ] ) = modify resetStatus >> unbind >> modify cursorLeft >> modify replaceModeOff >> modify outInsertMode replacemode ( EvKey ( KASCII c ) [ ] ) = modify deleteChar >> modify ( insertChar c ) replacemode ( EvKey KEnter [ ] ) = modify deleteChar >> modify insertNL replacemode _ = delegate deletemode, yankmode, changemode, gomode :: Event -> EventMonad Event ( Editor c ) () deletemode ( EvKey ( KASCII 'k' ) [ ] ) = modify deleteUp >> unbind deletemode ( EvKey ( KASCII 'j' ) [ ] ) = modify deleteDown >> unbind deletemode ( EvKey ( KASCII 'h' ) [ ] ) = modify ( multi deleteLeft ) >> unbind deletemode ( EvKey ( KASCII 'l' ) [ ] ) = modify ( multi deleteRight ) >> unbind deletemode ( EvKey ( KASCII 'd' ) [ ] ) = modify deleteLine >> unbind deletemode ( EvKey ( KASCII 'w' ) [ ] ) = modify ( multi deleteWord ) >> unbind deletemode ( EvKey ( KASCII 'e' ) [ ] ) = modify ( multi deleteWordEnd ) >> unbind deletemode ( EvKey ( KASCII 'b' ) [ ] ) = modify ( multi deleteBackWord ) >> unbind deletemode ( EvKey ( KASCII '0' ) [ ] ) = modify deleteCursorToBegin >> unbind deletemode ( EvKey ( KASCII '$' ) [ ] ) = modify deleteCursorToEnd >> unbind deletemode ( EvKey ( KASCII 'f' ) [ ] ) = bind deletefmode deletemode ( EvKey ( KASCII 't' ) [ ] ) = bind deletetmode deletemode ( EvKey ( KASCII _ ) [ ] ) = unbind deletemode _ = delegate deletefmode, deletetmode, changefmode, changetmode :: Event -> EventMonad Event ( Editor c ) () deletefmode ( EvKey ( KASCII c ) [ ] ) = do modify $ multi $ deleteFindMore c unbind >> unbind deletefmode ( EvKey _ _ ) = unbind >> unbind deletefmode _ = delegate deletetmode ( EvKey ( KASCII c ) [ ] ) = do modify $ multi $ deleteFind c unbind >> unbind deletetmode (EvKey _ _ ) = unbind >> unbind deletetmode _ = delegate changefmode ( EvKey ( KASCII c ) [ ] ) = do modify $ multi $ deleteFindMore c _ <- unbind >> unbind key 'i' changefmode ( EvKey _ _ ) = unbind >> unbind changefmode _ = delegate changetmode ( EvKey ( KASCII c ) [ ] ) = do modify $ multi $ deleteFind c _ <- unbind >> unbind key 'i' changetmode ( EvKey _ _ ) = unbind >> unbind changetmode _ = delegate yankmode ( EvKey ( KASCII 'y' ) [ ] ) = modify yankLines >> unbind yankmode ( EvKey _ _ ) = unbind yankmode _ = delegate changemode ( EvKey ( KASCII 'w' ) [ ] ) = modify ( multi deleteWord ) >> unbind >> key 'i' changemode ( EvKey ( KASCII 'e' ) [ ] ) = modify ( multi deleteWordEnd ) >> unbind >> key 'i' changemode ( EvKey ( KASCII 'b' ) [ ] ) = modify ( multi deleteBackWord ) >> unbind >> key 'i' changemode ( EvKey ( KASCII '$' ) [ ] ) = modify inInsertMode >> modify deleteCursorToEnd >> unbind >> key 'i' changemode ( EvKey ( KASCII '0' ) [ ] ) = modify deleteCursorToBegin >> unbind >> key 'i' changemode ( EvKey ( KASCII 'c' ) [ ] ) = modify cursorTopOfLine >> modify deleteCursorToEnd >> unbind >> key 'i' changemode ( EvKey ( KASCII 'f' ) [ ] ) = bind changefmode changemode ( EvKey ( KASCII 't' ) [ ] ) = bind changetmode changemode ( EvKey _ _ ) = unbind changemode _ = delegate gomode ( EvKey ( KASCII 'g' ) [ ] ) = modify cursorToTop >> unbind gomode ( EvKey ( KASCII _ ) [ ] ) = unbind gomode _ = delegate lzmode :: Cmdbind c -> Keybind c lzmode cb ( EvKey ( KASCII 'Z' ) [ ] ) = unbind >> cb "wq" lzmode _ ( EvKey _ _ ) = unbind lzmode _ _ = delegate zmode :: Keybind c zmode ( EvKey ( KASCII '.' ) [ ] ) = unbind >> modify scrollForCursorMiddle zmode ( EvKey KEnter [ ] ) = unbind >> modify scrollForCursorHead zmode ( EvKey ( KASCII '-' ) [ ] ) = unbind >> modify scrollForCursorLast zmode ( EvKey _ _ ) = unbind zmode _ = delegate digitmode :: Event -> EventMonad Event ( Editor c ) () digitmode ( EvKey ( KASCII c ) [ ] ) | isDigit c = modify $ addTimes c | otherwise = unbind >> runEvent ( EvKey ( KASCII c ) [ ] ) digitmode EvDeleteEditor = delegate digitmode ev = unbind >> runEvent ev exmode :: Cmdbind c -> Keybind c exmode _ ( EvKey ( KASCII c ) [ MMeta ] ) = do _ <- runEvent $ EvKey KEsc [ ] runEvent $ EvKey ( KASCII c ) [ ] exmode _ ( EvKey KEsc [ ] ) = do _ <- unbind modify resetStatus exmode cb ( EvKey KEnter [ ] ) = do _ <- unbind modify resetStatus cmd <- gets getExCmd modify resetExCmd cb cmd exmode _ ( EvKey ( KASCII 'h' ) [ MCtrl ] ) = do modify bsStatus modify bsExCmd exmode _ ( EvKey ( KASCII c ) [ ] ) = do modify $ addStatus c modify $ addExCmd c exmode _ _ = return () defaultCmdbind :: Cmdbind c defaultCmdbind "q" = do m <- gets isModified if m then modify ( setStatus "modified! use wq or q!" ) else removeContainer defaultCmdbind "q!" = removeContainer defaultCmdbind "w" = modify saveToFile defaultCmdbind "wq" = do modify saveToFile modify deleteThisEditor defaultCmdbind "e!" = do fn <- gets fileName modify $ saveToEditor fn defaultCmdbind ( 'e' : ' ' : fn ) = do _ <- copyContainer modify $ saveToEditor fn defaultCmdbind cmd = modify $ setStatus $ cmd ++ " is not valid ex command" visualVmode :: Event -> EventMonad Event ( Editor c ) () visualVmode ( EvKey ( KASCII c ) [ MMeta ] ) = runEvent ( EvKey KEsc [ ] ) >> runEvent ( EvKey ( KASCII c ) [ ] ) visualVmode ( EvKey KEsc [ ] ) = modify resetVisualmode >> unbind visualVmode ( EvKey ( KASCII 'y' ) [ ] ) = do modify yankInLargeVmode unbind visualVmode ( EvKey ( KASCII 'd' ) [ ] ) = saveHistory $ do modify deleteInLargeVmode unbind visualVmode _ = delegate