1 ;;; tinytf.el --- Document layout tool for (T)echnical text (F)ormat
3 ;; This file is not part of Emacs
7 ;; Copyright (C) 1997-2007 Jari Aalto
10 ;; Maintainer: Jari Aalto
12 ;; To get information on this program, call M-x tinytf-version.
13 ;; Look at the code with folding.el.
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with program; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30 ;; Boston, MA 02110-1301, USA.
32 ;; Visit <http://www.gnu.org/copyleft/gpl.html> for more information
37 ;; ....................................................... &t-install ...
38 ;; Put this file on your Emacs-Lisp load path, add following into your
39 ;; ~/.emacs startup file.
41 ;; (add-hook 'tinytf-:load-hook 'turn-on-tinytf-mode-all-buffers)
42 ;; (setq tinytf-:mode-prefix-key "z") ;; faster than default C-c C-z
45 ;; or autoload and your Emacs starts faster, preferred method:
47 ;; (setq tinytf-:mode-prefix-key "z")
48 ;; (autoload 'tinytf-mode "tinytf" "" t)
49 ;; (autoload 'turn-on-tinytf-mode-maybe "tinytf" "" t)
51 ;; To use additional function keys, add this line:
53 ;; (setq tinytf-:mode-define-keys-hook
54 ;; '(tinytf-mode-define-keys tinytf-mode-define-f-keys)))
56 ;; Additional hooks to detect and format buffer (optional):
58 ;; (add-hook 'write-file-hooks 'tinytf-untabify-buffer)
59 ;; (add-hook 'find-file-hooks 'turn-on-tinytf-mode-maybe)
61 ;; If you feel that you have to redefine some binding to suit your
62 ;; keyboard better, please do add similar setup to your emacs
64 ;; (add-hook 'tinytf-:mode-define-keys-hook 'my-tinytf-mode-define-keys)
66 ;; (defun my-tinytf-mode-define-keys ()
67 ;; (let ((map tinytf-:mode-prefix-map))
68 ;; (tinytf-mode-define-keys) ;; Default keys.
69 ;; (tinytf-mode-define-f-keys)
70 ;; (define-key map "]" 'tinytf-mark-word-sample)
71 ;; (define-key map "[" 'ignore)
72 ;; (define-key map "{" 'tinytf-mark-word-emp)
73 ;; (define-key map "}" 'tinytf-mark-word-strong)))
75 ;; To make HTML, you need conversion Perl script *t2html.pl* available at
76 ;; http://perl-text2html.sourceforge.net/
78 ;; It is possible to write documentation into other files as well
79 ;; using TF format. There is another perl program that can extract the
80 ;; documentation into text/plain by omitting comments:
82 ;; http://cpan.perl.org/modules/by-authors/id/J/JA/JARIAALTO/
85 ;; For example this lisp file's documentation can be converted into HTML
86 ;; with following command sequence:
88 ;; % ripdoc.pl tinytf.el | t2html.pl > tinytf.html
90 ;; If you have any questions use this function to contact maintainer
92 ;; M-x tinytf-submit-bug-report
98 ;; ..................................................... &t-commentary ...
103 ;; Late in the 1996 there was a need for a better text file
104 ;; handling than just plan `text-mode'. I was looking for a simple
105 ;; tool to generate HTML pages out of text-based documents. After some
106 ;; researching on the web, I still couldn't find anything that would
107 ;; have been strictly a text-based solution. There were many "languages"
108 ;; from which the HTML could be generated, but really, I didn't want
109 ;; to learn any new language just for that. I can understand people
110 ;; that write their documents still using LaTeX, but Win32 Word
111 ;; is much suitable and more known than any of those exotic formats.
112 ;; The project started by creating the tool that converted text into
113 ;; HTML (Perl *t2html.pl* script) and then writing a Emacs package to
114 ;; help writing the text files. It has been proven to be really nice
115 ;; combination where flexibility meets cross-platform demands.
117 ;; Overview of features
119 ;; You can use `M-x' `add-change-log-entry-other-window' (C-x 4 a) to
120 ;; create a standard ChangeLog record for your changes under the
123 ;; The text layout you write
125 ;; o You write text in rigid format called 'Technical'
126 ;; o There are only two heading levels, one at column 0, and
127 ;; another at column 4. NO OTHER SUB-HEADINGS SUPPORTED.
128 ;; o Text is written at column 8, at the first standard tab position.
129 ;; o Each column has different meaning how text is interpreted
130 ;; into HTML with *t2html.pl* perl script.
131 ;; o The full 'Technical text format' is described in the
132 ;; function description of `tinytf-mode'. The most recent description
133 ;; is always described in the perl program t2html.pl --help
134 ;; o The is only a handful, natural, mark up conventions for PLAIN TEXT.
135 ;; The whole idea was that you do not need to learn any
136 ;; mark up language, but just write standard looking text, which is
137 ;; easily managed and edited with any editor. In addition `diff(1)',
138 ;; `patch(1)' and `cvs(1)' are the most effective tools to keep your
139 ;; "text" document project in condition and encourage others to
140 ;; contribute fixes to your text files.
144 ;; o Can show text in outline style manner: you can open and close
146 ;; o Provides commands to move among headings easily.
147 ;; o Capitalizes heading with one command.
148 ;; o Numbers headings with one command.
149 ;; o Text is untabified in regular intervals.
150 ;; o On-line help in 19.30+. It assist you writing the text
151 ;; by displaying message in echo area: how the text is interpreted by
152 ;; t2html.pl program, that is, how the text would look in HTML.
153 ;; o Offer functions to mark text with special text MARKERS that
154 ;; would produce <STRONG> or <EMP> and the like in the HTML.
156 ;; What is Technical Format?
158 ;; In short: it is list of text placement and formatting rules.
159 ;; And you're looking at it right now in this document.
161 ;; This package offers minor mode for text files and helps you to
162 ;; maintain correct layout. You can even convert file into HTML very
163 ;; easily with the perl script which is usually distributed in the
164 ;; complete Tiny Tools Kit or available separately from the CPAN
165 ;; under developer account JARIAALTO. You do not need to know a shred
166 ;; about the HTML language itself. And it is much easier to update
167 ;; text files, than deal with HTML itself. When you have text ready,
168 ;; you just feed it to the t2html.pl perl script and it gives you
169 ;; nicely formatted HTML page. Writing HTML *home* pages is different
170 ;; story, because you usually want to include some graphics,
171 ;; JavaScript, PHP or JSP in the page. But putting some text document
172 ;; available in HTML format is easily made possible with this package.
174 ;; In the other hand, while you may not be interested in HTML, you
175 ;; could still consider writing your documents in 'Technical format'
176 ;; -- with word *technical* I refer to the layout of the text, which
177 ;; is very _rigid_. In order to use facilities in this package,
178 ;; e.g. heading hiding/showing, the headings must be placed in
179 ;; columns 0 and 4 and the first word must be in *uppercase*. The
180 ;; actual text you write starts at column 8.
182 ;; If you decide write text like this, you become accustomed to the
183 ;; layout very quickly and it also helps keeping your documents in
186 ;; All in all, this package was primarily designed to help writing
187 ;; text documents for t2html.pl and viewing document in *outline*
188 ;; styled selective display. Please refer to mode description for
189 ;; full details of the text layout format.
191 ;; TF described briefly
193 ;; Please note, that this section may be slightly out of date.
194 ;; You should read up to date information from the conversion
195 ;; program using command `t2html.pl' `--help' available at
196 ;; http://perl-text2html.sourceforge.net/ and nearest Perl CPAN
197 ;; http://cpan.perl.org/modules/by-authors/id/J/JA/JARIAALTO/
199 ;; --//-- TF description start
201 ;; 0123456789 123456789 123456789 123456789 123456789 column numbers
205 ;; <Do not write any text inside this heading. It will>
206 ;; <be generated by tinytf.el automatically with M-x tinytf-toc>
208 ;; Heading 1 starts from left
210 ;; emphatised text at column 1,2,3
213 ;; This is heading 2 at column 4, started with big letter
215 ;; Standard text starts at column 8, you can
216 ;; *emphatize* text or make it _strong_ and show
217 ;; variable name like =ThisVariableSample=. notice that
218 ;; `ThisIsAlsoVariable' and you can even _*nest*_ the mark up.
219 ;; more txt in this paragraph txt txt txt txt txt txt txt txt
220 ;; txt txt txt txt txt txt txt txt txt txt txt txt txt txt txt
221 ;; txt txt txt txt txt txt txt txt txt txt txt txt txt txt txt
223 ;; Plain but colored text at columns 5, 6
225 ;; EMPhatised text starts at column 7, Like heading level 3
227 ;; "Special STRONG EMP text in column 7 starts with double quote"
229 ;; txt txt txt txt txt txt txt txt txt txt txt txt
230 ;; txt txt txt txt txt txt txt txt txt txt txt txt
231 ;; txt txt txt txt txt txt txt txt txt txt txt txt
233 ;; strong text at columns 9 and 11
235 ;; Column 10 has quotation text
236 ;; Column 10 has quotation text
237 ;; Column 10 has quotation text
239 ;; Column 12 is reserved for code examples
240 ;; Column 12 is reserved for code examples
241 ;; All text here are surrounded by SAMP codes
243 ;; Heading 2, at column 4 again
245 ;; txt txt txt txt txt txt txt txt txt txt txt txt
246 ;; txt txt txt txt txt txt txt txt txt txt txt txt
247 ;; txt txt txt txt txt txt txt txt txt txt txt txt
249 ;; o Bullet 1 txt txt txt txt txt txt txt txt
250 ;; ,txt txt txt txt txt txt txt txt
252 ;; Notice that previous paragraph ends to P-comma code,
253 ;; it tells this paragraph to continue in bullet
254 ;; mode, otherwise this column at 12 would be
255 ;; interpreted as SAMPLE code.
257 ;; o Bullet 2, text starts at column 12
258 ;; o Bullet 3. Bullets are advised to keep together
259 ;; o Bullet 4. Bullets are advised to keep together
261 ;; . This is ordered list nbr 1, text starts at column 12
262 ;; . This is ordered list nbr 2
263 ;; . This is ordered list nbr 3
265 ;; .This line uses BR code, notice the DOT-code at beginning
266 ;; .This line uses BR code
267 ;; .This line uses BR code
269 ;; "This is emphatized text starting at column 7"
270 ;; .And this text is put after the previous line with BR code
271 ;; "This starts as separate line just below previous one, EM"
272 ;; .And continues again as usual with BR code
274 ;; See the document #URL-BASE/document.txt, where #URL-BASE
275 ;; tag is substituted with -base switch contents.
277 ;; Make this email address clickable <foo\@site.com>
278 ;; Do not make this email address clickable -<bar\@site.com>,
279 ;; because it is only an example and not a real address.
280 ;; Noticed the minus(-) prefix at the beginning of url?
282 ;; Heading level 1 again at column 0
284 ;; Sub heading, column 4
286 ;; And regular text, column 8
287 ;; txt txt txt txt txt txt txt txt txt txt txt txt
288 ;; txt txt txt txt txt txt txt txt txt txt txt txt
289 ;; txt txt txt txt txt txt txt txt txt txt txt txt
291 ;; --//-- TF description end
293 ;; How do you write text
295 ;; This package turns on two minor modes: `tinytab-mode', that handles
296 ;; your TAB key movements and `tinytf-mode', the Technical format
297 ;; minor mode. If you're uncertain about how the column will be
298 ;; treated in HTML output, call following function. If you have 19.30+
299 ;; this is not necessary, see note about post command above.
301 ;; Do you wonder why 'z' prefix is default? Well, I wanted a fast
302 ;; key that was mostly unused. You can change that if you prefer
303 ;; some other key. See variable `tinytf-:mode-prefix-key'
305 ;; z RET tinytf-column-info-display
307 ;; Normal text you write as usual, but if you want to mark regions
308 ;; as "quotations" or "code examples" there is appropriate indent
311 ;; z / tinytf-indent-region-text
312 ;; z ' tinytf-indent-region-quote
313 ;; z ; tinytf-indent-region-sample
314 ;; z : tinytf-indent-region-strong
316 ;; z t tinytf-indent-paragraph-text
317 ;; z a tinytf-indent-paragraph-text-as-is
318 ;; z l tinytf-indent-paragraph-text-and-fill
319 ;; z q tinytf-indent-paragraph-quote
320 ;; z Q tinytf-indent-paragraph-quote-and-fill
321 ;; z s tinytf-indent-paragraph-sample
322 ;; z 0 tinytf-indent-paragraph-zero
324 ;; The `tinytf-indent-paragraph-text-as-is' is a bit special, because
325 ;; it won't fill the text while it moves the paragraph to the text
326 ;; position. Instead it adds symbolic <BR> codes to the front of every
327 ;; moved line. In HTML this ensures that the lines will be shown
328 ;; exactly as you see them. See also BR mark commands.
330 ;; There is no functions for bullet creation, because you can write
331 ;; them easily by hand. Use `z' `b' to fill bullet text nicely.
332 ;; Bullets look like this
334 ;; o This is bullet..
335 ;; and cont'd line here
336 ;; o Yet another bullet
337 ;; and cont'd line here
339 ;; The `tinytab-mode' will advance your tab key by 4 every time, so
340 ;; the text in the bullets go to the right column (12). Remember also
341 ;; to keep the `tinytab-return-key-mode' on, because that continues
342 ;; lines as they were written above when you press return. See also
343 ;; bullet conversion command, which reformats previous text that used
344 ;; dashes(-) to separate bullets.
346 ;; z b tinytf-bullet-format
348 ;; BR marking commands
350 ;; In Html, the text would normally wrap according to the browser's
351 ;; page width. But sometimes you may wish to tell exactly that
352 ;; it shouldn't wrap the lines according to browser. For example
353 ;; if you want to include a quoted text "as is" from the Usenet
354 ;; posts to your page, you need o add symbolic BR code to the beginning
355 ;; of each line. Like including the following quotation
357 ;; >>Jim has a good point here...
358 ;; >>I would have expected that the system depends on..
359 ;; >Yeah; but you hadn't looked at the /usr/adm/today.log
362 ;; In order to add this to your page "as is"; you can do this:
363 ;; indent it as "Sample" and it will automatically show like that.
364 ;; But normally you want it to show as quoted text where you refer.
367 ;; z Q tinytf-indent-paragraph-quote
368 ;; z m b tinytf-mark-br-paragraph
370 ;; Which will prepend dot-code(.) to the front of every line.
371 ;; You can also add the *dot-code* by yourself or use following
374 ;; z m B tinytf-mark-br-line
376 ;; Heading writing and handling
378 ;; You can only use 2 heading levels, which normally suffices. Sorry,
379 ;; there is no support for more deeper headings. You start headings
380 ;; with big letters or number at column 0 or 4. Here is some
381 ;; specialized commands for headings.
383 ;; This one converts first character of each heading to
384 ;; uppercase. This fixes mistakenly left lowercase letters.
386 ;; z f h tinytf-heading-fix
396 ;; You can (re)number heading easily with following command. If
397 ;; there is no number in the line, one is added to the beginning of
398 ;; heading. And if you have added new heading somewhere in the
399 ;; middle of text, just call this function and it renumbers all
400 ;; headings again. Running command with *prefix* *argument* removes
403 ;; z f 0 tinytf-heading-numbering
417 ;; One note about renumbering. Some people write heading number so
418 ;; that they are closed with parenthesis. This style is not
419 ;; recommended with technical format style and when you do renumber,
420 ;; those parenthesis will be removed. The parenthesis style is not
421 ;; supported because the plain number style is more easily parsed
422 ;; and detected. In addition, the plain number style in headings is
423 ;; more widely used in the world.
436 ;; z f a `tinytf-fix-all'
437 ;; Does lot's of things. Trim away trailing blanks
438 ;; from buffer. Untabify buffer.
439 ;; Renumber headings if needed. Delete extra whitespace
442 ;; z f c `tinytf-heading-fix-case'
443 ;; convert current heading to lowercase
445 ;; z f C `tinytf-heading-fix-case-all'
446 ;; convert all heading to lowercase
448 ;; About table of contents
450 ;; When you write text, you don't write the table of contents, but
451 ;; the headings. Be sure to add heading "Table of contents" somewhere
452 ;; in the document. To generate table of contents use commands:
454 ;; z T tinytf-toc, Try with C-u argument too
455 ;; z mouse-1 tinytf-toc-mouse
459 ;; The hiding and showing of the headings and their text is done by
460 ;; using the outline/folding style display. There is no magic in this;
461 ;; but there is two interesting commands that you can use in any
462 ;; selective display buffer.
464 ;; z C-p Prints selective display (what you actually see)
465 ;; z C-c Copy selective display
467 ;; Word about key definitions when mode is turned on
469 ;; When the minor mode is active it overrides some commonly used
470 ;; key bindings and moves their original function under Control key.
473 ;; original PgUp --> Now Control-PgUp
474 ;; original PgDown --> Now Control-PgDown
476 ;; PgUp --> Moving heading backward
477 ;; DownUp --> Moving heading forward
479 ;; If you are using X environment or your emacs recognizes mouse,
480 ;; then there is one handy binding that opens or closes heading
481 ;; levels when you click over them.
483 ;; [mouse-3] tinytf-mouse-context-sensitive
485 ;; If you press this mouse button anywhere else than over the
486 ;; headings, it'll call original binding. This feature is similar as
487 ;; what is used in folding.el
489 ;; Technical note: about the outline layout
491 ;; Speed was my primary goal when I added the outline code. But that
492 ;; came with a price: I would have liked that the Heading-1 were
493 ;; separated by at least one empty space so that the buffer would
494 ;; look visually better.
499 ;; << empty space here
504 ;; But that would have required adding some extra code to do bound
505 ;; checking every time the block is collapsed/opened. Currently I'm
506 ;; not going to add that checking because it would reduce speed and
507 ;; the check would cause unnecessary complexity to current code
510 ;; Technical note: about the default prefix key z
512 ;; The prefix key can be defined by setting `tinytf-:mode-prefix-key'
513 ;; The default binding is `C-c` `C-z', but if you want more comfortable
514 ;; editing, you can set it to "z". When the key is a single character,
515 ;; the key "doubles"; i.e. pressing "zz" will generate the plain "z"
518 ;; Technical note: post command
520 ;; This note is valid only for old Emacs releases, prior 20.x.
522 ;; While you type text in the buffer, the post command activates at
523 ;; regular intervals to untabify the buffer. The untabify is done
524 ;; because it makes formatting text easier and when you print the text
525 ;; file, you can be sure that the output is the same regardless of
528 ;; If you have Emacs 19.30+ there is additional help feature available
529 ;; to you. When you sit still in some column position for few seconds,
530 ;; the column description will be shown automatically. That should
531 ;; help keeping you informed of the text layout.
533 ;; Technical note: HTML utilities
535 ;; Two external utilities are searched for HTML generation:
536 ;; t2html.pl and htmlize.el. If these utilities are found,
537 ;; their locations are stored to plist of variable `tinytf-menu'.
538 ;; See source code of function `tinytf-utility-programs-check'
543 ;; In Emacs 20.6 the TinyTf pull down menu contains bold titles
544 ;; for certain sections. This gets almost always garbled with
545 ;; the first pull-down. Selecting the menu second time shows
546 ;; correct section names with bold letters.
554 ;;{{{ Libraries and compilation
559 (ti::package-use-dynamic-compilation)
560 ;; Need grep-regexp-alist
564 (defvar tinytab-mode nil)
565 (defvar tinytab-:div-factor nil)
566 ;; Just forward declarations to shut up byte compiler.
567 (defvar font-lock-keywords)
568 (defvar font-lock-mode)
569 (defvar global-font-lock-mode)
570 (defvar grep-regexp-alist)
571 (defvar add-log-current-defun-header-regexp)
572 (autoload 'compile-internal "compile")
573 (if (or (fboundp 'htmlize-buffer)
574 (locate-library "htmlize"))
575 (autoload 'htmlize-buffer "htmlize" "" t)
577 ** tinytf.el: Hm, no htmlize.el found. [you can still use this package]
578 2001-10-10 it was at http://fly.srk.fer.hr/~hniksic/emacs/htmlize.el")))
580 (ti::package-defgroup-tiny TinyTf tinytf-: wp
581 "Minor mode for writing text in 'Technical text format'.
583 o You write text in rigid format called 'Technical'
584 o There are only two heading levels, one at column 0, and
585 another at column 4. NO OTHER SUB-HEADINGS SUPPORTED.
586 o Text is written in column 8
587 o Each column has different meaning how text is intepreted
589 o The full 'Technical text format' is described in the
590 function description of `tinytf-mode'")
595 (defcustom tinytf-:load-hook nil
596 "*Hook that is run when package is loaded."
600 (defcustom tinytf-:process-compile-hook
601 '(tinytf-compile-mode-settings)
602 "*Hook that is run when compile is called (See link check)."
606 (defcustom tinytf-:move-paragraph-hook nil
607 "*Hook run with arguments BEG END of region that was moved."
611 (defcustom tinytf-:fix-all-hook nil
612 "*Hook run when function `tinytf-fix-all' is called."
616 (defcustom tinytf-:tinytf-mode-p-function 'tinytf-text-format-file-p
617 "*Function to check if buffer is in Techical Format.
618 Function must return t or nil."
622 (defcustom tinytf-:t2html-link-cache-file
623 (ti::package-config-file-prefix "tinytf-link-cache.txt")
624 "*File to contains cached OK links for the link check feature."
628 (defcustom tinytf-:buffer-file-name-html-source-function
629 'tinytf-convert-buffer-file-name-html-source
630 "*Return filename from where to read plain text.
631 For files this should be `buffer-file-name', but for buffer
632 that are not associated with file, a temporary filename shoudl be generated.
640 (defcustom tinytf-:buffer-file-name-html-destination-function
641 'tinytf-convert-buffer-file-name-html-destination
642 "*Return filename where the HTML is stored.
650 (defcustom tinytf-:binary-t2html
651 (let ((path (ti::file-path-to-unix
652 (ti::file-get-load-path "t2html.pl" exec-path))))
654 (message "tinytf.el: FOUND %s" path)
657 "tinytf.el: ** No t2html.pl along PATH. "
658 "Visit http://perl-text2html.sourceforge.net/")))
660 "Path to t2html.pl perl script. Do not rename t2html.pl."
665 ;;{{{ setup: user config
667 (defcustom tinytf-:heading-regexp "[A-Z0-9!]"
668 "*Heading character set regexp. This charset is case sensitive.
669 If there is these characters immediately after indentation, then line
672 The default regexp is [A-Z0-9!], where the ! is used as a special control
673 code. The double !! signifies in the produced html
674 that there should be <hr> code before heading. Like the following.
676 !! This heading has HR code in the html."
677 :type '(string :tag "Charset regexp")
680 (defcustom tinytf-:heading-regexp-no-numbering "[!]"
681 "*When numbering headings, ignore headings matching this regexp.
682 at the beginning of first word."
686 (defcustom tinytf-:sentence-end "[.?!][]\"')}]*[ \r\n]+"
687 "*Like `sentence-end'. Used only in movement commands."
691 (defcustom tinytf-:paragraph-start "^[ \t]*$"
692 "*Like `paragraph-start'. Used only in movement commands."
696 (when (ti::emacs-p "21") ;; Variable width faces available
698 (defface tinytf-quote-face
699 '((((type tty pc) (class color))
700 (:foreground "lightblue" :weight bold))
701 (t (:height 1.0 :family "Georgia" )))
702 "Face for real quotes"
705 (defvar tinytf-quote-face 'tinytf-quote-face)
707 (defface tinytf-quote2-face
708 '((((type tty pc) (class color))
709 (:foreground "lightblue" :weight bold))
710 (t (:height 1.2 :family "helv" :italic t)))
711 "Face for temporary highlight quote"
714 (defvar tinytf-quote2-face 'tinytf-quote2-face)
716 (defface tinytf-level-1-face
717 '((((type tty pc) (class color)) (:foreground "blue" :weight bold))
718 (t (:height 1.2 :inherit tinytf-level-2-face)))
719 "Face for titles at level 1."
722 (defvar tinytf-level-1-face 'tinytf-level-1-face)
724 (defface tinytf-level-2-face
725 '((((type tty pc) (class color)) (:foreground "lightblue" :weight bold))
726 (t (:height 1.2 :inherit tinytf-level-3-face)))
727 "Face for titles at level 2."
730 (defvar tinytf-level-2-face 'tinytf-level-2-face)
732 (defface tinytf-level-3-face
733 '((((type tty pc) (class color)) (:foreground "black" :weight bold))
734 (t (:height 1.2 :inherit variable-pitch)))
735 "Face for titles at level 3."
738 (defvar tinytf-level-3-face 'tinytf-level-3-face))
740 ;; Order of these rexeps is very important; because there are many
741 ;; "override" flags set to 't.
743 ;; 1999-11-23 `font-lock-other-type-face' doesn't exist in XEmacs 21.1.6
745 ;; Please COPY this variable settign to your $HOME/.emacs if you
746 ;; want to change the colors. substitute `defcustom' with `setq'
747 ;; and delete the variable comments at the end.
749 (defcustom tinytf-:font-lock-keywords ;; &font
755 (concat (concat "^" (make-string 8 ?\ ) "[o.] "))
756 0 'font-lock-reference-face)
758 ;; bullet continue comma
761 (concat (concat "^" (make-string 12 ?\ ) "[,]"))
762 0 'font-lock-reference-face)
764 ;; #REF and other user defined markers. See perl script
765 ;; for option --reference REF=value that lets you define
772 "[^ \t\r\r\n][^ \t\r\n][^ \t\r\n]+")
773 0 'font-lock-type-face)
775 ;; Column 2 small bold blue
778 (concat "^ \\([^ \t].*\\)$")
779 1 'font-lock-builtin-face)
781 ;; Column 3, emphasized
784 (concat "^ \\([^ \t].*\\)$")
785 1 'font-lock-constant-face)
790 (concat "^ \\([^ \t].*\\)$")
792 'font-lock-type-face)
795 (concat "^ \\([^ \t].*\\)$")
797 (if (or (and (fboundp 'get-face) ;; XEmacs
798 (get-face 'tinytf-quote-face))
799 (facep 'tinytf-quote-face))
801 'font-lock-comment-face))
803 ;; Colum 7, leading double quote
806 (concat "^" (make-string 7 ?\ ) "\\(\"[^ \t].*\\)$")
807 1 'font-lock-comment-face)
809 ;; Colum 7 and 9, Strong [Small level 3 headers]
812 (concat "^" (make-string 7 ?\ ) "\\([^ \t].*\\)$")
814 (if (or (and (fboundp 'get-face) ;; XEmacs
815 (get-face 'tinytf-level-3-face))
816 ;; Only works in Emacs. Returns nil in XEmacs
817 (facep 'tinytf-level-3-face))
819 'font-lock-comment-face)
823 (concat "^" (make-string 9 ?\ ) "\\([^ \t].*\\)$")
824 1 'font-lock-comment-face)
826 ;; Colum 10, Quotation
829 (concat "^" (make-string 10 ?\ ) "\\([^ \t].*\\)$")
831 (if (or (and (fboundp 'get-face) ;; XEmacs
832 (get-face 'tinytf-quote2-face))
833 (facep 'tinytf-quote2-face))
835 'font-lock-type-face))
838 (concat "^" (make-string 11 ?\ ) "\\([^ \t].*\\)$")
839 1 'font-lock-constant-face)
841 ;; ..................................................... emphasisis ...
843 ;; _bold_ *italic* and =small=
845 '("_[^ \t\r\n]+_" 0 font-lock-type-face)
847 '("\\*[^ \t\r\n]+\\*" 0 font-lock-variable-name-face)
849 '(" =[^ '\t\r\n]+=" 0 font-lock-builtin-face prepend)
851 ;; ISO standard date YYYY-MM-DD HH:MM
855 "\\<[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]")
856 0 'font-lock-keyword-face)
858 ;; .................................................... references ...
860 ;; A long reference. There must be space somewhere otherwise
861 ;; this regexp would overlap with the shorter reference
862 ;; (font lock would do double job)
864 ;; [1998-08 Phil carmody pc@foo.com in vegetarian-L]
867 (let* ((re "\\(\\[[^][\r\n]+ [^][\r\n]+\\]\\)"))
873 1 'font-lock-keyword-face t)
876 "\\(\\[[^][\r\n]+ [^][\r\n]+\\]\\)"
877 1 'font-lock-keyword-face)
879 ;; When you refer to people or to document you do it like this
881 ;; [phil] said that [perlguts] is the document you should read..
883 '("\\(\\[[^ \t\r\n]+\\]\\)" 1 font-lock-type-face t)
885 ;; ........................................................ strings ...
889 '("\\<[A-Z][-/_.A-Z0-9]+\\>" 0 font-lock-variable-name-face)
893 '("`\\([^ '\t\r\n]+\\)'" 1 font-lock-reference-face prepend)
895 ;; ........................................................... urls ...
897 ;; File names or programs
899 '("[ \t\r\n][\\/][^ \t\r\n]+\\>" 0 font-lock-comment-face t)
901 ;; URL highlighting, we won't highlight Whole URL, because
902 ;; then the document would look like Xmas tree if it had
903 ;; hundreads of links. (or tens of links)
906 (concat "\\(http\\|ftp\\|news\\|wais\\)://"
908 "\\|[\\][\\][^ \t\r\n]+" ;; UNC \\machine\dir
910 ;; There is no good regexp to detect Win32 idiotic
911 ;; "space in filenames"
913 "\\|\\<[a-zA-Z]:[\\][^ \t\r\n]+" ;; c:\windows\file.txt
914 "\\|\\<\\([a-zA-Z]:\\)?/[^ \t\r\n]+") ;; c:/windows/file.txt
915 0 'font-lock-reference-face t)
916 ;; <foo@site.com> Email URLs.
917 '("\\(<[^ \t\r\n]+@[^ \t\r\n]+>\\)" 1 font-lock-reference-face t)
920 ;;; (concat "^" (make-string 12 ?\ ) "\\(.*\\)$")
921 ;;; '(1 font-lock-reference-face))
923 ;;; #todo: Hmm, font-lock doesn't allow calling functions?
925 ;;; The font-lock could also call functions that set the matched regions.
926 ;;; However that doesn't seem to work. The code snippet below hangs,
927 ;;; But if called directly via M-x tinytf-code-p, it works ok. Don't
928 ;;; know what is the problem,
930 ;;; '(tinytf-code-p . font-lock-reference-face)
932 ;; ........................................................ heading ...
936 "^\\([.A-Z0-9].*\\)$"
938 (if (or (and (fboundp 'get-face) ;; XEmacs
939 (get-face 'tinytf-level-1-face))
940 ;; Only works in Emacs. Returns nil in XEmacs
941 (facep 'tinytf-level-1-face))
943 'font-lock-keyword-face)
947 "^ \\([.A-Z0-9].*\\)$"
949 (if (or (and (fboundp 'get-face) ;; XEmacs
950 (get-face 'tinytf-level-2-face))
951 ;; Only works in Emacs. Returns nil in XEmacs
952 (facep 'tinytf-level-2-face))
954 'font-lock-keyword-face)
956 ;; font-lock-reference-face font-lock-keyword-face
957 ;; font-lock-type-face font-lock-function-name-face
958 ;; font-lock-string-face font-lock-comment-face
959 ;; font-lock-variable-name-face
961 ;; font-lock-keywords
963 "*Font lock keywords."
968 ;;{{{ suetup: private variables
970 (defvar tinytf-:process-compile-html "tinytf-compile-html"
971 "Name of the buffer/mode used for HTML compiling.")
973 (defvar tinytf-:process-compile-link "tinytf-compile-link"
974 "Name of the buffer/mode used for HTML link check.")
976 (defvar tinytf-:file-last-html-generated nil
977 "Filename of the last HTML generation.")
979 (defconst tinytf-:factor 4
980 "The indent factor. DO NOT CHANGE THIS. It is hard coded to 4.")
982 (defconst tinytf-:heading-number-level 2
983 "*Number of levels. Zero based. Allow values 0,1,2.")
985 (defvar tinytf-:counter nil
986 "Post command counter.")
987 (make-variable-buffer-local 'tinytf-:counter)
989 (defvar tinytf-:buffer-heading "*tinytf-headings*"
990 "List of gatehered Headings from buffer.")
992 (defvar tinytf-:buffer-html-process "*tinytf-t2html*"
993 "Output of t2html.pl run.")
997 (defsubst tinytf-indent (&optional level)
998 "Return indent space string at LEVEL. Default is 0."
1001 (make-string (+ (* 4 1) 3) ?\ ))
1003 (make-string (* tinytf-:factor (or level 0)) ?\ )))))
1005 (defvar tinytf-:add-log-current-defun-header-regexp
1007 ;; [text] Detect heading Levels 1 and 2 with possible numbering
1009 ;; 1.0 Heading level one
1011 ;; 1.1 Heading level two
1013 "^\\( [0-9]+\\(\\.[0-9.]+\\)+[ \t]+[A-Z].*"
1014 "\\|^[0-9]+\\(\\.[0-9.]+\\)+[ \t]+[A-Z].*"
1018 "*Additional ChangeLog regepx to recognize tinytf.el headings.
1019 This variable's locally set to `add-log-current-defun-header-regexp'
1020 when `tinytf-mode' is turned on.")
1022 (defvar tinytf-:heading-ignore-regexp-form
1024 "Table [Oo]f [Cc]ontents"
1025 ;; This is special <HR> mark, see t2html.pls
1027 "\\|^[0-9.]*[ \t]*End[ \t]*$"
1028 "\\|End[ \t]+of[ \t]+\\(file\\|document\\)[ \t]*$"
1030 (concat "^" ;; \\(" (tinytf-indent 0) "\\|"
1031 "\\(" (tinytf-indent 1) "\\)?"
1032 tinytf-:heading-regexp-no-numbering))
1033 "When making Table Of Contents, ignore these headings.
1034 This variable contains Lisp form that is evaled to get the string.
1035 If nil, then include all headings, dropping none.")
1037 (defconst tinytf-:column-table
1039 ;; First the most common positions.
1040 (0 ((nil "Heading 0")))
1041 (4 ((nil "Heading 1")))
1042 (8 ((nil "Standard text")))
1043 ;; Then special positions
1044 (1 ((nil "Emphatised")))
1045 (2 ((nil "Emphatised")))
1046 (3 ((nil "Emphatised")))
1047 (5 ((nil "Normal text, colored")))
1048 (6 ((nil "Normal text, colored")))
1049 (7 (("\"" "Emphatised")
1050 (nil "Heading 3, Strong")))
1056 "Single line, <BR> added to the end of line")
1058 "Line continues in next chapter. <P> code not added")))
1059 (9 ((nil "Strong")))
1060 (10 ((nil "Quotation, emphatised")))
1061 (11 ((nil "Normal, colored.")))
1064 "Bullet continues in next chapter. <P> code not added")
1067 "Column positions and their properties. DO NOT TOUCH THIS.
1068 The positions are fixed and reflect the perl program t2html.pl's HTML generation.
1071 '((COL ((REGEXP-OR-NIL EXPLANATION-STRING)
1072 (REGEXP-OR-NIL EXPLANATION-STRING)
1074 (COL ((RE EXPL) (RE EXPL) ..)))")
1076 (defvar tinytf-:saved-indent-tabs-mode
1077 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1079 (defvar tinytf-:saved-left-margin
1080 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1082 (defvar tinytf-:saved-tinytab-mode
1083 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1085 (defvar tinytf-:saved-font-lock-keywords
1086 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1088 (defvar tinytf-:saved-auto-fill-function
1089 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1091 (defvar tinytf-:saved-auto-fill-inhibit-regexp
1092 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1094 (defvar tinytf-:saved-comment-start
1095 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1097 (defvar tinytf-:saved-comment-end
1098 "Buffer local variable. Holds copy of original value before `tinytf-mode'.")
1103 ;;; ----------------------------------------------------------------------
1104 ;;; #todo: experimental
1105 (defun tinytf-code-p (&optional limit)
1106 "Determine if current text is code. LIMIT parameter is passed by font-lock."
1107 (let* ((re (eval-and-compile (concat "^" (make-string 12 ?\ )))))
1111 (and (looking-at re) ;match to return to font-lock
1112 (goto-char (match-end 0))
1113 (looking-at "\\(.*\\)$")))
1115 (save-match-data ;Now check if it was really ok
1116 (message (ti::read-current-line))
1121 (while (and (not (bobp))
1122 (not (input-pending-p))
1123 (looking-at "^[ \t]*$"))
1125 (message (ti::read-current-line))
1128 (not (input-pending-p))
1129 ;; Same indentation still
1131 ;; Not a P-comma code in bullet?
1132 (not (looking-at ".*[,o.]"))))))))))
1134 ;;; ----------------------------------------------------------------------
1137 (defun tinytf-tmp-swallow-empty-backwards ()
1146 ;;; ----------------------------------------------------------------------
1149 (defun tinytf-tmp-swallow-code-backwards ()
1151 (let* ((re (eval-and-compile (concat "^" (make-string 12 ?\ ))))
1152 (b-cont-re (eval-and-compile (concat "^" (make-string 12 ?\ ) ",")))
1153 (empty (eval-and-compile (concat "^$"))))
1165 (tinytf-tmp-swallow-empty-backwards)
1167 (not (looking-at b-cont-re))
1169 (tinytf-tmp-swallow-code-backwards))))))
1171 ;;; ----------------------------------------------------------------------
1174 (defun tinytf-tmp-dxc-code-p (&optional limit)
1176 (let* ((bullet (eval-and-compile
1177 (concat (concat "^" (make-string 8 ?\ ) "[o.] "))))
1178 (re (eval-and-compile (concat "^" (make-string 12 ?\ ))))
1179 (b-cont-re (eval-and-compile (concat "^" (make-string 12 ?\ ) ",")))
1180 (empty (eval-and-compile (concat "^$"))))
1185 (and (looking-at re)
1186 (goto-char (match-end 0))
1187 ;; match to return to font-lock
1188 (looking-at "\\(.*\\)$"))))
1192 (if (looking-at empty)
1193 (tinytf-tmp-swallow-empty-backwards))
1194 (if (not (looking-at re))
1197 (tinytf-tmp-swallow-code-backwards)
1198 (not (or (looking-at b-cont-re)
1199 (looking-at bullet)))))))))
1201 ;;; ----------------------------------------------------------------------
1202 ;;; a simple one for testing only.
1205 (defun tinytf-tmp-dxc-2-code-p (&optional limit)
1207 (let* ((re (eval-and-compile (concat "^" (make-string 12 ?\ )))))
1215 ;;;###autoload (autoload 'tinytf-version "tinytf" "Display commentary." t)
1218 (ti::macrof-version-bug-report
1222 "$Id: tinytf.el,v 2.93 2007/05/07 10:50:14 jaalto Exp $"
1223 '(tinytf-:version-id
1225 tinytf-:mode-define-keys-hook
1231 tinytf-:mode-prefix-key
1232 tinytf-:heading-regexp
1234 tinytf-:column-table)))
1237 ;;{{{ Minor Mode definition
1239 ;;; .......................................................... &v-mode ...
1240 ;;;###autoload (autoload 'tinytf-install-mode "tinytf" "" t)
1241 ;;;###autoload (autoload 'tinytf-mode "tinytf" "" t)
1242 ;;;###autoload (autoload 'turn-on-tinytf-mode "tinytf" "" t)
1243 ;;;###autoload (autoload 'turn-off-tinytf-mode "tinytf" "" t)
1244 ;;;###autoload (autoload 'tinytf-commentary "tinytf" "" t)
1247 (ti::macrof-minor-mode-wizard
1248 "tinytf-" " Tf" "\C-c\C-z" "Tf" 'TinyTf "tinytf-:" ;1-6
1250 "Minor mode for writing and editing text in technical format (TF).
1251 The text layout presented in this minor mode is ment to be
1252 feed to t2html.pls perl script which generates html out of
1255 The perl code is included in source file and can be unpacked with
1256 command \\[tinytf-install-files]
1258 To see the complete layout description and rules,
1259 run command `tinytf-commentary'. However, this description
1260 may be a little out of synch and you should consult perl file
1261 t2html.pl, available at nearest Perl CPAN http://cpan.perl.org/, for
1262 up to date description.
1266 \\{tinytf-:mode-prefix-map}
1269 "Technical text format"
1272 ;; reinstall is done every time, because some key definitions
1273 ;; are built dynamically from current/global map
1274 ;; Make C-x 4 a to detect text headings for ChangeLog
1275 (tinytf-install-add-log (if tinytf-mode
1280 (tinytf-utility-programs-check)
1281 (with-buffer-modified
1282 (tinytf-install-mode)
1283 (make-local-variable 'tinytf-:saved-indent-tabs-mode)
1284 (make-local-variable 'tinytf-:saved-left-margin)
1285 (make-local-variable 'tinytf-:saved-tinytab-mode)
1286 (make-local-variable 'tinytf-:saved-font-lock-keywords)
1287 (make-local-variable 'tinytf-:saved-comment-start)
1288 (setq tinytf-:saved-indent-tabs-mode indent-tabs-mode)
1289 (setq tinytf-:saved-left-margin left-margin)
1290 (setq tinytf-:saved-tinytab-mode tinytab-mode)
1291 ;; Emacs 21.2 newcomment.el breaks if these are not set
1292 ;; properly. When auto-fill-mode is on, the call chain is:
1295 ;; self-insert-command
1297 ;; comment-indent-new-line (newcomment.el)
1298 ;; comment-normalize-vars
1299 (setq tinytf-:saved-comment-start comment-start)
1300 (setq tinytf-:saved-comment-end comment-end)
1301 (setq comment-start "")
1302 (setq comment-end "")
1303 ;; When auto fill is used, do not indent lines that
1304 ;; contain special tags starting with "#", which may continue
1305 ;; past the right side. The tags must all be in one line, not
1306 ;; broken to multiple lines:
1308 ;; #PIC pic/this-picture.jpg # Explanation which is long ..... ###
1310 ;; Also, do not break long headings.
1312 ;; 2.2 This long chapter ....
1313 (make-local-variable 'auto-fill-inhibit-regexp)
1314 (setq tinytf-:saved-auto-fill-inhibit-regexp auto-fill-inhibit-regexp)
1315 (setq auto-fill-inhibit-regexp "^[ \t]+#\\|^[ \t]+[0-9]\\.[0-9] [A-Z]")
1316 (make-local-variable 'tinytf-:saved-auto-fill-function)
1317 (setq tinytf-:saved-auto-fill-function auto-fill-function)
1318 (turn-on-auto-fill-mode)
1319 (setq selective-display t
1320 selective-display-ellipses t
1321 ;; left-margin 8 ;; for return key
1322 indent-tabs-mode nil)
1323 (unless tinytab-mode ;;Turn on this mode
1324 (setq tinytf-:saved-tinytab-mode nil)
1325 (turn-on-tinytab-mode))
1326 (setq tinytab-:div-factor 4) ;; advance by four spaces
1327 ;; Make sure RETURN key continues indent.
1328 (turn-on-tinytab-return-key-mode)
1329 ;; Single space ends sentence. The Emacs default is some
1330 ;; old relict that nobody uses, or should use any more.
1331 (make-local-variable 'sentence-end-double-space)
1332 (setq sentence-end-double-space nil)
1333 ;; (make-local-variable 'sentence-end)
1334 ;; (setq sentence-end "[.?!][]\"')}]*\\($\\|[ \t]\\)[ \t\r\n]*"
1335 ;; Use our font lock keywords this time and save original
1336 (when (boundp 'font-lock-keywords)
1337 (setq tinytf-:saved-font-lock-keywords font-lock-keywords)
1338 (tinytf-font-lock-mode))))
1340 (with-buffer-modified
1342 (setq indent-tabs-mode tinytf-:saved-indent-tabs-mode)
1343 (setq auto-fill-function tinytf-:saved-auto-fill-function)
1344 (setq auto-fill-inhibit-regexp tinytf-:saved-auto-fill-inhibit-regexp)
1345 (setq comment-start tinytf-:saved-comment-start)
1346 (when (integerp tinytf-:saved-left-margin)
1347 (setq left-margin tinytf-:saved-left-margin))
1348 (if tinytf-:saved-tinytab-mode
1349 (turn-on-tinytab-mode)
1350 (turn-off-tinytab-mode))
1351 (setq selective-display nil)
1352 (tinytf-show-buffer)
1353 (when (boundp 'font-lock-keywords)
1354 (setq font-lock-keywords tinytf-:saved-font-lock-keywords)
1355 (when (ti::colors-supported-p)
1357 ;; force font lock to rework everything
1358 (set-buffer-modified-p nil)
1359 (set-text-properties (point-min) (point-max) nil)
1360 (tinytf-fontify-current-buffer-window))))))))
1362 "Technical text writing menu."
1365 tinytf-:mode-easymenu-name
1367 ["Mark word strong" tinytf-mark-word-strong t]
1368 ["Mark word sample" tinytf-mark-word-sample t]
1369 ["Mark word emphatised" tinytf-mark-word-emp t]
1370 ["Mark word small" tinytf-mark-word-small t]
1371 ["Mark word big" tinytf-mark-word-big t]
1372 ["Mark <BR> line" tinytf-mark-br-line t]
1373 ["Mark <BR> paragraph" tinytf-mark-br-paragraph t]
1374 ["Unmark word" tinytf-unmark-word t]
1376 ["Convert to bullet" tinytf-bullet-format t]
1377 ["Indent paragraph text" tinytf-indent-paragraph-text t]
1378 ["Indent paragraph text 'as is'" tinytf-indent-paragraph-text-as-is t]
1379 ["Indent paragraph text and fill" tinytf-indent-paragraph-text-and-fill t]
1380 ["Indent paragraph Quote" tinytf-indent-paragraph-quote t]
1381 ["Indent paragraph Quote and fill" tinytf-indent-paragraph-quote-and-fill t]
1382 ["Indent paragraph Sample" tinytf-indent-paragraph-sample t]
1385 ["Indent paragraph zero" tinytf-indent-paragraph-zero t]
1386 ["Indent paragraph 2" tinytf-indent-paragraph-2 t]
1387 ["Indent paragraph 3" tinytf-indent-paragraph-3 t]
1388 ["Indent paragraph 5" tinytf-indent-paragraph-5 t]
1389 ["Indent paragraph 6" tinytf-indent-paragraph-6 t]
1390 ["Indent paragraph 11" tinytf-indent-paragraph-11 t])
1395 ["HTML basic" tinytf-convert-t2html-basic
1396 (get 'tinytf-mode 't2html)]
1397 ["HTML frames" tinytf-convert-t2html-frame
1398 (get 'tinytf-mode 't2html)]
1399 ["HTML as you see" tinytf-convert-t2html-as-is
1400 (get 'tinytf-mode 't2html)]
1401 ["Link check" tinytf-convert-t2html-link-check
1402 (get 'tinytf-mode 't2html)]
1403 ["Link check (with cache)" tinytf-convert-t2html-link-check-cached
1404 (get 'tinytf-mode 't2html)]
1407 ["HTML buffer" tinytf-convert-htmlize
1408 (get 'tinytf-mode 'htmlize)]
1410 ["View HTML with browser" tinytf-convert-view-default t]
1411 ["View HTML source" tinytf-convert-view-html-source t]
1413 ["Conversion preferences" tinytf-convert-preference-set t]
1414 ["Conversion menu re-evaluate" tinytf-utility-programs-check-force t])
1417 ["Indent region strong" tinytf-indent-region-strong t]
1418 ["Indent region sample" tinytf-indent-region-sample t]
1419 ["Indent region quote" tinytf-indent-region-quote t]
1420 ["Indent region text" tinytf-indent-region-text t])
1423 "Heading management"
1424 ["Heading 1 backward" tinytf-heading-backward-0 t]
1425 ["Heading 1 forward" tinytf-heading-forward-0 t]
1426 ["Heading 2 backward" tinytf-heading-backward-any t]
1427 ["Heading 2 forward" tinytf-heading-forward-any t]
1429 ["Heading numbering" tinytf-heading-numbering t]
1430 ["Heading fix 1st chars" tinytf-heading-fix t]
1431 ["Heading fix case" tinytf-heading-fix-case t]
1432 ["Heading fix case all" tinytf-heading-fix-case-all t]
1434 ["Paragraph forward" tinytf-forward-paragraph t]
1435 ["Paragraph backward" tinytf-backward-paragraph t])
1438 ["Hide buffer" tinytf-hide-buffer t]
1439 ["Show buffer" tinytf-show-buffer t]
1440 ["Hide heading" tinytf-hide t]
1441 ["Show heading" tinytf-show t]
1442 ["Show/hide toggle" tinytf-show-toggle t])
1445 ["Toc create" tinytf-toc t]
1446 ["Toc popup" tinytf-toc-mouse t]
1447 ["Toc Occur" tinytf-toc-occur t]
1449 ["Selective display copy" ti::buffer-selective-display-copy-to t]
1450 ["Selective display print" ti::buffer-selective-display-print t]
1452 ["Untabify buffer" tinytf-untabify-buffer t]
1453 ["Column info" tinytf-column-info-display t])
1456 ["Package version" tinytf-version t]
1457 ["Package commentary" tinytf-commentary t]
1458 ["Mode and menu reload" tinytf-mode-reload t]
1459 ["Mode help" tinytf-mode-help t]
1460 ["Mode exit and cleanup" tinytf-exit t]
1461 ["Mode exit" turn-off-tinytf-mode t])
1464 (define-key map "?" 'tinytf-mode-help)
1465 (define-key map "H" nil)
1466 (define-key map "Hm" 'tinytf-mode-help)
1467 (define-key map "Hc" 'tinytf-commentary)
1468 (define-key map "Hv" 'tinytf-version)
1469 (define-key map "n" 'tinytf-heading-numbering)
1470 (define-key map "u" 'tinytf-untabify-buffer)
1472 ;; mouse binding "Prefix + mouse-1"
1473 (define-key map "T" 'tinytf-toc)
1474 (define-key map "O" 'tinytf-toc-occur)
1476 (define-key map [(mouse-1)] 'tinytf-toc-mouse)
1477 (define-key map [(button1)] 'tinytf-toc-mouse))
1479 ;; Marking commands in non-shift keys
1480 ;; STRONG = "."; like a heavy statement that
1481 ;; ends like this: "I said that. Perioti::d!"
1483 ;; It is most likely that you "EMP" characters most of the time;
1484 ;; That's why "`" is not defined as "w-". And to Undo easily
1485 ;; marking, the unmark must be fast to access via " ".
1487 (define-key map " " 'tinytf-unmark-word)
1488 (define-key map "-" 'tinytf-mark-word-strong)
1489 (define-key map "'" 'tinytf-mark-word-sample) ;; code
1490 (define-key map "*" 'tinytf-mark-word-emp) ;; italics
1491 (define-key map "+" 'tinytf-mark-word-big)
1492 (define-key map "_" 'tinytf-mark-word-small)
1493 (define-key map "mB" 'tinytf-mark-br-line)
1494 (define-key map "mb" 'tinytf-mark-br-paragraph)
1495 ;; If you're converting some document to TF format,
1496 ;; therse are the commands you will use 80% of the time.
1497 (define-key map "rS" 'tinytf-indent-region-strong)
1498 (define-key map "rs" 'tinytf-indent-region-sample)
1499 (define-key map "rq" 'tinytf-indent-region-quote)
1500 (define-key map "rt" 'tinytf-indent-region-text)
1501 (define-key map "c" nil)
1502 (define-key map "ct" nil)
1503 (define-key map "chb" 'tinytf-convert-t2html-basic)
1504 (define-key map "chf" 'tinytf-convert-t2html-frame)
1505 (define-key map "cha" 'tinytf-convert-t2html-as-is)
1506 (define-key map "chl" 'tinytf-convert-t2html-link-check)
1507 (define-key map "chL" 'tinytf-convert-t2html-link-check-cached)
1508 (define-key map "chH" 'tinytf-convert-htmlize)
1509 (define-key map "cr" 'tinytf-utility-programs-check-force)
1510 (define-key map "cp" 'tinytf-convert-preference-set)
1511 (define-key map "cvv" 'tinytf-convert-view-default)
1512 (define-key map "cvf" 'tinytf-convert-view-html-source)
1513 (define-key map "b" 'tinytf-bullet-format)
1514 (define-key map "t" 'tinytf-indent-paragraph-text)
1515 (define-key map "a" 'tinytf-indent-paragraph-text-as-is)
1517 (define-key map "l" 'tinytf-indent-paragraph-text-and-fill)
1518 (define-key map "q" 'tinytf-indent-paragraph-quote-and-fill)
1519 (define-key map "Q" 'tinytf-indent-paragraph-quote)
1520 (define-key map "s" 'tinytf-indent-paragraph-sample)
1521 (define-key map "0" 'tinytf-indent-paragraph-zero)
1522 (define-key map "1" 'tinytf-indent-paragraph-11)
1523 (define-key map "2" 'tinytf-indent-paragraph-2)
1524 (define-key map "3" 'tinytf-indent-paragraph-3)
1525 (define-key map "5" 'tinytf-indent-paragraph-5)
1526 (define-key map "6" 'tinytf-indent-paragraph-6)
1527 (define-key map "f" nil)
1528 (define-key map "fa" 'tinytf-fix-all)
1529 (define-key map "fh" 'tinytf-heading-fix)
1530 (define-key map "fC" 'tinytf-heading-fix-case-all)
1531 (define-key map "fc" 'tinytf-heading-fix-case)
1532 (define-key map "fn" 'tinytf-heading-fix-newlines)
1533 ;; Selective display
1534 (define-key map "Sp" 'ti::buffer-selective-display-print)
1535 (define-key map "Sc" 'ti::buffer-selective-display-copy-to)
1537 (define-key map "\C-q" 'tinytf-show-toggle)
1538 (define-key map "\C-x" 'tinytf-hide)
1539 (define-key map "\C-s" 'tinytf-show)
1540 (define-key map "\C-w" 'tinytf-hide-buffer)
1541 (define-key map "\C-y" 'tinytf-show-buffer)
1543 (define-key map "\C-m" 'tinytf-column-info-display)
1544 (define-key map "xr" 'tinytf-mode-reload)
1545 (define-key map "xX" 'tinytf-exit)
1546 (define-key map "xx" 'turn-off-tinytf-mode)
1547 ;; Original PgUp and down keys --> move under Control key
1548 (ti::copy-key-definition root-map [(control prior)] [(prior)])
1549 (ti::copy-key-definition root-map [(control next)] [(next)])
1550 (define-key root-map [(prior)] 'tinytf-heading-backward-any)
1551 (define-key root-map [(next)] 'tinytf-heading-forward-any)
1552 (define-key root-map [(shift prior)] 'tinytf-heading-backward-0)
1553 (define-key root-map [(shift next)] 'tinytf-heading-forward-0)
1554 ;; The Shift-prior do not always show in non-window system, so define
1556 (define-key map "\C-p" 'tinytf-heading-backward-0)
1557 (define-key map "\C-n" 'tinytf-heading-forward-0)
1558 ;; The 'home' and 'end' keys
1559 (ti::copy-key-definition root-map [(control end)] [(end)])
1560 (ti::copy-key-definition root-map [(control home)] [(home)])
1561 (ti::copy-key-definition root-map [(control select)] [(select)])
1562 (define-key root-map [(home)] 'tinytf-backward-paragraph)
1563 (define-key root-map [(select)] 'tinytf-forward-paragraph)
1564 (define-key root-map [(end)] 'tinytf-forward-paragraph)
1566 (define-key map [(mouse-3)]
1567 'tinytf-mouse-context-sensitive)
1568 (define-key map [(button3)]
1569 'tinytf-mouse-context-sensitive))))))
1571 ;;; ----------------------------------------------------------------------
1574 (defun tinytf-mode-define-f-keys ()
1575 "Define default function key to `tinytf-:mode-map'."
1577 (let* ((map tinytf-:mode-map))
1578 ;; more faster keys than the "w" word markup map.
1579 (define-key map [(f5)] 'tinytf-mark-word-emp)
1580 (define-key map [(f7)] 'tinytf-mark-word-strong)
1581 (define-key map [(f8)] 'tinytf-mark-word-sample)
1582 (define-key map [(f9)] 'tinytf-unmark-word)
1583 (define-key map [(f10)] 'tinytf-indent-paragraph-text-and-fill)
1584 (define-key map [(f11)] 'tinytf-indent-paragraph-quote-and-fill)
1585 (define-key map [(f12)] 'tinytf-indent-paragraph-sample)))
1587 ;;; ----------------------------------------------------------------------
1589 (defun tinytf-mode-reload ()
1590 "Reload and activate greyed menus (if new programs available).
1591 If you have changed `exec-path' or added htmlize.el along
1592 `load-path' the menus do not know when this has happened.
1594 Calling this function re-eaxamines available utilities."
1596 (tinytf-utility-programs-check-force))
1601 ;;; ----------------------------------------------------------------------
1603 ;;;###autoload (autoload 'tinytf-install-files "tinytf" "" t)
1604 (ti::macrof-install-pgp-tar tinytf-install-files "tinytf.el")
1606 ;;; ----------------------------------------------------------------------
1608 (defun tinytf-font-lock-mode ()
1609 "Install `font-lock' support. Activates only if `tinytf-mode' is on."
1610 (when (and tinytf-mode
1611 (boundp 'font-lock-keywords)
1612 (or (and (boundp 'font-lock-mode)
1614 (and (boundp 'global-font-lock-mode)
1615 global-font-lock-mode)))
1616 (when (font-lock-mode-maybe 1)
1617 (setq font-lock-keywords tinytf-:font-lock-keywords)
1618 ;; if lazy-lock is in effect, it may not fontify the current window
1620 (tinytf-fontify-current-buffer-window))))
1622 ;;; ----------------------------------------------------------------------
1624 (defun tinytf-install-eval-after-load (&optional uninstall)
1625 "Intall or UNINSTALL `eval-after-load' for add-log.el."
1626 (let* ((form '(tinytf-install-add-log-all-buffers)))
1629 (dolist (elt after-load-alist)
1630 (when (and (string-match "add-log" (car elt))
1631 (member form (cdr elt)))
1632 (setq after-load-alist (delete elt after-load-alist)))))
1634 (eval-after-load "add-log" form)))))
1636 ;;; ----------------------------------------------------------------------
1638 (defun tinytf-install-add-log (&optional uninstall)
1639 "Install or UNINSTALL add-log.el support.
1640 Calling this function makes variable
1641 `add-log-current-defun-header-regexp' local in the current
1642 buffer. The variable includes regexp to match heading levels so that
1643 the ChangeLog entry is put in parentheses:
1645 * file.txt (This Heading): <explanation>
1650 `tinytf-:add-log-current-defun-header-regexp'."
1651 (let ((sym 'add-log-current-defun-header-regexp))
1653 ;; See `add-log-current-defun'
1655 (kill-local-variable sym)
1656 (make-local-variable sym)
1657 (set sym tinytf-:add-log-current-defun-header-regexp)))))
1659 ;;; ----------------------------------------------------------------------
1661 (defun tinytf-install-add-log-all-buffers ()
1662 "Install add-log.el support for all `tinytf-mode' buffers."
1663 (ti::dolist-buffer-list
1667 (tinytf-install-add-log)))
1669 ;;; ----------------------------------------------------------------------
1671 (defun tinytf-install (&optional uninstall verb)
1672 "Install hook to mode or UNINSTALL. VERB allows verbose messages."
1675 (tinytf-install-eval-after-load uninstall))
1677 ;;; ----------------------------------------------------------------------
1679 (defun tinytf-text-format-not-p ()
1680 "This is backup to verify after running `tinytf-text-format-p'.
1681 Function `tinytf-text-format-p' may consider the file as TF format,
1682 but it would be good to check few things before making decisive
1685 (or (ti::re-search-check
1686 ;; Two consequent lines together, not good.
1687 "^[^ \t\r\n].*\\(\r\n\\|\r\\|\n\\)[^ \t\r\n]"
1690 ;;; ----------------------------------------------------------------------
1692 (defun tinytf-text-format-ok-p-test-toc ()
1693 "Check if buffer content looks like technical format.
1694 This is low level check. Use `tinytf-text-format-ok-p' instead."
1695 (ti::re-search-check
1696 ;; 1) If we see this
1697 "^Table [Oo]f [Cc]ontents[ \t]*$"
1700 ;;; ----------------------------------------------------------------------
1702 (defun tinytf-text-format-ok-p-test-headings ()
1703 "Check if buffer content looks like technical format.
1704 This is low level check. Use `tinytf-text-format-ok-p' instead."
1705 ;; See if you can find two consequtive headings. The
1706 ;; extra ".*" at the end of regexp is just for debugging
1707 ;; purpose: what are the lines that were matched. Headings
1710 ;; Heading one 1.0 Heading one
1712 ;; Heading two 1.1 Heading two
1713 (ti::re-search-check
1715 "^\\(\\([0-9]\\.[0-9.]*[0-9]\\) \\)?[A-Z][^ \t\f\r\n].*"
1716 "\\(\n\n\\|\r\n\r\n\\)" ;; Two newlines
1717 " \\(\\([0-9]\\.[0-9.]*[0-9]\\) \\)?[A-Z][^ \t\f\r\n].*")
1720 ;;; ----------------------------------------------------------------------
1722 (defun tinytf-text-format-ok-p-test-heading-and-text ()
1723 "Check if buffer content looks like technical format.
1724 This is low level check. Use `tinytf-text-format-ok-p' instead."
1725 ;; Try to find one heading and regular text
1729 ;; And normal text at column 8
1731 ;; But take into account a special case, where the text starts
1732 ;; at column 7, which causes it to be rendered as "small
1737 ;; This is small heading, at column 7, offset -1
1739 ;; And normal text at column 8
1740 ;; And normal text at column 8
1742 ;; This is small heading, at column 7, offset -1
1743 (ti::re-search-check
1745 "^\\( \\)?\\([0-9]\\.[0-9.]*[0-9] \\)?[A-Z][A-Za-z].*"
1746 "\\(\n\n\\|\r\n\r\n\\)"
1747 " ? ? ?[A-Z][A-Za-z].*")
1750 ;;; ----------------------------------------------------------------------
1752 (defun tinytf-text-format-ok-p ()
1753 "Check if buffer content looks like technical format."
1755 (let* (case-fold-search
1757 ;; Exclude mail messages from any checks.
1758 (unless (ti::mail-mail-p)
1760 (or (tinytf-text-format-ok-p-test-toc)
1761 (tinytf-text-format-ok-p-test-headings)
1762 (tinytf-text-format-ok-p-test-heading-and-text))))
1765 (message "Tinytf: No TF formattting found in this buffer.")
1766 (message "Tinytf: Found TF format location [%s]" ret)))
1769 ;;; ----------------------------------------------------------------------
1771 (defun tinytf-text-format-p ()
1772 "Check if buffer looks like TF format."
1773 (and (tinytf-text-format-ok-p)
1774 (not (tinytf-text-format-not-p))))
1776 ;;; ----------------------------------------------------------------------
1778 (defun tinytf-text-format-file-p ()
1779 "Test that file extension is .txt and `tinytf-text-format-p' returns t."
1782 (or (buffer-file-name) ""))
1783 (tinytf-text-format-p)))
1785 ;;; ----------------------------------------------------------------------
1788 (defun turn-on-tinytf-mode-maybe ()
1789 "If buffer looks like technical format, turn on `tinytf-mode'.
1791 `tinytf-:tinytf-mode-p-function'."
1792 (when (and tinytf-:tinytf-mode-p-function
1793 (funcall tinytf-:tinytf-mode-p-function))
1794 (turn-on-tinytf-mode)
1795 ;; Hook must return nil
1798 ;;; ----------------------------------------------------------------------
1800 (defun turn-on-tinytf-mode-all-buffers ()
1801 "Call`tinytf-mode' on in all technical format buffers. Optionally OFF.
1802 The buffer is detected by using function strored in variable
1803 `tinytf-:tinytf-mode-p-function'"
1805 (when tinytf-:tinytf-mode-p-function
1806 (ti::dolist-buffer-list
1807 (and (null tinytf-mode)
1808 (string-match "text" (downcase (symbol-name major-mode)))
1809 (funcall tinytf-:tinytf-mode-p-function))
1812 (turn-on-tinytf-mode))))
1815 ;;{{{ macros, defsubst
1817 ;;; These macros create functions
1819 ;;; For some unknown reason the ByteCompiler doesn't see thse
1820 ;;; function in the followed macros unless the functions are wrapped
1821 ;;; inside eval-and-compile FORM.
1823 ;;; fmacro = function create macro
1827 ;;; ----------------------------------------------------------------------
1829 (defun tinytf-fmacro-indent-region-1 (func doc col msg &rest body)
1830 "Use `tinytf-fmacro-indent-region' with FUNC DOC COL MSG BODY."
1831 (let* ((sym (intern (symbol-name (` (, func))))))
1833 (defun (, sym) (beg end &optional verb)
1838 (tinytf-move-paragraph-to-column
1844 ;;; ----------------------------------------------------------------------
1846 (defun tinytf-fmacro-mark-word-1 (func doc char1 &optional char2)
1847 "Use `tinytf-fmacro-mark-word' with FUNC DOC CHAR1 CHAR2."
1848 (let* ((sym (intern (symbol-name (` (, func))))))
1853 (unless (ti::space-p (preceding-char))
1854 (skip-chars-backward "^ ,\t\f\r\n"))
1855 (insert (char-to-string (, char1)))
1856 (skip-chars-forward "^ ,\t\f\r\n")
1857 (insert (char-to-string (or (, char2) (, char1))))
1858 (skip-chars-forward " ,\t\f\r\n")))))
1860 ;;; ----------------------------------------------------------------------
1862 (defun tinytf-paragraph-bounds ()
1863 "Return (beg . end) points of paragraph."
1864 (let* ((empty-line (ti::nil-p (ti::read-current-line)))
1869 (if (not empty-line)
1870 (or (re-search-backward "^[ \t]*$" nil t)
1874 (skip-chars-forward " \t\r\n"))
1875 (or (re-search-forward "^[ \t]*$" nil t) (ti::pmax))
1880 ;;; ----------------------------------------------------------------------
1882 (defun tinytf-fmacro-indent-paragraph-1 (func doc col msg &rest body)
1883 "Use `tinytf-fmacro-indent-paragraph'."
1884 (let* ((sym (intern (symbol-name (` (, func))))))
1886 (defun (, sym) (&optional verb)
1889 (let* ((region (tinytf-paragraph-bounds))
1890 (beg (car-safe region))
1891 (end (cdr-safe region)))
1894 (if verb (message "%s: Cannot find paragraph bounds."
1896 (tinytf-move-paragraph-to-column
1905 ;;; --++-- --++-- --++-- --++-- --++-- --++-- --++-- --++-- - eval end --
1908 ;;; ----------------------------------------------------------------------
1910 (defmacro tinytf-fmacro-indent-region (func doc col msg &optional body)
1911 "Create indent function FUNC with DOC COL MSG BODY.
1912 Created function arguments: (beg end &optional verb)"
1913 (` (, (tinytf-fmacro-indent-region-1
1920 ;;; ----------------------------------------------------------------------
1922 (defmacro tinytf-fmacro-mark-word (func doc char1 &optional char2)
1923 "Create word marking function FUNC with DOC and CHAR.
1924 Created function arguments: ()"
1925 (` (, (tinytf-fmacro-mark-word-1
1926 func doc char1 char2))))
1928 ;;; ----------------------------------------------------------------------
1930 (put 'tinytf-fmacro-indent-paragraph 'edebug-form-spec '(body))
1931 (defmacro tinytf-fmacro-indent-paragraph (func doc col msg &optional body)
1932 "Create word marking function FUNC with DOC and COL, MSG and BODY.
1933 Created function arguments: ()"
1934 (` (, (tinytf-fmacro-indent-paragraph-1
1935 func doc col msg body))))
1937 ;;; These are conventional macros
1939 ;;; ----------------------------------------------------------------------
1941 (put 'tinytf-paragraph-macro 'lisp-indent-function 0)
1942 (put 'tinytf-paragraph-macro 'edebug-form-spec '(body))
1943 (defmacro tinytf-paragraph-macro (&rest body)
1944 "Set paragraph values locally while executing BODY."
1946 (let* ((sentence-end tinytf-:sentence-end)
1947 (paragraph-start tinytf-:paragraph-start)
1948 (paragraph-separate paragraph-start))
1951 ;;; ----------------------------------------------------------------------
1953 (put 'tinytf-heading-macro 'lisp-indent-function 0)
1954 (put 'tinytf-heading-macro 'edebug-form-spec '(body))
1955 (defmacro tinytf-heading-macro (&rest body)
1956 "Map over every heading. The point sits at the beginning of heading text.
1957 The BODY must move the point so that next heading can be found."
1959 (let* ((RE-search (concat
1961 (if (> tinytf-:heading-number-level 0)
1962 (concat "\\|" (tinytf-regexp 1)))
1963 (if (> tinytf-:heading-number-level 1)
1964 (concat "\\|" (tinytf-regexp 2)))))
1965 (RE-no (or (eval tinytf-:heading-ignore-regexp-form)
1966 "NothingMatchesLikeThis")))
1968 (tinytf-heading-start)
1969 (while (re-search-forward RE-search nil t)
1970 (unless (string-match RE-no (ti::read-current-line))
1973 ;;; ----------------------------------------------------------------------
1975 (put 'tinytf-level-macro 'lisp-indent-function 0)
1976 (put 'tinytf-level-macro 'edebug-form-spec '(body))
1977 (defmacro tinytf-level-macro (&rest body)
1978 "Search begin point of current heading level or signal error.
1979 You can refer to variable 'level' and 'beg' and 'end' in the BODY.
1980 The point is at start of level."
1982 (let* ((level (tinytf-level-number))
1986 (if (tinytf-heading-backward-any)
1987 (setq level (tinytf-level-number))
1988 (error "Can't find begin point")))
1990 end (tinytf-block-end))
1994 ;;; ----------------------------------------------------------------------
1996 (defsubst tinytf-regexp (&optional level)
1997 "Return indent regexp string at LEVEL."
1998 ;; control character are not counted, like ^L page mark
1999 (concat "^" (tinytf-indent level) tinytf-:heading-regexp))
2001 ;;; ----------------------------------------------------------------------
2003 (defsubst tinytf-level-p (&optional level)
2004 "Check if line is LEVEL."
2005 (let* (case-fold-search) ;case sensitive match
2008 (looking-at (tinytf-regexp level)))))
2010 ;;; ----------------------------------------------------------------------
2012 (defsubst tinytf-level-number ()
2013 "Check current level on this line."
2015 ((tinytf-level-p 0) 0)
2016 ((tinytf-level-p 1) 1)
2017 ((tinytf-level-p 2) 2)))
2019 ;;; ----------------------------------------------------------------------
2021 (defsubst tinytf-block-end ()
2022 "Return text block end."
2024 (if (null (tinytf-heading-forward-any))
2029 ;;; ----------------------------------------------------------------------
2031 (defsubst tinytf-heading-number-regexp (&optional no-grouping)
2032 "Return heading number regexp: match 'N.n ' or 'N.n) '.
2033 If NO-GROUPING is non-nil, the regexp will not have regexp group operator."
2035 "[0-9]+\\.[0-9.]*[0-9])?[ \t]+"
2036 "\\([0-9]+\\.[0-9.]*[0-9])?[ \t]+\\)"))
2038 ;;; ----------------------------------------------------------------------
2040 (defsubst tinytf-headings-numbered-p ()
2041 "Check if first heading is numbered."
2044 (re-search-forward (tinytf-heading-number-regexp) nil t)))
2046 ;;; ----------------------------------------------------------------------
2048 (defsubst tinytf-heading-string (&rest levels)
2049 "Return heading string. 'MAJOR.MINOR '."
2050 (let ((str (number-to-string (pop levels))))
2051 (dolist (nbr levels)
2052 (setq str (concat str "." (number-to-string nbr))))
2055 ;;; ----------------------------------------------------------------------
2057 (defun tinytf-goto-non-space ()
2058 "Goto first non-whitespace of bol."
2060 (if (re-search-forward "^[ \t]+" (line-end-position) t)
2061 (goto-char (match-end 0))))
2063 ;;; ----------------------------------------------------------------------
2065 (defsubst tinytf-heading-same-p (level heading-regexp)
2066 "Check if heading LEVEL is identical to HEADING-REGEXP.
2067 After the regexp there must be non whitespace, which starts the heading
2074 (tinytf-indent level)
2076 ;; After the spaces there must be NON-space to start
2080 ;;; ----------------------------------------------------------------------
2082 (defun tinytf-toc-goto ()
2083 "Goto Table of contents and return t or to `point-min'."
2085 (when (re-search-forward "^Table [Oo]f [Cc]ontents[ \t]*$" nil t)
2092 ;;; ----------------------------------------------------------------------
2094 (defun tinytf-convert-preference-set ()
2095 "Set HTML conversion preferences."
2097 (message "tinytf-convert-preference-set is not yet implemented.")
2100 ;;; ----------------------------------------------------------------------
2102 (put 'tinytf-convert-view-macro 'lisp-indent-function 0)
2103 (put 'tinytf-convert-view-macro 'edebug-form-spec '(body))
2104 (defmacro tinytf-convert-view-macro (&rest body)
2105 "Check file `tinytf-:file-last-html-generated' and run BODY."
2107 (let* ((file tinytf-:file-last-html-generated))
2108 (when (or (not file)
2109 (not (file-exists-p file)))
2110 (error "TinyTf: Can't view HTML, file not available [%s]"
2111 (prin1-to-string file)))
2114 ;;; ----------------------------------------------------------------------
2116 (defun tinytf-convert-view-default ()
2117 "View last HTML with `browse-url'."
2119 (tinytf-convert-view-macro
2120 ;; (browse-url file)
2121 (tinyurl-agent-funcall 'url file)))
2123 ;;; ----------------------------------------------------------------------
2125 (defun tinytf-convert-view-html-source ()
2126 "View last HTML with `find-file-other-window'."
2128 (tinytf-convert-view-macro
2129 (find-file-other-window file)))
2131 ;;; ----------------------------------------------------------------------
2133 (defsubst tinytf-convert-file-name-html (file)
2134 "Make FILE.txt FILE.html"
2135 (concat (file-name-sans-extension file) ".html"))
2137 ;;; ----------------------------------------------------------------------
2139 (defun tinytf-convert-buffer-file-name-html-source (buffer)
2140 "Return filename from where to read plain text.
2141 For files this should be `buffer-file-name', but for buffer
2142 that are not associated with file, a temporary filename is
2143 generated using `ti::temp-file'."
2144 (or (buffer-file-name buffer)
2145 (ti::temp-file "tinytf-temp.html" 'temp-dir)))
2147 ;;; ----------------------------------------------------------------------
2149 (defun tinytf-convert-html-source (&optional buffer)
2150 "Return BUFFER's source file name. Default is `current-buffer'.
2151 See `tinytf-:buffer-file-name-html-source-function'"
2153 tinytf-:buffer-file-name-html-source-function
2156 (error "TinyTf: HTML source function failed.")))
2158 ;;; ----------------------------------------------------------------------
2160 (defun tinytf-convert-html-destinaton (&optional buffer)
2161 "Return BUFFER's destination file name. Default is `current-buffer'.
2162 See `tinytf-:buffer-file-name-html-destination-function'"
2163 (let* ((file (funcall
2164 tinytf-:buffer-file-name-html-destination-function
2166 (current-buffer)))))
2168 (error "TinyTf: HTML destination function failed %s."
2170 tinytf-:buffer-file-name-html-destination-function)))
2171 (setq tinytf-:file-last-html-generated file)))
2173 ;;; ----------------------------------------------------------------------
2175 (defsubst tinytf-file-name-html (file)
2176 "Make FILE.txt => FILE.html"
2177 (concat (file-name-sans-extension file) ".html"))
2179 ;;; ----------------------------------------------------------------------
2181 (defun tinytf-convert-buffer-file-name-html-destination (buffer)
2182 "Make buffer's FILE.txt => FILE.html"
2183 (tinytf-file-name-html (buffer-file-name buffer)))
2185 ;;; ----------------------------------------------------------------------
2187 (defsubst tinyperl-convert-binary-t2html ()
2188 "Return t2html.el full path."
2189 (let ((bin (get 'tinytf-mode 't2html)))
2191 (not (file-exists-p bin)))
2193 (substitute-command-keys "\
2194 No t2html.pl available. Run HTML=>Conversion menu re-evaluate\
2195 \\[tinytf-utility-programs-check-force]")))
2198 ;;; ----------------------------------------------------------------------
2200 (put 'tinytf-convert-wrapper-macro 'lisp-indent-function 1)
2201 (put 'tinytf-convert-wrapper-macro 'edebug-form-spec '(body))
2202 (defmacro tinytf-convert-wrapper-macro (temp &rest body)
2203 "Define some common variables in `let'.
2205 Variables available:
2207 file-name Buffer's file name or nil
2208 file The filename (possibley generated) for HTML output.
2212 TEMP if non-nil, write temporary buffers to disk
2213 BODY rest of the lisp forms."
2215 (let* ((file-name (buffer-file-name))
2216 (file (tinytf-convert-html-source)))
2219 (let* ((buffer (current-buffer)))
2221 (insert-buffer buffer)
2222 (write-region (point-min) (point-max) file))))
2225 ;;; ----------------------------------------------------------------------
2227 (defun tinytf-convert-call-process (&optional options process mode)
2228 "Convert buffer using Perl t2html.pl.
2229 In order to use this function, `tinytf-utility-programs-check' must
2230 have been called to set location of perl script.
2232 The current buffer is used as source. Temporary buffers
2233 are written on disk.
2237 OPTIONS List of option to be passed to t2html.pl
2238 Following options are usually the minunum:
2239 '(\"--Out\" \"buffer-file-name.txt\")
2240 Nil values will be ignored.
2242 PROCESS 'compile [this is default]
2243 'call-prosess, see also MODE
2245 MODE This is only used for PROCESS 'call-process
2246 'noerr = Do not display log on error.
2247 'display = Display the result buffer
2248 nil = Dislpay on only if process printed something
2249 (a possible HTML conversion error)
2253 '(html-file-name status). non-nil status is an error.
2254 Status may also be compile buffer process."
2256 (setq options (delq nil options))
2257 (tinytf-convert-wrapper-macro 'temp-write
2258 (message "TinyTf: Generating HTML... (t2html) %s" file-name)
2259 ;; This may take a while
2260 ;; We feed the script to Perl and that works in every
2262 (let* ((log (get-buffer-create tinytf-:buffer-html-process))
2263 (target (tinytf-convert-html-destinaton))
2264 (dir (file-name-directory target))
2265 (opt (append options
2272 (with-current-buffer log
2273 (insert (format "\nTinyTf: t2html.pl run %s\n"
2274 (ti::date-standard-date 'minutes)))
2276 (insert (format "Source: %s\n" file)
2277 (format "Target: %s\n" target))
2279 ((eq process 'call-process)
2281 (apply 'call-process "perl"
2285 (tinyperl-convert-binary-t2html)
2287 (message "TinyTf: Generating HTML...done. %s" target)
2289 ((or (eq mode 'display)
2291 (not (ti::buffer-empty-p))))
2292 (setq status 'error)
2293 (append-to-buffer log (point-min) (point-max))
2294 (display-buffer log))
2298 (let* ((command (concat
2300 (tinyperl-convert-binary-t2html)
2303 (ti::list-to-string opt))))
2304 (compile-internal command
2306 tinytf-:process-compile-html
2308 ;; Turn on URL recognizer so that lines can be clicked
2309 (with-current-buffer
2312 tinytf-:process-compile-html))
2313 (run-hooks 'tinytf-:process-compile-hook))
2314 (message "TinyTf: Generating HTML... compile. %s"
2316 (ti::append-to-buffer
2318 (format "\nEnd: %s\n"
2319 (ti::date-standard-date 'minutes)))
2320 (list target status)))))
2322 ;;; ----------------------------------------------------------------------
2324 (defsubst tinytf-convert-extra-options ()
2325 "If there is #t2html-* tag, return list of additional options."
2326 (when (ti::re-search-check "#t2html-")
2327 '("--Auto-detect")))
2329 ;;; ----------------------------------------------------------------------
2331 (defun tinytf-convert-t2html-basic ()
2334 (tinytf-convert-call-process
2335 (tinytf-convert-extra-options)))
2337 ;;; ----------------------------------------------------------------------
2339 (defun tinytf-convert-t2html-frame ()
2340 "Make HTML with frames using t2html.pl"
2342 (tinytf-convert-call-process
2344 (tinytf-convert-extra-options)
2345 (list "--html-frame"))))
2347 ;;; ----------------------------------------------------------------------
2349 (defun tinytf-convert-t2html-as-is ()
2350 "Make HTML with frames using t2html.pl"
2352 (tinytf-convert-call-process '("--as-is")))
2354 ;;; ----------------------------------------------------------------------
2356 (defun tinytf-convert-t2html-link-check (&optional options)
2357 "Call t2html.pl to check links with OPTIONS."
2359 (tinytf-convert-wrapper-macro 'temp-write
2360 (let* ((command-args
2362 (tinyperl-convert-binary-t2html)
2365 "--link-check --quiet")
2368 ;; compile-internal:
2374 ;; error-regexp-alist
2376 ;; enter-regexp-alist
2377 ;; leave-regexp-alist
2378 ;; file-regexp-alist
2379 ;; nomessage-regexp-alist
2380 (compile-internal command-args
2382 tinytf-:process-compile-html
2384 grep-regexp-alist))))
2386 ;;; ----------------------------------------------------------------------
2388 (defun tinytf-convert-t2html-link-check-cached ()
2389 "Call t2html.pl to check links by using `tinytf-:t2html-link-cache-file'."
2391 (unless (stringp tinytf-:t2html-link-cache-file)
2392 (error "Tinytf: `tinytf-:t2html-link-cache-file' must contain filename."))
2393 (tinytf-convert-t2html-link-check
2394 (format "--link-check --quiet --Link-cache %s"
2395 tinytf-:t2html-link-cache-file)))
2397 ;;; ----------------------------------------------------------------------
2399 (defun tinytf-compile-mode-settings ()
2400 "Install font lock and additional keybindings for Link check."
2404 ;;; ----------------------------------------------------------------------
2406 (defun tinytf-convert-htmlize ()
2407 "Convert buffer using Perl htmlize.el"
2409 (unless (fboundp 'htmlize-buffer)
2410 (error "TinyTf: `htmlize-buffer' is not available. You need htmlize.el"))
2411 (let* ((path (get 'tinytf-mode 'htmlize))
2412 (dir (file-name-directory path))
2413 (elc (concat dir "htmlize.elc")))
2414 (unless (file-exists-p elc)
2415 (message "TinyTf: (performance) Please compile %s" path)
2417 (let* ((html-buffer "*html*") ;; Thisis in htmlize.el, but hard coded
2418 (buffer (current-buffer)))
2419 ;; Prevent multple *html* buffers.
2420 (if (get-buffer html-buffer)
2421 (kill-buffer (get-buffer html-buffer)))
2423 (tinytf-convert-wrapper-macro nil
2424 (message "TinyTf: Generating HTML... (htmlize) %s" file-name)
2425 (ti::funcall 'htmlize-buffer)
2426 (with-current-buffer html-buffer
2430 (tinytf-convert-html-destinaton buffer)))
2431 (message "TinyTf: Generating HTML...done. %s"
2432 (tinytf-convert-file-name-html file)))))
2437 ;;; ----------------------------------------------------------------------
2439 (defun tinytf-utility-programs-check (&optional force verb)
2440 "Set or disable found utilities (HTML converters). FORCE check.
2441 The settings will affect the main drop-down menu. If you install
2442 htmllize.el or t2html.pl to the system after package ais loaded,
2443 you must run this function.
2447 See (symbol-plist 'tinytf-mode)."
2448 (interactive (list t t))
2449 (let* ((sym 'tinytf-mode)
2450 ;; Affects expand-file-name to use only / in XEmacs
2451 (path-separator ?/))
2453 (null (get sym 't2html-checked)))
2455 ;; Print messages because searching PATH may take
2458 (message "Tinytf: searching t2html.pl..."))
2460 (ti::file-get-load-path "t2html.pl" exec-path)
2462 (message "Tinytf: searching t2html.pl... Done.")))))
2463 ;; convert to use only forward slashes.
2464 (path2 (or tinytf-:binary-t2html path))
2466 (file-exists-p path2)
2467 (expand-file-name path2))))
2470 (put sym 't2html-checked t)
2471 (put sym 't2html bin))
2473 (message "Tinytf: Cannot find t2html.pl along `exec-path'.")))))
2475 (null (get sym 'htmlize-checked)))
2476 (let* ((path (locate-library "htmlize.el")))
2479 (put sym 'htmlize-checked t)
2480 (put sym 'htmlize path))
2482 (message "Tinytf: Cannot find htmlize.pl along `load-path'.")))))
2485 (get sym 't2html))))
2487 ;;; ----------------------------------------------------------------------
2489 (defun tinytf-utility-programs-check-force ()
2490 "Re-evaluate menu and find new conversion programs.
2491 The menu items are greyed out if the conversion programs were no
2492 available during startup. If you later install the conversion programs
2493 either to PATH or `load-path', run this function to enable menu
2496 This function calls `tinytf-utility-programs-check' with 'force."
2498 (tinytf-utility-programs-check 'force 'verb))
2500 ;;; ----------------------------------------------------------------------
2502 (defun tinytf-fontify-current-buffer-window ()
2503 "Fontify current buffer's window."
2504 (let* ((buffer (current-buffer))
2505 (win (get-buffer-window buffer)))
2509 global-font-lock-mode))
2511 (font-lock-fontify-region (window-start)
2512 (min (point-max) (window-end))))))
2514 ;;; ----------------------------------------------------------------------
2516 (defun tinytf-untabify-buffer ()
2517 "Untabify whole buffer."
2520 (untabify (point-min) (point-max))))
2522 ;;; ----------------------------------------------------------------------
2524 (defun tinytf-column-info ()
2525 "Return column intepretation."
2527 (let* ((col (current-column))
2528 (elt (assq col tinytf-:column-table))
2533 (setq list (nth 1 elt))
2537 ((not (stringp re)) ;Stop there
2538 (setq ret (nth 1 elt))
2540 ((looking-at re) ;found match ?
2541 (setq ret (nth 1 elt))
2546 ;;; ----------------------------------------------------------------------
2548 (defun tinytf-column-info-display (&optional suppress)
2549 "Display column info.
2550 This function displays information about the column and the text
2551 following it. Function does not look around the text and it will not
2552 detect text inside bullets or inside any other complex text.
2558 Cursor is at [*], which is column 12, which will indicate that the column
2559 is used for code examples and marked with <SAMPLE>.
2562 SUPPRESS If non-nil, do no display unneeded messages."
2564 (let ((string (tinytf-column-info))
2565 (col (current-column)))
2567 (message "TinyTf: %s (col %d)" string col)
2569 (message "TinyTf: Nothing special at column %d" col)))))
2574 ;;; ----------------------------------------------------------------------
2576 (defun tinytf-heading-positions (&optional and-heading-names)
2577 "Read heading sections forward.
2581 AND-HEADING-NAMES see return value.
2586 '((heading pos) (heading pos) ..) If AND-HEADING-NAMES is non-nil
2592 (tinytf-heading-macro
2593 (setq point (line-beginning-position))
2596 ;; Dont read trailing spaces.
2598 (if (re-search-backward "[^ \t]+" point t)
2599 ;; Search 'eats' one character include it too.
2600 (setq heading (buffer-substring point (1+ (point))))
2601 (setq heading (buffer-substring point (point))))
2602 (push (cons heading (point)) list))
2606 ;; Add point max there too. (due to hide region)
2607 (if (and list (null and-heading-names))
2608 (push (point-max) list))
2611 ;;; ----------------------------------------------------------------------
2613 (defun tinytf-heading-fix-case-all (&optional confirm verb)
2614 "Convert all headings to lowercase and capitalize first word.
2615 If CONFIRM is non-nil ask permission to fix for each heading. VERB."
2618 (tinytf-heading-macro
2619 (when (and (tinytf-heading-fix-case-p)
2625 (ti::read-current-line) 70))))
2627 (downcase-region (line-beginning-position) (line-end-position))
2628 (capitalize-word 1))
2631 (message "TinyTf: Case fix done.")))
2633 ;;; ----------------------------------------------------------------------
2635 (defun tinytf-heading-fix-case-p ()
2636 "Check if current heading need case fixing.
2637 Caller must ensure that current line is heading. Point is moved."
2639 (if (looking-at "[0-9. \t]+") ;Forget heading numbering
2640 (re-search-forward "[0-9. \t]+" (line-end-position)) )
2642 (or (and (looking-at "[a-z]") ;It alphabet
2643 (let* (case-fold-search) ;is it uppercase?
2644 (not (looking-at "[A-Z]"))))
2645 (save-excursion ;Howabout rest of the line; lowercase?
2647 (let* (case-fold-search)
2648 (looking-at ".*[A-Z]")))))
2650 ;;; ----------------------------------------------------------------------
2652 (defun tinytf-heading-fix-case ()
2653 "Write heading in lowercase and capitalize first word. Move heading forward.
2654 If current line is not a heading, do nothing.
2658 t if modified current and moved to next heading.
2661 (let* ((re (concat (tinytf-regexp) "\\|" (tinytf-regexp 1)))
2663 (when (save-excursion
2666 (when (tinytf-heading-fix-case-p)
2667 (downcase-region (line-beginning-position) (line-end-position))
2672 ;;; ----------------------------------------------------------------------
2674 (defun tinytf-heading-fix-newlines (&optional verb)
2675 "Search all headings and remove extra newlines. VERB.
2680 nbr this many fixed."
2682 (let ((mark (point-marker)) ;Heading start point
2686 (tinytf-heading-macro
2687 (move-marker mark (point))
2690 ;; Delete previous newlines
2693 ((not (looking-at "^[ \t]*$")) ;no whitespace at all
2694 (end-of-line) (insert "\n") (incf fix))
2695 ((not (zerop (skip-chars-backward " \t\r\n"))) ;extra whitespace
2697 (delete-region beg (point)) (incf fix))))
2698 (goto-char (marker-position mark))
2703 ((not (looking-at "^[ \t]*$")) ;no whitespace at all
2707 ((not (zerop (skip-chars-forward " \t\r\n"))) ;extra whitespace
2710 ;; Skip chars forward for to next line in following case,
2711 ;; see the (*) cursor position. When we do beginning of
2712 ;; line; the point is 1+ BEG, but we really don't want
2713 ;; to delete that region!
2718 (when (not (memq (point) (list beg (1+ beg))))
2719 (delete-region beg (point))
2721 (setq mark nil) ;kill marker
2724 (message "TinyTf: fixed %d places around headings" fix)
2725 (message "TinyTf: no newline fixes.")))
2727 (if (> fix 0) ;anything to return?
2730 ;;; ----------------------------------------------------------------------
2732 (defun tinytf-heading-fix (&optional verb)
2733 "Search all headings and convert first letter to uppercase if needed. VERB.
2734 This function will only chnage the first word in the heading, no
2735 other case conversions are done."
2737 (let* ((re (concat ;Search lower letters only
2738 "^" (tinytf-heading-number-regexp) "?"
2741 "\\|^" (tinytf-indent 1)
2742 (tinytf-heading-number-regexp) "?"
2749 (while (re-search-forward re nil t)
2754 (message "%s: Fixed %d headings" tinytf-:mode-name count))))
2756 ;;; ----------------------------------------------------------------------
2758 (defun tinytf-heading-numbering (&optional remove verb)
2759 "Number heading levels. Old numbering is replaced.
2760 Optionally REMOVE numbering. VERB."
2762 (let* ((re-no-nbr2 (if (> tinytf-:heading-number-level 0)
2764 (re-no-nbr3 (if (> tinytf-:heading-number-level 1)
2766 (re-nbr (tinytf-heading-number-regexp))
2767 (re1 (concat "^" (tinytf-indent 0) re-nbr))
2768 (re2 (if (> tinytf-:heading-number-level 0)
2769 (concat "^" (tinytf-indent 1) re-nbr)))
2770 (re3 (if (> tinytf-:heading-number-level 1)
2771 (concat "^" (tinytf-indent 2) re-nbr)))
2779 (tinytf-heading-macro
2784 (if (or (looking-at re1)
2789 (ti::replace-match 1)))
2790 ((looking-at re1) ;heading 1
2793 (setq str (tinytf-heading-string c1 c2))
2794 ;; Only change if different, this prevents buffer modify flag
2796 (unless (tinytf-heading-same-p 0 str)
2798 (ti::replace-match 1 str)))
2799 ((and re2 (looking-at re2))
2802 (setq str (tinytf-heading-string c1 c2))
2803 (unless (tinytf-heading-same-p 1 str)
2805 (ti::replace-match 1 str)))
2806 ((and re3 (looking-at re3))
2808 (setq str (tinytf-heading-string c1 c2 c3))
2809 (unless (tinytf-heading-same-p 2 str)
2811 (ti::replace-match 1 str)))
2813 (looking-at re-no-nbr2)) ;Level 2
2814 (goto-char (match-end 0))
2817 (insert (tinytf-heading-string c1 c2)))
2819 (looking-at re-no-nbr3)) ;Level 2
2820 (goto-char (match-end 0))
2823 (insert (tinytf-heading-string c1 c2 c3)))
2824 ((looking-at "^") ;must be level 1
2825 (setq c2 0) (incf c1)
2827 (insert (tinytf-heading-string c1 c2))))
2830 (message "%s: %d/%d headings numbered."
2831 tinytf-:mode-name fix count))))
2833 ;;; ----------------------------------------------------------------------
2835 (defun tinytf-fix-all (&optional verb)
2836 "Fix headers, untabify buffer and do other things. VERB.
2840 This function does not call following functions:
2842 `tinytf-heading-fix-case-all', because you are in charge of the case of
2843 headings. Only first letter is made uppercase.
2845 `tinytf-toc', because the TOC in the buffer would always be substituted.
2846 and this would mark buffer modified although no other changes were made.
2847 Update this manually after heading changes.
2851 `tinytf-:fix-all-hook' Well, you can do the misisng things here."
2854 ;; when you fill paragraphs, the default Emacs has nasty habits to
2855 ;; end the sentece to two spaces, which is some idiot way to separate
2856 ;; two sentences (the history says that the typewriter fonts were so bad
2857 ;; that the typists needed to add two spaces these).
2859 ;; Fix them to have only standard space.
2861 (message "TinyTf: Fixing double spaces..."))
2864 (while (re-search-forward "[a-zA-Z]+[!?.,]\\( +\\)[a-zA-Z]+" nil t)
2865 (ti::replace-match 1 " ")))
2867 (message "TinyTf: Trimming extra blank lines..."))
2868 (ti::buffer-trim-blanks (point-min) (point-max)) ;Remove trailing blanks
2870 (message "TinyTf: Heading fix..."))
2871 (tinytf-heading-fix)
2872 (tinytf-untabify-buffer)
2873 (tinytf-heading-fix-newlines)
2875 (message "TinyTf: Checking heading numbering..."))
2876 (when (tinytf-headings-numbered-p)
2877 (tinytf-heading-numbering))
2879 (message "TinyTf: Running user fix hooks..."))
2880 (run-hooks 'tinytf-:fix-all-hook)
2882 (message "TinyTf: Fixing done.")))
2885 ;;{{{ text: formatting with codes
2887 ;;; ----------------------------------------------------------------------
2889 (defun tinytf-paragraph-first-line-indent-fix (col)
2890 "Make sure the first line in the paragraph start at column COL.
2891 point must be inside paragraph before calling function."
2892 ;; After fill; the first line may still be ragged. fix it
2895 ;; txt txt txt txt txt
2896 ;; txt txt txt txt txt
2897 (if (string-match "^[ \t]$" (ti::read-current-line))
2898 (error "Must be inside text."))
2899 (when (re-search-backward "^[ \t]*$" nil t)
2901 (skip-chars-forward " \t")
2902 (unless (eq col (current-column))
2903 (delete-region (point) (line-beginning-position))
2904 (insert (make-string col ?\ )))))
2906 ;;; ----------------------------------------------------------------------
2908 (defun tinytf-move-paragraph-to-column (beg end col &optional msg noask)
2909 "If region BEG END is big, ask confirmation for COL move with MSG NOASK.
2911 (beg . end) Region bounds now."
2912 (let* ((lines (+ (count-char-in-region beg end ?\r)
2913 (count-char-in-region beg end ?\n)))
2915 ;; We use markers, because the points have moved after the
2916 ;; call to ti::buffer-move-paragraph-to-column. We must pass moved BEG end
2917 ;; to hook functions.
2918 (ti::keep-lower-order beg end)
2921 (setq beg (point-marker))
2923 (setq end (point-marker)))
2928 (y-or-n-p (format "%s: really move %d lines? "
2929 tinytf-:mode-name lines))))
2930 (ti::buffer-move-paragraph-to-column
2931 (marker-position beg) (marker-position end)
2933 (if (and (null noask) (< col 12))
2934 (let ((fill-prefix (make-string col ?\ ))
2936 (call-interactively 'fill-paragraph)))
2938 (message "TinyTf:%s" msg))
2940 (run-hook-with-args 'tinytf-:move-paragraph-hook
2941 (marker-position beg) (marker-position end))
2944 ;;; ----------------------------------------------------------------------
2946 (tinytf-fmacro-indent-region
2947 tinytf-indent-region-text
2948 "Move selected region to STRONG html code position."
2949 8 (format "TinyTf: Regular text, column 8"))
2951 (tinytf-fmacro-indent-region
2952 tinytf-indent-region-strong
2953 "Move selected region to STRONG html code position."
2954 9 (format "TinyTf: Strong, column 9"))
2956 (tinytf-fmacro-indent-region
2957 tinytf-indent-region-quote
2958 "Move selected region to EMPHATISED (quoted text) html code position."
2959 10 (format "TinyTf: Quotation, column 10"))
2961 (tinytf-fmacro-indent-region
2962 tinytf-indent-region-sample
2963 "Move selected region to SAMPLE (example code) html code position."
2964 12 (format "TinyTf: Sample, column 12"))
2966 ;;; ----------------------------------------------------------------------
2968 (tinytf-fmacro-indent-paragraph
2969 tinytf-indent-paragraph-zero
2970 "Move paragraph to column 0."
2971 0 (format "TinyTf: Zero, column 0"))
2973 (tinytf-fmacro-indent-paragraph
2974 tinytf-indent-paragraph-2
2975 "Move paragraph to column 2."
2976 2 (format "TinyTf: column 2"))
2978 (tinytf-fmacro-indent-paragraph
2979 tinytf-indent-paragraph-3
2980 "Move paragraph to column 3."
2981 3 (format "TinyTf: column 3"))
2983 (tinytf-fmacro-indent-paragraph
2984 tinytf-indent-paragraph-5
2985 "Move paragraph to column 5."
2986 5 (format "TinyTf: column 5"))
2988 (tinytf-fmacro-indent-paragraph
2989 tinytf-indent-paragraph-6
2990 "Move paragraph to column 6."
2991 6 (format "TinyTf: column 6")
2993 (fill-paragraph nil)
2994 (tinytf-forward-paragraph)))
2996 (tinytf-fmacro-indent-paragraph
2997 tinytf-indent-paragraph-11
2998 "Move paragraph to column 11."
2999 11 (format "TinyTf: column 11"))
3001 (tinytf-fmacro-indent-paragraph
3002 tinytf-indent-paragraph-text
3003 "Move paragraph to text position."
3004 8 (format "TinyTf: text, column 8")
3006 (tinytf-forward-paragraph)))
3008 (tinytf-fmacro-indent-paragraph
3009 tinytf-indent-paragraph-text-as-is
3010 "Move paragraph to text position."
3011 8 (format "TinyTf: text, column 8")
3013 (tinytf-forward-paragraph)))
3015 (tinytf-fmacro-indent-paragraph
3016 tinytf-indent-paragraph-text-and-fill
3017 "Move paragraph to text position and fill."
3018 8 (format "TinyTf: text, column 8")
3020 (or (ti::string-match "^[ \t]+" 0 (ti::read-current-line))
3023 (fill-paragraph nil)
3024 (tinytf-paragraph-first-line-indent-fix 8)
3025 (tinytf-forward-paragraph)))
3027 (tinytf-fmacro-indent-paragraph
3028 tinytf-indent-paragraph-quote
3029 "Move paragraph to Quotation position."
3030 10 (format "TinyTf: Quotation, column 10"))
3032 (tinytf-fmacro-indent-paragraph
3033 tinytf-indent-paragraph-quote-and-fill
3034 "Move paragraph to Quotation position and fill."
3035 10 (format "TinyTf: Quotation, column 10")
3036 (let* ((fill-prefix (or (ti::string-match
3039 (ti::read-current-line))
3042 (fill-paragraph nil)
3043 (tinytf-paragraph-first-line-indent-fix 10)
3044 (tinytf-forward-paragraph)))
3046 (tinytf-fmacro-indent-paragraph
3047 tinytf-indent-paragraph-sample
3048 "Move paragraph to Sample code position."
3049 12 (format "TinyTf: Sample, column 12")
3051 (tinytf-forward-paragraph)))
3053 ;;; ----------------------------------------------------------------------
3055 (tinytf-fmacro-mark-word
3056 tinytf-mark-word-sample
3057 "Put 'SAMP' code around word and move forward." ?` ?' )
3059 (tinytf-fmacro-mark-word
3060 tinytf-mark-word-emp
3061 "Put 'EM' code around word and move forward." ?* )
3063 (tinytf-fmacro-mark-word
3064 tinytf-mark-word-strong
3065 "Put 'STRONG' code around word and move forward." ?_ )
3067 (tinytf-fmacro-mark-word
3068 tinytf-mark-word-big
3069 "Put 'BIG' code around word and move forward." ?+ )
3071 (tinytf-fmacro-mark-word
3072 tinytf-mark-word-small
3073 "Put 'SMALL' code around word and move forward." ?= )
3075 ;;; ----------------------------------------------------------------------
3077 (defun tinytf-unmark-word ()
3078 "Remove 'STRONG' and 'EMP' mark from word and move forward."
3080 (let* ((word-skip "^ ,.;\n\r\t\f")
3083 (flet ((marker (beg skip)
3085 (skip-chars-forward skip)
3087 (buffer-substring beg (point))
3090 (string-match "[_*='`]+\\([^_*='`]+\\)[_*='`]+$" word)))
3091 (unless (looking-at "[ \t\f]")
3092 (skip-chars-backward "^ ,\n\r\t\f")
3094 ;; It depends how the markup has been done:
3096 ;; This _sentence._ And new sentence.
3097 ;; This _sentence_. And new sentence.
3098 (dolist (try (list "^ \n\r\t\f" word-skip))
3099 (multiple-value-bind (word end)
3101 (when (string-match "[_*='`]+\\([^_*='`]+\\)[_*='`]+$" word)
3102 (setq word (match-string 1 word))
3103 (delete-region beg end)
3108 (skip-chars-forward word-skip))
3109 (skip-chars-forward " (){}<>,.;:!?\"\'\n\r\t\f")))))
3111 ;;; ----------------------------------------------------------------------
3113 (defun tinytf-mark-br-line (&optional unmark &optional verb)
3114 "Mark current line with symbolic <BR>. Optionally UNMARK. VERB."
3121 (if (not (looking-at "[ \t]+[^\r\n]"))
3123 (message "TinyTf: There must be empty spaces before line."))
3124 (setq point (match-end 0))))
3126 (goto-char (1- point))
3127 (setq ch (following-char))
3133 (message "TinyTf: Already marked as <BR>"))
3136 (skip-chars-forward " \t\r\n")))
3138 ;;; ----------------------------------------------------------------------
3140 (defun tinytf-mark-br-paragraph (&optional unmark)
3141 "Mark current paragraph with symbolic <BR> codes. Optionally UNMARK."
3145 (tinytf-backward-paragraph)
3147 (tinytf-forward-paragraph)
3148 (setq end-mark (point-marker))
3150 (while (< (point) (marker-position end-mark))
3151 (tinytf-mark-br-line unmark))
3153 (setq end-mark nil)))
3156 ;;{{{ Formatting, misc
3158 ;;; ----------------------------------------------------------------------
3160 (defun tinytf-bullet-format ()
3161 "Reformat following bullet into Technical text bullet.
3162 Point sits somewhere in current bullet. Bullets accepted are:
3170 If the bullet strarts with 'o' or '.', then that is used as bullet
3171 mark. In all other cases 'o' is used."
3173 (let* ((bullet-re "^[ \t]*\\([-*o.+]\\)[ \t]")
3174 (para-re (concat bullet-re "\\|^[ \t]*$"))
3177 (str " ") ;; 8 + 4 spaces
3178 fill-prefix ;; Otherwise formatting won't work right
3181 (if (not (looking-at bullet-re))
3182 (re-search-backward para-re))
3184 (if (not (looking-at bullet-re))
3185 (re-search-forward bullet-re))
3186 ;; Set the bullet character
3187 (setq char (match-string 1))
3188 (if (not (member char '("o" ".")))
3190 (goto-char (match-end 0)) ;Over the bullet marker
3191 ;; Delete [WHITE-SPACE]- text
3192 (delete-region (point) (line-beginning-position))
3194 ;; handle continuing line
3198 (while (and (not (looking-at bullet-re))
3199 (looking-at "[ \t]*[^ \t\r\n]"))
3203 (ti::narrow-safe beg end
3204 ;; Now indent the text, then fill, and finally fix the
3206 (goto-char (point-min))
3207 (setq fill-prefix str)
3208 (indent-rigidly (point-min) (point-max) (+ 8 4))
3209 (call-interactively 'fill-paragraph)
3210 (goto-char (point-min))
3212 (insert " " char " ")
3213 (setq end (point-max)))
3216 (if (string-match "^[ \t\r\n]*$" (ti::read-current-line))
3217 (re-search-forward "^[ \t]*[^ \t\r\n]" nil t))))
3222 ;;; ----------------------------------------------------------------------
3224 (defun tinytf-backward-paragraph ()
3225 "Like `tinytf-forward-paragraph' but go backward."
3227 (tinytf-paragraph-macro
3228 (backward-paragraph)
3229 (backward-paragraph)
3230 (skip-chars-forward " \t\r\n")
3231 (tinytf-goto-non-space)))
3233 ;;; ----------------------------------------------------------------------
3235 (defun tinytf-forward-paragraph ()
3236 "Like `forward-paragraph' but keep cursor at the beginning of text."
3238 (tinytf-paragraph-macro
3240 (skip-chars-forward " \t\r\n")
3241 (tinytf-goto-non-space)))
3243 ;;; ----------------------------------------------------------------------
3245 (defun tinytf-heading-start ()
3246 "Goto first heading, excluding TOC heading."
3248 (when (tinytf-toc-goto)
3249 (tinytf-heading-forward-0)))
3251 ;;; ----------------------------------------------------------------------
3253 (defun tinytf-forward (level &optional back any)
3254 "Go to next heading. Optionally search LEVEL or BACK or ANY level.
3261 (concat (tinytf-regexp) "\\|" (tinytf-regexp 1))
3262 (tinytf-regexp level)))
3263 case-fold-search ;case sensitive
3266 (when (re-search-backward re nil t)
3267 (skip-chars-forward " \t") (point))
3269 ((bolp) ;Startt seaching from next char
3272 (if (re-search-forward re nil t)
3273 (setq point (point))))
3274 (if point ;If search ok, then move
3275 (goto-char (1- point))))
3277 (when (re-search-forward re nil t)
3278 (backward-char 1) (point)))))))
3280 ;;; ----------------------------------------------------------------------
3282 (defun tinytf-heading-forward-0 ()
3287 (defun tinytf-heading-forward-1 ()
3292 (defun tinytf-heading-forward-any ()
3295 (tinytf-forward 1 nil 'any))
3297 (defun tinytf-heading-backward-0 ()
3300 (tinytf-forward 0 'back))
3302 (defun tinytf-heading-backward-1 ()
3305 (tinytf-forward 1 'back))
3307 (defun tinytf-heading-backward-any ()
3310 (tinytf-forward 1 'back 'any))
3313 ;;{{{ outline control: show/hide
3315 ;;; ----------------------------------------------------------------------
3317 (defun tinytf-hide-region (beg end &optional show)
3318 "Hide region BEG END with selective display. Optionally SHOW.
3319 Point is END after function finishes."
3320 (let (buffer-read-only
3321 (ch1 (if show ?\r ?\n))
3322 (ch2 (if show ?\n ?\r)))
3323 (subst-char-in-region beg end ch1 ch2)
3324 (set-buffer-modified-p nil)
3325 (goto-char (max beg end))))
3327 ;;; ----------------------------------------------------------------------
3329 (defun tinytf-mouse-context-sensitive (event)
3330 "If `mouse-point' points indent 0 or 1 line, then hide/show level. EVENT.
3331 In other places call original function."
3334 (mouse-set-point event)
3337 ((or (tinytf-level-p 0)
3339 (tinytf-show-toggle))
3341 (ti::compat-mouse-call-original 'tinytf-mode event))))
3343 ;;; ----------------------------------------------------------------------
3345 (defun tinytf-show-buffer ()
3346 "Remove selective display codes from buffer."
3349 (tinytf-hide-region (point-min) (point-max) 'show)))
3351 ;;; ----------------------------------------------------------------------
3353 (defun tinytf-hide-buffer ()
3354 "Hide whole buffer."
3356 ;; Save current point
3357 (let ((point (line-beginning-position)))
3358 (goto-char (point-min))
3359 (if (tinytf-level-p 0)
3361 (while (tinytf-heading-forward-0)
3363 ;; But after collapsing buffer, the point is not exactly there
3364 ;; any more => Go to the nearest heading which is at the beginning of
3367 (goto-char (line-beginning-position))))
3369 ;;; ----------------------------------------------------------------------
3371 (defun tinytf-show-toggle ()
3372 "Open/close level 1. Does't touch level 0."
3374 (let* ((point (point)))
3375 (if (looking-at ".*\r")
3376 (tinytf-show) ;level is already collapsed, open it.
3379 (tinytf-goto-non-space)))
3381 ;;; ----------------------------------------------------------------------
3383 (defun tinytf-show ()
3384 "Show current level."
3386 (tinytf-hide 'show))
3388 ;;; ----------------------------------------------------------------------
3390 (defun tinytf-hide (&optional show)
3391 "Hide current level. Optionally SHOW."
3398 (tinytf-hide-region (point) (tinytf-block-end) show))
3400 (tinytf-hide-region (point) end show)
3401 (setq ok (tinytf-heading-forward-any))
3403 ;; Until next level 0 ...
3404 (not (eq 0 (tinytf-level-number))))
3407 ((setq ok (tinytf-heading-forward-any))
3408 (beginning-of-line) (backward-char 1)
3410 (subst-char-in-region beg (point) ?\r ?\n)
3411 (subst-char-in-region beg (point) ?\n ?\r))
3414 (tinytf-hide-region beg (point-max)))))
3415 (set-buffer-modified-p nil)
3416 (goto-char point))))))
3419 ;;{{{ misc: toc, exit
3421 ;;; ----------------------------------------------------------------------
3423 (defun tinytf-toc-p ()
3424 "Check if there is heading \"Table of contents\".
3426 (beg . end) begin toc body, end of toc body
3429 (let* ((re (concat ;May be Heading 1 or 2
3432 "\\)?Table [Oo]f [Cc]ontents[ \t]*$"))
3433 case-fold-search ;is sensitive
3438 (when (re-search-forward re nil t)
3439 (forward-line 1) (setq beg (point))
3440 ;; - If the above command doesn't move; assume that the Toc
3441 ;; has been placed to the end of buffer.
3442 ;; - maybe there is nothing more that toc or toc is at
3443 ;; the end where there is no more headings
3444 (if (null (tinytf-heading-forward-any)) ;Not moved?
3445 (ti::pmax)) ;go to end of buffer then
3450 ;;; ----------------------------------------------------------------------
3452 (defun tinytf-toc-mouse (event)
3453 "Create heading x-popup with mouse EVENT."
3457 ;;; ----------------------------------------------------------------------
3459 (defun tinytf-toc-occur ()
3460 "Generate Heading occur menu."
3464 (let ((toc (tinytf-toc-p))) ;Skip TOC
3466 (goto-char (cdr toc))))
3467 (occur "^[^ \t\r\n<#]\\|^ [^ \t\r\n]")))
3469 ;;; ----------------------------------------------------------------------
3471 (defun tinytf-toc (&optional arg verb)
3472 "Create table of contents.
3473 If there is heading level 1 whose name is \"Table of Contents\",
3474 update that. If there is no such heading, then show toc in separate
3479 nil create toc, possibly to separate buffer
3480 \\[universal-argument] create toc occur
3481 other must be mouse event, create x-popup toc
3483 VERB enables verbose messages."
3485 (let* ((hlist (tinytf-heading-positions 'strings))
3486 (toc (tinytf-toc-p))
3487 (buffer tinytf-:buffer-heading)
3492 (message "TinyTf: No headings found"))
3494 ;; ..................................... generate toc to (text) ...
3496 (setq buffer (ti::temp-buffer buffer 'clear))
3497 (with-current-buffer buffer
3499 (setq elt (car elt))
3500 (if (string-match "^[ \t]+" elt)
3501 (insert elt "\n") ;sub heading...
3502 (insert "\n" elt "\n")))
3503 (insert "\n") ;; Final newline
3505 (ti::buffer-trim-blanks (point-min) (point-max))
3506 (if (stringp tinytf-:heading-ignore-regexp-form)
3507 (flush-lines tinytf-:heading-ignore-regexp-form))
3508 ;; Make sure there are two newlines at the end so that
3509 ;; inserted TOC is positioned nicely
3511 ;; (when (and (looking-at "^$")
3513 ;; (forward-line -1)
3514 ;; (not (looking-at "^$"))))
3516 ;; Delete leading whitespace
3517 ;; 1997-08 Disabled for now and now makes:
3525 ;; Convert heading 2 level to heading 1
3526 (ti::pmin) (replace-string (tinytf-indent 1) ""))
3531 (if (zerop (skip-chars-forward " \t\r\n"))
3534 ;; Make indentation to text column
3539 (tinytf-indent 2)))) ;; with-current
3541 (toc ;Update existing toc
3542 (barf-if-buffer-read-only)
3543 (delete-region (car toc) (cdr toc))
3544 (ti::save-with-marker-macro
3545 ;; Leave one empty line
3546 (goto-char (car toc))
3547 (insert-buffer buffer)))
3550 (pop-to-buffer buffer)
3551 (ti::pmin))))) ;end cond inner
3552 ;; ......................................... create toc (occur) ...
3554 (ti::occur-macro (concat (tinytf-regexp) "\\|" (tinytf-regexp 1))))
3555 ;; ......................................... create toc (mouse) ...
3557 ;; ARG must be mouse-event
3558 (if (null (ti::compat-window-system))
3559 (message "TinyTf: Window system required to use popup menu")
3562 ((< (length hlist) 20)
3564 (nreverse (mapcar 'car hlist))
3565 arg nil "Headings"))
3566 ((fboundp 'imenu--mouse-menu)
3567 ;; It's too long to be displayed in one x-widget.
3569 (car-safe (ti::funcall
3570 'imenu--mouse-menu hlist arg)))
3573 "Tinytf: X-popup not available, no imenu.el")
3575 (let* ((ret (assoc elt hlist))
3576 (pos (cdr-safe ret)))
3581 (tinytf-heading-forward-0)
3582 (re-search-forward elt))))))))
3584 (message "TinyTf: TOC generated."))))
3586 ;;; ----------------------------------------------------------------------
3588 (defun tinytf-exit ()
3589 "Run `tinytf-fix-all' and exit mode."
3596 (unless tinytf-:mode-define-keys-hook ;; Set default setup
3598 'tinytf-:mode-define-keys-hook
3599 '(tinytf-mode-define-keys tinytf-mode-define-f-keys)))
3601 ;; It's important that this is as fast as possible
3603 (ti::byte-compile-defun-maybe '(tinytf-code-p))
3608 (run-hooks 'tinytf-:load-hook)
3610 ;;; tinytf.el ends here