.. pytextseg documentation

=============
Customization
=============

.. _`Formatting Lines`:

Formatting Lines
================

If you specify callable object as format property of LineBreak object,
it should accept three arguments::

    callable_object(self, context, string) -> text_or_None

*self* is a LineBreak object,
*context* is a string to determine the context that subroutine was called in, 
and *string* is a fragment of Unicode string leading or trailing breaking 
position.

  +-----------+----------------------+----------------------------------+
  | *context* | When                 | Value of *string*                |
  +===========+======================+==================================+
  | ``"sot"`` | Beginning of text    | Fragment of first line           |
  +-----------+----------------------+----------------------------------+
  | ``"sop"`` | After mandatory break| Fragment of next line            |
  +-----------+----------------------+----------------------------------+
  | ``"sol"`` | After arbitrary break| Fragment on sequel of line       |
  +-----------+----------------------+----------------------------------+
  | ``""``    | Just before any      | Complete line without trailing   |
  |           | breaks               | SPACEs                           |
  +-----------+----------------------+----------------------------------+
  | ``"eol"`` | Arbitrary break      | SPACEs leading breaking position |
  +-----------+----------------------+----------------------------------+
  | ``"eop"`` | Mandatory break      | Newline and its leading SPACEs   |
  +-----------+----------------------+----------------------------------+
  | ``"eot"`` | End of text          | SPACEs (and newline) at end of   |
  |           |                      | text                             |
  +-----------+----------------------+----------------------------------+

Callable object should return modified text fragment or may return
``None`` to express that no modification occurred.
Note that modification in the context of ``"sot"``, ``"sop"`` or ``"sol"`` 
may affect decision of successive breaking positions while in the others 
won't.

.. note::
   String arguments are actually sequences of grapheme clusters.
   See documentation of GCStr class.

For example, following code folds lines removing trailing spaces::

    from textseg import LineBreak
    
    def format(self, event, string):
        if event.startswith('eo'):
            return "\n"
        return None
    
    lb = LineBreak(format = format)
    output = ''.join([str(s) for s in lb.wrap(text)])

.. _`User-Defined Breaking Behaviors`:

User-Defined Breaking Behaviors
===============================

When a line generated by arbitrary break is expected to be beyond measure of
either CharMax, ColMax or ColMin, **urgent break** may be
performed on successive string.
If you specify callable object as a value of urgent option,
it should accept two arguments::

    callable_object(self, string) -> [text, ...]

*self* is a LineBreak object and *string* is a Unicode string to be broken.

Callable object should return a list of broken items of *string*.

.. note::
   String argument is actually a sequence of grapheme clusters.
   See GCStr class.

For example, following code inserts hyphen to the name of several chemical 
substances (such as Titin) so that it may be folded::

    # Example not yet written

If you specify ``(*regular expression*, *callable object*)`` tuple as any 
item of prep option, callable object should accept two arguments::

    callable_object(self, string) -> [text, ...]

*self* is a LineBreak object and
*string* is a Unicode string matched with *regular expression*.

Callable object should return a list of broken items of *string*.

For example, following code will break HTTP URLs using [CMOS]_ rule::

    urire = re.compile(r'\b(?:url:)?[a-z][-0-9a-z+.]+://[\x21-\x7E]+',
                       re.I + re.U)
    def breakURI(self, s):
        r = ''
        ret = []
        b = ''
        for c in s:
            if b == '':
                r = c
            elif r.lower().endswith('url:'):
                ret.append(r)
                r = c
            elif b in '/' and not c in '/' or \
                 not b in '-.' and c in '-~.,_?\#%=&' or \
                 b in '=&' or c in '=&':
                if r != '':
                    ret.append(r)
                r = c
            else:
                r += c
            b = c
        if r != '':
            ret.append(r)
        return ret

    output = fill(text, prep = [(urire, breakURI)])

.. _`Preserving State`:

Preserving State
----------------

LineBreak object can behave as dictionary.
Any items may be preserved throughout its life.

For example, following code will separate paragraphs with empty lines::

    # Example not yet written

.. _`Calculating String Size`:

Calculating String Size
=======================

If you specify callable object as a value of sizing property,
it will be called with five arguments::

    callable_object(self, length, pre, spc, string) -> number_of_columns

*self* is a LineBreak object, *length* is size of preceding string,
*pre* is preceding Unicode string, *spc* is additional SPACEs and 
*string* is a Unicode string to be processed.

Callable object should return calculated number of columns of 
``pre + spc + string``.
The number of columns may not be an integer: Unit of the number may be 
freely chosen, however, it should be same as those of minwidth and 
width properties.

.. note::
   String arguments are actually sequences of grapheme clusters.
   See GCStr class.

For example, following code processes lines with tab stops by each eight
columns::

    from textseg import fill
    from textseg.Consts import lbcSP
    
    def sizing(self, cols, pre, spc, string):
        spcstr = spc + string
        i = 0
        for c in spcstr:
            if c.lbc != lbcSP:
                cols += spcstr[i:].cols
                break
            if c == "\t":
                cols += 8 - (cols % 8)
            else:
                cols += c.cols
            i = i + 1
        return cols
    
    output = fill(text, lbc = {ord("\t"): lbcSP}, sizing = sizing,
                  expand_tabs = False)

.. _`Tailoring Character Properties`:

Tailoring Character Properties
==============================

.. |uni00AB| unicode:: U+00AB .. LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
.. |uni00BB| unicode:: U+00BB .. RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
.. |uni2018| unicode:: U+2018 .. LEFT SINGLE QUOTATION MARK
.. |uni2019| unicode:: U+2019 .. RIGHT SINGLE QUOTATION MARK
.. |uni201C| unicode:: U+201C .. LEFT DOUBLE QUOTATION MARK
.. |uni201D| unicode:: U+201D .. RIGHT DOUBLE QUOTATION MARK
.. |uni2039| unicode:: U+2039 .. SINGLE LEFT-POINTING ANGLE QUOTATION MARK
.. |uni203A| unicode:: U+203A .. SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
.. |uni3059| unicode:: U+3059 .. HIRAGANA LETTER SU
.. |uni307E| unicode:: U+307E .. HIRAGANA LETTER MA
.. |uni30B9| unicode:: U+30B9 .. KATAKANA LETTER SU
.. |uni30DE| unicode:: U+30DE .. KATAKANA LETTER MA

*To be written*

