Hello Vim developers; attached is a patch to add a new flag 'p' to
'formatoptions' to avoid breaking a line after an abbreviating period
during reformatting. The commit message from the patch is reproduced
here:
GNU Emacs' default settings for reformatting prose (fill-paragraph,
fill-region) include a useful subtlety: reformatting a block of text
will not break a line at a single space after a period. This means
title abbreviations such as "Mr. Feynman" always remain together on one
line, avoiding the editor (or the reader) subsequently misinterpreting a
period at the end of the line as constituting the end of a sentence.
There is some detail and rationale for this approach in the GNU Emacs
manual:
<https://www.gnu.org/software/emacs/manual/html_node/emacs/Sentences.html>
This patch adds a new 'p' flag to 'formatoptions' to support the same
behaviour in Vim. It works by excluding a single space as a potential
line breakpoint during formatting if the non-space character immediately
before it is a period. It will still break the line if there is more
than one space after the period.
For example, with 'formatoptions' including 'p', and with 'textwidth'
set to 28, keying `gqq` in normal mode to reformat this line:
Surely you're joking, Mr. Feynman!
Yields:
Surely you're joking,
Mr. Feynman!
Instead of:
Surely you're joking, Mr.
Feynman!
However, reformatting this line (note two spaces):
Surely you're joking, Sir. You must be!
Yields:
Surely you're joking, Sir.
You must be!
This new flag will probably only be of interest to users who write prose
with sentences separated by two spaces. These will be the same users
who leave 'joinspaces' on (the default), and who include the J flag in
'cpoptions' to define a sentence object according to their tastes.
However, the flag's behavior will likely not suit those who use a single
space to separate sentences, as formatting will then refuse to end a
line on any sentence terminating with a period. This is because the
flag knows no other way to determine the difference between an
abbreviating period and a sentence terminating period, aside from the
number of spaces that follow it.
A new test for this flag is added to the `Test_text_format()` function
in the "textformat" test group. A new entry in `:help fo-table` is also
added, with an example.
--
Tom Ryder <https://sanctum.geek.nz/>
--
--
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
---
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
>From cfcd9dfdfa0cf655ea53f9500d15dfabc5cf82ec Mon Sep 17 00:00:00 2001
From: Tom Ryder <[email protected]>
Date: Thu, 27 Dec 2018 16:45:11 +1300
Subject: [PATCH] Add 'formatoptions' 'p' flag for abbrev periods
GNU Emacs' default settings for reformatting prose (fill-paragraph,
fill-region) include a useful subtlety: reformatting a block of text
will not break a line at a single space after a period. This means
title abbreviations such as "Mr. Feynman" always remain together on one
line, avoiding the editor (or the reader) subsequently misinterpreting a
period at the end of the line as constituting the end of a sentence.
There is some detail and rationale for this approach in the GNU Emacs
manual:
<https://www.gnu.org/software/emacs/manual/html_node/emacs/Sentences.html>
This patch adds a new 'p' flag to 'formatoptions' to support the same
behaviour in Vim. It works by excluding a single space as a potential
line breakpoint during formatting if the non-space character immediately
before it is a period. It will still break the line if there is more
than one space after the period.
For example, with 'formatoptions' including 'p', and with 'textwidth'
set to 28, keying `gqq` in normal mode to reformat this line:
Surely you're joking, Mr. Feynman!
Yields:
Surely you're joking,
Mr. Feynman!
Instead of:
Surely you're joking, Mr.
Feynman!
However, reformatting this line (note two spaces):
Surely you're joking, Sir. You must be!
Yields:
Surely you're joking, Sir.
You must be!
This new flag will probably only be of interest to users who write prose
with sentences separated by two spaces. These will be the same users
who leave 'joinspaces' on (the default), and who include the J flag in
'cpoptions' to define a sentence object according to their tastes.
However, the flag's behavior will likely not suit those who use a single
space to separate sentences, as formatting will then refuse to end a
line on any sentence terminating with a period. This is because the
flag knows no other way to determine the difference between an
abbreviating period and a sentence terminating period, aside from the
number of spaces that follow it.
A new test for this flag is added to the `Test_text_format()` function
in the "textformat" test group. A new entry in `:help fo-table` is also
added, with an example.
---
runtime/doc/change.txt | 11 +++++++++++
src/edit.c | 13 +++++++++++++
src/option.h | 3 ++-
src/testdir/test_textformat.vim | 26 ++++++++++++++++++++++++++
4 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index ff0c44a66..bef750064 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1720,6 +1720,17 @@ j Where it makes sense, remove a comment leader
when joining lines. For
// in the list ~
Becomes:
int i; // the index in the list ~
+p Don't break lines at single spaces that follow periods. This is
+ intended to complement 'joinspaces' and |cpo-J|, for prose with
+ sentences separated by two spaces. For example, with 'textwidth' set
+ to 28: >
+ Surely you're joking, Mr. Feynman!
+< Becomes: >
+ Surely you're joking,
+ Mr. Feynman!
+< Instead of: >
+ Surely you're joking, Mr.
+ Feynman!
With 't' and 'c' you can specify when Vim performs auto-wrapping:
diff --git a/src/edit.c b/src/edit.c
index a522fe93b..8845cb429 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -6481,6 +6481,7 @@ internal_format(
char_u *saved_text = NULL;
colnr_T col;
colnr_T end_col;
+ int wcc; /* counter for whitespace chars in a
group */
virtcol = get_nolist_virtcol()
+ char2cells(c != NUL ? c : gchar_cursor());
@@ -6543,13 +6544,25 @@ internal_format(
end_col = curwin->w_cursor.col;
/* find start of sequence of blanks */
+ wcc = 0;
while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
{
dec_cursor();
cc = gchar_cursor();
+
+ /* Increment count of how many whitespace chars in this
+ * group; we only need to know if it's more than one */
+ if (wcc < 2)
+ wcc++;
}
if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
break; /* only spaces in front of text */
+
+ /* Don't break immediately after a period when 'formatoptions'
+ * has 'p' */
+ if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2)
+ continue;
+
#ifdef FEAT_COMMENTS
/* Don't break until after the comment leader */
if (curwin->w_cursor.col < leader_len)
diff --git a/src/option.h b/src/option.h
index cb25938e7..50fe380ed 100644
--- a/src/option.h
+++ b/src/option.h
@@ -101,10 +101,11 @@
#define FO_WHITE_PAR 'w' /* trailing white space continues paragr. */
#define FO_AUTO 'a' /* automatic formatting */
#define FO_REMOVE_COMS 'j' /* remove comment leaders when joining lines */
+#define FO_PERIOD_ABBR 'p' /* don't break a single space after a period */
#define DFLT_FO_VI "vt"
#define DFLT_FO_VIM "tcq"
-#define FO_ALL "tcroq2vlb1mMBn,awj" /* for do_set() */
+#define FO_ALL "tcroq2vlb1mMBn,awjp" /* for do_set() */
/* characters for the p_cpo option: */
#define CPO_ALTREAD 'a' /* ":read" sets alternate file name */
diff --git a/src/testdir/test_textformat.vim b/src/testdir/test_textformat.vim
index 377f761b7..539b6f5bd 100644
--- a/src/testdir/test_textformat.vim
+++ b/src/testdir/test_textformat.vim
@@ -163,6 +163,32 @@ func Test_text_format()
\ '# 1 xxxxx',
\ '# foobar'], getline(1, 2))
+ " Test the 'p' flag for 'formatoptions'
+ " First test without the flag: that it will break "Mr. Feynman" at the space
+ normal ggdG
+ setl tw=28 fo=tcq
+ call setline('.', 'Surely you''re joking, Mr. Feynman!')
+ normal gqq
+ call assert_equal([
+ \ 'Surely you''re joking, Mr.',
+ \ 'Feynman!'], getline(1, 2))
+ " Now test with the flag: that it will push the name with the title onto the
+ " next line
+ normal ggdG
+ setl fo+=p
+ call setline('.', 'Surely you''re joking, Mr. Feynman!')
+ normal gqq
+ call assert_equal([
+ \ 'Surely you''re joking,',
+ \ 'Mr. Feynman!'], getline(1, 2))
+ " Ensure that it will still break if two spaces are entered
+ normal ggdG
+ call setline('.', 'Surely you''re joking, Mr. Feynman!')
+ normal gqq
+ call assert_equal([
+ \ 'Surely you''re joking, Mr.',
+ \ 'Feynman!'], getline(1, 2))
+
setl ai& tw& fo& si& comments&
enew!
endfunc
--
2.20.1