2002-04-30  Dave Love  <fx@gnu.org>

	These changes principally re-do mode selection using an
	indirect buffer for the code mode.  That can be substantially
	more robust against what modes and local variables can get up
	to, but this implementation is really only proof of concept.
	Emacs should probably have built-in support for such things.

	* noweb-mode.el: Require font-lock when compiling.
	(noweb-doc-mode, noweb-code-mode, noweb-chunk-vector): Make
	buffer-local.
	(noweb-code-buffer, noweb-doc-buffer, noweb-chunk-vector): New.
	(noweb-mode-prefix-map, noweb-mode-menu-map): Deleted.
	(noweb-mode-map): Define all in defvar.
	(noweb-normal-fontify-function): New.
	(minor-mode-map-alist): Add noweb-mode.
	(noweb-mode): Re-written using indirect buffers.
	(noweb-setup-keymap, noweb-bind-keys, noweb-bind-menu)
	(noweb-make-variable-permanent-local): Deleted.
	(noweb-save-buffer-state, noweb-font-lock-region): New.
	(noweb-note-isearch-mode, noweb-note-isearch-mode-end): Use local
	hook.
	(noweb-post-command-hook): Don't call noweb-setup-keymap.
	(noweb-code-mode-p): New.
	(noweb-update-chunk-vector): Modified to deal with both buffers.
	(noweb-find-chunk-index): Use marker-position.
	(noweb-fill-chunk, noweb-electric-@, noweb-electric-<): Use
	noweb-code-mode-p.
	(noweb-next-chunk-any): New.
	(noweb-next-doc-chunk, noweb-next-code-chunk): Check cnt.
	(noweb-previous-doc-chunk, noweb-previous-code-chunk)
	(noweb-next-chunk, noweb-previous-chunk): Check for null n.
	(noweb-select-mode): Rewritten.

===================================================================
RCS file: noweb-mode.el,v
retrieving revision 1.3
diff -u -r1.3 noweb-mode.el
--- noweb-mode.el	2002/04/30 19:28:51	1.3
+++ noweb-mode.el	2002/04/30 21:51:23
@@ -1,6 +1,7 @@
 ;; noweb-mode.el - edit noweb files with GNU Emacs
 ;; Copyright (C) 1995 by Thorsten.Ohl @ Physik.TH-Darmstadt.de
 ;;     with a little help from Norman Ramsey <norman@bellcore.com>
+;; Copyright (C) 2002 David Love <fx@gnu.org>
 ;; 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
@@ -16,10 +17,7 @@
 ;; along with this program; if not, write to the Free Software
 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 ;; 
-;; See bottom of this file for information on language-dependent highlighting
-;;
-;; $Id: noweb-mode.el,v 1.3 2002/04/30 19:28:51 fx Exp fx $
-;; $Name:  $
+;; $Id: noweb-mode.el,v 1.2 2002/02/09 19:20:39 fx Exp $
 ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; THIS IS UNRELEASED CODE: IT IS MISSING FUNCTIONALITY AND IT NEEDS CLEANUP ;;
@@ -33,6 +31,14 @@
 
 ;; NEWS:
 ;;
