packages feed

yi-0.4: Yi/Keymap/Users/JP.hs

{-# LANGUAGE FlexibleContexts #-}
module Yi.Keymap.Users.JP where
-- This is an attempt at a completely "normalized" keymap.
-- Choose your mode/unit with the left hand;
-- Perform commands with the right hand.

import Prelude hiding (error)
import Control.Monad.State
import Data.Char
import Yi.Keymap.Keys
import Yi.Keymap.Emacs.Utils (insertSelf)
import Yi
import qualified Yi.Interact as I (choice, I())

-- | Enhanced keymap type, where the current unit is remembered using a StateT
type KM a = (StateT (TextUnit, String) (I.I Event Action)) a


{-
  We'll assume QWERTY layout:

qqq www eee rrr ttt yyy uuu iii ooo ppp
 aaa sss ddd fff ggg hhh jjj kkk lll ;;;
  zzz xxx ccc vvv bbb nnn mmm ,,, ... ///
-}

-- | Keyboard layout definition
leftHand, rightHand :: [String]
leftHand = ["qwert", "asdfg", "zxcvb"]
rightHand = ["yuiop", "hjkl;", "nm,./"]

-- data Mark = Paste | SetMark | Cut | Copy | SwitchMark
-- data Special = Complete | Undo | Indent | Search

-- Special shift for events that understands qwerty layout.
shi_ (Event (KASCII c) ms) | isAlpha c = Event (KASCII (toUpper c)) ms
shi_ (Event (KASCII ',') ms)  = Event (KASCII '<') ms
shi_ (Event (KASCII '.') ms)  = Event (KASCII '>') ms
shi_ (Event (KASCII '/') ms)  = Event (KASCII '?') ms
shi_ (Event (KASCII ';') ms)  = Event (KASCII ':') ms
shi_ (Event (KASCII '\'') ms)  = Event (KASCII '"') ms
shi_ (Event (KASCII '[') ms)  = Event (KASCII '{') ms
shi_ (Event (KASCII ']') ms)  = Event (KASCII '}') ms
shi_ _ = error "shi_: unhandled event"                          


selfInsertKeymap :: KM ()
selfInsertKeymap = do
  c <- printableChar
  write (insertSelf c)

retKeymap :: KM ()
retKeymap = do
  Event KEnter [] <- anyEvent
  write (insertSelf '\n')

insertKeymap :: KM ()
insertKeymap = do
  event $ char 'g'
  write $ msgEditor "-- INSERT --"
  many $ do
    write $ msgEditor "-- INSERT --"
    (selfInsertKeymap <|> retKeymap <|> quickCmdKeymap) <|| unrecognized
  quitInsert
  return ()

quitInsert = oneOf [ctrl $ spec KEnter, spec KEsc]

quickCmdKeymap :: KM ()
quickCmdKeymap =     mkCmdKeymap (return Character)  ctrl
                 <|> mkCmdKeymap (return Word)      (ctrl . shi_)

quitKeymap :: KM ()
quitKeymap = do
  Event KEsc [] <- anyEvent
  write quitEditor

unrecognized :: KM ()
unrecognized = do
  e <- anyEvent
  write (msgEditor $ "unrecognized: " ++ show e)

commandsKeymap :: KM ()
commandsKeymap = do
  (_, unitName) <- get
  write $ msgEditor $ "-- CMD: " ++ unitName
  quitKeymap <|| (I.choice $ insertKeymap : cmds : concat unts)
    where
      cmds = mkCmdKeymap (fst <$> get) id
      unts = zipWith (zipWith mkUnt) units leftHand
      mkUnt unt ch = do
        event $ char ch
        put unt

mkCmdKeymap :: KM TextUnit -> (Event -> Event) -> KM ()
mkCmdKeymap getUnit mods = I.choice $ concat $ zipWith (zipWith mkCmd) commands rightHand
    where mkCmd cmd ch = do
            event $ mods $ char ch
            unt <- getUnit
            write (cmd unt)

keymap :: Keymap
keymap = runKM $ forever commandsKeymap


{-
Commands: (right hand)


                cop  cut del del com
                 pop  pas mov mov sea '''
                  mpp  mxp xpo xpo und

com: complete
und: undo
sea: start incremental search of the Unit at point
pop: pop-yank
pas: paste
xpo: transpose in given direction
''': search start from empty
mxp: exchange point and mark
mpp: mark pop
cop: copy

-}

commands :: [[TextUnit -> BufferM ()]]
commands = [[copy, cut,   del  b, del f,  complete],
            [pop,  paste, move b, move f, search],
            [mpp,  mxp,   xpo  b, xpo  f, undo]]
    where copy = todo
          cut = todo
          pop = todo
          mpp = todo
          mxp = todo
          complete = todo
          paste = todo
          search = todo
          undo = const undoB
          move dir u = moveB u dir
          del dir u = deleteB u dir
          xpo dir u = transposeB u dir
          b = Backward
          f = Forward
          todo = \_ -> return ()


{-
Units: (left hand)


doc pag col ver   ovr
 par lin wor cha   ins
  *** *** *** sea   buf
-}

document, page, column :: TextUnit
document = Character
page = Character
column = Character

units :: [[(TextUnit, String)]]
units = [
         [(document, "DOC"), (page, "PAGE"), (column, "COL"), (VLine, "↕")],
         [(unitParagraph, "§"), (Line, "Line"), (Word, "Word"), (Character, "Char")]
        ]

runKM :: KM () -> Keymap
runKM p = fmap fst $ runStateT p (Character, "Char")

{-
ins: go to insert mode
ovr: go to overwrite mode
sea: navigate searched items.


... free
*** reserved for normal emacs usage.

----------


C-: briefly switch to character mode
M-: briefly switch to word mode

C-mode: go to that mode

-}