Install Emacs29.4 on Debian12
Debian12 「bookworm」に Emacs29.4 をインストールした。
Emacs29.1からEmacs29.4へのupdateである。 今回は、–with-native-compilation=aot としてみた。若干起動が早くなった感じがするが定かではない。
Debian12 「bookworm」に Emacs29.4 をインストールした。
Emacs29.1からEmacs29.4へのupdateである。 今回は、–with-native-compilation=aot としてみた。若干起動が早くなった感じがするが定かではない。
Debian12 「bookworm」に Emacs29.1 をインストールした。
Debianのバージンが12.7になったのを機にEmacs28.2からEmacs29.1にupdateした。インストールは以下の通りで問題なく完了、念の為に Pacckage群も全て削除して再インストールした。
私の emacsは、設定ファイルを分割して init-loader
で読み込んでいます。
ところが Emacsの設定を use-package
から leaf
へ移行したら 各分割ファイルで flycheckが leaf: Unrecognized keyword :el-get (emacs-lisp)
というようなエラーを吐くようになった。leaf
で使える便利なキーワード(:hydra :chord :el-getなど)のいくつかがエラーに引っかかるみたい。
init.el
で (leaf-keywords-init)
が宣言されているので、 分割ファイルでも問題なく leaf
固有のキーワードを使うことができるのだが flycheck
は分割ファイルごとに compileチェックをするのでエラーになるというのが原因のようだ。
そこで、各分割ファイルの冒頭に (eval-when-compile (leaf-keywords-init))
というのを書いてみたら警告が消えた。
Debian Linux 上で GNU Emacs 27.2.50を使っています。 現状の emacs-init-time
は、0.5秒前後で何ら不満はないのですが、さらなる起動時間の短縮にこだわって日々試行錯誤している Emacs馬鹿です。
設定ファイルを leaf
に移行し、且つafter-init-hook
を多用することでかなり短縮できました。で、最後にたどり着いたのが設定ファイルの全てを自動バイトコンパイルさせるという課題です。
Emacs設定ファイルは、 Ladicle’ s Emacs Configuration ver.2022 を参考にしているのですが、最近モードラインが doom-modelineから nano-modelineに変更されていたので私も試してみることにしました。
Ladicle’ s さんの設定で使われているパッケージは、nano-modelineは、GNU Emacs / N Λ NO という GNU Emacs 用の設定ファイルのセットに含まれています。
Ladiclsさんの設定をコピペするだけで簡単に確認することができます。
情報量は減りますがじつにシンプルでなかなかおもしろいと感じました。ただ残念ながら Evil-modeには対応していないようです。
いろいろ探していると Evil対応のパッケージが見つかりました。doom-nano-themeとともに Doom-emacs用として公開されているものです。
残念ながら themeパッケージは反映できませんでしたが modelineの方は流用できました。スクショと設定ファイルとを公開しておきます。
デフォルトのままでも悪くはなかったのですが、とりあえず自分好みの色設定に変更しています。
私の場合、Veiw-mode 代わりに Evilを導入しており、 [insert-state = emacs-state] という使い方をしているので必要なものだけ変更しています。
(leaf doom-nano-modeline
:doc "Nice look modeline based on N Λ N O"
:url "https://github.com/ronisbr/doom-nano-modeline"
:el-get "ronisbr/doom-nano-modeline"
:hook (emacs-startup-hook . doom-nano-modeline-mode)
:custom-face
(region . '((t (:background "#6272a4" :extend t))))
(hl-line . '((t (:background "#3B4252" :extend t))))
(doom-nano-modeline-active-face . '((t (:foreground "#f8f8f2" :background "#44475a" :weight bold))))
(doom-nano-modeline-evil-emacs-state-face . '((t (:foreground "#f4a460" :background "#6272a4" :weight bold))))
(doom-nano-modeline-evil-normal-state-face . '((t (:foreground "#adff2f" :background "#3cb371" :weight bold))))
(doom-nano-modeline-evil-visual-state-face . '((t (:foreground "#e0ffff" :background "#4682b4" :weight bold))))
(doom-nano-modeline-cursor-position-face . '((t (:foreground "#b0b8d1" :background "#44475a"))))
(doom-nano-modeline-major-mode-face . '((t (:foreground "#b0b8d1" :background "#44475a"))))
(doom-nano-modeline-vc-branch-name-face . '((t (:foreground "#b0b8d1" :background "#44475a"))))
:preface
(leaf hide-mode-line
:doc "Hide modeline in current buffer"
:ensure t
:hook (after-init-hook . global-hide-mode-line-mode)))
neotreeや imenu-list などの場合は、何故か Emacsデフォルトのモードラインが表示されてしまうので、hide-mode-lineパッケージをインストールして強引に消しています。
EmacsでLispを閲覧しているときにうっかりミスでソースを書き換えてしまって動かなくなったりするので、Vimで修正したりということがよくある。 新しいパッケージや設定を試したりするときにも同様なことが起きるので、そんなときにもVimの出番となる。
そこで、Emacsを使いながらVimの操作を覚えるためにEvil導入は良策だと考えるに至った。Evil導入を試すにあたり、数少ないTipsを調べてみた。
Evilバイブルである @taraoさん のTipsからは多くのことを教えられた。けれど私が作りたいのは、「EmacsをVimのごとく使う」という環境ではない。
徹底してEmacsのVim化を図ることにそれほど価値があるとは思えないからで、究極を追求するくらいならあっさりVimを使えば事足りるからである。 私の場合は、あくまでEmacsがメインであって「Vimのいいとこどりができたらいいな」ということである。
この点をしっかり自覚してからEvil導入を進めないと迷路から出られなくなると思う。
(leaf evil
:ensure t
:hook ((after-init-hook . evil-mode)
(find-file-hook . my:evil-insert-state))
:bind (("<zenkaku-hankaku>" . toggle-evil-mode)
(:evil-normal-state-map
("?" . chromium-vim-chert)
("C-e" . seq-end)
("SPC" . evil-insert-state)
("M-." . nil) ;; Use with other settings
("<hiragana-katakana>" . my:evil-normal-state)
([home] . open-dashboard)))
:init
;; options for Evil, must be written before (require 'evil)
(setq evil-insert-state-cursor '(bar . 4))
(setq evil-want-C-u-scroll t) ;; Enable scrolling with C-u
(setq evil-cross-lines t)
(setq evil-ex-search-vim-style-regexp nil)
(setq evil-search-module 'evil-search)
(setq evil-undo-system 'undo-fu)
:config
;; Use emacs key bindings in insert state
(setcdr evil-insert-state-map nil)
;; Go back to normal state with ESC
(define-key evil-insert-state-map [escape] 'my:evil-normal-state)
;; Hydra-select in visual-state region
(define-key evil-visual-state-map (kbd ".") 'hydra-selected/body)
;; Use muhenkan key as ESC
(define-key key-translation-map [muhenkan] 'evil-escape-or-quit)
(define-key evil-operator-state-map [muhenkan] 'evil-escape-or-quit)
;; Set the initial state for major mode
(evil-set-initial-state 'lisp-interaction-mode 'insert)
(evil-set-initial-state 'fundamental-mode 'insert)
(evil-set-initial-state 'easy-hugo-mode 'insert)
(add-to-list 'evil-emacs-state-modes 'neotree-mode)
(add-to-list 'evil-emacs-state-modes 'dired-mode)
(add-to-list 'evil-emacs-state-modes 'dashboard-mode)
(add-to-list 'evil-emacs-state-modes 'org-mode)
;; Customized functions
(defun evil-swap-key (map key1 key2)
"Swap KEY1 and KEY2 in MAP."
(let ((def1 (lookup-key map key1))
(def2 (lookup-key map key2)))
(define-key map key1 def2)
(define-key map key2 def1)))
(evil-swap-key evil-motion-state-map "j" "gj")
(evil-swap-key evil-motion-state-map "k" "gk")
(defun toggle-evil-mode ()
"Toggle on and off evil mode."
(interactive)
(if evil-mode (evil-mode 0)
(evil-mode 1)))
(defun my:evil-normal-state ()
"Turn off input-method then return to normal-state."
(interactive)
(if current-input-method (deactivate-input-method))
(evil-normal-state))
(defun evil-escape-or-quit (&optional prompt)
"If in evil state to ESC, else muhenkan key."
(interactive)
(cond
((or (evil-normal-state-p) (evil-insert-state-p) (evil-visual-state-p)
(evil-replace-state-p) (evil-visual-state-p)) [escape])
(t [muhenkan])))
(defun my:evil-insert-state ()
"New files are opened with insert-state."
(interactive)
(unless (file-exists-p buffer-file-name)
(evil-insert-state)))
(defvar my:auto-insert-state-buffers '("COMMIT_EDITMSG"))
(defun ad:switch-to-buffer (&rest _arg)
"Set buffer for automatic inser-state"
(when (member (buffer-name) my:auto-insert-state-buffers))
(evil-insert-state))
(advice-add 'switch-to-buffer :after #'ad:switch-to-buffer))
(leaf evil-plugins
:doc "Plugin for Evil modeline"
:el-get tarao/evil-plugins
:after evil
:require evil-mode-line)
最初は、設定の簡単なevil-local-mode で試してみた。
ところが evil-modeline-color
が動作しなかったり、C-[
による [escape] 機能が動作しなかったりというバグがあって不満だったので 最終的に evil-mode
で設定を工夫することにした。
久しぶりにQiitaに投稿しようとしたら以前は出来たコピペができなくなっている。
Emacsのクリップボードの設定ミスを疑って調べたけれど問題ない。仕様が変更されたのかどうかはわからないが、ダイレクトで記事を書くなんてことは考えられない。みんなどうしてるんだろう?
はてさてと悩んで、前に使った atomic-chrome
を再導入してみた。結果はGood!
Chrome側の拡張機能は、atomic-chrome-extensions だったと記憶していたのだけれど見当たらず、
Gost Text に置き換わったみたい。このあたりは下記Tipsに詳しい。
取り急ぎ下記の設定で試したところ快適にコピペ出来た。
;; atomic-chrome
(leaf atomic-chrome
:ensure t
:hook (after-init-hook . atomic-chrome-start-server)
:custom (atomic-chrome-buffer-open-style . 'full))
結構起動時間を消費するので、after-init-hook
で遅延起動している。また、Splitバッファーで表示されるデフォルトのスタイルが気に入らなかったので full window
に変更している。
Emacsから翻訳するのにGoogle-translateを愛用していたが、Slackのemacs-jpでGoogleよりも高性能だと評判の DeePL を知ったので、早速導入してみた。
“EmacsからDeePLを使う” で調べると下記3種類のTipsが見つかった。いづれもリージョン選択範囲を翻訳させるものである。
翻訳結果はミニバッファーに表示され、同じ内容がクリップボードにコピーされる。
オリジナルのコード
(deepl.el )
は、load-file
して使う仕様になっていたので、el-get
でパッケージインストールできるようにアレンジしたものを自分のGitHubに置いている。DeePLにユーザー登録してAPIキーの取得が必要。
翻訳結果は、ウインドウ分割でOther-window-bufferに表示される。Google-translateとの同時使用が可能なので比較して選べる。
buffer表示のほかにposframeやpopup-windowなどカスタマイズできる。 Melpaからパッケージインストールできるが、こちらもDeePLユーザー登録してAPIキーの取得が必要。
brows-urlを使ってWEB版のDeePL翻訳を表示させるもの。リージョン選択範囲が自動で貼り付けられる。
パッケージツールではないので、設定コードをinit.el
に貼り付けるだけで良く、APIキーも不要。
EmacsからDeePLを使うためには、ユーザー登録をしてAPI認証キーを取得する必要がある。手順は下記の通り。 詳細は、こちら がわかりやすい。
とりあえず全部設定して使い分けてみることにした。
;; Deepl translation appears in minibuffer.
;; Also, the same content is copied to the clipboard
(leaf deepl-translate
:el-get minorugh/deepl-translate
:bind ("C-t" . deepl-translate)
:custom (deepl-auth-key . "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX:XX"))
;; Deepl translate with go-translate
(leaf go-translate
:ensure t
:bind ("C-c t" . gts-do-translate)
:config
(setq gts-translate-list '(("en" "ja") ("ja" "en")))
(setq gts-default-translator
(gts-translator
:picker (gts-noprompt-picker)
:engines (list
(gts-deepl-engine :auth-key "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX:XX" :pro nil)
(gts-google-engine))
:render (gts-buffer-render))))
;; Deepl translation on web page
(leaf my:deeple-traqslate
:bind ("C-c d" . my:deepl-translate)
:preface
(defun my:deepl-translate (&optional string)
(interactive)
(setq string
(cond ((stringp string) string)
((use-region-p)
(buffer-substring (region-beginning) (region-end)))
(t
(save-excursion
(let (s)
(forward-char 1)
(backward-sentence)
(setq s (point))
(forward-sentence)
(buffer-substring s (point)))))))
(run-at-time 0.1 nil 'deactivate-mark)
(browse-url
(concat
"https://www.deepl.com/translator#en/ja/"
(url-hexify-string string)
))))
のdeepl.el
は、設定ファイルなどに書く短いコメント類の翻訳に適している。結果が気に入ればそのまま即yankで貼り付けできるので便利だ。自分的には、一番利用機会が多い。
mozc辞書をDropboxに置いて、そのシンボリックをそれぞれの各端末に貼って辞書共有をしている人は多いと思います。
リアルタイムで同時使用はしない…という使い方であれば何も問題ないのですが、
自分の場合は、基本メイン機のEmacsは起動しっぱなし(蓋閉じでSleep)なので、その状態でサブ機のEmacsを立ち上げると、mozcのON/OFFとは関係なく~/Dropbox/mozc/.mozc/
に競合コピーが量産されます。
そこで、簡単な回避方法を考えてみました。大げさなタイトルですが、Tipsといえるほどのものではありません。
くどくど説明するより下図を見ていただければ、“な〜んだ” と理解いただけると思います。
メイン機の .mozc/
は、Dropboxに保存してシンボリックリンクで使い、サブ機で使うときはEmacsを起動するたびにDropboxにある最新の .mozc/
をコピーして使うという仕組みです。
※ maine-machine
~/.mozc <-- symbolic link -- ~/Dropbox/mozc/.mozc
| Copy latest every time
※ sub-mchine |
~/.mozc <-- symbolic link -- ~/Dropbox/backup/mozc/.mozc
emacsの設定ファイルはメイン機とサブ機で共有しているので、uname -n
を条件子としてメイン機(自分の場合はe590)でない場合(サブ機のとき)は、emacsを起動したときにmozc辞書をコピーしています。シンボリックリンクは、一度貼っておけばコピーのたびに貼り直さなくても大丈夫です。
;; Clone the mozc dictionary placed in Dropbox to Nextcloud.
(defun mozc-copy ()
"Copy mozc for submachine."
(interactive)
(unless (string-match "e590" (shell-command-to-string "uname -n"))
(compile "cp -rf ~/Dropbox/mozc/.mozc ~/Dropbox/backup/mozc")))
(add-hook 'emacs-startup-hook 'mozc-copy)
Dropboxに配置したmozc辞書は、メイン機での単語登録や入力履歴を記憶し常に最新の状態でバックアップされます。 サブマシーンの場合は、emacsを起動するたびに最新の辞書をコピーしてそれを使うという簡単な割り切りです。
サブマシーンで単語登録したら、元辞書へ書き戻すという仕組みも考えれますが、結局は、競合コピーをどう回避するかという課題になると思うので割り切ることにしました。良い方法があれば教えてください。
メイン機、サブ機の定義は特にありません。使用頻度の高い方をメイン機として構成すればいいかなと思います。
上記の Tipsを参考にして、markdown-modeに導入してみた。
日本語においては、いわゆる半角文字と全角文字の間にスペースを入れた方が見やすいと言われていて、pangu-spacing.el
はそれを自動で行ってくれるというものです。
ただ、「Google日本語入力」などと書くときに「Google 日本語入力」ではおかしくなるし、なんとなく間延びした感じになるのが好みではなかったので アルファベット文字列の右端だけにスペースが入るようにカスタマイズした。
pangu-spacing.el
のコードを見るとデフォルトでは、正規表現で [a-zA-Z0-9] なっているので半角数字の場合にも同様に処理されてしまう。
数字にも半角スペースが有効になると、[2021 年 11 月 16 日] という感じになるので、日付表示のケースでは面白くない。
そこで、正規表現の記述を [a-zA-Z] に変更して半角数字は対象外としアルファベットのみが pangu-spacingの対象となるようにしている。
(leaf pangu-spacing
:ensure t
:hook ((markdown-mode-hook text-mode-hook) . pangu-spacing-mode)
:config
(setq pangu-spacing-real-insert-separtor t)
(setq pangu-spacing-include-regexp
(rx (or (and (or (group-n 3 (any "。,!?;:「」()、"))
(group-n 1 (or (category japanese))))))
(group-n 2 (in "a-zA-Z")))))
上記の例では、markdown-mode と text-modeに導入している。