fill: Emacs script to add line breaks between sentences

This makes fill-paragraph (M-q) in Emacs implement the desired format
for proposal documents.

Change-Id: I236f3f68ca40255ebab2382a117fb283cbb3908b
Reviewed-on: https://go-review.googlesource.com/67930
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/README.md b/README.md
index 4e92db1..83d9f76 100644
--- a/README.md
+++ b/README.md
@@ -94,6 +94,8 @@
 	- For ease of review with Gerrit, design documents should be wrapped around the
           80 column mark. [Each sentence should start on a new line](http://rhodesmill.org/brandon/2012/one-sentence-per-line/)
           so that comments can be made accurately and the diff kept shorter.
+          In Emacs, loading `fill.el` from this directory will make
+          `fill-paragraph` format text this way.
 	- Comments on Gerrit CLs should be restricted to grammar, spelling, or
           procedural errors related to the preparation of the proposal itself.
           All other comments should be addressed to the related GitHub issue.
diff --git a/fill.el b/fill.el
new file mode 100644
index 0000000..5ac8a8d
--- /dev/null
+++ b/fill.el
@@ -0,0 +1,62 @@
+;; Copyright 2017 The Go Authors. All rights reserved.
+;; Use of this source code is governed by a BSD-style
+;; license that can be found in the LICENSE file.
+
+;; This makes fill-paragraph (M-q) add line breaks at sentence
+;; boundaries in addition to normal wrapping. This is the style for Go
+;; proposals.
+;;
+;; Loading this script automatically enables this for markdown-mode
+;; buffers in the go-design/proposal directory. It can also be
+;; manually enabled with M-x enable-fill-split-sentences.
+;;
+;; This is sensitive to the setting of `sentence-end-double-space`,
+;; which defaults to t. If `sentence-end-double-space` is t, but a
+;; paragraph only a single space between sentences, this will not
+;; insert line breaks where expected.
+
+(defun fill-split-sentences (&optional justify)
+  "Fill paragraph at point, breaking lines at sentence boundaries."
+  (interactive)
+  (save-excursion
+    ;; Do a trial fill and get the fill prefix for this paragraph.
+    (let ((prefix (or (fill-paragraph) ""))
+          (end (progn (fill-forward-paragraph 1) (point)))
+          (beg (progn (fill-forward-paragraph -1) (point))))
+      (save-restriction
+        (narrow-to-region (line-beginning-position) end)
+        ;; Unfill the paragraph.
+        (let ((fill-column (point-max)))
+          (fill-region beg end))
+        ;; Fill each sentence.
+        (goto-char (point-min))
+        (while (not (eobp))
+          (if (bobp)
+              ;; Skip over initial prefix.
+              (goto-char beg)
+            ;; Clean up space between sentences.
+            (skip-chars-forward " \t")
+            (delete-horizontal-space 'backward-only)
+            (insert "\n" prefix))
+          (let ((sbeg (point))
+                (fill-prefix prefix))
+            (forward-sentence)
+            (fill-region-as-paragraph sbeg (point)))))
+      prefix)))
+
+(defun enable-fill-split-sentences ()
+  "Make fill break lines at sentence boundaries in this buffer."
+  (interactive)
+  (setq-local fill-paragraph-function #'fill-split-sentences))
+
+(defun proposal-enable-fill-split ()
+  (when (string-match "go-proposal/design/" (buffer-file-name))
+    (enable-fill-split-sentences)))
+
+;; Enable sentence splitting in new proposal buffers.
+(add-hook 'markdown-mode-hook #'proposal-enable-fill-split)
+
+;; Enable sentence splitting in this buffer, in case the user loaded
+;; fill.el when already in a buffer.
+(when (eq major-mode 'markdown-mode)
+  (proposal-enable-fill-split))