~mwshinn/+junk/notes3

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
;;; notes3-mode.el --- Emacs mode for notes files

;; Copyright (C) 2012-2015 by Max Shinn

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

;; This file 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
;; General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.


; Here are the default definitions of all of the faces.  Like always,
; they can be changed with "M-x customize-face".

(defgroup notes3-faces nil
  "Notes highlighting"
  :group 'notes)

(defface notes3-document-title-face
  `((((class color) (background dark))
     (:bold t :height 1.2 :inherit variable-pitch))
    (((class color) (background light))
     (:bold t :height 1.2 :inherit variable-pitch))
    (t (:bold t :height 1.2 :inherit variable-pitch)))
  "The face for the title of the docuent."
  :group 'notes3-faces)

(defface notes3-important-face
  `((((class color) (background dark))
     (:foreground "#ff3030" :bold t))
    (((class color) (background light))
     (:foreground "#ff0000" :bold t))
    (t (:foreground "#ff0000" :bold t)))
  "The face for the -> symbol in important text."
  :group 'notes3-faces)

; These need to be specifically added to font-lock because the
; keywords list is cemented into the markdown-mode font-lock list at
; markdown-mode's initialization.  So it is not possible to override
; this cleanly.

(defconst notes3-uri-types '("doi" "pmid" "isbn"))
; (defconst notes3-regex-uri
;   (concat (regexp-opt notes3-uri-types) ":[^]\t\n\r<>,;() ]+"))
(defconst notes3-regex-angle-uri
  (concat "\\(<\\)\\(" (regexp-opt notes3-uri-types) "\\):\\([^]\t\n\r<>,;()]+\\)\\(>\\)"))

; This is the regex that matches all of the things to be highlighted.
; This will later be combined with the markdown-mode regex.

(defconst notes3-font-lock-keywords
  `(
   ("^UPDATE ([0-9/-]+):" . font-lock-keyword-face)
   ("^Title: .*$" . 'notes3-document-title-face)
   ("^-> " . 'notes3-important-face)
   (,notes3-regex-angle-uri . 'markdown-link-face)
   ))

; Finally, we begin the definition of the mode itself.

(define-derived-mode notes3-mode markdown-mode "Notes mode"
  "A major mode to make editing notes easier"
  (setq font-lock-defaults 
        (list (append notes3-font-lock-keywords markdown-mode-font-lock-keywords)))
  (font-lock-refresh-defaults)

  ; Ignore latex syntax in notes when doing spellcheck
  (set (make-variable-buffer-local 'ispell-parser) 'tex)

  ; Map C-c C-e to running "extract-code.pl" on the current buffer.
  (define-key notes3-mode-map (kbd "C-c C-e") 
    (lambda () 
      (interactive) 
      (save-window-excursion 
        (shell-command (concatenate 'string 
                                    "/home/max/Scripts/notes3/extract-code " 
                                    (buffer-file-name)
                                    )))))
  ; Map C-c C-l to viewing the latex error output
  (define-key notes3-mode-map (kbd "C-c C-l") 
    (lambda () 
      (interactive)
      (let ((buffername (buffer-file-name)))
        (if (file-exists-p (concatenate 'string buffername ".log"))
          (progn
            (pop-to-buffer (generate-new-buffer "*Error output*"))
            (find-file (concatenate 'string buffername ".log"))
            (end-of-buffer)
        )
        (message "No errors"))
      )))
  ; Map C-c C-c to compiling the current buffer with "ncompile".  If
  ; there is an error, display the error output.
  (define-key notes3-mode-map (kbd "C-c C-c")
    (lambda () 
      (interactive) 
      (let ((oldwindow (current-window-configuration))
            (ncompileoutput (shell-command-to-string (concatenate 'string 
                                                         "/home/max/Scripts/notes3/ncompile " (buffer-file-name)))))
        (if (> (length ncompileoutput) 1)
          (progn
            (pop-to-buffer (generate-new-buffer "*Error output*"))
            (insert ncompileoutput))
          (message "Compilation complete.  Use C-c C-v to view.")
          )
        )))
  ; View the output pdf.  This should probably use "xdg-open" instead of
  ; hard-coding "okular".
  (define-key notes3-mode-map (kbd "C-c C-v") 
    (lambda () 
      (interactive) 
      (save-window-excursion 
        (shell-command (concatenate 'string 
                                    "xdg-open " 
                                    (buffer-file-name)
                                    ".pdf &")))))

; TODO I can't figure out a good way to programmatically override a
; list that is in customize in some way that is major-mode specific.
; There should be some way to do this, but it is unclear to me.
; Instead, I just overrode the relevant functions from markdown-mode,
; which isn't the best way to do it since it now affects all
; markdown-mode buffers, but I think the changes are minor enough that
; it doesn't really matter.

  (defun markdown-link-p ()
    "Return non-nil when `point' is at a non-wiki link.
See `markdown-wiki-link-p' for more information.  Overridden to work with doi/pmid/isbn links."
    (let ((case-fold-search nil))
      (and (not (markdown-wiki-link-p))
           (or (thing-at-point-looking-at markdown-regex-link-inline)
               (thing-at-point-looking-at markdown-regex-link-reference)
               (thing-at-point-looking-at markdown-regex-uri)
               (thing-at-point-looking-at notes3-regex-angle-uri)
               (thing-at-point-looking-at markdown-regex-angle-uri)))))

  (defun is-in-notes-dir (filename)
    "Checks to see if filename is a file located in the note's
directory, i.e. the filename plus '.d'."
    (and (not (string-equal filename ""))
         (file-exists-p (concatenate 'string (buffer-file-name) ".d/" filename))))
    

  (defun notes3-link-link ()
    "Returns the link to the pmid/doi/isbn link under the cursor,
and falls back to markdown-link-link on failure."
    (cond
     ((thing-at-point-looking-at markdown-regex-link-inline)
      (if (is-in-notes-dir (match-string-no-properties 5))
          (concatenate 'string (buffer-file-name) ".d/" (match-string-no-properties 5))
        (markdown-link-link)))
     ((thing-at-point-looking-at markdown-regex-link-reference)
      (let* ((text (match-string-no-properties 2))
             (reference (match-string-no-properties 4))
             (target (downcase (if (string= reference "[]") text reference)))
             (finallink (car (markdown-reference-definition target))))
        (if (is-in-notes-dir finallink)
            (concatenate 'string (buffer-file-name) ".d/" finallink)
          (markdown-link-link))))
     ((thing-at-point-looking-at notes3-regex-angle-uri)
      (cond
       ((string-equal (match-string-no-properties 2) "doi")
          (concatenate 'string "http://dx.doi.org/" (match-string-no-properties 3)))
       ((string-equal (match-string-no-properties 2) "isbn")
        (concatenate 'string "http://www.worldcat.org/isbn/" (match-string-no-properties 3)))
       ((string-equal (match-string-no-properties 2) "pmid")
        (concatenate 'string "http://www.ncbi.nlm.nih.gov/pubmed/" (match-string-no-properties 3)))
       (t (markdown-link-link))
        ))
     ; Could potentially add something similar for notes3-regex-uri
     (t (markdown-link-link))))


  (defun markdown-follow-link-at-point ()
    "Open the current non-wiki link in a browser.  This is a
redefined version of the one provided by markdown-mode that also
allows doi/pmid/isbn links.  It is otherwise backwards compatible
with the original."
    (interactive)
    (cond
     ((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
     ((markdown-link-p) (browse-url (notes3-link-link)))
     (t (error "Point is NOT at a Markdown link or URI"))))

  ; Hopefully we don't need something like this anymore, so commented
  ; out for now...
  ;; ; This offers a convenient way to run "latexify-notes.pl" and view
  ;; ; the output.  It can be run with "M-x latexify-notes".
  ;; (defun latexify-notes ()
  ;;   "Create a latexify notes"
  ;;   (interactive nil)
  ;;   (shell-command (concatenate 'string "/opt/notes3-bin/latexify-notes.pl " (buffer-file-name)))
  ;;   )

)

; Start orgtbl-mode on startup
(add-hook 'notes3-mode-hook 'notes3-minor-modes-hook)
(defun notes3-minor-modes-hook ()
  (orgtbl-mode 1))

; Finally, associate ".n" files with this major mode.
(setq auto-mode-alist (cons '("\\.n$" . notes3-mode) auto-mode-alist))
(provide 'notes3-mode)