2022年12月11日日曜日

Emacs org-mode の設定

エディタは、主に Emacs を使っていて、 メモ作業(TODO、予定を含む)は org-mode(now 9.6) に依存している。

年末なので、その使い方と設定を棚卸ししてみる。 使い始めた頃の設定も残っていたりする。環境は以下。

  • Debian GNU/Linux 11 (bullseye)
  • emacs 27.1
  • org 9.6

隠居老人なので、使い方はシンプルな方だと思う。 仕事がらみが無いし。

私のメモ作業は、基本的にひとつのファイル(memos.org)で行っている。

中身を、アウトラインでテーマ毎に分けてあって、 量が増えたり、完了した項目は、サブファイルを作成したり、 既ファイルのサブツリーへ移動させ、必要なら link を張る。 不要なものは、org-archive でアーカイブディレクトリへ移動。 更に、その後をどうするか、は未定。

TODO、予定を纏めた org-agenda は、 memos.org とサブファイル群を対象に作成させている。

ルールはこれだけ。

この時に重要なのがアイテムの移動手段で、 avy の avy-org-refile-as-child を使っている。

これを知るまでは、 org-refile を使っていて、 outline が整ってないと、気持ち悪い質なので、 refile 後の手間にイライラがあった。

当然だが、例外がある。

具体的な org-mode の設定は以下。
コピペ主体で作り込んできたものなので、 使ってない機能が含まれたりしするし、 動作を保証するものでもない。

