nonrepeatableBindings :: [VimBinding]
nonrepeatableBindings = fmap (mkBindingE Normal Drop)
    [ (spec KEsc, return (), resetCount)
    , (ctrlCh 'c', return (), resetCount)

    -- Changing
    , (char 'C',
        do region <- withCurrentBuffer $ regionWithTwoMovesB (return ()) moveToEol
           void $ operatorApplyToRegionE opChange 1 $ StyledRegion Exclusive region
        , switchMode $ Insert 'C')
    , (char 's', cutCharE Forward Sticky =<< getCountE, switchMode $ Insert 's')
    , (char 'S',
        do region <- withCurrentBuffer $ regionWithTwoMovesB firstNonSpaceB moveToEol
           void $ operatorApplyToRegionE opDelete 1 $ StyledRegion Exclusive region
        , switchMode $ Insert 'S')

    -- Replacing
    , (char 'R', return (), switchMode Replace)

    -- Yanking
    , ( char 'Y'
      , do region <- withCurrentBuffer $ regionWithTwoMovesB (return ()) moveToEol
           void $ operatorApplyToRegionE opYank 1 $ StyledRegion Exclusive region
      , id
      )

    -- Search
    , (char '*', addVimJumpHereE >> searchWordE True Forward, resetCount)
    , (char '#', addVimJumpHereE >> searchWordE True Backward, resetCount)
    , (char 'n', addVimJumpHereE >> withCount (continueSearching id), resetCount)
    , (char 'N', addVimJumpHereE >> withCount (continueSearching reverseDir), resetCount)
    , (char ';', repeatGotoCharE id, id)
    , (char ',', repeatGotoCharE reverseDir, id)

    -- Repeat
    , (char '&', return (), id) -- TODO

    -- Transition to ex
    , (char ':', do
        void (spawnMinibufferE ":" id)
        historyStart
        historyPrefixSet ""
      , switchMode Ex)

    -- Undo
    , (char 'u', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id)
    , (char 'U', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id) -- TODO
    , (ctrlCh 'r', withCountOnBuffer redoB >> withCurrentBuffer leftOnEol, id)

    -- scrolling
    ,(ctrlCh 'b', getCountE >>= withCurrentBuffer . upScreensB, id)
    ,(ctrlCh 'f', getCountE >>= withCurrentBuffer . downScreensB, id)
    ,(ctrlCh 'u', getCountE >>= withCurrentBuffer . vimScrollByB (negate . (`div` 2)), id)
    ,(ctrlCh 'd', getCountE >>= withCurrentBuffer . vimScrollByB (`div` 2), id)
    ,(ctrlCh 'y', getCountE >>= withCurrentBuffer . vimScrollB . negate, id)
    ,(ctrlCh 'e', getCountE >>= withCurrentBuffer . vimScrollB, id)

    -- unsorted TODO
    , (char '-', return (), id)
    , (char '+', return (), id)
    , (spec KEnter, return (), id)
    ] <> fmap (mkStringBindingE Normal Drop)
    [ ("g*", searchWordE False Forward, resetCount)
    , ("g#", searchWordE False Backward, resetCount)
    , ("gd", withCurrentBuffer $ withModeB modeGotoDeclaration, resetCount)
    , ("gD", withCurrentBuffer $ withModeB modeGotoDeclaration, resetCount)
    , ("<C-g>", printFileInfoE, resetCount)
    , ("<C-w>c", tryCloseE, resetCount)
    , ("<C-w>o", closeOtherE, resetCount)
    , ("<C-w>s", splitE, resetCount)
    , ("<C-w>w", nextWinE, resetCount)
    , ("<C-w><Down>", nextWinE, resetCount) -- TODO: please implement downWinE
    , ("<C-w><Right>", nextWinE, resetCount) -- TODO: please implement rightWinE
    , ("<C-w><C-w>", nextWinE, resetCount)
    , ("<C-w>W", prevWinE, resetCount)
    , ("<C-w>p", prevWinE, resetCount)
    , ("<C-w><Up>", prevWinE, resetCount) -- TODO: please implement upWinE
    , ("<C-w><Left>", prevWinE, resetCount) -- TODO: please implement leftWinE
    , ("<C-w>l", layoutManagersNextE, resetCount)
    , ("<C-w>L", layoutManagersPreviousE, resetCount)
    --, ("<C-w> ", layoutManagersNextE, resetCount)
    , ("<C-w>v", layoutManagerNextVariantE, resetCount)
    , ("<C-w>V", layoutManagerPreviousVariantE, resetCount)
    , ("<C-a>", getCountE >>= withCurrentBuffer . incrementNextNumberByB, resetCount)
    , ("<C-x>", getCountE >>= withCurrentBuffer . incrementNextNumberByB . negate, resetCount)

    -- z commands
    -- TODO Add prefix count
    , ("zt", withCurrentBuffer scrollCursorToTopB, resetCount)
    , ("zb", withCurrentBuffer scrollCursorToBottomB, resetCount)
    , ("zz", withCurrentBuffer scrollToCursorB, resetCount)
    {- -- TODO Horizantal scrolling
    , ("ze", withCurrentBuffer .., resetCount)
    , ("zs", withCurrentBuffer .., resetCount)
    , ("zH", withCurrentBuffer .., resetCount)
    , ("zL", withCurrentBuffer .., resetCount)
    , ("zh", withCurrentBuffer .., resetCount)
    , ("zl", withCurrentBuffer .., resetCount)
    -}
    , ("z.", withCurrentBuffer $ scrollToCursorB >> moveToSol, resetCount)
    , ("z+", withCurrentBuffer scrollToLineBelowWindowB, resetCount)
    , ("z-", withCurrentBuffer $ scrollCursorToBottomB >> moveToSol, resetCount)
    , ("z^", withCurrentBuffer scrollToLineAboveWindowB, resetCount)
    {- -- TODO Code folding
    , ("zf", .., resetCount)
    , ("zc", .., resetCount)
    , ("zo", .., resetCount)
    , ("za", .., resetCount)
    , ("zC", .., resetCount)
    , ("zO", .., resetCount)
    , ("zA", .., resetCount)
    , ("zr", .., resetCount)
    , ("zR", .., resetCount)
    , ("zm", .., resetCount)
    , ("zM", .., resetCount)
    -}

    -- Z commands
    ] <> fmap (mkStringBindingY Normal)
    [ ("ZQ", quitEditor, id)
    -- TODO ZZ should replicate :x not :wq
    , ("ZZ", fwriteE >> closeWindow, id)
    ]
