我在StackOverflow上seen至少有两个recommendations在编辑LaTeX文档时在句子之间插入换行符。原因是该练习有助于源代码控制,diff
和协作编辑。
我基本上确信,但我很懒,而且我不想考虑它。
所以我正在寻找一些emacs咒语来为我处理它。可能是次要模式,可能是需要设置的一组变量。
我认为不想要的是
(set long-lines-auto-wrap 't)
)。这是因为我不想对我的协作者编辑施加要求,我有时会使用其他unix工具来检查这些文件。我认为做想要的是
fill-paragraph
填充新行,这些新行看起来像是标记句子的结尾。 auto-fill-mode
一起使用的解决方案将是一个奖励。那是:
聊天聊天聊天。
新句子 需要修理的包装过度 嘟m嘟嘟
转换为:
聊天聊天聊天。
一个新的句子,包括需要修复的蠢事 嘟m嘟嘟
感谢您的意见和建议。
编辑:Jouni K. Seppänen的建议指出了我LaTeX-fill-break-at-separators
,这表明emacs几乎知道如何做到这一点。无论如何,我要读一些代码,然后报告回来。再次感谢。
同一问题的更一般版本:Editor showdown: Maintain newlines at the ends of sentences。谢谢,dreeves。
答案 0 :(得分:8)
这是what I use,其中大部分来自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))))))
我用
将其绑定到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)))
答案 1 :(得分:3)
如果您在每个句子的末尾添加注释标记,Emacs知道不会移动注释中的下一行:
chat chat chat.%
A new sentence
with goofed up wrapping that needs to be fixed.%
Mumble mumble%
然后M-q分别填写每个句子,至少在AUCTeX 11.85中。 (如果你在Emacs中进行测试,似乎有一个错误,如果这是缓冲区中的第一个段落,你输入Mq,你会得到一条错误信息。只需在文本前加一个换行符来解决它。)
如果您不想输入注释字符,可以使用LaTeX-fill-paragraph并对其进行修改,以便行尾的句尾标点与注释的工作方式类似。
答案 2 :(得分:3)
我一直想要永远这样做,我最近发现this blog post对我来说相当不错。所以这是我几天使用的(略微修改过的版本)。
(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)
答案 3 :(得分: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))))
要使其与auto-fill-mode
一起使用,请将(setq normal-auto-fill-function 'my-fill-sentence)
添加到您的LaTeX模式挂钩(我认为)。
答案 4 :(得分:1)
我假设你知道elisp。
您可以采取一些方法:
挂钩auto-fill-mode
。有很多硬编码
那里的条件,所以它可能不适合你。您可以
可能会与auto-fill-function
一起玩,看看你是否有
你需要的钩子。
制作一个角色(可能是.
)“电”,这样当你按下时
它,它插入自己,然后调用一个函数来确定如何
填写您所在的行。
设置after-change-hook
以调用确定方式的函数
填写句子。每次都会调用此函数
更改为缓冲区,因此请高效执行。 (这个机制是
由font-lock
使用,所以不要太担心。听起来
慢,但实际上不是 - 人们慢慢打字。)
一旦你迷上了正确的地方,你就必须实施
填充逻辑。 sentence-at-point
(来自thingatpt
)的来源可能是
指导性的。
无论如何,我从来没有听说过有人这样做过......但这绝对是可能的。像Emacs中的大多数东西一样,它只是一个简单的编程问题。
答案 5 :(得分: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
答案 6 :(得分:1)
我非常喜欢Chris Conway的宏,但只有在你手动换行每个句子之后它才有效。我是个懒人,所以我想让emacs为我做。今天早上我终于坐下来调查了这个问题。我现在的解决方案是破解内置宏fill-region-as-paragraph
。
应用以下hack后,新选项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)))))
...
您可以在my git repository中找到完整的宏。一些细节也写在my blog中。如果你不想读我糟糕的英语,你可以简单地使用
$ curl http://fermi.mycloudnas.com/cgit.cgi/fill/plain/hack.el >> ~/.emacs
将黑客附加到~/.emacs
并试一试。评论和错误报告都是受欢迎的。
答案 7 :(得分:1)
(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)
答案 8 :(得分:1)
另一种方法是将.tex文件保留原样,并使用latexdiff之类的工具 (在this StackExchange帖子中描述)而不是Unix diff。这会生成一个带有Word样式轨道更改标记的.tex文件,并正确处理空格,因此您不必担心句子的结束位置。
答案 9 :(得分:1)
我编写了以下内容,循环遍历某个区域并插入换行符。我没有使用forward-sentence
对我不起作用,而是使用re-search-forward "[.?!][]\"')}]*\\( \\)"
,它发现所有句子后面只跟两个空格(正则表达式是修改后的sentence-end
)。换行符使用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))))
为了能够修复格式不正确的文本,例如示例&#34;聊天聊天...&#34;,fill-sentences-in-region
首先调用unfill-region
,这样可以摆脱破解句子的空白:
(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)))
我使用visual-line-mode
并将我的默认段落填充M-q
替换为fill-sentences-in-paragraph
(global-set-key "\M-q" 'fill-sentences-in-paragraph)
。