Awesome
Wrapping Editor for Haskell
Tests | WEditor | WEditorHyphen | WEditorBrick |
---|---|---|---|
This library contains a simple text-editing component for fixed-size fonts. It
can either be used as a Brick Widget
or as the basis for creating a
new widget for another UI library.
Here are some important features:
- Supports dynamic viewport resizing while preserving the view position.
- Customizable line-wrapping policies, to include special line rendering.
- Includes a line-wrapping policy for word hyphenation.
- Efficient editing operations for long documents.
If you have any problems using this library, or if you would like to see new features, please see the issues page. Also check out the library reference.
Installation
This library is split into 3 separate packages:
-
WEditor
is the base package, containing the generic editor logic and simple line-wrapping and hyphenation policies. This can be used as the basis for a new editor widget for a UI library without depending on any of the other packages. -
WEditorHyphen
contains language-specific hyphenation policies for use with bothWEditor
andWEditorBrick
. This package is not required in order to use either of those packages. You will need to explicitly install thehyphenation
package in order to have access to the rules for each supported language. -
WEditorBrick
contains just the BrickWidget
.
All of these packages can be installed from Hackage using
cabal
. You will need to explicitly install WEditor
in order to set
up editors in either of the other packages.
-
Just the base package:
# cabal < 2.0 cabal install WEditor # cabal >= 2.0 cabal install --lib WEditor
-
Everything:
# cabal < 2.0 cabal install WEditor WEditorBrick hyphenation WEditorHyphen # cabal >= 2.0 cabal install --lib WEditor WEditorBrick hyphenation WEditorHyphen
Using with Brick
See brick-example.hs for an example program that uses
WrappingEditor
.
You can run the example with:
ghc -threaded example/WEditorBrick/brick-example.hs
example/WEditorBrick/brick-example README.md
Press Esc
to exit when you are finished. The final contents of the editor will
be sent to stdout
without modifying the file.
You can customize the widget using the following helper functions from the
WrappingEditor
module:
-
doEditor
allows you to useFixedFontEditor
andFixedFontViewer
functions to extract info from the editor, e.g., for custom rendering. -
genericEditor
allows you to use any custom editor component that instantiates bothFixedFontEditor
andFixedFontViewer
, e.g., an editor for a custom character type. (You might also need custom rendering and event handling.) -
mapEditor
allows you to transform the editor withFixedFontEditor
andFixedFontViewer
functions, e.g., calling editing actions in a custom event handler. (If you use a custom event handler, callupdateEditorExtent
before applying editor actions.)
Using the Generic Editor
import WEditor.LineWrap
import WEditor.Document
-- 1. Split your doc into paragraphs. Paragraph splitting is handled by the
-- caller so that the library can avoid end-of-line considerations.
paragraphs = map UnparsedPara $ lines $ "Your document contents."
-- 2. Create an editor. This example uses lazy word hyphenation.
editor = editDocument (breakWords lazyHyphen) paragraphs
-- 3a. Edit the document using actions from `Viewer` and `Editor`. Don't forget
-- to set the viewport size! If either dimension is < 1, the text will be
-- unbounded in that direction.
editor' = foldl (flip ($)) editor [
viewerResizeAction (80,24),
editorEndAction,
editorEnterAction,
editorAppendAction "Here is a new paragraph.",
-- Resizing while editing is fine.
viewerResizeAction (7,3),
-- Use this if you don't like scrolling below the last line.
viewerFillAction
]
-- 3b. Get the viewport contents for display. This does not necessarily fill up
-- the entire view area; pad it if necessary.
display = getVisible editor'
-- 4. Extract the edited contents.
final = unlines $ map upText $ exportData editor'
Wrapping Policies
-
breakExact
works for all character types because it breaks lines at exactly the editor width. -
breakWords p
takes aWordSplitter
policyp
to split words. Character support depends on the existence of aWordSplitter
for the character type. In theory, it supports all character types.-
noHyphen
avoids splitting words if at all possible, and it never uses hyphens. This policy requires aWordChar
instance for the character type. -
lazyHyphen
splits words without any dictionary awareness, and attempts to keep at least 2 characters of the word on each line. This policy requiresWordChar
andHyphenChar
instances for the character type. -
langHyphen l
(from the optionalWEditorHyphen
packge) uses language-specific hyphenation rules, e.g.,English_US
. -
Create custom word-splitting by creating a new
WordSplitter
. This can be used for supporting new character types, adding dictionary awareness, expanding the characters that are considered to be a part of words, etc.
-
-
Create a completely new wrapping policy with an instance of
FixedFontParser
. This can be used for things thatbreakWords
cannot support, e.g., line indentation and tab expansion.
Character Support
The generic editor can support any character type for which a wrapping policy is
available. The editor for Brick currently only supports Char
, but it
will likely be modified to support other character types.