This repository is settings for my Emacs.
File | |
---|---|
./init.el | Remember, the Force will be with you, always. |
./themes/simple-darkness-theme.el | That leads to the dark side. |
./distributions/ | Put submodules of Emacs distributions. |
./spacemacs/ | Settings for spacemacs. |
(message "Loading ~/.emacs.d/README.org")
git clone git@github.com:TakesxiSximada/emacs.d.git ~/.emacs.d
pip3 install -U --user -r python-mode-requirements.txt
npm install -g prettier
(defun getenv+ (name)
"環境変数から値を取得し、さもなければシンボルから値を取得する"
(or (getenv name)
(symbol-value (intern-soft name))))
(unless (package-installed-p 'use-package)
(package-install 'use-package))
(require 'use-package)
(use-package quelpa :ensure t :defer t)
(use-package quelpa-use-package :ensure t :defer t)
(use-package el-get :ensure t :defer t
:init
(setq el-get-dir (expand-file-name "/opt/ng")))
package-selected-packagesで管理されているパッケージを全てインストールする。
(defun refresh-installed-all-packaes ()
(interactive)
(mapcar (lambda (pkg-symbol)
(if (not (package-installed-p pkg-symbol))
(progn
(message (format "Installing.... %s" pkg-symbol))
(package-install pkg-symbol))
(message (format "Already installed: %s" pkg-symbol))))
package-selected-packages))
(el-get-bundle eglot :type "git" :url "git@github.com:joaotavora/eglot.git")
(el-get-bundle change-case :url "git@github.com:TakesxiSximada/change-case.el.git" :type "git")
(el-get-bundle sudden-death :url "git@github.com:TakesxiSximada/sudden-death.el.git" :type "git")
(el-get-bundle swift-mode :type "git" :url "git@github.com:swift-emacs/swift-mode.git")
(use-package sgml-mode :ensure t :defer t
:config
(setq sgml-quick-keys 'close))
(use-package add-node-modules-path :ensure t :defer t)
(use-package ag :ensure t :defer t :no-require t)
(use-package avy-menu :ensure t :defer t)
(use-package csv-mode :ensure t :defer t)
(use-package db :ensure t :defer t)
(use-package dired-filter :ensure t :defer t)
(use-package fakir :ensure t :defer t)
(use-package flycheck :ensure t :defer t)
(use-package github-review :ensure t :defer t)
(use-package google-translate :ensure t :defer t)
(use-package mew :ensure t :defer t)
(use-package monky :ensure t :defer t)
(use-package nginx-mode :ensure t :defer t)
(use-package ob-async :ensure t)
(use-package ob-restclient :ensure t :defer t)
(use-package pcre2el :ensure t :defer t)
(use-package request :ensure t :defer t)
(use-package restclient :ensure t :defer t)
(use-package s :ensure t :defer t)
(use-package smex :ensure t :defer t)
(use-package terraform-mode :ensure t :defer t)
(use-package transient :ensure t)
;; (use-package unicode-escape :ensure t :defer t)
(use-package vagrant-tramp :ensure t :defer t)
(use-package web :ensure t :defer t)
(use-package wgrep :ensure t :defer t)
(use-package wgrep-ag :ensure t :defer t)
(ido-mode 1)
(ido-everywhere 1)
(setq ido-enable-flex-matching t)
(use-package ido-vertical-mode :ensure t :defer
:init
(ido-vertical-mode)
(add-hook 'ido-setup-hook #'ido-vertical-define-keys-custom)
:custom
(ido-default-file-method 'selected-window)
(ido-default-buffer-method 'selected-window))
(defun ido-vertical-define-keys-custom ()
(define-key ido-completion-map (kbd "M-n") 'ido-next-match)
(define-key ido-completion-map (kbd "M-p") 'ido-prev-match)
)
;; WHY DID I USE ido-completing-read+ PACKAGE?:
;; I changed value t to ido-everywhere, but ido-vertical-mode did
;; not work. Should be enabled ido-ubiquitous-mode to work it.
(use-package ido-completing-read+ :ensure t :defer t
:init
(ido-ubiquitous-mode 1))
(use-package org :ensure t :defer t
:config
(org-indent-mode)
(setq org-startup-indented t
org-archive-location (format-time-string "ARCHIVE_%Y.org::" (current-time))
))
(require 'org-clock)
:; automatic timeout timer
(setq org-clock-automatic-timeout (* 60 10))
(setq org-clock-automatic-timeout-timer
(run-with-idle-timer org-clock-automatic-timeout
t 'org-clock-out))
org-scheduleで挿入される曜日を英語表記にする。 参考 :: https://qiita.com/tnoda_/items/9fefa1575f3bd5273b64
(setq system-time-locale "C")
(use-package company :ensure t :pin melpa
:config
(global-company-mode)
(setq
company-idle-delay 0 ; default = 0.5
company-minimum-prefix-length 2 ; default = 4
company-selection-wrap-around t ; 候補の一番下でさらに下に行こうとすると一番上に戻る
company-tooltip-idle-delay nil)
)
(use-package eglot :defer t :ensure t
:init
(defun eglot-install-language-server-python ()
(interactive)
(make-process :name "*EGLOT INSTALL*"
:buffer (get-buffer-create "*EGLOT INSTALL*")
:command `("pip" "install" "python-language-server")))
:config
(add-to-list 'eglot-server-programs '(vue-mode . ("vls")))
(define-key eglot-mode-map (kbd "M-.") 'xref-find-definitions)
(define-key eglot-mode-map (kbd "M-,") 'pop-tag-mark)
;; :if (eq system-type 'darwin)
;; :ensure-system-package
;; ("vls" . "npm install -g vls")
)
(use-package edit-indirect :ensure t :defer t
:config
(setq edit-indirect-guess-mode-function #'edit-indirect-custom-apply-major-mode))
(defun edit-indirect-custom-guess-major-mode (_parent-buffer _beg _end)
"Guess major-mode to parent-buffer major-mode.
Returns symbol of major-mode.
"
(with-current-buffer _parent-buffer
(goto-char _beg)
(if (eq major-mode 'org-mode)
(if-let ((lang (nth 0 (org-babel-get-src-block-info))))
(intern (format "%s-mode" lang))
'org-mode)
major-mode)))
(defun edit-indirect-custom-apply-major-mode (_parent-buffer _beg _end)
"Apply major-mode to parent-buffer major-mode."
(funcall (edit-indirect-custom-guess-major-mode _parent-buffer _beg _end)))
(use-package typescript-mode :defer t :ensure t
:config
(setq typescript-indent-level 2))
(use-package js-mode :defer t
:config
(setq js-indent-level 2))
(use-package js2-mode :defer t :ensure t
:config
(setq js-indent-level 2))
(use-package vue-mode :ensure t :defer t
:requires (vue-mode
vue-html-mode
css-mode
js-mode
typescript-mode)
:config
(define-key css-mode-map (kbd "C-c i") #'vue-mode-edit-all-indirect)
(define-key css-mode-map (kbd "M-i") #'vue-mode-edit-indirect-at-point)
(define-key js-mode-map (kbd "C-c i") #'vue-mode-edit-all-indirect)
(define-key js-mode-map (kbd "M-i") #'vue-mode-edit-indirect-at-point)
(define-key typescript-mode-map (kbd "C-c i") #'vue-mode-edit-all-indirect)
(define-key typescript-mode-map (kbd "M-i") #'vue-mode-edit-indirect-at-point)
(define-key vue-html-mode-map (kbd "C-c i") #'vue-mode-edit-all-indirect)
(define-key vue-html-mode-map (kbd "M-i") #'vue-mode-edit-indirect-at-point)
(define-key vue-mode-map (kbd "C-c i") #'vue-mode-edit-all-indirect)
(define-key vue-mode-map (kbd "M-i") #'vue-mode-edit-indirect-at-point)
(defun vue-mode-edit-all-indirect (&optional keep-windows)
"Open all subsections with `edit-indirect-mode' in seperate windows.
If KEEP-WINDOWS is set, do not delete other windows and keep the root window
open."
(interactive "P")
(when (not keep-windows)
(delete-other-windows))
(save-selected-window
(split-window-horizontally)
(dolist (ol (mmm-overlays-contained-in (point-min) (point-max)))
(let* ((window (split-window-below))
(mode (or (plist-get vue-dedicated-modes (overlay-get ol 'mmm-mode))
(overlay-get ol 'mmm-mode)))
(buffer (edit-indirect-region (overlay-start ol) (overlay-end ol))))
(maximize-window)
(with-current-buffer buffer
(funcall mode))
(set-window-buffer window buffer)))
(balance-windows))
(when (not keep-windows)
(delete-window)
(balance-windows)))
)
isortはPythonのimport順序を整列する。 isortコマンドを外部から指定できるようにモンキーパッチを当てる。
(autoload 'py-isort-buffer "py-isort")
(autoload 'py-isort-region "py-isort")
(autoload 'py-isort-before-save "py-isort")
(with-eval-after-load 'py-isort
(defcustom py-isort-executable "isort"
"Name of the executable to run."
:type 'string)
(defun py-isort--call-executable (errbuf file)
(let ((default-directory (py-isort--find-settings-path)))
(zerop (apply 'call-process py-isort-executable nil errbuf nil
(append `(" " , file, " ",
(concat "--settings-path=" default-directory))
py-isort-options))))))
可視性の向上のためカーソル位置の行にアンダーラインを表示する。
(global-hl-line-mode t)
Emacsでは、通常のOSなどでウィンドウと呼ばれている領域はフレームと呼び、 ウィンドウはEmacsの画面(フレーム)内に表示されている領域のことを指す。 できる限り文字を多く表示するためにウィンドウの分割線の幅を小さくする。 モードラインを表示しない場合、上下のウィンドウの境界がわからなくなって しまうのでウィンドウ下部に分割線を表示する。
(setq window-divider-default-bottom-width 1)
(setq window-divider-default-places 'bottom-only)
設定を反映する。
(window-divider-mode)
同様の理由からフリンジも表示しない。
(fringe-mode 0)
モードラインは本当に必要だろうか。モードラインには文字コードや改行コード、バックグラウンドで実行しているジョブの状態など、さまざまな情報を表示できる。
それらは一見便利なようにも思えるが、何かを記述したり作業する時に本当に必要な集中力を阻害してしまう。どのような情報が必要かということについては、個人のもしくは作業のニーズによって異なる。そのためこの情報が常に表示されているべきということは言えない。
必ず必要な情報が何かが決められない以上、最初は全ての表示を無効にし、それぞれの必要性に応じて表示を追加していくことで、個人のニーズにあったモードラインとして成長していく。
(setq-default mode-line-format nil)
(bind-key* "s-<up>" (lambda () (interactive) (window-resize nil -1)))
(bind-key* "s-<down>" (lambda () (interactive) (window-resize nil 1)))
(bind-key* "s-<right>" (lambda () (interactive) (window-resize nil 1 t)))
(bind-key* "s-<left>" (lambda () (interactive) (window-resize nil -1 t)))
(bind-key* "C-M-i" #'company-complete)
;; (bind-key* "C-c C-c M-x" #'execute-extended-command)
(bind-key* "C-t C-c" #'vterm-command)
(bind-key* "C-t C-t" #'other-frame)
(bind-key* "C-x C-v" #'magit-status)
(bind-key* "M-X" #'smex-major-mode-commands)
(bind-key* "M-x" #'smex)
(bind-key* "s-t" #'make-frame)
(define-key override-global-map (kbd "C-t C-i") #'org-clock-goto)
Emacsには標準でいくつかのデバッガーが付属していますが、それぞれのツールの名前がそのまま付いています。 M-x debug-on-XXXX
で全てのデバッガーを起動できるようにエイリアスを設定しています。
(defalias 'debug-on-c 'gdb)
(defalias 'debug-on-java 'jdb)
(defalias 'debug-on-perl 'perldb)
(defalias 'debug-on-python 'pdb)
;; dbx
;; sdb
CSS編集のためのタブ幅などを設定します。
(require 'css-mode)
(setq css-indent-offset 2)
フロントエンドのコードフォーマッターとしてprettierを用いています。公式の拡張であるPrettier-js for Emacsもありますが、使用感が合わなかったので必要な機能だけを実装しました。
パッケージとして独立させるほどでもなかったため、このリポジトリの prettier
ディレクトリにファイルを配置しました。そのためload-pathを追加し、 prettier-buffer
をrequireします。
(add-to-list 'load-path (expand-file-name "~/.emacs.d/prettier"))
(require 'prettier-buffer)
実行は M-x prettier-buffer
で実行できます。
コードブロックのインデントや見栄えをカスタマイズします。
(setq org-src-fontify-natively t
org-src-window-setup 'current-window
org-src-strip-leading-and-trailing-blank-lines t
org-src-preserve-indentation t
org-src-tab-acts-natively nil)
タスクの管理に org-agenda
を使用しています。
agendaファイルを追加するには org-agenda-files
にファイルパスを追加します。
今すべきタスクに集中するため概要では今日のタスクのみを表示します。
(setq org-agenda-span 'day)
デフォルトのアジェンダビューはタスクの見積もり時間と所要時間が表示され ていないためタスクのボリュームを判断できません。そこで見積もり時間と所 要時間を集計する関数を追加しそれを用いてアジェンダビューに表示するよう に変更します。
(require 'org)
(require 'org-clock)
(defun org-clock-get-item-content ()
(save-excursion
(let ((start-point (progn (org-back-to-heading t)
(point)))
(end-point (progn (org-end-of-subtree t t)
(point))))
(buffer-substring-no-properties start-point end-point))))
(defun org-clock-sum-current-item-custom ()
(interactive)
(condition-case err-var
(let* ((content (org-clock-get-item-content))
(minute (with-temp-buffer (insert content)
(org-clock-sum-current-item))))
(if (> minute 0)
minute
""))
(error "-")))
アジェンダビューでタスクのタイトルだけではタスクの内容を推測しにくいた
め親のタスクのタイトルも表示します。 %-10.20b
などの表示を入れること
で親タスクも表示できます。
各TODOに担当者を設定できるようにする。担当者は org-property
を利用し ASSIGNEE
属性に担当者名を記述するようにする。
次の関数で現在位置のTODOの担当者を取得する。この関数はアジェンダビューで担当者を表示するために用いる。
タスクの管理手法は人によってかなり異なるが、チーム主体で考えると担当者が設定されていないTODOには担当者を割り振るほうがよく、個人主体で考えるのであれば担当者が設定されていないTODOは自分用のTODOという扱いにしたほうが、管理がしやすくなる。
ライブラリとして切り出すのであれば、このあたりを両方対応できるように、設計したほうがよい。
現状は特に何も考えず、担当者が設定されていないものはnullを返し、表示もnullとなる。
(setq org-assign-assignee-default-assignee nil)
(defun org-assign-assignee-value-custom ()
"現在位置の担当者を取得する"
(interactive)
(or
(cdr (assoc "ASSIGNEE" (org-entry-properties)))
org-assign-assignee-default-assignee))
;(setq org-agenda-prefix-format
; '((agenda . "%4(org-clock-sum-current-item-custom) %4e %6(org-assign-assignee-value-custom) %t %.4s %-6.6c %-25.50b ")
; (todo . " %i %-12:c %-6e")
; (tags . " %i %-12:c")
; (search . " %i %-12:c")))
(use-package org-agenda-property :ensure t :defer t)
参考: org-agendaのday viewでlocationの表示を行う
org-todoの論理構造を強制します。 依存しているタスクが存在する場合、それらを完了していないと次のタスクに進めません。
(setq org-enforce-todo-dependencies t)
ただしチェックボックスは現在進行中のタスクを阻害してしまうので無効にします。
有効にするには org-enforce-todo-checkbox-dependencies
を用います。
(setq org-enforce-todo-checkbox-dependencies nil)
org-todoの論理構造を視覚的に表示します。 まだ実行の条件を満たさないorg-todoはorg-agendaでグレーアウト表示になります。
(setq org-track-ordered-property-with-tag t)
org-modeのタスクの優先度を設定します。
優先度としてA=Zの文字を使います。
(setq org-priority-lowest ?Z)
org-mode及びorg-agenda-modeではそれぞれ M-n
M-p
を用いて優先度を変更します。
(with-eval-after-load 'org
(define-key org-mode-map (kbd "M-p") 'org-priority-up)
(define-key org-mode-map (kbd "M-n") 'org-todo)
(add-hook 'org-mode-hook #'visual-fill-column-mode)
(add-hook 'org-mode-hook #'toggle-truncate-lines)
)
(with-eval-after-load 'org-agenda
(define-key org-agenda-mode-map (kbd "M-p") #'org-agenda-priority-up)
(define-key org-agenda-mode-map (kbd "M-n") #'org-agenda-todo)
)
Org Babelはorg-modeのコードブロックを実行する。ドキュメント内のコードを実行し、その出力をドキュメントに反映することができる。いわゆる文芸的プログラミングのようなことができる。
(org-babel-do-load-languages
'org-babel-load-languages
'(
(ditaa . t)
(scheme . t)
(emacs-lisp . t)
(python . t)
(restclient . t)
(http . t)
(shell . t)
(sql . t)))
Org Babelのコア部分はob-core.elに実装されている。例えばOrg-modeファイルのコードブロック内で C-c C-c
を実行すると org-babel-execute-src-block
関数が呼び出される。この時に用いるOrg Babel用拡張がサードパーティによって実装された別のパッケージである場合、その拡張がまだ読み込まれていないことがある。その場合、Org Babelは処理の実行に失敗する。必要なパッケージをrequireで読み込み、再度 org-babel-execute-src-block
関数を実行すればよいのだが、その都度Lispを記述しevalするのは面倒だ。そこでorg-core.elが読み込まれたら、ここで使用可能な拡張もrequireすることにした。
(with-eval-after-load 'ob-core
(require 'ob-async)
(require 'ob-ditaa)
(require 'ob-emacs-lisp)
(require 'ob-http)
(require 'ob-python)
(require 'ob-restclient)
(require 'ob-restclient)
(require 'ob-scheme)
(require 'ob-shell)
(require 'ob-sql))
ここでは必要に応じて定義した様々な目的の関数を記述します。
カレントバッファのファイルパスをクリップボードのコピーするコマンドを追加しています。
(defun our-buffer-copy-current-file-path ()
"バッファのファイルパスをクリップボードにコピーする"
(interactive)
(let ((path (buffer-file-name)))
(if path
(progn
(kill-new path)
(message (format "Copied: %s" path)))
(message (format "Cannot copied")))))
現在のカーソル位置のface名を表示します。
(defun what-face (pos)
"Display current position face name."
(interactive "d")
(if-let ((face-name (get-text-property pos 'face)))
(message "Face: %s" face-name)))
AsciiDocはマークアップのため記法(Nortation)の1つです。 AsciiDocをEmacsで表示したり編集する場合様々な方法があります。
adoc-modeはEmacs上でAsciiDoc形式のファイルを扱うためのメジャーモードです。 しかしデフォルトの設定ではコメントやメタ情報の表示サイズがとても小さくなっています。 これでは編集時に読めないので、ちょうどよい値に設定し直します。
(use-package adoc-mode :ensure t :defer t
:config
(set-face-attribute markup-comment-face nil :width 'normal :height 1)
(set-face-attribute markup-meta-face nil :width 'normal :height 1 :foreground "red")
)
ewwを用いてAsciiDocを表示する。
フォントはSource Han Mono[fn:source-han-mono-repo]をインストールする。
フォントを調節して文字幅が合うようにする。
;; (progn
;; (set-face-attribute 'default nil :family "源ノ等幅" :height 120)
;; (set-fontset-font nil 'japanese-jisx0208 (font-spec :family "源ノ等幅" :size 16))
;; (set-fontset-font nil 'japanese-jisx0208-1978 (font-spec :family "源ノ等幅" :size 16))
;; (set-fontset-font nil 'japanese-jisx0212 (font-spec :family "源ノ等幅" :size 16))
;; (set-fontset-font nil 'japanese-jisx0213.2004-1 (font-spec :family "源ノ等幅" :size 16))
;; (set-fontset-font nil 'jisx0201 (font-spec :family "源ノ等幅" :size 12))
;; (set-fontset-font nil 'symbol (font-spec :family "Apple Color Emoji" :size 12))
;; (set-fontset-font nil '(?☺ . ?☺) (font-spec :family "Apple Color Emoji" :size 6))
;; (set-fontset-font nil '(?🀄 . ?🀈) (font-spec :family "Apple Color Emoji" :size 9))
;; (set-fontset-font nil '(?一 . ?一) (font-spec :family "源ノ等幅" :size 12))
;; )
類似文字 |
---|
l I 1 |
o O 0 |
q 9 |
s S 5 |
x X |
z Z 2 |
一 ― |
ずれ確認用 半角40字、全角20字 | |
---|---|
AIfUEaiueoAIUEOaiueoAIUEOaiueoAIUEOaiueo | ASCII英字 |
0123456789012345678901234567890123456789 | ASCII数字 |
アイウエオアイウエオアイウエオアイウエオアイウエオアイウエオアイウエオアイウエオ | JIS X 0201カナ |
あいうえおあいうえおあいうえおあいうえお | JIS X 0208ひらがな |
アイウエオアイウエオアイウエオアイウエオ | 同カタカナ |
ABCDEABCDEABCDEABCDE | 同英字 |
亜唖娃阿哀亜唖娃阿哀亜唖娃阿哀亜唖娃阿哀 | 同漢字 |
𠀋𡈽𡌛𡑮𡢽𠀋𡈽𡌛𡑮𡢽𠀋𡈽𡌛𡑮𡢽𠀋𡈽𡌛𡑮𡢽 | JIS X 0213漢字 |
😃😇😍😜😸🙈🐺🐰👽🐉💰🏡🎅🍪🍕🚀🚻💩📷📦 | 絵文字 |
☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺ | 絵文字 |
🀄🀅🀆🀇🀈🀄🀅🀆🀇🀈🀄🀅🀆🀇🀈🀄🀅🀆🀇🀈 | 絵文字 |
AIUEOaiueo | ASCII英字 |
1234567890 | ASCII英字 |
アイウエオアイウエオ | JIS X 0201カナ |
あいうえお | JIS X 0208ひらがな |
アイウエオ | 同カタカナ |
𠀋𡈽𡌛𡑮𡢽 | JIS X 0213漢字 |
😃😇😍😜😸 | 絵文字 |
🙈🐺🐰👽🐉 | |
💰🏡🎅🍪🍕 | |
🚀🚻💩📷📦 | |
☺☺☺☺☺ | 絵文字 |
🀄🀄🀄🀄🀄 | |
AAAAA | |
亜亜亜亜亜 | |
ABCDE | 同英字 |
亜唖娃阿哀 | 同漢字 |
🀅🀅🀅🀅🀅🀅 | |
🀅🀆🀇🀈🀅 |
(この文字列は https://qiita.com/query1000/items/4b0b8db872adc1a5e2e9V から抜粋)
バッファの一部の領域を別のバッファに移して編集する機能をedit-indirectを用いて実現している。edit-indirectでは C-c C-c
には edit-indirect-commit
が割り当てられている。しかしOrg-modeなど C-c C-c
を既に使っているメジャーモードの場合、その設定が邪魔になるので無効化する。またedit-indirectに入った時のメジャーモードの判定処理をカスタマイズする。
(with-eval-after-load 'edit-indirect
(define-key edit-indirect-mode-map (kbd "C-c C-c") nil)
(defun edit-indirect-custom-guess-major-mode (_parent-buffer _beg _end)
"Guess major-mode to parent-buffer major-mode.
Returns symbol of major-mode.
"
(with-current-buffer _parent-buffer
(goto-char _beg)
(if (eq major-mode 'org-mode)
(if-let ((lang (nth 0 (org-babel-get-src-block-info))))
(intern (format "%s-mode" lang))
'org-mode)
major-mode)))
(defun edit-indirect-custom-apply-major-mode (_parent-buffer _beg _end)
"Apply major-mode to parent-buffer major-mode."
(funcall (edit-indirect-custom-guess-major-mode _parent-buffer _beg _end)))
)
タスク実行時の集中力の阻害を最小限にするため、関連する情報以外を見えないようにするコマンドを定義する。開始時に task-join
、終了時に task-leave
を呼び出す。
(require 'edit-indirect)
(require 'org-clock)
(defun task-join ()
"Join the task."
(interactive)
(org-narrow-to-subtree)
(mark-whole-buffer)
(switch-to-buffer
(edit-indirect-region
(region-beginning)
(region-end)))
(org-clock-in)
)
(defun task-leave ()
"Leave the clock-in task."
(interactive)
(if-let ((clock-buf (org-clock-is-active)))
(with-current-buffer clock-buf
(org-clock-out)))
(edit-indirect-commit)
(widen))
Org-modeやMarkdownの編集時にはリアルタイムプレビューがあると非常に捗る。 Emacsではgrip-modeを使うことで実現できる。
(use-package grip-mode :ensure t :defer t)
grip-modeは内部でGripというツールを使用している。このGripがリアルタイ ムレンダリングの機能を提供している。GripはPythonで実装されているので、 pipを用いてインストールする。
pip install grip
参考 :: https://blog.symdon.info/posts/1638063555/
org-exportはorg-mdoeで記述されたファイルを別の形式に変換する。
上付き文字(^で挟む)と下付き文字の記法(_で挟む)は通常の記述で使用するた め、更に{}の指定が必要になるように設定する。
(setq org-export-with-sub-superscripts '{})
参考 :: https://blog.symdon.info/posts/1605311844/
LaTeXを使ってOrgファイルをPDFにエクスポートする。 org-latex-export-to-pdfが定義されているが、文字コード関連で動作しなかったためコマンドを直接起動する形で独自に実装した。
(defun org-pdf-export-to-pdf-via-latex ()
"Export PDF file from org file via latex"
(interactive)
(let* ((tex-file-name (org-latex-export-to-latex))
(base-file-name (file-name-base tex-file-name))
(dvi-file-name (format "%s.dvi" base-file-name))
(pdf-file-name (format "%s.pdf" base-file-name))
(vterm-shell (format "bash -c 'platex %s && dvipdfmx %s'"
tex-file-name
dvi-file-name))
(vterm-buffer-name (format "*Org PDF Exporting: %s" pdf-file-name))
(vterm-kill-buffer-on-exit nil))
(vterm)
pdf-file-name))
スペルチェッカー。
(setq-default ispell-program-name "aspell")
(with-eval-after-load "ispell"
(setq ispell-local-dictionary "en_US")
(add-to-list 'ispell-skip-region-alist '("[^\000-\377]+")))
aspell自体のインストールは Homebrewの場合 brew install aspell
を実行する。
IMEにはAquaSKKを使用している。aquaskk/keymap.conf を ~/Library/Application Support/AquaSKK/
配下にコピーする。
mmm-modeは1つのバッファ内で複数のメジャーモードを利用できるようにする。 ただしバージョン0.5.8にはvue-modeでファイルを開く時にエラーが発生する既知のバグ[fn:mmm-mode-issue-112]がある。 この問題を回避するにはいくつか方法が示されているが確認したところ以下の関数を評価することで回避できた[fn:mmm-mode-issue-112-wa]。
(require 'mmm-region)
(defun mmm-syntax-propertize-function (start stop)
"Composite function that applies `syntax-table' text properties.
It iterates over all submode regions between START and STOP and
calls each respective submode's `syntax-propertize-function'."
(let ((saved-mode mmm-current-submode)
(saved-ovl mmm-current-overlay))
(mmm-save-changed-local-variables
mmm-current-submode mmm-current-overlay)
(unwind-protect
(mapc (lambda (elt)
(let* ((mode (car elt))
(func (get mode 'mmm-syntax-propertize-function))
(beg (cadr elt)) (end (nth 2 elt))
(ovl (nth 3 elt))
;; FIXME: Messing with syntax-ppss-* vars should not
;; be needed any more in Emacs≥26.
syntax-ppss-cache
syntax-ppss-last)
(goto-char beg)
(mmm-set-current-pair mode ovl)
(mmm-set-local-variables mode mmm-current-overlay)
(save-restriction
(when mmm-current-overlay
(narrow-to-region (overlay-start mmm-current-overlay)
(overlay-end mmm-current-overlay))
(put-text-property
(point-min) (point-max)
'syntax-table (syntax-table)))
(cond
(func
(funcall func beg end))
(font-lock-syntactic-keywords
(let ((syntax-propertize-function nil))
(font-lock-fontify-syntactic-keywords-region beg end))))
(run-hook-with-args 'mmm-after-syntax-propertize-functions
mmm-current-overlay mode beg end))))
(mmm-regions-in start stop))
(mmm-set-current-pair saved-mode saved-ovl)
(mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl))))
replace-region-contents
をコマンドとして呼び出せるようにし、適応する文字列処理を任意に指定できるようにした。
(defun apply-and-replace-region-string (func beg end)
"Replace after appling function the region string"
(interactive "a\nr")
(replace-region-contents
beg end (lambda ()
(let ((txt (buffer-substring-no-properties beg end)))
(funcall func txt)))))
リージョンの浮動小数点形式のUNIXエポックタイムを時刻形式に変換する関数を実装した。
(defun float-time-to-datetime-string (float-style-string)
"Convert unix epoc time (floating point style) string to date time formated string."
(format-time-string
"%Y-%m-%dT%H:%M:%S.%6N"
(encode-time (decode-time
(string-to-number float-style-string)))))
EditorConfigはプロジェクト毎のエディタの設定を統一する。
(use-package editorconfig
:ensure t
:config
(editorconfig-mode 1))
(setq account-alist '((sym . "ffffff")))
(defun switch-to-color (label)
(interactive (list (completing-read "Label: "
(mapcar 'car account-alist))))
(if-let ((color-fg (cdr (assoc (intern label) account-alist))))
(set-foreground-color color-fg)))
(require 'url-util)
(defun our-url-encode ()
(interactive)
(kill-new
(url-hexify-string
(buffer-substring-no-properties
(region-beginning) (region-end)))))
(put 'narrow-to-region 'disabled nil)
(put 'dired-find-alternate-file 'disabled nil)
各環境毎に読み込みするかどうかを切り替えたい設定もある。 それらを切り替えるために追加で読み込むファイルを環境変数から取得する。
(save-window-excursion
(when (file-exists-p custom-env-file)
(with-current-buffer (find-file-read-only custom-env-file)
(dotenv-mode-apply-all))))
(mapc (lambda (path) (add-to-list 'custom-additional-load-file-list path))
(split-string (getenv "EMACS_ADDITINONAL_LOAD_FILE_PATH") ":"))
(mapc (lambda (path) (load-file path))
custom-additional-load-file-list)
(solarized-create-theme-file-with-palette 'dark 'simple-darkness '("#000000" ;; darkest-base "#ffffff" ;; brightest-base "#dbb32d" ;; yellow "#e67f43" ;; orange "#ed4a46" ;; red "#eb6eb7" ;; magenta "#a580e2" ;; violet "#368aeb" ;; blue "#3fc5b7" ;; cyan "#70b433" ;; green ))
S3へのアクセスにはs3edを使用する。
(use-package s3ed :ensure t)
基本的にローカルでのみダミーサーバーに対して使用する。 その為に使用するコマンドをawslコマンドとして定義しているが、 それを利用できるようにaws cliのコマンドを返す関数を上書きする。
(defun s3ed-aws-cli (cmd)
"Run the aws cli (s3) command with the configured arguments.
The given CMD string will be appended."
(let* ((profile-arg (if s3ed-profile-name (format " --profile %s" s3ed-profile-name) "")))
(format "awsl%s s3 %s" profile-arg cmd)))
MagitはEmacs用のGitユーティリティで、Gitコマンドのラッパーとして transientを用いて実装されている。仕様をカスタマイズするため、関数の上 書きをする。
magit-commit、magit-push、magit-rebaseの3つのEmacsのコマンドについて
--no-verify
オプションが用意されているが、オプション文字列が統一され
ていない。magit-commitのみ -n
で指定するようになっているため他の2つ
のコマンドにならい -h
で指定できるように修正する。
関数 | --no-verify のデフォルトの指定 | --no-verify の変更後の指定 |
---|---|---|
magit-commit | -n | -h |
magit-push | -h | -h |
magit-rebase | -h | -h |
(require 'magit)
(require 'transient)
(transient-define-prefix magit-commit ()
"Create a new commit or replace an existing commit."
:info-manual "(magit)Initiating a Commit"
:man-page "git-commit"
["Arguments"
("-a" "Stage all modified and deleted files" ("-a" "--all"))
("-e" "Allow empty commit" "--allow-empty")
("-v" "Show diff of changes to be committed" ("-v" "--verbose"))
("-h" "Disable hooks" ("-n" "--no-verify"))
("-R" "Claim authorship and reset author date" "--reset-author")
(magit:--author :description "Override the author")
(7 "-D" "Override the author date" "--date=" transient-read-date)
("-s" "Add Signed-off-by line" ("-s" "--signoff"))
(5 magit:--gpg-sign)
(magit-commit:--reuse-message)]
[["Create"
("c" "Commit" magit-commit-create)]
["Edit HEAD"
("e" "Extend" magit-commit-extend)
("w" "Reword" magit-commit-reword)
("a" "Amend" magit-commit-amend)
(6 "n" "Reshelve" magit-commit-reshelve)]
["Edit"
("f" "Fixup" magit-commit-fixup)
("s" "Squash" magit-commit-squash)
("A" "Augment" magit-commit-augment)
(6 "x" "Absorb changes" magit-commit-autofixup)
(6 "X" "Absorb modules" magit-commit-absorb-modules)]
[""
("F" "Instant fixup" magit-commit-instant-fixup)
("S" "Instant squash" magit-commit-instant-squash)]]
(interactive)
(if-let ((buffer (magit-commit-message-buffer)))
(switch-to-buffer buffer)
(transient-setup 'magit-commit)))
Gitフックなどでテストや整形すると、その結果を即座に確認したい。そのため、git push時にはMagitのプロセスバッファを表示する。
https://blog.symdon.info/posts/1654845224/
(add-hook 'magit-credential-hook #'magit-process-buffer)
https://blog.symdon.info/posts/1652142295
集中力を維持するため、frame-titleにorg-clock-inしたタスクの名称を表示する。
org-clock-in
及び org-clock-out
された時に実行されるフックとして、自作のフレームタイトルを変更する関数を設定した。org-clock-inしていない時はフレームタイトルにはバッファ名を表示するようにした。
(defun change-frame-title-to-org-clock-current-task-name ()
"Change frame title to org- clock current task name.
Display current buffer name if not clock in now."
(interactive)
(setq frame-title-format (or org-clock-current-task "%b")))
(add-hook 'org-clock-in-hook #'change-frame-title-to-org-clock-current-task-name)
(add-hook 'org-clock-out-hook #'change-frame-title-to-org-clock-current-task-name)
アイドル状態になったら作業中のタスク名をミニバッファに表示する。
(defun display-current-task-name-in-to-mini-buffer ()
"Display current task name in to mini buffer"
(interactive)
(when org-clock-current-task
(let ((minibuffer-message-timeout nil))
(minibuffer-message org-clock-current-task))))
(setq display-current-task-name-in-to-mini-buffer-timer
(run-with-idle-timer 3 t #'display-current-task-name-in-to-mini-buffer))
インプットメソッドにはDaredevil SKKを使用している。
https://github.com/skk-dev/ddskk
(global-set-key "\C-x\C-j" #'skk-mode)
(defun disable-mode-line ()
(setq-local mode-line-format nil))
(autoload 'skk-mode "skk")
(with-eval-after-load 'skk
;; SKKモードに切り替わってもモードラインを表示しない
(add-hook 'skk-mode-hook 'disable-mode-line)
(setq-default mode-line-format nil)
(setq-default skk-modeline-input-mode nil)
;; 絶対にモードラインを表示させたくないため
;; モードラインの設定関数を上書きする。
(defun skk-setup-modeline () nil)
;; SKKの候補の表示方法
(setq skk-show-tooltip nil)
(setq skk-show-inline 'vertical)
(setq skk-egg-like-newline nil)
(setq skk-dcomp-activate t)
(setq skk-dcomp-multiple-activate t)
(setq skk-henkan-strict-okuri-precedence t)
;; カーソルの色を変更する
(setq-default skk-cursor-latin-color "turquoise")
(setq-default skk-cursor-hiragana-color "orange")
(setq-default skk-cursor-katakana-color "systemGreenColor")
(setq skk-show-mode-show t)
(setq skk-show-mode-style "tooltip")
(defun skk-isearch-setup-maybe ()
(require 'skk-vars)
(when (or (eq skk-isearch-mode-enable 'always)
(and (boundp 'skk-mode)
skk-mode
skk-isearch-mode-enable))
(skk-isearch-mode-setup)))
(defun skk-isearch-cleanup-maybe ()
(require 'skk-vars)
(when (and (featurep 'skk-isearch)
skk-isearch-mode-enable)
(skk-isearch-mode-cleanup)))
(add-hook 'isearch-mode-hook #'skk-isearch-setup-maybe)
(add-hook 'isearch-mode-end-hook #'skk-isearch-cleanup-maybe)
)
;; 学習
(require 'skk-study)
safe-local-variable-valuesを保存してしまうと、custom-fileファイルをGitに登録できなくなってしまうため、safe-local-variable-valuesはcustom-fileに反映しないように設定する。
(setq-default enable-local-variables :all)
Org Modeは巨大なドキュメントシステムであり、プロジェクト管理や表計算など様々な機能を提供している。
org-clockはタスク(org-todo)の作業時間の計測を行う。作業時間の計測を簡 略化するためにキーバインドを変更する。
(with-eval-after-load 'org-clock
(define-key org-mode-map (kbd "M-i") #'org-clock-in)
(define-key org-mode-map (kbd "M-o") #'org-clock-out)
)
org-agendaはタスクの状況を一覧で表示する。org-agendaの一覧表示からでも 作業を開始できるようにキーバインドを変更する。
(with-eval-after-load 'org-agenda
(define-key org-agenda-mode-map (kbd "M-i") #'org-agenda-clock-in)
(define-key org-agenda-mode-map (kbd "M-o") #'org-agenda-clock-out)
)
org-agendaのレポート機能を強化したライブラリとして org-super-agenda
がある。org-super-agendaを使用しているがカテゴリ別に見積の値をラベルに
集計するようにカスタマイズする。
(with-eval-after-load 'org-super-agenda
(defun org-super-agenda-get-effort (item)
(if-let ((item-todo-state (get-text-property 0 'todo-state item)))
(get-text-property 0 'effort-minutes item-todo-state)))
(defun org-super-agenda-summary-effort (items)
(apply #'+
(seq-filter
(lambda (it) it)
(mapcar #'org-super-agenda-get-effort items))))
(defun org-super-agenda--make-agenda-header (name &optional items)
"Return agenda header named NAME.
If NAME is nil or `none', return empty string. Otherwise, return
string NAME prepended with `org-super-agenda-header-separator',
which see. NAME has the face `org-super-agenda-header' appended,
and the text properties `keymap' and `local-map' set to the value
of `org-super-agenda-header-map', which see."
(pcase name
((or `nil 'none) "")
(_ (let* ((properties (text-properties-at 0 name))
(header (concat org-super-agenda-header-prefix name))
(separator
(cl-etypecase org-super-agenda-header-separator
(character (concat (make-string (window-width) org-super-agenda-header-separator)
"\n"))
(string org-super-agenda-header-separator))))
(set-text-properties 0 (length header) properties header)
(add-face-text-property 0 (length header) 'org-super-agenda-header t header)
(org-add-props header org-super-agenda-header-properties
'keymap org-super-agenda-header-map
;; NOTE: According to the manual, only `keymap' should be necessary, but in my
;; testing, it only takes effect in Agenda buffers when `local-map' is set, so
;; we'll use both.
'local-map org-super-agenda-header-map)
;; Don't apply faces and properties to the separator part of the string.
(concat separator header
(format " (Effort => %d)"
(org-super-agenda-summary-effort items)))))))
(defun org-super-agenda--group-items (all-items)
"Divide ALL-ITEMS into groups based on `org-super-agenda-groups'."
(if (bound-and-true-p org-super-agenda-groups)
;; Transform groups
(let ((org-super-agenda-groups (org-super-agenda--transform-groups org-super-agenda-groups)))
;; Collect and insert groups
(cl-loop with section-name
for filter in org-super-agenda-groups
for custom-section-name = (plist-get filter :name)
for order = (or (plist-get filter :order) 0) ; Lowest number first, 0 by default
for (auto-section-name non-matching matching) = (org-super-agenda--group-dispatch all-items filter)
do (when org-super-agenda-keep-order
(setf matching (sort matching #'org-entries-lessp)))
;; Transformer
for transformer = (plist-get filter :transformer)
when transformer
do (setq matching (-map (pcase transformer
(`(function ,transformer) transformer)
((pred symbolp) transformer)
(_ `(lambda (it) ,transformer)))
matching))
;; Face
for face = (plist-get filter :face)
when face
do (let ((append (plist-get face :append)))
(when append (cl-remf face :append))
(--each matching
(add-face-text-property 0 (length it) face append it)))
;; Auto category/group
if (cl-member auto-section-name org-super-agenda-auto-selector-keywords)
do (setq section-name (or custom-section-name "Auto category/group"))
and append (cl-loop for group in matching
collect (list :name (plist-get group :name)
:items (plist-get group :items)
:order order))
into sections
and do (setq all-items non-matching)
;; Manual groups
else
do (setq section-name (or custom-section-name auto-section-name))
and collect (list :name section-name :items matching :order order) into sections
and do (setq all-items non-matching)
;; Sort sections by :order then :name
finally do (setq non-matching (list :name org-super-agenda-unmatched-name
:items non-matching
:order org-super-agenda-unmatched-order))
finally do (setq sections (--sort (let ((o-it (plist-get it :order))
(o-other (plist-get other :order)))
(cond ((and
;; FIXME: This is now quite ugly. I'm not sure that all of these tests
;; are necessary, but at the moment it works, so I'm leaving it alone.
(equal o-it o-other)
(not (equal o-it 0))
(stringp (plist-get it :name))
(stringp (plist-get other :name)))
;; Sort by string only for items with a set order
(string< (plist-get it :name)
(plist-get other :name)))
((and (numberp o-it)
(numberp o-other))
(< o-it o-other))
(t nil)))
(push non-matching sections)))
;; Insert sections
finally return (cl-loop for (_ name _ items) in sections
when items
collect (org-super-agenda--make-agenda-header name items)
and append items)))
;; No super-filters; return list unmodified
all-items))
)
https://github.com/zk-phi/indent-guide
インデントの崩れを確認しやすくする。ただし常に表示されて見た目を損ないたくないため、必要な時に有効にする。
Auto Fillingを長らく使用してきたが、テキストをブログ用にレンダラに渡すと改行が空白に変換され、読みにくくなる、改行のせいで検索が困難になる、差分を判断しにくいなどの不都合があった。しかしエディタで読む場合、適当な行で折り返されていないと、それはそれで読みにくい。toggle-truncate-linesを用いて折り返す方法もあるが、それはウィンドウサイズに従って折り返されてしまうため、ウィンドウサイズを気にしなければならないが、それはそれで面倒だ。そのため visual-fill-column
を用いて見た目上の折り返しを文字数で指定できるようにする。
https://codeberg.org/joostkremers/visual-fill-column
package-install RET visual-fill-column RET
(with-eval-after-load 'visual-fill-column
(add-hook 'visual-line-mode-hook #'visual-fill-column-mode)
(setq-default visual-fill-column-center-text nil))
[fn:source-han-mono-repo] https://github.com/adobe-fonts/source-han-mono [fn:mmm-mode-issue-112] dgutov/mmm-mode#112 [fn:mmm-mode-issue-112-wa] dgutov/mmm-mode#112 (comment)
(message "Loaded ~/.emacs.d/README.org")