emacs でお気に入りの設定 2025
目次
- 1. 環境
- 2. elpaca
- 3. ddskk
- 4. 標準機能のカスタマイズ
- 5. ediff
- 6. iserch でも C-h は DEL
- 7. whitespace の見え方
- 8. key-chord
- 9. shell-pop
- 10. 時を感じるで有名なやつ
- 11. smartrep をページャーとして
- 12. viewer-mode で色を変える
- 13. visual-replace
- 14. 昔の org-structure
- 15. org-agenda を q で閉じるだけ
- 16. ox-publish のオプション多すぎ
- 17. org-modern
- 18. mykie でクルクル移動
- 19. icons-in-terminal-dired で elc も emacs アイコンにする
- 20. ivy-with-migemo
- 21. 自作の小さな関数
1. 環境
- Ubuntu 24.04.1 LTS
- GNU Emacs 29.3 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.41, cairo version 1.18.0) of 2024-04-01, modified by Debian
2. elpaca
elpaca-manager を起動した時、省略せずに、一覧を一気に出したい
;; elpaca-manager で全てを一括で表示する (setq elpaca-ui-row-limit nil)
3. ddskk
3.1. ddskk の設定フォルダの変更
(setq skk-user-directory "~/.emacs.d/.ddskk")
3.2. azik の設定("~/.emacs.d/.ddskk/init")
超高速タイピング。
(setq skk-use-azik t)
3.3. stikey の設定("~/.emacs.d/.ddskk/init")
;; (setq skk-sticky-key [convert]) (setq skk-sticky-key [henkan])
3.4. 全角の入力
(setq skk-rom-kana-rule-list '(("z " nil " ")))
4. 標準機能のカスタマイズ
4.1. C-x C-c で容易にEmacsを終了させないように質問するようにする
(setq confirm-kill-emacs 'y-or-n-p)
4.2. ファイルパスからファイルを開く
(ffap-bindings)
4.3. なんか変なメーラ起動するのやめて
(global-set-key (kbd "C-c m") nil)
4.4. C-h はどこでも DEL
(define-key key-translation-map (kbd "C-h") (kbd "<DEL>"))
4.5. Scroll Lock は返してね
;; PC 切り換え機に割り当てるので (global-set-key (kbd "<Scroll_Lock>") 'ignore)
4.6. backup ファイルとかロックファイルとか、まとめてね
;; backup に 関する設定
;; http://yohshiy.blog.fc2.com/blog-entry-319.html
;; バックアップファイル (foo.txt~)
(setq backup-directory-alist
'((".*" . "~/.emacs.d/backup/emacs-backup-files")))
;; 番号付けによる複数保存
(setq version-control t) ;; 実行の有無
(setq kept-new-versions 10) ;; 最新の保持数
(setq kept-old-versions 10) ;; 最古の保持数
(setq delete-old-versions t) ;; 範囲外を削除
;; 自動保存ファイル (#foo.txt#)
(setq auto-save-file-name-transforms
'((".*" "~/.emacs.d/backup/auto-saved-files" t)))
;; 保存の間隔
(setq auto-save-timeout 10) ;; 秒 (デフォルト : 30)
(setq auto-save-interval 100) ;; 打鍵 (デフォルト : 300)
;; 自動保存リストファイル (~/.emacs.d/auto-save-list/.saves-xxxx)
(setq auto-save-list-file-prefix "~/tmp/.saves-")
;; ロックファイル (.#foo.txt)
;; 作成しない
(setq create-lockfiles nil)
5. ediff
(use-package ediff :ensure nil ;; Emacs標準のライブラリなので :ensure nil を指定 :init ;; ediff時に新しいフレームを作らない(シンプルになる) (setq ediff-window-setup-function 'ediff-setup-windows-plain) ;; diffのバッファを上下ではなく左右に並べる (setq ediff-split-window-function 'split-window-horizontally))
6. iserch でも C-h は DEL
(use-package isearch
:ensure nil
:bind (:map isearch-mode-map
("C-h" . isearch-del-char)))
7. whitespace の見え方
(use-package whitespace
:ensure nil ;; whitespace は組み込みなので ensure は nil
:commands (whitespace-mode) ;; コマンドをオートロードしたい場合に指定
:init
;; 基本的な変数設定などは :init で
(setq whitespace-style
'(face
trailing
tabs
spaces
lines
lines-tail
newline
indentation::tab
indentation::space
indentation
big-indent
space-after-tab::tab
space-after-tab::pace
space-after-tab
space-before-tab::tab
space-before-tab::space
space-before-tab
tab-mark
newline-mark))
;; 全角スペースを可視化
(setq whitespace-space-regexp "\\(\u3000+\\)")
:hook
;; 対象のモードで自動的に whitespace-mode を有効化
((lisp-mode
emacs-lisp-mode
lisp-interaction-mode
c-common-mode
perl-mode
python-mode
org-mode
markdown-mode) . whitespace-mode)
:custom-face
;; custom-set-faces の代わりに :custom-face でまとめることが可能
(whitespace-big-indent ((t (:background "alice blue" :foreground "black"))))
(whitespace-line ((t (:background "alice blue" :foreground "black"))))
:config
;; さらに必要な設定を :config にまとめる
(set-face-attribute 'whitespace-tab nil
:foreground "light grey"
:background 'unspecified
:underline nil)
(set-face-attribute 'whitespace-newline nil
:foreground "light grey")
(set-face-attribute 'whitespace-space nil
:background "pink"
:foreground 'unspecified
:underline nil
:weight 'bold))
8. key-chord
jkでview-modeに入る。もうちょっと活用できそうだけどなあ。
(use-package key-chord :ensure t :demand t :custom (key-chord-two-keys-delay 0.08) :init (key-chord-mode 1) :config (key-chord-define-global "jk" 'view-mode) ;; (key-chord-define-global "fn" 'open-junk-file) ;; (key-chord-define-global "fj" 'org-capture) )
9. shell-pop
f12がいい感じ
(use-package shell-pop
:ensure t
:bind
("<f12>" . shell-pop)
:custom
(shell-pop-shell-type '("eshell" "*eshell*" (lambda nil (eshell)))))
10. 時を感じるで有名なやつ
(use-package sky-color-clock :ensure (:host github :repo "tsuu32/sky-color-clock" :branch "master") :config (sky-color-clock-initialize 35) ; Tokyo, Japan (setq sky-color-clock-format "%Y-%m-%d (%a) %H:%M") (push '(:eval (sky-color-clock)) (default-value 'mode-line-format)) )
11. smartrep をページャーとして
(use-package smartrep
:ensure t
:init
;; C-l を一旦グローバルで未割り当てにする
(global-unset-key (kbd "C-l"))
:config
;; "C-l" に続くキー操作を smartrep で定義
(smartrep-define-key
global-map "C-l"
'(("h" . backward-char)
("l" . forward-char)
("j" . next-line)
("n" . next-line)
("k" . previous-line)
("p" . previous-line)
("b" . scroll-down)
("SPC" . scroll-up)
("f" . forward-word)
("e" . move-end-of-line)
("a" . move-beginning-of-line)
("J" . (lambda () (interactive) (scroll-up 1)))
("K" . (lambda () (interactive) (scroll-down 1)))
("g" . beginning-of-buffer)
("G" . end-of-buffer)
("r" . repeat)
("o" . open-line)
("C-l" . recenter-top-bottom))))
12. viewer-mode で色を変える
(use-package viewer
:ensure t
:config
(viewer-stay-in-setup)
(setq viewer-modeline-color-unwritable "tomato"
viewer-modeline-color-view "orange")
(viewer-change-modeline-color-setup)
(setq view-mode-default-regexp "\\.ml$"))
13. visual-replace
ずっとvisual-regexpを使ってたけど、今回乗り変えた。
(use-package visual-replace
:defer t
:hook
;; Visual Replaceのミニバッファが立ち上がったら、
;; 自動でクエリモードに切り替える
(visual-replace-minibuffer-mode . visual-replace-toggle-query)
:bind (("C-c r" . visual-replace)
:map isearch-mode-map
("C-c r" . visual-replace-from-isearch)))
14. 昔の org-structure
(use-package org-tempo
:ensure nil
:after org
:config
(add-to-list 'org-structure-template-alist '("el" . "src elisp"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("sh" . "src shell")))
15. org-agenda を q で閉じるだけ
(use-package org-agenda
:ensure nil
:after org
:bind (:map org-agenda-mode-map
("q" . quit-window))
)
16. ox-publish のオプション多すぎ
;; ----------------------------------------
;; 6. Org Export: ox-publish
;; ----------------------------------------
(use-package ox-publish
:after org
:ensure nil
:config
(setq org-publish-project-alist
'(("gitpages-org"
;; 1) 必須設定 -------------------------------------
:base-directory "~/clothoid.github.io/clothoid.github.io/org/" ;; ソース (Org) ファイルのあるディレクトリ
:base-extension "org" ;; 対象となるファイル拡張子
:publishing-directory "~/clothoid.github.io/clothoid.github.io/docs/" ;; 出力先ディレクトリ
:publishing-function org-html-publish-to-html ;; HTML に変換する関数
:recursive t ;; サブディレクトリを再帰的に処理するかどうか
;; 2) よく使う基本オプション -------------------------
:headline-levels 4 ;; 見出しを何階層まで出力するか
:auto-preamble t ;; テンプレート(プレアンブル)を自動挿入
;; :auto-postamble t ;; ポストアンブルを自動挿入 (デフォルト t)
;; :auto-index t ;; (古いオプション) インデックス生成を自動化 (Org 9.0以降は推奨されていない)
:auto-sitemap t ;; サイトマップ (目次) の自動生成
:sitemap-title "site map" ;; サイトマップのタイトル
:sitemap-style list ;; サイトマップの形式: `list` か `tree` か `random`
:sitemap-sort-files anti-chronologically ;; ファイルを新しい順にソート
;; :sitemap-sort-folders nil ;; サブディレクトリのソート (nil, first, last)
;; :sitemap-filename "sitemap.org" ;; サイトマップファイル名
;; :sitemap-file-entry-format "%t" ;; サイトマップでのエントリ表示形式 (%t=タイトル, %f=ファイル名, など)
;; :sitemap-date-format "%Y-%m-%d" ;; 日付の表示形式
;; :sitemap-ignore-case nil ;; 大文字小文字を無視してソートするかどうか
;; :sitemap-exclude "Private" ;; この正規表現にマッチするファイルをサイトマップに含めない
;; :sitemap-function nil ;; カスタムでサイトマップを生成したい場合の関数
;; :sitemap-format-entry nil ;; 各エントリのフォーマット関数
;; 3) HTML 出力オプション --------------------------
:html_link_up "index.html" ;; アップリンク用 (上位ページへのリンク)
:html_link_home "index.html" ;; ホームリンク用
;; :html_doctype "html5" ;; <!DOCTYPE html> の種類 (例: "html5")
;; :html_extension "html" ;; 出力ファイルの拡張子
;; :html_head "<link rel=\"stylesheet\" href=\"style.css\" />" ;; <head> に追加する要素
;; :html_head_include_default_style t ;; Org デフォルトの CSS を含めるかどうか
;; :html_head_include_scripts t ;; Org デフォルトのスクリプトを含めるかどうか
;; :html_preamble nil ;; HTML の <body> 内、本文開始前に挿入する内容
;; :html_postamble nil ;; HTML の <body> 内、本文終了後に挿入する内容
;; :htmlized_source t ;; ソースブロックを HTML のソース表示にするかどうか
;; :inline-css nil ;; HTML 内に CSS をインラインで埋め込むかどうか (古いオプション)
;; :style "<link rel=\"stylesheet\" type=\"text/css\" href=\"mystyle.css\"/>" ;; 古い形式でのスタイル指定 (Org 8 以前)
;; :style-include-default nil ;; 古い形式でのデフォルト CSS を含めるかどうか
;; :style-include-scripts nil ;; 古い形式でのデフォルトスクリプトを含めるかどうか
;; 4) Table of Contents, 見出し番号など ------------
;; :with-toc t ;; 目次を表示するかどうか
;; :section-numbers t ;; 見出し番号を付与するかどうか
;; :table-of-contents t ;; :with-toc の別名
;; :preserve-breaks nil ;; 改行をHTMLでも改行として扱うかどうか
;; :with-author t ;; 著者名の出力 ( #+AUTHOR: など )
;; :with-creator t ;; "Created by Org ..." のメタ情報を出力するか
;; :with-email t ;; メールアドレスの出力 ( #+EMAIL: など )
;; :with-footnotes t ;; 脚注を出力するか
;; :with-latex t ;; LaTeX 数式を変換 (デフォルト: t)
;; :with-sub-superscript t ;; ^ や _ 記号の上付き・下付き処理
;; 5) 細かい制御オプション --------------------------
;; :exclude "PrivateOrgFile.org" ;; 発行対象から除外するファイルを指定(正規表現)
;; :include ("some.org") ;; 発行対象に含めるファイルを明示的に指定
;; :makeindex t ;; 索引ファイルを作る (古い方式)
;; :index-style 'inline ;; 索引のスタイル (inline, fancy)
;; :timestamp nil ;; ファイルの先頭にタイムスタンプを付加するか
)
("gitpages-files"
:base-directory "~/clothoid.github.io/clothoid.github.io/org/"
:publishing-directory "~/clothoid.github.io/clothoid.github.io/docs/"
:base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
:recursive t
:publishing-function org-publish-attachment
;; :exclude "secret.png"
;; :include ("somefile.css")
)
("gitpages"
:components ("gitpages-org" "gitpages-files"))))
(message "ox-publish loaded."))
17. org-modern
おしゃれにしたいよ。
(use-package org-modern
:defer t
:after org
:hook (org-mode . org-modern-mode)
:config
;; org-modern をグローバルに有効化
(global-org-modern-mode)
;; https://misohena.jp/blog/2022-08-27-fix-org-table-lines-using-org-modern-and-org-indent.html
;; org-indentを使っていると表の水平線の高さが狭まらない問題を修正する。
;; インデントの空白文字列をdisplayプロパティで高さ1pxのspaceに置き換える。
(defun my-org-indent--compute-prefixes-after ()
(let ((prefixes org-indent--text-line-prefixes))
(dotimes (i (length prefixes))
(let* ((space-str (aref prefixes i))
(space-length (length space-str)))
(when (> space-length 0)
(aset prefixes i
(org-add-props
space-str
nil
'display (cons 'space
(list :width space-length
:height '(1))))))))))
(advice-add #'org-indent--compute-prefixes :after
#'my-org-indent--compute-prefixes-after)
;; org-modern--table を差し替え
(defun org-modern--table ()
"Prettify vertical table lines."
(save-excursion
(let* ((beg (match-beginning 0))
(end (match-end 0))
(tbeg (match-beginning 1))
(tend (match-end 1))
;; Unique objects
(sp1 (list 'space :width 1))
(sp2 (list 'space :width 1))
(color (face-attribute 'org-table :foreground nil t))
(inner (progn
(goto-char beg)
(forward-line)
(re-search-forward "^[ \t]*|" (line-end-position) t)))
(separator (progn
(goto-char beg)
(re-search-forward "^[ \t]*|-" end 'noerror))))
;; 横線を引く
(goto-char beg)
(when separator
;; overline を引いて高さを縮める
(when (numberp org-modern-table-horizontal)
(add-face-text-property tbeg tend `(:overline ,color) 'append)
(add-face-text-property beg (1+ end)
`(:height ,org-modern-table-horizontal)
'append))
(while (re-search-forward "[^|+]+" tend 'noerror)
(let ((a (match-beginning 0))
(b (match-end 0)))
(cl-loop for i from a below b do
(put-text-property i (1+ i) 'display
(if (= 0 (mod i 2)) sp1 sp2))))))
;; 縦線を引く
(goto-char beg)
(while (re-search-forward
"-+\\(?1:+\\)-\\|\\(?:^\\|[- ]\\)\\(?1:|\\)\\(?:$\\|[- ]\\)"
end 'noerror)
(let ((a (match-beginning 1))
(b (match-end 1)))
(cond
((and org-modern-table-vertical (or (not separator) inner))
(add-text-properties
a b
`(display " " face (:inherit org-table :inverse-video t)))
;; 高さを小さくする (ピクセル単位指定のため厳密な制御は困難)
(add-face-text-property a b `(:height 0.1) 'append))
((and org-modern-table-horizontal separator)
(put-text-property a b 'display " "))
(t (put-text-property a b 'face 'org-hide)))))))))
18. mykie でクルクル移動
死ぬほど使ってる。。。なんでだろ。
(use-package mykie
:ensure t
:config
;; :region&repeat を mykie:region-conditions に追加
(push '(:region&repeat . (mykie:repeat-p)) mykie:region-conditions)
;; seq-home/seq-end 相当の機能で使う変数
(defvar mykie-seq-point nil)
;; "C-a" に対する mykie の設定
(mykie:global-set-key "C-a"
:default (progn
(setq mykie-seq-point (point))
(beginning-of-line))
:repeat (cond
((bobp)
(goto-char mykie-seq-point))
((bolp)
(beginning-of-buffer))
(t
(beginning-of-line))))
;; "C-e" に対する mykie の設定
(mykie:global-set-key "C-e"
:default (progn
(setq mykie-seq-point (point))
(end-of-line))
:repeat (cond
((eobp)
(goto-char mykie-seq-point))
((eolp)
(end-of-buffer))
(t
(end-of-line))))
(mykie:global-set-key "C-t"
:default
(progn
(when (one-window-p)
(split-window-horizontally))
(other-window 1)))
)
19. icons-in-terminal-dired で elc も emacs アイコンにする
;; 1. icons-in-terminal-dired を使う場合の設定
(use-package icons-in-terminal-dired
:ensure (icons-in-terminal-dired
:repo "takaxp/icons-in-terminal-dired"
:host github)
:if (display-graphic-p) ;; GUI環境のみ使う場合
:hook (dired-mode . icons-in-terminal-dired-mode))
;; 2. icons-in-terminal のアイコンルールを上書きする例
(with-eval-after-load 'icons-in-terminal
;; まずは ".elc" 用の既存ルールを削除 (いったんアイコンを消す)
(setq icons-in-terminal-icon-alist
(cl-remove-if (lambda (it)
(string= (car it) "\\.elc"))
icons-in-terminal-icon-alist))
;; そして改めて ".elc" 用を好きなアイコンで再登録
(add-to-list 'icons-in-terminal-icon-alist
'("\\.elc"
icons-in-terminal-fileicon "elisp"
:height 1.0 :v-adjust -0.2 :face icons-in-terminal-purple))
0)
;; 注意
;; icons-in-terminal は icons-in-terminal-icon-alist のエントリを上から順に正規表現マッチして、
;; 一番最初にヒットしたものを使う仕組み。
;; デフォルト設定に
;; 「`_test.`(または `-test.`)が含まれるファイル名はテストファイル扱いにして `test-generic` のアイコンを表示する」
;; というルールが入っている
;; `999_test.el` が先にそのパターンにマッチしてしまい、「テストファイル用アイコン」になってしまう
20. ivy-with-migemo
ありがてえ、ありがてえ。。。
(use-package ivy-with-migemo
:ensure (:repo "https://gist.github.com/tam17aki/256094b57faad19d60eed7761c351d5b.git"
;; Gist の中で必要なファイルがこれだけなら指定
:files ("ivy-with-migemo.el"))
:init
;; パッケージ読み込み前に設定しておきたい変数は :init に書く
(setq ivy-with-migemo-enable-command
'(swiper
swiper-isearch
counsel-recentf
counsel-rg
ivy-switch-buffer
counsel-locate))
(setq migemo-options '("--quiet" "--nonewline" "--emacs"))
:config
;; パッケージ読み込み後に実行する設定
;; (require 'migemo) ;; migemo-kill, migemo-initを呼ぶために require しておく
(migemo-kill)
(migemo-init)
(global-ivy-with-migemo-mode 1)
(message "ivy-with-migemo.el loaded")
)
21. 自作の小さな関数
21.1. markdown から org へ変換
ChatGPTもFeloもmarkdownコピーなので。。。要pandoc
;;; markdown-to-org.el --- Convert Markdown to Org-mode format using pandoc
;; Copyright (C) 2023 Your Name
;; Author: Your Name <your.name@example.com>
;; URL: https://github.com/yourname/markdown-to-org
;; Version: 0.1.0
;; Keywords: markdown, org-mode, pandoc, convert
;; Package-Requires: ((emacs "24.4"))
;; License: MIT
;;; Commentary:
;;
;; This package provides functions to convert Markdown text into Emacs
;; org-mode text by using pandoc. You can use it in a buffer, region, or
;; an external file.
;;; Code:
(defgroup markdown-to-org nil
"Convert Markdown to Org-mode with pandoc."
:group 'tools
:prefix "markdown-to-org-")
(defcustom markdown-to-org-pandoc-path "pandoc"
"Path to the pandoc command."
:type 'string
:group 'markdown-to-org)
(defun markdown-to-org--run-pandoc (beg end)
"Run pandoc on the region between BEG and END to convert Markdown to Org."
(let ((pandoc-cmd (format "%s -f markdown -t org" markdown-to-org-pandoc-path)))
(shell-command-on-region
beg
end
pandoc-cmd
;; Insert results in current buffer, replacing the region
t
;; Output buffer
t)))
;;;###autoload
(defun markdown-to-org-convert-region (beg end)
"Convert the Markdown in region (BEG to END) to Org-mode in-place."
(interactive "r")
(markdown-to-org--run-pandoc beg end)
(message "Converted Markdown region to Org-mode!"))
;;;###autoload
(defun markdown-to-org-convert-buffer ()
"Convert the entire buffer from Markdown to Org-mode."
(interactive)
(markdown-to-org--run-pandoc (point-min) (point-max))
(message "Converted entire buffer from Markdown to Org-mode!"))
;;;###autoload
(defun markdown-to-org-convert-file (input-file output-file)
"Convert INPUT-FILE (Markdown) to OUTPUT-FILE (Org-mode) using pandoc."
(interactive "fMarkdown file to convert: \nFOutput Org file: ")
(let ((pandoc-cmd (format "%s -f markdown -t org %s -o %s"
markdown-to-org-pandoc-path
(shell-quote-argument (expand-file-name input-file))
(shell-quote-argument (expand-file-name output-file)))))
(shell-command pandoc-cmd)
(message "Converted %s to %s" input-file output-file)))
(provide 'markdown-to-org)
;;; markdown-to-org.el ends here
21.2. 時間と日付のコピー
;; -*- Mode: Emacs-Lisp ; Coding: utf-8 -*-
(require 'org)
;; 時間をコピーする
(defun copy-time ()
"現在時間をキルリングにセットする"
(interactive)
(kill-new (format-time-string "%Y-%m-%d-%H%M%S_")))
(defun get-date ()
(interactive)
(let ((org-time-stamp-formats org-time-stamp-custom-formats))
(org-insert-time-stamp (current-time) nil)))
(defun get-dtime ()
(interactive)
(let ((org-time-stamp-formats org-time-stamp-custom-formats))
(org-insert-time-stamp (current-time) t)))
(provide 'get-and-copy-time-and-date)
21.3. 透過の設定を interactive に変更
; -*- Mode: Emacs-Lisp ; Coding: utf-8 -*- ;;; フレームを半透明にする ;; (set-frame-parameter nil 'alpha 75) (defun frame-transparency (n) "alphaをnに変更する" (interactive "n value: ") (set-frame-parameter nil 'alpha n)) (provide 'frame-transparency)
21.4. 行コピー
標準でありそうだけど…
;; -*- Mode: Emacs-Lisp ; Coding: utf-8 -*-
;; 現在行をコピーして下の行に貼り付ける
(defun duplicate-this-line-forward (n)
"Duplicates the line point is on. The point is next line.
With prefix arg, duplicate current line this many times."
(interactive "p")
(when (eq (point-at-eol)(point-max))
(save-excursion (end-of-line) (insert "\n")))
(save-excursion
(beginning-of-line)
(dotimes (i n)
(insert-buffer-substring (current-buffer) (point-at-bol)(1+ (point-at-eol))))))
(provide 'duplicate-this-line-forward)
21.5. OS連携1
;;; my-dired-extensions.el --- 自作 Dired 拡張や OS 連携
;;; Code:
(require 'dired) ;; dired を拡張するので一応読み込む
(require 'cl-lib)
(require 'recentf)
;;----------------------------------------
;; OS 判定 & OS ごとにファイルを開くコマンドを決定するコード
;;----------------------------------------
(defun os-type ()
"現在の OS タイプを返す (cygwin, linux, darwin など)."
(let ((uname-str (shell-command-to-string "uname")))
(cond ((string-match "CYGWIN" uname-str)
'cygwin)
((string-match "Linux" uname-str)
'linux)
((string-match "Darwin" uname-str)
'darwin))))
(defun os-open-command-name (os-type)
"OS-TYPE に応じて実行できるファイルオープンコマンドのパスを探す."
(let ((command-name-list (cl-case os-type
('cygwin '("sglstart" "cygstart"))
('linux '("sglstart" "wslstart" "xdg-open" "gnome-open"))
('darwin '("open")))))
(catch 'loop
(dolist (command-name command-name-list)
(let* ((command1 (concat "which " command-name " 2> /dev/null"))
(command2 (if (file-remote-p default-directory)
;; リモートではログインシェルでコマンドを実行する
(format "$0 -l -c '%s' 2> /dev/null" command1)
command1))
(absolute-path-command-name
(replace-regexp-in-string
"\n" ""
(shell-command-to-string command2))))
(unless (string= absolute-path-command-name "")
(throw 'loop absolute-path-command-name)))))))
;; コマンド名をホストごとにキャッシュ
(defvar os-open-command-cache nil
"ホスト名をキーにして (OS-TYPE OS-OPEN-COMMAND-NAME) を保持するキャッシュ変数.")
(defun os-open-command-cache ()
"ホストごとのコマンドキャッシュを返す."
(let* ((hostname (if (file-remote-p default-directory)
(let* ((vec (tramp-dissect-file-name default-directory))
(host (tramp-file-name-host vec))
(user (tramp-file-name-user vec)))
(if user
(format "%s@%s" user host)
host))
"<localhost>")))
(cdr (or (assoc hostname os-open-command-cache)
(let* ((type (os-type))
(cmd (os-open-command-name type)))
(car (push (cons hostname (list type cmd))
os-open-command-cache)))))))
;;----------------------------------------
;; OS で直接ファイルを開く
;;----------------------------------------
(defun os-open-command (filename)
"FILENAME を OS のコマンドで開く."
(interactive "FOpen file: ")
(let* ((filename (expand-file-name filename))
(default-directory (file-name-directory filename)))
(let* ((cache (os-open-command-cache))
(type (nth 0 cache))
(cmd (nth 1 cache)))
(if cmd
(let ((localname (if (file-remote-p filename)
(tramp-file-name-localname
(tramp-dissect-file-name filename))
filename)))
(message "%s %s" (file-name-nondirectory cmd) localname)
(cond
((and (eq type 'linux)
(not (file-remote-p default-directory)))
;; Linux + ローカル環境
(let (process-connection-type)
(start-process "os-open-command" nil cmd localname)))
(t
;; リモートでも使えるように shell-command-to-string
(shell-command-to-string
(format "%s %s &" cmd (shell-quote-argument localname))))))
(message "利用できるコマンドがありません。")))))
(defun os-open-command-2 (filename)
"FILENAME を recentf に登録してから OS で開く."
(interactive "FOpen file with recentf: ")
(recentf-push filename)
(os-open-command filename))
;;----------------------------------------
;; Dired でキー操作・マウス操作をしたとき OS で開く
;;----------------------------------------
(define-key dired-mode-map (kbd "W")
(lambda ()
(interactive)
(os-open-command-2 (dired-get-file-for-visit))))
(define-key dired-mode-map [mouse-2]
(lambda (event)
(interactive "e")
(dired-mouse-find-file event 'os-open-command-2 'os-open-command-2)))
(define-key dired-mode-map (kbd "E")
(lambda ()
(interactive)
(os-open-command (dired-current-directory))))
(define-key dired-mode-map [mouse-3]
(lambda (event)
(interactive "e")
(mouse-select-window event)
(os-open-command (dired-current-directory))))
;;----------------------------------------
;; OS で開きたいファイルの拡張子リスト & find-file のアドバイス
;;----------------------------------------
(setq os-open-file-suffixes
'("doc" "docx"
"xls" "xlsx"
"ppt" "pptx"
"mdb" "mdbx"
"vsd" "vdx" "vsdx"
"mpp"
"pdf"
"bmp" "jpg"
"odt" "ott"
"odg" "otg"
"odp" "otp"
"ods" "ots"
"odf"))
(defun os-open-file-p (filename)
"FILENAME が os-open-file-suffixes の拡張子を持つ通常ファイルなら t."
(when (file-regular-p filename)
(let ((ext (file-name-extension filename)))
(when (and ext
(member (downcase ext) os-open-file-suffixes))
t))))
(advice-add 'find-file :around
(lambda (orig-fun &rest args)
(let* ((file-name (nth 0 args))
(target-name (or (file-symlink-p file-name)
file-name)))
(if (os-open-file-p target-name)
(os-open-command-2 target-name)
(apply orig-fun args)))))
;;----------------------------------------
;; dired-guess-shell の設定
;;----------------------------------------
(setq dired-guess-shell-alist-user
'(("\\.doc$" (nth 1 (os-open-command-cache)))
("\\.docx$" (nth 1 (os-open-command-cache)))
("\\.xls$" (nth 1 (os-open-command-cache)))
("\\.xlsx$" (nth 1 (os-open-command-cache)))
("\\.ppt$" (nth 1 (os-open-command-cache)))
("\\.pptx$" (nth 1 (os-open-command-cache)))
("\\.mdb$" (nth 1 (os-open-command-cache)))
("\\.mdbx$" (nth 1 (os-open-command-cache)))
("\\.vsd$" (nth 1 (os-open-command-cache)))
("\\.vdx$" (nth 1 (os-open-command-cache)))
("\\.vsdx$" (nth 1 (os-open-command-cache)))
("\\.mpp$" (nth 1 (os-open-command-cache)))
("\\.pdf$" (nth 1 (os-open-command-cache)))
("\\.bmp$" (nth 1 (os-open-command-cache)))
("\\.odt$" (nth 1 (os-open-command-cache)))
("\\.ott$" (nth 1 (os-open-command-cache)))
("\\.odg$" (nth 1 (os-open-command-cache)))
("\\.otg$" (nth 1 (os-open-command-cache)))
("\\.odp$" (nth 1 (os-open-command-cache)))
("\\.otp$" (nth 1 (os-open-command-cache)))
("\\.ods$" (nth 1 (os-open-command-cache)))
("\\.ots$" (nth 1 (os-open-command-cache)))
("\\.odf$" (nth 1 (os-open-command-cache)))))
;;----------------------------------------
;; Dired を 2つのウィンドウで開いているときに
;; other-window へ copy/move/symlink する
;;----------------------------------------
(defun dired-do-copy-dwim ()
(interactive)
(let ((dired-dwim-target t))
(dired-do-copy)))
(defun dired-do-rename-dwim ()
(interactive)
(let ((dired-dwim-target t))
(dired-do-rename)))
(defun dired-do-symlink-dwim ()
(interactive)
(let ((dired-dwim-target t))
(dired-do-symlink)))
(define-key dired-mode-map (kbd "c") 'dired-do-copy-dwim)
(define-key dired-mode-map (kbd "r") 'dired-do-rename-dwim)
(define-key dired-mode-map (kbd "s") 'dired-do-symlink-dwim)
(define-key dired-mode-map (kbd "e") 'wdired-change-to-wdired-mode)
;; dired-start-eshell を別の関数に remap
(define-key dired-mode-map [remap dired-do-shell-command] 'dired-start-eshell)
(provide 'dired-extensions)
;;; dired-extensions.el ends here
21.6. バッファ名をコピー
標準でありそうだけど、見つからず…
;; -*- Mode: Emacs-Lisp ; Coding: utf-8 -*-
;; バッファ名をコピーする
(defun copy-buffer-name ()
(interactive)
(kill-new (buffer-name)))
;; フルパスをコピーする
(defun copy-fullpath-buffer-file-name ()
"カレントバッファのファイル名 (フルパス) をコピー"
(interactive)
(if buffer-file-name
(progn
(kill-new buffer-file-name)
(message buffer-file-name))
(message "ファイルじゃありません")))
(provide 'copy-buffer-name)
21.7. 現在のバッファとファイル名を同時に変更
; -*- Mode: Emacs-Lisp ; Coding: utf-8 -*-
;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun rename-file-and-buffer (new-name)
"Renames both current buffer and file it's visiting to NEW-NAME."
(interactive "sNew name: ")
(let ((name (buffer-name))
(filename (buffer-file-name)))
(if (not filename)
(message "Buffer '%s' is not visiting a file!" name)
(if (get-buffer new-name)
(message "A buffer named '%s' already exists!" new-name)
(progn
(rename-file filename new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil))))))
(provide 'rename-file-and-buffer)
21.8. 自動確固挿入
smart paren がうまく動かなくなったので..
;; -*- Mode: Emacs-Lisp ; Coding: utf-8 -*-
(defvar wrap-pairs-alist '(( "(" . ")")
( "[" . "]")
( "{" . "}")
( "<" . ">")
( "\"" . "\"")
( "'" . "'")))
(defun get-right-wrap (left-wrap)
"左の囲み文字から右の囲み文字を取得する。"
(cdr (assoc left-wrap wrap-pairs-alist)))
(defun wrap-region-with-auto-right (start end left-wrap)
"リージョンを指定された囲み文字で囲む。右の囲み文字は左の囲み文字から自動で類推される。"
(let* ((right-wrap (get-right-wrap left-wrap))
(end-marker (set-marker (make-marker) end)))
(save-excursion
(goto-char start)
(insert left-wrap)
(goto-char (marker-position end-marker))
(insert (or right-wrap "")))
(set-marker end-marker nil))) ; マーカーをクリーンアップ
(defun wrap-region-or-insert (left-wrap)
"リージョンが選択されていればリージョンを指定された囲み文字で囲む。
リージョンが選択されていなければ囲み文字を挿入し、カーソルを囲み文字の間に移動する。"
(interactive)
(if (use-region-p)
(wrap-region-with-auto-right (region-beginning) (region-end) left-wrap)
(let ((right-wrap (get-right-wrap left-wrap)))
(insert left-wrap (or right-wrap ""))
(backward-char (length (or right-wrap "")))))
(deactivate-mark)) ; リージョンの選択を解除
(provide 'wrap-region-or-insert)
21.9. os のバージョン
(defun get-os-version ()
"Return a string describing the OS version."
(cond
;; macOS
((eq system-type 'darwin)
(string-trim (shell-command-to-string "sw_vers -productVersion")))
;; Linux
((eq system-type 'gnu/linux)
(or
;; まずは lsb_release があればそれを使う
(let ((lsb (executable-find "lsb_release")))
(when lsb
(string-trim
(shell-command-to-string (concat lsb " -d | cut -f2-")))))
;; なければ /etc/os-release を試す
(when (file-readable-p "/etc/os-release")
(with-temp-buffer
(insert-file-contents "/etc/os-release")
(goto-char (point-min))
(if (re-search-forward "^PRETTY_NAME=\"\\(.*?\\)\"" nil t)
(match-string 1)
"Unknown Linux distribution")))
;; 最後の手段: uname -r などで kernel version を返す
(string-trim (shell-command-to-string "uname -r"))))
;; Windows
((eq system-type 'windows-nt)
(string-trim (shell-command-to-string "ver")))
;; 上記以外
(t "Unknown OS")))
(defun os-version ()
"Display the OS version in *Messages*."
(interactive)
(message "Your OS version: %s" (get-os-version)))
21.10. その他
雑誌やメルマガに掲載されていたものは、そのまま書けないな。。。
- view-mode-pager.el
- view-mode では、vi ライクな閲覧モード
- yes-or-no-p.el
- yes/no を y/n で
脚注:
1
Windows ネイティブ版があったはずだけど、wsl2 に移行してから、どっかいってしまった。探してみよう。。。