hledger-iadd-1.2.3: src/Brick/Widgets/Edit/EmacsBindings.hs
{-# LANGUAGE TemplateHaskell, CPP #-}
-- | Widget like "Brick.Widgets.Edit", but with more emacs style keybindings.
--
-- This is also a complete wrapper around the "Brick.Widgets.Edit" API to retain
-- compatability with older brick versions.
--
-- See 'handleEditorEvent' for a list of added keybindings.
module Brick.Widgets.Edit.EmacsBindings
( Editor
, editorText
, getEditContents
, applyEdit
, editContentsL
, handleEditorEvent
, renderEditor
) where
import Brick
import Graphics.Vty
import qualified Brick.Widgets.Edit as E
import Data.Text.Zipper
import Data.Text (Text)
import Lens.Micro.TH
import Lens.Micro
import Data.Text.Zipper.Generic.Words
-- | Wrapper around 'E.Editor', but specialized to 'Text'
data Editor n = Editor {
_origEditor :: E.Editor Text n,
_drawingFunction :: [Text] -> Widget n
}
makeLenses ''Editor
-- | Wrapper for 'E.editorText' specialized to 'Text'
editorText :: n -> ([Text] -> Widget n)-> Maybe Int -> Text -> Editor n
editorText name draw linum content =
#if MIN_VERSION_brick(0,19,0)
Editor (E.editorText name linum content) draw
#else
Editor (E.editorText name draw linum content) draw
#endif
-- | Wrapper for 'E.getEditContents' specialized to 'Text'
getEditContents :: Editor n -> [Text]
getEditContents edit = edit ^. origEditor . to E.getEditContents
-- | Wrapper for 'E.applyEdit' specialized to 'Text'
applyEdit :: (TextZipper Text -> TextZipper Text) -> Editor n -> Editor n
applyEdit f = over origEditor (E.applyEdit f)
-- | Wrapper for 'E.editContentsL' specialized to 'Text'
editContentsL :: Lens (Editor n) (Editor n) (TextZipper Text) (TextZipper Text)
editContentsL = origEditor . E.editContentsL
-- | Same as 'E.handleEditorEvent', but with more emacs-style keybindings and
-- specialized to 'Text'
--
-- Specifically:
--
-- - Ctrl-f: Move forward one character
-- - Ctrl-b: Move backward one character
-- - Alt-f: Move forward one word
-- - Alt-b: Move backward one word
-- - Alt-Backspace: Delete the previous word
-- - Ctrl-w: Delete the previous word
-- - Alt-d: Delete the next word
handleEditorEvent :: Event -> Editor n -> EventM n (Editor n)
handleEditorEvent event edit = case event of
EvKey (KChar 'f') [MCtrl] -> return $ applyEdit moveRight edit
EvKey (KChar 'b') [MCtrl] -> return $ applyEdit moveLeft edit
EvKey (KChar 'f') [MMeta] -> return $ applyEdit moveWordRight edit
EvKey (KChar 'b') [MMeta] -> return $ applyEdit moveWordLeft edit
EvKey KBS [MMeta] -> return $ applyEdit deletePrevWord edit
EvKey (KChar 'w') [MCtrl] -> return $ applyEdit deletePrevWord edit
EvKey (KChar 'd') [MMeta] -> return $ applyEdit deleteWord edit
EvKey KHome [] -> return $ applyEdit gotoBOL edit
EvKey KEnd [] -> return $ applyEdit gotoEOL edit
_ -> do
newOrig <- E.handleEditorEvent event (edit^.origEditor)
return $ edit & origEditor .~ newOrig
-- | Wrapper for 'E.renderEditor' specialized to 'Text'
renderEditor :: (Ord n, Show n) => Bool -> Editor n -> Widget n
renderEditor focus edit =
#if MIN_VERSION_brick(0,19,0)
E.renderEditor (edit^.drawingFunction) focus (edit^.origEditor)
#else
E.renderEditor focus (edit^.origEditor)
#endif