;** ;** BRIEF -- Basic Reconfigurable Interactive Editing Facility ;** ;** Written by Dave Nanian and Michael Strickman. ;** ;** Revision history: ;** ----------------- ;** ;** ;** wp.m: ;** ;** This file contains a set of macros that can help with very simple word ;** processing applications. The functions supported are word_wrap, centering, ;** and paragraph reformatting, with a flexible right margin. By default, ;** word_wrap is turned on when this package is loaded. The other functions ;** can be invoked as they are needed, or can be assigned to any keys you ;** choose. ;** ;** These functions are NOT intended to replace a full-featured word processor. ;** They are useful for letters and other short documents, and as a supplement ;** to a text formatter. ;** #define ADD_CHAR_MACRO 0 #define NEW_FILE_MACRO 1 #define DEFAULT_MARGIN 70 ;** ;** _init: ;** ;** This macro starts the package by setting up word_wrap and initializing ;** the margin. ;** (macro _init ( (int margin_val default_margin ) (global margin_val default_margin ) (= margin_val (= default_margin DEFAULT_MARGIN)) ) ) (macro wp (error "You must set BPACKAGES to turn on WP.") ) ;** ;** _wp_on, _wp_off: ;** ;** These macros are called to turn word processing on and off for specific ;** files. Note that an optional margin can be specified in the BPACKAGES ;** line; the previous margin is restored when the current file is changed. ;** (macro _wp_on ( (if (! (get_parm 0 margin_val)) (= margin_val default_margin) ) (register_macro ADD_CHAR_MACRO "_word_wrap") (return "_wp_off") ) ) (macro _wp_off (unregister_macro ADD_CHAR_MACRO "_word_wrap") ) ;** ;** center: ;** ;** Centers the current line in the work area (the area between column 1 ;** and the current margin). ;** (macro center ( (string text) (search_back "<[ \\t]@\\c[~ \\t]") (= text (read)) (= text (substr text 1 (- (strlen text) 1))) (beginning_of_line) (delete_to_eol) (move_rel 0 (/ (- margin_val (strlen text)) 2)) (insert text) ) ) ;** ;** word_wrap: ;** ;** This macro is automatically invoked after each time that a character ;** is typed. It moves the cursor to the next line when it is past the ;** margin, taking the current word with it if necessary. ;** ;** Automatic invocation is done via the standard BPACKAGES interface. ;** (macro _word_wrap ( (int col) (inq_position NULL col) (if (> col margin_val) ( (prev_char) (if (! (index " \t" (read 1))) ( (int new_col space_between_words ) (= space_between_words 1) (search_back "<|[ \\t][~ \\t]") (inq_position NULL new_col) (if (== (read 1) "\t") (= space_between_words (distance_to_tab)) ) (if (== new_col 1) (end_of_line) ) (insert "\n") (if (!= new_col 1) ( (delete_char) (move_rel 0 (- (- col new_col) space_between_words)) ) ) ) ;else (next_char) ) ) ) ) ) ;** ;** margin: ;** ;** Resets the current margin, prompting the user if necessary. ;** (macro margin ( (get_parm 0 default_margin "Enter margin: ") (= margin_val default_margin) ) ) ;** ;** reform: ;** ;** Reformats the currently marked area a line at a time. The main ;** loop goes through each line, adjusting it to the margin as necessary. ;** If the line is too long, it splits it at the last space before the ;** margin; it it's too short, it keeps joining the following lines to it, ;** or parts of them if they are too long, until the line fits the margin. ;** (macro reform ( (string last_char tab_reply ) (int old_buffer temp_buffer start_line start_col end_line end_col curr_line curr_col prev_line prev_col not_done tab_stop ) (= tab_reply (use_tab_char "n")) (message "Reformatting paragraph...") ;** If no paragraph marked, find ends of it at blank or indented lines. (if (! (inq_marked)) ( (end_of_line) (move_rel 0 -1) (if (! (search_back "{<[ \t]+[~ \t\n]}|{\n @\n\\c}")) (top_of_buffer) ) (drop_anchor) (next_char) (if (! (search_fwd "{\\c\n[ \t]+[~ \t]}|{\\c\n[ \t]@\n}")) (end_of_buffer) ) ) ) ;** Transfer marked area into a fresh buffer, then delete it. (inq_marked start_line start_col end_line end_col) (save_position) (beginning_of_line) (= tab_stop (distance_to_tab)) (restore_position) (= old_buffer (inq_buffer)) (set_buffer (= temp_buffer (create_buffer "Word Process" NULL 1))) (tabs tab_stop) (transfer old_buffer start_line start_col end_line end_col) (set_buffer old_buffer) (delete_block) (move_abs start_line start_col) (set_buffer temp_buffer) (top_of_buffer) ;** Loop through buffer a line at a time, shrinking or expanding ;** each line as necessary. (while (! (inq_position)) ( (end_of_line) (inq_position NULL curr_col) ;** If line is too long, split it. (if (> curr_col margin_val) ( (move_abs 0 (+ margin_val 1)) (search_back "[ \t]") (insert "\n") (while (== " " (read 1)) (delete_char) ) (up) ) ;else line might need to be merged with following lines. ( (= not_done 1) (while not_done ( (left) (= last_char (read 1)) ;** Skip current character and leave two spaces after ;** .:!? (+= curr_col (!= last_char " ")) (+= curr_col (> (index ".:!?" last_char) 0)) ;** Stop if we don't need any more after punc. (if (>= curr_col margin_val) (= not_done 0) ;else try to fill more of line ( (down) (end_of_line) (inq_position prev_line prev_col) ;** If we need the entire next line, prepare for join. (if (<= (-- prev_col) (- margin_val curr_col)) ( (beginning_of_line) (if (== (read) "\n") (= not_done 0) ) (up) ) ;else if we need just a chunk of it ( ;** Find the maximum amt. we can take. (move_abs 0 (+ 1 (- margin_val curr_col))) (search_back "[ \t][~ \t]") (inq_position curr_line) ;** If the first word on the next line is ;** too long, we're done with the line. (if (!= curr_line prev_line) (= not_done 0) ;else ( ;** Split off line and clean up start of next. (insert "\n") (delete_char) ;** Go back up and prepare to join. (move_rel -2 0) ) ) ;Endif first word is too long ) ) ;Endif (now have old line + chunk) ;** Now join the lines together if needed. (if not_done ( (move_abs 0 curr_col) (delete_char) ) ) ;** Prepare to loop again. (end_of_line) (inq_position NULL curr_col) ) ) ;Endif line needs to be extended ) ) ;Endwhile line isn't full ) ) ;Endif (Line is now ready to insert) ;** Read line into string and insert in other buffer. (beginning_of_line) (= last_char (read)) (set_buffer old_buffer) (if (!= last_char "\n") (insert last_char) ) (refresh) (set_buffer temp_buffer) (delete_line) (if (== (read) "\n") (delete_line) ) ) ) ;Endwhile there are lines to insert. ;** Get rid of the scrap buffer and insert the remaining text. (set_buffer old_buffer) (delete_buffer temp_buffer) (message "Reformatting complete.") (use_tab_char tab_reply) ) )