(leaf org :ensure t :require t
  :bind (("C-c c" . org-capture)
         (org-mode-map
          ("C-c a" . org-agenda)
          ("C-c l" . org-store-link)
          ;; ("C-c c-l" . org-insert-link)
          ;; ("C-c C-z" . org-add-note)  ;; note は使ってない
          ("<tab>" . org-cycle)
          ;;
          ;; timestamp は頻繁に使う。heading しなくても日時が必要な場合がある
          ("C-c (" . my-insert-todays)  ;; 今日の日付挿入
          ("C-u C-c (" . my-timestamp)  ;; 現在の日時挿入
          ("C-c )" . org-time-stamp-inactive)  ;; カレンダーから日付挿入
          ("C-u C-c C-a" . my-org-toggle-time-stamp-activity)  ;; active inactive の toggle

          ;; リストの toggle が未完だけど、使わなくなってるので、止めてる。
          ("C-u C-c C-c" . my-org-toggle-list-checkbox) ;; リストに checkbox を付ける。
          ("C-u C-c C-t" . my-org-toggle-list-timestamp)
          ;;
          ("M-;" . org-comment-dwim-2)  ;; babel の中で使う
          ))
  :mode ("\\.org\\'" "\\.org$")
  ;; :init
  ;; (push '("\\.txt$" . org-mode)
  ;;      auto-mode-alist)  ;;  txt ファイルをorg-modeで開くようにする。
  :custom (
           (org-directory . "~/Documents/ownCloud")
           ;; このディレクトリは、Nextcloud のシンク対象にしてある。
           )
  :config
  (setq org-default-notes-file (concat org-directory "/captured.org")
        org-archive-dir (concat org-directory "/archive")
        org-archive-location (concat org-archive-dir "/archive-" (format-time-string "%Y%m" (current-time)) ".org_archive::")) ;;月単位でまとめる。

  (setq org-log-done 'time                  ;; DONEにした時、時刻追記
        org-startup-folded 'content         ;; defaultの折り畳み表示方法
        org-startup-truncated nil           ;; 右端で折り返すか
        org-hide-leading-stars t            ;; 見出しの余分な*を消すか nil t
        org-list-allow-alphabetical t       ;; listに a. を使う。exportに反映してない
        org-return-follows-link t           ;; return でリンクを追う
        org-startup-indented t              ;; 見出しをインデント original nil
        org-startup-with-inline-images nil  ;; inline imageの表示
        org-image-actual-width nil          ;; original t  width of inline image
        org-enforce-todo-dependencies t     ;; タスク依存関係で、子の全完済、要
        )

  (require 'org-protocol)

  (setq org-link-frame-setup '((gnus . org-gnus-other-frame)
                               (file . find-file-other-window)))

  ;; agenda

  ;; ディレクトリの全ファイルではなく、必要なものだけを対象にする
  (setq org-agenda-files `("~/Documents/ownCloud/memos.org"
                           "~/Documents/ownCloud/khal.org"  ;; ほぼ、read only.
                           "~/Documents/ownCloud/todo.org"
                           "~/Documents/ownCloud/bike_memo.org"
                           "~/Documents/ownCloud/pc_memo.org"
                           "~/Documents/ownCloud/emacs_memo.org"
                           "~/Documents/ownCloud/private.org"
                           ))
  ;;
  (setq org-agenda-dim-blocked-tasks 'invisible)
  (setq org-agenda-include-diary nil)  ;; 使ってない
  (setq org-agenda-current-time-string "← now")
  (setq org-agenda-time-grid '((daily today require-timed)
                               (500 900 1200 1500 1800 2100 2400)
                               "...." "--------"))
  (setq org-agenda-start-day "-1d")
  (setq org-agenda-start-on-weekday nil)
  (setq org-agenda-span 'fortnight)  ;; 2週間分を表示
  ;;don't show tasks as scheduled if they are already shown as a deadline
  (setq org-agenda-skip-scheduled-if-deadline-is-shown nil)
  ;;don't give awarning colour to tasks with impending deadlines
  ;;if they are scheduled to be done
  (setq org-agenda-skip-deadline-if-done nil)
  (setq org-agenda-skip-scheduled-if-done t)
  (setq org-agenda-include-inactive-timestamp nil)
  ;; (setq org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled)
  (setq org-agenda-skip-deadline-prewarning-if-scheduled t)
  ;; warn me of any deadlines in next 7 days    nil, t, pre-scheduled
  (setq org-deadline-warning-days 7)
  (setq org-agenda-todo-ignore-deadlines 'all)
  (setq org-agenda-todo-ignore-scheduled 'all)
  (setq org-agenda-window-setup 'reorganize-frame)

  ;; tag で agenda を絞り込むメニュを追加
  (setq org-agenda-custom-commands '(("h" "Home-related tasks"
                                      ((agenda)
                                       (tags-todo "pubs")
                                       (tags "pubs"
                                             ((org-agenda-sorting-strategy
                                               '(priority-up)))))
                                      ((org-agenda-sorting-strategy
                                        '(priority-down))))
                                     ("o" "work agenda"
                                      ((agenda)
                                       (tags-todo "work")
                                       (tags "work")))))

  ;; task(todo)

  ;; todo-keyword は、これでいいかんじ。
  (setq org-todo-keywords '((sequence "TODO(t)" "WAIT(w)" "INPROGRESS(p)" "IDLE(i)" "VERIFY(v)" "|" "DONE(d)" "SOMEDAY(s)" "CANCEL(c)")))

  ;; (setq org-enforce-todo-dependencies t)
  (setq org-todo-keyword-faces '(("TODO" :foreground "cyan2" :weight bold)
                                 ("INPROGRESS" :foreground "firebrick1" :weight bold)
                                 ("DONE" :foreground "dark olive green" :weight bold)
                                 ("WAIT" :foreground "orange" :weight bold)
                                 ("SOMEDAY" :foreground "indian red" :weight normal)
                                 ("CANCEL" :foreground "dark sea green" :weight bold)
                                 ("VERIFY" :foreground "OliveDrab1" :weight bold)
                                 ("IDLE" :foreground "burlywood" :weight bold)))

  ;; tags
  ;;   グループ化は便利だが、分類が細かすぎたと反省。もっとラフでいい
  (setq org-group-tags nil) ; enable group tags
  (setq org-tags-column -60) ; The default value is -77
  (setq org-tag-alist '((:startgroup)
                        ("@HOME" . 72) ("@WORK" . 87) ("@EDC" . 101) ("@Duty" . 68) ("@Pubs" . 80)
                        (:endgroup)
                        (:startgroup)
                        ("Get"   . 71) ("Talk"  . 84)  ("Listen" . 76) ("Read" . 82)
                        ("Serch" . 83) ("Exert" . 88)  ("Care"   . 99)
                        (:endgroup)
                        ("unix"   . 117) ("emacs"  .  65) ("lang" . 108)
                        ("pcpda"  .  99) ("python" . 112)
                        ("tour"   . 116) ("gpxs"   . 103) ("bikes" . 98)
                        ("others" . 111)))

  ;; org-refile
  ;;    avy の avy-org-refile-as-child を使うようになった。
  ;;    org-refile より楽だと思う。

  (setq org-refile-use-outline-path 'file)
  (setq org-refile-use-cache nil)
  (setq org-outline-path-complete-in-steps nil)
  (setq org-refile-targets '((nil :maxlevel . 3)
                             ("~/Documents/ownCloud/todo.org" :level . 1)
                             ("/home/QNAP/clouds/dropbox_ayageman/org/dropmemo.org" :level . 1)
                             ("~/Documents/ownCloud/bicycle_memo.org" :level . 1)
                             ("~/Documents/ownCloud/pc_memo.org" :level . 1)
                             ("~/Documents/ownCloud/python.org" :level . 1)
                             ("~/Documents/ownCloud/memos.org" :level . 1)
                             ("~/Documents/ownCloud/hugo/blogger_hugo.org" :level . 1)))
  (setq org-refile-allow-creating-parent-nodes 'confirm)
  ;; When the value of this variable is ‘confirm’, new node
  ;; creation must be confirmed by the user (recommended). When nil,
  ;; the completion must match an existing entry.

  ;; org-src

  (setq org-src-window-setup 'reorganize-frame)
  (setq org-src-tab-acts-natively nil)
  (setq org-src-fontify-natively t)
  (setq org-src-preserve-indentation nil)
  (setq org-edit-src-content-indentation 0)   ;; インデントを残す

  (setq electric-quote-mode nil)

  :defer-config

  ;; org-table

  (leaf org-table :ensure nil
    :config
    (setq org-table-formula-evaluate-inline nil)  ;; Default = t
    (leaf org-table-sticky-header :ensure nil :disabled t)
    )

  ;; org-ox

  (leaf ox :ensure nil
    :config
    (setq org-export-with-timestamps nil)  ;; heading timestamp
    (leaf ox-pandoc :ensure t :require t)
    ;; pandoc は優秀だと思う。重複するメニューを消したいが、わからないので放置。
    (leaf ox-md :ensure nil :require t)  ;; markdown
    (leaf ox-hugo :ensure t :require t
      :config
      (setq org-hugo-default-section-directory "posts")
      (setq org-hugo-export-with-section-numbers t)
      )
    (leaf ox-rst :ensure t :disabled t)
    )

  ;; file が大きくなると、すごく遅いので、使わなくなった。
  (leaf ox-publish :ensure nil :disabled t
    ;; 設定は削除
    )

  ;; org-babel

  (leaf ob-async :ensure t :require t
    :commands (ob-async-org-babel-execute-src-block)
    :config
    (setq ob-async-no-async-languages-alist '("ipython" "python"))
    )

  (leaf ob :ensure nil
    :defer-config
    (setq org-confirm-babel-evaluate t)  ;; 実行時に確認する。
    ;;
    ;; = blockdiag
    (leaf ob-blockdiag :ensure t
      :url "https://github.com/corpix/ob-blockdiag.el"
      )
    ;; = mermaid
    (leaf ob-mermaid :ensure t
      :url "https://github.com/arnm/ob-mermaid"
      :mode  ("\\.mmd\\'")
      :config
      (setq ob-mermaid-cli-path "/home/hoge/.yarn/bin/mmdc")
      ;;(setq ob-mermaid-cli-path "/home/hoge/.yarn/bin/mmdc -p ~/.config/puppeteer-config.json")
      ;; ob-mermaid.el で対応済み
      )
    ;; = ditta
    (setq org-ditaa-jar-path (expand-file-name "/usr/share/ditaa/ditaa.jar"))

    ;; = plantuml
    (leaf ob-plantuml :ensure nil
     :custom
         (org-plantuml-exec-mode . 'jar)
         (org-plantuml-jar-path . "/usr/share/plantuml/plantuml.jar")
    )

    ;; = gnuplot これが無いと動かない。 [2019-08-13]
    ;; (leaf gnuplot :ensure t)
    ;;
    ;;active Babel languages
    (org-babel-do-load-languages
     'org-babel-load-languages
     '((R . t)
       (emacs-lisp . t)  ;; elisp
       (lisp       . t)  ;; lisp
       (awk        . t)  ;; awk
       (shell      . t)  ;; shell
       (python     . t)  ;; python
       (perl       . t)  ;; perl
       (dot        . t)  ;; graphviz
       (gnuplot    . t)  ;; gnuplot
       (blockdiag  . t)  ;; blockdiag
       (css        . t)  ;; css
       (mermaid    . t)  ;; mermaid
       (plantuml   . t)  ;; plantuml
       (sqlite     . t)  ;; sqlite
       ))
    ;;
    (add-to-list 'org-src-lang-modes '("dot" . graphviz-dot))
    ;; (add-to-list 'org-src-lang-modes '("diag" . blockdiag))  ;; 対応してない?
    (add-to-list 'org-src-lang-modes '("mermaid" . mermaid))
    (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))
    (add-to-list 'org-src-lang-modes '("gnuplot" . gnuplot))
    )

  (leaf org-cliplink :ensure t :require t
    :doc "クリップボードがurlのみなら、アクセスして、org-linkにしてくれる。"
    :url "https://github.com/rexim/org-cliplink"
    :bind (org-mode-map ("C-c M-l" . org-cliplink)))

  ;; alart by org-mode (使ってない)

  (leaf org-wild-notifier :ensure t
    :doc "alart by org-mode"
    :url "https://github.com/akhramov/org-wild-notifier.el"
    :init (setf alert-default-style 'wild)
    :config
    (org-wild-notifier-mode))

  ;; id は使ってない
  (leaf org-id-cleanup :ensure t)

  ;; jorunal

  (leaf org-journal :ensure t
    ;; :commands org-journal-new-entry
    :bind (
           ("C-c j" . nil)
           ("C-c j" . org-journal-new-entry) ;; open today and start new entry
           (org-journal-mode-map (("C-c f" . org-journal-next-entry)
                                  ("C-c b" . org-journal-previous-entry)))
           )
    :hook (
           (org-journal-mode-hook . (lambda() (setq-local truncate-lines t)))
           )
    :custom (
             (org-journal-file-type . 'weekly)
             (org-journal-date-format . "%A, %d %B %Y")
             (org-journal-date-prefix . "* ")
             (org-journal-time-prefix . "** ")
             (org-journal-time-format . "%H:%M ")
             ;;(org-journal-enable-agenda-integration . t)
             ;; agenda には含めてない。
             )
    :config
    (customize-set-variable 'org-journal-dir (concat org-directory "/journal/"))
    )

  ;; org-bullet

  (leaf org-bullets :ensure t :disabled nil
    :url "https://github.com/emacsorphanage/org-bullets"
    :custom (org-bullets-bullet-list . '("➽" "◉" "" "" "" "" "" "" "" "" ""))
    :commands org-bullets-mode
    :init
    (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
    :require t
    )

  ;; org-capture

  (leaf org-capture :ensure nil
    :config

    (defun org-journal-find-location ()
      ;; Open today's journal, but specify a non-nil prefix argument in order to
      ;; inhibit inserting the heading; org-capture will insert the heading.
      (org-journal-new-entry t)
      ;; Position point on the journal's top-level heading so that org-capture
      ;; will add the new entry as a child entry.
      (goto-char (point-min)))

    (defun my/generate-md-memo-name ()
      (setq my-org-note--name (read-string "Name: "))
      (setq my-org-note--date (format-time-string "%Y-%m-%d"))
      (setq my-org-note--dtime (format-time-string "%Y-%m-%d %H:%M"))
      (expand-file-name (format "%s-%s.md" my-org-note--date my-org-note--name) "~/Documents/ownCloud/_posts"))

    (defun my/generate-post-name ()
      (setq my-org-note--name (read-string "Name: "))
      (setq my-org-note--dtime (format-time-string "%Y%m%d-%H%M"))
      (format "%s_%s.md" my-org-note--dtime my-org-note--name))

    (defun my/generate-blogger-name-m ()  ;; post markdown
      (setq my-blogger-post--name-m (read-string "Name: "))
      (setq my-blogger-post--time (format-time-string "%Y%m%d"))
      (expand-file-name (format "%s-%s.mkd" my-blogger-post--time my-blogger-post--name-m) "~/Documents/mup/blogg/content"))

    (defun my/generate-blogger-name-r ()  ;; post restructuredtext
      (setq my-blogger-post--name-r (read-string "Name: "))
      (setq my-blogger-post--time (format-time-string "%Y%m%d"))
      (expand-file-name (format "%s-%s.rst" my-blogger-post--time my-blogger-post--name-r) "~/Documents/mup/blogg/content"))

    (defun org-hugo-new-subtree-post-capture-template ()
      (let* ((title (read-from-minibuffer "Post Title: " )) ;; Prompt to enter the post title
             (hugo-post-time (format-time-string "%Y-%m-%d" ))
             (fname (org-hugo-slug title)))
        (mapconcat #'identity
                   `(
                     ,(concat "* TODO " title "  \t:@Cars:")
                     ":PROPERTIES:"
                     ,(concat ":EXPORT_FILE_NAME: " hugo-post-time "-" fname)
                     ":EXPORT_HUGO_CUSTOM_FRONT_MATTER: :description \"summary\""
                     ":EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :toc true"
                     ":END:"
                     "%?\n")          ;; Place the cursor here finally
                   "\n")
        )
      )

    ;; org capture templates

    (setq org-capture-templates  '(
                                   ("t" "TODO(sch/nosch)")
                                   ("tt"  "Todo(no)" entry
                                    (file+headline "~/Documents/ownCloud/memos.org" "Task")
                                    "* TODO %?\n %i\n %a\nEntered on %U\n")
                                   ("ts"  "Todo(sch)" entry
                                    (file+headline "~/Documents/ownCloud/memos.org" "Task(scheduled)")
                                    "* TODO %?\n %i\nSCHEDULED: <%<%Y-%m-%d %a %H:%M>>\nEntered on %U\n" :empty-lines 1)
                                   ("td"  "Todo(dropbox)" entry
                                    (file+headline "/home/QNAP/clouds/dropbox/org/dropmemo.org" "todo_dropbox")
                                    "* TODO %?\n %i\nSCHEDULED: <%<%Y-%m-%d %a %H:%M>>\nEntered on %U\n" :empty-lines 1)
                                   ("m"  "Memo" entry
                                    (file+headline "~/Documents/ownCloud/memos.org" "Memos")
                                    "* %?\n %U\n %i")
                                   ("n" "note(deft for vi)" plain
                                    (file my/generate-md-memo-name)
                                    "%(format \"---\ntitle: %s\ndate: %s\n---\n\n# \" my-org-note--name my-org-note--dtime)%?")
                                   ;;
                                   ("b" "Bike memos")  ;; 各自転車毎にエントリー
                                   ("bm" "Marine" entry
                                    (file+headline "~/Documents/ownCloud/bike_memo.org" "Marine")
                                    "* %?\n %U\n %i")
                                   ("bs" "Sutra" entry
                                    (file+headline "~/Documents/ownCloud/bike_memo.org" "Sutra")
                                    "* %?\n %U\n %i")
                                   ("br" "Rouvaix" entry
                                    (file+headline "~/Documents/ownCloud/bike_memo.org" "Rouvaix")
                                    "* %?\n %U\n %i")
                                   ("bo" "Others" entry
                                    (file+headline "~/Documents/ownCloud/bike_memo.org" "Others")
                                    "* %?\n %U\n %i")
                                   ;;
                                   ("p" "Post for Blogger")
                                   ("pp"  "blogger(pelican mkd)" plain  ;; pelican 用のキャプチャ。今は使ってない。
                                    (file my/generate-blogger-name-m)
                                    "Title: %?\nDate:  %<%Y-%m-%d %H:%M>\nTags:\nCategory:\nAuthors: AYAGE\nSummary: \nStatus: draft\n\n\n ")
                                   ("ps"  "blogger(pelican rst)" plain   ;; pelican 用のキャプチャ。今は使ってない。
                                    (file my/generate-blogger-name-r)
                                    "%?\n###################\n\n:date: %<%Y-%m-%d %H:%M>\n:tags:\n:category:\n:authors: AYAGE\n:summary: \n:status: draft\n\n\n ")
                                   ;;
                                   ("pa" "blogger(hugo) page" entry   ;; hugo 用のキャプチャ。page.
                                    (file+olp "hugo/blogger_hugo.org" "pages")
                                    "** TODO %? \t:@debian:\n:PROPERTIES:\n:EXPORT_FILE_NAME: %(my/generate-post-name)\n\
 :EXPORT_HUGO_FRONT_MATTER_FORMAT: toml\n\
 :EXPORT_HUGO_SECTION: pages\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :description false\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :archives %<%Y\/%m>\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :series [debian python emacs]\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :toc 2 :num t\n\
 :END:\n\n")
                                   ("ph" "blogger(hugo) post" entry    ;; hugo 用のキャプチャ。post.
                                    (file+olp "hugo/blogger_hugo.org" "posts")
                                    "** TODO %? \t:@debian:\n:PROPERTIES:\n:EXPORT_FILE_NAME: %(my/generate-post-name)\n\
 :EXPORT_HUGO_FRONT_MATTER_FORMAT: toml\n\
 :EXPORT_HUGO_SECTION: posts\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :description false\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :archives %<%Y\/%m>\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :series [debian python emacs]\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :toc 2 :num t\n\
 :END:\n\n\n")
                                   ;;
                                   ("j" "org-journal(Default)" entry (function org-journal-find-location)
                                    "** %(format-time-string org-journal-time-format)%^{Title}\n %i%?")
                                   ;; datetree のファイルに追記してゆく
                                   ("J" "journal.org(agenda)" entry (file+datetree "~/Documents/ownCloud/journal/journal.org")
                                    "* %?\nSCHEDULED:<%<%Y-%m-%d %a %H:%M>>\nEntered on %U\n\n%i\n")
                                   ;;
                                   ("h" "Hugo Yasa")  ;; 別のテーマの hugo. 今は使ってない
                                   ("hp" "Hugo Yasa post for Cars" entry
                                    (file+olp "hugo/hugo_post.org" "Blog Posts")
                                    "** TODO %? \t:@Cars:\n:PROPERTIES:\n:EXPORT_FILE_NAME: %<%Y-%m-%d>-post_name.md\n\
 :EXPORT_HUGO_FRONT_MATTER_FORMAT: yaml\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :comments false\n\
 :EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :image \"/ox-hugo/rimg.jpg\"\n\
 :END:\n\n")
                                   ("ht" "Hugo post page" entry
                                    (file "~/Documents/ownCloud/hugo/hugo_page.org")
                                    (function org-hugo-new-subtree-post-capture-template))
                                   ;;
                                   ))
    )

  (setq flycheck-mode nil)  ;; デフォでは動かさない。
  )

ゆるい縛りで、 使い散らかしているという思いはあるが、 まあ、なんとか使っている、というところか。仕事の縛りが無いので気楽だ。

暗号化したファイルでメモを管理したいけど、それは未挑戦。

やっぱ、在宅介護オンリーで、外出は病院と近所のコンビニだけ、 という生活では、もひとつ使い甲斐が無い。 まあ、org-journal は活躍しているから、よしとする。

麻のボディタオル

2018年の秋(まだ、自転車を封印してない)、 近江上布伝統産業会館 で、興味からボディタオルを購入した。 お、よかった。: 自然派パン工房 ふるさとの道 ほぼ毎日風呂で使ってきて、ついに寿命がきたようだ。 お店の方に、「糸が痩せて破れてくる」まで使える、と...