home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
me34exe.zip
/
mutt
/
contrib
/
docmode.mut
< prev
next >
Wrap
Text File
|
1995-01-14
|
24KB
|
823 lines
;;
;; File:
;; docmode.mut - document mode
;;
;; Description:
;; This 'DocumentMode' is a replacement for 'TextMode'. The function
;; 'doc-format-paragraph' handles the formatting of paragraphs. The
;; function is able to recognize some special kinds of paragraphs,
;; it allows for special indentation of the first line of a
;; paragraph and it handles justification.
;;
;; Paragraph indentation is as follows:
;;
;; - The indentation of the first line of a paragraph is never
;; changed!
;;
;; - The indentation of a paragraph relative to the left edge of the
;; paper is based on the indentation of the first non-blank
;; character on the first line of the paragraph.
;;
;; - The indentation of the 'tail' of a paragraph (all lines except
;; the first) is based on the indentation of the first line of the
;; paragraph and the value of the variable 'docTailOffset':
;;
;; - If docTailOffset equals 0, the tail of the paragraph is
;; alligned with the first line of the paragraph.
;;
;; - If docTailOffset not equals 0, the tail of the paragraph is
;; indented by the sum of the indentation of the first line and
;; the value of docTailOffset. Note that a negative
;; docTailOffset gives an extra indented first line, a positive
;; docTailOffset gives an extra indented tail.
;;
;; - Paragraphs that start with a dash or a number followed by a
;; right-brace are indented automatically.
;;
;; - The variable 'docJustify' controls whether a paragraph is
;; justified or not. All varieties of paragraphs can be justified,
;; flushed left, flushed right or centered.
;;
;; Examples: (All examples assume docJustify equals TRUE)
;;
;; - This is the first example of a paragraph that is formatted with
;; doc-format-paragraph. Indentation of the paragraph is based on
;; the dash ('- ').
;;
;; 1) This is the second example of a paragraph that is formatted
;; with doc-format-paragraph. Indentation of the paragraph is
;; based on the number ('1) ').
;;
;; This paragraph is the third example of a paragraph that is
;; formatted with doc-format-paragraph (assumes that docTailOffset
;; equals 0).
;;
;; 33) This is the fourth example of a paragraph that is
;; formatted with doc-format-paragraph. Indentation is based
;; on the number ('33) ') and on the fact that the first
;; line is indented.
;;
;; This is paragraph number five. This example assumes
;; docTailOffset equals -4. Then, although the indentation of the
;; first line equals 4, the tail is indented (4 + docTailIndent),
;; which is 0.
;;
;; SIX This is paragraph number six. This example assumes
;; docTailOffset equals 4. Then, although the indentation of
;; the first line equals 0, the tail is indented (0 +
;; docTailOffset), which is 4.
;;
;; - In the text below a 'special' paragraph is a paragraph that
;; starts with a text defined in function 'doc-special-paragraph'.
;;
;; Known Bugs:
;; - A big NEGATIVE docTailIndent gives badly distributed extra
;; spaces when justifying a paragraph.
;;
;; History:
;; 942601 M.J. van der Velden
;; - added support for repagination (see docform.mut)
;; - more special paragraphs are recognized
;; - fixed documentation errors
;; - special formats now handled in function
;; 'doc-special-paragraph'
;; Public Domain (Version 2.3)
;; 930702 M.J. van der Velden
;; - fixed documentation errors
;; - less info in modeline (the clock is more interesting)
;; removed 'doc-add-major-mode' and added 'doc-minor-mode'.
;; Public Domain (Version 2.2)
;; 930130 M.J. van der Velden
;; - Removed MAIN from doc-mode.
;; - Added doc-flush-right (based on end-slide made by C.
;; Durland in cstuff.mut)
;; Public Domain (Version 2.1)
;; 930105 M.J. van der Velden
;; Public Domain (Version 2.0)
;; 921119 M.J. van der velden
;; - Fixed a formatting error when the last line of a
;; paragraph has exactly the correct format before
;; justification.
;; - Added "doc-mode-hook".
;; - Added functions to set or get the various "docXXX"
;; variables non-interactivally.
;; - Changed format of major-mode and minor-mode.
;; - Fixed some minor documentation errors.
;; - Added '\a+)\ ' to be the start of a special paragraph.
;; - added funtions to add text to the major mode.
;; 921005 M.J. van der Velden
;; Public Domain (Version 1.0)
;;
(include me.mh)
;; Global Constants.
(const
DOC-DEF-LINES-ON-PAGE 60
DOC-DEF-RIGHT-MARGIN 72
DOC-DEF-TAIL-OFFSET 0
DOC-DEF-TAB-SIZE 4
DOC-DEF-JUSTIFY TRUE
DOC-DEF-RIGHT-FLUSH FALSE
DOC-DEF-CENTER FALSE
DOC-MAJOR-MODE "Doc"
DOC-MINOR-MODE ""
DOC-EMPTY-LINE '\ *$'
)
;; End Of Global Constants.
;; Global Variables.
(int
docRightMargin ;; Current column to word wrap at (0 means no
;; wrapping).
docTailOffset ;; Offset between indentation of first line
;; and the indentation of the rest of the
;; paragraph.
docTabSize ;; Tab size (0 means use the TAB character).
)
(string
docMajorMode ;; Major mode string
docMinorMode ;; Minor mode string
)
(bool
docJustify ;; Justify?
docRightFlush ;; Flush right?
docCenter ;; Center?
;; Note: if all these options are false, paragraphs
;; are flushed left.
)
;; End Of Global Variables.
;; Paragraph movement and selection.
(defun
doc-begin-of-paragraph
;; pre:
;; true
;; post:
;; if >THE-DOT between paragraphs then
;; THE-DOT> is at the beginning of the next paragraph
;; else
;; THE-DOT> is at the beginning of the current paragraph
;; endif
;; returns:
;; void
{
(beginning-of-line)
(while (and (not (EoB)) (looking-at DOC-EMPTY-LINE)) {
(forward-line 1)
})
(while (forward-line -1) {
(if (looking-at DOC-EMPTY-LINE) {
(forward-line 1)
(break)
})
})
}
doc-end-of-paragraph
;; pre:
;; true
;; post:
;; if >THE-DOT between paragraphs then
;; THE-DOT> is at the end of the next paragraph
;; else
;; THE-DOT> is at the end of the current paragraph
;; endif
;; returns:
;; void
{
(beginning-of-line)
(while (and (not (EoB)) (looking-at DOC-EMPTY-LINE)) {
(forward-line 1)
})
(while (not (EoB)) {
(forward-line 1)
(if (looking-at DOC-EMPTY-LINE) {
(break)
})
})
(forward-line -1)
(end-of-line)
}
doc-select-paragraph
;; pre:
;; true
;; post:
;; if >THE-DOT between paragraphs then
;; THE-MARK> is at the beginning of the next paragraph
;; THE-DOT> is at the end of the next paragraph
;; else
;; THE-MARK> is at the beginning of the current paragraph
;; THE-DOT> is at the end of the current paragraph
;; endif
;; returns:
;; void
{
(doc-begin-of-paragraph)
(set-mark THE-MARK)
(doc-end-of-paragraph)
}
)
;; Paragraph formatting.
(defun
;; pre:
;; true
;; post:
;; true
;; returns:
;; >THE-DOT is looking at the start of a special paragraph
doc-special-paragraph
{
(or (looking-at '-\ ')
(looking-at '\d+)\ ')
(looking-at '\a+)\ ')
(looking-at '\d+.\d+)\ ')
)
}
;; pre:
;; >THE-DOT is at the beginning-of-paragraph
;; post:
;; - indent> is the indentation level of current paragraph
;; - tailOffset> is the tail offset of the current paragraph
;; - if the current paragraph is 'special' then
;; THE-DOT> is on the first line of the current paragraph
;; at column tailOffset>
;; else
;; THE-DOT> is on the first line of the current paragraph
;; at column indent>
;; endif
;; returns:
;; void
doc-get-indent-and-tail (array int indent 1 tailOffset 1) HIDDEN
{
(skip-whitespace)
(indent 0 (current-column))
(if (doc-special-paragraph) {
(while (not (is-space)) {
(next-character)
})
(skip-whitespace)
(tailOffset 0 (- (current-column) (indent 0)))
} {
(tailOffset 0 docTailOffset)
})
}
doc-justify-line (int from rightMargin) HIDDEN
;; pre:
;; - current line has no trailing whitespace
;; - there is at most a single space between each word
;; - >from < >rightMargin
;; post:
;; - the current line is justified such that at most
;; (>rightMargin - 1) characters are put on the line
;; - extra spaces are only added after column >from
;; returns:
;; void
{
(int noOfGaps)
(int noOfExtraSpaces)
(int widening)
;; calculate the number of gaps
(noOfGaps 0)
(current-column from)
(while (not (looking-at '$')) {
(if (is-space) {
(+= noOfGaps 1)
})
(next-character)
})
;; calculate the number of extra spaces
(end-of-line)
(noOfExtraSpaces (- rightMargin (current-column)))
;; add the extra spaces to the line
(current-column from)
(while (> noOfGaps 0) {
(if (is-space) {
(widening (/ noOfExtraSpaces noOfGaps))
(-= noOfExtraSpaces widening)
(-= noOfGaps 1)
(while (>= (-= widening 1) 0) {
(insert-text " ")
})
})
(next-character)
})
}
doc-left-flush-line (int from) HIDDEN
;; pre:
;; true
;; post:
;; - sequences of more than one space at or after column >from
;; in the current line are replaced by a single space
;; - trailing whitespace is removed from the current line
;; - THE-DOT> is at the end-of-line
;; returns:
;; void
{
(while (not (looking-at '$')) {
(if (is-space) {
(next-character)
(delete-whitespace)
} {
(next-character)
})
})
(delete-previous-whitespace)
}
doc-right-flush-line (int from rightMargin) HIDDEN
;; pre:
;; current line is flushed left from postion >from
;; post:
;; - the current line is flushed right such that at most
;; (>rightMargin -1) characters are put on the line
;; - extra spaces are added at column >from
;; returns:
;; void
{
(int noOfExtraSpaces)
(end-of-line)
(noOfExtraSpaces (- rightMargin (current-column)))
(current-column from)
(while (>= (-= noOfExtraSpaces 1) 0) {
(insert-text " ")
})
}
doc-center-line (int from rightMargin) HIDDEN
;; pre:
;; the current line is flushed left from column >from
;; post:
;; - the current line is centered between >from and
;; (>rightMargin -1)
;; - extra spaces are added at column >from
;; returns:
;; void
{
(int noOfExtraSpaces)
(end-of-line)
(noOfExtraSpaces (/ (- rightMargin (current-column)) 2))
(current-column from)
(while (>= (-= noOfExtraSpaces 1) 0) {
(insert-text " ")
})
}
doc-find-split-position (int from rightMargin) HIDDEN
;; pre:
;; - length of current line extends >rightMargin
;; - there is not more than one space between words
;; post:
;; THE-DOT is on the "best" column to split the line
;; returns:
;; void
{
(current-column rightMargin)
(while (and (> (current-column) from) (previous-character)) {
(if (is-space) {
(break)
})
})
;; if line is solid, go to rightMargin...
(if (== (current-column) from) {
(current-column rightMargin)
})
}
doc-format-previous-line
(int from rightMargin) (bool lastOfParagraph) HIDDEN
;; pre:
;; - there is a previous line
;; - the previous line is flushed left from column >from
;; post:
;; - if not (>docJustify and >lastOfParagraph) then
;; the previous line is formatted according to >docJustify,
;; >docRightFlush, >docCenter, >from and >rightMargin.
;; endif
;; - THE-DOT> is at the beginning of the current line
;; returns:
;; void
{
(forward-line -1)
(cond
docJustify {
(if (not (lastOfParagraph)) {
(doc-justify-line from rightMargin)
})
}
docRightFlush {
(doc-right-flush-line from rightMargin)
}
docCenter {
(doc-center-line from rightMargin)
}
)
(forward-line 1)
(beginning-of-line)
}
doc-format-paragraph
;; pre:
;; true
;; post:
;; - if >THE-DOT is between paragraphs then
;; the next paragraph is formatted
;; else
;; the current paragraph is formatted
;; endif
;; - THE-DOT> is after the current paragraph (therefore a second
;; call formats the next paragraph, and so on)
;; - note: see 'description' in module heading for a description
;; of the kind of formatting supported
;; returns:
;; void
{
(bool atEndOfParagraph)
(int rightMargin)
(int indent)
(int tailOffset)
(int from)
(msg "Formatting... ")
(rightMargin
(+ (if (== 0 (word-wrap)) docRightMargin (word-wrap)) 1)
)
(doc-begin-of-paragraph)
(doc-get-indent-and-tail (loc indent) (loc tailOffset))
(from (if (> tailOffset 0) (+ indent tailOffset) indent))
(if (>= from rightMargin) {
(doc-end-of-paragraph)
(next-character)
(msg "Paragraph indentation extends the right margin...")
(done)
})
(atEndOfParagraph FALSE)
(while (not atEndOfParagraph) {
(doc-left-flush-line (current-column))
(cond
(> (current-column) rightMargin) {
;; a "long line"...
(doc-find-split-position from rightMargin)
(newline)
(doc-format-previous-line from rightMargin FALSE)
;; indent the current line...
(delete-whitespace)
(to-col (+ indent tailOffset))
}
(< (current-column) rightMargin) {
;; a "short" line, go and see the next line...
(next-character)
(atEndOfParagraph (or (EoB) (looking-at DOC-EMPTY-LINE)))
(if (not atEndOfParagraph) {
;; join the current line with the previous line...
(delete-previous-character)
(insert-text " ")
(delete-whitespace)
})
}
TRUE {
;; length of line is ok, go and see the next line
(next-character)
(atEndOfParagraph (or (EoB) (looking-at DOC-EMPTY-LINE)))
(if (not atEndOfParagraph) {
;; indent the current line...
(delete-whitespace)
(to-col (+ indent tailOffset))
})
}
)
})
;; format the last line of the paragraph...
(doc-format-previous-line indent rightMargin TRUE)
(msg "Formatted!")
}
)
;; Simple formatting functions
(defun
doc-flush-right
{
(int col n x)
(n (if (arg-flag) (arg-prefix) docRightMargin))
(delete-horizontal-space)
(col (current-column))
(end-of-line)
(x (+ 1 (- n (current-column))))
(current-column col)
(to-col (+ col x))
}
)
;; Interactivally change document options.
(defun
doc-show-modes HIDDEN
;; pre:
;; true
;; post:
;; - major-mode> gives an identification of this Document mode
;; - minor-mode> gives information about the current paragraph
;; formatting style according to >docJustify, >docRightFlush
;; and >docCenter.
;; returns:
;; void
{
(major-mode
(concat
docMajorMode
"("
(cond
docJustify "J"
docRightFlush "R"
docCenter "C"
TRUE "L"
)
")"
)
)
(minor-mode docMinorMode)
}
doc-set-tail
;; pre:
;; true
;; post:
;; - the user is allowed to enter a new >docTailOffset>
;; returns:
;; void
{
(string answer)
(answer (ask (concat "Tail [" docTailOffset "]: ")))
(if (!= answer "") {
(docTailOffset (convert-to NUMBER answer))
})
}
doc-set-tab-size
;; pre:
;; true
;; post:
;; - the user is allowed to enter a new >docTabSize>
;; - tab-stops> equals docTabSize>
;; returns:
;; void
{
(string answer)
(answer (ask (concat "Tab Size [" docTabSize "]: ")))
(if (!= answer "") {
(docTabSize (convert-to NUMBER answer))
(tab-stops docTabSize)
})
}
doc-set-right-margin
;; pre:
;; true
;; post:
;; - the user is allowed to enter a new >docRightMargin>
;; - word-wrap> equals docRightMargin>
;; returns:
;; void
{
(string answer)
(answer (ask (concat "Right margin [" docRightMargin "]: ")))
(if (!= answer "") {
(docRightMargin (convert-to NUMBER answer))
(word-wrap docRightMargin)
})
}
doc-set-justify
;; pre:
;; true
;; post:
;; - docJustfiy> equals TRUE
;; - docRightFlush> equals FALSE
;; - docCenter> equals FALSE
;; - changes are reflected in modes
;; returns:
;; void
{
(docJustify TRUE)
(docRightFlush FALSE)
(docCenter FALSE)
(doc-show-modes)
}
doc-set-left-flush
;; pre:
;; true
;; post:
;; - docJustfiy> equals FALSE
;; - docRightFlush> equals FALSE
;; - docCenter> equals FALSE
;; - changes are reflected in modes
;; returns:
;; void
{
(docJustify FALSE)
(docRightFlush FALSE)
(docCenter FALSE)
(doc-show-modes)
}
doc-set-right-flush
;; pre:
;; true
;; post:
;; - docJustfiy> equals FALSE
;; - docRightFlush> equals TRUE
;; - docCenter> equals FALSE
;; - changes are reflected in modes
;; returns:
;; void
{
(docJustify FALSE)
(docRightFlush TRUE)
(docCenter FALSE)
(doc-show-modes)
}
doc-set-center
;; pre:
;; true
;; post:
;; - docJustfiy> equals FALSE
;; - docRightFlush> equals FALSE
;; - docCenter> equals TRUE
;; - changes are reflected in modes
;; returns:
;; void
{
(docJustify FALSE)
(docRightFlush FALSE)
(docCenter TRUE)
(doc-show-modes)
}
)
;; Non-interactivally change document options.
(defun
;; set or get docTailOffset
doc-tail-offset
{
(if (!= 0 (nargs)) {
(docTailOffset (arg 0))
})
docTailOffset
}
;; set or get docRightMargin
doc-right-margin
{
(if (!= 0 (nargs)) {
(docRightMargin (arg 0))
})
docRightMargin
}
;; set or get docTabSize
doc-tab-size
{
(if (!= 0 (nargs)) {
(docTabSize (arg 0))
})
docTabSize
}
;; set or get docJustify
doc-justify
{
(if (!= 0 (nargs)) {
(docJustify (arg 0))
})
docJustify
}
;; set or get docRightFlush
doc-right-flush
{
(if (!= 0 (nargs)) {
(docRightFlush (arg 0))
})
docRightFlush
}
;; set or get docCenter
doc-center
{
(if (!= 0 (nargs)) {
(docCenter (arg 0))
})
docCenter
}
;; set or get docMinorMode
doc-minor-mode
{
(if (!= 0 (nargs)) {
(docMinorMode (arg 0))
})
docMinorMode
}
)
;; Hooks into docform.mut
(defun
doc-repaginate { (autoload "doc-repaginate" "docform" ) }
doc-set-lines-on-page { (autoload "doc-set-lines-on-page" "docform" ) }
doc-lines-on-page { (autoload "doc-lines-on-page" "docform" (push-args 0) ) }
doc-remove-pagebreaks { (autoload "doc-remove-pagebreaks" "docform" ) }
)
;; Enable document mode.
(defun
doc-mode
;; pre:
;; true
;; post:
;; - all active modes are cleared
;; - current mode settings are displayed
;; - all global variables used by this modules are given their
;; default values
;; - some keys are rebound according to this mode
;; returns:
;; void
{
(clear-modes)
(bind-local-key "newline-and-indent" "C-M")
(bind-local-key "doc-end-of-paragraph" "M-e")
(bind-local-key "doc-begin-of-paragraph" "M-a")
(bind-local-key "doc-select-paragraph" "M-h")
(bind-local-key "doc-format-paragraph" "M-J")
(bind-local-key "doc-flush-right" "M-`")
(docRightMargin DOC-DEF-RIGHT-MARGIN)
(docTailOffset DOC-DEF-TAIL-OFFSET)
(docTabSize DOC-DEF-TAB-SIZE)
(docJustify DOC-DEF-JUSTIFY)
(docRightFlush DOC-DEF-RIGHT-FLUSH)
(docCenter DOC-DEF-CENTER)
(docMajorMode DOC-MAJOR-MODE)
(docMinorMode DOC-MINOR-MODE)
(tab-stops DOC-DEF-TAB-SIZE)
(word-wrap DOC-DEF-RIGHT-MARGIN)
(if (pgm-exists "doc-mode-hook") {
(floc "doc-mode-hook" ())
})
(doc-show-modes)
}
)