packages feed

WEditor 0.1.0.0 → 0.2.0.0

raw patch · 18 files changed

+209/−50 lines, 18 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- WEditor.Base.Parser: defaultBreak :: FixedFontParser a c => a -> BreakType a
+ WEditor.Base.Parser: splitLine :: FixedFontParser a c => a -> Int -> VisibleLine c (BreakType a) -> (VisibleLine c (BreakType a), VisibleLine c (BreakType a))
+ WEditor.Base.Viewer: FillView :: ViewAction
+ WEditor.Base.Viewer: ShiftVertical :: Int -> ViewAction
+ WEditor.Base.Viewer: data ViewAction
+ WEditor.Base.Viewer: instance GHC.Classes.Eq WEditor.Base.Viewer.ViewAction
+ WEditor.Base.Viewer: instance GHC.Show.Show WEditor.Base.Viewer.ViewAction
+ WEditor.Base.Viewer: updateView :: FixedFontViewer a c => a -> ViewAction -> a
+ WEditor.Base.Viewer: viewerFillAction :: ViewerAction c
+ WEditor.Base.Viewer: viewerShiftDownAction :: Int -> ViewerAction c
+ WEditor.Base.Viewer: viewerShiftUpAction :: Int -> ViewerAction c
+ WEditor.Document: updateView :: FixedFontViewer a c => a -> ViewAction -> a
+ WEditor.Document: viewerFillAction :: ViewerAction c
+ WEditor.Document: viewerShiftDownAction :: Int -> ViewerAction c
+ WEditor.Document: viewerShiftUpAction :: Int -> ViewerAction c

Files

