aboutsummaryrefslogtreecommitdiff
path: root/emacs/.emacs.d/lisp/my/wiki.el
blob: c1ea0644b89aff3a774141ad7cea18c7396960d8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
;;; wiki.el -- A wikitext mode -*- lexical-binding: t -*-

;; Copyright (C) 2023 Free Software Foundation.

;; Author: Yuchen Pei <id@ypei.org>
;; Package-Requires: ((emacs "28.2"))

;; This file is part of dotted.

;; dotted is free software: you can redistribute it and/or modify it under
;; the terms of the GNU Affero General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; dotted is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
;; Public License for more details.

;; You should have received a copy of the GNU Affero General Public
;; License along with dotted.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; A wikitext mode.

;;; Code:
(require 'wiki-faces)

(defvar wiki-url-regexp "https?://[^ ]+")

(defvar wiki-external-link-re
  (rx (seq "[["
           (group (seq "http"
                       (opt "s")
                       "://"
                       (+ (not " "))))
           (opt (seq " " (group (+? anything))))
           "]]")))

(defvar wiki-internal-link-re
  (rx (seq "[["
	         ;; Target
	         (group
	          (one-or-more
             (not (any "[|]"))))
		       ;; Label (optional)
		       (opt (seq "|" (group (+? anything))))
		       "]]"))
  ;; "\\(\\[\\[\\)\\([^][|]+\\)\\(|\\)\\([^][|]+\\)\\(\\]\\]\\)"
  )

(defvar wiki-font-lock-keywords
  (list
   (cons "^======.*======\\ *$" 'wiki-level-6)
   (cons "^=====.*=====\\ *$" 'wiki-level-5)
   (cons "^====.*====\\ *$" 'wiki-level-4)
   (cons "^===.*===\\ *$" 'wiki-level-3)
   (cons "^==.*==\\ *$" 'wiki-level-2)
   (cons "^=.*=\\ *$" 'wiki-level-1)
   (cons "^----+\\ *$" 'wiki-hr-face)
   (cons "'''''[^ \t\n].*?[^ \t\n]'''''" 'wiki-bold-italic)
   (cons "'''[^ \t\n'].*?[^ \t\n']'''" 'wiki-bold)
   (cons "''[^ \t\n'].*?[^ \t\n']''" 'wiki-italic)
   (cons "^ .*$" 'wiki-pre-face)
   '(wiki-activate-external-links)
   '(wiki-activate-internal-links)
   ))

(defvar wiki-outline-regexp "=+.*=+\ *$")

(defun wiki-outline-level ()
  (when (looking-at "\\(=+\\).*\\(=+\\)\ *$")
    (min (length (match-string 1))
         (length (match-string 2))
         6)))

;; Like `org-activate-links'
(defun wiki-activate-links (link-re limit)
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward link-re limit t)
      (let ((start (match-beginning 0))
            (end (match-end 0))
            (visible-start (or (match-beginning 2) (match-beginning 1)))
            (visible-end (or (match-end 2) (match-end 1)))
            )
        (put-text-property start visible-start 'invisible t)
        (put-text-property start end 'font-lock-face 'wiki-link)
        (put-text-property visible-end end 'invisible t)
        (add-text-properties (1- visible-start) visible-start
                             '(rear-nonsticky (invisible)))
        (add-text-properties (1- visible-end) visible-end
                             '(rear-nonsticky (invisible)))
        ))))

(defun wiki-activate-internal-links (limit)
  (wiki-activate-links wiki-internal-link-re limit))

(defun wiki-activate-external-links (limit)
  (wiki-activate-links wiki-external-link-re limit))

(define-derived-mode wiki-mode outline-mode "Wiki"
  "A wikitext mode."

  (setq-local comment-start "<!--")
  (setq-local comment-end "-->")

  ;; FIXME: this should not be necessary in outline mode
  (setq-local font-lock-defaults '(wiki-font-lock-keywords t nil nil nil))
  (setq-local outline-regexp wiki-outline-regexp)
  (setq-local outline-level 'wiki-outline-level)
  )

(provide 'wiki)
;;; wiki.el ends here