picolisp

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/picolisp.git/
Log | Files | Refs | README | LICENSE

picolisp-wiki-mode.el (41038B)


      1 ;;; picolisp-wiki-mode.el --- Emacs Major mode for PicoLisp-Wiki formatted text files
      2 
      3 ;; Copyright (C) 2012-13 Thorsten Jolitz <tjolitz@gmail.com>
      4 
      5 ;; Author: Thorsten Jolitz <tjolitz@gmail.com>
      6 ;; Maintainer: Thorsten Jolitz <tjolitz@gmail.com>
      7 ;; Created: September 01, 2012
      8 ;; Version: 1.0
      9 ;; Keywords: PicoLisp, wiki
     10 ;; URL: http://picolisp.com/5000/!wiki?home
     11 
     12 ;; This file is not part of GNU Emacs.
     13 
     14 ;; This program is free software; you can redistribute it and/or modify
     15 ;; it under the terms of the GNU General Public License as published by
     16 ;; the Free Software Foundation; either version 2, or (at your option)
     17 ;; any later version.
     18 
     19 ;; This program is distributed in the hope that it will be useful,
     20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     22 ;; GNU General Public License for more details.
     23 
     24 ;; You should have received a copy of the GNU General Public License
     25 ;; along with this program; if not, write to the Free Software
     26 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor,
     27 ;; Boston, MA 02110-1301, USA.
     28 
     29 ;;; Commentary:
     30 
     31 ;; picolisp-wiki-mode is a major mode for editing text files for
     32 ;; PicoLisp-Wiki in GNU Emacs. picolisp-wiki-mode is free software,
     33 ;; licensed under the GNU GPL.
     34 
     35 ;;; Dependencies:
     36 
     37 ;; picolisp-wiki-mode requires easymenu, a standard package since GNU Emacs
     38 ;; 19 and XEmacs 19, which provides a uniform interface for creating
     39 ;; menus in GNU Emacs and XEmacs.
     40 
     41 ;;; Installation:
     42 
     43 ;; Make sure to place `picolisp-wiki-mode.el` somewhere in the
     44 ;; load-path and add the following lines to your `.emacs` file to
     45 ;; associate picolisp-wiki-mode with `.text` files:
     46 
     47     (autoload 'picolisp-wiki-mode "picolisp-wiki-mode"
     48        "Major mode for editing Picolisp-Wiki files" t)
     49     (setq auto-mode-alist
     50        ;; (cons '("\\.text" . picolisp-wiki-mode) auto-mode-alist))
     51        (cons '("\\.plw" . picolisp-wiki-mode) auto-mode-alist))
     52 
     53 ;; There is no consensus on an official file extension so change `.text` to
     54 ;; `.plw`, `.lw`, `.lwik`, or whatever you call your picolisp-wiki files.
     55 
     56 ;;; Customization:
     57 
     58 ;; Although no configuration is *necessary* there are a few things
     59 ;; that can be customized.  The `M-x customize-mode` command
     60 ;; provides an interface to all of the possible customizations.
     61 
     62 ;; Usage:
     63 
     64 ;; Keybindings for inserting are grouped by prefixes based on their
     65 ;; function. For example, commands inserting links and lists begin
     66 ;; with `C-c C-l`, those inserting floating content with `C-c C-f`,
     67 ;; all other inserting commands with `C-c C-c`. The commands in each
     68 ;; group are described below. You can obtain a list of all keybindings
     69 ;; by pressing `C-c C-h`.
     70 
     71 ;;     ;; Element insertion
     72 ;;     "\C-c\C-l n" Insert Internal Link
     73 ;;     "\C-c\C-l x" Insert External Link
     74 ;;     "\C-c\C-l u" Insert Unordered List
     75 ;;     "\C-c\C-l o" Insert Ordered List
     76 ;;     "\C-c\C-l i" Insert List Item
     77 ;;     "\C-c\C-f l" Insert Left-Floating-Content
     78 ;;     "\C-c\C-f n" Insert Non-Floating Content
     79 ;;     "\C-c\C-f r" Insert Right-Floating-Content
     80 ;;     "\C-c\C-c k" Insert Line Breaks
     81 ;;     "\C-c\C-c 1" Insert Header 1
     82 ;;     "\C-c\C-c 2" Insert Header 2
     83 ;;     "\C-c\C-c 3" Insert Header 3
     84 ;;     "\C-c\C-c 4" Insert Header 4
     85 ;;     "\C-c\C-c 5" Insert Header 5
     86 ;;     "\C-c\C-c 6" Insert Header 6
     87 ;;     "\C-c\C-c b" Insert Bold
     88 ;;     "\C-c\C-c i" Insert Italic
     89 ;;     "\C-c\C-c u" Insert Underlined
     90 ;;     "\C-c\C-c p" Insert Pre Block
     91 ;;     "\C-c\C-c c" Insert Comment
     92 ;;     "\C-c\C-c -" Insert Horizontal Rule (hr)
     93 ;;     ;; Visibility cycling
     94 ;;     "<tab>" Picolisp Wiki Cycle
     95 ;;     "<S-iso-lefttab>" Picolisp Wiki Shifttab
     96 ;;     ;; Header navigation
     97 ;;     "C-M-n" Outline Next Visible Heading
     98 ;;     "C-M-p" Outline Previous Visible Heading
     99 ;;     "C-M-f" Outline Forward Same Level
    100 ;;     "C-M-b" Outline Backward Same Level
    101 ;;     "C-M-u" Outline Up Heading
    102 
    103 ;; Many of the commands described above behave differently depending on
    104 ;; whether Transient Mark mode is enabled or not.  When it makes sense,
    105 ;; if Transient Mark mode is on and a region is active, the command
    106 ;; applies to the text in the region (e.g., `C-c C-c b` makes the region
    107 ;; bold).  For users who prefer to work outside of Transient Mark mode,
    108 ;; in Emacs 22 it can be enabled temporarily by pressing `C-SPC C-SPC`.
    109 ;;
    110 ;; picolisp-wiki-mode supports outline-minor-mode as well as
    111 ;; org-mode-style visibility cycling for PicoLisp-Wikli-style headers.
    112 ;; There are two types of visibility cycling: Pressing `S-TAB` cycles
    113 ;; globally between the table of contents view (headers only), outline
    114 ;; view (top-level headers only), and the full document view. Pressing
    115 ;; `TAB` while the point is at a header will cycle through levels of
    116 ;; visibility for the subtree: completely folded, visible children,
    117 ;; and fully visible. 
    118 
    119 ;;   * Outline Navigation:
    120 ;;
    121 ;;     Navigation between headings is possible using `outline-mode'.
    122 ;;     Use `C-M-n` and `C-M-p` to move between the next and previous
    123 ;;     visible headings.  Similarly, `C-M-f` and `C-M-b` move to the
    124 ;;     next and previous visible headings at the same level as the one
    125 ;;     at the point.  Finally, `C-M-u` will move up to a lower-level
    126 ;;     (more inclusive) visible heading.
    127 ;;
    128 ;; FIXME: different headers levels are not yet recognized by the outine
    129 ;; commands.
    130 
    131 
    132 ;;; Acknowledgments:
    133 
    134 ;; picolisp-wiki-mode is based on markdown.el (available from ELPA).
    135 ;; It has benefited greatly from the efforts of the following people:
    136 ;;
    137 ;;   * Thorsten Jolitz <tjolitz [AT] gmail [DOT] com>
    138 ;;   * Doug Lewan <dougl [@] shubertticketing [DOT] com>
    139 ;;; Bugs:
    140 
    141 ;; picolisp-wiki-mode is developed and tested primarily using GNU
    142 ;; Emacs 24, compatibility with earlier Emacsen is no priority. For
    143 ;; bugs and todo's, see the HISTORY.org file in the github-repo
    144 ;; (https://github.com/tj64/picolisp-wiki-mode).
    145 ;;
    146 ;; If you find any bugs in picolisp-wiki-mode, please construct a test case
    147 ;; or a patch and email me at <tjolitz@gmail.com>.
    148 
    149 ;;; History:
    150 
    151 ;; picolisp-wiki-mode was written and is maintained by Thorsten
    152 ;; Joltiz. The first version (0.9) was released on Sept 01, 2012. For
    153 ;; further information see the HISTORY.org file in the github-repo
    154 ;; (https://github.com/tj64/picolisp-wiki-mode).
    155 
    156 
    157 ;;; Code:
    158 
    159 (require 'easymenu)
    160 (require 'outline)
    161 (require 'cl)
    162 
    163 ;;; Constants =================================================================
    164 
    165 (defconst picolisp-wiki-mode-version "1.0"
    166   "Picolisp-Wiki mode version number.")
    167 
    168 ;;; Customizable variables ====================================================
    169 
    170 (defvar picolisp-wiki-mode-hook nil
    171   "Hook runs when Picolisp-Wiki mode is loaded.")
    172 
    173 (defgroup picolisp-wiki nil
    174   "Major mode for editing text files in Picolisp-Wiki format."
    175   :prefix "picolisp-wiki-"
    176   :group 'wp
    177   :link '(url-link "http://picolisp.com/5000/!wiki?homef"))
    178 
    179 
    180 (defcustom picolisp-wiki-hr-string "------------------------------------"
    181   "String to use for horizonal rules."
    182   :group 'picolisp-wiki
    183   :type 'string)
    184 
    185 (defcustom picolisp-wiki-uri-types
    186   '("acap" "cid" "data" "dav" "fax" "file" "ftp" "gopher" "http" "https"
    187     "imap" "ldap" "mailto" "mid" "modem" "news" "nfs" "nntp" "pop" "prospero"
    188     "rtsp" "service" "sip" "tel" "telnet" "tip" "urn" "vemmi" "wais")
    189   "Link types for syntax highlighting of URIs."
    190   :group 'picolisp-wiki
    191   :type 'list)
    192 
    193 
    194 (defcustom picolisp-wiki-link-space-sub-char
    195   "_"
    196   "Character to use instead of spaces when mapping wiki links to filenames."
    197   :group 'picolisp-wiki
    198   :type 'string)
    199 
    200 
    201 ;;; Font lock =================================================================
    202 
    203 (require 'font-lock)
    204 
    205 (defvar picolisp-wiki-starting-brace-face
    206   'picolisp-wiki-starting-brace-face
    207   "Face name to use for starting braces.")
    208 
    209 (defvar picolisp-wiki-closing-brace-face
    210   'picolisp-wiki-closing-brace-face
    211   "Face name to use for closing braces.")
    212 
    213 (defvar picolisp-wiki-line-break-face 'picolisp-wiki-line-break-face
    214   "Face name to use for line breaks.")
    215 
    216 (defvar picolisp-wiki-italic-face 'picolisp-wiki-italic-face
    217   "Face name to use for italic text.")
    218 
    219 (defvar picolisp-wiki-bold-face 'picolisp-wiki-bold-face
    220   "Face name to use for bold text.")
    221 
    222 (defvar picolisp-wiki-underlined-face 'picolisp-wiki-underlined-face
    223   "Face name to use for underlined text.")
    224 
    225 (defvar picolisp-wiki-header-face 'picolisp-wiki-header-face
    226   "Face name to use as a base for headers.")
    227 
    228 (defvar picolisp-wiki-header-face-1 'picolisp-wiki-header-face-1
    229   "Face name to use for level-1 headers.")
    230 
    231 (defvar picolisp-wiki-header-face-2 'picolisp-wiki-header-face-2
    232   "Face name to use for level-2 headers.")
    233 
    234 (defvar picolisp-wiki-header-face-3 'picolisp-wiki-header-face-3
    235   "Face name to use for level-3 headers.")
    236 
    237 (defvar picolisp-wiki-header-face-4 'picolisp-wiki-header-face-4
    238   "Face name to use for level-4 headers.")
    239 
    240 (defvar picolisp-wiki-header-face-5 'picolisp-wiki-header-face-5
    241   "Face name to use for level-5 headers.")
    242 
    243 (defvar picolisp-wiki-header-face-6 'picolisp-wiki-header-face-6
    244   "Face name to use for level-6 headers.")
    245 
    246 (defvar picolisp-wiki-list-item-face 'picolisp-wiki-list-item-face
    247   "Face name to use for list markers.")
    248 
    249 (defvar picolisp-wiki-left-floating-content-face
    250   'picolisp-wiki-left-floating-content-face
    251   "Face name to use for left floating content.")
    252 
    253 (defvar picolisp-wiki-non-floating-content-face
    254   'picolisp-wiki-non-floating-content-face
    255   "Face name to use for non floating content.")
    256 
    257 (defvar picolisp-wiki-right-floating-content-face
    258   'picolisp-wiki-right-floating-content-face
    259   "Face name to use for right floating content.")
    260 
    261 (defvar picolisp-wiki-pre-face 'picolisp-wiki-pre-face
    262   "Face name to use for preformatted text.")
    263 
    264 (defvar picolisp-wiki-link-label-face 'picolisp-wiki-link-label-face
    265   "Face name to use for link labels.")
    266 
    267 (defvar picolisp-wiki-url-face 'picolisp-wiki-url-face
    268   "Face name to use for URLs.")
    269 
    270 (defvar picolisp-wiki-link-title-face 'picolisp-wiki-link-title-face
    271   "Face name to use for reference link titles.")
    272 
    273 (defvar picolisp-wiki-comment-face 'picolisp-wiki-comment-face
    274   "Face name to use for HTML comments.")
    275 
    276 
    277 
    278 ;; FACE definitions
    279 
    280 (defgroup picolisp-wiki-faces nil
    281   "Faces used in Picolisp-Wiki Mode"
    282   :group 'picolisp-wiki
    283   :group 'faces)
    284 
    285 (defface picolisp-wiki-hr-face
    286   '((t (:inherit font-lock-comment-delimiter-face)))
    287   "Face for starting braces."
    288   :group 'picolisp-wiki-faces)
    289 
    290 (defface picolisp-wiki-starting-brace-face
    291   '((t (:inherit font-lock-comment-delimiter-face)))
    292   "Face for starting braces."
    293   :group 'picolisp-wiki-faces)
    294 
    295 (defface picolisp-wiki-closing-brace-face
    296   '((t (:inherit font-lock-comment-delimiter-face)))
    297   "Face for closing braces."
    298   :group 'picolisp-wiki-faces)
    299 
    300 (defface picolisp-wiki-italic-face
    301   '((t (:inherit font-lock-negation-char-face :slant italic)))
    302   "Face for italic text."
    303   :group 'picolisp-wiki-faces)
    304 
    305 (defface picolisp-wiki-bold-face
    306   '((t (:inherit font-lock-negation-char-face :weight bold)))
    307   "Face for bold text."
    308   :group 'picolisp-wiki-faces)
    309 
    310 (defface picolisp-wiki-underlined-face
    311   '((t (:inherit font-lock-negation-char-face :underline t)))
    312   "Face for underlined text."
    313   :group 'picolisp-wiki-faces)
    314 
    315 (defface picolisp-wiki-line-break-face
    316   '((t (:inherit font-lock-warning-face)))
    317   "Face for underlined text."
    318   :group 'picolisp-wiki-faces)
    319 
    320 (defface picolisp-wiki-header-face
    321   '((t (:inherit font-lock-function-name-face :weight bold)))
    322   "Base face for headers."
    323   :group 'picolisp-wiki-faces)
    324 
    325 (defface picolisp-wiki-header-face-1
    326   '((t (:inherit picolisp-wiki-header-face)))
    327   "Face for level-1 headers."
    328   :group 'picolisp-wiki-faces)
    329 
    330 (defface picolisp-wiki-header-face-2
    331   '((t (:inherit picolisp-wiki-header-face)))
    332   "Face for level-2 headers."
    333   :group 'picolisp-wiki-faces)
    334 
    335 (defface picolisp-wiki-header-face-3
    336   '((t (:inherit picolisp-wiki-header-face)))
    337   "Face for level-3 headers."
    338   :group 'picolisp-wiki-faces)
    339 
    340 (defface picolisp-wiki-header-face-4
    341   '((t (:inherit picolisp-wiki-header-face)))
    342   "Face for level-4 headers."
    343   :group 'picolisp-wiki-faces)
    344 
    345 (defface picolisp-wiki-header-face-5
    346   '((t (:inherit picolisp-wiki-header-face)))
    347   "Face for level-5 headers."
    348   :group 'picolisp-wiki-faces)
    349 
    350 (defface picolisp-wiki-header-face-6
    351   '((t (:inherit picolisp-wiki-header-face)))
    352   "Face for level-6 headers."
    353   :group 'picolisp-wiki-faces)
    354 
    355 (defface picolisp-wiki-list-item-face
    356   '((t (:inherit font-lock-string-face)))
    357   "Face for list item markers."
    358   :group 'picolisp-wiki-faces)
    359 
    360 (defface picolisp-wiki-pre-face
    361   '((t (:inherit font-lock-constant-face)))
    362   ;; '((t (:inherit font-lock-string-face)))
    363   "Face for preformatted text."
    364   :group 'picolisp-wiki-faces)
    365 
    366 (defface picolisp-wiki-internal-link-face
    367   '((t (:inherit font-lock-keyword-face)))
    368   "Face for internal links."
    369   :group 'picolisp-wiki-faces)
    370 
    371 (defface picolisp-wiki-external-link-face
    372   '((t (:inherit font-lock-keyword-face)))
    373   "Face for external links."
    374   :group 'picolisp-wiki-faces)
    375 
    376 (defface picolisp-wiki-url-face
    377   '((t (:inherit font-lock-string-face)))
    378   "Face for URLs."
    379   :group 'picolisp-wiki-faces)
    380 
    381 (defface picolisp-wiki-link-label-face
    382   '((t (:inherit font-lock-keyword-face)))
    383   "Face for reference link titles."
    384   :group 'picolisp-wiki-faces)
    385 
    386 (defface picolisp-wiki-comment-face
    387   '((t (:inherit font-lock-comment-face)))
    388   "Face for HTML comments."
    389   :group 'picolisp-wiki-faces)
    390 
    391 
    392 ;; REGEXP
    393 ;; FIXME consider linebreaks in pattern
    394 
    395 ;; [start] regexp by Doug Lewan (Newsgroups: gmane.emacs.help)
    396 
    397 (defconst picolisp-wiki-regex-plain-text 
    398   (concat "\\([[:space:]]*[^}]+\\)[[:space:]]*" ; Matches "123$%^ Чебурашка &*(0-="
    399 	  )
    400   "Regular expression defining what 'plain text' is.")
    401 
    402 (defconst  picolisp-wiki-regex-bold-text
    403   (concat "\\(!{\\)"
    404 	  picolisp-wiki-regex-plain-text
    405 	  "\\(}\\)")
    406   "Regular expression defining what 'bold text' is.")
    407 
    408 (defconst picolisp-wiki-regex-text
    409   (concat "\\("
    410 	  picolisp-wiki-regex-plain-text
    411 	  "\\|"
    412 	  picolisp-wiki-regex-bold-text
    413 	  "\\)")
    414   "Regular expression defining what 'text'.
    415 Text is a mix of plain text and bold text.")
    416 
    417 (defconst picolisp-wiki-regex-list-item-text
    418   (concat "\\(-{\\)"
    419 	  picolisp-wiki-regex-text "+"
    420 	  "\\(}\\)")
    421   "Regular expression defining what a 'list item' is.")
    422 
    423 ;; [end] regexp by Doug Lewan (Newsgroups: gmane.emacs.help)
    424 
    425 ;; [start] testcode for regexp by Doug Lewan
    426 
    427 ;; ;; 
    428 ;; ;; Sunny day test code
    429 ;; ;; 
    430 ;; (defconst test-plain-text (list "foo"
    431 ;; 				"foo bar "
    432 ;; 				"	foo bar baz bat"
    433 ;; 				" --- 123$%^ Чебурашка &*(0-= --- "))
    434 ;; (defconst test-bold-text (mapcar (lambda (text)
    435 ;; 				   (concat "!{" text "}"))
    436 ;; 				 test-plain-text))
    437 ;; (defconst test-list-item-text (mapcar (lambda (list-text)
    438 ;; 				   (concat "-{" list-text "}"))
    439 ;; 				 (append test-plain-text test-bold-text)))
    440 
    441 ;; (mapc (lambda (test-spec)
    442 ;; 	(let ((re (car test-spec))
    443 ;; 	      (test-data (cdr test-spec)))
    444 ;; 	  (mapc (lambda (item)
    445 ;; 		  (if (string-match re item)
    446 ;; 		      (message "PASS -- [[%s]] matches [[%s]]" re item)
    447 ;; 		    (message "FAIL -- [[%s]] DIDN'T match [[%s]]" re item))
    448 ;; 		  (sit-for 1))
    449 ;; 		test-data)))
    450 ;;       (list (cons picolisp-wiki-regex-plain-text test-plain-text)
    451 ;; 	    (cons picolisp-wiki-regex-bold-text test-bold-text)
    452 ;; 	    (cons picolisp-wiki-regex-list-item-text test-list-item-text)))
    453 
    454 ;; [end] testcode testcode for regexp by Doug Lewan
    455 
    456 (defconst picolisp-wiki-regex-internal-link
    457   "\\(={\\)\\([^ ]+\\)\\( \\)\\(.*\\)\\(}\\)"
    458   "Regular expression for an internal link.")
    459 
    460 (defconst picolisp-wiki-regex-external-link
    461    "\\(\\^{\\)\\([^ ]+\\)\\( \\)\\(.*\\)\\(}\\)"
    462   "Regular expression for an external link.")
    463 
    464 (defconst picolisp-wiki-regex-comment
    465   "\\(#{\\)\\([ 	
    466 ]*[^}]+\\)\\(}\\)"
    467   "Regular expression for an external link.")
    468 
    469 (defconst picolisp-wiki-regex-header-1
    470   "\\(1{\\)\\([ 	
    471 ]*[^}]+\\)\\(}\\)"
    472   "Regular expression for level 1 headers.")
    473 
    474 (defconst picolisp-wiki-regex-header-2
    475   "\\(2{\\)\\([ 	
    476 ]*[^}]+\\)\\(}\\)"
    477   "Regular expression for level 2 headers.")
    478 
    479 (defconst picolisp-wiki-regex-header-3
    480   "\\(3{\\)\\([ 	
    481 ]*[^}]+\\)\\(}\\)"
    482   "Regular expression for level 3 headers.")
    483 
    484 (defconst picolisp-wiki-regex-header-4
    485   "\\(4{\\)\\([ 	
    486 ]*[^}]+\\)\\(}\\)"
    487   "Regular expression for level 4 headers.")
    488 
    489 (defconst picolisp-wiki-regex-header-5
    490   "\\(5{\\)\\([ 	
    491 ]*[^}]+\\)\\(}\\)"
    492   "Regular expression for level 5 headers.")
    493 
    494 (defconst picolisp-wiki-regex-header-6
    495   "\\(6{\\)\\([ 	
    496 ]*[^}]+\\)\\(}\\)"
    497   "Regular expression for level 6 headers.")
    498 
    499 (defconst picolisp-wiki-regex-hr
    500   "\\(--\\)+\\(---\\)*$"
    501   "Regular expression for matching Picolisp-Wiki horizontal rules.")
    502 
    503 (defconst picolisp-wiki-regex-left-floating-content
    504   "\\(<{\\)\\([ 	
    505 ]*[^}]+\\)\\(}\\)"
    506   "Regular expression for matching left-floating-content.")
    507 
    508 (defconst picolisp-wiki-regex-non-floating-content
    509   "\\(@{\\)\\([ 	
    510 ]*[^}]+\\)\\(}\\)"
    511   "Regular expression for matching non-floating-content.")
    512 
    513 (defconst picolisp-wiki-regex-right-floating-content
    514   "\\(>{\\)\\([ 	
    515 ]*[^}]+\\)\\(}\\)"
    516   "Regular expression for matching right-floating-content.")
    517 
    518 (defconst picolisp-wiki-regex-pre-block
    519    "\\(:{\\)\\([ 	
    520 ]*[^}]+\\)\\(}\\)"
    521 
    522 ;;  "\\(:{\\)\\([ \t\n]*[^}]+\\)\\(}\\)"
    523 
    524 ;;   "\\(:{\\)\\([ 	
    525 ;; ][^}]+\\)\\(}\\)"
    526   "Regular expression for matching preformatted text sections.")
    527 
    528 ;; (defconst picolisp-wiki-regex-unordered-list
    529 ;;   "\\(^[\\t ]*\\*{\\)\\([ 	]*[ 
    530 ;; ]+\\)\\(-{.*}[ 	
    531 ;; ]+\\)\\{1,\\}\\(}\\)"
    532 ;;   "Regular expression for matching unordered list markers.")
    533 
    534 ;; (defconst picolisp-wiki-regex-ordered-list
    535 ;;   "\\(^[\\t ]*\\+{\\)\\([ 	]*[ 
    536 ;; ]+\\)\\(-{.*}[ 	
    537 ;; ]+\\)\\{1,\\}\\(}\\)"
    538 ;;   "Regular expression for matching ordered list markers.")
    539 
    540 ;; (defconst picolisp-wiki-regex-unordered-list-start
    541 ;;   "\\(^\\*{\\)\\([ \t\n]*$\\)"
    542 ;;   "Regular expression for matching the start of an unordered list.")
    543 
    544 ;; (defconst picolisp-wiki-regex-ordered-list-start
    545 ;;   "\\(^\\+{\\)\\([ \t\n]*$\\)"
    546 ;;   "Regular expression for matching the start of an ordered list.")
    547 
    548 (defconst picolisp-wiki-regex-starting-brace
    549   (concat "\\(\\*\\|\\+\\|-\\|&\\|/\\|_\\|\\^\\|"
    550           "<\\|>\\|@\\|!\\|=\\|:\\|#\\|1\\|2\\|"
    551           "3\\|4\\|5\\|6\\)\\({\\)")
    552   "Regular expression for matching a starting brace.")
    553 
    554 (defconst picolisp-wiki-regex-closing-brace
    555   "\\([^\\]\\)\\(}\\)"
    556   "Regular expression for matching a closing brace.")
    557 
    558 (defconst picolisp-wiki-regex-list-item
    559   "\\(-{\\)\\([ 	
    560 ]*[^}]+\\)\\(}\\)"
    561   "Regular expression for matching a list item.")
    562 
    563 (defconst picolisp-wiki-regex-bold
    564   "\\(!{\\)\\([ 	
    565 ]*[^}]+\\)\\(}\\)"
    566   "Regular expression for matching bold text.")
    567 
    568 (defconst picolisp-wiki-regex-italic
    569   "\\(/{\\)\\([ 	
    570 ]*[^}]+\\)\\(}\\)"
    571   "Regular expression for matching italic text.")
    572 
    573 (defconst picolisp-wiki-regex-underlined
    574    "\\(_{\\)\\([ 	
    575 ]*[^}]+\\)\\(}\\)"
    576   "Regular expression for matching underlined text.")
    577 
    578 (defconst picolisp-wiki-regex-line-break
    579   "\\(&{\\)\\([-]?[0-9]\\)\\(}\\)"
    580   "Regular expression for matching line breaks.")
    581 
    582 (defconst picolisp-wiki-regex-wiki-link
    583   "\\[\\[\\([^]|]+\\)\\(|\\([^]]+\\)\\)?\\]\\]"
    584   "Regular expression for matching wiki links.
    585 This matches typical bracketed [[WikiLinks]] as well as 'aliased'
    586 wiki links of the form [[PageName|link text]].  In this regular
    587 expression, #1 matches the page name and #3 matches the link
    588 text.")
    589 
    590 (defconst picolisp-wiki-regex-uri
    591   (concat
    592    "\\(" (mapconcat 'identity picolisp-wiki-uri-types "\\|")
    593    "\\):[^]\t\n\r<>,;() ]+")
    594   "Regular expression for matching inline URIs.")
    595 
    596 (defconst picolisp-wiki-regex-angle-uri
    597   (concat
    598    "\\(<\\)\\("
    599    (mapconcat 'identity picolisp-wiki-uri-types "\\|")
    600    "\\):[^]\t\n\r<>,;()]+\\(>\\)")
    601   "Regular expression for matching inline URIs in angle brackets.")
    602 
    603 (defconst picolisp-wiki-regex-email
    604   "<\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+>"
    605   "Regular expression for matching inline email addresses.")
    606 
    607 
    608 
    609 ;; Keywords
    610 
    611 (defvar picolisp-wiki-mode-font-lock-keywords-basic
    612   (list
    613    (cons picolisp-wiki-regex-header-1 '(2 picolisp-wiki-header-face-1))
    614    (cons picolisp-wiki-regex-header-2 '(2 picolisp-wiki-header-face-2))
    615    (cons picolisp-wiki-regex-header-3 '(2 picolisp-wiki-header-face-3))
    616    (cons picolisp-wiki-regex-header-4 '(2 picolisp-wiki-header-face-4))
    617    (cons picolisp-wiki-regex-header-5 '(2 picolisp-wiki-header-face-5))
    618    (cons picolisp-wiki-regex-header-6 '(2 picolisp-wiki-header-face-6))
    619    (cons picolisp-wiki-regex-starting-brace 'picolisp-wiki-starting-brace-face)
    620    (cons picolisp-wiki-regex-closing-brace '(2 picolisp-wiki-closing-brace-face))
    621    (cons picolisp-wiki-regex-pre-block '(2 picolisp-wiki-pre-face))
    622    (cons picolisp-wiki-regex-hr '(2 picolisp-wiki-hr-face))
    623    (cons picolisp-wiki-regex-line-break '(2 picolisp-wiki-line-break-face))
    624    (cons picolisp-wiki-regex-comment '(2 picolisp-wiki-comment-face))
    625    (cons picolisp-wiki-regex-angle-uri '(2 picolisp-wiki-url-face))
    626    (cons picolisp-wiki-regex-uri '(2 picolisp-wiki-url-face))
    627    (cons picolisp-wiki-regex-email '(2 picolisp-wiki-url-face))
    628    ;; (cons picolisp-wiki-regex-left-floating-content
    629    ;;       '(2 picolisp-wiki-left-floating-content-fact))
    630    ;; (cons picolisp-wiki-regex-non-floating-content
    631    ;;       '(2 picolisp-wiki-non-floating-content-fact))
    632    ;; (cons picolisp-wiki-regex-right-floating-content
    633    ;;       '(2 picolisp-wiki-right-floating-content-fact))
    634    (cons picolisp-wiki-regex-email '(2 picolisp-wiki-url-face))
    635    ;; changed from picolisp-wiki-regex-list-item
    636    ;; (cons picolisp-wiki-regex-list-item '(2 picolisp-wiki-list-item-face))
    637    ;; (cons picolisp-wiki-regex-list-item-text 'picolisp-wiki-list-item-face)
    638    (cons picolisp-wiki-regex-internal-link
    639          '((2 picolisp-wiki-url-face t)
    640            (4 picolisp-wiki-internal-link-face t)))
    641    (cons picolisp-wiki-regex-external-link
    642          '((2 picolisp-wiki-url-face t)
    643            (4 picolisp-wiki-external-link-face t)))
    644    (cons picolisp-wiki-regex-bold '(2 picolisp-wiki-bold-face))
    645    ;; (cons picolisp-wiki-regex-bold-text 'picolisp-wiki-bold-face)
    646    (cons picolisp-wiki-regex-italic '(2 picolisp-wiki-italic-face))
    647    (cons picolisp-wiki-regex-underlined '(2 picolisp-wiki-underlined-face))
    648     )
    649    "Syntax highlighting for Picolisp-Wiki files.")
    650 
    651 (defvar picolisp-wiki-mode-font-lock-keywords
    652   (append picolisp-wiki-mode-font-lock-keywords-basic)
    653   "Default highlighting expressions for Picolisp-Wiki mode.")
    654 
    655 
    656 
    657 ;;; Syntax Table ==============================================================
    658 
    659 (defvar picolisp-wiki-mode-syntax-table
    660   (let ((picolisp-wiki-mode-syntax-table (make-syntax-table)))
    661     (modify-syntax-entry ?\" "w" picolisp-wiki-mode-syntax-table)
    662     picolisp-wiki-mode-syntax-table)
    663   "Syntax table for `picolisp-wiki-mode'.")
    664 
    665 
    666 
    667 ;;; Element Insertion =========================================================
    668 
    669 (defun picolisp-wiki-wrap-or-insert (s1 s2 &optional beg-newline-p)
    670   "Insert the strings S1 and S2.
    671 If Transient Mark mode is on and a region is active, wrap the strings S1
    672 and S2 around the region."
    673   (if (and transient-mark-mode mark-active)
    674       (let ((a (region-beginning)) (b (region-end)))
    675         (goto-char a)
    676         (insert s1)
    677         (goto-char (+ b (length s1)))
    678         (insert s2))
    679     (if (not beg-newline-p)
    680         (insert s1 s2)
    681       (end-of-line)
    682       (newline 2)
    683       (insert s1 s2))))
    684 
    685 (defun picolisp-wiki-insert-hr ()
    686   "Insert a horizonal rule using `picolisp-wiki-hr-string'."
    687   (interactive)
    688   ;; Leading blank line
    689   (when (and (>= (point) (+ (point-min) 2))
    690              (not (looking-back "\n\n" 2)))
    691     (insert "\n"))
    692   ;; Insert custom HR string
    693   (insert (concat picolisp-wiki-hr-string "\n"))
    694   ;; Following blank line
    695   (backward-char)
    696   (unless (looking-at "\n\n")
    697           (insert "\n")))
    698 
    699 (defun picolisp-wiki-insert-bold ()
    700   "Insert markup for a bold word or phrase.
    701 If Transient Mark mode is on and a region is active, it is made bold."
    702   (interactive)
    703   (picolisp-wiki-wrap-or-insert "!{" "}")
    704   (backward-char 1))
    705 
    706 (defun picolisp-wiki-insert-italic ()
    707   "Insert markup for an italic word or phrase.
    708 If Transient Mark mode is on and a region is active, it is made italic."
    709   (interactive)
    710   (picolisp-wiki-wrap-or-insert "/{" "}")
    711   (backward-char 1))
    712 
    713 (defun picolisp-wiki-insert-underlined ()
    714   "Insert markup for an underlined word or phrase.
    715 If Transient Mark mode is on and a region is active, it is underlined."
    716   (interactive)
    717   (picolisp-wiki-wrap-or-insert "_{" "}")
    718   (backward-char 1))
    719 
    720 
    721 (defun picolisp-wiki-insert-pre-block ()
    722   "Insert markup for a pre-formatted block.
    723 If Transient Mark mode is on and a region is active, it is marked
    724 as inline code."
    725   (interactive)
    726   (picolisp-wiki-wrap-or-insert ":{" "}")
    727   (backward-char 1))
    728 
    729 (defun picolisp-wiki-insert-comment ()
    730   "Insert markup for an comment.
    731 If Transient Mark mode is on and a region is active, it is marked
    732 as inline code."
    733   (interactive)
    734   (picolisp-wiki-wrap-or-insert "#{" "}")
    735   (backward-char 1))
    736 
    737 
    738 (defun picolisp-wiki-insert-internal-link ()
    739   "Insert an internal link.
    740 If Transient Mark mode is on and a region is active, it is used
    741 as the link text."
    742   (interactive)
    743   (picolisp-wiki-wrap-or-insert "={" "}")
    744   (backward-char 1))
    745 
    746 (defun picolisp-wiki-insert-external-link ()
    747   "Insert an external link.
    748 If Transient Mark mode is on and a region is active, it is used
    749 as the link text."
    750   (interactive)
    751   (picolisp-wiki-wrap-or-insert "^{" "}")
    752   (backward-char 1))
    753 
    754 
    755 (defun picolisp-wiki-insert-left-floating-content ()
    756   "Insert an inline image tag of the form <{content}.
    757 If Transient Mark mode is on and a region is active, it is used
    758 as the alt text of the image."
    759   (interactive)
    760   (picolisp-wiki-wrap-or-insert "<{" "}")
    761   (backward-char 1))
    762 
    763 (defun picolisp-wiki-insert-non-floating-content ()
    764   "Insert an inline image tag of the form @{content}.
    765 If Transient Mark mode is on and a region is active, it is used
    766 as the alt text of the image."
    767   (interactive)
    768   (picolisp-wiki-wrap-or-insert "@{" "}")
    769   (backward-char 1))
    770 
    771 (defun picolisp-wiki-insert-right-floating-content ()
    772   "Insert an inline image tag of the form >{content}.
    773 If Transient Mark mode is on and a region is active, it is used
    774 as the alt text of the image."
    775   (interactive)
    776   (picolisp-wiki-wrap-or-insert ">{" "}")
    777   (backward-char 1))
    778 
    779 
    780 (defun picolisp-wiki-insert-line-breaks (n)
    781   "Insert line-breaks. With no prefix argument, insert 1
    782 line-break. With prefix N, insert N line-breaks. With prefix N,
    783 insert N line-breaks. With negative prefix -N, insert N
    784 line-breaks and clear float style."
    785   (interactive "p")
    786   (unless n                             ; Test to see if n is defined
    787     (setq n 1))                         ; Default to level 1 header
    788   (insert
    789    (format "&{%d}" n )))
    790 
    791 
    792 (defun picolisp-wiki-insert-unordered-list ()
    793   "Insert an unordered list.
    794 If Transient Mark mode is on and a region is active, it is wrapped in an unordered list (the region should only contain list-items)."
    795   (interactive)
    796   (end-of-line)
    797   (newline)
    798   (insert "*{")
    799   (newline)
    800   (insert "   -{}")
    801   (newline)
    802   (insert "}")
    803   (newline)
    804   (search-backward "-{" nil t 1)
    805   (forward-char 2))
    806 
    807 
    808 (defun picolisp-wiki-insert-ordered-list ()
    809   "Insert an ordered list.
    810 If Transient Mark mode is on and a region is active, it is
    811 wrapped in an ordered list (the region should only contain
    812 list-items)."
    813   (interactive)
    814   (end-of-line)
    815   (newline)
    816   (insert "+{")
    817   (newline)
    818   (insert "   -{}")
    819   (newline)
    820   (insert "}")
    821   (newline)
    822   (search-backward "-{" nil t 1)
    823   (forward-char 2))
    824 
    825 
    826 ;; FIXME consider escaped braces '\{'and '\}' inside list items
    827 (defun picolisp-wiki--inside-list-item-p (&optional second-trial-p)
    828   "Return t if inside list-item, nil otherwise.
    829 This function takes care of the (common) case when there is one
    830 nested markup inside the list item, e.g. a link or a bold text,
    831 and point is inside the nested markup braces."
    832   (save-excursion
    833     (let ((pt (point)))
    834       (search-backward "{" nil t 1)
    835       (backward-char)
    836       (if (not (looking-at "-{"))
    837           (if (and               
    838                (not second-trial-p)
    839                (looking-at
    840                 (concat "\\(\\*\\|\\+\\|&\\|/\\|_\\|\\^\\|"
    841                         "<\\|>\\|@\\|!\\|=\\|:\\|#\\)\\({\\)")))
    842               (picolisp-wiki--inside-list-item-p 'SECOND-TRIAL-P)
    843             nil)
    844         (and
    845          (if second-trial-p
    846              (search-forward-regexp "}[^}]*}" nil t 1)
    847            (search-forward "}" nil t 1))
    848          (setq item-end (point))
    849          (> item-end pt))))))
    850         
    851 (defun picolisp-wiki-insert-list-item ()
    852   "Insert a list-item.
    853 If Transient Mark mode is on and a region is active, it becomes the text of a list item."
    854   (interactive)
    855   (if (not (picolisp-wiki--inside-list-item-p))   
    856       (progn  
    857         (picolisp-wiki-wrap-or-insert "-{" "}")
    858         (backward-char 1))
    859     (end-of-line)
    860     (newline)
    861     (insert "   -{}")
    862     (backward-char 1)
    863     ))
    864 
    865 
    866 (defun picolisp-wiki-insert-header-1 ()
    867   "Insert a first level picolisp-wiki-style header.
    868 If Transient Mark mode is on and a region is active, it is used
    869 as the header text."
    870   (interactive)
    871   (picolisp-wiki-insert-header 1))
    872 
    873 (defun picolisp-wiki-insert-header-2 ()
    874   "Insert a second level picolisp-wiki-style header.
    875 If Transient Mark mode is on and a region is active, it is used
    876 as the header text."
    877   (interactive)
    878   (picolisp-wiki-insert-header 2))
    879 
    880 (defun picolisp-wiki-insert-header-3 ()
    881   "Insert a third level picolisp-wiki-style header.
    882 If Transient Mark mode is on and a region is active, it is used
    883 as the header text."
    884   (interactive)
    885   (picolisp-wiki-insert-header 3))
    886 
    887 (defun picolisp-wiki-insert-header-4 ()
    888   "Insert a fourth level picolisp-wiki-style header.
    889 If Transient Mark mode is on and a region is active, it is used
    890 as the header text."
    891   (interactive)
    892   (picolisp-wiki-insert-header 4))
    893 
    894 (defun picolisp-wiki-insert-header-5 ()
    895   "Insert a fifth level picolisp-wiki-style header.
    896 If Transient Mark mode is on and a region is active, it is used
    897 as the header text."
    898   (interactive)
    899   (picolisp-wiki-insert-header 5))
    900 
    901 (defun picolisp-wiki-insert-header-6 ()
    902   "Insert a sixth level picolisp-wiki-style header.
    903 If Transient Mark mode is on and a region is active, it is used
    904 as the header text."
    905   (interactive)
    906   (picolisp-wiki-insert-header 6))
    907 
    908 (defun picolisp-wiki-insert-header (n)
    909   "Insert an picolisp-wiki-style header.
    910 With no prefix argument, insert a level-1 header.  With prefix N,
    911 insert a level-N header.  If Transient Mark mode is on and the
    912 region is active, it is used as the header text."
    913   (interactive "p")
    914   (unless n                             ; Test to see if n is defined
    915     (setq n 1))                         ; Default to level 1 header
    916   (picolisp-wiki-wrap-or-insert
    917    (concat (number-to-string n) "{") "}" 'BEG-NEWLINE-P)
    918   (backward-char 1))
    919 
    920 
    921 
    922 ;;; Keymap ====================================================================
    923 
    924 (defvar picolisp-wiki-mode-map
    925   (let ((map (make-keymap)))
    926     ;; Element insertion
    927     (define-key map "\C-c\C-ln" 'picolisp-wiki-insert-internal-link)
    928     (define-key map "\C-c\C-lx" 'picolisp-wiki-insert-external-link)
    929     (define-key map "\C-c\C-lu" 'picolisp-wiki-insert-unordered-list)
    930     (define-key map "\C-c\C-lo" 'picolisp-wiki-insert-ordered-list)
    931     (define-key map "\C-c\C-li" 'picolisp-wiki-insert-list-item)
    932     (define-key map "\C-c\C-fl" 'picolisp-wiki-insert-left-floating-content)
    933     (define-key map "\C-c\C-fn" 'picolisp-wiki-insert-non-floating-content)
    934     (define-key map "\C-c\C-fr" 'picolisp-wiki-insert-right-floating-content)
    935     (define-key map "\C-c\C-ck" 'picolisp-wiki-insert-line-breaks)
    936     (define-key map "\C-c\C-c1" 'picolisp-wiki-insert-header-1)
    937     (define-key map "\C-c\C-c2" 'picolisp-wiki-insert-header-2)
    938     (define-key map "\C-c\C-c3" 'picolisp-wiki-insert-header-3)
    939     (define-key map "\C-c\C-c4" 'picolisp-wiki-insert-header-4)
    940     (define-key map "\C-c\C-c5" 'picolisp-wiki-insert-header-5)
    941     (define-key map "\C-c\C-c6" 'picolisp-wiki-insert-header-6)
    942     (define-key map "\C-c\C-cb" 'picolisp-wiki-insert-bold)
    943     (define-key map "\C-c\C-ci" 'picolisp-wiki-insert-italic)
    944     (define-key map "\C-c\C-cu" 'picolisp-wiki-insert-underlined)
    945     (define-key map "\C-c\C-cp" 'picolisp-wiki-insert-pre-block)
    946     (define-key map "\C-c\C-cc" 'picolisp-wiki-insert-comment)
    947     (define-key map "\C-c\C-c-" 'picolisp-wiki-insert-hr)
    948     ;; Visibility cycling
    949     (define-key map (kbd "<tab>") 'picolisp-wiki-cycle)
    950     (define-key map (kbd "<S-iso-lefttab>") 'picolisp-wiki-shifttab)
    951     ;; Header navigation
    952     (define-key map (kbd "C-M-n") 'outline-next-visible-heading)
    953     (define-key map (kbd "C-M-p") 'outline-previous-visible-heading)
    954     (define-key map (kbd "C-M-f") 'outline-forward-same-level)
    955     (define-key map (kbd "C-M-b") 'outline-backward-same-level)
    956     (define-key map (kbd "C-M-u") 'outline-up-heading)
    957     ;; Picolisp-Wiki functions
    958     ;; (define-key map "\C-c\C-cm" 'picolisp-wiki)
    959     ;; (define-key map "\C-c\C-cp" 'picolisp-wiki-preview)
    960     ;; (define-key map "\C-c\C-ce" 'picolisp-wiki-export)
    961     ;; (define-key map "\C-c\C-cv" 'picolisp-wiki-export-and-view)
    962     map)
    963   "Keymap for Picolisp-Wiki major mode.")
    964 
    965 
    966 
    967 
    968 
    969 ;;; Menu ==================================================================
    970 
    971 (easy-menu-define picolisp-wiki-mode-menu picolisp-wiki-mode-map
    972   "Menu for Picolisp-Wiki mode"
    973   '("Picolisp-Wiki"
    974     ("Show/Hide"
    975      ["Cycle visibility" picolisp-wiki-cycle (outline-on-heading-p)]
    976      ["Cycle global visibility" picolisp-wiki-shifttab])
    977     "---"
    978     ("Headers"
    979      ["First level" picolisp-wiki-insert-header-1]
    980      ["Second level" picolisp-wiki-insert-header-2]
    981      ["Third level" picolisp-wiki-insert-header-3]
    982      ["Fourth level" picolisp-wiki-insert-header-4]
    983      ["Fifth level" picolisp-wiki-insert-header-5]
    984      ["Sixth level" picolisp-wiki-insert-header-6])
    985     "---"
    986     ["Bold" picolisp-wiki-insert-bold]
    987     ["Italic" picolisp-wiki-insert-italic]
    988     ["Underlined" picolisp-wiki-insert-underlined]
    989     ["Preformatted" picolisp-wiki-insert-pre-block]
    990     ["Comment" picolisp-wiki-insert-comment]
    991     ["Insert horizontal rule" picolisp-wiki-insert-hr]
    992     "---"
    993     ["Insert internal link" picolisp-wiki-insert-internal-link]
    994     ["Insert external link" picolisp-wiki-insert-external-link]
    995     "---"
    996     ["Insert left-floating content" picolisp-wiki-insert-left-floating-content]
    997     ["Insert non-floating content" picolisp-wiki-insert-non-floating-content]
    998     ["Insert right-floating content" picolisp-wiki-insert-right-floating-content]
    999     "---"
   1000     ["Insert unordered list" picolisp-wiki-insert-unordered-list]
   1001     ["Insert ordered list" picolisp-wiki-insert-ordered-list]
   1002     "---"
   1003     ["Version" picolisp-wiki-show-version]
   1004     ))
   1005 
   1006 
   1007 
   1008 ;;; Outline ===================================================================
   1009 
   1010 ;; The following visibility cycling code was taken from org-mode
   1011 ;; by Carsten Dominik and adapted for picolisp-wiki-mode.
   1012 
   1013 (defvar picolisp-wiki-cycle-global-status 1)
   1014 (defvar picolisp-wiki-cycle-subtree-status nil)
   1015 
   1016 ;; Based on org-end-of-subtree from org.el
   1017 (defun picolisp-wiki-end-of-subtree (&optional invisible-OK)
   1018   "Move to the end of the current subtree.
   1019 Only visible heading lines are considered, unless INVISIBLE-OK is
   1020 non-nil."
   1021   (outline-back-to-heading invisible-OK)
   1022   (let ((first t)
   1023         (level (funcall outline-level)))
   1024     (while (and (not (eobp))
   1025                 (or first (> (funcall outline-level) level)))
   1026       (setq first nil)
   1027       (outline-next-heading))
   1028     (if (memq (preceding-char) '(?\n ?\^M))
   1029         (progn
   1030           ;; Go to end of line before heading
   1031           (forward-char -1)
   1032           (if (memq (preceding-char) '(?\n ?\^M))
   1033               ;; leave blank line before heading
   1034               (forward-char -1)))))
   1035   (point))
   1036 
   1037 ;; Based on org-cycle from org.el.
   1038 (defun picolisp-wiki-cycle (&optional arg)
   1039   "Visibility cycling for Picolisp-Wiki mode.
   1040 If ARG is t, perform global visibility cycling. If the point is
   1041 at an picolisp-wiki-style header, cycle visibility of the
   1042 corresponding subtree. Otherwise, insert a tab using
   1043 `indent-relative'."
   1044   (interactive "P")
   1045   (cond
   1046      ((eq arg t) ;; Global cycling
   1047       (cond
   1048        ((and (eq last-command this-command)
   1049              (eq picolisp-wiki-cycle-global-status 2))
   1050         ;; Move from overview to contents
   1051         (hide-sublevels 1)
   1052         (message "CONTENTS")
   1053         (setq picolisp-wiki-cycle-global-status 3))
   1054 
   1055        ((and (eq last-command this-command)
   1056              (eq picolisp-wiki-cycle-global-status 3))
   1057         ;; Move from contents to all
   1058         (show-all)
   1059         (message "SHOW ALL")
   1060         (setq picolisp-wiki-cycle-global-status 1))
   1061 
   1062        (t
   1063         ;; Defaults to overview
   1064         (hide-body)
   1065         (message "OVERVIEW")
   1066         (setq picolisp-wiki-cycle-global-status 2))))
   1067 
   1068      ((save-excursion (beginning-of-line 1) (looking-at outline-regexp))
   1069       ;; At a heading: rotate between three different views
   1070       (outline-back-to-heading)
   1071       (let ((goal-column 0) eoh eol eos)
   1072         ;; Determine boundaries
   1073         (save-excursion
   1074           (outline-back-to-heading)
   1075           (save-excursion
   1076             (beginning-of-line 2)
   1077             (while (and (not (eobp)) ;; this is like `next-line'
   1078                         (get-char-property (1- (point)) 'invisible))
   1079               (beginning-of-line 2)) (setq eol (point)))
   1080           (outline-end-of-heading)   (setq eoh (point))
   1081           (picolisp-wiki-end-of-subtree t)
   1082           (skip-chars-forward " \t\n")
   1083           (beginning-of-line 1) ; in case this is an item
   1084           (setq eos (1- (point))))
   1085         ;; Find out what to do next and set `this-command'
   1086       (cond
   1087          ((= eos eoh)
   1088           ;; Nothing is hidden behind this heading
   1089           (message "EMPTY ENTRY")
   1090           (setq picolisp-wiki-cycle-subtree-status nil))
   1091          ((>= eol eos)
   1092           ;; Entire subtree is hidden in one line: open it
   1093           (show-entry)
   1094           (show-children)
   1095           (message "CHILDREN")
   1096           (setq picolisp-wiki-cycle-subtree-status 'children))
   1097          ((and (eq last-command this-command)
   1098                (eq picolisp-wiki-cycle-subtree-status 'children))
   1099           ;; We just showed the children, now show everything.
   1100           (show-subtree)
   1101           (message "SUBTREE")
   1102           (setq picolisp-wiki-cycle-subtree-status 'subtree))
   1103          (t
   1104           ;; Default action: hide the subtree.
   1105           (hide-subtree)
   1106           (message "FOLDED")
   1107           (setq picolisp-wiki-cycle-subtree-status 'folded)))))
   1108 
   1109      (t
   1110       (indent-for-tab-command))))
   1111 
   1112 ;; Based on org-shifttab from org.el.
   1113 (defun picolisp-wiki-shifttab ()
   1114   "Global visibility cycling.
   1115 Calls `picolisp-wiki-cycle' with argument t."
   1116   (interactive)
   1117   (picolisp-wiki-cycle t))
   1118 
   1119 
   1120 ;;; Miscellaneous =============================================================
   1121 
   1122 (defun picolisp-wiki-line-number-at-pos (&optional pos)
   1123   "Return (narrowed) buffer line number at position POS.
   1124 If POS is nil, use current buffer location.
   1125 This is an exact copy of `line-number-at-pos' for use in emacs21."
   1126   (let ((opoint (or pos (point))) start)
   1127     (save-excursion
   1128       (goto-char (point-min))
   1129       (setq start (point))
   1130       (goto-char opoint)
   1131       (forward-line 0)
   1132       (1+ (count-lines start (point))))))
   1133 
   1134 (defun picolisp-wiki-nobreak-p ()
   1135   "Return nil if it is acceptable to break the current line at the point."
   1136   ;; inside in square brackets (e.g., link anchor text)
   1137   (looking-back "\\[[^]]*"))
   1138 
   1139 
   1140 
   1141 ;;; Mode definition  ==========================================================
   1142 
   1143 (defun picolisp-wiki-show-version ()
   1144   "Show the version number in the minibuffer."
   1145   (interactive)
   1146   (message "picolisp-wiki-mode, version %s" picolisp-wiki-mode-version))
   1147 
   1148 ;;;###autoload
   1149 (define-derived-mode picolisp-wiki-mode text-mode "PicoLisp-Wiki"
   1150   "Major mode for editing PicoLisp-Wiki files."
   1151   ;; Natural Picolisp-Wiki tab width
   1152   (setq tab-width 4)
   1153   ;; Comments
   1154   (make-local-variable 'comment-start)
   1155   (setq comment-start "#{")
   1156   (make-local-variable 'comment-end)
   1157   (setq comment-end "}")
   1158   ;; (make-local-variable 'comment-start-skip)
   1159   ;; (setq comment-start-skip "#{ \t}*")
   1160   (make-local-variable 'comment-column)
   1161   (setq comment-column 0)
   1162   ;; Font lock.
   1163   (set (make-local-variable 'font-lock-defaults)
   1164        '(picolisp-wiki-mode-font-lock-keywords))
   1165   (set (make-local-variable 'font-lock-multiline) t)
   1166   ;; Make filling work with lists (unordered, ordered, and definition)
   1167   ;; (set (make-local-variable 'paragraph-start)
   1168   ;;      "\f\\|[ \t]*$\\|^[ \t]*[*+-] \\|^[ \t*][0-9]+\\.\\|^[ \t]*: ")
   1169   ;; Outline mode
   1170   (make-local-variable 'eval)
   1171   (setq eval (outline-minor-mode))
   1172   (make-local-variable 'outline-regexp)
   1173   ;; (setq outline-regexp "^[ \t]*[0-9]{")
   1174   (setq outline-regexp
   1175         "^[ 	]*\\(1{\\|2{.\\|3{..\\|4{...\\|5{....\\|6{.....\\)")
   1176   ;; Cause use of ellipses for invisible text.
   1177   (add-to-invisibility-spec '(outline . t)))
   1178 
   1179 
   1180 (provide 'picolisp-wiki-mode)
   1181 
   1182 ;;; picolisp-wiki-mode.el ends here