-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathgolbarg.el
171 lines (144 loc) · 5.63 KB
/
golbarg.el
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
;; golbarg.el
;;
;; Emacs support for Golbarg blogs.
;;
;; To use, just put this file somewhere in the load path and
;; (require 'golbarg)
(require 'markdown-mode)
(require 'org)
(require 'yaml-mode)
;;; Customizable variables ====================================================
(defgroup golbarg nil
"Major mode for editing Golbarg blog posts."
:prefix "golbarg-"
:group 'wp)
(defcustom golbarg-mode-hook nil
"Hook run by `golbarg-mode'."
:group 'golbarg
:type 'hook)
(defcustom golbarg-posts-dir "~/golbarg/posts"
"Golbarg posts directory."
:group 'golbarg
:type 'string)
(defcustom golbarg-drafts-dir "~/golbarg/drafts"
"Golbarg drafts directory."
:group 'golbarg
:type 'string)
(defcustom golbarg-post-ext ""
"Golbarg posts files extension."
:group 'golbarg
:type 'string)
(defcustom golbarg-post-template "title: %s\ndate: %s\ntags: []\n---\n\n"
"Template for Golbarg posts."
:group 'golbarg
:type 'string)
(defvar golbarg-header-face 'golbarg-header-face
"Face for Golbarg posts headers.")
(defface golbarg-header-face
'((t (:background "gray85")))
"Face for Golbarg posts headers."
:group 'golbarg)
;;; Keymap ====================================================================
(defvar golbarg-mode-map
(let ((golbarg-mode-map (make-keymap)))
(define-key golbarg-mode-map "\C-c\C-cp" 'golbarg-preview)
(define-key golbarg-mode-map "\C-c\C-c\C-m" 'golbarg-publish-post)
golbarg-mode-map)
"Keymap for Golbarg major mode.")
;;; Buffer-local variables ====================================================
(defvar golbarg-header-overlay nil
"Overlay used to change the face of the post header.")
(make-variable-buffer-local 'golbarg-header-overlay)
;;; Actual code ===============================================================
(defun golbarg-slug (title)
"Turn a post title into a slug."
(downcase (replace-regexp-in-string "[^A-Za-z0-9]+" "-" title)))
(defun golbarg-new-draft (title)
"Create a draft for a new Golbarg post."
(interactive "MPost title: \n")
(let* ((date (if (interactive-p)
(org-read-date nil nil nil "Post date: ")
(format-time-string "%Y-%m-%d")))
(fn (expand-file-name (concat date "-" (golbarg-slug title) golbarg-post-ext) golbarg-drafts-dir))
(buf (create-file-buffer fn)))
(set-buffer buf)
(set-visited-file-name fn)
(insert (format golbarg-post-template title date))
(switch-to-buffer buf)
(golbarg-mode)))
(defun golbarg-publish-post ()
"Publish a Golbarg post draft. This moves the draft to the
posts directory, renaming the file to if the date or title were
changed."
(interactive)
;; Check if this the buffer is in golbarg-mode
(if (eq major-mode 'golbarg-mode)
(save-excursion
(let (date title new-fn)
;; Look for the date
(goto-char (point-min))
(if (not (re-search-forward "^date:[ \t]*\\(.+\\)$" nil t))
(error "Post date not found"))
(setq date (match-string 1))
;; Look for the title
(goto-char (point-min))
(if (not (re-search-forward "^title:[ \t]*\\(.+\\)$" nil t))
(error "Post title not found"))
(setq title (match-string 1))
;; New filename
(setq new-fn (expand-file-name (concat date "-" (golbarg-slug title) golbarg-post-ext) golbarg-posts-dir))
;; Rename file and buffer
(rename-file (buffer-file-name) new-fn)
(set-visited-file-name new-fn nil t)
(message (concat "This post has been saved as " new-fn))))
(error "This is not a Golbarg post")))
(define-derived-mode golbarg-mode markdown-mode "Golbarg"
"Major mode for Golbarg blog posts."
(set (make-local-variable 'font-lock-fontify-region-function) 'golbarg-fontify-region)
(setq golbarg-header-overlay (make-overlay (point-min) (golbarg-header-end)))
(overlay-put golbarg-header-overlay 'face 'golbarg-header-face))
(defun golbarg-header-end ()
"Get the point of the end of a Golbarg post header."
(save-excursion
(goto-char (point-min))
(re-search-forward "^--+\n" nil t)))
(defun golbarg-fontify-region (beg end loudly)
"Fontify a region, using YAML font-lock parameters in the header."
(let ((hdr-end (golbarg-header-end)))
;; Update header overlay
(if (not (= hdr-end (overlay-end golbarg-header-overlay)))
(move-overlay golbarg-header-overlay (point-min) hdr-end))
;; Check how to fontify the region
(cond ((> beg hdr-end) ;; Region is after the header
(font-lock-default-fontify-region beg end loudly))
((>= hdr-end end) ;; Region is inside the header
(golbarg-fontify-region-as-yaml beg end loudly))
(t ;; Header end is inside the region...
(golbarg-fontify-region-as-yaml beg hdr-end loudly)
(font-lock-default-fontify-region (1+ hdr-end) end loudly)))))
(defun golbarg-fontify-region-as-yaml (beg end loudly)
(let ((font-lock-syntactic-keywords yaml-font-lock-syntactic-keywords)
(font-lock-keywords yaml-font-lock-keywords))
(font-lock-default-fontify-region beg end loudly)))
(defun golbarg-preview ()
"Run markdown on the current buffer and preview the output in a
browser, omitting the post header."
(interactive)
(let* ((my-next-win (next-window))
(my-next-buf (window-buffer my-next-win))
output-win)
(if (and (boundp 'transient-mark-mode) transient-mark-mode mark-active)
(markdown-preview)
(save-excursion
;; Select the content
(set-mark (golbarg-header-end))
(goto-char (point-max))
(markdown-preview)))
;; Don't show the markdown output buffer
(setq output-win (get-buffer-window "*markdown-output*" nil))
(if (eq my-next-win output-win)
;; The window already existed
(set-window-buffer my-next-win my-next-buf)
;; The window was created for the output buffer
(delete-window output-win))))
(provide 'golbarg)