14
by Max Shinn
Emacs notes3-mode |
1 |
;;; notes3-mode.el --- Emacs mode for notes files
|
2 |
||
3 |
;; Copyright (C) 2012-2015 by Max Shinn
|
|
4 |
||
5 |
;; This file is free software; you can redistribute it and/or modify
|
|
6 |
;; it under the terms of the GNU General Public License as published
|
|
7 |
;; by the Free Software Foundation; either version 2, or (at your
|
|
8 |
;; option) any later version.
|
|
9 |
||
10 |
;; This file is distributed in the hope that it will be useful, but
|
|
11 |
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13 |
;; General Public License for more details.
|
|
14 |
||
15 |
;; You should have received a copy of the GNU General Public License
|
|
16 |
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
17 |
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
18 |
;; Boston, MA 02111-1307, USA.
|
|
19 |
||
20 |
||
21 |
; Here are the default definitions of all of the faces. Like always,
|
|
22 |
; they can be changed with "M-x customize-face".
|
|
23 |
||
24 |
(defgroup notes3-faces nil |
|
25 |
"Notes highlighting"
|
|
26 |
:group 'notes) |
|
27 |
||
28 |
(defface notes3-document-title-face |
|
29 |
`((((class color) (background dark)) |
|
30 |
(:bold t :height 1.2 :inherit variable-pitch)) |
|
31 |
(((class color) (background light)) |
|
32 |
(:bold t :height 1.2 :inherit variable-pitch)) |
|
33 |
(t (:bold t :height 1.2 :inherit variable-pitch))) |
|
34 |
"The face for the title of the docuent."
|
|
35 |
:group 'notes3-faces) |
|
36 |
||
37 |
(defface notes3-important-face |
|
38 |
`((((class color) (background dark)) |
|
39 |
(:foreground "#ff3030" :bold t)) |
|
40 |
(((class color) (background light)) |
|
41 |
(:foreground "#ff0000" :bold t)) |
|
42 |
(t (:foreground "#ff0000" :bold t))) |
|
43 |
"The face for the -> symbol in important text."
|
|
44 |
:group 'notes3-faces) |
|
45 |
||
46 |
; These need to be specifically added to font-lock because the
|
|
47 |
; keywords list is cemented into the markdown-mode font-lock list at
|
|
48 |
; markdown-mode's initialization. So it is not possible to override
|
|
49 |
; this cleanly.
|
|
50 |
||
51 |
(defconst notes3-uri-types '("doi" "pmid" "isbn")) |
|
52 |
; (defconst notes3-regex-uri
|
|
53 |
; (concat (regexp-opt notes3-uri-types) ":[^]\t\n\r<>,;() ]+"))
|
|
54 |
(defconst notes3-regex-angle-uri |
|
55 |
(concat "\\(<\\)\\(" (regexp-opt notes3-uri-types) "\\):\\([^]\t\n\r<>,;()]+\\)\\(>\\)")) |
|
56 |
||
57 |
; This is the regex that matches all of the things to be highlighted.
|
|
58 |
; This will later be combined with the markdown-mode regex.
|
|
59 |
||
60 |
(defconst notes3-font-lock-keywords |
|
61 |
`( |
|
62 |
("^UPDATE ([0-9/-]+):" . font-lock-keyword-face) |
|
63 |
("^Title: .*$" . 'notes3-document-title-face) |
|
64 |
("^-> " . 'notes3-important-face) |
|
65 |
(,notes3-regex-angle-uri . 'markdown-link-face) |
|
66 |
))
|
|
67 |
||
68 |
; Finally, we begin the definition of the mode itself.
|
|
69 |
||
70 |
(define-derived-mode notes3-mode markdown-mode "Notes mode" |
|
71 |
"A major mode to make editing notes easier"
|
|
72 |
(setq font-lock-defaults |
|
73 |
(list (append notes3-font-lock-keywords markdown-mode-font-lock-keywords))) |
|
74 |
(font-lock-refresh-defaults) |
|
75 |
||
76 |
; Ignore latex syntax in notes when doing spellcheck
|
|
77 |
(set (make-variable-buffer-local 'ispell-parser) 'tex) |
|
78 |
||
79 |
; Map C-c C-e to running "extract-code.pl" on the current buffer.
|
|
80 |
(define-key notes3-mode-map (kbd "C-c C-e") |
|
81 |
(lambda () |
|
82 |
(interactive) |
|
83 |
(save-window-excursion |
|
84 |
(shell-command (concatenate 'string |
|
29.1.1
by Max Shinn
Changing paths |
85 |
"/home/max/Scripts/notes3/extract-code "
|
14
by Max Shinn
Emacs notes3-mode |
86 |
(buffer-file-name) |
87 |
)))))
|
|
88 |
; Map C-c C-l to viewing the latex error output
|
|
89 |
(define-key notes3-mode-map (kbd "C-c C-l") |
|
90 |
(lambda () |
|
91 |
(interactive) |
|
92 |
(let ((buffername (buffer-file-name))) |
|
93 |
(if (file-exists-p (concatenate 'string buffername ".log")) |
|
94 |
(progn |
|
95 |
(pop-to-buffer (generate-new-buffer "*Error output*")) |
|
96 |
(find-file (concatenate 'string buffername ".log")) |
|
97 |
(end-of-buffer) |
|
98 |
)
|
|
99 |
(message "No errors")) |
|
100 |
)))
|
|
101 |
; Map C-c C-c to compiling the current buffer with "ncompile". If
|
|
102 |
; there is an error, display the error output.
|
|
103 |
(define-key notes3-mode-map (kbd "C-c C-c") |
|
104 |
(lambda () |
|
105 |
(interactive) |
|
106 |
(let ((oldwindow (current-window-configuration)) |
|
107 |
(ncompileoutput (shell-command-to-string (concatenate 'string |
|
18
by Max Shinn
Fixed problem with punctuation after short file links |
108 |
"/home/max/Scripts/notes3/ncompile " (buffer-file-name))))) |
14
by Max Shinn
Emacs notes3-mode |
109 |
(if (> (length ncompileoutput) 1) |
110 |
(progn |
|
111 |
(pop-to-buffer (generate-new-buffer "*Error output*")) |
|
112 |
(insert ncompileoutput)) |
|
113 |
(message "Compilation complete. Use C-c C-v to view.") |
|
114 |
)
|
|
115 |
)))
|
|
116 |
; View the output pdf. This should probably use "xdg-open" instead of
|
|
117 |
; hard-coding "okular".
|
|
118 |
(define-key notes3-mode-map (kbd "C-c C-v") |
|
119 |
(lambda () |
|
120 |
(interactive) |
|
121 |
(save-window-excursion |
|
122 |
(shell-command (concatenate 'string |
|
123 |
"xdg-open "
|
|
124 |
(buffer-file-name) |
|
125 |
".pdf &"))))) |
|
126 |
||
127 |
; TODO I can't figure out a good way to programmatically override a
|
|
128 |
; list that is in customize in some way that is major-mode specific.
|
|
129 |
; There should be some way to do this, but it is unclear to me.
|
|
130 |
; Instead, I just overrode the relevant functions from markdown-mode,
|
|
131 |
; which isn't the best way to do it since it now affects all
|
|
132 |
; markdown-mode buffers, but I think the changes are minor enough that
|
|
133 |
; it doesn't really matter.
|
|
134 |
||
135 |
(defun markdown-link-p () |
|
136 |
"Return non-nil when `point' is at a non-wiki link. |
|
137 |
See `markdown-wiki-link-p' for more information. Overridden to work with doi/pmid/isbn links." |
|
138 |
(let ((case-fold-search nil)) |
|
139 |
(and (not (markdown-wiki-link-p)) |
|
140 |
(or (thing-at-point-looking-at markdown-regex-link-inline) |
|
141 |
(thing-at-point-looking-at markdown-regex-link-reference) |
|
142 |
(thing-at-point-looking-at markdown-regex-uri) |
|
143 |
(thing-at-point-looking-at notes3-regex-angle-uri) |
|
144 |
(thing-at-point-looking-at markdown-regex-angle-uri))))) |
|
145 |
||
146 |
(defun is-in-notes-dir (filename) |
|
147 |
"Checks to see if filename is a file located in the note's
|
|
148 |
directory, i.e. the filename plus '.d'."
|
|
149 |
(and (not (string-equal filename "")) |
|
150 |
(file-exists-p (concatenate 'string (buffer-file-name) ".d/" filename)))) |
|
151 |
||
152 |
||
153 |
(defun notes3-link-link () |
|
154 |
"Returns the link to the pmid/doi/isbn link under the cursor,
|
|
155 |
and falls back to markdown-link-link on failure."
|
|
156 |
(cond |
|
157 |
((thing-at-point-looking-at markdown-regex-link-inline) |
|
158 |
(if (is-in-notes-dir (match-string-no-properties 5)) |
|
159 |
(concatenate 'string (buffer-file-name) ".d/" (match-string-no-properties 5)) |
|
160 |
(markdown-link-link))) |
|
161 |
((thing-at-point-looking-at markdown-regex-link-reference) |
|
162 |
(let* ((text (match-string-no-properties 2)) |
|
163 |
(reference (match-string-no-properties 4)) |
|
164 |
(target (downcase (if (string= reference "[]") text reference))) |
|
165 |
(finallink (car (markdown-reference-definition target)))) |
|
166 |
(if (is-in-notes-dir finallink) |
|
167 |
(concatenate 'string (buffer-file-name) ".d/" finallink) |
|
168 |
(markdown-link-link)))) |
|
169 |
((thing-at-point-looking-at notes3-regex-angle-uri) |
|
170 |
(cond |
|
171 |
((string-equal (match-string-no-properties 2) "doi") |
|
172 |
(concatenate 'string "http://dx.doi.org/" (match-string-no-properties 3))) |
|
173 |
((string-equal (match-string-no-properties 2) "isbn") |
|
174 |
(concatenate 'string "http://www.worldcat.org/isbn/" (match-string-no-properties 3))) |
|
175 |
((string-equal (match-string-no-properties 2) "pmid") |
|
176 |
(concatenate 'string "http://www.ncbi.nlm.nih.gov/pubmed/" (match-string-no-properties 3))) |
|
177 |
(t (markdown-link-link)) |
|
178 |
))
|
|
179 |
; Could potentially add something similar for notes3-regex-uri
|
|
180 |
(t (markdown-link-link)))) |
|
181 |
||
182 |
||
183 |
(defun markdown-follow-link-at-point () |
|
184 |
"Open the current non-wiki link in a browser. This is a
|
|
185 |
redefined version of the one provided by markdown-mode that also
|
|
186 |
allows doi/pmid/isbn links. It is otherwise backwards compatible
|
|
187 |
with the original."
|
|
188 |
(interactive) |
|
189 |
(cond |
|
190 |
((thing-at-point-looking-at notes3-regex-angle-uri) (browse-url (notes3-link-link))) ; This goes first because pmid intersects with mid and the overridden markdown-link-p matches notes3-regex-uri |
|
191 |
((markdown-link-p) (browse-url (notes3-link-link))) |
|
192 |
(t (error "Point is NOT at a Markdown link or URI")))) |
|
193 |
||
194 |
; Hopefully we don't need something like this anymore, so commented
|
|
195 |
; out for now...
|
|
196 |
;; ; This offers a convenient way to run "latexify-notes.pl" and view
|
|
197 |
;; ; the output. It can be run with "M-x latexify-notes".
|
|
198 |
;; (defun latexify-notes ()
|
|
199 |
;; "Create a latexify notes"
|
|
200 |
;; (interactive nil)
|
|
201 |
;; (shell-command (concatenate 'string "/opt/notes3-bin/latexify-notes.pl " (buffer-file-name)))
|
|
202 |
;; )
|
|
203 |
||
204 |
)
|
|
205 |
||
206 |
; Start orgtbl-mode on startup
|
|
207 |
(add-hook 'notes3-mode-hook 'notes3-minor-modes-hook) |
|
208 |
(defun notes3-minor-modes-hook () |
|
209 |
(orgtbl-mode 1)) |
|
210 |
||
211 |
; Finally, associate ".n" files with this major mode.
|
|
212 |
(setq auto-mode-alist (cons '("\\.n$" . notes3-mode) auto-mode-alist)) |
|
213 |
(provide 'notes3-mode) |