Mercurial > vim
diff src/ops.c @ 3562:5c1aaf9b4b1b v7.3.541
updated for version 7.3.541
Problem: When joining lines comment leaders need to be removed manually.
Solution: Add the 'j' flag to 'formatoptions'. (Lech Lorens)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Wed, 06 Jun 2012 16:12:59 +0200 |
parents | 9a1dba1f969a |
children | 4f4db5d661c4 |
line wrap: on
line diff
--- a/src/ops.c +++ b/src/ops.c @@ -112,6 +112,9 @@ static void may_set_selection __ARGS((vo # endif #endif static void dis_msg __ARGS((char_u *p, int skip_esc)); +#if defined(FEAT_COMMENTS) || defined(PROTO) +static char_u *skip_comment __ARGS((char_u *line, int process, int include_space, int *is_comment)); +#endif #ifdef FEAT_VISUAL static void block_prep __ARGS((oparg_T *oap, struct block_def *, linenr_T, int)); #endif @@ -1987,7 +1990,7 @@ op_delete(oap) curwin->w_cursor = curpos; /* restore curwin->w_cursor */ } if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - (void)do_join(2, FALSE, FALSE); + (void)do_join(2, FALSE, FALSE, FALSE); } } @@ -4197,17 +4200,98 @@ dis_msg(p, skip_esc) ui_breakcheck(); } +#if defined(FEAT_COMMENTS) || defined(PROTO) +/* + * If "process" is TRUE and the line begins with a comment leader (possibly + * after some white space), return a pointer to the text after it. Put a boolean + * value indicating whether the line ends with an unclosed comment in + * "is_comment". + * line - line to be processed, + * process - if FALSE, will only check whether the line ends with an unclosed + * comment, + * include_space - whether to also skip space following the comment leader, + * is_comment - will indicate whether the current line ends with an unclosed + * comment. + */ + static char_u * +skip_comment(line, process, include_space, is_comment) + char_u *line; + int process; + int include_space; + int *is_comment; +{ + char_u *comment_flags = NULL; + int lead_len; + int leader_offset = get_last_leader_offset(line, &comment_flags); + + *is_comment = FALSE; + if (leader_offset != -1) + { + /* Let's check whether the line ends with an unclosed comment. + * If the last comment leader has COM_END in flags, there's no comment. + */ + while (*comment_flags) + { + if (*comment_flags == COM_END + || *comment_flags == ':') + break; + ++comment_flags; + } + if (*comment_flags != COM_END) + *is_comment = TRUE; + } + + if (process == FALSE) + return line; + + lead_len = get_leader_len(line, &comment_flags, FALSE, include_space); + + if (lead_len == 0) + return line; + + /* Find: + * - COM_START, + * - COM_END, + * - colon, + * whichever comes first. + */ + while (*comment_flags) + { + if (*comment_flags == COM_START + || *comment_flags == COM_END + || *comment_flags == ':') + { + break; + } + ++comment_flags; + } + + /* If we found a colon, it means that we are not processing a line + * starting with an opening or a closing part of a three-part + * comment. That's good, because we don't want to remove those as + * this would be annoying. + */ + if (*comment_flags == ':' || *comment_flags == NUL) + line += lead_len; + + return line; +} +#endif + /* * Join 'count' lines (minimal 2) at cursor position. * When "save_undo" is TRUE save lines for undo first. + * Set "use_formatoptions" to FALSE when e.g. processing + * backspace and comment leaders should not be removed. * * return FAIL for failure, OK otherwise */ int -do_join(count, insert_space, save_undo) +do_join(count, insert_space, save_undo, use_formatoptions) long count; int insert_space; int save_undo; + int use_formatoptions UNUSED; { char_u *curr = NULL; char_u *curr_start = NULL; @@ -4221,6 +4305,13 @@ do_join(count, insert_space, save_undo) linenr_T t; colnr_T col = 0; int ret = OK; +#if defined(FEAT_COMMENTS) || defined(PROTO) + int *comments; + int remove_comments = (use_formatoptions == TRUE) + && has_format_option(FO_REMOVE_COMS); + int prev_was_comment; +#endif + if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1), (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL) @@ -4232,6 +4323,17 @@ do_join(count, insert_space, save_undo) spaces = lalloc_clear((long_u)count, TRUE); if (spaces == NULL) return FAIL; +#if defined(FEAT_COMMENTS) || defined(PROTO) + if (remove_comments) + { + comments = (int *)lalloc_clear((long_u)count * sizeof(int), TRUE); + if (comments == NULL) + { + vim_free(spaces); + return FAIL; + } + } +#endif /* * Don't move anything, just compute the final line length @@ -4240,6 +4342,25 @@ do_join(count, insert_space, save_undo) for (t = 0; t < count; ++t) { curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t)); +#if defined(FEAT_COMMENTS) || defined(PROTO) + if (remove_comments) + { + /* We don't want to remove the comment leader if the + * previous line is not a comment. */ + if (t > 0 && prev_was_comment) + { + + char_u *new_curr = skip_comment(curr, TRUE, insert_space, + &prev_was_comment); + comments[t] = new_curr - curr; + curr = new_curr; + } + else + curr = skip_comment(curr, FALSE, insert_space, + &prev_was_comment); + } +#endif + if (insert_space && t > 0) { curr = skipwhite(curr); @@ -4327,6 +4448,10 @@ do_join(count, insert_space, save_undo) if (t == 0) break; curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1)); +#if defined(FEAT_COMMENTS) || defined(PROTO) + if (remove_comments) + curr += comments[t - 1]; +#endif if (insert_space && t > 1) curr = skipwhite(curr); currsize = (int)STRLEN(curr); @@ -4364,6 +4489,10 @@ do_join(count, insert_space, save_undo) theend: vim_free(spaces); +#if defined(FEAT_COMMENTS) || defined(PROTO) + if (remove_comments) + vim_free(comments); +#endif return ret; } @@ -4788,7 +4917,7 @@ format_lines(line_count, avoid_fex) (long)-next_leader_len); #endif curwin->w_cursor.lnum--; - if (do_join(2, TRUE, FALSE) == FAIL) + if (do_join(2, TRUE, FALSE, FALSE) == FAIL) { beep_flush(); break; @@ -4844,7 +4973,7 @@ fmt_check_par(lnum, leader_len, leader_f ptr = ml_get(lnum); if (do_comments) - *leader_len = get_leader_len(ptr, leader_flags, FALSE); + *leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE); else *leader_len = 0;