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

前端 未结 10 1020
予麋鹿
予麋鹿 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:58

    May not work in all circumstances, but:

    (defun my-fill-sentence ()
      "Fill sentence separated by punctuation or blank lines."
      (interactive)
      (let (start end)
        (save-excursion
          (re-search-backward "\\(^\\s-*$\\|[.?!]\\)" nil t)
          (skip-syntax-forward "^w")
          (setq start (point-at-bol)))
        (save-excursion
          (re-search-forward "\\(^\\s-*$\\|[.?!]\\)" nil t)
          (setq end (point-at-eol)))
        (save-restriction
          (narrow-to-region start end)
          (fill-paragraph nil))))
    

    To make it work with auto-fill-mode, add (setq normal-auto-fill-function 'my-fill-sentence) to your LaTeX mode hook (I think).

    0 讨论(0)
  • 2020-12-23 03:00

    Here's what I use, which was mostly cribbed from Luca de Alfaro:

    (defun fill-sentence ()
      (interactive)
      (save-excursion
        (or (eq (point) (point-max)) (forward-char))
        (forward-sentence -1)
        (indent-relative t)
        (let ((beg (point))
              (ix (string-match "LaTeX" mode-name)))
          (forward-sentence)
          (if (and ix (equal "LaTeX" (substring mode-name ix)))
              (LaTeX-fill-region-as-paragraph beg (point))
            (fill-region-as-paragraph beg (point))))))
    

    I bind this to M-j with

    (global-set-key (kbd "M-j") 'fill-sentence)
    

    The references to "LaTeX" are for AUCTeX support. If you don't use AUCTeX, the let can be simplified to

    (let (beg (point))
      (forward-sentence)
      (fill-region-as-paragraph beg (point)))
    
    0 讨论(0)
  • 2020-12-23 03:01

    I am assuming you know elisp.

    There are a few approaches you can take:

    • Hook into auto-fill-mode. There are a lot of hard-coded conditionals there, so it might not work for you. You can potentially play with auto-fill-function and see if you have the hook you need there.

    • Make a character (probably .) "electric" so that when you press it, it inserts itself and then calls a function to determine how to fill the line you're on.

    • Set an after-change-hook to call a function that determines how to fill the sentence. This function will be called after every change to the buffer, so do it efficiently. (This mechanism is used by font-lock, so don't worry about it too much. It sounds slow, but really isn't -- people type slowly.)

    Once you have hooked in at the right place, you just have to implement the filling logic. The source for sentence-at-point (from thingatpt) may be instructive.

    Anyway, I've never heard of anyone doing this... but it is definitely possible. Like most things in Emacs, it's just a Simple Matter Of Programming.

    0 讨论(0)
  • 2020-12-23 03:04

    I have been meaning to do this forever and I recently found this blog post which worked fairly well for me. So here is (a slightly modified version of) what I have been using for a few days.

    (defun auto-fill-by-sentences ()
      (if (looking-back (sentence-end))
          ;; Break at a sentence
          (progn
            (LaTeX-newline)
            t)
        ;; Fall back to the default
        (do-auto-fill)))
    (add-hook 'LaTeX-mode-hook (lambda () (setq auto-fill-function 'auto-fill-by-sentences)))
    
    ;; Modified from http://pleasefindattached.blogspot.com/2011/12/emacsauctex-sentence-fill-greatly.html
    (defadvice LaTeX-fill-region-as-paragraph (around LaTeX-sentence-filling)
      "Start each sentence on a new line."
      (let ((from (ad-get-arg 0))
            (to-marker (set-marker (make-marker) (ad-get-arg 1)))
            tmp-end)
        (while (< from (marker-position to-marker))
          (forward-sentence)
          ;; might have gone beyond to-marker---use whichever is smaller:
          (ad-set-arg 1 (setq tmp-end (min (point) (marker-position to-marker))))
          ad-do-it
          (ad-set-arg 0 (setq from (point)))
          (unless (or (looking-back "^\\s *")
                      (looking-at "\\s *$"))
            (LaTeX-newline)))
        (set-marker to-marker nil)))
    (ad-activate 'LaTeX-fill-region-as-paragraph)
    
    0 讨论(0)
提交回复
热议问题