How do I get Emacs to fill sentences, but not paragraphs?

前端 未结 10 1019
予麋鹿
予麋鹿 2020-12-23 02:23

I\'ve seen at least two recommendations on StackOverflow to insert newlines between sentences when editing LaTeX documents. The reason being that the practice facilitates so

相关标签:
10条回答
  • 2020-12-23 02:43

    An alternative approach would be to leave your .tex file as is, and use a tool like latexdiff (described in this StackExchange post) instead of Unix diff. This produces a .tex file with Word-style track changes marks, and handles whitespace correctly so you don't have to worry about where your sentences end.

    0 讨论(0)
  • 2020-12-23 02:47

    If the other answers are too automatic, here's a semiautomatic approach. It's basically what you would do repeatedly if you were going to manually reformat, but condensed so you can hit a single key repeatedly instead.

    ;; - go to the end of the line,
    ;; - do ^d to suck the previous line onto this one, 
    ;; - make sure there's only one space between the now-concatenated
    ;;   lines, and then 
    ;; - jump to the end and hit space so that (with auto-fill-mode)
    ;;   the line nicely rewraps itself:
    ;;   (turn on auto-fill-mode with M-x auto-fill-mode)
    (defalias 'fill-sentence
      (read-kbd-macro "C-e C-d SPC M-x just- one- space RET C-e SPC <backspace>"))
    
    (define-key global-map [f4] 'fill-sentence)  ; or whatever key you like
    
    0 讨论(0)
  • 2020-12-23 02:47

    I like Chris Conway's macro a lot but it only works after you manually line-break each sentence. I'm a lazy guy so I want emacs to do it for me. This morning I finally sat down and looked into the problem. The solution I have now is to hack the built-in macro fill-region-as-paragraph.

    After applying the following hack, a new option newline-after-sentence will be set to true. The standard M-q (fill-paragraph) will automatically fill and create line-breaks between sentences. Note that tests are only done with GNU Emacs 23.3.1 — use it at your own risk.

    The full macro is long so I won't post it here. The idea is to add the following loops in fill-region-as-paragraph

    ...
    
    ;; Insert a line break after each sentence
    (while (< (point) to)
      (forward-sentence)
      (if (< (point) to) (fill-newline)))
    
    ;; This is the actual filling loop.
    (goto-char from)
    (let (sentbeg sentend)
      (while (< (point) to)
        (setq sentbeg (point))
        (end-of-line)
        (setq sentend (point))
        (fill-one-line sentbeg sentend justify) ;; original filling loop
        (forward-line)))))
    
    ...
    

    You can find the full macro in my git repository. Some details are also written in my blog. In case you don't want to read my poor English, you can simply use

    $ curl http://fermi.mycloudnas.com/cgit.cgi/fill/plain/hack.el >> ~/.emacs
    

    to append the hack to your ~/.emacs and give it a try. Comments and bug reports are all welcome.

    0 讨论(0)
  • 2020-12-23 02:48
    (defun wrap-at-sentences ()
      "Fills the current paragraph, but starts each sentence on a new line."
      (interactive)
      (save-excursion
        ;; Select the entire paragraph.
        (mark-paragraph)
        ;; Move to the start of the paragraph.
        (goto-char (region-beginning))
        ;; Record the location of the end of the paragraph.
        (setq end-of-paragraph (region-end))
        ;; Wrap lines with 'hard' newlines (i.e., real line breaks).
        (let ((use-hard-newlines 't))
          ;; Loop over each sentence in the paragraph.
          (while (< (point) end-of-paragraph)
            ;; Determine the region spanned by the sentence.
            (setq start-of-sentence (point))
            (forward-sentence)
            ;; Wrap the sentence with hard newlines.
            (fill-region start-of-sentence (point))
            ;; Delete the whitespace following the period, if any.
            (while (char-equal (char-syntax (preceding-char)) ?\s)
              (delete-char -1))
            ;; Insert a newline before the next sentence.
            (insert "\n")))))
    
    (global-set-key (kbd "M-q") 'wrap-at-sentences)
    
    0 讨论(0)
  • 2020-12-23 02:48

    I wrote the following which loops over a region and inserts newlines. Instead of using forward-sentence which didn't work for me, I use re-search-forward "[.?!][]\"')}]*\\( \\)", which finds all sentences followed only by two spaces (the regexp is a modified sentence-end). The newline is made using newline-and-indent.

    (defun fill-sentences-in-paragraph ()
      "Put a newline at the end of each sentence in paragraph."
      (interactive)
      (save-excursion
        (mark-paragraph)
        (call-interactively 'fill-sentences-in-region)))
    
    (defun fill-sentences-in-region (start end)
      "Put a newline at the end of each sentence in region."
      (interactive "*r")
      (call-interactively 'unfill-region)
      (save-excursion
        (goto-char start)
        (while (re-search-forward "[.?!][]\"')}]*\\(  \\)" end t)
          (newline-and-indent))))
    

    To be able to fix improperly formatted text such as the example "chat chat chat...", fill-sentences-in-region first calls unfill-region which gets rid of sentence-breaking whitespace:

       (defun unfill-region (beg end)
          "Unfill the region, joining text paragraphs into a
           single logical line.  This is useful, e.g., for use
           with 'visual-line-mode'."
          (interactive "*r")
          (let ((fill-column (point-max)))
            (fill-region beg end)))
    

    I use visual-line-mode and replace my default paragraph fill M-q to fill-sentences-in-paragraph with (global-set-key "\M-q" 'fill-sentences-in-paragraph).

    0 讨论(0)
  • 2020-12-23 02:49

    If you put a comment marker at the end of each sentence, Emacs knows not to move the next line inside the comment:

    chat chat chat.%
    A new sentence
    with goofed up wrapping that needs to be fixed.%
    Mumble mumble%
    

    Then M-q fills each sentence separately, at least in AUCTeX 11.85. (If you test this in Emacs, there seems to be a bug where if this is the first paragraph in the buffer and you type M-q, you get an error message. Just put a newline before the text to work around it.)

    If you don't want to type the comment characters, you could take LaTeX-fill-paragraph and modify it so that sentence-ending punctuation at end of line works similarly to comments.

    0 讨论(0)
提交回复
热议问题