Un-ignored: the dev drive is the ground truth the restoration and emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio content). Kept in-repo for the pod-owner community. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
955 lines
23 KiB
Plaintext
955 lines
23 KiB
Plaintext
/*
|
|
** BRIEF -- Basic Reconfigurable Interactive Editing Facility
|
|
**
|
|
** Written by Dave Nanian and Michael Strickman.
|
|
*/
|
|
|
|
/*
|
|
** indent.cb:
|
|
**
|
|
** This macro performs automatic indenting for a number of languages.
|
|
** Other languages can be supported through the standard BPACKAGES
|
|
** interface.
|
|
*/
|
|
|
|
#define MIN_ABBREV 1 // Increase this to specify longer
|
|
// default minimum abbreviations.
|
|
|
|
#define REG_MARK 1 // Regular marks.
|
|
#define COL_MARK 2 // Column marks.
|
|
#define LINE_MARK 3 // Line marks.
|
|
#define NI_MARK 4 // Non-inclusive marks.
|
|
|
|
#define C_SKIP_PAT "{{/\\*{{[~*/]{/+[~*/]}@}|\\*}@\\*/}|{//*}|{<{[A-Za-z0-9_]+:}|{[ \xc\t]@#*}}|[ \xc\t\n]}@"
|
|
|
|
/*
|
|
** ABBREV_LIST_2 contains the list of abbreviations that don't require
|
|
** cursor positioning. ABBREV_LIST_1 requires the cursor to back up a
|
|
** character (usually placing it inside a parenthesis).
|
|
*/
|
|
|
|
#define ABBREV_LIST_1 "\xffreturn \xffbreak;\xffdo\xffdefault:\xffelse \xffcase :\xffcontinue;\xff"
|
|
#define ABBREV_LIST_2 "\xffei\xffelse if ()\xffif ()\xffwhile ()\xfffor ()\xffswitch ()\xff"
|
|
|
|
void back_tab (void);
|
|
void open_line (void);
|
|
string .c_template_first (~int, ~int, ~int, ~int);
|
|
string .c_smart_first (~int, ~int, ~int);
|
|
string .cb_template_first (~int, ~int, ~int, ~int);
|
|
string .cb_smart_first (~int, ~int, ~int);
|
|
string _regular_first (void);
|
|
int .c_indent (~int indent_query);
|
|
void r_indent (void);
|
|
void slide_in (void);
|
|
void slide_out (void);
|
|
void .c_abbrev (void);
|
|
void brace_expand (void);
|
|
void .c_open_brace (void);
|
|
void .c_close_brace (void);
|
|
void just_brace (void);
|
|
void just_cbrace (void);
|
|
void just_space (void);
|
|
void comment_block (void);
|
|
void uncomment_block (void);
|
|
|
|
int .c_min_abbrev, // Minimum template abbreviation.
|
|
.c_indent_open, // Location of the open brace.
|
|
.c_indent_close, // Location of the close brace.
|
|
.c_indent_first, // Location of the first braces.
|
|
.c_smart, // C smart indenting keymap.
|
|
.c_template, // C template editing keymap, expands on <Space>.
|
|
.c_alt_template, // C template editing keymap, expands on <Tab>.
|
|
_r_keymap; // Regular indenting keymap.
|
|
|
|
/*
|
|
** .c_template_first, .c_smart_first,
|
|
** .cb_template_first, .cb_smart_first,
|
|
** _regular_first:
|
|
**
|
|
** These macros are called by the BPACKAGES parser in language.m.
|
|
** They initialize the local keymaps for the various indenting functions,
|
|
** set the abbreviation length and adjust the indenting style.
|
|
*/
|
|
|
|
string .c_template_first (~int, ~int, ~int, ~int)
|
|
{
|
|
.c_min_abbrev = MIN_ABBREV;
|
|
get_parm (3, .c_min_abbrev);
|
|
|
|
if (first_time())
|
|
{
|
|
keyboard_push ();
|
|
assign_to_key ("<Enter>", ".c_indent");
|
|
assign_to_key ("<Tab>", ".c_abbrev");
|
|
assign_to_key ("<Shift-Tab>", "slide_out");
|
|
assign_to_key ("<{>", "brace_expand");
|
|
assign_to_key ("<}>", ".c_close_brace");
|
|
assign_to_key ("<Ctrl-{>", "just_brace");
|
|
assign_to_key ("<Ctrl-}>", "just_cbrace");
|
|
assign_to_key ("<Ctrl-s>", "just_space");
|
|
.c_alt_template = inq_keyboard ();
|
|
keyboard_pop (1);
|
|
keyboard_push ();
|
|
assign_to_key ("<Enter>", ".c_indent");
|
|
assign_to_key ("<Tab>", "slide_in");
|
|
assign_to_key ("<Shift-Tab>", "slide_out");
|
|
assign_to_key ("<Space>", ".c_abbrev");
|
|
assign_to_key ("<{>", "brace_expand");
|
|
assign_to_key ("<}>", ".c_close_brace");
|
|
assign_to_key ("<Ctrl-{>", "just_brace");
|
|
assign_to_key ("<Ctrl-}>", "just_cbrace");
|
|
assign_to_key ("<Ctrl-s>", "just_space");
|
|
.c_template = inq_keyboard ();
|
|
keyboard_pop (1);
|
|
}
|
|
if (.c_min_abbrev == 0)
|
|
{
|
|
use_local_keyboard (.c_alt_template);
|
|
.c_min_abbrev = 1;
|
|
}
|
|
else
|
|
use_local_keyboard (.c_template);
|
|
|
|
.c_indent_open = 1;
|
|
.c_indent_close = 1;
|
|
.c_indent_first = 0;
|
|
get_parm (0, .c_indent_open);
|
|
get_parm (1, .c_indent_close);
|
|
get_parm (2, .c_indent_first);
|
|
|
|
if (!.c_indent_open || !.c_indent_close)
|
|
.c_indent_first = 0;
|
|
|
|
returns ("");
|
|
}
|
|
|
|
string .c_smart_first (~int, ~int, ~int)
|
|
{
|
|
if (first_time())
|
|
{
|
|
keyboard_push ();
|
|
assign_to_key ("<Enter>", ".c_indent");
|
|
assign_to_key ("<Tab>", "slide_in");
|
|
assign_to_key ("<Shift-Tab>", "slide_out");
|
|
assign_to_key ("<{>", ".c_open_brace");
|
|
assign_to_key ("<}>", ".c_close_brace");
|
|
assign_to_key ("<Ctrl-{>", "just_brace");
|
|
assign_to_key ("<Ctrl-}>", "just_cbrace");
|
|
.c_smart = inq_keyboard ();
|
|
keyboard_pop (1);
|
|
}
|
|
use_local_keyboard (.c_smart);
|
|
.c_indent_open = 1;
|
|
.c_indent_close = 1;
|
|
.c_indent_first = 0;
|
|
get_parm (0, .c_indent_open);
|
|
get_parm (1, .c_indent_close);
|
|
get_parm (2, .c_indent_first);
|
|
|
|
if (!.c_indent_open || !.c_indent_close)
|
|
.c_indent_first = 0;
|
|
|
|
returns ("");
|
|
}
|
|
|
|
string .cb_template_first (~int p1, ~int p2, ~int p3, ~int p4)
|
|
{
|
|
returns ( .c_template_first(p1, p2, p3, p4) );
|
|
}
|
|
|
|
string .cb_smart_first (~int p1, ~int p2, ~int p3)
|
|
{
|
|
returns ( .c_smart_first(p1, p2, p3) );
|
|
}
|
|
|
|
|
|
string _regular_first (void)
|
|
{
|
|
if (first_time())
|
|
{
|
|
keyboard_push ();
|
|
assign_to_key ("<Enter>", "r_indent");
|
|
assign_to_key ("<Tab>", "slide_in");
|
|
assign_to_key ("<Shift-Tab>", "slide_out");
|
|
_r_keymap = inq_keyboard ();
|
|
keyboard_pop (1);
|
|
}
|
|
use_local_keyboard (_r_keymap);
|
|
returns ("");
|
|
}
|
|
|
|
/*
|
|
** .c_indent:
|
|
**
|
|
** This macro does syntax-sensitive indenting ("smart indenting") for
|
|
** C language files.
|
|
*/
|
|
|
|
int .c_indent (~int indent_query)
|
|
{
|
|
int curr_indent_col, // Current unmodified indent col.
|
|
prev_indent_col, // Previous unmodified indent col.
|
|
curr_line, // Line cursor is on when called.
|
|
curr_col, // Column cursor is on when called.
|
|
prev_end_char, // Character at end of current line.
|
|
curr_end_char, // Character at end of previous line.
|
|
indent_level; // Current indenting level.
|
|
|
|
string following_text, // All characters following the cursor.
|
|
curr_text; // The text of the current line.
|
|
|
|
/*
|
|
** Gather information on the two previous non-blank lines.
|
|
*/
|
|
|
|
if (!inq_mode ())
|
|
end_of_line ();
|
|
else if ((following_text = ltrim (read ())) != "")
|
|
{
|
|
/*
|
|
** If there are non-whitespace characters following
|
|
** the cursor, we save them in following_text. These
|
|
** characters are re-inserted after the new indent column
|
|
** has been determined.
|
|
*/
|
|
|
|
following_text = substr (following_text, 1, strlen (following_text) - 1);
|
|
delete_to_eol ();
|
|
}
|
|
|
|
/*
|
|
** We now search back for the previous line, skipping over
|
|
** all intervening comments, compiler directives and labels.
|
|
** The cursor is left one character after the character we're
|
|
** interested in.
|
|
*/
|
|
|
|
prev_end_char = curr_end_char = ';';
|
|
prev_indent_col = 1;
|
|
inq_position (curr_line, curr_col);
|
|
search_back (C_SKIP_PAT, -2);
|
|
|
|
if (prev_char ())
|
|
{
|
|
string line_end = read (); // The text after the cursor on this line.
|
|
|
|
curr_end_char = atoi (substr (line_end, 1, 1), 0);
|
|
|
|
/*
|
|
** We trim the end of the preceding line to ensure that any
|
|
** spaces left by template expansion of else statements (or
|
|
** accidental user typing) are removed.
|
|
*/
|
|
|
|
delete_to_eol ();
|
|
|
|
/*
|
|
** If we're dealing with an open brace, later indenting code
|
|
** needs the entire text of the line. We retrieve that information
|
|
** here.
|
|
*/
|
|
|
|
if (curr_end_char == '{')
|
|
{
|
|
save_position ();
|
|
beginning_of_line ();
|
|
curr_text = trim (ltrim (read ())) + "{";
|
|
restore_position ();
|
|
}
|
|
insert (trim (line_end));
|
|
|
|
/*
|
|
** Now we move to the first non-blank character on the
|
|
** line, and get that line's indent column. We then search
|
|
** back for the previous line, which may or may not exist.
|
|
** If it doesn't exist, we assume it ends in a semi-colon --
|
|
** this ensures that the indent level doesn't change.
|
|
*/
|
|
|
|
beginning_of_line ();
|
|
next_char (strlen (read ()) - strlen (ltrim (read ())));
|
|
inq_position (NULL, curr_indent_col);
|
|
|
|
if (prev_char () && search_back (C_SKIP_PAT, -2) > 1)
|
|
{
|
|
prev_char ();
|
|
prev_end_char = atoi (read (1), 0);
|
|
|
|
if (.c_indent_first && .c_indent_open)
|
|
{
|
|
beginning_of_line ();
|
|
next_char (strlen (read ()) - strlen (ltrim (read ())));
|
|
inq_position (NULL, prev_indent_col);
|
|
}
|
|
}
|
|
}
|
|
move_abs (curr_line, curr_indent_col);
|
|
|
|
/*
|
|
** We've determined the last two non-blank lines' last characters
|
|
** as well as the column position of the first non-blank character.
|
|
** Now we position the cursor on the new line's proper level.
|
|
*/
|
|
|
|
if (curr_indent_col == 1)
|
|
{
|
|
if (!.c_indent_first && curr_end_char == '{')
|
|
curr_indent_col += distance_to_tab ();
|
|
}
|
|
else
|
|
{
|
|
int prev_char_known;
|
|
|
|
/*
|
|
** Some indenting methods need to know if we've
|
|
** actually recognized a given character at all. Rather
|
|
** than duplicate the compound if statements required, we
|
|
** set a variable here.
|
|
*/
|
|
|
|
switch (prev_end_char)
|
|
{
|
|
case ';':
|
|
case '{':
|
|
case '}':
|
|
case ':':
|
|
++prev_char_known;
|
|
|
|
case ')':
|
|
--prev_char_known;
|
|
}
|
|
|
|
switch (curr_end_char)
|
|
{
|
|
/*
|
|
** If the current line ends with a semicolon, we make
|
|
** an indenting decision based on the previous line. If
|
|
** it ends with a "known" character, we leave the indenting
|
|
** level as is. Otherwise, we assume we've hit the end of
|
|
** an indented clause and outdent.
|
|
*/
|
|
|
|
case ';':
|
|
{
|
|
if (prev_char_known <= 0)
|
|
--curr_indent_col;
|
|
}
|
|
/*
|
|
** If close braces are supposed to be indented, we
|
|
** outdent after encountering one. Otherwise, we stay
|
|
** at the same level.
|
|
*/
|
|
|
|
case '}':
|
|
{
|
|
if (.c_indent_close)
|
|
--curr_indent_col;
|
|
}
|
|
/*
|
|
** The rule for open braces is the opposite of that for
|
|
** close braces. If they're supposed to be indented, we
|
|
** leave the indenting level the same (since we've already
|
|
** indented.
|
|
**
|
|
** There is a special case, however. If the open brace
|
|
** is placed on the same line as the statement, we want to
|
|
** indent the block. So, we assume that if the open brace
|
|
** isn't the only text on the line, we're dealing with this
|
|
** case, and should indent.
|
|
*/
|
|
|
|
case '{':
|
|
{
|
|
if (!.c_indent_open || (curr_text != "{" && !(.c_indent_first && prev_indent_col == 1)))
|
|
curr_indent_col += distance_to_tab ();
|
|
}
|
|
/*
|
|
** Finally, if we didn't recognize the end of the
|
|
** previous line, we assume we're supposed to indent. This
|
|
** ends up indenting for statement continuations, case
|
|
** statements, if statements, etc.
|
|
*/
|
|
|
|
default:
|
|
{
|
|
if (prev_char_known)
|
|
curr_indent_col += distance_to_tab ();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Here we move the cursor back to the original
|
|
** column we started at (where the newline should go).
|
|
** We then execute the correct command for the pressed
|
|
** key. If we were assigned to "<Enter>", we insert the
|
|
** Enter keystroke, thereby ensuring that overstrike and
|
|
** insert modes are handled properly. If not, we insert
|
|
** the keystroke for Ctrl-m, which always inserts a newline.
|
|
*/
|
|
|
|
move_abs (0, curr_col);
|
|
|
|
/*
|
|
** Since <Enter> actually differently in insert and overstrike modes,
|
|
** we try to ensure that we do the right thing based on the command that's
|
|
** running.
|
|
**
|
|
** We assume that a direct assignment to .c_indent means we should
|
|
** use "normal" <Enter> processing: otherwise, we assume we're assigned
|
|
** to something like open_line, and use <Ctrl-m>.
|
|
*/
|
|
|
|
if (!indent_query)
|
|
{
|
|
if (inq_command () == ".c_indent")
|
|
self_insert (key_to_int ("<Enter>"));
|
|
else
|
|
self_insert (key_to_int ("<Ctrl-m>"));
|
|
}
|
|
/*
|
|
** We now move the cursor to the new indenting level on
|
|
** the next line, and we retain the indenting "level" so that
|
|
** we can return it to the calling function.
|
|
*/
|
|
|
|
beginning_of_line ();
|
|
curr_col = distance_to_tab () + 1;
|
|
|
|
while (curr_col <= curr_indent_col)
|
|
{
|
|
move_abs (0, curr_col);
|
|
++indent_level;
|
|
curr_col += distance_to_tab ();
|
|
}
|
|
/*
|
|
** Finally, if we split the original line, we insert the
|
|
** characters that were following the cursor here. They're
|
|
** inserted, of course, at the new, indented column.
|
|
*/
|
|
|
|
save_position ();
|
|
insert (following_text);
|
|
restore_position ();
|
|
|
|
returns (indent_level);
|
|
}
|
|
|
|
/*
|
|
** r_indent:
|
|
**
|
|
** This macro does "standard" style indenting, indenting new lines
|
|
** to the same column as the previous non-blank line.
|
|
*/
|
|
|
|
void r_indent (void)
|
|
{
|
|
int curr_indent_col,
|
|
curr_line,
|
|
curr_col;
|
|
|
|
string following_text;
|
|
|
|
/*
|
|
** First, check to see if there are any following characters
|
|
** on the line. If so, read them into a temporary variable and
|
|
** delete from the first line. Then, get the column of the first
|
|
** non-blank line.
|
|
*/
|
|
|
|
if (!inq_mode ())
|
|
end_of_line ();
|
|
else if ((following_text = ltrim (read ())) != "")
|
|
{
|
|
/*
|
|
** If there are non-whitespace characters following
|
|
** the cursor, we save them in following_text. These
|
|
** characters are re-inserted after the new indent column
|
|
** has been determined.
|
|
*/
|
|
|
|
following_text = substr (following_text, 1, strlen (following_text) - 1);
|
|
delete_to_eol ();
|
|
}
|
|
inq_position (curr_line, curr_col);
|
|
|
|
if (search_back ("<*\\c[~ \\t\\n]"))
|
|
inq_position (NULL, curr_indent_col);
|
|
else
|
|
curr_indent_col = 1;
|
|
|
|
move_abs (curr_line, curr_col);
|
|
|
|
/*
|
|
** We've determined the last non-blank lines' indent level --
|
|
** do mode-sensitive return, indent, line split, and clean up.
|
|
*/
|
|
|
|
if (inq_command () == "r_indent")
|
|
self_insert (key_to_int ("<Enter>"));
|
|
else
|
|
self_insert (key_to_int ("<Ctrl-m>"));
|
|
|
|
move_abs (0, curr_indent_col);
|
|
insert (following_text);
|
|
move_abs (0, curr_indent_col);
|
|
}
|
|
|
|
/*
|
|
** slide_in:
|
|
**
|
|
** This macros slides a marked block of text in one tab stop per press
|
|
** of the tab key (-->|).
|
|
*/
|
|
|
|
void slide_in (void)
|
|
{
|
|
int start_line,
|
|
start_col,
|
|
end_line,
|
|
mark_type,
|
|
tab_key = key_to_int ("<Tab>");
|
|
|
|
if (mark_type = inq_marked (start_line, start_col, end_line))
|
|
{
|
|
int cursor_line,
|
|
cursor_col,
|
|
mark_line,
|
|
mark_col,
|
|
num_lines,
|
|
old_mode;
|
|
|
|
inq_position (cursor_line, cursor_col);
|
|
swap_anchor ();
|
|
inq_position (mark_line, mark_col);
|
|
|
|
if (mark_type != COL_MARK)
|
|
start_col = 1;
|
|
|
|
move_abs (start_line, start_col);
|
|
raise_anchor ();
|
|
|
|
old_mode = inq_mode ();
|
|
insert_mode (1);
|
|
|
|
while (start_line <= end_line)
|
|
{
|
|
search_fwd ("[~ \t]");
|
|
|
|
/*
|
|
** Note that self_inserting the complete
|
|
** key definition ensures the Tab is converted
|
|
** to spaces if -t is used.
|
|
*/
|
|
|
|
if (read (1) != "\n")
|
|
self_insert (tab_key);
|
|
|
|
move_abs (++start_line, start_col);
|
|
}
|
|
move_abs (mark_line, mark_col);
|
|
drop_anchor (mark_type);
|
|
move_abs (cursor_line, cursor_col);
|
|
insert_mode (old_mode);
|
|
}
|
|
else
|
|
self_insert (tab_key);
|
|
}
|
|
|
|
/*
|
|
** slide_out:
|
|
**
|
|
** This macros slides a marked block of text out one tab stop per press
|
|
** of the back-tab key (|<--).
|
|
*/
|
|
|
|
void slide_out (void)
|
|
{
|
|
int start_line,
|
|
start_col,
|
|
end_line,
|
|
mark_type;
|
|
|
|
if (mark_type = inq_marked (start_line, start_col, end_line))
|
|
{
|
|
int num_lines;
|
|
|
|
save_position ();
|
|
|
|
if (mark_type != COL_MARK)
|
|
start_col = 1;
|
|
|
|
move_abs (start_line, start_col);
|
|
|
|
while (start_line <= end_line)
|
|
{
|
|
int curr_col;
|
|
|
|
search_fwd ("[~ \t]");
|
|
inq_position (NULL, curr_col);
|
|
|
|
if (curr_col > start_col)
|
|
{
|
|
drop_anchor (4);
|
|
back_tab ();
|
|
inq_position (NULL, curr_col);
|
|
|
|
if (curr_col < start_col)
|
|
move_abs (0, start_col);
|
|
|
|
delete_block ();
|
|
}
|
|
move_abs (++start_line, start_col);
|
|
}
|
|
restore_position ();
|
|
}
|
|
else
|
|
back_tab ();
|
|
}
|
|
|
|
/*
|
|
** Template editing macros:
|
|
**
|
|
** These macro performs simple template editing for C programs. Each
|
|
** time the space bar is pressed, the characters before the cursor are
|
|
** checked to see if they are "if", "else if", "while", "for", "do",
|
|
** "switch" or "case" (or abbreviations for them). These keywords must
|
|
** only be preceded with spaces or tabs, and be typed at the end of a
|
|
** line. If a match is found, the remainder of the statement is filled
|
|
** in automatically.
|
|
**
|
|
** In addition, a brace pairer is included -- this automatically
|
|
** inserts a matching brace at the proper indentation level when an
|
|
** opening brace is typed in. To insert a brace without a matching
|
|
** brace (it attempts to be smart about matching braces, but you never
|
|
** can make this type of thing quite smart enough), type either Ctrl-{
|
|
** or quote the brace with Alt-q.
|
|
*/
|
|
|
|
/*
|
|
** .c_abbrev:
|
|
**
|
|
** This function checks to see if the characters before the space just
|
|
** typed (and actually inserted by this function) are destined to be
|
|
** followed by the remainder of a C construct.
|
|
*/
|
|
|
|
void .c_abbrev (void)
|
|
{
|
|
int done;
|
|
|
|
if (read (1) == "\n")
|
|
{
|
|
int loc;
|
|
|
|
string line;
|
|
|
|
save_position ();
|
|
beginning_of_line ();
|
|
line = trim (ltrim (read ()));
|
|
restore_position ();
|
|
|
|
if (!index (" \t\n", substr (line, 1, 1)) && (strlen (line) && strlen (line) < 8))
|
|
{
|
|
int length;
|
|
|
|
string abbrev_list = ABBREV_LIST_1;
|
|
|
|
line = "\xff" + line;
|
|
|
|
if (.c_min_abbrev < strlen (line)
|
|
&& ((loc = search_string (line, abbrev_list, length, 0))
|
|
|| (loc = search_string (line, abbrev_list = ABBREV_LIST_2, length, 0))))
|
|
{
|
|
string completion;
|
|
|
|
completion = substr (abbrev_list, loc + length);
|
|
completion = substr (completion, 1, index (completion, "\xff") - 1);
|
|
|
|
if (line + completion == "\xffei")
|
|
{
|
|
left ();
|
|
delete_char ();
|
|
completion = "lse if ()";
|
|
}
|
|
done = strlen (completion);
|
|
insert (completion);
|
|
|
|
if (line + completion == "\xffdo")
|
|
{
|
|
open_line ();
|
|
brace_expand ();
|
|
save_position ();
|
|
move_rel (1, 0);
|
|
open_line ();
|
|
insert ("while ();");
|
|
restore_position ();
|
|
done++;
|
|
}
|
|
/*
|
|
** Only back up if the last character of the completion is
|
|
** ) or :.
|
|
*/
|
|
|
|
else if (strlen (completion) && index (":)", substr (completion, strlen (completion))))
|
|
prev_char ();
|
|
}
|
|
}
|
|
}
|
|
if (!done)
|
|
if (inq_local_keyboard () == .c_alt_template)
|
|
slide_in ();
|
|
else
|
|
self_insert ();
|
|
}
|
|
|
|
/*
|
|
** brace_expand:
|
|
**
|
|
** This function checks to see if the typed brace should be indented
|
|
** and matched to the current indenting level.
|
|
*/
|
|
|
|
void brace_expand (void)
|
|
{
|
|
string line;
|
|
|
|
save_position ();
|
|
beginning_of_line ();
|
|
line = read ();
|
|
restore_position ();
|
|
.c_open_brace ();
|
|
|
|
if (search_string ("<|{{else}|{do}}|{{typedef}|{struct}[ \t]@[~ \t\n]@}|[):][ \t]@>", line) && "" == trim (ltrim (read ())))
|
|
{
|
|
int col;
|
|
|
|
inq_position (NULL, col);
|
|
|
|
.c_indent ();
|
|
save_position ();
|
|
|
|
if (col == 2)
|
|
insert ("\n}");
|
|
else
|
|
{
|
|
inq_position (NULL, col);
|
|
insert ("\n");
|
|
|
|
if (.c_indent_close == 1)
|
|
{
|
|
move_abs (0, col);
|
|
insert ("}");
|
|
}
|
|
else
|
|
.c_close_brace ();
|
|
}
|
|
restore_position ();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** .c_open_brace:
|
|
**
|
|
** This function inserts an open brace at the correct column, given the
|
|
** current indenting conventions.
|
|
*/
|
|
|
|
void .c_open_brace (void)
|
|
{
|
|
save_position ();
|
|
beginning_of_line ();
|
|
|
|
if (trim (ltrim (read ())) == "")
|
|
{
|
|
restore_position ();
|
|
.c_indent (1);
|
|
|
|
if (!.c_indent_open)
|
|
back_tab ();
|
|
else if (.c_indent_first)
|
|
{
|
|
int curr_col;
|
|
|
|
inq_position (NULL, curr_col);
|
|
|
|
if (curr_col == 1)
|
|
move_rel (0, distance_to_tab ());
|
|
}
|
|
}
|
|
else
|
|
restore_position ();
|
|
|
|
self_insert ('{');
|
|
}
|
|
|
|
/*
|
|
** .c_close_brace:
|
|
**
|
|
** This function inserts a close brace at the correct column, given the
|
|
** current indenting conventions.
|
|
*/
|
|
|
|
void .c_close_brace (void)
|
|
{
|
|
save_position ();
|
|
beginning_of_line ();
|
|
|
|
if ("" == trim (ltrim (read ())))
|
|
{
|
|
restore_position ();
|
|
|
|
if (!.c_indent_first && .c_indent (1) == 1 || !.c_indent_close)
|
|
back_tab ();
|
|
}
|
|
else
|
|
restore_position ();
|
|
|
|
self_insert ('}');
|
|
}
|
|
|
|
/*
|
|
** just_brace, just_cbrace, just_space:
|
|
**
|
|
** These functions insert unexpanded and expanded braces and spaces.
|
|
*/
|
|
|
|
void just_brace (void)
|
|
{
|
|
insert ("{");
|
|
}
|
|
|
|
void just_cbrace (void)
|
|
{
|
|
insert ("}");
|
|
}
|
|
|
|
void just_space (void)
|
|
{
|
|
insert (" ");
|
|
}
|
|
|
|
/*
|
|
** comment_block:
|
|
**
|
|
** This macro comments out a block of code. It tries to be intelligent
|
|
** about things like comments inside the block -- if it finds one, it
|
|
** escapes it and moves on.
|
|
**
|
|
** Two different types of blocks are created, depending on the cursor
|
|
** start and end positions. If both are in column one, comment_block
|
|
** assumes a "block" type comment is desired. Block comments have "**"
|
|
** inserted in rows other than the first and last.
|
|
**
|
|
** If the start and end columns are not both in column one, the area is
|
|
** simply bracketed with "/*" and "* /".
|
|
*/
|
|
|
|
void comment_block (void)
|
|
{
|
|
int start_line,
|
|
start_col,
|
|
end_line,
|
|
end_col,
|
|
curr_col;
|
|
|
|
if (inq_marked (start_line, start_col, end_line, end_col))
|
|
{
|
|
string pattern;
|
|
|
|
raise_anchor ();
|
|
save_position ();
|
|
move_abs (end_line, end_col);
|
|
insert ("\xff");
|
|
move_abs (start_line, start_col);
|
|
|
|
if (start_col == 1)
|
|
insert ("/* ");
|
|
else
|
|
insert (" /* ");
|
|
|
|
if (start_col == 1 && end_col == 1)
|
|
pattern = "{/\\*}|{\\*/}|{\\*\\*}|<|\xff";
|
|
else
|
|
pattern = "{/\\*}|{\\*/}|{\\*\\*}|\xff";
|
|
|
|
while (search_fwd (pattern) && "\xff" != read (1))
|
|
{
|
|
inq_position (NULL, curr_col);
|
|
|
|
if (curr_col == 1 && (start_col == 1 && end_col == 1))
|
|
insert ("**\t");
|
|
else
|
|
{
|
|
insert ("\\");
|
|
right ();
|
|
}
|
|
}
|
|
delete_char ();
|
|
|
|
if (end_col == 1)
|
|
insert ("*/ ");
|
|
else
|
|
insert (" */ ");
|
|
|
|
restore_position ();
|
|
}
|
|
else
|
|
error ("No marked block.");
|
|
}
|
|
|
|
/*
|
|
** uncomment_block:
|
|
**
|
|
** This routine uncomments a block of code that was commented out by
|
|
** comment_block. It removed the comment and leading "**" characters (if
|
|
** appropriate), and restores the internal comments to their original,
|
|
** un-escaped state.
|
|
*/
|
|
|
|
void uncomment_block (void)
|
|
{
|
|
int start_line,
|
|
start_col,
|
|
end_line,
|
|
end_col;
|
|
|
|
if (inq_marked (start_line, start_col, end_line, end_col))
|
|
{
|
|
raise_anchor ();
|
|
save_position ();
|
|
move_abs (end_line, end_col);
|
|
insert ("\xff");
|
|
move_abs (start_line, start_col);
|
|
|
|
while (read (1) != "\xff")
|
|
{
|
|
search_fwd ("{</\\* }|{<\\*/ }|{ /\\* }|{<\\*\\*\t}|{ \\*/ }|{\\\\\\*}|{\\\\/\\*}|\xff");
|
|
|
|
if (read (1) != "\xff")
|
|
{
|
|
if (read (1) == "\\")
|
|
{
|
|
delete_char ();
|
|
right ();
|
|
}
|
|
else
|
|
{
|
|
drop_anchor ();
|
|
|
|
if (read (1) != " " || read (2) == "**")
|
|
move_rel (0, 2);
|
|
else
|
|
move_rel (0, 3);
|
|
delete_block ();
|
|
}
|
|
}
|
|
}
|
|
delete_char ();
|
|
restore_position ();
|
|
}
|
|
else
|
|
error ("No marked block.");
|
|
}
|
|
|