~mwshinn/+junk/notes

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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
;;; notes-mode.el --- Emacs mode for notes files

;; Copyright (C) 2012-2013 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.



; These functions allow for code to be edited inline when enclodes
; with the "===>" and "<===" markers.  This uses org-mode babel for
; the code functionality.  When calling it, first we need to figure
; out what type of file it is.  This figures out which type of file it
; is based on the extension.  A proper extension that will be detected
; is "[something].[ext].n".  Otherwise, it defaults to a generic mode.

(defun notes-mode-from-buffername ()
  ;; Returns the name of the mode associated with the current buffer's
  ;; name, after chopping the ".n" off the end.
  (setq langs '(("pl" . "perl")
                ("py" . "python")
                ("c" . "c")
                ("erl" . "erlang")))
  (setq bn (replace-regexp-in-string "^.*\\.\\([A-Za-z0-9]+\\)\\.n" "\\1" (buffer-file-name)))
  (cdr (assoc bn langs))
)

(defun set-notes-mode-from-buffername ()
  (setq org-edit-src-region-extra (list (list "===>\n?" "\n?<===" (notes-mode-from-buffername))))
  (interactive)
  (org-edit-special)
)

; Call this once to associate the above function with the function
; above with the "C-c '" command.  I don't know why I didn't just put
; this in the mode definition, though I'm assuming there's a good
; reason for it.

