Initial Commit
[packages] / xemacs-packages / ess / lisp / ess-latex.el
1 ;; ess-latex.el - Interface ESS and LaTeX.
2
3 ;; Copyright (C) 1999 by A.J. Rossini <rossini@biostat.washington.edu>
4 ;; based on noweb-mode by: Thorsten.Ohl @ Physik.TH-Darmstadt.de
5 ;;     with a little help from Norman Ramsey <norman@bellcore.com>
6 ;;                         and Mark Lunt <mark.lunt@mrc-bsu.cam.ac.uk>
7
8 ;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
9
10 ;; This file is part of ESS.
11
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16 ;; 
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;; GNU General Public License for more details.
21 ;; 
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with this program; if not, write to the Free Software
24 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 ;; 
26 ;; See bottom of this file for information on language-dependent
27 ;; highlighting, and recent changes.
28
29
30 \f
31 ;;; Variables
32
33 (defconst ess-latex-minor-mode-RCS-Id
34   "Imported to ESS Subversion repository and RCS ids not maintained.")
35
36 (defconst ess-latex-minor-mode-RCS-Name
37   " ")
38
39 (defvar ess-latex-minor-mode-prefix "\M-n"
40   "*Prefix key to use for noweb mode commands.
41 The value of this variable is checked as part of loading noweb mode.
42 After that, changing the prefix key requires manipulating keymaps.")
43
44 (defvar ess-latex-minor-mode-load-hook nil
45   "Hook that is run after noweb mode is loaded.")
46
47 (defvar ess-latex-mode-hook nil
48   "Hook that is run after entering ess-latex mode.")
49
50 (defvar ess-latex-select-code-mode-hook nil
51   "Hook that is run after the code mode is selected.
52 This is the place to overwrite keybindings of the ESS-LATEX-CODE-MODE.")
53
54 (defvar ess-latex-select-doc-mode-hook nil
55   "Hook that is run after the documentation mode is selected.
56 This is the place to overwrite keybindings of the ESS-LATEX-DOC-MODE.")
57
58 (defvar ess-latex-select-mode-hook nil
59   "Hook that is run after the documentation or the code mode is selected.
60 This is the place to overwrite keybindings of the other modes.")
61
62 (defvar ess-latex-changed-chunk-hook nil
63   "Hook that is run every time point moves from one chunk to another.
64 It will be run whether or not the major-mode changes.")
65
66 (defvar ess-latex-default-code-mode 'fundamental-mode
67   "Default major mode for editing code chunks.  
68 This is set to FUNDAMENTAL-MODE by default, but you might want to
69 change this in the Local Variables section of your file to something
70 more appropriate, like C-MODE, FORTRAN-MODE, or even
71 INDENTED-TEXT-MODE.")
72
73 (defvar ess-latex-code-mode 'c-mode
74   "Major mode for editing this particular code chunk. 
75 It defaults to ess-latex-default-code-mode, but can be reset by a comment
76 on the first line of the chunk containing the string 
77 \"-*- NEWMODE -*-\" or  
78 \"-*- NEWMODE-mode -*-\" or  
79 \"-*- mode: NEWMODE -*- \"  or
80 \"-*- mode: NEWMODE-mode -*- \" 
81 Option three is recommended, as it is the closest to standard emacs usage.") 
82
83 (defvar ess-latex-default-doc-mode 'latex-mode
84   "Major mode for editing documentation chunks.")
85
86 (defvar ess-latex-doc-mode-syntax-table nil
87   "A syntax-table syntax table that makes quoted code in doc chunks to behave.") 
88
89 (defvar ess-latex-last-chunk-index 0
90   "This keeps track of the chunk we have just been in. If this is not the same as the current chunk, we have to check if we need to change major mode.")
91
92 (defvar ess-latex-chunk-vector nil
93   "Vector of the chunks in this buffer.")
94
95 (defvar ess-latex-narrowing nil
96   "If not NIL, the display will always be narrowed to the
97 current chunk pair.")
98
99 (defvar ess-latex-electric-@-and-< t
100   "If not nil, the keys `@' and `<' will be bound to ESS-LATEX-ELECTRIC-@
101 and ESS-LATEX-ELECTRIC-<, respectively.")
102
103 (defvar ess-latex-use-mouse-navigation t
104   "If not nil, enables moving between chunks using mouse-1.
105 Clicking on the '<<' at the beginning of a chunk name takes you to the
106 previous occurence of that chunk name, clicking on the '>>' takes you
107 to the next.
108 Assumes mouse-1 is bound to mouse-set-point, so if you have rebound
109 mouse-1, this will override your binding.")
110
111\f
112 ; (defvar ess-latex-weave-options "-delay")
113 ; (defvar ess-latex-latex-viewer "xdvi")
114 ; (defvar ess-latex-html-viewer "netscape")
115
116 ; (defun ess-latex-weave (&optional name)
117 ;   (interactive)
118 ;   (let ((buffer (get-buffer-create "Weave Buffer")))
119 ;     (if (not name)
120 ;       (progn
121 ;       ;; Assume latex documentation, but set to html if appropriate
122 ;       (if (eq ess-latex-doc-mode html-mode)
123 ;           (setq name (concat (substring (buffer-file-name) 0 
124 ;                                         (string-match ".nw" name))
125 ;                              ".html"))
126 ;         (setq name (concat (substring (buffer-file-name) 0 
127 ;                                           (string-match ".nw" name))
128 ;                                ".tex")))))
129 ;     (setq name (concat "> " name))
130 ;     (setq ess-latex-weave-options (concat ess-latex-weave-options name))
131 ;     (start-process weave-process buffer "noweave" ess-latex-weave-options)))
132
133 ; (defun ess-latex-view  ())
134 \f
135 ;;; Setup
136 (defvar ess-latex-mode nil
137   "Buffer local variable, T iff this buffer is edited in ess-latex mode.")
138
139 ;; For some reason that I do not understand, `newline' does not do the
140 ;; right thing in quoted code. If point is not preceded by whitespace,
141 ;; it moves to the beginning of the current line, not the beginning of
142 ;; the new line. `newline 1' works fine, hence the kludge. I'd love to
143 ;; understand what's going on, though. Try running M-x newline in the
144 ;; middle of a code quote in a doc chunk to see
145 ;; what I mean: its odd.
146
147 (defun ess-latex-newline (&optional arg) 
148   "A kludge to get round very odd behaviour of newline in quoted code."
149   (interactive "p")
150   (if arg (newline arg) (newline 1)))
151
152 (defvar ess-latex-mode-prefix-map 
153   (let ((map (make-sparse-keymap)))
154     (define-key map "\C-n" 'ess-latex-next-chunk)
155     (define-key map "\C-p" 'ess-latex-previous-chunk)
156     (define-key map "\M-n" 'ess-latex-goto-next)
157     (define-key map "\M-m" 'ess-latex-insert-default-mode-line)
158     (define-key map "\M-p" 'ess-latex-goto-previous)
159     (define-key map "c" 'ess-latex-next-code-chunk)
160     (define-key map "C" 'ess-latex-previous-code-chunk)
161     (define-key map "d" 'ess-latex-next-doc-chunk)
162     (define-key map "D" 'ess-latex-previous-doc-chunk)
163     (define-key map "g" 'ess-latex-goto-chunk)
164     (define-key map "\C-l" 'ess-latex-update-chunk-vector)
165     (define-key map "\M-l" 'ess-latex-update-chunk-vector)
166     (define-key map "w" 'ess-latex-copy-chunk-as-kill)
167     (define-key map "W" 'ess-latex-copy-chunk-pair-as-kill)
168     (define-key map "k" 'ess-latex-kill-chunk)
169     (define-key map "K" 'ess-latex-kill-chunk-pair)
170     (define-key map "m" 'ess-latex-mark-chunk)
171     (define-key map "M" 'ess-latex-mark-chunk-pair)
172     (define-key map "n" 'ess-latex-narrow-to-chunk)
173     (define-key map "N" 'ess-latex-narrow-to-chunk-pair)
174     (define-key map "t" 'ess-latex-toggle-narrowing)
175     (define-key map "\t" 'ess-latex-complete-chunk)
176     (define-key map "q" 'ess-latex-fill-chunk)
177     (define-key map "i" 'ess-latex-new-chunk)
178     (define-key map "o" 'ess-latex-occur)
179     (define-key map "v" 'ess-latex-mode-version)
180     (define-key map "h" 'ess-latex-describe-mode)
181     (define-key map "\C-h" 'ess-latex-describe-mode)
182     map)
183   "ess-latex minor-mode prefix keymap")
184
185 (defvar ess-latex-minor-mode-map 
186   (let ((map (make-sparse-keymap)))
187     (if ess-latex-electric-@-and-<
188         (progn
189           (define-key map "@" 'ess-latex-electric-@)
190           (define-key map "<" 'ess-latex-electric-<)))
191     (define-key map "\M-q" 'ess-latex-fill-paragraph-chunk)
192     (define-key map [tab] 'ess-latex-indent-line)
193     (define-key map [return] 'ess-latex-newline)
194     (define-key map [mouse-1] 'ess-latex-mouse-first-button)
195     (define-key map ess-latex-mode-prefix ess-latex-mode-prefix-map)
196     map)
197   "Ess-Latex minor mode keymap")
198
199 (easy-menu-define 
200  ess-latex-minor-mode-menu ess-latex-minor-mode-map "Menu keymap for ess-latex."
201  '("Ess-Latex"
202    ("Movement"
203     ["Previous chunk" ess-latex-previous-chunk t]
204     ["Next chunk" ess-latex-next-chunk t]
205     ["Previous chunk of same name" ess-latex-goto-previous t]
206     ["Next chunk of same name" ess-latex-goto-next t]
207     ["Goto chunk" ess-latex-goto-chunk t]
208     ["Previous code chunk" ess-latex-previous-code-chunk t]
209     ["Next code chunk" ess-latex-next-code-chunk t]
210     ["Previous documentation chunk" ess-latex-previous-doc-chunk t]
211     ["Next documentation chunk" ess-latex-next-doc-chunk t])
212    ("Editing"
213     ["Copy chunk" ess-latex-copy-chunk-as-kill t]
214     ["Copy chunk pair" ess-latex-copy-chunk-pair-as-kill t]
215     ["Kill chunk" ess-latex-kill-chunk t]
216     ["Kill chunk pair" ess-latex-kill-chunk-pair t]
217     ["Mark chunk" ess-latex-mark-chunk t]
218     ["Mark chunk pair" ess-latex-mark-chunk-pair t])
219    ("Narrowing"
220     ["Narrow to chunk" ess-latex-narrow-to-chunk t]
221     ["Narrow to chunk pair" ess-latex-narrow-to-chunk-pair t]
222     ["Toggle auto narrowing" ess-latex-toggle-narrowing t]
223     ["Widen" widen t])
224    ("Modes"
225     ["Set documentation mode" ess-latex-set-doc-mode t]
226     ["Set default code mode" ess-latex-set-code-mode t]
227     ["Set code mode for this chunk" ess-latex-set-this-code-mode t]
228     ["Insert default mode line" ess-latex-insert-default-mode-line t])
229    ("Tangling"
230     ["Tangle current chunk" ess-latex-tangle-chunk t]
231     ["Tangle current thread" ess-latex-tangle-current-thread t]
232     ["Tangle named thread" ess-latex-tangle-thread t])
233    ("Miscellaneous"
234     ["Complete chunk name" ess-latex-complete-chunk t]
235     ["Fill current chunk" ess-latex-fill-chunk t]
236     ["Insert new chunk" ess-latex-new-chunk t]
237     ["Update the chunk vector" ess-latex-update-chunk-vector t]
238     ["Chunk occurrences" ess-latex-occur t])
239    "--"
240    ["Help" ess-latex-describe-mode t]
241    ["Version" ess-latex-mode-version t]))
242
243 ;; Add ess-latex-mode to the list of minor modes  
244 (if (not (assq 'ess-latex-mode minor-mode-alist))
245     (setq minor-mode-alist (append minor-mode-alist
246                                    (list '(ess-latex-mode " Ess-Latex")))))
247 ;; Add ess-latex-minor-mode-map to the list of minor-mode keymaps
248 ;; available. Then, whenever ess-latex-mode is activated, the keymap is
249 ;; automatically activated
250 (if (not (assq 'ess-latex-mode minor-mode-map-alist))
251     (setq minor-mode-map-alist 
252           (cons (cons 'ess-latex-mode ess-latex-minor-mode-map)
253                 minor-mode-map-alist)))
254
255 (defun ess-latex-minor-mode (&optional arg)
256   "Minor meta mode for editing ess-latex files. See ESS-LATEX-MODE."
257   (interactive)
258   (ess-latex-minor-mode arg))
259
260 (defun ess-latex-mode ( &optional arg )
261   "Minor meta mode for editing ess-latex files.
262 `Meta' refers to the fact that this minor mode is switching major
263 modes depending on the location of point.
264
265 The following special keystrokes are available in ess-latex mode:
266
267 Movement:
268 \\[ess-latex-next-chunk] \tgoto the next chunk
269 \\[ess-latex-previous-chunk] \tgoto the previous chunk
270 \\[ess-latex-goto-previous] \tgoto the previous chunk of the same name
271 \\[ess-latex-goto-next] \tgoto the next chunk of the same name
272 \\[ess-latex-goto-chunk] \t\tgoto a chunk
273 \\[ess-latex-next-code-chunk] \t\tgoto the next code chunk
274 \\[ess-latex-previous-code-chunk] \t\tgoto the previous code chunk
275 \\[ess-latex-next-doc-chunk] \t\tgoto the next documentation chunk
276 \\[ess-latex-previous-doc-chunk] \t\tgoto the previous documentation chunk
277
278 Copying/Killing/Marking/Narrowing:
279 \\[ess-latex-copy-chunk-as-kill] \t\tcopy the chunk the point is in into the kill ring
280 \\[ess-latex-copy-chunk-pair-as-kill] \t\tcopy the pair of doc/code chunks the point is in
281 \\[ess-latex-kill-chunk] \t\tkill the chunk the point is in
282 \\[ess-latex-kill-chunk-pair] \t\tkill the pair of doc/code chunks the point is in
283 \\[ess-latex-mark-chunk] \t\tmark the chunk the point is in
284 \\[ess-latex-mark-chunk-pair] \t\tmark the pair of doc/code chunks the point is in
285 \\[ess-latex-narrow-to-chunk] \t\tnarrow to the chunk the point is in
286 \\[ess-latex-narrow-to-chunk-pair] \t\tnarrow to the pair of doc/code chunks the point is in
287 \\[widen] \twiden
288 \\[ess-latex-toggle-narrowing] \t\ttoggle auto narrowing
289
290 Filling and Indenting:
291 \\[ess-latex-fill-chunk] \tfill (or indent) the chunk at point according to mode
292 \\[ess-latex-fill-paragraph-chunk] \tfill the paragraph at point, restricted to chunk
293 \\[ess-latex-indent-line] \tindent the line at point according to mode
294
295 Insertion:
296 \\[ess-latex-insert-default-mode-line] \tinsert a line to set this file's code mode
297 \\[ess-latex-new-chunk] \t\tinsert a new chunk at point
298 \\[ess-latex-complete-chunk] \tcomplete the chunk name before point
299 \\[ess-latex-electric-@] \t\tinsert a `@' or start a new doc chunk
300 \\[ess-latex-electric-<] \t\tinsert a `<' or start a new code chunk
301
302 Modes:
303 \\[ess-latex-set-doc-mode] \t\tset the major mode for editing doc chunks
304 \\[ess-latex-set-code-mode] \tset the major mode for editing code chunks
305 \\[ess-latex-set-this-code-mode] \tset the major mode for editing this code chunk
306
307 Misc:
308 \\[ess-latex-occur] \t\tfind all occurrences of the current chunk
309 \\[ess-latex-update-chunk-vector] \tupdate the markers for chunks
310 \\[ess-latex-describe-mode] \tdescribe ess-latex-mode
311 \\[ess-latex-mode-version] \t\tshow ess-latex-mode's version in the minibuffer
312 "  (interactive "P")
313 ; This bit is tricky: copied almost verbatim from bib-cite-mode.el
314 ; It seems to ensure that the variable ess-latex-mode is made
315 ; local to this buffer. It then sets ess-latex-mode to `t' if 
316 ;     1) It was called with an argument greater than 0
317 ; or  2) It was called with no argument, and ess-latex-mode is
318 ;        currently nil
319 ; ess-latex-mode is nil if the argument was <= 0 or there
320 ; was no argument and ess-latex-mode is currently `t'
321   (set (make-local-variable 'ess-latex-mode)
322        (if arg
323            (> (prefix-numeric-value arg) 0)
324          (not ess-latex-mode)))
325 ; Now, if ess-latex-mode is true, we want to turn
326 ; ess-latex-mode on
327   (cond 
328    (ess-latex-mode                 ;Setup the minor-mode
329     (mapcar 'ess-latex-make-variable-permanent-local
330             '(ess-latex-mode
331               after-change-functions
332               ess-latex-narrowing
333               ess-latex-chunk-vector
334               post-command-hook
335               isearch-mode-hook
336               isearch-mode-end-hook
337               ess-latex-doc-mode
338               ess-latex-code-mode
339               ess-latex-default-code-mode
340               ess-latex-last-chunk-index))
341     (ess-latex-update-chunk-vector)
342     (if (equal 0 (ess-latex-find-chunk-index-buffer))
343         (setq ess-latex-last-chunk-index 1)
344       (setq ess-latex-last-chunk-index 0))
345     (if font-lock-mode 
346         (progn
347           (font-lock-mode -1)
348           (ess-latex-font-lock-mode 1)))
349     (add-hook 'post-command-hook 'ess-latex-post-command-function)
350     (add-hook 'after-change-functions 'ess-latex-after-change-function)
351     (add-hook 'ess-latex-select-doc-mode-hook 'ess-latex-auto-fill-doc-mode)
352     (add-hook 'ess-latex-select-code-mode-hook 'ess-latex-auto-fill-code-mode)
353     (add-hook 'isearch-mode-hook 'ess-latex-note-isearch-mode)
354     (add-hook 'isearch-mode-end-hook 'ess-latex-note-isearch-mode-end)
355     (setq ess-latex-doc-mode-syntax-table nil)
356     (run-hooks 'ess-latex-mode-hook)
357     (message 
358      "ess-latex mode: use `M-x ess-latex-describe-mode' for further information"))
359    ;; If we didn't do the above, then we want to turn ess-latex-mode
360    ;; off, no matter what (hence the condition `t')
361    (t
362     (remove-hook 'post-command-hook 'ess-latex-post-command-function)
363     (remove-hook 'after-change-functions 'ess-latex-after-change-function)
364     (remove-hook 'ess-latex-select-doc-mode-hook 'ess-latex-auto-fill-doc-mode)
365     (remove-hook 'ess-latex-select-code-mode-hook 'ess-latex-auto-fill-code-mode)
366     (remove-hook 'isearch-mode-hook 'ess-latex-note-isearch-mode)
367     (remove-hook 'isearch-mode-end-hook 'ess-latex-note-isearch-mode-end)
368     (if ess-latex-font-lock-mode 
369         (progn
370           (ess-latex-font-lock-mode -1)
371           (message "Ess-Latex and Ess-Latex-Font-Lock Modes Removed"))
372       (message "Ess-Latex mode removed")))))
373
374 (defun ess-latex-make-variable-permanent-local (var)
375   "Declare VAR buffer local, but protect it from beeing killed
376 by major mode changes."
377   (make-variable-buffer-local var)
378   (put var 'permanent-local 't))
379
380 (defun ess-latex-note-isearch-mode ()
381   "Take note of an incremental search in progress"
382   (remove-hook 'post-command-hook 'ess-latex-post-command-function))
383
384 (defun ess-latex-note-isearch-mode-end ()
385   "Take note of an incremental search having ended"
386   (add-hook 'post-command-hook 'ess-latex-post-command-function))
387
388 (defun ess-latex-post-command-function ()
389   "The hook being run after each command in ess-latex mode."
390   (ess-latex-select-mode))
391
392 (defun ess-latex-after-change-function (begin end length)
393   "Function to run after every change in a ess-latex buffer.
394 If the changed region contains a chunk start (^@ or ^<<), it will
395 update the chunk vector"
396   (save-excursion
397     (goto-char begin)
398     (if (re-search-forward "^\\(@[^@]\\)\\|\\(<<\\)" end t)
399       (ess-latex-update-chunk-vector))))
400
401 \f
402 ;;; Chunks
403
404 (defun ess-latex-update-chunk-vector ()
405   "Scan the whole buffer and place a marker at each \"^@\" and \"^<<\".
406 Record them in ESS-LATEX-CHUNK-VECTOR."
407   (interactive)
408   (save-excursion
409     (goto-char (point-min))
410     (let ((chunk-list (list (cons 'doc (point-marker)))))
411       (while (re-search-forward "^\\(@\\( \\|$\\|\\( %def\\)\\)\\|<<\\(.*\\)>>=\\)" nil t)
412         (goto-char (match-beginning 0))
413         ;; If the 3rd subexpression matched @ %def, we're still in a code
414         ;; chunk (sort of), so don't place a marker here.
415         (if (not (match-beginning 3))
416             (setq chunk-list
417                   ;; If the 4th subexpression matched inside <<...>>,
418                   ;; we're seeing a new code chunk.
419                   (cons (cons (if (match-beginning 4)
420                                   ;;buffer-substring-no-properties better
421                                   ;;than buffer-substring if highlighting
422                                   ;;may be used
423                                   (buffer-substring-no-properties 
424                                    (match-beginning 4) (match-end 4))
425                                 'doc)
426                               (point-marker))
427                         chunk-list))
428           ;; Scan forward either to !/^@ %def/, which will start a docs chunk,
429           ;; or to /^<<.*>>=$/, which will start a code chunk.
430           (progn
431             (next-line 1)
432             (while (looking-at "@ %def")
433               (next-line 1))
434             (setq chunk-list
435                   ;; Now we can tell code vs docs
436                   (cons (cons (if (looking-at "<<\\(.*\\)>>=")
437                                   (buffer-substring-no-properties
438                                    (match-beginning 1) (match-end 1)) 
439                                 'doc)
440                               (point-marker))
441                         chunk-list))))
442         (next-line 1))
443       (setq chunk-list (cons (cons 'doc (point-max-marker)) chunk-list))
444       (setq ess-latex-chunk-vector (vconcat (reverse chunk-list))))))
445
446 (defun ess-latex-find-chunk ()
447   "Return a pair consisting of the name (or 'DOC) and the
448 marker of the current chunk."
449   (if (not ess-latex-chunk-vector)
450       (ess-latex-update-chunk-vector))
451   (aref ess-latex-chunk-vector (ess-latex-find-chunk-index-buffer)))
452
453 (defun ess-latex-chunk-is-code (index)
454   "Return t if the chunk 'index' is a code chunk, nil otherwise"
455   (interactive)
456   (stringp (car (ess-latex-chunk-vector-aref index))))
457
458 (defun ess-latex-in-code-chunk ()
459   "Return t if we are in a code chunk, nil otherwise."
460   (interactive)
461   (ess-latex-chunk-is-code (ess-latex-find-chunk-index-buffer)))
462
463 (defun ess-latex-in-mode-line ()
464   "Return the name of the mode to use if we are in a mode line, nil
465 otherwise." 
466   (interactive)
467   (let (beg end mode)
468     (save-excursion  
469       (beginning-of-line 1)                                                 
470       (and (search-forward "-*-"
471                            (save-excursion (end-of-line) (point))           
472                            t)
473            (progn                                                           
474              (skip-chars-forward " \t")                                     
475              (setq beg (point))                                             
476              (search-forward "-*-"                                          
477                              (save-excursion (end-of-line) (point))         
478                              t))
479            (progn               
480              (forward-char -3)                                              
481              (skip-chars-backward " \t")                                    
482              (setq end (point))                                             
483              (goto-char beg)                                                
484              (setq mode (concat                                            
485                          (downcase (buffer-substring beg end))             
486                          "-mode"))
487              (if ;(and 
488                  (>= (length mode) 11)
489                       (progn
490                         (if
491                             (equal (substring mode -10 -5) "-mode")
492                             (setq mode (substring mode 0 -5)))
493                         (if 
494                             (equal (substring mode 0 5) "mode:")
495                             (setq mode (substring mode 6)))))
496              (intern mode))))))
497
498 (defun ess-latex-find-chunk-index-buffer ()
499   "Return the index of the current chunk in ESS-LATEX-CHUNK-VECTOR."
500   (ess-latex-find-chunk-index 0 (1- (length ess-latex-chunk-vector))))
501
502 (defun ess-latex-find-chunk-index (low hi)
503   (if (= hi (1+ low))
504       low
505     (let ((med (/ (+ low hi) 2)))
506       (if (< (point) (cdr (aref ess-latex-chunk-vector med)))
507           (ess-latex-find-chunk-index low med)
508         (ess-latex-find-chunk-index med hi)))))
509
510 (defun ess-latex-chunk-region ()
511   "Return a pair consisting of the beginning and end of the current chunk."
512   (interactive)
513   (let ((start (ess-latex-find-chunk-index-buffer)))
514     (cons (marker-position (cdr (aref ess-latex-chunk-vector start)))
515           (marker-position (cdr (aref ess-latex-chunk-vector (1+ start)))))))
516
517 (defun ess-latex-copy-code-chunk ()
518   "Copy the current code chunk to the kill ring, excluding the chunk name.
519 This will be particularly useful when interfacing with ESS."
520   (interactive)
521   (let ((r (ess-latex-chunk-region)))
522     (save-excursion
523       (goto-char (car r))
524       (if (ess-latex-in-code-chunk)
525           (progn
526             (beginning-of-line 2)
527             (copy-region-as-kill (point) (cdr r)))))))
528
529 (defun ess-latex-extract-code-chunk ()
530   "Create a new buffer with the same name as the current code chunk,
531 and copy all code  from chunks of the same name to it."
532   (interactive)
533   (save-excursion 
534     (if (ess-latex-in-code-chunk)
535         (progn
536           (let ((chunk-name (car (ess-latex-find-chunk))) 
537                 (chunk-counter 0)
538                 (copy-counter 0)
539                 (this-chunk) (oldbuf (current-buffer))) 
540             (if (get-buffer chunk-name)
541                 (progn
542                   (set-buffer-modified-p nil)
543                   (kill-buffer chunk-name)))
544             (get-buffer-create chunk-name)
545             (message "Created buffer %s" chunk-name)
546             (while (< chunk-counter (- (length ess-latex-chunk-vector) 2))
547               (setq this-chunk (ess-latex-chunk-vector-aref
548                                 chunk-counter))
549               (message "Current buffer is %s" (car this-chunk))
550               (if (equal chunk-name (car this-chunk))
551                   (progn
552                     (setq copy-counter (+ copy-counter 1))
553                     (goto-char (cdr this-chunk))
554                     (ess-latex-copy-code-chunk)
555                     (set-buffer chunk-name)
556                     (goto-char (point-max))
557                     (yank)
558                     (set-buffer oldbuf)))
559               (setq chunk-counter (+ chunk-counter 1)))
560             (message "Copied %d bits" copy-counter)
561             (set-buffer chunk-name)
562             (copy-region-as-kill (point-min)(point-max)))))))
563
564 (defun ess-latex-chunk-pair-region ()
565   "Return a pair consisting of the beginning and end of the current pair of
566 documentation and code chunks."
567   (interactive)
568   (let* ((start (ess-latex-find-chunk-index-buffer))
569          (end (1+ start)))
570     (if (ess-latex-chunk-is-code start)
571         (cons (marker-position (cdr (aref ess-latex-chunk-vector (1- start))))
572               (marker-position (cdr (aref ess-latex-chunk-vector end))))
573       (while (not (ess-latex-chunk-is-code  end))
574         (setq end (1+ end)))
575       (cons (marker-position (cdr (aref ess-latex-chunk-vector start)))
576             (marker-position (cdr (aref ess-latex-chunk-vector (1+ end))))))))
577
578 (defun ess-latex-chunk-vector-aref (i)
579   (if (< i 0)
580       (error "Before first chunk."))
581   (if (>= i (length ess-latex-chunk-vector))
582       (error "Beyond last chunk."))
583   (aref ess-latex-chunk-vector i))
584
585 (defun ess-latex-complete-chunk ()
586   "Complete the chunk name before point, if any."
587   (interactive)
588   (if (ess-latex-in-code-chunk)
589       (let ((end (point))
590       (beg (save-excursion
591             (if (re-search-backward "<<"
592                    (save-excursion
593                                              (beginning-of-line)
594                                              (point))
595                                            t)
596                        (match-end 0)
597                      nil))))
598         (if beg
599             (let* ((pattern (buffer-substring beg end))
600                    (alist (ess-latex-build-chunk-alist))
601                    (completion (try-completion pattern alist)))
602               (cond ((eq completion t))
603                     ((null completion)
604                      (message "Can't find completion for \"%s\"" pattern)
605                      (ding))
606                     ((not (string= pattern completion))
607                      (delete-region beg end)
608                      (insert completion)
609                      (if (not (looking-at ">>"))
610                          (insert ">>")))
611                     (t
612                      (message "Making completion list...")
613                      (with-output-to-temp-buffer "*Completions*"
614                        (display-completion-list (all-completions pattern alist)))
615                      (message "Making completion list...%s" "done"))))
616           (message "Not at chunk name...")))
617     (message "Not in code chunk...")))
618
619 \f
620 ;;; Filling, etc
621
622 (defun ess-latex-hide-code-quotes ()
623   "Replace all non blank characters in [[...]] code quotes
624 in the current buffer (you might want to narrow to the interesting
625 region first) by `*'.  Return a list of pairs with the position and
626 value of the original strings." 
627   (save-excursion
628     (let ((quote-list nil))
629       (goto-char (point-min))
630       (while (re-search-forward "\\[\\[" nil 'move)
631         (let ((beg (match-end 0))
632               (end (if (re-search-forward "\\]\\]" nil t)
633                        (match-beginning 0)
634                      (point-max))))
635           (goto-char beg)
636           (while (< (point) end)
637             ;; Move on to the next word:
638             (let ((b (progn
639                        (skip-chars-forward " \t\n" end)
640                        (point)))
641                   (e (progn
642                        (skip-chars-forward "^ \t\n" end)
643                        (point))))
644               (if (> e b)
645                   ;; Save the string and a marker to the end of the 
646                   ;; replacement text.  A marker to the beginning is
647                   ;; useless.  See ESS-LATEX-RESTORE-CODE-QUOTES.
648                   (save-excursion
649                     (setq quote-list (cons (cons (copy-marker e)
650                                                  (buffer-substring b e))
651                                            quote-list))
652                     (goto-char b)
653                     (insert-char ?* (- e b) t)
654                     (delete-char (- e b))))))))
655       (reverse quote-list))))
656
657 (defun ess-latex-restore-code-quotes (quote-list)
658   "Reinsert the strings modified by `ess-latex-hide-code-quotes'."
659   (save-excursion
660     (mapcar '(lambda (q)
661                (let* ((e (marker-position (car q)))
662                       ;; Slightly inefficient, but correct way to find
663                       ;; the beginning of the word to be replaced.
664                       ;; Using the marker at the beginning will loose
665                       ;; if whitespace has been rearranged
666                       (b (save-excursion
667                            (goto-char e)
668                            (skip-chars-backward "*")
669                            (point))))
670                  (delete-region b e)
671                  (goto-char b)
672                  (insert (cdr q))))
673             quote-list)))
674
675 (defun ess-latex-fill-chunk ()
676   "Fill the current chunk according to mode.
677 Run `fill-region' on documentation chunks and `indent-region' on code
678 chunks."
679   (interactive)
680   (save-excursion
681     (save-restriction
682       (ess-latex-narrow-to-chunk)
683       (if (ess-latex-in-code-chunk)
684           (progn
685             ;; Narrow to the code section proper; w/o the first and any
686             ;; index declaration lines.
687             (narrow-to-region (progn
688                                 (goto-char (point-min))
689                                 (forward-line 1)
690                                 (point))
691                               (progn
692                                 (goto-char (point-max))
693                                 (forward-line -1)
694                                 (while (looking-at "@")
695                                   (forward-line -1))
696                                 (forward-line 1)
697                                 (point)))
698             (if (or indent-region-function indent-line-function)
699                 (indent-region (point-min) (point-max) nil)
700               (error "No indentation functions defined in %s!" major-mode)))
701         (let ((quote-list (ess-latex-hide-code-quotes)))
702           (fill-region (point-min) (point-max))
703           (ess-latex-restore-code-quotes quote-list))))))
704
705 (defun ess-latex-indent-line ()
706   "Indent the current line according to mode, after narrowing to this chunk."
707   (interactive)
708   (save-restriction
709     (ess-latex-narrow-to-chunk)
710     (if (stringp (car (ess-latex-find-chunk)))
711         (progn
712           ;; Narrow to the code section proper; w/o the first and any
713           ;; index declaration lines.
714           (save-excursion
715             (narrow-to-region (progn
716                                 (goto-char (point-min))
717                                 (forward-line 1)
718                                 (point))
719                               (progn
720                                 (goto-char (point-max))
721                                 (forward-line -1)
722                                 (while (looking-at "@")
723                                   (forward-line -1))
724                                 (forward-line 1)
725                                 (point))))))
726       (indent-according-to-mode)))
727
728 (defun ess-latex-fill-paragraph-chunk (&optional justify)
729   "Fill a paragraph in the current chunk."
730   (interactive "P")
731   (ess-latex-update-chunk-vector)
732   (save-restriction
733     (save-excursion
734       (ess-latex-narrow-to-chunk)
735       (if (stringp (car (ess-latex-find-chunk)))
736           (progn
737             ;; Narrow to the code section proper; w/o the first and any
738             ;; index declaration lines.
739             (narrow-to-region (progn
740                                 (goto-char (point-min))
741                                 (forward-line 1)
742                                 (point))
743                               (progn
744                                 (goto-char (point-max))
745                                 (forward-line -1)
746                                 (while (looking-at "@")
747                                   (forward-line -1))
748                                 (forward-line 1)
749                                 (point)))
750             (fill-paragraph justify))
751         (let ((quote-list (ess-latex-hide-code-quotes)))
752           (fill-paragraph justify)
753           (ess-latex-restore-code-quotes quote-list))))))
754
755 (defun ess-latex-auto-fill-doc-chunk ()
756   "Replacement for `do-auto-fill'."
757   (save-restriction
758     (narrow-to-region (car (ess-latex-chunk-region))
759                       (save-excursion
760                         (end-of-line)
761                         (point)))
762     (let ((quote-list (ess-latex-hide-code-quotes)))
763       (do-auto-fill)
764       (ess-latex-restore-code-quotes quote-list))))
765
766 (defun ess-latex-auto-fill-doc-mode ()
767   "Install the improved auto fill function, iff necessary."
768   (if auto-fill-function
769       (setq auto-fill-function 'ess-latex-auto-fill-doc-chunk)))
770
771 (defun ess-latex-auto-fill-code-mode ()
772   "Install the default auto fill function, iff necessary."
773   (if auto-fill-function
774       (setq auto-fill-function 'do-auto-fill)))
775 \f
776 ;;; Marking
777
778 (defun ess-latex-mark-chunk ()
779   "Mark the current chunk."
780   (interactive)
781   (let ((r (ess-latex-chunk-region)))
782     (goto-char (car r))
783     (push-mark (cdr r) nil t)))
784
785 (defun ess-latex-mark-chunk-pair ()
786   "Mark the current pair of documentation and code chunks."
787   (interactive)
788   (let ((r (ess-latex-chunk-pair-region)))
789     (goto-char (car r))
790     (push-mark (cdr r) nil t)))
791
792 \f
793 ;;; Narrowing
794
795 (defun ess-latex-toggle-narrowing (&optional arg)
796   "Toggle if we should narrow the display to the current pair of
797 documentation and code chunks after each movement.  With argument:
798 switch narrowing on."
799   (interactive "P")
800   (if (or arg (not ess-latex-narrowing))
801       (progn
802         (setq ess-latex-narrowing t)
803         (ess-latex-narrow-to-chunk-pair))
804     (setq ess-latex-narrowing nil)
805     (widen)))
806
807 (defun ess-latex-narrow-to-chunk ()
808   "Narrow the display to the current chunk."
809   (interactive)
810   (let ((r (ess-latex-chunk-region)))
811     (narrow-to-region (car r) (cdr r))))
812
813 (defun ess-latex-narrow-to-chunk-pair ()
814   "Narrow the display to the current pair of documentation and code chunks."
815   (interactive)
816   (let ((r (ess-latex-chunk-pair-region)))
817     (narrow-to-region (car r) (cdr r))))
818
819 \f
820 ;;; Killing
821
822 (defun ess-latex-kill-chunk ()
823   "Kill the current chunk."
824   (interactive)
825   (let ((r (ess-latex-chunk-region)))
826     (kill-region (car r) (cdr r))))
827
828 (defun ess-latex-kill-chunk-pair ()
829   "Kill the current pair of chunks."
830   (interactive)
831   (let ((r (ess-latex-chunk-pair-region)))
832     (kill-region (car r) (cdr r))))
833
834 (defun ess-latex-copy-chunk-as-kill ()
835   "Place the current chunk on the kill ring."
836   (interactive)
837   (let ((r (ess-latex-chunk-region)))
838     (copy-region-as-kill (car r) (cdr r))))
839
840 (defun ess-latex-copy-chunk-pair-as-kill ()
841   "Place the current pair of chunks on the kill ring."
842   (interactive)
843   (let ((r (ess-latex-chunk-pair-region)))
844     (copy-region-as-kill (car r) (cdr r))))
845
846 \f
847 ;;; Movement
848
849 (defun ess-latex-sign (n)
850   "Return the sign of N."
851   (if (< n 0) -1 1))
852
853 (defun ess-latex-next-doc-chunk (&optional cnt)
854   "Goto to the Nth documentation chunk from point."
855   (interactive "p")
856   (widen)
857   (let ((start (ess-latex-find-chunk-index-buffer))
858         (i 1))
859     (while (<= i (abs cnt))
860       (setq start (+ (ess-latex-sign cnt) start))
861       (while (ess-latex-chunk-is-code start)
862         (setq start (+ (ess-latex-sign cnt) start)))
863       (setq i (1+ i)))
864     (goto-char (marker-position (cdr (ess-latex-chunk-vector-aref start))))
865     (forward-char 1))
866   (if ess-latex-narrowing
867       (ess-latex-narrow-to-chunk-pair)))
868
869 (defun ess-latex-previous-doc-chunk (&optional n)
870   "Goto to the -Nth documentation chunk from point."
871   (interactive "p")
872   (ess-latex-next-doc-chunk (- n)))
873
874 (defun ess-latex-next-code-chunk (&optional cnt)
875   "Goto to the Nth code chunk from point."
876   (interactive "p")
877   (widen)
878   (let ((start (ess-latex-find-chunk-index-buffer))
879         (i 1))
880     (while (<= i (abs cnt))
881       (setq start (+ (ess-latex-sign cnt) start))
882       (while (not (ess-latex-chunk-is-code start))
883         (setq start (+ (ess-latex-sign cnt) start)))
884       (setq i (1+ i)))
885     (goto-char (marker-position (cdr (ess-latex-chunk-vector-aref start))))
886     (next-line 1))
887   (if ess-latex-narrowing
888       (ess-latex-narrow-to-chunk-pair)))
889
890 (defun ess-latex-previous-code-chunk (&optional n)
891   "Goto to the -Nth code chunk from point."
892   (interactive "p")
893   (ess-latex-next-code-chunk (- n)))
894
895 (defun ess-latex-next-chunk (&optional n)
896   "If in a documentation chunk, goto to the Nth documentation
897 chunk from point, else goto to the Nth code chunk from point."
898   (interactive "p")
899   (if (ess-latex-in-code-chunk)
900       (ess-latex-next-code-chunk n)
901     (ess-latex-next-doc-chunk n)))
902
903 (defun ess-latex-previous-chunk (&optional n)
904   "If in a documentation chunk, goto to the -Nth documentation
905 chunk from point, else goto to the -Nth code chunk from point."
906   (interactive "p")
907   (ess-latex-next-chunk (- n)))
908
909 (defvar ess-latex-chunk-history nil
910   "")
911
912 (defun ess-latex-goto-chunk ()
913   "Goto the named chunk."
914   (interactive)
915   (widen)
916   (let* ((completion-ignore-case t)
917          (alist (ess-latex-build-chunk-alist))
918          (chunk (completing-read
919                  "Chunk: " alist nil t
920                  (ess-latex-goto-chunk-default)
921                  ess-latex-chunk-history)))
922     (goto-char (cdr (assoc chunk alist))))
923   (if ess-latex-narrowing
924       (ess-latex-narrow-to-chunk-pair)))
925
926 (defun ess-latex-goto-chunk-default ()
927   (save-excursion
928     (if (re-search-backward "<<"
929                             (save-excursion
930                               (beginning-of-line)
931                               (point))
932                             'move)
933         (goto-char (match-beginning 0)))
934     (if (re-search-forward "<<\\(.*\\)>>"
935                            (save-excursion
936                              (end-of-line)
937                              (point))
938                            t)
939         (buffer-substring (match-beginning 1) (match-end 1))
940       nil)))
941
942 (defun ess-latex-build-chunk-alist ()
943   (if (not ess-latex-chunk-vector)
944       (ess-latex-update-chunk-vector))
945   ;; The naive recursive solution will exceed MAX-LISP-EVAL-DEPTH in
946   ;; buffers w/ many chunks.  Maybe there is a tail recursivce solution,
947   ;; but iterative solutions should be acceptable for dealing with vectors.
948   (let ((alist nil)
949         (i (1- (length ess-latex-chunk-vector))))
950     (while (>= i 0)
951       (let* ((chunk (aref ess-latex-chunk-vector i))
952              (name (car chunk))
953              (marker (cdr chunk)))
954         (if (and (stringp name)
955                  (not (assoc name alist)))
956             (setq alist (cons (cons name marker) alist))))
957       (setq i (1- i)))
958     alist))
959
960 (defun ess-latex-goto-next (&optional cnt)
961   "Goto the continuation of the current chunk."
962   (interactive "p")
963   (widen)
964   (if (not ess-latex-chunk-vector)
965       (ess-latex-update-chunk-vector))
966   (let ((start (ess-latex-find-chunk-index-buffer)))
967     (if (not (ess-latex-chunk-is-code  start))
968         (setq start (1+ start)))
969     (if (ess-latex-chunk-is-code start)
970         (let ((name (car (ess-latex-chunk-vector-aref start)))
971               (i 1))
972           (while (<= i (abs cnt))
973             (setq start (+ (ess-latex-sign cnt) start))
974             (while (not (equal (car (ess-latex-chunk-vector-aref start))
975                                name))
976               (setq start (+ (ess-latex-sign cnt) start)))
977             (setq i (1+ i)))
978           (goto-char (marker-position
979                       (cdr (ess-latex-chunk-vector-aref start))))
980           (next-line 1))))
981   (if ess-latex-narrowing
982       (ess-latex-narrow-to-chunk-pair)))
983
984 (defun ess-latex-goto-previous (&optional cnt)
985   "Goto the previous chunk."
986   (interactive "p")
987   (ess-latex-goto-next (- cnt)))
988
989 (defun ess-latex-occur (arg)
990   "Find all occurences of the current chunk.
991 This function simply runs OCCUR on \"<<NAME>>\"."
992   (interactive "P")
993   (let ((n (if (and arg
994                     (numberp arg))
995                arg
996              0))
997         (idx (ess-latex-find-chunk-index-buffer)))
998     (if (ess-latex-chunk-is-code idx)
999         (occur (regexp-quote (concat "<<"
1000                                      (car (aref ess-latex-chunk-vector idx))
1001                                      ">>"))
1002                n)
1003       (setq idx (1+ idx))
1004       (while (not (ess-latex-chunk-is-code idx))
1005         (setq idx (1+ idx)))
1006       (occur (regexp-quote (concat "<<"
1007                                    (car (aref ess-latex-chunk-vector idx))
1008                                    ">>"))
1009                            n))))
1010
1011 \f
1012 ;;; Insertion
1013
1014 (defun ess-latex-new-chunk (name)
1015   "Insert a new chunk."
1016   (interactive "sChunk name: ")
1017   (insert "@ \n<<" name ">>=\n")
1018   (save-excursion
1019     (insert "@ %def \n"))
1020   (ess-latex-update-chunk-vector))
1021
1022 (defun ess-latex-at-beginning-of-line ()
1023   (equal (save-excursion
1024            (beginning-of-line)
1025            (point))
1026          (point)))
1027
1028 (defun ess-latex-electric-@ (arg)
1029   "Smart incarnation of `@', starting a new documentation chunk, maybe.
1030 If given an numerical argument, it will act just like the dumb `@'.
1031 Otherwise and if at the beginning of a line in a code chunk:
1032 insert \"@ \" and update the chunk vector."
1033   (interactive "P")
1034   (if arg
1035       (self-insert-command (if (numberp arg) arg 1))
1036     (if (and (ess-latex-at-beginning-of-line)
1037              (ess-latex-in-code-chunk))
1038         (progn
1039           (insert "@ ")
1040           (ess-latex-update-chunk-vector))
1041       (self-insert-command 1))))
1042
1043 (defun ess-latex-electric-< (arg)
1044   "Smart incarnation of `<', starting a new code chunk, maybe.
1045 If given an numerical argument, it will act just like the dumb `<'.
1046 Otherwise and if at the beginning of a line in a documentation chunk:
1047 insert \"<<>>=\" and a newline if necessary.  Leave point in the middle
1048 and and update the chunk vector."
1049   (interactive "P")
1050   (if arg
1051       (self-insert-command (if (numberp arg) arg 1))
1052     (if (and (ess-latex-at-beginning-of-line)
1053              (not (stringp (car (ess-latex-find-chunk)))))
1054         (progn
1055           (insert "<<")
1056           (save-excursion
1057             (insert ">>=")
1058             (if (not (looking-at "\\s *$"))
1059                 (newline)))
1060           (ess-latex-update-chunk-vector))
1061       (self-insert-command 1))))
1062
1063 \f
1064 ;;; Modes
1065
1066 (defun ess-latex-set-chunk-code-mode ()
1067   "Set the ess-latex-code-mode for the current chunk"
1068   (interactive)
1069   (if (ess-latex-in-code-chunk)
1070       (progn
1071         ;; Reset code-mode to default and then check for a mode comment.
1072         (setq ess-latex-code-mode ess-latex-default-code-mode)
1073         (let (mode chunk-name)
1074           (save-restriction
1075             (save-excursion  
1076               (end-of-line)
1077               (re-search-backward "^[ \t]*<<\\(.*\\)>>=" nil t)
1078               (setq chunk-name (match-string 1))
1079               (widen)
1080               (goto-char (point-min))
1081               (re-search-forward (concat "^<<" chunk-name ">>=") nil t)
1082               (beginning-of-line 2)    
1083               (setq mode (ess-latex-in-mode-line))
1084               (if (functionp mode)
1085                   (setq ess-latex-code-mode mode))))))
1086     (error "This only makes sense in a code chunk")))
1087
1088 (defun ess-latex-set-doc-syntax-table ()
1089   "Sets the doc-mode syntax-table to treat code quotes as comments."
1090   (interactive)
1091   (let ((square-bracket-string (char-to-string (char-syntax ?\[))))
1092     (if (string= square-bracket-string "(")
1093         (progn
1094           (modify-syntax-entry ?\[ "(]12b" ess-latex-doc-mode-syntax-table)
1095           (modify-syntax-entry ?\] ")[34b" ess-latex-doc-mode-syntax-table))
1096       (progn
1097         (modify-syntax-entry  ?\[ 
1098                               (concat square-bracket-string " 12b")
1099                               ess-latex-doc-mode-syntax-table)
1100         (modify-syntax-entry  ?\] 
1101                               (concat square-bracket-string " 34b")
1102                               ess-latex-doc-mode-syntax-table)))))
1103
1104 (defun ess-latex-select-mode ()
1105   "Select ESS-LATEX-DOC-MODE or ESS-LATEX-CODE-MODE, as appropriate."
1106   (interactive)
1107   (let ((this-chunk-index (ess-latex-find-chunk-index-buffer)))
1108     ;; Has the last change to the buffer taken us into a different
1109     ;; chunk ?
1110     (if (not (equal this-chunk-index ess-latex-last-chunk-index))
1111         (progn
1112           (setq ess-latex-last-chunk-index this-chunk-index)
1113           (if (ess-latex-in-code-chunk)
1114               ;; Inside a code chunk
1115               (progn
1116                 ;; Find out which code mode to use
1117                 (ess-latex-set-chunk-code-mode)
1118                 ;; If we aren't already using it, use it.
1119                 (if (not (equal major-mode ess-latex-code-mode))
1120                     (progn
1121                       (funcall ess-latex-code-mode)
1122                       (run-hooks 'ess-latex-select-mode-hook)
1123                       (run-hooks 'ess-latex-select-code-mode-hook))))
1124             ;; Inside a documentation chunk
1125             (progn
1126               (if (not (equal major-mode ess-latex-doc-mode))
1127                   (progn
1128                     (funcall ess-latex-doc-mode)))
1129               (if (not ess-latex-doc-mode-syntax-table)
1130                   (progn 
1131                     (message "Setting up syntax table")
1132                     (setq ess-latex-doc-mode-syntax-table 
1133                           (make-syntax-table (syntax-table)))
1134                     (ess-latex-set-doc-syntax-table)))
1135               (set-syntax-table ess-latex-doc-mode-syntax-table)
1136               (run-hooks 'ess-latex-select-mode-hook)
1137               (run-hooks 'ess-latex-select-doc-mode-hook)))
1138           (run-hooks 'ess-latex-changed-chunk-hook)))))
1139
1140 (defvar ess-latex-doc-mode ess-latex-default-doc-mode
1141   "Default major mode for editing ess-latex documentation chunks.
1142 It is not possible to have more than one doc-mode in a file.
1143 However, this variable is used to determine whether the doc-mode needs
1144 to by added to the mode-line")
1145
1146 (defun ess-latex-set-doc-mode (mode)
1147   "Change the major mode for editing documentation chunks."
1148   (interactive "CNew major mode for documentation chunks: ")
1149   (setq ess-latex-doc-mode mode)
1150   (setq ess-latex-doc-mode-syntax-table nil)
1151   ;;Pretend we've changed chunk, so the mode will be reset if necessary
1152   (setq ess-latex-last-chunk-index (1- ess-latex-last-chunk-index))
1153   (ess-latex-select-mode))
1154
1155 (defun ess-latex-set-code-mode (mode)
1156   "Change the major mode for editing all code chunks."
1157   (interactive "CNew major mode for all code chunks: ")
1158   (setq ess-latex-default-code-mode mode)   
1159   ;;Pretend we've changed chunk, so the mode will be reset if necessary
1160   (setq ess-latex-last-chunk-index (1- ess-latex-last-chunk-index))
1161   (ess-latex-select-mode))
1162
1163 (defun ess-latex-set-this-code-mode (mode)
1164   "Change the major mode for editing this code chunk.
1165 The only sensible way to do this is to add a mode line to the chunk"
1166   (interactive "CNew major mode for this code chunk: ")
1167   (if (ess-latex-in-code-chunk)
1168       (progn
1169         (setq ess-latex-code-mode mode)
1170         (save-restriction
1171           (save-excursion 
1172             (let (chunk-name)
1173               (widen)
1174               (end-of-line)
1175               (re-search-backward "^[ \t]*<<\\(.*\\)>>=" nil t)
1176               (setq chunk-name (match-string 1))
1177               (goto-char (point-min))
1178               (re-search-forward (concat "^<<" chunk-name ">>=") nil t)
1179               (beginning-of-line 2))
1180             ;; remove mode-line, if there is one
1181             (if (ess-latex-in-mode-line) 
1182                 (progn
1183                   (kill-line)
1184                   (kill-line)))
1185             (if (not (equal ess-latex-code-mode ess-latex-default-code-mode))
1186                 (progn
1187                   (setq mode (substring (symbol-name mode) 0 -5))
1188                   ;; Need to set major mode so that we can comment out
1189                   ;; the mode line
1190                   (funcall ess-latex-code-mode)
1191                   (insert comment-start 
1192                           " -*- " mode 
1193                           " -*- " comment-end "\n")))
1194             (setq ess-latex-last-chunk-index (1- ess-latex-last-chunk-index)))))
1195     (message "This only makes sense in a code chunk.")))
1196 \f
1197 ;;; Misc
1198
1199 (defun ess-latex-mode-version ()
1200   "Echo the RCS identification of ess-latex mode."
1201   (interactive)
1202   (message "Thorsten's ess-latex-mode (PRERELEASE). RCS: %s"
1203            ess-latex-mode-RCS-Id))
1204
1205 (defun ess-latex-describe-mode ()
1206   "Describe ess-latex mode."
1207   (interactive)
1208   (describe-function 'ess-latex-mode))
1209
1210 (defun ess-latex-insert-default-mode-line ()
1211   "Insert line that will set the ess-latex mode of this file in emacs.
1212 The file is set to use the current doc and default-code modes, so
1213 ensure they are set correctly (with ess-latex-set-code-mode and
1214 ess-latex-set-doc-mode) before calling this function"
1215   (interactive)
1216   (save-excursion
1217     (goto-char 1)
1218     (if (ess-latex-in-mode-line) 
1219         (progn
1220           (kill-line)
1221           (kill-line)))
1222     (if (not (eq major-mode ess-latex-doc-mode))
1223         (ess-latex-select-mode))
1224     (insert comment-start " -*- mode: ess-latex; ess-latex-default-code-mode: "
1225             (symbol-name ess-latex-default-code-mode) 
1226             (if (not (eq ess-latex-doc-mode ess-latex-default-doc-mode))
1227                 (concat "; ess-latex-doc-mode: " (symbol-name
1228                                               ess-latex-doc-mode) ";")
1229               ";")
1230             " -*-" comment-end "\n"))
1231   (ess-latex-select-mode))
1232
1233 (defun ess-latex-mouse-first-button (event)
1234   (interactive "e")
1235   (mouse-set-point event)
1236   (if (and ess-latex-use-mouse-navigation
1237            (eq (save-excursion 
1238                  (end-of-line)
1239                  (re-search-backward "^[\t ]*\\(<<\\)\\(.*\\)\\(>>\\)" nil t))
1240                (save-excursion 
1241                  (beginning-of-line) (point))))
1242       (progn
1243 (if (< (point) (match-beginning 2))
1244             (let ((chunk-name (buffer-substring-no-properties 
1245                                (match-beginning 2)
1246                                (match-end 2))))
1247               (re-search-backward (concat "<<" chunk-name ">>") nil t))
1248           (if (and (<= (match-end 2) (point))
1249                    (>  (+ 2 (match-end 2)) (point)))
1250               (let ((chunk-name (buffer-substring-no-properties 
1251                                  (match-beginning 2)
1252                                  (match-end 2))))
1253                 (re-search-forward (concat "<<" chunk-name ">>") nil t)))))))
1254
1255 \f
1256 ;;; Debugging
1257
1258 (defun ess-latex-log (s)
1259   (let ((b (current-buffer)))
1260     (switch-to-buffer (get-buffer-create "*ess-latex-log*"))
1261     (goto-char (point-max))
1262     (setq buffer-read-only nil)
1263     (insert s)
1264     (setq buffer-read-only t)
1265     (switch-to-buffer b)))
1266
1267
1268
1269
1270
1271 (defvar ess-latex-thread-alist nil
1272   "A list of threads in the current buffer.
1273 Each entry in the list contains 5 elements:
1274 1) The name of the threads
1275 2) The name of the immdiate parent thread in which it is used (nil if
1276    it is a \"top-level\" thread which is not used anywhere). 
1277 3) The name of the top-level parent thread in which it is used (i.e. a
1278    thread in which it is used but which is not itself used anywhere:
1279    nil if this thread is not used anywhere.
1280 4) The format string to use to define line numbers in the output
1281    file of this thread. Should only be set if this thread is not used
1282    anywhere: if a thread is used as part of another thread, the parent
1283    thread's format string should be used.
1284 5) If this is nil, tabs are converted to spaces in the tangled
1285    file. If it is a number, tabs are copied to the tangled file 
1286    unchanged, and tabs are also used for indentation, with the number
1287    of spaces per tab defined by this number. This MUST be set in order
1288    to tangle makefiles, which depend on tabs.Should only be set if
1289    this thread is not used anywhere. otherwise set to nil. "
1290 )
1291
1292 (defun ess-latex-update-thread-alist ()
1293   "Updates the list of threads in the current buffer.
1294 Each entry in the list contains 5 elements:
1295 1) The name of the thread
1296 2) The name of the immdiate parent thread in which it is used (nil if
1297    it is a \"top-level\" thread which is not used anywhere). 
1298 3) The name of the top-level parent thread in which it is used (i.e. a
1299    thread in which it is used but which is not itself used anywhere:
1300    nil if this thread is not used anywhere.
1301 4) The format string to use to define line numbers in the output
1302    file of this thread. Should only be set if this thread is not used
1303    anywhere: if a thread is used as part of another thread, the parent
1304    thread's format string should be used.
1305 5) If this is nil, tabs are converted to spaces in the tangled
1306    file. If it is a number, tabs are copied to the tangled file 
1307    unchanged, and tabs are also used for indentation, with the number
1308    of spaces per tab defined by this number. This MUST be set in order
1309    to tangle makefiles, which depend on tabs.Should only be set if
1310    this thread is not used anywhere. otherwise set to nil. "
1311   (interactive)
1312   (save-excursion
1313     (goto-char (point-min))
1314     (let ((thread-alist) (thread-list-entry) (chunk-use-name)
1315           (current-thread) (new-thread-alist))
1316       (while (re-search-forward 
1317               "^[ \t]*<<\\(.*\\)>>\\(=\\)?" nil t)
1318         (goto-char (match-beginning 0))
1319         ;; Is this the definition of a chunk ?
1320         (if (match-beginning 2)
1321             ;;We have a chunk definition
1322             (progn
1323               ;; Get the thread name
1324               (setq current-thread 
1325                     (buffer-substring-no-properties (match-beginning 1)
1326                                                     (match-end 1)))
1327               ;; Is this thread already in our list ?
1328               (if (assoc current-thread thread-alist)
1329                   nil
1330                 (progn
1331                   ;; If not, create an entry with 4 nils at the end      
1332                   (setq thread-list-entry 
1333                         (list (cons current-thread 
1334                                     (make-list 4 nil))))
1335                   ;; And add it to the list
1336                   (setq thread-alist 
1337                         (append thread-alist thread-list-entry)))))
1338      
1339             ;; Not a definition but a use
1340             (progn
1341               ;; Get the thread name
1342                 (setq chunk-use-name 
1343                     (buffer-substring-no-properties (match-beginning 1)
1344                                                     (match-end 1)))
1345               ;; Has the thread already been defined before being used ?
1346               (if (setq thread-list-entry (assoc chunk-use-name
1347                                                  thread-alist))
1348                   ;; If it has, set its parent to be the thread we are in at the moment
1349                   (setcar (cdr thread-list-entry) current-thread)
1350                 ;; If not, add it to the list, with its parent name and 3 nils
1351                 (progn
1352                   (setq thread-list-entry 
1353                         (list (cons chunk-use-name 
1354                                     (cons current-thread
1355                                           (make-list 3 nil)))))
1356                   (setq thread-alist (append thread-alist thread-list-entry)))))
1357 )
1358         ;;Go to the next line   
1359         (beginning-of-line 2))
1360       ;; Now, the second element of each entry points to that thread's
1361       ;; immediate parent. Need to set it to the thread's ultimate
1362       ;; parent.
1363       (let ((thread-counter 0)
1364             (this-thread)
1365             (this-thread-parent))
1366         (while (<= thread-counter (1- (length thread-alist)))
1367           (setq this-thread (nth thread-counter thread-alist))
1368           (setq this-thread-parent (assoc 
1369                                     (car (cdr this-thread))
1370                                     thread-alist))
1371           (while (not (equal nil (car (cdr this-thread-parent))))
1372             (setq this-thread-parent (assoc 
1373                                       (car (cdr this-thread-parent))
1374                                       thread-alist)))
1375           (setq this-thread (cons (car this-thread)
1376                                   (cons (car (cdr this-thread))
1377                                         (cons (car this-thread-parent)
1378                                               (nthcdr 2 this-thread)))))
1379           (setq new-thread-alist (append new-thread-alist (list this-thread)))
1380           (setq thread-counter (1+ thread-counter))))
1381
1382       (setq ess-latex-thread-alist new-thread-alist))))
1383
1384
1385 ; Option setting functions to go here
1386
1387 (defun ess-latex-set-thread-line-format ())
1388
1389 (defun ess-latex-set-thread-tabs ())
1390
1391
1392 (defvar ess-latex-default-line-number-format nil
1393   "The format string to use to  define line numbers in this thread. 
1394 If nil, do  not use line numbers.")
1395
1396 (defvar ess-latex-default-line-number-skip-lines 0 
1397   "The number of initial lines to output before the line number.
1398 This may be useful in shell scripts, where the first line (or two) must have a
1399   specific form.")
1400
1401 (defvar ess-latex-default-tab-width 8
1402   "If a number, convert tabs to  that number of spaces in the output. If nil, let tabs through to the output unaltered.")
1403
1404 (defvar ess-latex-line-number-format  ess-latex-default-line-number-format
1405   "The format string to use to  define line numbers in this thread. 
1406 If nil, do  not use line numbers.")
1407
1408 (defvar ess-latex-line-number-skip-lines ess-latex-default-line-number-skip-lines 
1409   "The number of initial lines to output before the line number.
1410 This may be useful in shell scripts, where the first line (or two) must have a
1411   specific form.")
1412
1413 (defvar ess-latex-tab-width  ess-latex-default-tab-width
1414   "If a number, convert tabs to  that number of spaces in the output. If nil, let tabs through to the output unaltered.")
1415
1416 (defun ess-latex-get-thread-local-variables ()
1417   "Get the values of the variables that are local to a thread."
1418   (interactive)
1419   (save-restriction
1420     (save-excursion  
1421       (end-of-line)
1422       (re-search-backward "^[ \t]*<<\\(.*\\)>>=" nil t)
1423       (let ((chunk-name (match-string 1)))
1424         (widen)
1425         (goto-char (point-min))
1426         (re-search-forward (concat "^<<" chunk-name ">>=") nil t)
1427         (beginning-of-line 2)    
1428         (while (looking-at ".*-\*-.*-\*-")
1429           (let ((this-line (buffer-substring-no-properties 
1430                             (point)
1431                             (progn (end-of-line) (point)))))
1432             (if (string-match 
1433                  "mode:[ \t]*\\([^\t ]*\\)" this-line)
1434                 (setq ess-latex-code-mode (match-string-no-properties 1 this-line)))
1435             (if (string-match 
1436                  "ess-latex-line-number-format:[ \t]*\"\\([^\"]*\\)\"" this-line)
1437                 (setq ess-latex-line-number-format 
1438                       (match-string-no-properties 1 this-line)))
1439             (if (string-match 
1440                  "ess-latex-line-number-skip-lines:[ \t]*\\([^\t ]*\\)" this-line)
1441                 (setq ess-latex-line-number-skip-lines 
1442                       (string-to-number
1443                        (match-string-no-properties 1 this-line))))
1444             (if (string-match 
1445                  "ess-latex-tab-width:[ \t]*\\([^\t ]*\\)" this-line)
1446                 (setq ess-latex-tab-width    
1447                       (string-to-number
1448                        (match-string-no-properties 1 this-line))))
1449             (beginning-of-line 2)))))))
1450   
1451 (defun ess-latex-reset-thread-local-variables ()
1452   "Resets the thread-local variables to their default values"
1453   (setq ess-latex-tab-width ess-latex-default-tab-width)
1454   (setq ess-latex-line-number-format ess-latex-default-line-number-format)
1455   (setq ess-latex-line-number-skip-lines ess-latex-default-line-number-skip-lines))
1456
1457 (defun ess-latex-write-line-number (line-number-format buffer)
1458   (if line-number-format
1459       (progn
1460         (let ((this-line (count-lines (point-min)(point))))
1461           (while (string-match ".*\\(%L\\).*" line-number-format)
1462             (setq line-number-format
1463                   (replace-match
1464                    (format "%d" this-line) t t line-number-format 1)))
1465           (while (string-match ".*\\(%F\\).*" line-number-format)
1466             (setq line-number-format
1467                   (replace-match 
1468                    (format "%s" (buffer-file-name)) t t line-number-format 1)))
1469           (while (string-match ".*\\(%N\\).*" line-number-format)
1470             (setq line-number-format
1471                   (replace-match "\n" t t line-number-format 1)))
1472           (save-excursion
1473             (set-buffer buffer)
1474             (insert line-number-format))))))
1475
1476
1477 (defun ess-latex-tangle-chunk ( &optional buffer prefix-string)
1478   "Generate the code produced by this chunk, & any threads used in this chunk."
1479   (interactive)
1480   (save-excursion
1481     (ess-latex-reset-thread-local-variables)
1482     (ess-latex-get-thread-local-variables)
1483     (ess-latex-update-chunk-vector)
1484     (let* 
1485         ((chunk-end (progn 
1486                       (end-of-line)
1487                       (re-search-forward "^@" nil t)
1488                       (beginning-of-line)
1489                       (point)))
1490          ;;get name and start point of this chunk    
1491          (chunk-start (progn
1492                         (re-search-backward "^<<\\([^>]*\\)>>=$" nil t)
1493                         (beginning-of-line 2)
1494                         (point)))
1495          (chunk-name (buffer-substring-no-properties 
1496                       (match-end 1)
1497                       (match-beginning 1)))
1498          ;; get end of this chunk        
1499          ;; Get information we need about this thread    
1500          (thread-info (assoc chunk-name ess-latex-thread-alist))
1501          (thread-tabs (nth 4 thread-info))
1502          (line-number-format (nth 3 thread-info))
1503          (thread-name-re) (post-chunk) (pre-chunk)
1504          (first-line t)
1505          (tangle-buffer (generate-new-buffer "Tangle Buffer")))
1506
1507         (progn
1508           (goto-char chunk-start)
1509           ;; If this is a mode-line, ignore it
1510           (while (looking-at ".*-\\*-.*-\\*-")
1511             (beginning-of-line 2))
1512           ;; If we want to include line numbers, write one
1513           (if line-number-format
1514               (while (> ess-latex-line-number-skip-lines 0)
1515                 (append-to-buffer tangle-buffer 
1516                                   (point)
1517                                   (save-excursion (progn
1518                                                     (end-of-line) (point))))
1519                 (beginning-of-line 2)
1520                 (1- ess-latex-line-number-skip-lines))
1521             (ess-latex-write-line-number line-number-format buffer))
1522           (message "Now at %d" (point))
1523
1524           (while (< (point) chunk-end)
1525             (untabify (point) (save-excursion (beginning-of-line 2)(point)))
1526             ;; This RE gave me trouble. Without the `\"', it recognised itself
1527             ;; and so could not copy itself correctly.
1528             (if (looking-at "\\([^\n\"@]*\\)<<\\(.*\\)\\(>>\\)\\([^\n\"]*\\)$")
1529                 (progn
1530                   (save-restriction
1531                     (save-excursion
1532                       (setq thread-name-re (concat "<<"
1533                                                    (match-string 2)
1534                                                    ">>="))
1535                       (setq pre-chunk (match-string 1))
1536                       (if prefix-string (setq pre-chunk (concat prefix-string pre-chunk)))
1537                       (setq post-chunk (match-string 4))
1538                       (widen)
1539                       (goto-char (point-min))
1540                       (while (re-search-forward thread-name-re nil t)
1541                         (ess-latex-tangle-chunk tangle-buffer pre-chunk)
1542                         (next-line 1)))
1543                     (if post-chunk
1544                         (save-excursion
1545                           (set-buffer tangle-buffer)
1546                           (backward-char)
1547                           (insert post-chunk)
1548                           (beginning-of-line 2)))))
1549                                       
1550                 ;; Otherwise, just copy this line 
1551                 (setq pre-chunk
1552                       (buffer-substring 
1553                        (point) 
1554                        (save-excursion
1555                          (beginning-of-line 2)
1556                          (point))))
1557                 ;; Add a prefix if necessary
1558                 (if (and prefix-string
1559                          (> (length pre-chunk) 1))
1560                     (setq pre-chunk (concat prefix-string pre-chunk)))
1561                 ;; And copy it to the buffer
1562                 (save-excursion
1563                   (set-buffer tangle-buffer)
1564                   (insert pre-chunk)))
1565             ;; If this is the first line of the chunk, we need to change
1566             ;; prefix-string to consist solely of spaces 
1567             (if (and first-line
1568                      prefix-string)
1569                 (progn
1570                   (setq prefix-string (make-string (length prefix-string) ?\  ))
1571                   (setq first-line nil)))
1572             ;; Either way, go to the next line
1573             (beginning-of-line 2))
1574
1575           (save-excursion
1576             (set-buffer tangle-buffer)
1577             (goto-char (point-min))
1578             (while (re-search-forward "\@\<<" nil t)
1579               (replace-match "<<" nil nil)
1580               (forward-char 3))
1581             (if thread-tabs 
1582               (progn
1583                   (setq tab-width thread-tabs)
1584                   (tabify (point-min)(point-max)))
1585               (untabify (point-min)(point-max))))
1586
1587           (if buffer
1588               (save-excursion
1589                 (set-buffer buffer)
1590                 (insert-buffer-substring tangle-buffer)
1591                 (kill-buffer tangle-buffer)))
1592 ))))
1593
1594 (defun ess-latex-tangle-thread ( name &optional buffer)
1595   "Given the name of a thread, tangles the thread to buffer.
1596 If no buffer is given, create a new one with the same name as the thread."
1597   (interactive "sWhich thread ? ")
1598   (if (not buffer)
1599       (progn
1600         (setq buffer (get-buffer-create name))
1601         (save-excursion 
1602           (set-buffer buffer)
1603           (erase-buffer))))
1604   (save-excursion
1605     (goto-char (point-min))
1606     (let ((chunk-counter 0))
1607       (while (re-search-forward 
1608               "^<<\\(.*\\)>>=[\t ]*" nil t)
1609         (if (string= (match-string 1)
1610                      name)
1611             (progn
1612               (setq chunk-counter (1+ chunk-counter))
1613               (message "Found %d chunks" chunk-counter)
1614               (ess-latex-tangle-chunk buffer)))))))
1615
1616 (defun ess-latex-tangle-current-thread ( &optional buffer)
1617   (interactive)
1618   (save-excursion
1619     (let* ((chunk-start (progn
1620                           (re-search-backward "^<<\\([^>]*\\)>>=[\t ]*$" 
1621                                               nil t)
1622                           (beginning-of-line 2)
1623                           (point)))
1624            (chunk-name (buffer-substring-no-properties 
1625                         (match-end 1)
1626                         (match-beginning 1))))
1627       (ess-latex-tangle-thread chunk-name buffer))))
1628 ;menu functions
1629
1630 \f
1631 ;;; Finale
1632
1633 (run-hooks 'ess-latex-mode-load-hook)
1634 (provide 'ess-latex-mode)
1635
1636 ;; Changes made by Mark Lunt (mark.lunt@mrc-bsu.cam.ac.uk) 22/03/1999
1637
1638 ;; The possibility of having code chunks using more than one language
1639 ;; was added. This was first developed by Adnan Yaqub
1640 ;; (AYaqub@orga.com) for syntax highlighting, but even people who hate
1641 ;; highlighting may like to maintain their Makefile with their code,
1642 ;; or test-scripts with their programs, or even user documentation as
1643 ;; latex-mode code chunks.
1644 ;; This required quite a few changes to ess-latex-mode:
1645 ;; 1) A new variable `ess-latex-default-code-mode' was create to do the job
1646 ;;    `ess-latex-code-mode' used to.
1647 ;; 2) ess-latex-code-mode now contains the code-mode of the current chunk
1648 ;; 3) Each chunk can now have its own mode-line to tell emacs what
1649 ;;    mode to use to edit it. The function `ess-latex-in-mode-line'
1650 ;;    recognises such mode-lines, and the function
1651 ;;    `ess-latex-set-this-code-mode' sets the code mode for the current
1652 ;;    chunk and adds a mode-line if necessary. If several chunks have
1653 ;;    the same name, the mode-line must appear in the first chunk with
1654 ;;    that name.
1655 ;; 4) The mechanism for deciding whether to change mode was altered,
1656 ;;    since the old method assumed a single code mode. Now,
1657 ;;    `ess-latex-last-chunk-index' keeps track of which chunk we were in
1658 ;;    last. If we have moved to a different chunk, we have to check
1659 ;;    which mode we should be in, and change if necessary.
1660
1661 ;; The keymap and menu-map handling was changed. Easymenu was used to
1662 ;; define the menu, and it the keymap was attached to the 'official'
1663 ;; minor-modes-keymaps list. This means that
1664 ;; 1) It was automatically loaded when ess-latex-mode was active and
1665 ;;    unloaded when it was inactive.
1666 ;; 2) There was no need to worry about the major mode map clobbering
1667 ;;    it , since it takes precedence over the major mode
1668 ;;    map. `ess-latex-setup-keymap' is therefore now superfluous
1669 ;; The menu was also reorganised to make it less cluttered, so there
1670 ;; would be room for adding tangling and weaving commands (one day).
1671
1672 ;; Mouse navigation is supported, in so far as clicking mouse-1 on the
1673 ;; '<<' of a chunk name moves to the previous instance of that chunk
1674 ;; name, and clicking in the '>>' moves to the next instance. They are
1675 ;; not mouse-hightlighted, though: too much hassle for zero added
1676 ;; functionality. 
1677
1678 ;; ess-latex-doc-mode has been given its own syntax-table. It is the same
1679 ;; as the current doc-mode syntax-table, except that [[ is a comment
1680 ;; start and ]] a comment end. Fixes some ugliness in LaTeX-mode if
1681 ;; `$' or `%' appear in quoted code (or even `<<', which happens often
1682 ;; in C++).
1683 ;; (This should make ess-latex-hide-code-quotes and
1684 ;; ess-latex-restore-code-quotes unnecessary, but I have not yet removed
1685 ;; them, nor the calls to them).
1686
1687 ;; A new function `ess-latex-indent-line' was defined and bound by default
1688 ;; to the tab key. This should indent the current line correctly in
1689 ;; whichever mode we are currently in. Previously, c-mode in
1690 ;; particular did not behave well with indentation (although
1691 ;; `ess-latex-fill-chunk' worked fine). Indentation is only accurate
1692 ;; within the chunk: it does not know the syntax at the end of the
1693 ;; previous chunk, so it does not know where to start indenting in
1694 ;; this chunk. However, provided the indentation within each chunk is correct,
1695 ;; notangle will correctly indented code.
1696
1697 ;; (I think it would be good to separate filling and indenting,
1698 ;; though, since `indent-region' and `fill-region' have completely
1699 ;; different meanings in LaTeX-mode (and both are useful))
1700
1701 ;; ess-latex-mode and ess-latex-minor-mode were given an optional argument, so
1702 ;; that (ess-latex-mode -1) turns it off, (ess-latex-mode 1) turns it on, and
1703 ;; (ess-latex-mode) toggles it. This is considered normal for minor modes.
1704
1705 ;; buffer-substring changed to buffer-substring-no-properties:
1706 ;; comparisons with buffer-substring can be unreliable if highlighting
1707 ;; is used.
1708
1709 ;; New functions `ess-latex-in-code-chunk' & `ess-latex-chunk-is-code' created
1710 ;; to replace (if (stringp (car (ess-latex-find-chunk)))) and 
1711 ;; (if (stringp (car (ess-latex-chunk-vector-aref index)))).
1712
1713 ;; `ess-latex-insert-mode-line' was renamed
1714 ;; `ess-latex-insert-default-mode-line' and modified to put the mode-line
1715 ;; at the start of the file and remove any existing mode-line.
1716
1717 ;; a '<=' in `ess-latex-find-chunk-index' changed to '<', so we get the
1718 ;; right answer if point is on the first character in a chunk
1719
1720 ;; The name of `ess-latex-post-command-hook' changed to
1721 ;; `ess-latex-post-command-function', since it is a function.
1722
1723 ;; All the highlighting code moved to a separate file (ess-latex-font-lock-mode.el)
1724
1725 ;; Menu driven tangling is in the process of being added. It can
1726 ;; currently tangle a single chunk or a series of  chunks with the
1727 ;; same name (which I refer to as a thread) into a separate
1728 ;; buffer. This buffer can then be saved to a file, sent to an
1729 ;; interpreter, whatever. I haven't tested using line-numbers as yet.