aboutsummaryrefslogtreecommitdiff
path: root/wiki-markup.el
blob: 4a749746baaff1eaf94675088e721c55833f59f3 (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
118
119
120
121
122
123
124
125
126
127
128
129
;;; wiki-markup.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 wiki-markup.el.

;; wiki-markup.el 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.

;; wiki-markup.el 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 wiki-markup.el.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; A wikitext mode for wiki-markup

;;; 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 "=+.*=+\ *$")

(defvar-local wiki-fetcher nil
  "Buffer-local function to fetch a wiki title")
(defun wiki-follow-wikilink-action (data)
  "Button action to follow a wikilink"
  (funcall wiki-fetcher (alist-get 'title data)))

(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)))
            (title (buffer-substring-no-properties (match-beginning 1)
                                                   (match-end 1)))
            )
        (put-text-property start visible-start 'invisible t)
        (make-text-button start end
                          'action 'wiki-follow-wikilink-action
                          'button-data `((title . ,title)))
        (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 "-->")

  (setq-local font-lock-defaults
              '(wiki-font-lock-keywords
                t
                nil
                nil
                (font-lock-extra-managed-props invisible font-lock-face)))
  (setq-local outline-regexp wiki-outline-regexp)
  (setq-local outline-level 'wiki-outline-level)
  )

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