目次

Emacs

まくら 

Emacsはとても古いEditor実装である。自分がEmacsを利用し始めたのは、高校生の時代にX68000を使っていた頃のはず。PC8801-mk2SRの次に入手したのがX68000だったとおもう。

それまでもPCは使っていた。88の頃は主にゲームばかり。X68000を手に入れてパソコン通信のChatにはまり、PC9801LVを入手してBBSサーバーにしたりはしていたが、普段使いのComputerはX68000だったと思う。

プログラムを書くようになって最初に手に馴染んだEditorはμEmacsだった。X68000でmicro Emacsを使い始めたのが最初だったと思う。そこからNEmacsに移り、Muleに移り、icam版GNU Emacsに移っていった。当時、TeXにがっつりハマり、pTeX(pLaTeXではない)で縦書き3段組の同人誌を作ったりもしていた。EmacsでTeX modeが非常に便利だったことを覚えている。

それ以来EditorといえばEmacs系のものを利用している。浪人時代に、中古で買ったSony NEWS(NEWS 1250, NEWS830, NEWS 3860)でThin EthernetでNetworkを組み、X68000をSerial Terminal にしてみたり、大学でSun MicrosystemsのSPARCstation 5, 10, IPC, IPX あたりを利用していたが、その時もEditorは常にEmacsだった。

大学時代から、Unix System管理者としては、当然にed, ex, viを「最小限」使っていた。「viはEmacsをCompileするためのpatch適用のためのEditorでしょ」なんてイキがっていたこともあった。要するに、EmacsのKey Bindingsに体が馴染んでおり、他のEditorに引っ越すことができなかっただけだろう。当然、秀丸、Vzなど様々なEditorを触ってきたし、なんとなれば EcripsやVisualStudioなどのIDEも利用したことはあるが、やはりEmacsに戻ってきてしまった。

社会人になっても、Reportや提出書類の大半はTeXを利用していた(WYSIWYGなんて面倒で不便と思っていた。今でもそう思うことは多い)ので、2000年代前半まではEmacs/TeXでほとんどの文書を処理していたし、WordやExcelを使わざるを得ない場合は、同僚のPCで処理させてもらうという悪逆非道なことをしていた。しかし、仕事の関係でどうしてもExcelやPowerPoint/KeyNoteを利用することがメインになったため、しばらく(15年くらい)ほとんどEmacsを利用していなかった。

最近またEmacsに戻ってきたので、備忘録も兼ねてEmacsの設定などを記載することにした。

