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 +12/−0
- WEditor.cabal +4/−3
- WEditor/Base/Line.hs +0/−5
- WEditor/Base/Parser.hs +8/−7
- WEditor/Base/Viewer.hs +26/−3
- WEditor/Document.hs +30/−4
- WEditor/Internal/Line.hs +4/−5
- WEditor/Internal/Para.hs +3/−1
- WEditor/LineWrap.hs +4/−1
- test/TestDocument.hs +57/−0
- test/TestLine.hs +0/−21
- test/testfiles/fill-end-view.txt +10/−0
- test/testfiles/fill-noop-view.txt +10/−0
- test/testfiles/fill-short-view.txt +6/−0
- test/testfiles/shift-down-bounded-view.txt +10/−0
- test/testfiles/shift-down-unbounded-view.txt +5/−0
- test/testfiles/shift-up-bounded-view.txt +10/−0
- test/testfiles/shift-up-unbounded-view.txt +10/−0
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