/***************************************************************************\ * Comment Mode * * * * This file contains routines and commands dealing with comments * * Larry Osterman * \**************************************************************************/ /* * Commented and tweaked a little by K. Shane Hartman. * * This file implements command for manipulating comments. It uses three * buffer specific variables: comment_start, comment_end and comment_column. * See below for a description. The commands implemented are: * * set-comment-column (C-x ;) Sets the comment column to the current column, * with an arg, sets it back to the default value. * * insert-comment (A-;) Creates (or moves to) a comment. If a comment already * exists, it is moved to the comment column (unless it is the first thing * on the line, in which case it stays put). * * insert-comment-on-next-line (A-n) Like insert-comment, but on next line. * * insert-comment-on-previous-line (A-p) Like insert-comment, but on previous * line. * * There are also commands for commenting out lines and regions at the end * of the file, but I prefer to use #if 0 for this. You document them if * you use them. */ #include "eel.h" #ifdef SPR #include "vardefs.h" #else /* * Set these variables on a per mode basis. I set them like this: */ #if 0 c_mode_hook () { comment_start = "/* "; comment_end = "*/"; } #endif /* * I set the default values to ";" and "" when saving state. */ buffer char *comment_start; /* Set on a per mode basis */ buffer char *comment_end; buffer short comment_column = 40; #endif /* SPR */ /* * set_comment_column (C-x ;) Sets the comment column to the current column, * with an arg, sets it back to the default value. */ command set_comment_column() on cx_tab[';'] { iter = 0; if (has_arg) { comment_column = comment_column.default; } else { comment_column = current_column (); } say ("Comment column set to %d in this buffer", comment_column); } /* Quotes regular expression for searching */ re_enquote (targ, source) char *targ; char *source; { char ch; while (ch = *source++) { if (index ("^*%()\\[]|", ch)) *targ++ = '%'; *targ++ = ch; } *targ++ = '\0'; } delete_empty_comment_on_line() { int comment_len = (strlen(comment_start) + strlen(comment_end) * 2); char *empty_comment = malloc(comment_len + 20); char *comment_dummy = malloc(comment_len + 10); int beginsrch,tpoint,beginmatch,endmatch; to_begin_line(); /* * Build up a regular expression that looks like an empty comment * [ \t]* * * Since comment_start and comment_end can contain regular expression * special characters we call the routine re_enquote to stick * regular expression quoting characters around the comment * (ie the C comment characters become: "%/%*% [ \t]*% %*%/") */ re_enquote(comment_dummy,comment_start); strcpy(empty_comment,comment_dummy); strcat(empty_comment,"[ \\t]*"); /* RE that matches whitespace!! */ if (comment_end) { re_enquote(comment_dummy,comment_end); strcat(empty_comment,comment_dummy); } strcat(empty_comment,"\n"); /* * Search forward to find an empty comment */ beginsrch = point; /* Mark the search start. */ if (!re_search(1,empty_comment)) { /* If we found no empty comments */ point = beginsrch; /* Go back to beginning of search */ free(empty_comment); /* and free up our buffers */ free(comment_dummy); return; } /* Otherwise.... */ /* * We mark the beginning and end of the comment that we found, * interchange point and the search start (to make horizontal() * work properly), and see if this comment was on the * same line we are on. If so, we are in luck and we can delete * the comment */ endmatch = point; /* endmatch = end of match */ beginmatch = matchstart; /* beginmatch = start of match */ point = matchstart; /* Point is at beginning of match */ tpoint = beginsrch; /* Interchange point and beginning */ beginsrch = point; point = tpoint; if (horizontal(beginsrch)!=-1) { /* If we found an empty comment on * this line */ /* * We can delete the comment on this line. * We set tmpoint to hold the start location and * tmatch to be the start of the match. We then delete the * comment from the buffer, stick in a \n (we deleted it * from the end of the string), clean up any whitespace at the * end of the line and return. */ int *tmpoint = alloc_spot(), *tmatch = alloc_spot(); *tmpoint = point; *tmatch = beginmatch; delete(beginmatch,endmatch); /* Kill the comment */ point = *tmatch; insert('\n'); /* Insert newline deleted in search */ point = *tmatch; /* Update point to before \n */ delete_horizontal_space(); /* Kill trailing whitespace. */ point = *tmpoint; /* go to before deleted comment. */ free_spot(tmpoint); free_spot(tmatch); } free(empty_comment); /* Just clean up, there were */ free(comment_dummy); /* no empty comments on this line */ } /* insert_comment_on_this_line - insert a comment. * * int insert_comment_on_this_line(eol) * * eol - column containing the end of the current line. * returns: * the column of the start of the comment */ int insert_comment_on_this_line(eol) int eol; { int comcol; /* * If line is longer than the comment column, stick * the comment at end of the line. */ if (eol > comment_column) { to_end_line(); insert(' '); comcol = eol + 1; } else { /* * Otherwise, to to the comment column and stick it there */ my_to_column(comment_column); comcol = comment_column; } stuff(comment_start); if (comment_end) { stuff(comment_end); } return comcol; } /* * insert-comment (A-;) Creates (or moves to) a comment. If a comment already * exists, it is moved to the comment column (unless it is the first thing * on the line, in which case it stays put). */ command insert_comment() on reg_tab[ALT(';')] { int eol, beglin, hcommentposn, tpoint, comcol, comment_start_len = strlen(comment_start); /* * Compute the location of the beginning of the line */ comcol = current_column(), to_end_line(); eol = current_column(); /* eol = column of end of line */ to_begin_line(); beglin = point; /* beglin = beginning of line. */ /* * Find if there is a comment on this line * We do this by searching forward from the current position * for a comment beginning character. If we find one, * we update point to the beginning of the comment, if not, * point is set at the end of the line */ { int len = strlen (comment_start); char *s = malloc (len + 1); int i; for (i = 0; i < len; i++) if ((s[i] = comment_start[i]) == ' ') break; s[i] = 0; if (!search(1,s)) { /* Non zero if we found a comment */ point = beglin; /* Go to beginning of line, */ comcol = insert_comment_on_this_line(eol); /* stick a comment here */ my_to_column(comcol+comment_start_len); /* Stick point at start */ free (s); return; /* and return to caller. */ } free (s); } point = matchstart; tpoint = beglin; beglin = point; point = tpoint; /* Swap start and end of search */ /* * If newline before comment, horizontal will return -1. */ if (horizontal(beglin)==-1) comcol = insert_comment_on_this_line(eol); else { /* * There is a comment on this line. point is set to the * beginning of the comment string. Move the string * to the comment column */ point = beglin; /* Update point to start of comment */ if (current_column()) { /* If not beginning of line, */ /* adjust the comment. */ delete_horizontal_space(); /* Remove whitespace */ eol = current_column(); comcol=(eol>=comment_column)? eol + 1 : comment_column; to_column(comcol); } } my_to_column(comcol+comment_start_len); } /* * my_to_column(col) - go to this column absolutly */ my_to_column(columnum) int columnum; { int eolcol; move_to_column(columnum); /* Move to specified column */ if ((eolcol = current_column()) < columnum) { insert_to_column(eolcol,columnum); to_end_line(); /* Travel to the end of the line */ } } /* insert-comment-on-next-line (A-n) Like insert-comment, but on next line. */ command insert_comment_on_next_line() on reg_tab[ALT('n')] { delete_empty_comment_on_line(); nl_forward(); insert_comment(); } /* * insert-comment-on-previous-line (A-p) Like insert-comment, but on previous * line. */ command insert_comment_on_previous_line() on reg_tab[ALT('p')] { delete_empty_comment_on_line(); nl_reverse(); insert_comment(); } /* * KSH - I don't use this so I commented them at my site. They work. */ #ifndef SPR /* * * comment_out_line - Comment out the current line. * * Comments out the current line, leaving point on the start of * the next line. */ command comment_out_next_line() on reg_tab[ALT('+')] { to_end_line(); point++; comment_out_line(); } command comment_out_prev_line() on reg_tab[ALT('-')] { to_begin_line(); point--; comment_out_line(); } command comment_out_line() { int *oldpoint = alloc_spot(); *oldpoint = point; to_begin_line(); /* Move to beginning of line */ stuff(comment_start); to_end_line(); stuff(comment_end); point = *oldpoint; free_spot(oldpoint); } command comment_out_region() on cx_tab['+'] { int direction; /* +1 or -1 from start of line. */ int *oldpoint; if (point==mark) return; oldpoint = alloc_spot(); /* allocate a spot for current point*/ *oldpoint = point; /* keep track of where we started */ if (point < mark) { while (pointmark) { comment_out_line(); to_begin_line(); point--; } } point = *oldpoint; free_spot(oldpoint); return; } #endif