{{{  comments
; This macro-package gives you the possibility to beautify texts.
; The text-paragraphs will be `filled'. All lines should have the same
; length.
; The filling can be done in three modes:
; * block   - all lines have exact the same length
; * ragged  - ``  '' replaced by `` ''
; * roff    - ``. '' replaced by ``.  '' (active after startup)
; a paragraph ends at a line beginning with ``.'' or if the
; indentation has changed.
;
; fill-paragraph does this filling
;
; inv-blank-handle skips between the fill-modes
;
; set-fill-column changes the width of a paragraph
;   width is given:
;      1: REPEAT-ARGUMENT
;   or 2: position of cursor
;   or 3: (if cursor is to near to the beginning of a line) by
;         keyboardinput
;
; wrap-word wraps a word,
;   if the cursor stands on end-of-line
;      and the line is to long
;
;------------------------------------------------------------------------
;
; if tag TEX-FILL is set, the roff mode can be switched to a tex-mode
; counter t-mode >  0 : fill tex
; counter t-mode =  0 : fill roff
;
;------------------------------------------------------------------------
;
; if tag SCR-OFF is set, fill-paragraph works without displaying
}}}
@if-using not(FILLPARA)
  @use (FILLPARA)
  {{{  libs
  {{{F fun/error
  :::F fun/error
  }}}
  {{{F fun/delspaces
  :::F fun/delspaces
  }}}
  }}}
  {{{  vars
  ( defvar
     ( fill-column         ; up to this position should be filled
       single-blank        ; which fill-mode is set
       wrap-mode           ; should spaces break line in macro wrap-word
       fill-start          ; start of lines
       fill-begin          ; first char in block
       fill-end            ; last char in block
       fill-width          ; # of chars in block
       fill-x              ; help-counter
       fill-count          ; help-counter
       fill-post-c         ; local var: missing spaces for block-fill
       fill-para-space-po  ; local var: position to start filling block-spaces
       fill-post-x         ; local var: space for block-fill found?
     )
  )
  }}}
  {{{  globals
  {{{  init-fill-column
  (defmac init-fill-column
    (if counter-0 fill-column  (set-counter fill-column 72) fi )
  )
  }}}
  {{{  set-fill-column
  (deffun set-fill-column
  (
    init-fill-column
    set-counter fill-x read-repeat
    {{{  use numeric argument if any
    if counter>0 fill-x (
      set-counter fill-column fill-x
      return-from-macro
    ) fi
    }}}
    set-counter fill-end +(store-pos -20)
    {{{  if greater than 20, use this position for fill-column
    if counter>0 fill-end (
      set-counter fill-column store-pos
      return-from-macro
    ) fi
    }}}
    {{{  else prompt for the correct value
    prompt-counter fill-end ( "fill-column "  "? )
    if not(counter>0 fill-end) ( failed ) fi
    set-counter fill-column fill-end
    }}}
  ))
  }}}
  }}}
  {{{  fill
  {{{  fill-paragraph
  {{{  pre-handle-line
  {{{  tab-test
  ( deffun tab-test
     ( if test-char C-I
        ( message-exit ( "tab "  "in  "  "paragraph ) )
       fi
     )
  )
  }}}
  (deffun pre-handle-line (
    beginning-of-line
    if counter-0 single-blank (
      {{{  expand ``. '' to ``.  ''
      while not(test-end-line) (
        tab-test
        {{{  maybe expand ``. ''
        if test-char ". (
          forward-character
          if test-char "  (
            forward-character
            if not(test-char " ) (" ) fi
          ) fi
        ) fi
        }}}
        forward-character
      )
      }}}
    ) else (
      {{{  ``  ''->:`` ''
      while not(test-end-line) (
        tab-test
        if test-char "  (
          forward-character
          delspaces
        ) fi
        forward-character
      )
      }}}
    ) fi
  ))
  }}}
  {{{  post-last-handle
  (defmac post-last-handle (
    if counter>0 single-blank ( pre-handle-line ) fi
  ))
  }}}
  {{{  post-handle-line
  (deffun post-handle-line (
    if counter>0 single-blank (
      {{{  expand sline exact to fill column
      {{{  fill-post-c = number of missing spaces
      goto-counter fill-end
      set-counter fill-post-c 0
      while and(not(test-begin-line),test-char " ) (
        set-counter fill-post-c +(fill-post-c 1)
        backward-character
      )
      }}}
      do (
        {{{  one line pass, fill-post-x=0, if space found
        {{{  move cursor to correct position
        if counter-0 fill-para-space-po (
          set-counter fill-post-x 1
          end-of-line
        ) else (
          set-counter fill-post-x 0
          goto-counter fill-para-space-po
          while test-end-line (backward-character)
          forward-character
        ) fi
        }}}
        while and(counter>0 fill-post-c,not(test-begin-line)) (
          {{{  maybe insert space, go left
          backward-character
          if test-char " (
            "  ;
            backward-character
            backward-character
            set-counter fill-post-x 0
            set-counter fill-post-c +(fill-post-c -1)
          ) fi
          }}}
        )
        set-counter fill-para-space-po 0
        }}}
      ) while and(counter>0 fill-post-c,counter-0 fill-post-x)
      set-counter fill-para-space-po store-pos
      }}}
    ) fi
  ))
  }}}
  {{{  fill-line
  (defmac fill-line
  (
    {{{  how many chars needed, which position in next line
    end-of-line
    set-counter fill-count store-pos
    backward-character
    if and(test-char ".,counter-0 single-blank)
     ( set-counter fill-count +(fill-count 1) )
    fi
    set-counter fill-count -(fill-end fill-count)
    set-counter fill-x +(fill-count fill-begin)
    }}}
    next-line
    goto-counter fill-x
    if test-end-line (
      {{{  next line to short
      goto-counter fill-start
      delspaces
      delete-previous-character
      if counter-0 single-blank (
        backward-character
        if test-char ". (forward-character " ) else (forward-character) fi
      ) fi
      "  ;
      }}}
    ) else (
      {{{  line long enough
      {{{  search splitt positions
      while and(counter>0 fill-count,not(test-char " )) (
        backward-character
        set-counter fill-count +(fill-count -1)
      )
      }}}
      if counter>0 fill-count (
        {{{  can splitt
        newline-and-indent
        goto-counter fill-begin
        delspaces
        previous-line
        goto-counter fill-start
        delspaces
        delete-previous-character
        if counter-0 single-blank (
          backward-character
          if test-char ". (forward-character " ) else (forward-character) fi
        ) fi
        "  ;
        next-line
        }}}
      ) fi
      previous-line
      post-handle-line
      next-line
      }}}
    ) fi
  ))
  }}}
  {{{  splitt-line
  (defmac splitt-line
  (
    goto-counter fill-end
    forward-character
    set-counter fill-count fill-width
    {{{  look for a splitt-position
    while and(counter>0 fill-count,not(test-char " )) (
      backward-character
      set-counter fill-count +(fill-count -1)
    )
    if counter-0 fill-count ( failed ) fi
    }}}
    newline-and-indent
    goto-counter fill-begin
    delspaces
  ))
  }}}
  {{{  fill-block
  (defmac fill-block (
    if not(test-text) ( failed ) fi
    beginning-of-line
    if and(test-char ".,counter-0 single-blank) ( failed  ) fi
    {{{  set start/begin/end/fillpo/width
    ; fill-begin = first char in block
    ; fill-start = first edit-posiotn in current fold
    ; fill-end   = fill-column
    ; fill-width = number of chars in a blockline
    ; fill-para-space-po = 0
    ;              counter to spread added spaces (block-mode)
    set-counter fill-begin store-pos
    newline-and-indent
    previous-line
    beginning-of-line
    set-counter fill-start store-pos
    delete-line
    init-fill-column
    set-counter fill-end fill-column
    set-counter fill-width +(1 -(fill-end fill-begin))
    set-counter fill-para-space-po 0
    }}}
    pre-handle-line
    while test-text (
      {{{  handle one line (current line is maybe to short, but prehandled)
      goto-counter fill-begin
      {{{  `.' or ` ' at begin or not start-of-line => ready
      if or(test-char " ,
            @if-using (TEX-FILL)
              and(or(and(test-language "t test-char "\),
                     and(test-language "r test-char ".)),
                  counter-0 single-blank),
            @fi
            @if-using not(TEX-FILL)
              and(test-char ".,counter-0 single-blank),
            @fi
            not(test-begin-line))
      (
        return-from-macro
      ) fi
      }}}
      goto-counter fill-end
      forward-character
      if test-end-line (
        {{{  fill or leave
        backward-character
        if test-end-line (
          {{{  fill it
          next-line
          goto-counter fill-begin
          {{{  `.' or ` ' at begin or not start-of-line or no text => ready
          if or(test-char " ,
                @if-using (TEX-FILL)
                  and(or(and(test-language "t test-char "\),
                         and(test-language "r test-char ".)),
                      counter-0 single-blank),
                @fi
                @if-using not(TEX-FILL)
                  and(test-char ".,counter-0 single-blank),
                @fi
                not(test-text),
                not(test-begin-line))
          (
            previous-line
            post-handle-line
            next-line
            beginning-of-line
            return-from-macro
          ) fi
          }}}
          pre-handle-line
          previous-line
          fill-line
          }}}
        ) else (
          {{{  line exact ok
          post-handle-line
          next-line
          pre-handle-line
          }}}
        ) fi
        }}}
      ) else (
        {{{  splitting
        splitt-line
        previous-line
        post-handle-line
        next-line
        }}}
      ) fi
      }}}
    )
  ))
  }}}
  (deffun fill-paragraph (
    if test-overwrite ( failed ) fi
    @if-using (SCR-OFF)
      screen-off
    @fi
    fill-block
    previous-line
    post-last-handle
    @if-using (SCR-OFF)
      screen-on
      redraw-display
    @fi
  ))
  }}}
  {{{  inv-blank-handle
  ( deffun inv-blank-handle
     ( set-counter fill-x +(single-blank 1)
       menu-counter fill-x
        ( "shrink "  "roff @if-using ( TEX-FILL ) "/tex @fi "  "block )
       set-counter single-blank +(fill-x -1)
     )
  )
  }}}
  }}}
  {{{  wrap
  {{{  wrap-word
  (deffun wrap-word (
    if
       {{{  word should be wrapped
       and(counter>0 wrap-mode,
           not(in-prompt),
           test-end-line,
           pre ( init-fill-column ) test-behind-counter fill-column)
       }}}
    {{{  wrap the word
    (
      {{{  go to last char in line
      while and(test-char " ,not(test-begin-line)) (backward-character)
      }}}
      {{{  move to correct wrap-position
      if test-behind-counter fill-column (
        {{{  if to long, wrap word
        {{{  move to last space
        while and(not(test-char " ),not(test-begin-line)) (backward-character)
        }}}
        {{{  if not at start-of-line, right to correct wrap-word
        if test-begin-line (end-of-line) else (forward-character) fi
        }}}
        }}}
      ) else (
        forward-character
      ) fi
      }}}
      newline-and-indent
      {{{  maybe move behind wraped word
      previous-line
      beginning-of-line
      next-line
      if not(test-end-line) (end-of-line "  ) fi
      }}}
    )
    }}}
    else
    {{{  insert space
    (
      "  ;
    )
    }}}
    fi
  ))
  }}}
  {{{  add/delete wrap-mode
  (defmodestring WM "Wrap "W )
  {{{  add-mode-wrap
  (deffun add-mode-wrap (set-counter wrap-mode 1 set-user-mode WM))
  }}}
  {{{  delete-mode-wrap
  (deffun delete-mode-wrap (set-counter wrap-mode 0 reset-user-mode WM ))
  }}}
  }}}
  }}}
  {{{  vars
  ( undeclare
     ( init-fill-column
       pre-handle-line
       post-handle-line
       fill-line
       splitt-line
       fill-block
       fill-start
       fill-begin
       fill-end
       fill-width
       fill-x
       fill-count
       fill-post-c
       fill-para-space-po
       fill-post-x
     )
  )
  }}}
@fi
