• R/O
  • SSH

提交

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

修订版7d171c6a7406d25f4e732cb045f4b0400e5db988 (tree)
时间2010-12-02 01:10:40
作者lorenzo
Commiterlorenzo

Log Message

I added a file which should help emacs to deal with non-English spelling in
latex documents.

更改概述

差异

diff -r 80a9c830c244 -r 7d171c6a7406 emacs_files/flyspell-babel.el
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emacs_files/flyspell-babel.el Wed Dec 01 16:10:40 2010 +0000
@@ -0,0 +1,482 @@
1+;; flyspell-babel.el -- Switch flyspell language according to LaTeX
2+;; Babel commands
3+;;
4+;; Copyright (C) 2004 P J Heslin
5+;;
6+;; Author: Peter Heslin <p.j.heslin@dur.ac.uk>
7+;; URL: http://www.dur.ac.uk/p.j.heslin/Software/Emacs/Download/flyspell-babel.el
8+;; Version: 3.2
9+;;
10+;; This program is free software; you can redistribute it and/or modify
11+;; it under the terms of the GNU General Public License as published by
12+;; the Free Software Foundation; either version 2, or (at your option)
13+;; any later version.
14+;;
15+;; This program is distributed in the hope that it will be useful,
16+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+;; GNU General Public License for more details.
19+;;
20+;; If you do not have a copy of the GNU General Public License, you
21+;; can obtain one by writing to the Free Software Foundation, Inc., 59
22+;; Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23+
24+;;; Installation:
25+;;
26+;; Flyspell is an Emacs package that highlights misspelled words as
27+;; you type; Babel is the standard mechanism for switching languages
28+;; in LaTeX. There are a number of Emacs packages available that will
29+;; try to guess the current language of a buffer or part of a buffer,
30+;; and make flyspell switch to a different dictionary; but I didn't
31+;; find one that used the explicit language-switching commands
32+;; available in a LaTeX file for this purpose. This package makes
33+;; flyspell use the correct dictionary for the language used in each
34+;; part of a LaTeX file. There are some restrictions on the usage of
35+;; Babel commands, on which see below.
36+;;
37+;; flyspell-babel requires ispell-multi to be installed; it may be
38+;; found in the same directory indicated by the URL above. It also
39+;; needs flyspell to be installed (version 1.7f or better) and
40+;; flyspell-mode to be active. If you are using Emacs 21.3 or
41+;; earlier, you will need to upgrade to ispell.el version 3.6,
42+;; available from http://www.kdstevens.com/~stevens/ispell-page.html.
43+;;
44+;; To use this file, put it somewhere in your load-path, and add this
45+;; to your .emacs file:
46+;;
47+;; (autoload 'flyspell-babel-setup "flyspell-babel")
48+;; (add-hook 'latex-mode-hook 'flyspell-babel-setup)
49+;;
50+;; You will need to reload flyspell-babel.el if you install any new
51+;; ispell languages or language aliases.
52+;;
53+;; I have only tested this with GNU Emacs.
54+
55+;;; Commentary:
56+;;
57+;; This package examines the LaTeX code around point to discover the
58+;; language of the current text, and then it caches that value in a
59+;; text-property. This means that, if you modify or add a Babel
60+;; command to change the language of some text, the current language
61+;; may be out of sync with the cached value. In this case, you can
62+;; just stop typing for a bit, and the surrounding text will be
63+;; re-parsed, and the new, correct language should be determined. The
64+;; length of time that Emacs is idle before this re-parsing happens is
65+;; configurable via the variable flyspell-babel-delay (default is 5
66+;; seconds).
67+;;
68+;; The parsing done by this package has its limits limited, and so it
69+;; will not work with arbitrary LaTeX code. I hope that these
70+;; restrictions will not in practice impinge on the typical usage of
71+;; most people. The first language declaration is usually determined
72+;; by the final language option passed to the babel \usepackage
73+;; command, which takes effect after \begin{document}. Thereafter,
74+;; you can switch the declared language with \selectlanguage
75+;; statements, otherlanguage environments, and \foreignlanguage
76+;; commands. You can also define your own language-switching
77+;; commands, and register these with flyspell-babel.
78+;;
79+;; This package does not understand complex LaTeX constructs, such as
80+;; \input. If you want to set the default language for a particular
81+;; file (for example, one that has no Babel declaration, but is going
82+;; to be \input into a file that does), you can just put a redundant
83+;; \selectlanguage declaration at the start of the file. You can
84+;; limit the scope of a \selectlanguage declaration by putting an
85+;; opening brace immediately before it, and flyspell-babel will
86+;; respect that scoping, but not otherwise, since that would make the
87+;; task of parsing too complex.
88+;;
89+;; By default, an ispell dictionary is invoked with the same name as
90+;; the current Babel language or dialect, which works in many cases.
91+;; If your ispell has a different name for that language, you have two
92+;; options. You can make ispell recognize the Babel name by adding
93+;; symlinks under that name in your Ispell directory. Alternatively,
94+;; you can customize flyspell-babel-to-ispell-alist, which maps Babel
95+;; languages and dialects to Ispell language names. If you map a
96+;; language to 'nil, that means not to spell-check that language,
97+;; which can be useful for languages without an ispell dictionary.
98+
99+;;; Customization:
100+;;
101+;; The code that follows is an example of my customization of this
102+;; package. The first form tells the package to turn on debugging
103+;; messages to see when we switch dictionaries as we move from place
104+;; to place. The second tells it not to spell-check the languages
105+;; "latin" and "ibycus" (an encoding for ancient Greek), since I don't
106+;; have ispell dictionaries for them; it also tells it to translate
107+;; the Babel language "french" to the ispell dictionary "francais".
108+;; The third form defines some language-switching shortcut commands,
109+;; so that I can more easily say \fr{merci} and \itl{grazie}. The
110+;; fourth defines some short-cut environments, since \begin{german} is
111+;; a lot easier to write than \begin{otherlanguage}{german}. The last
112+;; form defines some shortcut declarations for switching between
113+;; American and British spelling.
114+;;
115+;; (setq flyspell-babel-verbose t)
116+;;
117+;; (setq flyspell-babel-to-ispell-alist
118+;; '(("latin" nil)
119+;; ("ibycus" nil)
120+;; ("french" "francais")))
121+;;
122+;; (setq flyspell-babel-command-alist
123+;; '(("lat" "latin")
124+;; ("gk" "ibycus")
125+;; ("fr" "french")
126+;; ("ger" "german")
127+;; ("itl" "italian")))
128+;;
129+;; (setq flyspell-babel-environment-alist
130+;; '(("latin" "latin")
131+;; ("greek" "ibycus")
132+;; ("french" "french")
133+;; ("german" "german")
134+;; ("italian" "italian")))
135+;;
136+;; (setq flyspell-babel-declaration-alist
137+;; '(("yank" "american")
138+;; ("brit" "british")))
139+;;
140+;; Here is the LaTeX code that defines these short-cuts:
141+;;
142+;; \usepackage[ibycus,latin,french,german,italian,british,american]{babel}
143+;;
144+;; \newcommand{\lat}[1]{\foreignlanguage{latin}{\emph{#1}}}
145+;; \newenvironment{latin}{\begin{otherlanguage}{latin}}{\end{otherlanguage}}
146+;;
147+;; \newcommand{\fr}[1]{\foreignlanguage{french}{\emph{#1}}}
148+;; \newenvironment{french}{\begin{otherlanguage}{french}}{\end{otherlanguage}}
149+;;
150+;; \newcommand{\ger}[1]{\foreignlanguage{german}{\emph{#1}}}
151+;; \newenvironment{german}{\begin{otherlanguage}{german}}{\end{otherlanguage}}
152+;;
153+;; \newcommand{\itl}[1]{\foreignlanguage{italian}{\emph{#1}}}
154+;; \newenvironment{italian}{\begin{otherlanguage}{italian}}{\end{otherlanguage}}
155+;;
156+;; \newcommand{\yank}{\selectlanguage{american}}
157+;; \newcommand{\brit}{\selectlanguage{british}}
158+
159+;;; Bugs:
160+;;
161+;; If a word comes to be erroneously highlighted as misspelled because
162+;; you have recently changed a Babel command, then the normal thing to
163+;; do is to wait a few seconds until the idle-timer runs the code to
164+;; re-parse the text. This works, except when the new Babel language
165+;; is mapped to 'nil, meaning that it shouldn't be spell-checked at
166+;; all. When this is the case, the spell-checking mechanism is
167+;; by-passed completely, so the erroneous highlighting will not be
168+;; removed, since those words will not be re-recognized as "correctly"
169+;; spelled. The best thing to do in this case is to switch
170+;; flyspell-mode off and on again, which will remove all flyspell
171+;; highlighting.
172+
173+;;; Changes
174+;;
175+;; 3.2 Made flyspell-babel-parse-block non-recursive to avoid blowing
176+;; max-lisp-eval-depth in long files
177+;; 3.1 Fixed bug when \usepackage[foo]{babel} was commented out
178+;; 3.0 Re-factored to use new ispell-multi.el.
179+;; 2.0 Major re-write. Instead of partially-parsing every time a word
180+;; is spell-checked, we now cache the language in a text property,
181+;; and use an idle timer to re-parse in case the language has
182+;; changed.
183+;; 1.3 Only use ispell-valid-dictionary-list if it's available
184+;; 1.2 Removed dependency on AUCTeX and newcomment and fixed bug when
185+;; disabling flyspell-large-region
186+;; 1.1 Removed error report when \usepackage{babel} not present
187+;; 1.0 Initial public release
188+
189+(require 'ispell-multi)
190+(require 'flyspell)
191+
192+(defgroup flyspell-babel nil
193+ "Switch flyspell language according to LaTeX babel commands"
194+ :tag "Switch flyspell language according to Babel commands"
195+ :group 'tex
196+ :prefix "flyspell-babel-")
197+
198+(defcustom flyspell-babel-to-ispell-alist ()
199+ "Maps LaTeX babel language or dialect names to ispell
200+ dictionaries"
201+ :type 'alist
202+ :group 'flyspell-babel)
203+
204+(defcustom flyspell-babel-declaration-alist ()
205+ "Maps LaTeX language-switching declarations (other than the
206+ built-in babel \\selectlanguage declaration) to babel
207+ languages"
208+ :type 'alist
209+ :group 'flyspell-babel)
210+
211+(defcustom flyspell-babel-environment-alist ()
212+ "Maps LaTeX language-switching environments (other than the
213+ built-in babel \"otherlanguage\" environment) to babel languages"
214+ :type 'alist
215+ :group 'flyspell-babel)
216+
217+(defcustom flyspell-babel-command-alist ()
218+ "Maps LaTeX language-switching commands (other than the
219+ built-in babel \\foreignlanguage command) to babel languages"
220+ :type 'alist
221+ :group 'flyspell-babel)
222+
223+(defcustom flyspell-babel-verbose nil
224+ "Whether routinely to report changing from one language to another"
225+ :type 'boolean
226+ :group 'flyspell-babel)
227+
228+(defcustom flyspell-babel-delay 5
229+ "Seconds of idleness before current Babel block is re-parsed."
230+ :type 'integer
231+ :group 'flyspell-babel)
232+
233+
234+(defvar flyspell-babel-declaration-alist-all nil)
235+(defvar flyspell-babel-decl-regexp nil)
236+(defvar flyspell-babel-environment-alist-all nil)
237+(defvar flyspell-babel-env-regexp nil)
238+(defvar flyspell-babel-command-alist-all nil)
239+(defvar flyspell-babel-com-regexp nil)
240+(defvar flyspell-babel-decl-env-com-regexp nil)
241+
242+(setq flyspell-babel-declaration-alist-all
243+ (append '(("selectlanguage" "selectlanguage"))
244+ flyspell-babel-declaration-alist))
245+
246+(setq flyspell-babel-decl-regexp
247+ (concat "\\\\begin[ \t\n]*{document}" "\\|"
248+ (mapconcat (lambda (pair) (concat "\\\\" (car pair) "[ \t\n{]"))
249+ flyspell-babel-declaration-alist-all "\\|")))
250+
251+(setq flyspell-babel-environment-alist-all
252+ (append '(("otherlanguage" "otherlanguage"))
253+ flyspell-babel-environment-alist))
254+
255+(setq flyspell-babel-env-regexp
256+ (mapconcat (lambda (pair) (concat "\\\\begin{" (car pair) "}"))
257+ flyspell-babel-environment-alist-all "\\|"))
258+
259+(setq flyspell-babel-command-alist-all
260+ (append '(("foreignlanguage" "foreignlanguage"))
261+ flyspell-babel-command-alist))
262+
263+(setq flyspell-babel-com-regexp
264+ (mapconcat (lambda (pair) (concat "\\\\" (car pair) "[ \t\n{]"))
265+ flyspell-babel-command-alist-all "\\|"))
266+
267+(setq flyspell-babel-decl-env-com-regexp
268+ (mapconcat 'identity (list flyspell-babel-decl-regexp
269+ flyspell-babel-env-regexp
270+ flyspell-babel-com-regexp) "\\|"))
271+
272+
273+(defun flyspell-babel-parse-buffer ()
274+ (save-excursion
275+ (goto-char (point-max))
276+ (flyspell-babel-parse)))
277+
278+(defun flyspell-babel-parse ()
279+ "Parse backward from point until containing element or bob is
280+found; then run forward and flag regions found."
281+ (let ((current-position (point))
282+ beg end lang macro-begin tag-list finished)
283+ (while (and (not finished)
284+ (not (input-pending-p))
285+ (flyspell-babel-find-previous-macro nil))
286+ ;; We standardize on having the language switch happening
287+ ;; just *after* regexp-match, since re-search-backward
288+ ;; will fail to match when we are in the middle of a macro.
289+ (setq beg (match-end 0))
290+ (setq macro-begin (point))
291+ (if (looking-at flyspell-babel-com-regexp)
292+ (flyspell-babel-check-com)
293+ (if (looking-at flyspell-babel-env-regexp)
294+ (flyspell-babel-check-env)
295+ (if (looking-at flyspell-babel-decl-regexp)
296+ (flyspell-babel-check-decl)
297+ (flyspell-babel-message "internal error 1"))))
298+ (setq end (point))
299+ (when (< current-position end)
300+ ;; Got it
301+ (setq finished t)
302+ ;; As an optimization, we flag the text after point
303+ ;; as far as the start of the next Babel command.
304+ (goto-char current-position)
305+ (when (and (flyspell-babel-find-next-macro end)
306+ (< current-position (point))
307+ (< (point) end))
308+ (setq end (1+ (point)))))
309+ (setq tag-list (cons (list beg end lang) tag-list))
310+ (goto-char macro-begin))
311+ ;; Background is default lang
312+ (setq tag-list (cons (list (point-min) current-position "no-command-found") tag-list))
313+ ;; We now run through in a forward direction
314+ (while tag-list
315+ (apply 'flyspell-babel-flag-region (car tag-list))
316+ (setq tag-list (cdr tag-list)))))
317+
318+
319+
320+(defun flyspell-babel-find-previous-macro (end)
321+ (let ((found))
322+ (while (and (not found)
323+ (re-search-backward flyspell-babel-decl-env-com-regexp end t))
324+ (setq found (not (flyspell-babel-in-comment-p))))
325+ found))
326+
327+(defun flyspell-babel-find-next-macro (end)
328+ (let ((found))
329+ (while (and (not found)
330+ (re-search-forward flyspell-babel-decl-env-com-regexp end t))
331+ (setq found (not (flyspell-babel-in-comment-p))))
332+ found))
333+
334+(defun flyspell-babel-check-com ()
335+ (if (re-search-forward
336+ "\\=\\\\foreignlanguage[ \t\n]*{\\([^}]+\\)}[ \t\n]*{" nil t)
337+ (setq lang (match-string 1))
338+ (if (re-search-forward "\\=\\\\\\([^{ \t\n]+\\)[ \t\n]*{" nil t)
339+ (setq lang (cadr
340+ (assoc (match-string 1)
341+ flyspell-babel-command-alist-all)))
342+ (flyspell-babel-message "internal error 2")))
343+ (backward-char)
344+ (flyspell-babel-forward-sexp))
345+
346+(defun flyspell-babel-check-env ()
347+ (let ((env))
348+ (if (looking-at "\\=\\\\begin{otherlanguage}[ \t\n]*{\\([^}]+\\)}")
349+ (setq env "otherlanguage" lang (match-string 1))
350+ (if (looking-at "\\=\\\\begin[ \t\n]*{\\([^}]+\\)}")
351+ (setq env (match-string 1)
352+ lang (cadr
353+ (assoc env flyspell-babel-environment-alist-all)))
354+ (flyspell-babel-message "internal error 3")))
355+ (flyspell-babel-find-matching-end env)
356+; (backward-char)))
357+ ))
358+
359+(defun flyspell-babel-check-decl ()
360+ (if (looking-at "\\\\begin[ \t\n]*{document}")
361+ (progn
362+ (if (save-excursion
363+ (re-search-backward
364+ ;; To exclude commented lines, only allow spaces before
365+ "^[ \t\n]*\\\\usepackage.*[[,]\\([^]]+\\)\\]{babel}" nil t))
366+ (setq lang (match-string 1))
367+ (setq lang "no-command-found"))
368+ (goto-char (point-max)))
369+ (if (looking-at "\\\\selectlanguage[ \t\n]*{\\([^}]+\\)}")
370+ (setq lang (match-string 1))
371+ (if (and (looking-at "\\\\\\([^{ \t\n]+\\)")
372+ (cadr (assoc (match-string 1)
373+ flyspell-babel-declaration-alist-all)))
374+ (setq lang
375+ (cadr (assoc (match-string 1)
376+ flyspell-babel-declaration-alist-all)))
377+ (flyspell-babel-message "internal error 4")))
378+ (unless (bobp)
379+ (backward-char))
380+ (if (looking-at "{")
381+ (flyspell-babel-forward-sexp)
382+ (goto-char (point-max)))))
383+
384+(defun flyspell-babel-flag-region (beg end lang)
385+ (let ((trans (assoc lang flyspell-babel-to-ispell-alist))
386+ (buffer-modified-before (buffer-modified-p))
387+ (after-change-functions nil))
388+ (when trans
389+ ;; We have a translation of a Babel language name to ispell
390+ ;; nomenclature
391+ (setq lang (cadr trans)))
392+ (cond
393+ ((not lang)
394+ ;; A parsed region with a nil dict -- don't spell-check.
395+ (setq lang "void"))
396+ ((equal lang "no-command-found")
397+ (setq lang "default"))
398+ ((and ispell-multi-valid-dictionary-list
399+ (not (member lang ispell-multi-valid-dictionary-list)))
400+ ;; A parsed region with an uninstalled dict
401+ (message "Flyspell-babel warning: no dictionary installed for %s" lang)
402+ (setq lang "void")))
403+ (put-text-property beg end 'ispell-multi-lang lang)
404+ (set-buffer-modified-p buffer-modified-before)))
405+
406+
407+(defun flyspell-babel-forward-sexp (&optional arg)
408+ "Makes sure to ignore comments when using forward-sexp, and
409+ trap errors for unbalanced braces."
410+ (interactive "p")
411+ (let ((parse-sexp-ignore-comments t))
412+ (condition-case nil
413+ (forward-sexp arg)
414+ (error (goto-char (point-max))))))
415+
416+(defun flyspell-babel-find-matching-end (env)
417+ "Find end of current environment, or end of file when there is
418+ no matching \end."
419+ (interactive)
420+ (let ((regexp (concat "\\\\\\(begin\\|end\\)[ \t\n]*{" env "}"))
421+ (level 0)
422+ (proceed t))
423+ (while proceed
424+ (if (re-search-forward regexp nil t)
425+ (let ((match (match-string 1)))
426+ (unless (flyspell-babel-in-comment-p)
427+ (if (string= match "begin")
428+ (setq level (1+ level))
429+ (if (string= match "end")
430+ (setq level (1- level))
431+ (flyspell-babel-message "internal error 5")))))
432+ (goto-char (point-max))
433+ (setq proceed nil))
434+ (when (= 0 level)
435+ (setq proceed nil)))))
436+
437+(defun flyspell-babel-in-comment-p ()
438+ "Are we in a Latex comment? (Stolen from auctex tex.el)"
439+ (save-match-data
440+ (if (or (bolp)
441+ (null comment-start-skip)
442+ (eq (preceding-char) ?\r))
443+ nil
444+ (save-excursion
445+ (let ((pos (point)))
446+ (re-search-backward "^\\|\r" nil t)
447+ (or (looking-at comment-start-skip)
448+ (re-search-forward comment-start-skip pos t)))))))
449+
450+(defun flyspell-babel-message (mess &optional force)
451+ (when (or flyspell-babel-verbose force)
452+ (message "Flyspell-babel -- %s" mess)))
453+
454+(defun flyspell-babel-start ()
455+ (flyspell-babel-parse-buffer)
456+ (setq ispell-multi-nil-callback 'flyspell-babel-parse)
457+ (make-local-variable 'flyspell-large-region)
458+ (setq flyspell-large-region 'nil)
459+ (flyspell-mode 1)
460+ (setq flyspell-generic-check-word-p 'ispell-multi-verify)
461+ (setq ispell-multi-idler-callback 'flyspell-babel-parse-buffer)
462+ (ispell-multi-idler-setup flyspell-babel-delay)
463+ (ispell-multi-hack-flyspell-modeline))
464+
465+(defun flyspell-babel-stop ()
466+; (ispell-multi-idler-cancel)
467+ (setq flyspell-generic-check-word-p nil)
468+ (ispell-multi-unhack-flyspell-modeline)
469+ (flyspell-mode -1))
470+
471+(define-minor-mode flyspell-babel-mode
472+ "Mode to make flyspell language selection obey LaTeX Babel commands" nil
473+ :group 'flyspell-babel
474+ (if flyspell-babel-mode
475+ (flyspell-babel-start)
476+ (flyspell-babel-stop)))
477+
478+(defun flyspell-babel-setup ()
479+ (flyspell-babel-mode 1))
480+
481+(provide 'flyspell-babel)
482+