Greetings all,
Given these settings:
:set tw=20
:set formatoptions=tcq2
:set smartindent
... and given this text:
NOTE: blah blah
blah blah
# NOTE: blah blah
# blah blah
If I do gq{motion} on the top paragraph, formatting is unchanged (as
expected), however, gq{motion} (or gwap) on the bottom paragraph
results in this new formatting:
# NOTE: blah blah
# blah blah
So, even though I have both the 2 and q formatoptions, the second
line's indentation is not used when within a comment block...
The t and c formatoptions (for auto-wrap) are working properly with
formatoptions+=2 in both paragraphs.
I would prefer for Vim to be consistent; in this case, I think it
should handle auto-wrap and formatting in the same way. So...
I've made a patch!
The patch applies against version 7.3.538 and doesn't mess with
the auto-wrap logic (it's working!). It does mess with these funcs:
format_lines()
insertchar()
internal_format()
open_line()
The patch also fixes numeric list handling within comments (not just
2nd line indenting)...
I've tried my best to "tread lightly" and comment things pretty well.
I've run "make test" and it is OK. I've also added two new tests to
the "test suite"...
I've attached the patch separately to preserve white space, etc..
Finally, below I include a more complex test case that showcases what
this patch can do (I hope it will be accepted by Bram)...
Thanks for your time and consideration, and thanks for Vim!
- Tor
PS - more test cases here:
== numbered list formatting ======================
vi:tw=25:formatoptions=tcqn:smartindent
11 aaaa aaaa aaaa bbbb bbbb bbbb
22 aaaa aaaa aaaa bbbb
bbbb bbbb
33 aaaa aaaa
aaaa bbbb bbbb bbbb
# 11 aaaa aaaa aaaa bbbb bbbb bbbb
# 22 aaaa aaaa aaaa bbbb
# bbbb bbbb
# 33 aaaa aaaa
# aaaa bbbb bbbb bbbb
> > 11 aaaa aaaa aaaa bbbb bbbb bbbb
> > 22 aaaa aaaa aaaa bbbb
> > bbbb bbbb
> > 33 aaaa aaaa
> > aaaa bbbb bbbb bbbb
-- above = before, below = after --
11 aaaa aaaa aaaa
bbbb bbbb bbbb
22 aaaa aaaa aaaa
bbbb bbbb bbbb
33 aaaa aaaa aaaa
bbbb bbbb bbbb
# 11 aaaa aaaa aaaa
# bbbb bbbb bbbb
# 22 aaaa aaaa aaaa
# bbbb bbbb bbbb
# 33 aaaa aaaa aaaa
# bbbb bbbb bbbb
> > 11 aaaa aaaa aaaa
> > bbbb bbbb bbbb
> > 22 aaaa aaaa aaaa
> > bbbb bbbb bbbb
> > 33 aaaa aaaa aaaa
> > bbbb bbbb bbbb
== 2nd line indent formatting ====================
vi:tw=25:formatoptions=tcq2:smartindent
xx aaaa aaaa aaaa bbbb
bbbb bbbb
xx aaaa aaaa
aaaa bbbb bbbb bbbb
# xx aaaa aaaa aaaa bbbb
# bbbb bbbb
# xx aaaa aaaa
# aaaa bbbb bbbb bbbb
> > xx aaaa aaaa aaaa bbbb
> > bbbb bbbb
> > xx aaaa aaaa
> > aaaa bbbb bbbb bbbb
-- above = before, below = after --
xx aaaa aaaa aaaa
bbbb bbbb bbbb
xx aaaa aaaa aaaa
bbbb bbbb bbbb
# xx aaaa aaaa aaaa
# bbbb bbbb bbbb
# xx aaaa aaaa aaaa
# bbbb bbbb bbbb
> > xx aaaa aaaa aaaa
> > bbbb bbbb bbbb
> > xx aaaa aaaa aaaa
> > bbbb bbbb bbbb
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
diff -up ./src/testdir/test68.in.org ./src/testdir/test68.in
--- ./src/testdir/test68.in.org 2012-06-02 07:40:50.000000000 -0700
+++ ./src/testdir/test68.in 2012-06-05 19:30:51.000000000 -0700
@@ -51,6 +51,27 @@ a b
}
STARTTEST
+/^{/+1
+:set tw=5 fo=qn comments=:#
+gwap
+ENDTEST
+
+{
+# 1 a b
+}
+
+STARTTEST
+/^{/+1
+:set tw=5 fo=q2 comments=:#
+gwap
+ENDTEST
+
+{
+# x
+# a b
+}
+
+STARTTEST
/^{/+2
:set tw& fo=a
I^^
diff -up ./src/testdir/test68.ok.org ./src/testdir/test68.ok
--- ./src/testdir/test68.ok.org 2012-06-02 07:40:50.000000000 -0700
+++ ./src/testdir/test68.ok 2012-06-05 19:30:56.000000000 -0700
@@ -34,5 +34,17 @@ a b
}
+{
+# 1 a
+# b
+}
+
+
+{
+# x a
+# b
+}
+
+
{ 1aa ^^2bb }
diff -up ./src/vim.h.org ./src/vim.h
--- ./src/vim.h.org 2012-06-02 07:40:50.000000000 -0700
+++ ./src/vim.h 2012-06-05 16:31:39.000000000 -0700
@@ -1072,12 +1072,14 @@ extern char *(*dyn_libintl_textdomain)(c
#define INSCHAR_DO_COM 2 /* format comments */
#define INSCHAR_CTRLV 4 /* char typed just after CTRL-V */
#define INSCHAR_NO_FEX 8 /* don't use 'formatexpr' */
+#define INSCHAR_COM_WITH_N_OR_2 16 /* format comments with num list or 2nd line indent */
/* flags for open_line() */
#define OPENLINE_DELSPACES 1 /* delete spaces after cursor */
#define OPENLINE_DO_COM 2 /* format comments */
#define OPENLINE_KEEPTRAIL 4 /* keep trailing spaces */
#define OPENLINE_MARKFIX 8 /* fix mark positions */
+#define OPENLINE_COM_WITH_N_OR_2 16 /* format comments with num list or 2nd line indent */
/*
* There are four history tables:
diff -up ./src/ops.c.org ./src/ops.c
--- ./src/ops.c.org 2012-06-02 07:40:50.000000000 -0700
+++ ./src/ops.c 2012-06-05 16:50:50.000000000 -0700
@@ -4597,9 +4597,10 @@ format_lines(line_count, avoid_fex)
char_u *leader_flags = NULL; /* flags for leader of current line */
char_u *next_leader_flags; /* flags for leader of next line */
int do_comments; /* format comments */
+ int do_comments_with_n_or_2 = 0; /* format comments ('q') w/ 'n' or '2' */
#endif
int advance = TRUE;
- int second_indent = -1;
+ int second_indent = -1; /* indent for second line (comment aware) */
int do_second_indent;
int do_number_indent;
int do_trail_white;
@@ -4703,17 +4704,33 @@ format_lines(line_count, avoid_fex)
&& (do_second_indent || do_number_indent)
&& prev_is_end_par
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
-#ifdef FEAT_COMMENTS
- && leader_len == 0
- && next_leader_len == 0
-#endif
)
{
- if (do_second_indent
- && !lineempty(curwin->w_cursor.lnum + 1))
+ if (do_second_indent && !lineempty(curwin->w_cursor.lnum + 1)) {
+#ifdef FEAT_COMMENTS
+ if ( leader_len == 0 && next_leader_len == 0 ) { /* no comment found */
+#endif
second_indent = get_indent_lnum(curwin->w_cursor.lnum + 1);
- else if (do_number_indent)
+#ifdef FEAT_COMMENTS
+ } else {
+ second_indent = next_leader_len;
+ do_comments_with_n_or_2 = 1;
+#endif
+ }
+ }
+ else if (do_number_indent) {
+#ifdef FEAT_COMMENTS
+ if ( leader_len == 0 && next_leader_len == 0 ) { /* no comment found */
+#endif
second_indent = get_number_indent(curwin->w_cursor.lnum);
+#ifdef FEAT_COMMENTS
+ } else {
+ /* get_number_indent() is now "comment aware"... */
+ second_indent = get_number_indent(curwin->w_cursor.lnum);
+ do_comments_with_n_or_2 = 1;
+#endif
+ }
+ }
}
/*
@@ -4752,6 +4769,7 @@ format_lines(line_count, avoid_fex)
insertchar(NUL, INSCHAR_FORMAT
#ifdef FEAT_COMMENTS
+ (do_comments ? INSCHAR_DO_COM : 0)
+ + (do_comments && do_comments_with_n_or_2 ? INSCHAR_COM_WITH_N_OR_2 : 0)
#endif
+ (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
State = old_State;
diff -up ./src/edit.c.org ./src/edit.c
--- ./src/edit.c.org 2012-06-02 07:40:50.000000000 -0700
+++ ./src/edit.c 2012-06-05 16:31:14.000000000 -0700
@@ -5769,6 +5769,17 @@ insert_special(c, allow_modmask, ctrlv)
# define WHITECHAR(cc) vim_iswhite(cc)
#endif
+/*
+ * "flags": INSCHAR_FORMAT - force formatting
+ * INSCHAR_CTRLV - char typed just after CTRL-V
+ * INSCHAR_NO_FEX - don't use 'formatexpr'
+ *
+ * NOTE: passes the flags value straight through to internal_format() which,
+ * beside INSCHAR_FORMAT (above), is also looking for these:
+ *
+ * INSCHAR_DO_COM - format comments
+ * INSCHAR_COM_WITH_N_OR_2 - format comments w/ num list or 2nd line indent
+ */
void
insertchar(c, flags, second_indent)
int c; /* character to insert or NUL */
@@ -6011,6 +6022,10 @@ insertchar(c, flags, second_indent)
/*
* Format text at the current insert position.
+ *
+ * If the INSCHAR_COM_WITH_N_OR_2 flag is present, then the value of
+ * second_indent will be the comment leader length sent to open_line().
+ *
*/
static void
internal_format(textwidth, second_indent, flags, format_only, c)
@@ -6289,13 +6304,22 @@ internal_format(textwidth, second_indent
+ (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
#ifdef FEAT_COMMENTS
+ (do_comments ? OPENLINE_DO_COM : 0)
+ + ((flags & INSCHAR_COM_WITH_N_OR_2) ? OPENLINE_COM_WITH_N_OR_2 : 0)
#endif
- , old_indent);
- old_indent = 0;
+ ,( (flags & INSCHAR_COM_WITH_N_OR_2) ? second_indent : old_indent ));
+ if ( ! ( flags & INSCHAR_COM_WITH_N_OR_2 ) ) old_indent = 0;
replace_offset = 0;
if (first_line)
{
+ if ( ! (flags & INSCHAR_COM_WITH_N_OR_2) ) {
+ /*
+ * This section is for numeric lists w/o comments. If comment
+ * indents are needed with numeric lists (formatoptions=nq), then
+ * the INSCHAR_COM_WITH_N_OR_2 flag will cause the corresponding
+ * OPENLINE_COM_WITH_N_OR_2 flag to be passed through to
+ * open_line() (as seen above)...
+ */
if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
second_indent = get_number_indent(curwin->w_cursor.lnum -1);
if (second_indent >= 0)
@@ -6307,6 +6331,7 @@ internal_format(textwidth, second_indent
#endif
(void)set_indent(second_indent, SIN_CHANGED);
}
+ }
first_line = FALSE;
}
diff -up ./src/misc1.c.org ./src/misc1.c
--- ./src/misc1.c.org 2012-06-02 07:40:50.000000000 -0700
+++ ./src/misc1.c 2012-06-05 16:56:55.000000000 -0700
@@ -423,27 +423,63 @@ get_number_indent(lnum)
{
colnr_T col;
pos_T pos;
- regmmatch_T regmatch;
if (lnum > curbuf->b_ml.ml_line_count)
return -1;
pos.lnum = 0;
- regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
- if (regmatch.regprog != NULL)
- {
- regmatch.rmm_ic = FALSE;
- regmatch.rmm_maxcol = 0;
- if (vim_regexec_multi(®match, curwin, curbuf, lnum,
- (colnr_T)0, NULL))
- {
- pos.lnum = regmatch.endpos[0].lnum + lnum;
- pos.col = regmatch.endpos[0].col;
+
+#ifdef FEAT_COMMENTS
+ if ( has_format_option(FO_Q_COMS) && has_format_option(FO_Q_NUMBER) ) {
+ regmatch_T regmatch;
+ int lead_len; /* length of comment leader */
+
+ lead_len = get_leader_len(ml_get(lnum), NULL, FALSE);
+ regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
+ if (regmatch.regprog != NULL) {
+ regmatch.rm_ic = FALSE;
+ /*
+ * vim_regexec() expects a pointer to a line. This lets us
+ * start matching for the flp beyond any comment leader...
+ */
+ if (vim_regexec(®match, ml_get(lnum) + lead_len, (colnr_T)0)) {
+ pos.lnum = lnum;
+ pos.col = *regmatch.endp - (ml_get(lnum) + lead_len);
+ pos.col += lead_len;
#ifdef FEAT_VIRTUALEDIT
pos.coladd = 0;
#endif
}
- vim_free(regmatch.regprog);
+ }
+ vim_free(regmatch.regprog);
+ } else {
+ /*
+ * What follows is the orig code that is not "comment aware"...
+ *
+ * I'm not sure if regmmatch_T (multi-match) is needed in this case.
+ * It may be true that this section would work properly using the
+ * regmatch_T code above, in which case, these two seperate sections
+ * should be consolidated w/ FEAT_COMMENTS making lead_len > 0...
+ */
+#endif
+ regmmatch_T regmatch;
+
+ regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
+
+ if (regmatch.regprog != NULL) {
+ regmatch.rmm_ic = FALSE;
+ regmatch.rmm_maxcol = 0;
+ if (vim_regexec_multi(®match, curwin, curbuf, lnum, (colnr_T)0, NULL)) {
+ pos.lnum = regmatch.endpos[0].lnum + lnum;
+ pos.col = regmatch.endpos[0].col;
+#ifdef FEAT_VIRTUALEDIT
+ pos.coladd = 0;
+#endif
+ }
+ vim_free(regmatch.regprog);
+ }
+#ifdef FEAT_COMMENTS
}
+#endif
if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL)
return -1;
@@ -502,15 +538,16 @@ cin_is_cinword(line)
* OPENLINE_DO_COM format comments
* OPENLINE_KEEPTRAIL keep trailing spaces
* OPENLINE_MARKFIX adjust mark positions after the line break
+ * OPENLINE_COM_WITH_N_OR_2 format comments with num list or 2nd line indent
*
* Return TRUE for success, FALSE for failure
*/
int
-open_line(dir, flags, old_indent)
+open_line(dir, flags, second_line_indent)
int dir; /* FORWARD or BACKWARD */
int flags;
- int old_indent; /* indent for after ^^D in Insert mode */
-{
+ int second_line_indent; /* indent for after ^^D in Insert mode */
+{ /* ... or if flag OPENLINE_COM_WITH_N_OR_2 */
char_u *saved_line; /* copy of the original line */
char_u *next_line = NULL; /* copy of the next line */
char_u *p_extra = NULL; /* what goes to next line */
@@ -650,8 +687,8 @@ open_line(dir, flags, old_indent)
* count white space on current line
*/
newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts);
- if (newindent == 0)
- newindent = old_indent; /* for ^^D command in insert mode */
+ if (newindent == 0 && ! (flags & OPENLINE_COM_WITH_N_OR_2) )
+ newindent = second_line_indent; /* for ^^D command in insert mode */
#ifdef FEAT_SMARTINDENT
/*
@@ -1008,8 +1045,8 @@ open_line(dir, flags, old_indent)
if (lead_len)
{
/* allocate buffer (may concatenate p_exta later) */
- leader = alloc(lead_len + lead_repl_len + extra_space +
- extra_len + 1);
+ leader = alloc(lead_len + lead_repl_len + extra_space + extra_len + 1
+ + ( second_line_indent > 0 ? second_line_indent : 0 ) );
allocated = leader; /* remember to free it later */
if (leader == NULL)
@@ -1304,6 +1341,20 @@ open_line(dir, flags, old_indent)
/* concatenate leader and p_extra, if there is a leader */
if (lead_len)
{
+ if (flags & OPENLINE_COM_WITH_N_OR_2 && second_line_indent > 0) {
+ /*
+ * Here whitespace is inserted after the comment char...
+ *
+ * Below, set_indent(newindent, SIN_INSERT) will insert the whitespace
+ * needed before the comment char.
+ */
+ int i;
+ int padding = second_line_indent - ( newindent + strlen(leader) );
+ for (i = 0; i < padding; i++) {
+ strcat(leader, " ");
+ newcol++;
+ }
+ }
STRCAT(leader, p_extra);
p_extra = leader;
did_ai = TRUE; /* So truncating blanks works with comments */