/* ** BRIEF -- Basic Reconfigurable Interactive Editing Facility ** ** Written by Dave Nanian and Michael Strickman. */ /* ** wp.cb: ** ** 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. */ void _init () { global int margin_val, default_margin; margin_val = default_margin = DEFAULT_MARGIN; } void 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. */ string _wp_on (~int) { if (!get_parm (0, margin_val)) margin_val = default_margin; register_macro (ADD_CHAR_MACRO, "_word_wrap"); returns ("_wp_off"); } void _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). */ void 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. */ void _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 = 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. */ void margin (int) { 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. */ void 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 + 1); 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 { 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 { 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 { /* ** 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); } } /* ** 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); } } } /* ** 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 (); } /* ** Get rid of the temporary buffer and insert the remaining text. */ set_buffer (old_buffer); delete_buffer (temp_buffer); message ("Reformatting complete."); use_tab_char (tab_reply); }