~mwshinn/+junk/notes3

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)