ChangeLog.md view
@@ -1,5 +1,17 @@ # Revision history for WEditor +## 0.2.0.0  -- 2020-04-17++* **[breaking]** Adds line-splitting to `FixedFontParser` requirements. This+  ensures that a custom parser that formats the front of the line (e.g., adding+  block indentation) works properly when paragraph breaks are inserted. This+  does not affect compilation or behavior of code that isn't using custom+  line-wrapping policies.++* **[breaking]** Adds vertical shifting of the viewable text area. This only+  affects compilation of custom `FixedFontViewer`, and otherwise extends the+  available functionality of existing code.+ ## 0.1.0.0  -- 2020-04-14  * First version. Released on an unsuspecting world.
WEditor.cabal view
@@ -1,5 +1,5 @@ name:                WEditor-version:             0.1.0.0+version:             0.2.0.0 synopsis:            Generic text-editor logic for use with fixed-width fonts.  description:@@ -10,14 +10,15 @@   .   * Dynamic line wrapping that preserves the cursor and edit positions.   * Customizable line-wrapping policies and word-hyphenation policies.-  * Automatic management of a fixed-size viewable area.+  * Automatic management of a dynamically-sized viewable area.   * Support for novel character types.  homepage:            https://github.com/ta0kira/wrapping-editor license:             Apache-2.0 license-file:        LICENSE author:              Kevin P. Barry-maintainer:          ta0kira@gmail.com+maintainer:          Kevin P. Barry <ta0kira@gmail.com>+copyright:           (c) Kevin P. Barry 2020 category:            Text build-type:          Simple 
WEditor/Base/Line.hs view
@@ -32,8 +32,3 @@     vlText :: [c] -- ^ The complete data of the line.   }   deriving (Eq,Ord,Show)---- | Break type that has a default.-class DefaultBreak b where-  -- | The default break for the break type.-  defaultBreak :: b
WEditor/Base/Parser.hs view
@@ -26,7 +26,6 @@  module WEditor.Base.Parser (   FixedFontParser(..),-  emptyLine, ) where  import WEditor.Base.Line@@ -36,8 +35,6 @@ class FixedFontParser a c | a -> c where   -- | Type used to differentiate between line-break types.   type BreakType a :: *-  -- | An acceptable fallback line-break type.-  defaultBreak :: a -> BreakType a   -- | Change the max line width used for parsing. A width of zero must result   --   in breakLines skipping line breaks.   setLineWidth :: a -> Int -> a@@ -51,13 +48,17 @@   --   Implement 'renderLine' and 'tweakCursor' to make visual adjustments (such   --   as adding hyphens or indentation) if necessary.   breakLines :: a -> [c] -> [VisibleLine c (BreakType a)]+  -- | A place-holder line for empty paragraphs.+  emptyLine :: a -> VisibleLine c (BreakType a)   -- | Render the line for viewing. Implement 'tweakCursor' if 'renderLine'   --   changes the positions of any characters on the line.   renderLine :: a -> VisibleLine c (BreakType a) -> [c]   -- | Adjust the horizontal cursor position.   tweakCursor :: a -> VisibleLine c (BreakType a) -> Int -> Int   tweakCursor _ _ = id---- | Create an empty line.-emptyLine :: FixedFontParser a c => a -> VisibleLine c (BreakType a)-emptyLine p = VisibleLine (defaultBreak p) []+  -- | Split the line to create a paragraph break.+  splitLine :: a+            -> Int                           -- ^ Index to split at.+            -> VisibleLine c (BreakType a)   -- ^ Line to split.+            -> (VisibleLine c (BreakType a),+                VisibleLine c (BreakType a)) -- ^ End of original paragraph and beginning of next paragraph.
WEditor/Base/Viewer.hs view
@@ -25,25 +25,48 @@  module WEditor.Base.Viewer (   FixedFontViewer(..),+  ViewAction(..),   ViewerAction,+  viewerFillAction,   viewerResizeAction,+  viewerShiftUpAction,+  viewerShiftDownAction, ) where   -- | Generic editor viewport for fixed-width fonts. class FixedFontViewer a c | a -> c where-  -- | Sets the (width,height) size of the viewport. A width < 0 must disable+  -- | Set the (width,height) size of the viewport. A width < 0 must disable   --   line wrapping, and a height < 0 must disable vertical bounding.   setViewSize :: a -> (Int,Int) -> a-  -- | Gets the (width,height) size of the viewport.+  -- | Get the (width,height) size of the viewport.   getViewSize :: a -> (Int,Int)-  -- | Gets the visible lines in the viewport. This does not need to completely+  -- | Get the visible lines in the viewport. This does not need to completely   --   fill the viewport area, but it must not exceed it.   getVisible :: a -> [[c]]+  -- | Apply a view change.+  updateView :: a -> ViewAction -> a +-- | Actions that modify the view without affecting editing.+data ViewAction =+  ShiftVertical Int | -- ^ Shift the vertical offset. Negative values shift up.+  FillView            -- ^ Attempt to fill the entire viewport.+    deriving (Eq,Show)+ -- | Any action that updates a 'FixedFontViewer'. type ViewerAction c = forall a. FixedFontViewer a c => a -> a  -- | Action to resize the viewport. viewerResizeAction :: (Int,Int) -> ViewerAction c viewerResizeAction s v = setViewSize v s++-- | Action to shift the view upward.+viewerShiftUpAction :: Int -> ViewerAction c+viewerShiftUpAction n v = updateView v (ShiftVertical (-n))++-- | Action to shift the view downward.+viewerShiftDownAction :: Int -> ViewerAction c+viewerShiftDownAction n v = updateView v (ShiftVertical n)++viewerFillAction :: ViewerAction c+viewerFillAction v = updateView v FillView
WEditor/Document.hs view
@@ -51,7 +51,10 @@   editorRightAction,   editorSetPositionAction,   editorUpAction,+  viewerFillAction,   viewerResizeAction,+  viewerShiftUpAction,+  viewerShiftDownAction,   -- <<< From Base ) where @@ -61,6 +64,9 @@   -- | Generic document editor with a dynamic viewport.+--+--   This editor bounds vertical view scrolling (see 'ViewAction') to keep the+--   cursor within view. data EditingDocument c =   forall a. FixedFontParser a c => EditingDocument {     edBefore :: [VisibleParaBefore c (BreakType a)],  -- Reversed.@@ -108,6 +114,7 @@     | otherwise = d   getViewSize d = (edWidth d,edHeight d)   getVisible = getVisibleLines+  updateView = flip updateDocView  instance FixedFontEditor (EditingDocument c) c where   editText da m d = storeCursor $ modifyDoc m d da@@ -162,14 +169,19 @@ resizeHeight h da@(EditingDocument bs e as w _ k c p) =   (EditingDocument bs e as w h offset c p) where     offset-      | h < 1 = countLinesAbove da-      | otherwise = boundOffset h $ min (countLinesAbove da) k+      | h < 1 = paraLinesBefore da+      | otherwise = boundOffset h $ min (paraLinesBefore da) k -countLinesAbove :: EditingDocument c -> Int-countLinesAbove (EditingDocument bs e _ _ _ _ _ _) = total where+paraLinesBefore :: EditingDocument c -> Int+paraLinesBefore (EditingDocument bs e _ _ _ _ _ _) = total where   total = countLinesBefore bs'   bs' = getBeforeLines e:bs +paraLinesAfter :: EditingDocument c -> Int+paraLinesAfter (EditingDocument _ e as _ _ _ _ _) = total where+  total = countLinesAfter as'+  as' = getAfterLines e:as+ getVisibleLines :: EditingDocument c -> [[c]] getVisibleLines (EditingDocument bs e as _ h k _ p) = visible where   visible = map (renderLine p) $ bs2 ++ [e2] ++ as2@@ -260,3 +272,17 @@  setDocEditPoint :: (Int,Int) -> EditingDocument c -> EditingDocument c setDocEditPoint (p,c) = setEditChar c . setEditPara p++updateDocView :: ViewAction -> EditingDocument c -> EditingDocument c+updateDocView _ da@(EditingDocument _ _ _ _ h _ _ _) | h <= 0 = da+updateDocView FillView da@(EditingDocument bs e as w h k c p) = revised where+  revised = EditingDocument bs e as w h (boundOffset h k2) c p+  before = paraLinesBefore da+  after  = paraLinesAfter  da+  k2 = if after >= h-k-1  -- The view is already full.+          then k+          else h-after-1  -- k2+after=h-1, i.e., a full viewport.+updateDocView (ShiftVertical n) da@(EditingDocument bs e as w h k c p) = revised where+  revised = EditingDocument bs e as w h (boundOffset h k2) c p+  before = paraLinesBefore da+  k2 = min before (k-n)
WEditor/Internal/Line.hs view
@@ -33,7 +33,7 @@   moveLineCursor,   prependToLine,   setLineCursor,-  splitLine,+  splitLineAtCursor,   viewLine, ) where @@ -69,10 +69,9 @@     | k > n && not (null as) = seek (n+1) (head as:bs) (tail as)     | otherwise = (bs,as) -splitLine :: b -> EditingLine c b -> (VisibleLine c b,VisibleLine c b)-splitLine b0 (EditingLine bs as b) =-  (VisibleLine b0 (reverse bs),-   VisibleLine b as)+splitLineAtCursor :: (Int -> VisibleLine c b -> (VisibleLine c b,VisibleLine c b))+                  -> EditingLine c b -> (VisibleLine c b,VisibleLine c b)+splitLineAtCursor f l@(EditingLine bs _ _) = f (length bs) (viewLine l)  lineCursorMovable :: MoveDirection -> EditingLine c b -> Bool lineCursorMovable MovePrev (EditingLine (_:_) _ _) = True
WEditor/Internal/Para.hs view
@@ -154,9 +154,11 @@ takeLinesAfter :: Int -> [VisibleParaAfter c b] -> [VisibleLine c b] takeLinesAfter n = take n . concat . map vpaLines +-- TODO: Add an upper bound, to avoid unnecessary traversal. countLinesBefore :: [VisibleParaBefore c b] -> Int countLinesBefore = length . concat . map vpbLines +-- TODO: Add an upper bound, to avoid unnecessary traversal. countLinesAfter :: [VisibleParaAfter c b] -> Int countLinesAfter = length . concat . map vpaLines @@ -182,7 +184,7 @@   | otherwise = p  splitPara :: FixedFontParser a c => a -> EditingPara c (BreakType a) -> (UnparsedPara c,UnparsedPara c)-splitPara parser (EditingPara bs l as _) = let (b,a) = splitLine (defaultBreak parser) l in+splitPara parser (EditingPara bs l as _) = let (b,a) = splitLineAtCursor (splitLine parser) l in   (unparseParaBefore $ VisibleParaBefore (b:bs) 0,    unparseParaAfter  $ VisibleParaAfter  (a:as)) 
WEditor/LineWrap.hs view
@@ -154,9 +154,12 @@  instance FixedFontParser (BreakWords c) c where   type BreakType (BreakWords c) = LineBreak-  defaultBreak _ = lineBreakEnd   setLineWidth (BreakWords _ s) w = BreakWords w s   breakLines (BreakWords w s) = breakAllLines w s+  splitLine _ k (VisibleLine b cs) =+    (VisibleLine lineBreakEnd (take k cs),+     VisibleLine b            (drop k cs))+  emptyLine _ = VisibleLine lineBreakEnd []   renderLine (BreakWords w _) (VisibleLine ParagraphEnd cs)     | w < 1 = cs     | otherwise = take w cs
test/TestDocument.hs view
@@ -77,6 +77,63 @@            editorPageUpAction,            editorAppendAction "XYZ"          ]),+    ("fill view ignores already full", checkEditView+       "original-long.txt"+       "fill-noop-view.txt" $+       composeActions [+           editorPageDownAction,+           repeatAction 4 editorDownAction,+           viewerFillAction+         ]),+    ("fill view with short text", checkEditView+       "original-short.txt"+       "fill-short-view.txt" $+       composeActions [+           editorPageDownAction,+           -- Manually shift the view up by one line.+           editorUpAction,+           editorDownAction,+           viewerFillAction+         ]),+    ("fill view starting past end", checkEditView+       "original-long.txt"+       "fill-end-view.txt" $+       composeActions [+           repeatAction 5 editorPageDownAction,+           repeatAction 2 editorUpAction,+           viewerFillAction+         ]),+    ("shift view up within bounds", checkEditView+       "original-long.txt"+       "shift-up-bounded-view.txt" $+       composeActions [+           editorPageDownAction,+           repeatAction 4 editorDownAction,+           viewerShiftUpAction 4+         ]),+    ("shift view down within bounds", checkEditView+       "original-long.txt"+       "shift-down-bounded-view.txt" $+       composeActions [+           editorPageDownAction,+           repeatAction 4 editorDownAction,+           viewerShiftDownAction 4+         ]),+    ("shift view up past doc front", checkEditView+       "original-long.txt"+       "shift-up-unbounded-view.txt" $+       composeActions [+           repeatAction 4 editorDownAction,+           viewerShiftUpAction 4+         ]),+    ("shift view down past doc back", checkEditView+       "original-long.txt"+       "shift-down-unbounded-view.txt" $+       composeActions [+           repeatAction 5 editorPageDownAction,+           repeatAction 4 editorUpAction,+           viewerShiftDownAction 7+         ]),     ("move previous at doc front", checkEditView        "original-long.txt"        "insert-front-view.txt" $
test/TestLine.hs view
@@ -139,27 +139,6 @@            moveLineCursor MoveEnd,            modifyLine DeleteText EditAfter          ]),-    ("split line middle", do-       let line = editLine $ innerLine "this is a test line"-       let (left,right) = splitLine lineBreakEnd $ setLineCursor 5 line-       checkConditions [-           ("Left: " ++ show left,left == (endLine "this ")),-           ("Right: " ++ show right,right == (innerLine "is a test line"))-         ]),-    ("split line front", do-       let line = editLine $ innerLine "this is a test line"-       let (left,right) = splitLine lineBreakEnd $ moveLineCursor MoveUp line-       checkConditions [-           ("Left: " ++ show left,left == (endLine "")),-           ("Right: " ++ show right,right == (innerLine "this is a test line"))-         ]),-    ("split line back", do-       let line = editLine $ innerLine "this is a test line"-       let (left,right) = splitLine lineBreakEnd $ moveLineCursor MoveDown line-       checkConditions [-           ("Left: " ++ show left,left == (endLine "this is a test line")),-           ("Right: " ++ show right,right == (innerLine ""))-         ]),     ("prepend preserves cursor", checkLineEdit        "this is a test line"        "XYthis Zis a test line" $
+ test/testfiles/fill-end-view.txt view
@@ -0,0 +1,10 @@+d.++I can't seem to stop+ writing paragraphs,+ even though this is+ just a test file.+Isn't it annoying ho+w each paragraph onl+y has a single sente+nce in it?
+ test/testfiles/fill-noop-view.txt view
@@ -0,0 +1,10 @@+is all very contrive+d.+It would certainly s+uffice to just fill+it with random chara+cters, but this will+ be easier to read i+n test output.++Since the view buffe
+ test/testfiles/fill-short-view.txt view
@@ -0,0 +1,6 @@+This is a shorter te+st doc.+It has 3 paragraphs,+ just in case.+Definitely a struggl+e.
+ test/testfiles/shift-down-bounded-view.txt view
@@ -0,0 +1,10 @@+it with random chara+cters, but this will+ be easier to read i+n test output.++Since the view buffe+r has five parts to+it, we need at least+ five paragraphs.+But, that five numbe
+ test/testfiles/shift-down-unbounded-view.txt view
@@ -0,0 +1,5 @@+ just a test file.+Isn't it annoying ho+w each paragraph onl+y has a single sente+nce in it?
+ test/testfiles/shift-up-bounded-view.txt view
@@ -0,0 +1,10 @@+ some are out of vie+w, and thus remain u+nparsed.+Honestly, this file+is all very contrive+d.+It would certainly s+uffice to just fill+it with random chara+cters, but this will
+ test/testfiles/shift-up-unbounded-view.txt view
@@ -0,0 +1,10 @@+I need a lot more te+xt here in order to+test out viewing.++I also need some mor+e paragraphs so that+ some are out of vie+w, and thus remain u+nparsed.+Honestly, this file