(defun set-org-load-notes ()
  (define-key org-mode-map (kbd "C-c '") 'set-notes-mode-from-buffername)
)

; Org-mode automatically handles links.  This function, when passed
; the link name, will return the corect file within the note's
; associated subdirectory.

(defun open-link-file-in-dir (linkname)
  ; Tests to see if there is a file called "linkname" in the notes
  ; subdirectory.  If so, open it and return t.  If not, return nil.
  (if (file-exists-p (concatenate 'string (buffer-file-name) ".d/" linkname))
    (org-open-file (concatenate 'string (buffer-file-name) ".d/" linkname))
    nil))

; This treats all code segments as comments.  I could have treated
; them as normal keywords, but then long segments would surpass the
; value of the "jit-lock-chunk-size" variable.  Also, this avoids
; stray dollar signs, quotes, and whatnot.

(defvar notes-font-lock-syntactic-keywords
  '(("===>\\(\n\\)" (1 "< b"))
    ("<==="
     (0 (unless (eq (match-beginning 0) (point-min))
          (put-text-property (1- (match-beginning 0)) (match-beginning 0)
                             'syntax-table (eval-when-compile 
                                             (string-to-syntax "> b")))
          (put-text-property (1- (match-beginning 0)) (match-end 0)
                             'font-lock-multiline t)
          nil)))))

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

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

(defface notes-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 'notes-faces)

(defface notes-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 'notes-faces)

(defface notes-math-face
  `((((class color) (background dark))
     (:foreground "#ccccff"))
    (((class color) (background light))
     (:foreground "#990099"))
    (t (:foreground "#990099")))
  "The face for both block and inline latex math text."
  :group 'notes-faces)

; The following functions are needed to allow for multiline font
; locking.  Multiline font locking is a pain in the butt, and if you
; can avoid it in any way possible, it is a good idea to do so.
; However, I noticed that without it, I often had a problem with
; mismatched math environment symbols and things like that.  So, I had
; no choce.  I would not have been able to figure this out without the
; following website: http://a-kat.com/Multi-Line_Re-Fontification.html

; The following two functions ensure that the multiline segments will
; be rehighlighted correctly.  This first one is called after every
; edit to the buffer, and defines the area that should be highlighted.

; Problems with tables when this was turned on - FIXME 4/20/13
;; (defun notes-extend-after-change-region (beg end oldlen)
;;   (save-excursion
;;     (goto-char beg)
;;     (search-backward "\n\n" nil t)
;;     (forward-char 2)
;;     (setq begin (point))
;;     (goto-char end)
;;     (search-forward "\n\n" nil t)
;;     (backward-char 2)
;;     (setq ending (point))
;;   (cons begin ending)))

; This function makes sure that when a region is to be rehighlighted,
; it doesn't start in the middle of something.  I don't quite know how
; this one differs from the one above.  Another thing I don't
; understand is why "word-search-backward" is necessary here.  I tried
; replacing this with "search-backward", which caused emacs to hang.
; I can't imagine it is finding anything like this, since "\n\n" isn't
; a word, and probably doesn't make regex that matches anything.

(defun notes-font-lock-extend-region-function ()
  (save-excursion
    (beginning-of-line)
    (condition-case nil
	(progn
	  (word-search-backward "\n\n")
	  (setq font-lock-beg (point)))
      (error nil))))

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

(defconst notes-font-lock-keywords
  '(
   ("^UPDATE ([0-9/]+):" . font-lock-keyword-face)
   ("<<[A-Za-z0-9 \\.-]+>>\\|^[ ]*[A-Za-z]+: " . 'font-lock-type-face)
   ("^> .+$\\|\"[^\"]+\"" . font-lock-constant-face)
;   ("\\$[^\$]*\\$" . 'notes-math-face)
   ("\\`.*$" . 'notes-document-title-face)
   ("^-> " . 'notes-important-face)
   ("^TODO .*$" . 'notes-important-face)
   ))

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

(define-derived-mode notes-mode org-mode "Notes mode"
  "A major mode to make editing notes easier"
  (setq font-lock-defaults 
        (list (append org-font-lock-keywords notes-font-lock-keywords)  
              nil nil nil nil  
              '(font-lock-syntactic-keywords . notes-font-lock-syntactic-keywords)))

; Problems with tables when this was turned on - FIXME 4/20/13
;  (set (make-local-variable 'font-lock-extend-after-change-region-function)
;       'notes-extend-after-change-region)
  (add-to-list (make-local-variable 'font-lock-extend-region-functions)
	       'notes-font-lock-extend-region-function)

  (set (make-local-variable 'jit-lock-chunk-size) 1500)
  (set (make-local-variable 'org-src-preserve-indentation) 0)

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

  (define-key notes-mode-map (kbd "C-c '") 'set-notes-mode-from-buffername)
  ; Map C-c C-e to running "extract-code.pl" on the current buffer.
  (define-key notes-mode-map (kbd "C-c C-e") 
    (lambda () 
      (interactive) 
      (save-window-excursion 
        (shell-command (concatenate 'string 
                                    "/opt/notes-bin/extract-code.pl " 
                                    (buffer-file-name)
                                    )))))
  ; Map C-c C-l to viewing the error output
  (define-key notes-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 notes-mode-map (kbd "C-c C-c")
    (lambda () 
      (interactive) 
      (let ((oldwindow (current-window-configuration))
            (ncompileoutput (shell-command-to-string (concatenate 'string 
                                                         "/opt/notes-bin/ncompile " (buffer-file-name)))))
        (if (string-match-p "Output written on " ncompileoutput)
          (message "Compilation complete.  Use C-c C-v to view.")
          (progn
            (pop-to-buffer (generate-new-buffer "*Error output*"))
            (insert ncompileoutput))
          )
        )))
  ; View the output pdf.  This should probably use "xdg-open" instead of
  ; hard-coding "okular".
  (define-key notes-mode-map (kbd "C-c C-v") 
    (lambda () 
      (interactive) 
      (save-window-excursion 
        (shell-command (concatenate 'string 
                                    "okular " 
                                    (buffer-file-name)
                                    ".pdf &")))))
  ; 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/notes-bin/latexify-notes.pl " (buffer-file-name)))
    )

  ; Open links with the prefix "doi" with a doi resolver, and open
  ; links without a prefix with the default program, provided the file
  ; exists.
  (setq org-link-abbrev-alist
        '(("doi" . "http://dx.doi.org/")))
  (setq org-open-link-functions '(open-link-file-in-dir))
)

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