nonrepeatableBindings :: [VimBinding]
nonrepeatableBindings = fmap (mkBindingE Normal Drop)
    [ (spec KEsc, return (), resetCount)
    , (ctrlCh 'c', return (), resetCount)

    -- Changing
    , (char 'C',
        do region <- withCurrentBuffer $ regionWithTwoMovesB (return ()) moveToEol
           void $ operatorApplyToRegionE opChange 1 $ StyledRegion Exclusive region
        , switchMode $ Insert 'C')
    , (char 's', cutCharE Forward Sticky =<< getCountE, switchMode $ Insert 's')
    , (char 'S',
        do region <- withCurrentBuffer $ regionWithTwoMovesB firstNonSpaceB moveToEol
           void $ operatorApplyToRegionE opDelete 1 $ StyledRegion Exclusive region
        , switchMode $ Insert 'S')

    -- Replacing
    , (char 'R', return (), switchMode Replace)

    -- Yanking
    , ( char 'Y'
      , do region <- withCurrentBuffer $ regionWithTwoMovesB (return ()) moveToEol
           void $ operatorApplyToRegionE opYank 1 $ StyledRegion Exclusive region
      , id
      )

    -- Search
    , (char '*', addVimJumpHereE >> searchWordE True Forward, resetCount)
    , (char '#', addVimJumpHereE >> searchWordE True Backward, resetCount)
    , (char 'n', addVimJumpHereE >> withCount (continueSearching id), resetCount)
    , (char 'N', addVimJumpHereE >> withCount (continueSearching reverseDir), resetCount)
    , (char ';', repeatGotoCharE id, id)
    , (char ',', repeatGotoCharE reverseDir, id)

    -- Repeat
    , (char '&', return (), id) -- TODO

    -- Transition to ex
    , (char ':', do
        void (spawnMinibufferE ":" id)
        historyStart
        historyPrefixSet ""
      , switchMode Ex)

    -- Undo
    , (char 'u', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id)
    , (char 'U', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id) -- TODO
    , (ctrlCh 'r', withCountOnBuffer redoB >> withCurrentBuffer leftOnEol, id)

    -- scrolling
    ,(ctrlCh 'b', getCountE >>= withCurrentBuffer . upScreensB, id)
    ,(ctrlCh 'f', getCountE >>= withCurrentBuffer . downScreensB, id)
    ,(ctrlCh 'u', getCountE >>= withCurrentBuffer . vimScrollByB (negate . (`div` 2)), id)
    ,(ctrlCh 'd', getCountE >>= withCurrentBuffer . vimScrollByB (`div` 2), id)
    ,(ctrlCh 'y', getCountE >>= withCurrentBuffer . vimScrollB . negate, id)
    ,(ctrlCh 'e', getCountE >>= withCurrentBuffer . vimScrollB, id)

    -- unsorted TODO
    , (char '-', return (), id)
    , (char '+', return (), id)
    , (spec KEnter, return (), id)
    ] <> fmap (mkStringBindingE Normal Drop)
    [ ("g*", searchWordE False Forward, resetCount)
    , ("g#", searchWordE False Backward, resetCount)
    , ("gd", withCurrentBuffer $ withModeB modeGotoDeclaration, resetCount)
    , ("gD", withCurrentBuffer $ withModeB modeGotoDeclaration, resetCount)
    , ("<C-g>", printFileInfoE, resetCount)
    , ("<C-w>c", tryCloseE, resetCount)
    , ("<C-w>o", closeOtherE, resetCount)
    , ("<C-w>s", splitE, resetCount)
    , ("<C-w>w", nextWinE, resetCount)
    , ("<C-w><Down>", nextWinE, resetCount) -- TODO: please implement downWinE
    , ("<C-w><Right>", nextWinE, resetCount) -- TODO: please implement rightWinE
    , ("<C-w><C-w>", nextWinE, resetCount)
    , ("<C-w>W", prevWinE, resetCount)
    , ("<C-w>p", prevWinE, resetCount)
    , ("<C-w><Up>", prevWinE, resetCount) -- TODO: please implement upWinE
    , ("<C-w><Left>", prevWinE, resetCount) -- TODO: please implement leftWinE
    , ("<C-w>l", layoutManagersNextE, resetCount)
    , ("<C-w>L", layoutManagersPreviousE, resetCount)
    --, ("<C-w> ", layoutManagersNextE, resetCount)
    , ("<C-w>v", layoutManagerNextVariantE, resetCount)
    , ("<C-w>V", layoutManagerPreviousVariantE, resetCount)
    , ("<C-a>", getCountE >>= withCurrentBuffer . incrementNextNumberByB, resetCount)
    , ("<C-x>", getCountE >>= withCurrentBuffer . incrementNextNumberByB . negate, resetCount)

    -- z commands
    -- TODO Add prefix count
    , ("zt", withCurrentBuffer scrollCursorToTopB, resetCount)
    , ("zb", withCurrentBuffer scrollCursorToBottomB, resetCount)
    , ("zz", withCurrentBuffer scrollToCursorB, resetCount)
    {- -- TODO Horizantal scrolling
    , ("ze", withCurrentBuffer .., resetCount)
    , ("zs", withCurrentBuffer .., resetCount)
    , ("zH", withCurrentBuffer .., resetCount)
    , ("zL", withCurrentBuffer .., resetCount)
    , ("zh", withCurrentBuffer .., resetCount)
    , ("zl", withCurrentBuffer .., resetCount)
    -}
    , ("z.", withCurrentBuffer $ scrollToCursorB >> moveToSol, resetCount)
    , ("z+", withCurrentBuffer scrollToLineBelowWindowB, resetCount)
    , ("z-", withCurrentBuffer $ scrollCursorToBottomB >> moveToSol, resetCount)
    , ("z^", withCurrentBuffer scrollToLineAboveWindowB, resetCount)
    {- -- TODO Code folding
    , ("zf", .., resetCount)
    , ("zc", .., resetCount)
    , ("zo", .., resetCount)
    , ("za", .., resetCount)
    , ("zC", .., resetCount)
    , ("zO", .., resetCount)
    , ("zA", .., resetCount)
    , ("zr", .., resetCount)
    , ("zR", .., resetCount)
    , ("zm", .., resetCount)
    , ("zM", .., resetCount)
    -}

    -- Z commands
    ] <> fmap (mkStringBindingY Normal)
    [ ("ZQ", quitEditor, id)
    -- TODO ZZ should replicate :x not :wq
    , ("ZZ", fwriteE >> closeWindow, id)
    ]
