31

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 source control, diffing, and collaborative editing.

I'm basically convinced, but I'm lazy, and I don't want to have to think about it.

So I'm searching for some emacs incantation to handle it for me. Could be a minor mode, could be a set of variables that need to be set.

I think what I don't want is

  • Soft wrapping of text (say using the longlines and (set long-lines-auto-wrap 't)). This is because I don't want to impose requirements on my collaborators' editors, and I sometimes use other unix tools to examine these files.

I think what I do want is

  • For fill-paragraph to fill between newlines that look like they mark the end of a sentence.
  • A solution that works with auto-fill-mode would be a bonus.

That is:

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

Transformed to:

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

Your comments and suggestions are appreciated.


Edit: The suggestion by Jouni K. Seppänen pointed me at LaTeX-fill-break-at-separators, which suggests that emacs almost knows how to do this already. Anyway, I'm off to read some code, and will report back. Thanks again.


More general version of the same question: Editor showdown: Maintain newlines at the ends of sentences. Thanks, dreeves.

4

10 に答える 10

10

これが私が使用するもので、ほとんどがルカ・デ・アルファロから盗用されたものです:

(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))))))

これをにバインドM-jします

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

への参照"LaTeX"AUCTeXサポート用です。AUCTeX を使用しない場合は、次のletように簡略化できます。

(let (beg (point))
  (forward-sentence)
  (fill-region-as-paragraph beg (point)))
于 2009-02-12T22:29:34.007 に答える
5

私はこれを永遠に行うつもりでしたが、最近このブログ投稿を見つけました。これは私にとってかなりうまくいきました。だからここに私が数日間使ってきたもの(のわずかに修正されたバージョン)があります.

(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)
于 2012-02-22T11:20:29.980 に答える
4

各文の終わりにコメント マーカーを置くと、Emacs は次の行をコメント内で移動しないことを認識します。

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

次に、少なくとも AUCTeX 11.85 では、Mq は各文を個別に埋めます。(Emacs でこれをテストすると、これがバッファの最初の段落で、Mq と入力するとエラー メッセージが表示されるというバグがあるようです。テキストの前に改行を入れるだけで回避できます。)

コメント文字を入力したくない場合は、LaTeX-fill-paragraph を使用して、行末の文末句読点がコメントと同様に機能するように変更できます。

于 2009-02-12T10:35:20.560 に答える
3
(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)
于 2012-01-29T10:20:36.030 に答える
2

すべての状況で機能するとは限りませんが、次のようになります。

(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))))

で動作させるには、LaTeX モード フックauto-fill-modeに追加(setq normal-auto-fill-function 'my-fill-sentence)します (と思います)。

于 2009-02-12T14:28:24.447 に答える
1

他の答えが自動すぎる場合は、半自動のアプローチがあります。これは基本的に、手動で再フォーマットする場合に繰り返し行うことですが、代わりに 1 つのキーを繰り返し押すことができるように要約されています。

;; - 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
于 2009-02-12T15:43:30.787 に答える
1

私は Chris Conway のマクロが大好きですが、各文を手動で改行しないと機能しません。私は怠け者なので、emacs にやってもらいたいと思っています。今朝、ようやく座って問題を調べました。私が今持っている解決策は、組み込みのマクロをハックすることfill-region-as-paragraphです。

次のハックを適用すると、新しいオプションnewline-after-sentenceが true に設定されます。標準M-q( ) は、文の間fill-paragraphに自動的に入力して改行を作成します。テストは GNU Emacs 23.3.1 でのみ行われることに注意してください — 自己責任で使用してください。

完全なマクロは長いので、ここには掲載しません。アイデアは、次のループを追加することです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)))))

...

完全なマクロは私の git リポジトリにあります。詳細はブログにも書いています。私の下手な英語を読みたくない場合は、単に使用できます

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

ハックをあなたに追加し~/.emacsて試してみてください。コメントやバグレポートは大歓迎です。

于 2011-05-23T21:42:11.827 に答える
1

私はあなたがelispを知っていると仮定しています。

いくつかの方法があります。

  • にフックしauto-fill-modeます。そこにはハードコードされた条件文がたくさんあるので、うまくいかないかもしれません。潜在的に遊んでauto-fill-function、そこに必要なフックがあるかどうかを確認できます。

  • 文字を(おそらく.)「エレクトリック」にして、押すと自分自身を挿入し、関数を呼び出して、現在の行を埋める方法を決定します。

  • を設定しafter-change-hookて、文を埋める方法を決定する関数を呼び出します。この関数は、バッファが変更されるたびに呼び出されるため、効率的に実行してください。(このメカニズムは によって使用されるfont-lockため、あまり心配する必要はありません。遅いように聞こえますが、実際にはそうではありません。人々はゆっくりと入力します。)

適切な場所に接続したら、充填ロジックを実装するだけです。sentence-at-point(from )のソースは参考にthingatptなるかもしれません。

とにかく、これをやっている人は聞いたことがありません...しかし、それは間違いなく可能です. Emacs のほとんどのものと同様に、これは単純なプログラミングの問題です。

于 2009-02-12T10:37:18.340 に答える