1 ;;; eh-org.el --- Tumashu's org-mode configuation -*- lexical-binding: t; -*-
4 ;; Copyright (c) 2012-2016, Feng Shu
6 ;; Author: Feng Shu <tumashu@gmail.com>
7 ;; URL: https://github.com/tumashu/emacs-helper
10 ;; This file is not part of GNU Emacs.
14 ;; This program is free software; you can redistribute it and/or
15 ;; modify it under the terms of the GNU General Public License
16 ;; as published by the Free Software Foundation; either version 3
17 ;; of the License, or (at your option) any later version.
19 ;; This program is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
32 ;; 这个文件是tumashu个人专用的emacs配置文件,emacs中文用户可以参考。
41 (require 'org-archive
)
43 (add-to-list 'auto-mode-alist
'("\\.org$" . org-mode
))
44 (add-to-list 'auto-mode-alist
'("\\.org_archive$" . org-mode
))
46 (defvar eh-org-directory
48 (or (cl-find-if #'file-exists-p
53 "~/storage/shared/org/"))
56 ;; 这个附件设置只适合我自己,千万别乱抄。
57 (setq org-attach-id-dir
58 (concat (file-name-as-directory
62 (dolist (f '(org-open-file))
63 (advice-add f
:around
'eh-find-file
))
65 (setq org-todo-keywords
66 '((type "TODO(t)" "|" "DONE(d!)" "CANCELED(c!)")))
68 (setq org-tags-exclude-from-inheritance
71 (setq org-tag-persistent-alist
76 (setq org-stuck-projects
77 '("+proj/-DONE-CANCELED"
81 (setq org-use-fast-tag-selection t
)
82 (setq org-complete-tags-always-offer-all-agenda-tags t
)
84 (defun eh-org-fast-tag-selection (current _inherited table
&optional _todo-table
)
85 (let* ((crm-separator "[ ]*[:,][ ]*")
86 (current-tags (cl-copy-list current
))
87 (buf (current-buffer))
88 (n (length current-tags
))
91 (format "Tag (%s%s): "
93 (cl-subseq current-tags
0 (min n max
))
106 (let ((item (car-safe x
)))
109 (org--tag-add-to-alist
110 (with-current-buffer buf
111 (org-get-buffer-tags))
114 (setq tags
(completing-read-multiple
117 (if (member (car x
) current-tags
)
118 (cons (propertize (car x
) 'face
'(:box t
)) (cdr x
))
122 (dolist (tg (delete-dups (remove "" tags
)))
123 (when (string-match "\\S-" tg
)
124 (if (member tg current-tags
)
125 (setq current-tags
(delete tg current-tags
))
126 (push tg current-tags
))))
127 (org-make-tag-string current-tags
)))
129 (advice-add 'org-fast-tag-selection
:override
#'eh-org-fast-tag-selection
)
131 (defun eh-org-end-of-id-line ()
132 (when (eq major-mode
'org-mode
)
133 (org-back-to-heading t
)
135 (search-forward ":ID:")
137 (org-fold-show-all '(drawers))))
139 (setq org-insert-heading-respect-content nil
)
140 (setq org-log-done t
)
141 (setq org-startup-indented nil
)
142 (setq org-adapt-indentation
'headline-data
)
143 (setq org-edit-src-content-indentation
0)
144 (setq org-id-link-to-org-use-id t
)
145 (setq org-log-into-drawer t
)
147 ;; org 文件显示内嵌图片的时候,首先缩放一下。
148 (setq org-image-actual-width t
)
150 ;; 插入日期戳的命令不弹出日历表,太占地方。
151 (setq org-read-date-popup-calendar nil
)
153 (defun eh-org-refile-agenda-files ()
154 (org-agenda-files t t
))
156 (setq org-refile-targets
157 '((nil .
(:maxlevel .
1))
158 (eh-org-refile-agenda-files .
(:maxlevel .
1))))
160 (setq org-outline-path-complete-in-steps nil
)
161 (setq org-refile-allow-creating-parent-nodes
'confirm
)
162 (setq org-refile-use-outline-path
'file
)
163 (setq org-refile-active-region-within-subtree t
)
165 (defun eh-org-fill-paragraph ()
168 (let ((fill-column 10000000))
169 (org-fill-paragraph)))
171 (defun eh-org-ctrl-c-ctrl-c (&optional arg
)
172 "根据光标处内容,智能折行,比如,在表格中禁止折行。"
174 (let* ((context (org-element-context))
175 (type (org-element-type context
)))
177 ((or `table
`table-cell
`table-row
`item
`plain-list
)
178 (toggle-truncate-lines 1))
179 (_ (toggle-truncate-lines -
1))))
180 (org-ctrl-c-ctrl-c arg
))
182 (defun eh-org-smart-truncate-lines (&optional _arg
)
184 (org-defkey org-mode-map
"\C-c\C-c" 'eh-org-ctrl-c-ctrl-c
))
186 (defun eh-org-visual-line-mode ()
188 (setq visual-line-fringe-indicators
'(nil nil
))
191 (setq word-wrap nil
)))
193 (add-hook 'org-mode-hook
'eh-org-visual-line-mode
)
194 (add-hook 'org-mode-hook
'eh-org-smart-truncate-lines
)
196 (require 'autorevert
)
197 (add-hook 'org-mode-hook
#'turn-on-auto-revert-mode
)
199 ;; (require 'org-protocol)
208 (setq org-export-default-language
"zh-CN")
210 ;; org默认使用"_下标"来定义一个下标,使用"^上标"定义一个上标,
211 ;; 但这种方式在中文环境中与下划线冲突。
212 ;; 这里强制使用"_{下标}"来定义一个下标。"^{上标}"来定义一个上标。
213 (setq org-export-with-sub-superscripts
'{})
214 (setq org-use-sub-superscripts
'{})
217 (setq org-html-coding-system
'utf-8
)
218 (setq org-html-head-include-default-style t
)
219 (setq org-html-head-include-scripts t
)
220 (setq org-html-validation-link nil
)
222 (defun eh-org-wash-text (text backend _info
)
223 "导出 org file 时,删除中文之间不必要的空格。"
224 (when (org-export-derived-backend-p backend
'html
)
225 (let ((regexp "[[:multibyte:]]")
227 ;; org-mode 默认将一个换行符转换为空格,但中文不需要这个空格,删除。
229 (replace-regexp-in-string
230 (format "\\(%s\\) *\n *\\(%s\\)" regexp regexp
)
233 (dolist (str '("</b>" "</code>" "</del>" "</i>"))
235 (replace-regexp-in-string
236 (format "\\(%s\\)\\(%s\\)[ ]+\\(%s\\)" regexp str regexp
)
237 "\\1\\2\\3" string
)))
239 (dolist (str '("<b>" "<code>" "<del>" "<i>" "<span class=\"underline\">"))
241 (replace-regexp-in-string
242 (format "\\(%s\\)[ ]+\\(%s\\)\\(%s\\)" regexp str regexp
)
243 "\\1\\2\\3" string
)))
246 (add-hook 'org-export-filter-headline-functions
#'eh-org-wash-text
)
247 (add-hook 'org-export-filter-paragraph-functions
#'eh-org-wash-text
)
250 (setq org-confirm-babel-evaluate nil
)
251 (setq org-src-fontify-natively t
)
253 (defun eh-org-show-babel-image ()
254 (when (not org-export-current-backend
)
255 (org-display-inline-images)))
257 (add-hook 'org-babel-after-execute-hook
#'eh-org-show-babel-image
)
259 ;; *** org babel other modules
261 (require 'ob-emacs-lisp
)
265 ;; 日常情况下,使用 ARCHIVE TAG 来隐藏已经完成的任务,安全又方便。
266 (setq org-archive-default-command
'org-archive-set-tag
)
269 (setq org-attach-store-link-p
'attached
)
270 (setq org-attach-sync-delete-empty-dir t
)
272 (defun eh-org-attach-sync-all ()
274 (org-map-entries #'org-attach-sync
)
275 (org-align-tags 'all
))
277 (defun eh-org-attach-reveal ()
280 (when (eq major-mode
'org-agenda-mode
)
281 (setq marker
(or (get-text-property (point) 'org-hd-marker
)
282 (get-text-property (point) 'org-marker
)))
284 (error "No task in current line")))
287 (set-buffer (marker-buffer marker
))
289 (org-back-to-heading t
)
290 (call-interactively 'org-attach-reveal
))))
292 (defun eh-org-attach-subtree ()
294 (when (yes-or-no-p "确定将 subtree 转移到 attach 目录中? ")
295 (org-back-to-heading t
)
296 (let* ((case-fold-search nil
)
297 (org-export-with-tags t
)
298 (filename (expand-file-name
300 (org-element-property
301 :title
(org-element-at-point))
303 (format-time-string "%Y%m%dT%H%M%S")
305 (org-attach-dir t
))))
306 (org-export-to-file 'org filename nil t
)
307 (org-end-of-meta-data)
308 (delete-region (point) (org-end-of-subtree t
)))))
311 (require 'org-capture
)
312 (global-set-key (kbd "C-c c") 'org-capture
)
314 (setq org-capture-templates
315 (let ((file (concat (file-name-as-directory eh-org-directory
) "projects.org")))
316 `(("n" "Note" entry
(file ,file
)
323 ("s" "Schedule" entry
(file+headline
,file
"待整理")
331 ("d" "Deadline" entry
(file+headline
,file
"待整理")
340 (defun eh-org-capture-note ()
342 (org-capture nil
"n"))
344 (defun eh-org-capture-schedule ()
346 (org-capture nil
"s"))
348 (defun eh-org-capture-refresh-agenda (&rest _
)
349 (when (eq major-mode
'org-agenda-mode
)
350 (eh-org-agenda-redo-all)))
352 (advice-add 'org-capture-finalize
:after
#'eh-org-capture-refresh-agenda
)
353 (advice-add 'org-capture-refile
:after
#'eh-org-capture-refresh-agenda
)
356 (require 'org-agenda
)
358 (global-set-key (kbd "C-c a") 'org-agenda
)
359 (define-key org-agenda-mode-map
(kbd "SPC") 'org-agenda-switch-to
)
360 (define-key org-agenda-mode-map
(kbd "i") 'org-agenda-switch-to
)
361 (define-key org-agenda-mode-map
(kbd "g") 'eh-org-agenda-redo-all
)
362 (define-key org-agenda-mode-map
(kbd "A") 'org-agenda-archive-default-with-confirmation
)
364 (defun eh-org-agenda-kill ()
366 (call-interactively #'org-agenda-kill
)
367 (eh-org-agenda-redo-all))
369 (define-key org-agenda-mode-map
(kbd "C-k") #'eh-org-agenda-kill
)
370 (define-key org-agenda-mode-map
(kbd "k") #'eh-org-agenda-kill
)
371 (define-key org-agenda-mode-map
(kbd "c") #'eh-org-capture-schedule
)
372 (define-key org-agenda-mode-map
(kbd "C") #'eh-org-capture-note
)
374 (define-key org-agenda-mode-map
(kbd "h") 'ignore
)
375 (define-key org-agenda-mode-map
(kbd "y") 'ignore
)
376 (define-key org-agenda-mode-map
(kbd "a") 'ignore
)
378 ;; 取消下面关于 archive 的快捷键,容易误操作
379 (org-defkey org-agenda-mode-map
"\C-c\C-x\C-a" 'ignore
)
380 (org-defkey org-agenda-mode-map
"\C-c\C-xa" 'ignore
)
381 (org-defkey org-agenda-mode-map
"\C-c\C-xA" 'ignore
)
382 (org-defkey org-agenda-mode-map
"\C-c\C-x\C-s" 'ignore
)
383 (org-defkey org-agenda-mode-map
"$" 'ignore
)
386 (setq org-agenda-dim-blocked-tasks t
)
387 (setq org-agenda-inhibit-startup t
)
389 ;; 我更习惯类似 google 的搜索方式。
390 (setq org-agenda-search-view-always-boolean t
)
391 (setq org-agenda-search-view-force-full-words nil
)
393 (add-to-list 'org-agenda-files eh-org-directory t
)
394 (add-to-list 'org-agenda-files
(concat (file-name-as-directory eh-org-directory
) "orgzly") t
)
396 (when (file-writable-p "~")
397 (make-directory (concat (file-name-as-directory eh-org-directory
) "orgzly") t
))
399 (defun eh-revert-org-buffers ()
400 "Refreshes all opened org buffers."
402 (dolist (buf (buffer-list))
403 (with-current-buffer buf
404 (when (and (buffer-file-name)
405 (string-match-p "org$" (buffer-file-name))
406 (file-exists-p (buffer-file-name))
407 (not (buffer-modified-p)))
408 (revert-buffer t t t
) )))
409 (message "Refreshed all opened org files."))
411 (defun eh-org-agenda-redo-all (&optional arg
)
413 (eh-revert-org-buffers)
414 (funcall-interactively #'org-agenda-redo-all arg
)
415 (message (substitute-command-keys
416 "刷新完成,记得按快捷键 '\\[org-save-all-org-buffers]' 来保存更改。")))
418 (setq org-agenda-span
'day
)
419 (setq org-agenda-window-setup
'current-window
)
420 (setq org-agenda-include-diary nil
)
422 (setq org-agenda-todo-ignore-scheduled t
)
423 (setq org-agenda-todo-ignore-deadlines t
)
425 (setq org-agenda-todo-list-sublevels t
)
426 (setq org-agenda-todo-ignore-scheduled t
)
428 (setq org-agenda-breadcrumbs-separator
" ~> ")
430 (setq org-agenda-prefix-format
431 '((agenda .
" %i %-14:c%?-12t% s")
432 (todo .
" %i %-14:c")
433 (tags .
" %i %-14:c")
434 (search .
" %i %-14:c")))
436 (setq org-agenda-format-date
'eh-org-agenda-format-date-aligned
)
438 (defun eh-org-agenda-format-date-aligned (date)
440 (let* ((dayname (calendar-day-name date
))
442 (day-of-week (calendar-day-of-week date
))
445 (iso-week (org-days-to-iso-week
446 (calendar-absolute-from-gregorian date
)))
447 (cn-date (calendar-chinese-from-absolute
448 (calendar-absolute-from-gregorian date
)))
449 (cn-month (cl-caddr cn-date
))
450 (cn-day (cl-cadddr cn-date
))
452 ["正月" "二月" "三月" "四月" "五月" "六月"
453 "七月" "八月" "九月" "十月" "冬月" "腊月"])
455 ["初一" "初二" "初三" "初四" "初五" "初六" "初七" "初八" "初九" "初十"
456 "十一" "十二" "十三" "十四" "十五" "十六" "十七" "十八" "十九" "二十"
457 "廿一" "廿二" "廿三" "廿四" "廿五" "廿六" "廿七" "廿八" "廿九" "三十"
458 "卅一" "卅二" "卅三" "卅四" "卅五" "卅六" "卅七" "卅八" "卅九" "卅十"])
459 (extra (format "(%s%s%s%s%s)"
460 (if (or (eq org-agenda-current-span
'day
)
463 (aref cn-month-name
(1- (floor cn-month
)))
465 (if (or (= day-of-week
1)
467 (if (integerp cn-month
) "" "[闰]")
469 (aref cn-day-name
(1- cn-day
))
470 (if (or (= day-of-week
1)
471 (eq org-agenda-current-span
'day
))
472 (let ((holiday (mapconcat #'identity
(calendar-check-holidays date
) ", ")))
473 (if (> (length holiday
) 0)
474 (concat ", " holiday
)
477 (if (or (= day-of-week
1)
478 (eq org-agenda-current-span
'day
))
479 (format ", 第%02d周" iso-week
)
481 (format "%04d-%02d-%02d %s %s"
482 year month day dayname extra
)))
484 (defun eh-org-agenda-jump-to-first-item ()
485 ;; 用 (goto-char (point-min)) 不管用,我估计是切换 tab 的缘故。
486 (let ((window (get-buffer-window org-agenda-buffer
)))
487 (when (windowp window
)
488 (set-window-point window
(point-min))
489 (org-agenda-next-item 1))))
491 (add-hook 'org-agenda-finalize-hook
#'eh-org-agenda-jump-to-first-item
100)
494 (require 'org-super-agenda
)
496 (org-super-agenda--def-auto-group eh-parent
"their parent heading"
497 :key-form
(org-super-agenda--when-with-marker-buffer (org-super-agenda--get-marker item
)
498 (when (org-up-heading-safe)
499 (concat (org-entry-get nil
"ITEM")
500 (if (string-suffix-p ".org_archive" (buffer-name))
504 (setq org-super-agenda-unmatched-name
"未分组")
505 (setq org-super-agenda-groups
506 '((:name
"Today" :time-grid t
)
507 (:name
"待整理" :tag
"待整理")
508 (;; :auto-parent 和 :auto-outline-path 无法很好的处理一级
509 ;; headline, 这里首先将一级 headline 归类。
512 (org-super-agenda--when-with-marker-buffer
513 (org-super-agenda--get-marker item
)
514 (equal (org-current-level) 1))))
515 (:auto-eh-parent t
)))
517 (org-super-agenda-mode 1)
520 '("a" "[org-super-agenda] Agenda for current week or day." agenda
""
521 ((org-agenda-remove-tags t
)
522 (org-super-agenda-header-separator "\n")
523 (org-super-agenda-final-group-separator "\n")))
524 org-agenda-custom-commands
)
530 (defun eh-org-update-all-headlines ()
532 (org-map-entries #'eh-org-update-headline
))
534 (defun eh-org-update-headline ()
536 (eh-org-update-gongwen-headline)
537 (eh-org-update-xieyi-headline))
539 (defun eh-org-update-gongwen-headline ()
541 (when (and (eq major-mode
'org-mode
)
542 (equal (org-entry-get (point) "CATEGORY")
544 (let* ((title (org-entry-get (point) "标题"))
545 (daizi (or (org-entry-get (point) "发文机关代字") ""))
546 (year (or (org-entry-get (point) "年份") ""))
547 (num (or (org-entry-get (point) "发文顺序号") ""))
548 (data (or (org-entry-get (point) "成文日期") ""))
549 (organization (org-entry-get (point) "发文机关标志"))
550 (organization (if (= (length organization
) 0)
553 (zihao1 (org-entry-get (point) "发文字号"))
554 (zihao (cond ((and (> (length daizi
) 0)
557 (format "%s〔%s〕%s号" daizi year num
))
558 ;; 以前记录的一些公文信息,只记录字号,没有记录代字,年份和
560 ((> (length zihao1
) 0)
561 (replace-regexp-in-string
562 (regexp-quote "]") "〕"
563 (replace-regexp-in-string
564 (regexp-quote "[") "〔"
566 ((and (= (length daizi
) 0)
568 (format "%s %s" organization data
))
571 (when (> (length title
) 0)
572 (when (and title
(string-match-p "《" title
))
574 (replace-regexp-in-string
576 (replace-regexp-in-string "》" "〉" title
))))
579 (format "%s《%s》(%s)" prefix title zihao
))
580 (when (string-match-p "〔" zihao
)
581 (org-set-property "发文字号" zihao
))))))
583 (defun eh-org-update-xieyi-headline ()
585 (when (and (eq major-mode
'org-mode
)
586 (equal (org-entry-get (point) "CATEGORY")
588 (let* ((project (org-entry-get (point) "项目或服务名称"))
589 (weituo (or (org-entry-get (point) "委托方") ""))
590 (chengjie (or (org-entry-get (point) "承接方") ""))
591 (jiakuan (or (org-entry-get (point) "价款(元)") ""))
592 (date (org-entry-get (point) "签署日期"))
594 (when (> (length project
) 0)
597 (format "%s《%s》(%s %s %s %s)" prefix project weituo chengjie jiakuan date
))))))
599 (add-hook 'write-file-functions
#'eh-org-update-headline
100)
600 (add-hook 'org-capture-prepare-finalize-hook
#'eh-org-update-headline
100)
606 ;; coding: utf-8-unix
609 ;;; eh-org.el ends here