WEditorBrick 0.1.0.0 → 0.2.0.0
raw patch · 4 files changed
+163/−41 lines, 4 filesdep +WEditorBrickdep ~WEditordep ~basedep ~bricknew-component:exe:brick-examplePVP ok
version bump matches the API change (PVP)
Dependencies added: WEditorBrick
Dependency ranges changed: WEditor, base, brick, vty
API changes (from Hackage documentation)
- WEditorBrick.WrappingEditor: doWrappingEditor :: WrappingEditorDoer c b -> WrappingEditor c n -> b
- WEditorBrick.WrappingEditor: dumpWrappingEditor :: WrappingEditor c n -> [[c]]
- WEditorBrick.WrappingEditor: genericWrappingEditor :: (FixedFontViewer a c, FixedFontEditor a c) => n -> a -> WrappingEditor c n
- WEditorBrick.WrappingEditor: handleWrappingEditor :: Eq n => WrappingEditor Char n -> Event -> EventM n (WrappingEditor Char n)
- WEditorBrick.WrappingEditor: mapWrappingEditor :: WrappingEditorAction c -> WrappingEditor c n -> WrappingEditor c n
- WEditorBrick.WrappingEditor: newWrappingEditor :: FixedFontParser a c => a -> n -> [[c]] -> WrappingEditor c n
- WEditorBrick.WrappingEditor: renderWrappingEditor :: (Ord n, Show n) => Bool -> WrappingEditor Char n -> Widget n
+ WEditorBrick.WrappingEditor: doEditor :: WrappingEditorDoer c b -> WrappingEditor c n -> b
+ WEditorBrick.WrappingEditor: dumpEditor :: WrappingEditor c n -> [[c]]
+ WEditorBrick.WrappingEditor: genericEditor :: (FixedFontViewer a c, FixedFontEditor a c) => n -> a -> WrappingEditor c n
+ WEditorBrick.WrappingEditor: handleEditor :: Eq n => WrappingEditor Char n -> Event -> EventM n (WrappingEditor Char n)
+ WEditorBrick.WrappingEditor: mapEditor :: WrappingEditorAction c -> WrappingEditor c n -> WrappingEditor c n
+ WEditorBrick.WrappingEditor: newEditor :: FixedFontParser a c => a -> n -> [[c]] -> WrappingEditor c n
+ WEditorBrick.WrappingEditor: renderEditor :: (Ord n, Show n) => Bool -> WrappingEditor Char n -> Widget n
+ WEditorBrick.WrappingEditor: updateEditorExtent :: Eq n => WrappingEditor c n -> EventM n (WrappingEditor c n)
Files
- ChangeLog.md +8/−0
- WEditorBrick.cabal +21/−4
- WEditorBrick/WrappingEditor.hs +61/−37
- example/brick-example.hs +73/−0
ChangeLog.md view
@@ -1,5 +1,13 @@ # Revision history for WEditorBrick +## 0.2.0.0 -- 2020-04-17++* **[breaking]** Shortens function names in the `WrappingEditor` module.++* **[new]** Adds `updateEditorExtent` to better support custom event-handlers.++* **[behavior]** Adds key bindings for vertical scrolling actions.+ ## 0.1.0.0 -- 2020-04-14 * First version. Released on an unsuspecting world.
WEditorBrick.cabal view
@@ -1,5 +1,5 @@ name: WEditorBrick-version: 0.1.0.0+version: 0.2.0.0 synopsis: Text-editor widget with dynamic line-wrapping for use with Brick. description:@@ -13,8 +13,9 @@ license: Apache-2.0 license-file: LICENSE author: Kevin P. Barry-maintainer: ta0kira@gmail.com-category: Text+maintainer: Kevin P. Barry <ta0kira@gmail.com>+copyright: (c) Kevin P. Barry 2020+category: Graphics build-type: Simple cabal-version: 2.0@@ -36,6 +37,22 @@ brick >= 0.47 && < 0.53, vty >= 5.24, microlens >= 0.3,- WEditor >= 0.1 && < 0.2+ WEditor >= 0.2 && < 0.3++ default-language: Haskell2010+++executable brick-example+ hs-source-dirs: example++ main-is: brick-example.hs++ ghc-options: -threaded++ build-depends: base,+ brick,+ vty,+ WEditorBrick,+ WEditor default-language: Haskell2010
WEditorBrick/WrappingEditor.hs view
@@ -30,13 +30,14 @@ WrappingEditor, WrappingEditorAction, WrappingEditorDoer,- doWrappingEditor,- dumpWrappingEditor,- genericWrappingEditor,- handleWrappingEditor,- mapWrappingEditor,- newWrappingEditor,- renderWrappingEditor,+ doEditor,+ dumpEditor,+ genericEditor,+ handleEditor,+ mapEditor,+ newEditor,+ renderEditor,+ updateEditorExtent, ) where import Brick.Main@@ -49,35 +50,35 @@ -- | Create a new 'WrappingEditor' using the default editor component.-newWrappingEditor :: FixedFontParser a c => a -> n -> [[c]] -> WrappingEditor c n-newWrappingEditor b n cs = genericWrappingEditor n $ editDocument b $ map UnparsedPara cs+newEditor :: FixedFontParser a c => a -> n -> [[c]] -> WrappingEditor c n+newEditor b n cs = genericEditor n $ editDocument b $ map UnparsedPara cs -- | Create a new 'WrappingEditor' using a custom editor component.-genericWrappingEditor :: (FixedFontViewer a c, FixedFontEditor a c) => n -> a -> WrappingEditor c n-genericWrappingEditor = WrappingEditor+genericEditor :: (FixedFontViewer a c, FixedFontEditor a c) => n -> a -> WrappingEditor c n+genericEditor = WrappingEditor -- | Any action that updates the editor state. type WrappingEditorAction c = forall a. (FixedFontViewer a c, FixedFontEditor a c) => a -> a -- | Update the editor state.-mapWrappingEditor :: WrappingEditorAction c -> WrappingEditor c n -> WrappingEditor c n-mapWrappingEditor f (WrappingEditor name editor) = WrappingEditor name (f editor)+mapEditor :: WrappingEditorAction c -> WrappingEditor c n -> WrappingEditor c n+mapEditor f (WrappingEditor name editor) = WrappingEditor name (f editor) -- | Any action that reads the editor state. type WrappingEditorDoer c b = forall a. (FixedFontViewer a c, FixedFontEditor a c) => a -> b -- | Read from the editor state.-doWrappingEditor :: WrappingEditorDoer c b -> WrappingEditor c n -> b-doWrappingEditor f (WrappingEditor _ editor) = f editor+doEditor :: WrappingEditorDoer c b -> WrappingEditor c n -> b+doEditor f (WrappingEditor _ editor) = f editor -- | Dump the final contents of the edited document.-dumpWrappingEditor :: WrappingEditor c n -> [[c]]-dumpWrappingEditor = map upText . doWrappingEditor exportData+dumpEditor :: WrappingEditor c n -> [[c]]+dumpEditor = map upText . doEditor exportData -- | Render the editor as a 'Widget'.-renderWrappingEditor :: (Ord n, Show n) => Bool -> WrappingEditor Char n -> Widget n-renderWrappingEditor focus editor = doWrappingEditor edit editor where- edit e = Widget Greedy Greedy $ do+renderEditor :: (Ord n, Show n) => Bool -> WrappingEditor Char n -> Widget n+renderEditor focus editor = doEditor view editor where+ view e = Widget Greedy Greedy $ do ctx <- getContext let width = ctx^.availWidthL let height = ctx^.availHeightL@@ -93,29 +94,52 @@ strFill w cs = str $ take w $ cs ++ repeat ' ' lineFill w h ls = take h $ ls ++ repeat (strFill w "") +-- | Updates the viewport size based on the most-recent rendering of the editor.+--+-- Call this before any custom event-handling logic so that the viewport is+-- the correct size. This will ensure that vertical cursor movements match+-- what the user expects.+updateEditorExtent :: Eq n => WrappingEditor c n -> (EventM n (WrappingEditor c n))+updateEditorExtent editor = do+ extent <- lookupExtent (getName editor)+ return $ mapEditor (resize extent) editor where+ resize (Just ext) | snd (extentSize ext) > 0 = viewerResizeAction (extentSize ext)+ resize _ = id+ -- | Update the editor based on Brick events.-handleWrappingEditor :: (Eq n) => WrappingEditor Char n -> Event -> EventM n (WrappingEditor Char n)-handleWrappingEditor editor event = do+--+-- In addition to the canonical typing events, this editor also supports:+--+-- * `PageUp`, `PageDown`, `Home`, and `End` keys.+-- * `Alt`+`Up` shifts the view upward one line.+-- * `Alt`+`Down` shifts the view downward one line.+-- * `Alt`+`Home` shifts the view to hide empty space at the bottom.+--+-- To disable or override any of these keys, intercept them in the main+-- handler for the `App`.+handleEditor :: Eq n => WrappingEditor Char n -> Event -> EventM n (WrappingEditor Char n)+handleEditor editor event = do extent <- lookupExtent (getName editor)- return $ mapWrappingEditor (action . resizeAction extent) editor where- action :: EditorAction Char+ updateEditorExtent editor >>= return . mapEditor action where+ action :: WrappingEditorAction Char action = case event of- EvKey KBS [] -> editorBackspaceAction- EvKey KDel [] -> editorDeleteAction- EvKey KDown [] -> editorDownAction- EvKey KEnd [] -> editorEndAction- EvKey KEnter [] -> editorEnterAction- EvKey KHome [] -> editorHomeAction- EvKey KLeft [] -> editorLeftAction- EvKey KPageDown [] -> editorPageDownAction- EvKey KPageUp [] -> editorPageUpAction- EvKey KRight [] -> editorRightAction- EvKey KUp [] -> editorUpAction+ EvKey KBS [] -> editorBackspaceAction+ EvKey KDel [] -> editorDeleteAction+ EvKey KDown [] -> editorDownAction+ EvKey KEnd [] -> editorEndAction+ EvKey KEnter [] -> editorEnterAction+ EvKey KHome [] -> editorHomeAction+ EvKey KLeft [] -> editorLeftAction+ EvKey KPageDown [] -> editorPageDownAction+ EvKey KPageUp [] -> editorPageUpAction+ EvKey KRight [] -> editorRightAction+ EvKey KUp [] -> editorUpAction+ EvKey KDown [MMeta] -> viewerShiftDownAction 1+ EvKey KUp [MMeta] -> viewerShiftUpAction 1+ EvKey KHome [MMeta] -> viewerFillAction EvKey (KChar c) [] | not (c `elem` "\t\r\n") -> editorAppendAction [c] _ -> id- resizeAction (Just ext) | snd (extentSize ext) > 0 = viewerResizeAction (extentSize ext)- resizeAction _ = id -- | Editor widget for use with Brick. data WrappingEditor c n =
+ example/brick-example.hs view
@@ -0,0 +1,73 @@+{- -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++import Data.Maybe+import System.Environment+import System.Exit+import System.IO++import Brick.AttrMap+import Brick.Main+import Brick.Types+import Graphics.Vty (defAttr)+import Graphics.Vty.Input+import WEditor.LineWrap -- For the line-wrapping policy.+import WEditorBrick.WrappingEditor -- For the wrapping editor Brick widget.+++-- Delegate most events to a single handler.+handleEventsWith _ x (VtyEvent (EvKey KEsc [])) = halt x+handleEventsWith handler x (VtyEvent e) = continue =<< handler x e++-- An app containing nothing but a single editor widget.+app = App {+ -- renderEditor renders the current editor in a viewport with the same name as+ -- the editor. True means that the editor has focus.+ appDraw = \edit -> [renderEditor True edit],+ appChooseCursor = const listToMaybe,+ -- handleEditor handles editor events such as cursor movements and typing.+ appHandleEvent = handleEventsWith handleEditor,+ appStartEvent = return,+ appAttrMap = const (attrMap defAttr [])+}++-- Loads the filename, runs the editor, and returns the final data.+-- NOTE: This *doesn't* modify the contents of the file.+fakeEditFile f = do+ contents <- fmap lines $ readFile f+ -- newEditor creates an editor object. breakWords is semi-aware of words, and+ -- lazyHyphen performs hyphenation.+ let editor = newEditor (breakWords lazyHyphen) "editor" contents+ -- dumpEditor extracts the editor's contents.+ modified <- defaultMain app editor >>= return . dumpEditor+ return $ unlines modified++main = do+ args <- getArgs+ case args of+ [f] -> do+ result <- fakeEditFile f+ hPutStr stdout result+ exitSuccess+ _ -> do+ hPutStrLn stderr "Pass a single filename, or call fakeEditFile from ghci."+ exitFailure