diff -urN WiLiKi.orig/src/wiliki/core.scm WiLiKi/src/wiliki/core.scm
--- WiLiKi.orig/src/wiliki/core.scm	2011-08-01 23:20:20.000000000 +0900
+++ WiLiKi/src/wiliki/core.scm	2011-08-11 17:41:50.000000000 +0900
@@ -84,6 +84,8 @@
           wiliki:contains-spam?
           wiliki:ip-blacklist wiliki:ip-blacklist-append!
           wiliki:from-blacklisted-ip?
+
+          wiliki:renew-db-handler
           ))
 (select-module wiliki.core)
 
@@ -788,6 +790,12 @@
                    :muser (ref page 'muser)))
       (display (ref page 'content)))))
 
+(define-method wiliki:renew-db-handler ((self <wiliki>) . opts)
+  ;; !!! if you override this method,
+  ;; !!! be careful to avoid to infinite loop by call wiliki:db-put! .
+  ;; !!! (instead of wiliki:db-put!, you can call wiliki:db-raw-put! .)
+  (next-method))
+
 ;; Raw acessors
 (define (wiliki:db-raw-get key . maybe-default)
   (apply dbm-get (check-db) key maybe-default))
@@ -814,6 +822,7 @@
       (unless donttouch
         (let1 r (alist-delete key (read-recent-changes db))
           (write-recent-changes db (acons key (ref page 'mtime) r))))
+      (wiliki:renew-db-handler (wiliki))
       )))
 
 (define (wiliki:db-touch! key)
@@ -826,6 +835,7 @@
   (let* ((db (check-db))
          (r (alist-delete key (read-recent-changes db))))
     (dbm-delete! db key)
+    (wiliki:renew-db-handler (wiliki))
     (write-recent-changes db r)))
 
 (define (wiliki:db-recent-changes)
diff -urN WiLiKi.orig/src/wiliki/format.scm WiLiKi/src/wiliki/format.scm
--- WiLiKi.orig/src/wiliki/format.scm	2011-08-01 23:20:20.000000000 +0900
+++ WiLiKi/src/wiliki/format.scm	2011-08-09 22:16:22.000000000 +0900
@@ -63,6 +63,7 @@
           wiliki:sxml->stree
           wiliki:format-diff-pre
           wiliki:format-diff-line
+          wiliki:fmt-line-procs
           )
   )
 (select-module wiliki.format)
@@ -161,13 +162,28 @@
   (string-append "H-" (number->string (hash headings) 36)))
 
 ;; Backward compatibility
-(define wiliki:format-line-plainly wiliki-remove-markup)
+(define (wiliki:format-line-plainly . args)
+  (parameterize ((fmt-line:proc-list (wiliki:fmt-line-procs (the-formatter))))
+    (apply wiliki-remove-markup args)))
   
 ;; Page ======================================================
 
+(define-method wiliki:fmt-line-procs ((self <wiliki-formatter-base>))
+  (list
+    fmt-line:smacro
+    ;fmt-line:code ; included in smacro
+    fmt-line:bold
+    fmt-line:italic
+    fmt-line:nl
+    fmt-line:bracket
+    fmt-line:uri
+    fmt-line:mailto
+    ))
+
 (define (wiliki:format-content page)
   (define (do-fmt content)
-    (expand-page (wiliki-parse-string content)))
+    (parameterize ((fmt-line:proc-list (wiliki:fmt-line-procs (the-formatter))))
+      (expand-page (wiliki-parse-string content))))
   (cond ((string? page) (do-fmt page))
         ((is-a? page <wiliki-page>)
          (if (wiliki-page-circular? page)
diff -urN WiLiKi.orig/src/wiliki/parse.scm WiLiKi/src/wiliki/parse.scm
--- WiLiKi.orig/src/wiliki/parse.scm	2011-08-01 23:20:20.000000000 +0900
+++ WiLiKi/src/wiliki/parse.scm	2011-08-12 22:21:42.000000000 +0900
@@ -30,8 +30,20 @@
   (use srfi-13)
   (use text.tree)
   (use util.match)
-  (export wiliki-parse wiliki-parse-string
-          wiliki-remove-markup))
+  (use gauche.parameter)
+  (export wiliki-parse wiliki-parse-string wiliki-remove-markup
+          fmt-line:next-proc
+          fmt-line:proc-list
+          fmt-line:smacro
+          fmt-line:code
+          fmt-line:bold
+          fmt-line:italic
+          fmt-line:nl
+          fmt-line:bracket
+          fmt-line:uri
+          fmt-line:mailto
+          regexp-fold
+          ))
 (select-module wiliki.parse)
 
 ;; This module provides basic procedues to parse Wiki markup text
@@ -78,9 +90,36 @@
 ;; Parser body
 ;;
 
-;; Find wiki name in the line.
-;; Correctly deal with nested "[[" and "]]"'s.
-(define (fmt-line ctx line seed)
+(define fmt-line:proc-list (make-parameter '()))
+(define fmt-line:next-proc (make-parameter cons))
+(define (fmt-line:mailto line seed)
+  (regexp-fold
+   #/\[(mailto:[-\w]+(?:\.[-\w]+)*@[-\w]+(?:\.[-\w]+)+)\s+(.*)\]/
+   (fmt-line:next-proc)
+   (lambda (match seed)
+     (cons `(a (@ (href ,(match 1))) ,(match 2)) seed))
+   seed line))
+(define (fmt-line:uri line seed)
+  (regexp-fold
+   #/(\[)?(http|https|ftp):(\/\/[^\/?#\s]*)?([^?#\s]*(\?[^#\s]*)?(#\S*)?)(\s([^\]]+)\])?/
+   (fmt-line:next-proc)
+   (lambda (match seed)
+     ;; NB: If a server name is not given, we omit the protocol scheme in
+     ;; href attribute, so that the same page would work on both
+     ;; http and https access. (Patch from YAEGASHI Takeshi).
+     (let ((scheme (match 2))
+           (server (match 3))
+           (path   (match 4))
+           (openp  (match 1))
+           (name   (match 8)))
+       (let1 url (if server #`",|scheme|:,|server|,|path|" path)
+         (if (and openp name)
+           (cons `(a (@ (href ,url)) ,name) seed)
+           (list* (if openp "[" "")
+                  `(a (@ (href ,url)) ,scheme ":" ,(or server "") ,path)
+                  seed)))))
+   seed line))
+(define (fmt-line:bracket line seed)
   ;; parse to next "[[" or "]]"
   (define (token s)
     (cond ((#/\[\[|\]\]/ s)
@@ -97,94 +136,75 @@
              (values (tree->string (reverse (cons pre in))) post))
             (else
              (find-closer post (- level 1) (list* "]]" pre in))))))
-  ;; deal with other inline items between wikinames
-  ;; NB: the precedence is embedded to the order of calling regexp-fold.
-  (define (mailto line seed)
-    (regexp-fold
-     #/\[(mailto:[-\w]+(?:\.[-\w]+)*@[-\w]+(?:\.[-\w]+)+)\s+(.*)\]/
-     cons
-     (lambda (match seed)
-       (cons `(a (@ (href ,(match 1))) ,(match 2)) seed))
-     seed line))
-  (define (uri line seed)
-    (regexp-fold
-     #/(\[)?(http|https|ftp):(\/\/[^\/?#\s]*)?([^?#\s]*(\?[^#\s]*)?(#\S*)?)(\s([^\]]+)\])?/
-     mailto
-     (lambda (match seed)
-       ;; NB: If a server name is not given, we omit the protocol scheme in
-       ;; href attribute, so that the same page would work on both
-       ;; http and https access. (Patch from YAEGASHI Takeshi).
-       (let ((scheme (match 2))
-             (server (match 3))
-             (path   (match 4))
-             (openp  (match 1))
-             (name   (match 8)))
-         (let1 url (if server #`",|scheme|:,|server|,|path|" path)
-           (if (and openp name)
-             (cons `(a (@ (href ,url)) ,name) seed)
-             (list* (if openp "[" "")
-                    `(a (@ (href ,url)) ,scheme ":" ,(or server "") ,path)
-                    seed)))))
-     seed line))
-  (define (bracket line seed)
-    (if (string-null? line)
-      seed
-      (receive (pre post) (string-scan line "[[" 'both)
-        (if pre
-          (receive (wikiname rest) (find-closer post 0 '())
-            (if wikiname
-              (bracket rest
-                       (cons `(wiki-name ,wikiname) (uri pre seed)))
-              (uri rest (uri pre seed))))
-          (uri line seed)))))
-  (define (nl line seed)
-    (regexp-fold
-     #/~%/
-     bracket
-     (lambda (match seed) (cons '(br) seed))
-     seed line))
-  ;; NB: we remove empty bold and italic, for backward compatibility
-  (define (italic line seed)
-    (regexp-fold
-     #/''([^'].*?)?''/
-     nl
-     (lambda (match seed)
-       (if (or (not (match 1)) (string-null? (match 1)))
-         seed
-         (cons `(em ,@(reverse! (nl (match 1) '()))) seed)))
-     seed line))
-  (define (bold line seed)
-    (regexp-fold
-     #/'''([^'].*?)?'''/
-     italic
-     (lambda (match seed)
-       (if (or (not (match 1)) (string-null? (match 1)))
-         seed
-         (cons `(strong ,@(reverse! (nl (match 1) '()))) seed)))
-     seed line))
-  (define (code line seed)
-    (regexp-fold
-     #/"""([^\"].*?)?"""/
-     bold
-     (lambda (match seed)
-       (if (or (not (match 1)) (string-null? (match 1)))
-         seed
-         (cons `(code ,@(reverse! (nl (match 1) '()))) seed)))
-     seed line))
-  (define (smacro line seed)
-    (if (string-null? line)
-      seed
-      (receive (pre post) (string-scan line "##(" 'both)
-        (if pre
-          (receive (expr rest) (read-macro-expr post)
-            ;; NB: we should handle distinction of inline and block elements
-            ;; here.  It requires some trick, so for now I leave it.
-            (if expr
-              (smacro rest (cons `(wiki-macro ,@expr) (bold pre seed)))
-              (smacro post (bold (string-append pre "##(") seed))))
-          (code line seed)))))
+  (if (string-null? line)
+    seed
+    (receive (pre post) (string-scan line "[[" 'both)
+      (if pre
+        (receive (wikiname rest) (find-closer post 0 '())
+          (if wikiname
+            (fmt-line:bracket rest
+                     (cons `(wiki-name ,wikiname) ((fmt-line:next-proc) pre seed)))
+            ((fmt-line:next-proc) rest ((fmt-line:next-proc) pre seed))))
+        ((fmt-line:next-proc) line seed)))))
+(define (fmt-line:nl line seed)
+  (regexp-fold
+   #/~%/
+   (fmt-line:next-proc)
+   (lambda (match seed) (cons '(br) seed))
+   seed line))
+;; NB: we remove empty bold and italic, for backward compatibility
+(define (fmt-line:italic line seed)
+  (regexp-fold
+   #/''([^'].*?)?''/
+   (fmt-line:next-proc)
+   (lambda (match seed)
+     (if (or (not (match 1)) (string-null? (match 1)))
+       seed
+       (cons `(em ,@(reverse! ((fmt-line:next-proc) (match 1) '()))) seed)))
+   seed line))
+(define (fmt-line:bold line seed)
+  (regexp-fold
+   #/'''([^'].*?)?'''/
+   (fmt-line:next-proc)
+   (lambda (match seed)
+     (if (or (not (match 1)) (string-null? (match 1)))
+       seed
+       (cons `(strong ,@(reverse! ((fmt-line:next-proc) (match 1) '()))) seed)))
+   seed line))
+(define (fmt-line:code line seed)
+  (regexp-fold
+   #/"""([^\"].*?)?"""/
+   (fmt-line:next-proc)
+   (lambda (match seed)
+     (if (or (not (match 1)) (string-null? (match 1)))
+       seed
+       (cons `(code ,@(reverse! ((fmt-line:next-proc) (match 1) '()))) seed)))
+   seed line))
+(define (fmt-line:smacro line seed)
+  (if (string-null? line)
+    seed
+    (receive (pre post) (string-scan line "##(" 'both)
+      (if pre
+        (receive (expr rest) (read-macro-expr post)
+          ;; NB: we should handle distinction of inline and block elements
+          ;; here.  It requires some trick, so for now I leave it.
+          (if expr
+            (smacro rest (cons `(wiki-macro ,@expr) ((fmt-line:next-proc) pre seed)))
+            (smacro post ((fmt-line:next-proc) (string-append pre "##(") seed))))
+        (fmt-line:code line seed)))))
+
+;; Find wiki name in the line.
+;; Correctly deal with nested "[[" and "]]"'s.
+(define (fmt-line ctx line seed)
+  (define (proc-solver line seed rest)
+    (if (null? rest)
+      (cons line seed)
+      (let1 next-proc (lambda (line-n seed-n)
+                        (proc-solver line-n seed-n (cdr rest)))
+        (fmt-line:next-proc next-proc)
+        ((car rest) line seed))))
   ;; Main body
-  (cons "\n" (smacro line seed)))
+  (cons "\n" (proc-solver line seed (fmt-line:proc-list))))
 
 ;; Read lines from generator and format them.  This is the main
 ;; parser/transformer of WiLiKi format.
diff -urN WiLiKi.orig/src/wiliki.scm WiLiKi/src/wiliki.scm
--- WiLiKi.orig/src/wiliki.scm	2011-08-01 23:20:20.000000000 +0900
+++ WiLiKi/src/wiliki.scm	2011-08-12 08:30:36.000000000 +0900
@@ -60,6 +60,7 @@
           wiliki:page-lines-fold
           wiliki:lang
           wiliki:version
+          wiliki:self-url
           )
   )
 (select-module wiliki)
diff -urN WiLiKi.orig/src/wiliki2.cgi WiLiKi/src/wiliki2.cgi
--- WiLiKi.orig/src/wiliki2.cgi	2011-08-01 23:20:20.000000000 +0900
+++ WiLiKi/src/wiliki2.cgi	2011-08-11 17:51:18.000000000 +0900
@@ -2,12 +2,19 @@
 
 ;; wiliki2 - sample of customizing page format
 
+(use text.tree)
+(use gauche.parameter)
 (use util.list)
 (use wiliki)
 (use wiliki.format)
 (use wiliki.db)
+(use wiliki.core)
+(use wiliki.parse)
+
+(define wikiname-re (make-parameter #f))
 
 (define-class <my-formatter> (<wiliki-formatter>) ())
+(define-class <my-wiliki> (<wiliki>) ())
 
 (define-method wiliki:format-page-header ((fmt <my-formatter>) page . opts)
   (define (td x) (list 'td x))
@@ -32,6 +39,11 @@
          (a (@ (href "http://www.shiro.dreamhost.com/scheme/gauche/"))
             "Gauche ",(gauche-version)))))
 
+(define (page-title page)
+  `((h1 ,(if (wiliki:persistent-page? page)
+           `(a (@ (href ,(wiliki:url "c=s&key=~a" (ref page 'key))))
+               ,(ref page 'title))
+           (ref page 'title)))))
 (define-method wiliki:format-page-content ((fmt <my-formatter>) page . opts)
   `((table
      (@ (border 0) (cellspacing 8) (width "100%") (class "content-table"))
@@ -49,14 +61,69 @@
                         (wiliki:recent-changes-alist :length 20)))
              (a (@ (href ,(wiliki:self-url "c=r"))) "More ..."))
          (td (@ (valign "top"))
-             ,@(wiliki:page-title page)
+             ,@(page-title page)
              ,@(wiliki:format-content page))))))
 
+(define-method wiliki:renew-db-handler ((self <my-wiliki>) . opts)
+  (wiliki:db-raw-put!
+    " %index-cache"
+    (write-to-string (wiliki-db-map (lambda (k v) k)))))
+
+(define (read-index-cache)
+  (and-let* ((index-cache (wiliki:db-raw-get " %index-cache" #f)))
+    (read-from-string index-cache)))
+(define (read-index)
+  (wiliki-db-map (lambda (k v) k)))
+(define (get-wikiname-re)
+  (if (wikiname-re)
+    (wikiname-re)
+    (let* ((index (or (read-index-cache) (read-index)))
+           (sorted-index (sort index (lambda (a b)
+                                       (> (string-length a)
+                                          (string-length b)))))
+           (re (if (null? sorted-index)
+                 #/^\B$/ ; never matched
+                 (string->regexp
+                   (tree->string
+                     `("("
+                       ,(intersperse
+                          "|"
+                          (map
+                            (lambda (key)
+                              `("(?:" ,(regexp-quote key) ")"))
+                            sorted-index))
+                       ")"))))))
+      (wikiname-re re)
+      re)))
+
+(define (fmt-line:auto-wiliki-word line seed)
+  (regexp-fold
+    (get-wikiname-re)
+    (fmt-line:next-proc)
+    (lambda (match seed)
+      (cons `(wiki-name ,(match)) seed))
+    seed line))
+(define-method wiliki:fmt-line-procs ((fmt <my-formatter>))
+  (list
+    fmt-line:smacro
+    fmt-line:bold
+    fmt-line:italic
+    fmt-line:nl
+    fmt-line:bracket
+    fmt-line:uri
+    fmt-line:mailto
+    fmt-line:auto-wiliki-word
+    ))
+
+(define-method wiliki-main ((self <my-wiliki>))
+  (parameterize ((wikiname-re #f))
+    (next-method)))
+
 (wiliki:formatter (make <my-formatter>))
 
 (define (main args)
   (wiliki-main
-   (make <wiliki>
+   (make <my-wiliki>
      :db-path "/home/shiro/data/wikidata.dbm"
      :top-page "WiLiKi"
      :title "MyWiliki2"