nonrepeatableBindings = fmap (mkBindingE Normal Drop)
    [ (spec KEsc, return (), resetCount)
    , (ctrlCh 'c', return (), resetCount)

    -- Changing
    , (char 'C',
        do region <- withCurrentBuffer $ regionWithTwoMovesB (return ()) moveToEol
           void $ operatorApplyToRegionE opChange 1 $ StyledRegion Exclusive region
        , switchMode $ Insert 'C')
    , (char 's', cutCharE Forward Sticky =<< getCountE, switchMode $ Insert 's')
    , (char 'S',
        do region <- withCurrentBuffer $ regionWithTwoMovesB firstNonSpaceB moveToEol
           void $ operatorApplyToRegionE opDelete 1 $ StyledRegion Exclusive region
        , switchMode $ Insert 'S')

    -- Replacing
    , (char 'R', return (), switchMode Replace)

    -- Yanking
    , ( char 'Y'
      , do region <- withCurrentBuffer $ regionWithTwoMovesB (return ()) moveToEol
           void $ operatorApplyToRegionE opYank 1 $ StyledRegion Exclusive region
      , id
      )

    -- Search
    , (char '*', addVimJumpHereE >> searchWordE True Forward, resetCount)
    , (char '#', addVimJumpHereE >> searchWordE True Backward, resetCount)
    , (char 'n', addVimJumpHereE >> withCount (continueSearching id), resetCount)
    , (char 'N', addVimJumpHereE >> withCount (continueSearching reverseDir), resetCount)
    , (char ';', repeatGotoCharE id, id)
    , (char ',', repeatGotoCharE reverseDir, id)

    -- Repeat
    , (char '&', return (), id) -- TODO

    -- Transition to ex
    , (char ':', do
        void (spawnMinibufferE ":" id)
        historyStart
        historyPrefixSet ""
      , switchMode Ex)

    -- Undo
    , (char 'u', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id)
    , (char 'U', withCountOnBuffer undoB >> withCurrentBuffer leftOnEol, id) -- TODO
    , (ctrlCh 'r', withCountOnBuffer redoB >> withCurrentBuffer leftOnEol, id)

    -- scrolling
    ,(ctrlCh 'b', getCountE >>= withCurrentBuffer . upScreensB, id)
    ,(ctrlCh 'f', getCountE >>= withCurrentBuffer . downScreensB, id)
    ,(ctrlCh 'u', getCountE >>= withCurrentBuffer . vimScrollByB (negate . (`div` 2)), id)
    ,(ctrlCh 'd', getCountE >>= withCurrentBuffer . vimScrollByB (`div` 2), id)
    ,(ctrlCh 'y', getCountE >>= withCurrentBuffer . vimScrollB . negate, id)
    ,(ctrlCh 'e', getCountE >>= withCurrentBuffer . vimScrollB, id)

    -- unsorted TODO
    , (char '-', return (), id)
    , (char '+', return (), id)
    , (spec KEnter, return (), id)
    ] <> fmap (mkStringBindingE Normal Drop)
    [ ("g*", searchWordE False Forward, resetCount)
    , ("g#", searchWordE False Backward, resetCount)
    , ("gd", withCurrentBuffer $ withModeB modeGotoDeclaration, resetCount)
    , ("gD", withCurrentBuffer $ withModeB modeGotoDeclaration, resetCount)
    , ("<C-g>", printFileInfoE, resetCount)
    , ("<C-w>c", tryCloseE, resetCount)
    , ("<C-w>o", closeOtherE, resetCount)
    , ("<C-w>s", splitE, resetCount)
    , ("<C-w>w", nextWinE, resetCount)
    , ("<C-w><Down>", nextWinE, resetCount) -- TODO: please implement downWinE
    , ("<C-w><Right>", nextWinE, resetCount) -- TODO: please implement rightWinE
    , ("<C-w><C-w>", nextWinE, resetCount)
    , ("<C-w>W", prevWinE, resetCount)
    , ("<C-w>p", prevWinE, resetCount)
    , ("<C-w><Up>", prevWinE, resetCount) -- TODO: please implement upWinE
    , ("<C-w><Left>", prevWinE, resetCount) -- TODO: please implement leftWinE
    , ("<C-w>l", layoutManagersNextE, resetCount)
    , ("<C-w>L", layoutManagersPreviousE, resetCount)
    --, ("<C-w> ", layoutManagersNextE, resetCount)
    , ("<C-w>v", layoutManagerNextVariantE, resetCount)
    , ("<C-w>V", layoutManagerPreviousVariantE, resetCount)
    , ("<C-a>", getCountE >>= withCurrentBuffer . incrementNextNumberByB, resetCount)
    , ("<C-x>", getCountE >>= withCurrentBuffer . incrementNextNumberByB . negate, resetCount)

    -- z commands
    -- TODO Add prefix count
    , ("zt", withCurrentBuffer scrollCursorToTopB, resetCount)
    , ("zb", withCurrentBuffer scrollCursorToBottomB, resetCount)
    , ("zz", withCurrentBuffer scrollToCursorB, resetCount)
    {- -- TODO Horizantal scrolling
    , ("ze", withCurrentBuffer .., resetCount)
    , ("zs", withCurrentBuffer .., resetCount)
    , ("zH", withCurrentBuffer .., resetCount)
    , ("zL", withCurrentBuffer .., resetCount)
    , ("zh", withCurrentBuffer .., resetCount)
    , ("zl", withCurrentBuffer .., resetCount)
    -}
    , ("z.", withCurrentBuffer $ scrollToCursorB >> moveToSol, resetCount)
    , ("z+", withCurrentBuffer scrollToLineBelowWindowB, resetCount)
    , ("z-", withCurrentBuffer $ scrollCursorToBottomB >> moveToSol, resetCount)
    , ("z^", withCurrentBuffer scrollToLineAboveWindowB, resetCount)
    {- -- TODO Code folding
    , ("zf", .., resetCount)
    , ("zc", .., resetCount)
    , ("zo", .., resetCount)
    , ("za", .., resetCount)
    , ("zC", .., resetCount)
    , ("zO", .., resetCount)
    , ("zA", .., resetCount)
    , ("zr", .., resetCount)
    , ("zR", .., resetCount)
    , ("zm", .., resetCount)
    , ("zM", .., resetCount)
    -}

    -- Z commands
    ] <> fmap (mkStringBindingY Normal)
    [ ("ZQ", quitEditor, id)
    -- TODO ZZ should replicate :x not :wq
    , ("ZZ", fwriteE >> closeWindow, id)
    ]