マクラが長い。しかも割と黒歴史だったorz...
  • 2026/07/20
    • Updated for emacs-plus@32
  • 2024/11/07
    • Updated for emacs-plus@31
    • Remove poll(Removed from emacs-plus because poll causes problem
    • install after commandline, add sign.

環境とInstall

2024年現在、メイン端末はMacBookProで、管理しているサーバーは大半がFreeBSD(一部NetBSD, OpenBSD, AlmaLinux, Debian GNU Linux, Ubuntu, Windows11がある)である。したがって、最も利用する端末であるMacBookProにEmacsを導入しており、その他の環境では原則としてvi系のSystem標準Editorを利用している。

環境

年代 端末 CPU Memory OS
2026年 MacBookPro 16“ 2025 Apple Silicon m.4 48G macOS Tahoe/26.5.2
2024年 MacBookPro 16” 2019 Intel Core-i9 64G macOS Sonoma/14.6.1
2024年 VM(XCP-ng) AMD Ryzen7 3700X 4G FreeBSD 14.1

Install

昔はSource Codeを持ってきてCompileしていたが現在では流石にBinary Packageを利用している。

macOS

MacOSの場合、IMEのInline patchを当てないとMetaコマンド系を入力する際にM-あなどとなって少し(というかだいぶ)不便なので、patchを適用する。 そのため、少し面倒な対応が必要になる。

[参考]

macOSに HomeBrew を導入し、以下の一連の流れでInstallした。

$ mkdir ~/.config/emacs-plus
$ vi ~/.config/emacs-plus/build.yml
=====
icon: modern-pen
patches:
  - ns-inline-patch:
      url: "https://raw.githubusercontent.com/takaxp/ns-inline-patch/master/emacs-head-inline.patch"
      sha256: 1c77650e1eb5f661efc3fab02a9c8491915e5e65a40caf1503aff0e222c1a613
  # - aggressive-read-buffering
  # - frame-transparency
  # - mac-font-use-typo-metrics
=====
$ brew tap d12frosted/emacs-plus	# Emacs-plusのtapを追加 brew tapで取り込んでいるTapを確認できる
$ brew install --formula d12frosted/emacs-plus/emacs-plus@32 --with-mailutils
$ osascript -e 'tell application "Finder" to make alias file to posix file "/opt/homebrew/opt/emacs-plus@32/Emacs.app" at POSIX file "/Applications" with properties {name:"Emacs.app"}'
$ sudo codesign --force --deep --sign - /opt/homebrew/opt/emacs-plus@32/Emacs.app
$ brew services start d12frosted/emacs-plus/emacs-plus@32

ここまでを実行すると、

される。一応 Inline-patch を確認するために、一度Emacsを起動し、

が動作するかを確認しておく。

なお、自明だが、ImageMagickやDBUSを利用する場合には、brew install imagemagick dbusを実行しておくこと。 Emacs-plus@32では、Imagemagickは不要になった。DBUSはEmacs-plus@31の途中で非推奨になった。

このIME用 Inline-Patchを適用した場合、init.elに以下のelisp codeを追加しておくと良い。

(when (and (memq window-system '(ns nil))
           (fboundp 'mac-get-current-input-source))
  (when (version< "27.0" emacs-version)
    ;; Required for some cases when auto detection is failed or the locale is "en".
    (custom-set-variables
     '(mac-default-input-source "com.google.inputmethod.Japanese.base")))
  (mac-input-method-mode 1))

Emacs install時の引数に –with-x11 を追加すると、Compileに失敗した(@2024/08/15)

–with-imagemagickをつけてCompile/Installすると、mu4eを利用している時に画像などが綺麗に出力されるので、余裕があるなら入れておくほうが良い。<del> Obsolate
<del>–with-dbusをつけてCompile/Installすると、Process間通信のMessage BUSとしてDBUSを利用する。
 Obsolate.

https://github.com/d12frosted/homebrew-emacs-plus/issues/742
ここにあるように、macOS Sequoiaにおいて、Xcode commandline tools を最新にすると、Emacs.appを実行できない。
sudo codesign –force –deep –sign - /usr/local/opt/emacs-plus@32/Emacs.app
によってApp FileをSignすると実行できるようになる。注意すること。

Reading directory: Operation not permitted エラーが出て、Emacsからフォルダが開けない場合
macOS SequoiaでEmacsをInstallした後、どうしてもDesktop FolderをEmacsから開けなかった。
こういう時は、一度フルディスクアクセス設定を削除したのち、もう一度フルディスクアクセス設定を行うことで回避できる可能性がある。
Commandlineから sudo tccutil reset All org.gnu.Emacs を実行し、システム環境設定からセキュリティ→フルディスクアクセスに移動し、左下の「+」からEmacs.appを追加。その後、Emacs.appを再度起動すると、Desktopフォルダにアクセスできるようになった。

FreeBSD

自分はFreeBSDをサーバーとして利用しており、GUIを利用していない。そのため、EmacsをX11経由ではなくConsoleから利用している。ほとんどの接続がssh経由だからこれでよい。

したがって、EmacsのInstallは

$ doas pkg install emacs-nox		# sudoでもよい

で終わりである。

初期設定

Emacsはそれ単体では最小限のことしかできない。しかし、Emacs-Lispを組み込み、設定を行うことで色々なことができるようになる。これを称して、昔は、「EmacsはEditorではない。Environmentである」などとも言われていた。

以下、個人の設定。 (2024/08/26)

ここで、Packageごとの設定など、細かいことを説明すればいいんだろうけど、かなり面倒なので、コメントで勘弁して。

このinit.elは、byte-compileするとgo-translate関連の変数が未定義扱いになる。 本来は:customで設定すべきなんだろうと思うがうまく行かなかったので、とりあえずは:configで逃げてある。

early-init.el
;;; -*- lexical-binding: t; -*-
;;; ~/.config/emacs/early-init.el --- Early initialization
;;;
;;; last updated: 2026/01/02
;;; Author: HEO SeonMeyong <seirios@seirios.org>
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; log
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 2026/01/02	Refactoring by Microsoft Copilot.
 
;; 起動直後は GC を後ろ倒し(起動後に元へ戻す)
(setq gc-cons-threshold most-positive-fixnum)
(add-hook 'emacs-startup-hook (lambda () (setq gc-cons-threshold 134217728)))
 
;; package.el は自動では有効化しない(init.el側で initialize)
(setq package-enable-at-startup nil)
 
;; フレームの暗黙のリサイズ抑制(ちらつき防止)
(setq frame-inhibit-implied-resize t)
 
;; 早期に不要なUIをオフ
(push '(tool-bar-lines . 0)   default-frame-alist)
(push '(menu-bar-lines . 1)   default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
 
(provide 'early-init)
;;; early-init.el ends here
init.el
;;; -*- lexical-binding: t; -*-
;;; ~/.config/emacs/init.el --- Refactored init.el (Intel macOS)
;;;
;;; last updated: 2026/01/02
;;; Author: HEO SeonMeyong <seirios@seirios.org>
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Tips
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; emacs -nw -q --batch --eval '(message system-configuration-options)'	; Emacs compile option(Commandline)
;; emacs --batch -f batch-byte-compile init.el				; init.elの文法チェック(init.elcは削除すること)
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Prefix keys memo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; C-? : Control+?
;; M-? : Meta(ESC)+?
;; s-? : Super(command)+?
;; S-? : Shift+?	(本当?)
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; コメント定義
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; セミコロン 3 つは段落コメント
;; セミコロン 2 つはコードブロックコメント
;; セミコロン 1 つは、行コメント
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Reference site
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; https://emacs-jp.github.io						; 日本のEmacsユーザーのためのハブサイト
;;   https://emacs-jp.github.io/tips/emacs-in-2020			; * 2020年代のEmacs入門
;; https://qiita.com/conao3/items/347d7e472afd0c58fbd7			; * Emacs入門から始めるleaf.el入門
;; https://qiita.com/conao3/items/dc88bdadb0523ef95878			; * leaf.elで「init.el」をクリーンにする
;; https://uwabami.github.io/cc-env/Emacs.html				; Emacs の設定
;; https://zenn.dev/zenwerk/scraps/b1280f66c8d11a			; Emacs設定記 2021
;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Find-Init.html	; Emacs Manual
;; https://github.com/purcell/exec-path-from-shell			; Macでshellから環境変数を取り込む
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; log
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 2026/01/02	Refactoring by Microsoft Copilot.
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Path & package bootstrap
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 追加の elisp を load-path に加える(存在チェック付き)
(let ((extra-paths '("/usr/local/share/emacs/site-lisp"
                     "~/.config/emacs/elisp/")))
  (dolist (p extra-paths)
    (let ((abs (expand-file-name p)))
      (when (file-directory-p abs)
        (add-to-list 'load-path abs)))))
 
;; Info の追加ディレクトリ(Homebrew等)
(dolist (info-dir '("/usr/local/share/info/"))
  (when (file-directory-p info-dir)
    (add-to-list 'Info-default-directory-list info-dir)))
 
;; package.el の初期化(early-init.el で package-enable-at-startup を nil にしている前提)
(require 'package)
(custom-set-variables
 '(package-archives '(("gnu"   . "https://elpa.gnu.org/packages/")
                      ("melpa" . "https://melpa.org/packages/")
                      ("org"   . "https://orgmode.org/elpa/")))
 '(package-gnupghome-dir (expand-file-name ".gnupg" (getenv "HOME"))))
(package-initialize)
 
;; leaf を未導入なら取得
(unless (package-installed-p 'leaf)
  (package-refresh-contents)
  (package-install 'leaf))
 
(leaf leaf-keywords
  :ensure t
  :config (leaf-keywords-init))
 
;; customize の書き込み先を分離
(setq custom-file (expand-file-name "~/.config/emacs/custom.el"))
(when (file-exists-p custom-file)
  (load custom-file))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; macOS: シェルの環境変数を取り込む(GUI起動でも PATH 等を揃える)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf exec-path-from-shell
  :ensure t
  :require t
  :when (memq window-system '(mac ns x))
  :config
  (dolist (var '("PATH" "MANPATH" "LD_LIBRARY_PATH" "LIBRARY_PATH"))
    (add-to-list 'exec-path-from-shell-variables var))
  (exec-path-from-shell-initialize))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 基本設定(UI/操作系)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf cus-start
  :doc "Builtins のカスタマイズをまとめる"
  :bind (("M-%"      . replace-regexp)
         ("C-c M-%"  . query-replace-regexp)
         ("C-%"      . replace-string)
         ("C-c C-%"  . query-replace)
         ("C-z"      . undo)
         ("C-x c"    . browse-url-at-point)
         ("C-h"      . delete-backward-char)
         ("C-c C-l"  . toggle-truncate-lines)
         ("C-c /"    . comment-or-uncomment-region)
         ("C-c l"    . display-line-numbers-mode)
         ("C-s"      . isearch-forward)
         ;; mu4e ランチャー
         ("C-x m"    . mu4e)
         ;; Tab-bar 操作(mac風)
         ("s-}"      . tab-bar-switch-to-next-tab)
         ("s-{"      . tab-bar-switch-to-prev-tab)
         ("s-T"      . tab-new)
         ("s-w"      . tab-close))
  :hook ((minibuffer-setup-hook . shrink-window-if-larger-than-buffer))
  :custom '((create-lockfiles . nil)                 ; lockfile を作らない
            (debug-on-error . t)                     ; エラー時 backtrace
            (frame-resize-pixelwise . t)
            (enable-recursive-minibuffers . t)
            (history-length . 1000)
            (history-delete-duplicates . t)
            (scroll-preserve-screen-position . t)
            (scroll-conservatively . 10000)
            (scroll-step . 1)
            (scroll-margin . 2)
            (visible-bell . t)
            (text-quoting-style . 'straight)
            (truncate-lines . nil)                   ; 折り返し表示
            (tab-width . 8)
            (line-number-display-limit-width . 10000)
            (resize-mini-windows . t)
            (max-mini-window-height . 0.1)
            (indicate-empty-lines . t)
            (indicate-buffer-boundaries . 'left)
            (gc-cons-percentage . 0.2)
            (gc-cons-threshold . 134217728)         ; 128MB
            (menu-bar-mode . t)
            (tool-bar-mode . nil)
            (scroll-bar-mode . nil)
            (indent-tabs-mode . nil)
            (transient-mark-mode . t)
            (tab-bar-mode . t))
  :config
  ;; yes-or-no を y/n に短縮
  (defalias 'yes-or-no-p 'y-or-n-p)
  ;; 改行のバックスラッシュを非表示
  (set-display-table-slot standard-display-table 0 ?\ )
  (set-display-table-slot standard-display-table 'wrap ?\ )
  ;; macOS 固有
  (leaf cus-start-mac
    :when (eq system-type 'darwin)
    :custom ((ns-alternate-modifier . 'meta)
             (ns-use-srgb-colorspace . t)))
             ;; Frame Transparency (for emacs-plus@31)
             ;; (set-frame-parameter nil 'ns-alpha-elements nil)	; Not use Transparency
             (set-frame-parameter nil 'ns-alpha-elements '(ns-alpha-all))
             ;; Choose elements:
             ;; - Full list: ns-alpha-default (default face/background)
             ;;              ns-alpha-fringe (fringes + internal border clears)
             ;;              ns-alpha-box (boxed face outlines)
             ;;              ns-alpha-stipple (stipple mask background clears)
             ;;              ns-alpha-relief (3D relief/shadow lines)
             ;;              ns-alpha-glyphs (glyph background fills like hl-line/region)
             (set-frame-parameter nil 'ns-alpha-elements
                 '(ns-alpha-default ns-alpha-fringe ns-alpha-glyphs))
             (set-frame-parameter nil 'alpha-background 0.8)
             (set-frame-parameter nil 'ns-background-blur 20)
)
 
;; dired のショートカット
(leaf dired :bind ((:dired-mode-map ("u" . dired-up-directory))))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 多言語環境(mule)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf mule
  :config
  (set-language-environment 'Japanese)
  (set-terminal-coding-system 'utf-8)
  (set-keyboard-coding-system 'utf-8)
  (set-buffer-file-coding-system 'utf-8)
  (set-file-name-coding-system 'utf-8)
  (set-clipboard-coding-system 'utf-8)
  (prefer-coding-system 'utf-8)
  (set-default-coding-systems 'utf-8)
  (when (eq system-type 'darwin)
    (customize-set-variable 'default-input-method "macOS")))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; GUI/フォント
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (memq window-system '(x mac ns))
  (defvar my-frame-parameters
    '((height . 45) (width . 188)
      (top . 20) (left . 20)
      (line-spacing . 0)
      (left-fringe . 12) (right-fringe . 12)
      (cursor-type . box)
      (alpha . 95)
      (foreground-color . "#F2F2F2")
      (background-color . "#000040")
      (cursor-color . "#C0C000")
      (mouse-color . "#8D8D8D")))
  (setq default-frame-alist my-frame-parameters)
  (setq frame-title-format '(multiple-frames "%b" ("" invocation-name)))
  (setq blink-cursor-mode t)
  (setq frame-inherited-parameters '(font tool-bar-lines))
  (setq ns-pop-up-frames nil)
  ;; mac/ns フォント
  (when (memq window-system '(mac ns))
    (global-set-key [s-mouse-1] 'browse-url-at-mouse)
    (let* ((size 16)
           (jpfont "PlemolJP")
           (asciifont "PlemolJP")
           (h (* size 10)))
      (set-face-attribute 'default nil :family asciifont :height h)
      (set-fontset-font t 'katakana-jisx0201 jpfont)
      (set-fontset-font t 'japanese-jisx0208 jpfont)
      (set-fontset-font t 'japanese-jisx0212 jpfont)
      (set-fontset-font t 'japanese-jisx0213-1 jpfont)
      (set-fontset-font t 'japanese-jisx0213-2 jpfont)
      (set-fontset-font t '(#x0080 . #x024F) asciifont))
    (setq face-font-rescale-alist
          '(("^-apple-hiragino.*" . 1.2)
            (".*-Hiragino Maru Gothic ProN-.*" . 1.2)
            (".*osaka-bold.*" . 1.2)
            (".*osaka-medium.*" . 1.2)
            (".*courier-bold-.*-mac-roman" . 1.0)
            (".*monaco cy-bold-.*-mac-cyrillic" . 0.9)
            (".*monaco-bold-.*-mac-roman" . 0.9)
            ("-cdac$" . 1.3))))
  ;; マウス設定
  (setq mouse-drag-copy-region t)
  (setq mouse-wheel-scroll-amount '(1 ((shift) . 2) ((control))))
  (setq mouse-wheel-progressive-speed nil))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Builtins: modeline/time 等
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf which-function :custom '((which-function-mode . t)))
 
(leaf time
  :hook (emacs-startup-hook . display-time-mode)
  :custom '((display-time-interval . 1)
            (display-time-string-forms '((format "%s:%s:%s" 24-hours minutes seconds)))
            (display-time-day-and-date . t)))
 
(leaf browse-url
  :custom '((browse-url-browser-function . 'browse-url-generic))
  :config
  (when (eq system-type 'darwin)
    (customize-set-variable 'browse-url-generic-program "open")))
 
(leaf time-stamp
  :hook (before-save-hook . time-stamp)
  :custom '((time-stamp-active . t)
            (time-stamp-start . "last updated: ")
            (time-stamp-format . "%Y/%02m/%02d")
            (time-stamp-end . " \n$")))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 表示/編集補助
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
(setq-default display-line-numbers nil)			;; 行番号は基本オフ(必要なら C-c l で局所的にトグル)
(global-display-line-numbers-mode -1)			;; ← nil ではなく -1 で確実に OFF
(setq column-number-mode t)
(setq size-indication-mode t)
 
(leaf whitespace
  :require t
  :hook (find-file-hook . (lambda () (whitespace-mode 1)))
  :config
  (setq whitespace-style '(face trailing tabs empty spaces)
        ;; 全角スペースのみ可視化
        whitespace-space-regexp "\\(\\u3000+\\)")
  ;; フェイスは一度だけ設定
  (set-face-attribute 'whitespace-trailing nil
    :foreground "DeepPink" :background "Purple4" :underline t)
  (set-face-attribute 'whitespace-tab nil
    :foreground "RoyalBlue4" :background "gray20" :underline t)
  (set-face-attribute 'whitespace-space nil
    :background "blue3" :foreground "GreenYellow" :weight 'bold :underline t)
  (set-face-attribute 'whitespace-empty nil
    :foreground "MediumPurple4" :background "thistle4" :underline t)
  (global-whitespace-mode t))
 
(leaf paren
  :hook (emacs-startup-hook . show-paren-mode)
  :custom '((show-paren-delay . 0)
            (show-paren-style . 'mixed)))
 
(leaf simple
  :custom '((kill-ring-max . 100)
            (kill-read-only-ok . t)
            (kill-whole-line . nil)
            (eval-expression-print-length . nil)
            (eval-expression-print-level . nil)
            (indent-tabs-mode . nil)
            (mail-user-agent . 'mu4e-user-agent)))
 
(leaf files
  :custom '((make-backup-files . t)
            (backup-by-copying . t)
            (version-control . t)
            (kept-new-versions . 2)
            (kept-old-versions . 2)
            (delete-old-versions . t)
            (auto-save-timeout . 15)
            (auto-save-interval . 60)
            (delete-auto-save-files . t)))
 
(leaf startup
  :config
  (setq init-file-debug t
        auto-save-list-file-prefix (locate-user-emacs-file "backup/.saves-")
        inhibit-startup-screen t
        inhibit-startup-message t
        inhibit-startup-echo-area-message t
        initial-scratch-message ""))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 補完: company
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf company
  :ensure t
  :bind (("C-M-i" . company-complete)
         (:company-active-map
          ("C-n" . company-select-next)
          ("C-p" . company-select-previous)
          ("C-s" . company-filter-candidates)
          ("C-h" . nil)
          ("C-S-h" . company-show-doc-buffer)
          ("<tab>" . company-complete-common))
         (:company-search-map
          ("C-n" . company-select-next)
          ("C-p" . company-select-previous)))
  :custom '((company-idle-delay . 0.3)
            (company-minimum-prefix-length . 2)
            (company-transformers . '(company-sort-by-backend-importance))
            (company-auto-expand . t)
            (company-selection-wrap-around . t)
            (completion-ignore-case . t)
            (company-dabbrev-downcase . nil)
            (company-show-numbers . t)))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 言語モード
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf lua-mode
  :ensure t
  :mode ("\\.lua\\'" . lua-mode)
  :interpreter ("lua" . lua-mode)
  :custom '((lua-indent-level . 2)
            (lua-indent-string-contents . nil)
            (lua-indent-nested-block-content-align . t)
            (lua-indent-close-paren-align . t)
            (lua-default-application . "/usr/local/bin/lua")
            (lua-default-command-switches . "-i")
            (lua-always-show . t))
  :config (add-hook 'lua-mode-hook #'company-mode))
 
(leaf caddyfile-mode
  :ensure t
  :mode (("Caddyfile\\'" . caddyfile-mode)
         ("caddy\\.conf\\'" . caddyfile-mode))
  :hook (caddyfile-mode-hook . (lambda () (setq-local tab-width 4
                                                     indent-tabs-mode nil))))
 
(leaf nginx-mode
  :ensure t
  :mode (("nginx\\.conf\\'" . nginx-mode))
  :hook (nginx-mode-hook . company-mode))
 
(leaf w3m
  :ensure t
  :custom ((w3m-command . "/usr/local/bin/w3m")))
 
(leaf vc-fossil
  :ensure t
  :init (add-to-list 'vc-handled-backends 'Fossil t))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 翻訳: go-translate (鍵は環境変数/認証ストアから取得推奨)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf go-translate
  :ensure t
  :bind (("C-c t" . gt-do-translate))
  :custom '((gt-langs . '(en ja)))
  :config
  ;; DeepL API キーは環境変数 DEEPL_API_KEY から取得。未設定なら DeepL を使わず Google/Bing へフォールバック。
  (let ((deepl-key (getenv "DEEPL_API_KEY")))
    (setq gt-default-translator
          (gt-translator
           :taker (gt-taker :text 'buffer :pick 'paragraph)
           :engines (delq nil (list (gt-deepl-engine :key "d7b2482e-9a53-43a5-885d-bc511b7b0aad:fx" :pro nil)
                                    (gt-google-engine)
                                    (gt-bing-engine)))
           :render (gt-buffer-render)))))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; EasyPG (GPG)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(leaf epa-file
  :require t
  :config
  (epa-file-enable)
  ;; pinentry-mode は epg-config の変数
  (with-eval-after-load 'epg-config
    (setq epg-pinentry-mode 'loopback)))
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; mu4e 設定を分離ロード
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(load (expand-file-name "~/.config/emacs/mu4e-init.el") t)
 
(provide 'init)
;;; init.el ends here