+;;   * [Dave Love] Mode-selection stuff re-done using an indirect
+;;     buffer to DTRT more.  For instance, font-locking works,
+;;     assuming only one code mode.  (Multiple mode should be
+;;     supported using gerd's <<name -*-mode-*->> notation.)  This is
+;;     mostly proof of concept, and should be re-done.  Note that it
+;;     works badly with Flyspell -- a new Ispell process gets started
+;;     when the mode changes between chunks.
+;;
 ;;   * [tho] M-n q, aka: M-x noweb-fill-chunk
 ;;
 ;;   * [tho] M-n TAB, aka: M-x noweb-complete-chunk
@@ -58,9 +64,6 @@
 
 ;; TODO:
 ;;
-;;   * replace obscure hacks like `(stringp (car (noweb-find-chunk)))'
-;;     by something more reasonable like `(noweb-code-chunkp)'.
-;;
 ;;   * _maybe_ replace our `noweb-chunk-vector' by text properties.  We
 ;;     could then use highlighting to jazz up the visual appearance.
 ;;
@@ -73,13 +76,11 @@
 ;;   * ...
 ;;
 
+(eval-when-compile (require 'font-lock))
 ;;; Variables
 
 (defconst noweb-mode-RCS-Id
-  "$Id: noweb-mode.el,v 1.3 2002/04/30 19:28:51 fx Exp fx $")
-
-(defconst noweb-mode-RCS-Name
-  "$Name:  $")
+  "$Id: noweb-mode.el,v 1.2 2002/02/09 19:20:39 fx Exp $")
 
 (defvar noweb-mode-prefix "\M-n"
   "*Prefix key to use for noweb mode commands.
@@ -106,15 +107,18 @@
 
 (defvar noweb-doc-mode 'latex-mode
   "Major mode for editing documentation chunks.")
+(make-variable-buffer-local 'noweb-doc-mode)
 
 (defvar noweb-code-mode 'fundamental-mode
   "Major mode for editing code chunks.  This is set to FUNDAMENTAL-MODE
 by default, but you might want to change this in the Local Variables
 section of your file to something more appropriate, like C-MODE,
 FORTRAN-MODE, or even INDENTED-TEXT-MODE.")
+(make-variable-buffer-local 'noweb-code-mode)
 
 (defvar noweb-chunk-vector nil
   "Vector of the chunks in this buffer.")
+(make-local-variable 'noweb-chunk-vector)
 
 (defvar noweb-narrowing nil
   "If not NIL, the display will always be narrowed to the
@@ -124,21 +128,121 @@
   "If not nil, the keys `@' and `<' will be bound to NOWEB-ELECTRIC-@
 and NOWEB-ELECTRIC-<, respectively.")
 
+(defvar noweb-code-buffer nil
+  "Internal use.")
+(make-variable-buffer-local 'noweb-code-buffer)
+(defvar noweb-doc-buffer nil
+  "Internal use.")
+(make-variable-buffer-local 'noweb-doc-buffer)
+(defvar noweb-chunk-vector nil)
+(make-variable-buffer-local 'noweb-chunk-vector)
 
 ;;; Setup
-(defvar noweb-mode-prefix-map nil
-  "Keymap for noweb mode commands.")
 
-(defvar noweb-mode-menu-map nil
-  "Keymap for noweb mode menu commands.")
+(defvar noweb-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map noweb-mode-prefix
+      (let ((map (make-sparse-keymap)))
+	(define-key map "\C-n" 'noweb-next-chunk)
+	(define-key map "\C-p" 'noweb-previous-chunk)
+	(define-key map "\M-n" 'noweb-goto-next)
+	(define-key map "\M-p" 'noweb-goto-previous)
+	(define-key map "c" 'noweb-next-code-chunk)
+	(define-key map "C" 'noweb-previous-code-chunk)
+	(define-key map "d" 'noweb-next-doc-chunk)
+	(define-key map "D" 'noweb-previous-doc-chunk)
+	(define-key map "g" 'noweb-goto-chunk)
+	(define-key map "\C-l" 'noweb-update-chunk-vector)
+	(define-key map "w" 'noweb-copy-chunk-as-kill)
+	(define-key map "W" 'noweb-copy-chunk-pair-as-kill)
+	(define-key map "k" 'noweb-kill-chunk)
+	(define-key map "K" 'noweb-kill-chunk-pair)
+	(define-key map "m" 'noweb-mark-chunk)
+	(define-key map "M" 'noweb-mark-chunk-pair)
+	(define-key map "n" 'noweb-narrow-to-chunk)
+	(define-key map "N" 'noweb-narrow-to-chunk-pair)
+	(define-key map "t" 'noweb-toggle-narrowing)
+	(define-key map "\t" 'noweb-complete-chunk)
+	(define-key map "q" 'noweb-fill-chunk)
+	(define-key map "i" 'noweb-new-chunk)
+	(define-key map "o" 'noweb-occur)
+	(define-key map "v" 'noweb-mode-version)
+	(define-key map "h" 'noweb-describe-mode)
+	(define-key map "\C-h" 'noweb-describe-mode)
+	map))
+    (define-key map [menu-bar noweb]
+      (cons "Noweb"
+	    (let ((map (make-sparse-keymap "Noweb")))
+	      (define-key map [noweb-mode-version]
+		'("Version" . noweb-mode-version))
+	      (define-key map [noweb-describe-mode]
+		'("Help" . noweb-describe-mode))
+	      (define-key map [separator-noweb-help] '("--"))
+	      (define-key map [noweb-occur]
+		'("Chunk occurrences" . noweb-occur))
+	      (define-key map [noweb-update-chunk-vector]
+		'("Update the chunk vector" . noweb-update-chunk-vector))
+	      (define-key map [noweb-new-chunk]
+		'("Insert new chunk" . noweb-new-chunk))
+	      (define-key map [noweb-fill-chunk]
+		'("Fill current chunk" . noweb-fill-chunk))
+	      (define-key map [noweb-complete-chunk]
+		'("Complete chunk name" . noweb-complete-chunk))
+	      (define-key map [separator-noweb-chunks] '("--"))
+	      (define-key map [noweb-toggle-narrowing]
+		'("Toggle auto narrowing" . noweb-toggle-narrowing))
+	      (define-key map [noweb-narrow-to-chunk-pair]
+		'("Narrow to chunk pair" . noweb-narrow-to-chunk-pair))
+	      (define-key map [noweb-narrow-to-chunk]
+		'("Narrow to chunk" . noweb-narrow-to-chunk))
+	      (define-key map [noweb-mark-chunk-pair]
+		'("Mark chunk pair" . noweb-mark-chunk-pair))
+	      (define-key map [noweb-mark-chunk]
+		'("Mark chunk" . noweb-mark-chunk))
+	      (define-key map [noweb-kill-chunk-pair]
+		'("Kill chunk pair" . noweb-kill-chunk-pair))
+	      (define-key map [noweb-kill-chunk]
+		'("Kill chunk" . noweb-kill-chunk))
+	      (define-key map [noweb-copy-chunk-pair-as-kill]
+		'("Copy chunk pair" . noweb-copy-chunk-pair-as-kill))
+	      (define-key map [noweb-copy-chunk-as-kill]
+		'("Copy chunk" . noweb-copy-chunk-as-kill))
+	      (define-key map [separator-noweb-move] '("--"))
+	      (define-key map [noweb-next-doc-chunk]
+		'("Next documentation chunk" . noweb-next-doc-chunk))
+	      (define-key map [noweb-previous-doc-chunk]
+		'("Previous documentation chunk" . noweb-previous-doc-chunk))
+	      (define-key map [noweb-next-code-chunk]
+		'("Next code chunk" . noweb-next-code-chunk))
+	      (define-key map [noweb-previous-code-chunk]
+		'("Previous code chunk" . noweb-previous-code-chunk))
+	      (define-key map [noweb-goto-chunk]
+		'("Goto chunk" . noweb-goto-chunk))
+	      (define-key map [noweb-goto-next]
+		'("Next chunk of same name" . noweb-goto-next))
+	      (define-key map [noweb-goto-previous]
+		'("Previous chunk of same name" . noweb-goto-previous))
+	      (define-key map [noweb-next-chunk]
+		'("Next chunk" . noweb-next-chunk))
+	      (define-key map [noweb-previous-chunk]
+		'("Previous chunk" . noweb-previous-chunk))
+	      map)))
+    map))
 
 (defvar noweb-mode nil
   "Buffer local variable, T iff this buffer is edited in noweb mode.")
 
+(defvar noweb-normal-fontify-function nil)
+(make-variable-buffer-local 'noweb-normal-fontify-function)
+
 (if (not (assq 'noweb-mode minor-mode-alist))
     (setq minor-mode-alist (append minor-mode-alist
 				   (list '(noweb-mode " Noweb")))))
 
+(if (not (assq 'noweb-mode minor-mode-map-alist))
+    (setq minor-mode-map-alist (append minor-mode-map-alist
+				       (list (cons 'noweb-mode noweb-mode-map)))))
+
 (defun noweb-minor-mode ()
   "Minor meta mode for editing noweb files. See NOWEB-MODE."
   (interactive)
@@ -176,10 +280,8 @@
 
 Filling:
 \\[noweb-fill-chunk] \tfill the chunk at point according to mode.
-\\[noweb-fill-paragraph-chunk] \tfill the paragraph at point, restricted to chunk.
 
 Insertion:
-\\[noweb-insert-mode-line] \tinsert a line to set this file's code mode
 \\[noweb-new-chunk] \tinsert a new chunk at point
 \\[noweb-complete-chunk] \tcomplete the chunk name before point.
 \\[noweb-electric-@] \tinsert a `@' or start a new doc chunk.
@@ -196,171 +298,134 @@
 \\[noweb-mode-version] \tshow noweb-mode's version in the minibuffer
 "
   (interactive)
-  (mapcar 'noweb-make-variable-permanent-local
-	  '(noweb-mode
-	    noweb-narrowing
-	    noweb-chunk-vector
-	    post-command-hook
-	    isearch-mode-hook
-	    isearch-mode-end-hook
-	    noweb-doc-mode
-	    noweb-code-mode))
-  (setq noweb-mode t)
-  (noweb-setup-keymap)
-  (add-hook 'post-command-hook 'noweb-post-command-hook)
+  (funcall noweb-doc-mode)
+  (let ((code-buffer (make-indirect-buffer (current-buffer)
+					   (generate-new-buffer-name
+					    (buffer-name))))
+	(buf (current-buffer)))
+    (setq noweb-code-buffer code-buffer)
+    (setq noweb-doc-buffer buf)
+    (when (boundp 'font-lock-fontify-region-function)
+      (setq noweb-normal-fontify-function font-lock-fontify-region-function)
+      (set (make-local-variable 'font-lock-fontify-region-function)
+	   #'noweb-font-lock-region))
+    (with-current-buffer code-buffer
+      (let ((late-noweb-mode (symbol-function 'noweb-mode)))
+	(unwind-protect
+	    (progn (fset 'noweb-mode 'ignore)
+		   (hack-local-variables))
+	  (fset 'noweb-mode late-noweb-mode)))
+      (funcall noweb-code-mode)
+      (let ((late-noweb-mode (symbol-function 'noweb-mode)))
+	(unwind-protect
+	    (progn (fset 'noweb-mode 'ignore)
+		   (hack-local-variables))
+	  (fset 'noweb-mode late-noweb-mode)))
+      (set (make-local-variable 'noweb-mode) t)
+      (add-hook 'post-command-hook 'noweb-post-command-hook nil t)
+      (when (boundp 'font-lock-fontify-region-function)
+	(setq noweb-normal-fontify-function font-lock-fontify-region-function)
+	(set (make-local-variable 'font-lock-fontify-region-function)
+	     #'noweb-font-lock-region))
+      (when (or (local-variable-p 'font-lock-keywords)
+		(local-variable-p 'font-lock-defaults))
+	(font-lock-add-keywords nil '(("\\(^\\|[^@]\\)<<\\([^>]+\\)>>="
+				       (2 font-lock-type-face))
+				      ("\\(^\\|[^@]\\)<<\\([^>]+\\)>>"
+				       (2 font-lock-function-name-face)))))
+      (add-hook 'isearch-mode-hook 'noweb-note-isearch-mode nil t)
+      (add-hook 'isearch-mode-end-hook 'noweb-note-isearch-mode-end nil t)
+      ;; Kill the base buffer along with the indirect one; careful not
+      ;; to infloop.
+      (add-hook (make-local-hook 'kill-buffer-hook)
+		'(lambda ()
+		   (setq kill-buffer-hook nil)
+		   (kill-buffer (buffer-base-buffer (current-buffer))))
+		t t)
+      (set (make-local-variable 'noweb-mode) t)
+      (setq noweb-doc-buffer buf)
+      (setq noweb-code-buffer (current-buffer))))
+  (set (make-local-variable 'noweb-mode) t)
+  (add-hook 'post-command-hook 'noweb-post-command-hook nil t)
   (add-hook 'noweb-select-doc-mode-hook 'noweb-auto-fill-doc-mode)
   (add-hook 'noweb-select-code-mode-hook 'noweb-auto-fill-code-mode)
-  (add-hook 'isearch-mode-hook 'noweb-note-isearch-mode)
-  (add-hook 'isearch-mode-end-hook 'noweb-note-isearch-mode-end)
+  (add-hook 'isearch-mode-hook 'noweb-note-isearch-mode nil t)
+  (add-hook 'isearch-mode-end-hook 'noweb-note-isearch-mode-end nil t)
   (run-hooks 'noweb-mode-hook)
   (message "nobweb mode: use `M-x noweb-describe-mode' for further information"))
 
-(defun noweb-setup-keymap ()
-  "Setup the noweb-mode keymap.  This function is rerun every time the
-major modes changes, because it might have grabbed the keys."
-  (if noweb-mode-prefix-map
-      nil
-    (setq noweb-mode-prefix-map (make-sparse-keymap))
-    (noweb-bind-keys))
-  (if noweb-mode-menu-map
-      nil
-    (setq noweb-mode-menu-map (make-sparse-keymap "Noweb"))
-    (noweb-bind-menu))
-  (if noweb-electric-@-and-<
-      (progn
-	(local-set-key "@" 'noweb-electric-@)
-	(local-set-key "<" 'noweb-electric-<)))
-  (local-set-key "\M-q" 'noweb-fill-paragraph-chunk)
-  (local-set-key noweb-mode-prefix noweb-mode-prefix-map)
-  (local-set-key [menu-bar noweb] (cons "Noweb" noweb-mode-menu-map)))
-
-    (defun noweb-bind-keys ()
-      "Establish noweb mode key bindings."
-      (define-key noweb-mode-prefix-map "\C-n" 'noweb-next-chunk)
-      (define-key noweb-mode-prefix-map "\C-p" 'noweb-previous-chunk)
-      (define-key noweb-mode-prefix-map "\M-n" 'noweb-goto-next)
-      (define-key noweb-mode-prefix-map "\M-m" 'noweb-insert-mode-line)
-      (define-key noweb-mode-prefix-map "\M-p" 'noweb-goto-previous)
-      (define-key noweb-mode-prefix-map "c" 'noweb-next-code-chunk)
-      (define-key noweb-mode-prefix-map "C" 'noweb-previous-code-chunk)
-      (define-key noweb-mode-prefix-map "d" 'noweb-next-doc-chunk)
-      (define-key noweb-mode-prefix-map "D" 'noweb-previous-doc-chunk)
-      (define-key noweb-mode-prefix-map "g" 'noweb-goto-chunk)
-      (define-key noweb-mode-prefix-map "\C-l" 'noweb-update-chunk-vector)
-      (define-key noweb-mode-prefix-map "\M-l" 'noweb-update-chunk-vector)
-      (define-key noweb-mode-prefix-map "w" 'noweb-copy-chunk-as-kill)
-      (define-key noweb-mode-prefix-map "W" 'noweb-copy-chunk-pair-as-kill)
-      (define-key noweb-mode-prefix-map "k" 'noweb-kill-chunk)
-      (define-key noweb-mode-prefix-map "K" 'noweb-kill-chunk-pair)
-      (define-key noweb-mode-prefix-map "m" 'noweb-mark-chunk)
-      (define-key noweb-mode-prefix-map "M" 'noweb-mark-chunk-pair)
-      (define-key noweb-mode-prefix-map "n" 'noweb-narrow-to-chunk)
-      (define-key noweb-mode-prefix-map "N" 'noweb-narrow-to-chunk-pair)
-      (define-key noweb-mode-prefix-map "t" 'noweb-toggle-narrowing)
-      (define-key noweb-mode-prefix-map "\t" 'noweb-complete-chunk)
-      (define-key noweb-mode-prefix-map "q" 'noweb-fill-chunk)
-      (define-key noweb-mode-prefix-map "i" 'noweb-new-chunk)
-      (define-key noweb-mode-prefix-map "o" 'noweb-occur)
-      (define-key noweb-mode-prefix-map "v" 'noweb-mode-version)
-      (define-key noweb-mode-prefix-map "h" 'noweb-describe-mode)
-      (define-key noweb-mode-prefix-map "\C-h" 'noweb-describe-mode))
-    
-  (defun noweb-bind-menu ()
-    "Establish noweb mode menu bindings."
-    (define-key noweb-mode-menu-map [noweb-mode-version]
-      '("Version" . noweb-mode-version))
-    (define-key noweb-mode-menu-map [noweb-describe-mode]
-      '("Help" . noweb-describe-mode))
-    (define-key noweb-mode-menu-map [separator-noweb-help] '("--"))
-    (define-key noweb-mode-menu-map [noweb-occur]
-      '("Chunk occurrences" . noweb-occur))
-    (define-key noweb-mode-menu-map [noweb-update-chunk-vector]
-      '("Update the chunk vector" . noweb-update-chunk-vector))
-    (define-key noweb-mode-menu-map [noweb-new-chunk]
-      '("Insert new chunk" . noweb-new-chunk))
-    (define-key noweb-mode-menu-map [noweb-fill-chunk]
-      '("Fill current chunk" . noweb-fill-chunk))
-    (define-key noweb-mode-menu-map [noweb-complete-chunk]
-      '("Complete chunk name" . noweb-complete-chunk))
-    (define-key noweb-mode-menu-map [separator-noweb-chunks] '("--"))
-    (define-key noweb-mode-menu-map [noweb-toggle-narrowing]
-      '("Toggle auto narrowing" . noweb-toggle-narrowing))
-    (define-key noweb-mode-menu-map [noweb-narrow-to-chunk-pair]
-      '("Narrow to chunk pair" . noweb-narrow-to-chunk-pair))
-    (define-key noweb-mode-menu-map [noweb-narrow-to-chunk]
-      '("Narrow to chunk" . noweb-narrow-to-chunk))
-    (define-key noweb-mode-menu-map [noweb-mark-chunk-pair]
-      '("Mark chunk pair" . noweb-mark-chunk-pair))
-    (define-key noweb-mode-menu-map [noweb-mark-chunk]
-      '("Mark chunk" . noweb-mark-chunk))
-    (define-key noweb-mode-menu-map [noweb-kill-chunk-pair]
-      '("Kill chunk pair" . noweb-kill-chunk-pair))
-    (define-key noweb-mode-menu-map [noweb-kill-chunk]
-      '("Kill chunk" . noweb-kill-chunk))
-    (define-key noweb-mode-menu-map [noweb-copy-chunk-pair-as-kill]
-      '("Copy chunk pair" . noweb-copy-chunk-pair-as-kill))
-    (define-key noweb-mode-menu-map [noweb-copy-chunk-as-kill]
-      '("Copy chunk" . noweb-copy-chunk-as-kill))
-    (define-key noweb-mode-menu-map [separator-noweb-move] '("--"))
-    (define-key noweb-mode-menu-map [noweb-next-doc-chunk]
-      '("Next documentation chunk" . noweb-next-doc-chunk))
-    (define-key noweb-mode-menu-map [noweb-previous-doc-chunk]
-      '("Previous documentation chunk" . noweb-previous-doc-chunk))
-    (define-key noweb-mode-menu-map [noweb-next-code-chunk]
-      '("Next code chunk" . noweb-next-code-chunk))
-    (define-key noweb-mode-menu-map [noweb-previous-code-chunk]
-      '("Previous code chunk" . noweb-previous-code-chunk))
-    (define-key noweb-mode-menu-map [noweb-goto-chunk]
-      '("Goto chunk" . noweb-goto-chunk))
-    (define-key noweb-mode-menu-map [noweb-goto-next]
-      '("Next chunk of same name" . noweb-goto-next))
-    (define-key noweb-mode-menu-map [noweb-goto-previous]
-      '("Previous chunk of same name" . noweb-goto-previous))
-    (define-key noweb-mode-menu-map [noweb-next-chunk]
-      '("Next chunk" . noweb-next-chunk))
-    (define-key noweb-mode-menu-map [noweb-previous-chunk]
-      '("Previous chunk" . noweb-previous-chunk)))
-  
-(defun noweb-make-variable-permanent-local (var)
-  "Declare VAR buffer local, but protect it from beeing killed
-by major mode changes."
-  (make-variable-buffer-local var)
-  (put var 'permanent-local 't))
+;; Like save-buffer-state in font-lock.
+(defmacro noweb-save-buffer-state (&rest body)
+  (let ((modified (make-symbol "modified")))
+    `(let* ((,modified (buffer-modified-p)) (buffer-undo-list t)
+	    (inhibit-read-only t) (inhibit-point-motion-hooks t)
+	    (inhibit-modification-hooks t)
+	    deactivate-mark buffer-file-name buffer-file-truename)
+       ,@body
+       (when (and (not ,modified) (buffer-modified-p))
+	 (set-buffer-modified-p nil)))))
+(def-edebug-spec noweb-save-buffer-state t)
+
+(defun noweb-font-lock-region (beg end loudly)
+  (noweb-save-buffer-state ()
+    (font-lock-unfontify-region beg end)
+    (save-restriction
+      (widen)
+      (goto-char beg)
+      (save-excursion
+	(save-window-excursion
+	  (let ((beg beg)
+		last)
+	    (while (< (point) end)
+	      (setq last (point))
+	      (noweb-select-mode)
+	      (save-restriction
+		(noweb-narrow-to-chunk)
+		(if font-lock-mode
+		    (funcall noweb-normal-fontify-function
+			     (point-min) (point-max) loudly))
+		(goto-char (point-max)))
+	      (unless (and (noweb-next-chunk-any) (> (point) last))
+		(goto-char (point-max))))))))
+   ;; In case font-lock isn't done for code or doc chunks.
+   (put-text-property beg end 'fontified t)))
 
 (defun noweb-note-isearch-mode ()
   "Take note of an incremental search in progress"
-  (remove-hook 'post-command-hook 'noweb-post-command-hook))
+  (remove-hook 'post-command-hook 'noweb-post-command-hook t))
 
 (defun noweb-note-isearch-mode-end ()
   "Take note of an incremental search having ended"
-  (add-hook 'post-command-hook 'noweb-post-command-hook))
+  (add-hook 'post-command-hook 'noweb-post-command-hook nil t))
 
 (defun noweb-post-command-hook ()
   "The hook being run after each command in noweb mode."
-  (noweb-select-mode)
-  ;; reinstall our keymap if the major mode screwed it up:
-  (noweb-setup-keymap))
+  (noweb-select-mode))
 
 
 ;;; Chunks
 
+(defun noweb-code-mode-p ()
+  (stringp (car (noweb-find-chunk))))
+
 (defun noweb-update-chunk-vector ()
   "Scan the whole buffer and place a marker at each \"^@\" and \"^<<\".
 Record them in NOWEB-CHUNK-VECTOR."
   (interactive)
   (save-excursion
+    (set-buffer noweb-doc-buffer)
     (goto-char (point-min))
     (let ((chunk-list (list (cons 'doc (point-marker)))))
-      (while (re-search-forward "^\\(@\\( \\|$\\|\\( %def\\)\\)\\|<<\\(.*\\)>>=\\)" nil t)
+      (while (re-search-forward "^\\(@\\( %def\\)?\\|<<\\(.*\\)>>=\\)" nil t)
 	(goto-char (match-beginning 0))
-	;; If the 3rd subexpression matched @ %def, we're still in a code
+	;; If the second subexpression matched, we're still in a code
 	;; chunk (sort of), so don't place a marker here.
-	(if (not (match-beginning 3))
+	(if (not (match-beginning 2))
 	    (setq chunk-list
-		  ;; If the 4th subexpression matched inside <<...>>, we're seeing
+		  ;; If the third subexpression matched, we're seeing
 		  ;; a new code chunk.
-		  (cons (cons (if (match-beginning 4)
-				  (buffer-substring (match-beginning 4) (match-end 4))
+		  (cons (cons (if (match-beginning 3)
+				  (buffer-substring (match-beginning 3) (match-end 3))
 				'doc)
 			      (point-marker))
 			chunk-list))
@@ -379,7 +444,18 @@
 			chunk-list))))
 	(next-line 1))
       (setq chunk-list (cons (cons 'doc (point-max-marker)) chunk-list))
-      (setq noweb-chunk-vector (vconcat (reverse chunk-list))))))
+      (let ((vec (vconcat (reverse chunk-list))))
+	(with-current-buffer noweb-doc-buffer
+	  (setq noweb-chunk-vector vec))
+	(with-current-buffer noweb-code-buffer
+	  (setq noweb-chunk-vector
+		(apply 'vector
+		       (mapcar (lambda (pair)
+			  (cons (car pair)
+				(set-marker (make-marker)
+					    (cdr pair)
+					    noweb-code-buffer)))
+			vec))))))))
 
 (defun noweb-find-chunk ()
   "Return a pair consisting of the name (or 'DOC) and the
@@ -396,7 +472,7 @@
   (if (= hi (1+ low))
       low
     (let ((med (/ (+ low hi) 2)))
-      (if (<= (point) (cdr (aref noweb-chunk-vector med)))
+      (if (<= (point) (marker-position (cdr (aref noweb-chunk-vector med))))
 	  (noweb-find-chunk-index low med)
 	(noweb-find-chunk-index med hi)))))
 
@@ -526,7 +602,7 @@
   (interactive)
   (save-restriction
     (noweb-narrow-to-chunk)
-    (if (stringp (car (noweb-find-chunk)))
+    (if (noweb-code-mode-p)
 	(progn
 	  ;; Narrow to the code section proper; w/o the first and any
 	  ;; index declaration lines.
@@ -548,32 +624,6 @@
 	(fill-region (point-min) (point-max))
 	(noweb-restore-code-quotes quote-list)))))
 
-(defun noweb-fill-paragraph-chunk (&optional justify)
-  "Fill a paragraph in the current chunk."
-  (interactive "P")
-  (noweb-update-chunk-vector)
-  (save-restriction
-    (noweb-narrow-to-chunk)
-    (if (stringp (car (noweb-find-chunk)))
-	(progn
-	  ;; Narrow to the code section proper; w/o the first and any
-	  ;; index declaration lines.
-	  (narrow-to-region (progn
-			      (goto-char (point-min))
-			      (forward-line 1)
-			      (point))
-			    (progn
-			      (goto-char (point-max))
-			      (forward-line -1)
-			      (while (looking-at "@")
-				(forward-line -1))
-			      (forward-line 1)
-			      (point)))
-	  (fill-paragraph justify))
-      (let ((quote-list (noweb-hide-code-quotes)))
-	(fill-paragraph justify)
-	(noweb-restore-code-quotes quote-list)))))
-
 (defun noweb-auto-fill-doc-chunk ()
   "Replacement for `do-auto-fill'."
   (save-restriction
@@ -672,9 +722,22 @@
   "Return the sign of N."
   (if (< n 0) -1 1))
 
+(defun noweb-next-chunk-any ()
+  (widen)
+  (let ((start (noweb-find-chunk-index-buffer)))
+    (if (>= (1+ start) (length noweb-chunk-vector))
+	nil
+      (goto-char (marker-position (cdr (aref noweb-chunk-vector (1+ start)))))
+      (forward-char 1)
+      (let ((point (point)))
+	(noweb-select-mode)
+	(goto-char point)
+	point))))
+
 (defun noweb-next-doc-chunk (&optional cnt)
   "Goto to the Nth documentation chunk from point."
   (interactive "p")
+  (unless cnt (setq cnt 1))
   (widen)
   (let ((start (noweb-find-chunk-index-buffer))
 	(i 1))
@@ -691,11 +754,12 @@
 (defun noweb-previous-doc-chunk (&optional n)
   "Goto to the -Nth documentation chunk from point."
   (interactive "p")
-  (noweb-next-doc-chunk (- n)))
+  (noweb-next-doc-chunk (- (or n 1))))
 
 (defun noweb-next-code-chunk (&optional cnt)
   "Goto to the Nth code chunk from point."
   (interactive "p")
+  (unless cnt (setq cnt 1))
   (widen)
   (let ((start (noweb-find-chunk-index-buffer))
 	(i 1))
@@ -712,12 +776,13 @@
 (defun noweb-previous-code-chunk (&optional n)
   "Goto to the -Nth code chunk from point."
   (interactive "p")
-  (noweb-next-code-chunk (- n)))
+  (noweb-next-code-chunk (- (or n 1))))
 
 (defun noweb-next-chunk (&optional n)
   "If in a documentation chunk, goto to the Nth documentation
 chunk from point, else goto to the Nth code chunk from point."
   (interactive "p")
+  (unless n (setq n 1))
   (if (stringp (car (aref noweb-chunk-vector
 			  (noweb-find-chunk-index-buffer))))
       (noweb-next-code-chunk n)
@@ -727,7 +792,7 @@
   "If in a documentation chunk, goto to the -Nth documentation
 chunk from point, else goto to the -Nth code chunk from point."
   (interactive "p")
-  (noweb-next-chunk (- n)))
+  (noweb-next-chunk (- (or n 1))))
 
 (defvar noweb-chunk-history nil
   "")
@@ -842,12 +907,6 @@
     (insert "@ %def \n"))
   (noweb-update-chunk-vector))
 
-(defun noweb-at-beginning-of-line ()
-  (equal (save-excursion
-	   (beginning-of-line)
-	   (point))
-	 (point)))
-
 (defun noweb-electric-@ (arg)
   "Smart incarnation of `@', starting a new documentation chunk, maybe.
 If given an numerical argument, it will act just like the dumb `@'.
@@ -856,8 +915,8 @@
   (interactive "P")
   (if arg
       (self-insert-command (if (numberp arg) arg 1))
-    (if (and (noweb-at-beginning-of-line)
-	     (stringp (car (noweb-find-chunk))))
+    (if (and (bolp)
+	     (noweb-code-mode-p))
 	(progn
 	  (insert "@ ")
 	  (noweb-update-chunk-vector))
@@ -872,8 +931,8 @@
   (interactive "P")
   (if arg
       (self-insert-command (if (numberp arg) arg 1))
-    (if (and (noweb-at-beginning-of-line)
-	     (not (stringp (car (noweb-find-chunk)))))
+    (if (and (bolp)
+	     (not (noweb-code-mode-p)))
 	(progn
 	  (insert "<<")
 	  (save-excursion
@@ -889,19 +948,25 @@
 (defun noweb-select-mode ()
   "Select NOWEB-DOC-MODE or NOWEB-CODE-MODE, as appropriate."
   (interactive)
-  (if (stringp (car (noweb-find-chunk)))
-      ;; Inside a code chunk
-      (if (equal major-mode noweb-code-mode)
-	  nil
-	(funcall noweb-code-mode)
-	(run-hooks 'noweb-select-code-mode-hook)
-	(run-hooks 'noweb-select-mode-hook))
-    ;; Inside a documentation chunk
-    (if (equal major-mode noweb-doc-mode)
-	nil
-      (funcall noweb-doc-mode)
-      (run-hooks 'noweb-select-doc-mode-hook)
-      (run-hooks 'noweb-select-mode-hook))))
+  (let ((point (point))
+	(window-start (window-start)))
+    (if (noweb-code-mode-p)
+	;; Inside a code chunk
+	(when (and (eq (current-buffer) noweb-doc-buffer)
+		   (buffer-live-p noweb-code-buffer))
+	  (bury-buffer noweb-doc-buffer)
+	  (switch-to-buffer noweb-code-buffer)
+	  (goto-char point)
+	  (set-window-start (get-buffer-window noweb-code-buffer) window-start)
+	  (run-hooks 'noweb-select-code-mode-hook))
+      ;; Inside a documentation chunk
+      (when (and (eq (current-buffer) noweb-code-buffer))
+	(bury-buffer noweb-code-buffer)
+	(switch-to-buffer noweb-doc-buffer)
+	(goto-char point)
+	(set-window-start (get-buffer-window noweb-code-buffer) window-start)
+	(run-hooks 'noweb-select-doc-mode-hook)))
+    (run-hooks 'noweb-select-mode-hook)))
 
 (defun noweb-set-doc-mode (mode)
   "Change the major mode for editing documentation chunks."
@@ -927,11 +992,6 @@
   (interactive)
   (describe-function 'noweb-mode))
 
-(defun noweb-insert-mode-line (arg)
-  "Insert line that will set the noweb mode of this file in emacs"
-  (interactive "CNoweb code mode for this file: ")
-  (insert "% -*- mode: Noweb; noweb-code-mode: " (symbol-name arg) " -*-\n"))
-
 
 ;;; Debugging
 
@@ -949,129 +1009,6 @@
 
 (run-hooks 'noweb-mode-load-hook)
 (provide 'noweb-mode)
-
-
-;;; Code-dependent highlighting
-
-;;  *****
-;;  
-;;  Adding highlighting to noweb-mode.el
-;;  
-;;  Here is a description of how one can add highlighting via the
-;;  font-lock package to noweb buffers.  It uses the hooks provided by
-;;  noweb-mode.el.  The solution provides the following features:
-;;  1) The documentation chunks are highlighted in the noweb-doc-mode
-;;  (e.g., LaTeX).
-;;  2) The code chunks without mode comments (-*- mode -*-) arew
-;;  highlighted in the noweb-code-mode.
-;;  3) The code chunks with mode comments (-*- mode -*-) one the first
-;;  line of the chunk, are highlighted in the mode in the comment.
-;;  
-;;  For example, given the file:
-;;  
-;;    % -*- mode: Noweb; noweb-code-mode: c-mode -*-
-;;  
-;;    \begin{itemize}
-;;    \item a main routine written in C,
-;;    \item a log configuration file parser written in YACC, and
-;;    \item a lexical analyzer written in Lex.
-;;    \end{itemize}
-;;  
-;;    <<warning c comment>>=
-;;    /* DO NOT EDIT ME! */
-;;    /* This file was automatically generated from %W% (%G%). */
-;;    @
-;;  
-;;    <<warning nroff comment>>=
-;;    .\" -*- nroff -*-
-;;    .\" DO NOT EDIT ME!
-;;    .\" This file was automatically generated from %W% (%G%).
-;;    @
-;;  
-;;  The LaTeX list is highlighted in latex-mode (the default noweb doc
-;;  mode), the chunk <<warning c comment>> is highlighted in c-mode (the
-;;  default noweb code mode), and the chunk <<warning nroff comment>> is
-;;  highlighted in nroff-mode due to the "-*- nroff -*-" comment.
-;;  
-;;  Chunks are highlighted each time point moves into them from a
-;;  different mode.
-;;  
-;;  The solution has the following drawbacks:
-;;  1) It won't work if global-font-lock-mode is set.
-;;  2) The ighlighting sometimes get confuses.  For example, a "$" in a
-;;  previous code chunk throws the highlighting in the LaTeX math mode.
-;;  (Note this problem exist in LaTeX highlighting if the "$" is in a
-;;  verbatim as well.)  Similarly a lone "'" in a previous LaTeX chunk can
-;;  cause problems in code mode highlighting.
-;;  
-;;  To use highlighing, add the following to your .emacs:
-;;  
-;;  ;;; We need this variable since we will be overwriting the
-;;  ;;; noweb-code-mode from time to time.
-;;  (defvar my-noweb-main-code-mode nil
-;;    "Variable used to save the default noweb-code-mode.")
-;;  
-;;  (defun my-set-noweb-code-mode (beg-pt end-pt)
-;;    "Set the noweb-code-mode for the chunk between BEG-PT and END-PT."
-;;    (let (beg end done mode)
-;;  	;; Reset code-mode to default and then check for a mode comment.
-;;  	(setq mode my-noweb-main-code-mode)
-;;  	(save-excursion
-;;  	  (goto-char beg-pt)
-;;  	  (beginning-of-line 2)
-;;  	  (and (search-forward "-*-"
-;;  			       (save-excursion (end-of-line) (point))
-;;  			       t)
-;;  	       (progn
-;;  		 (skip-chars-forward " \t")
-;;  		 (setq beg (point))
-;;  		 (search-forward "-*-"
-;;  				 (save-excursion (end-of-line) (point))
-;;  				 t))
-;;  	       (progn
-;;  		 (forward-char -3)
-;;  		 (skip-chars-backward " \t")
-;;  		 (setq end (point))
-;;  		 (goto-char beg)
-;;  		 (setq mode (intern
-;;  			     (concat
-;;  			      (downcase (buffer-substring beg end))
-;;  			      "-mode")))))
-;;  	  (noweb-set-code-mode mode))))
-;;  
-;;  (defun my-noweb-pre-select-code-mode-hook ()
-;;    "Set the code mode for the current chunk."
-;;    (let ((r (noweb-chunk-region)))
-;;  	(my-set-noweb-code-mode (car r) (cdr r))
-;;  	t))
-;;  
-;;  (defun my-noweb-select-mode-hook ()
-;;    "Fontify the current chunk based on the chunks mode."
-;;    ;; If this is the first time, save the default noweb-code-mode.
-;;    (if my-noweb-first-time
-;;  	  (progn
-;;  	    (setq my-noweb-first-time nil)
-;;  	    (setq my-noweb-main-code-mode noweb-code-mode)))
-;;    (font-lock-set-defaults)
-;;    (let ((r (noweb-chunk-region)))
-;;  	(save-excursion
-;;  	  (font-lock-fontify-region (car r) (cdr r))
-;;  	  t)))
-;;  
-;;  (defun my-noweb-mode-hook()
-;;    (setq my-noweb-first-time t))
-;;  
-;;  (add-hook 'noweb-mode-hook 'my-noweb-mode-hook)
-;;  (add-hook 'noweb-select-mode-hook 'my-noweb-select-mode-hook)
-;;  (add-hook 'noweb-pre-select-code-mode-hook 'my-noweb-pre-select-code-mode-hook)
-;;  
-;;  *****
-;;  
-;;  Adnan Yaqub (AYaqub@orga.com)
-;;  ORGA Kartensysteme GmbH // An der Kapelle 2 // D-33104 Paderborn // Germany
-;;  Tel. +49 5254 991-823 //Fax. +49 5254 991-749
-
-
 
 
 ;; Local Variables:
