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