GNU Emacs
開発ツール
GNU Emacs
概要
GNU EmacsはRichard Stallman氏によって開発された高度に拡張可能なテキストエディタです。「オペレーティングシステム」とも呼ばれる豊富な機能群と、Emacs Lispによる無限の拡張性で、多くのプログラマーに愛用されています。
詳細
Emacsは1976年にRichard Stallman氏によって開発が開始され、1985年にGNU Emacsとしてリリースされました。単なるテキストエディタを超えて、メール、ウェブブラウジング、カレンダー、ゲーム、プログラミング環境など、あらゆる機能を統合したプラットフォームとして機能します。
Emacsの最大の特徴は、Emacs Lispによる完全なプログラマビリティです。エディタのほぼ全ての機能がEmacs Lispで記述されており、ユーザーは自由に機能を追加・変更できます。org-mode(情報整理)、Magit(Git クライアント)、mu4e(メールクライアント)、evil-mode(Vim エミュレーション)など、強力なパッケージが豊富に存在します。
セルフドキュメンティング設計により、エディタ内で全ての機能のドキュメントにアクセスでき、関数定義の参照や動的な機能探索が可能です。バッファベースのウィンドウシステム、強力なキーバインドシステム、正規表現による検索・置換、多様なプログラミング言語サポートなど、高度なテキスト編集機能を提供します。
メリット・デメリット
メリット
- 無限の拡張性: Emacs Lispによる完全なカスタマイズ可能性
- 統合プラットフォーム: エディタ、メール、ブラウザ、PIM機能の統合
- セルフドキュメント: エディタ内での完全なドキュメント参照
- 強力なパッケージ: Org-mode、Magit、mu4eなど高機能パッケージ
- プログラマブル: あらゆる操作をプログラムで自動化可能
- 長い歴史: 40年以上の開発で培われた安定性と成熟度
- 独立性: 他のツールに依存しない完結した環境
デメリット
- 急峻な学習曲線: 独特な操作体系の習得に長期間必要
- 重いリソース消費: 多機能ゆえにメモリと CPU を大量消費
- ターミナルでの制限: GUI版と比較してターミナル版は機能制限
- 初期設定の複雑さ: 基本的な使用でも相当な設定作業が必要
- UI の古さ: 現代的なエディタと比較してインターフェースが古い
- プラグイン管理: パッケージ間の競合や互換性問題
- 起動時間: 大量の設定読み込みにより起動が遅い
主要リンク
書き方の例
基本設定(init.el)
;; ~/.emacs.d/init.el - 基本設定
;; パッケージシステム設定
(require 'package)
(setq package-enable-at-startup nil)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/"))
(package-initialize)
;; use-packageのインストール
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
;; 基本設定
(setq inhibit-startup-message t) ; スタートアップメッセージを非表示
(setq inhibit-scratch-message nil) ; scratchバッファメッセージ
(setq initial-scratch-message "") ; 初期メッセージを空に
;; UI設定
(menu-bar-mode -1) ; メニューバーを非表示
(tool-bar-mode -1) ; ツールバーを非表示
(scroll-bar-mode -1) ; スクロールバーを非表示
(global-display-line-numbers-mode 1) ; 行番号表示
(column-number-mode 1) ; カラム番号表示
(show-paren-mode 1) ; 対応する括弧をハイライト
(global-hl-line-mode 1) ; カーソル行をハイライト
;; インデント設定
(setq-default indent-tabs-mode nil) ; タブをスペースに変換
(setq-default tab-width 4) ; タブ幅
(setq indent-line-function 'insert-tab) ; インデント関数
;; バックアップとオートセーブ
(setq backup-directory-alist `((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t)))
(setq backup-by-copying t)
(setq delete-old-versions t)
(setq kept-new-versions 6)
(setq kept-old-versions 2)
(setq version-control t)
;; エンコーディング
(set-language-environment "Japanese")
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
;; キーバインド
(global-set-key (kbd "C-h") 'delete-backward-char)
(global-set-key (kbd "M-?") 'help-command)
(global-set-key (kbd "C-c l") 'toggle-truncate-lines)
(global-set-key (kbd "C-c r") 'replace-string)
(global-set-key (kbd "C-c R") 'replace-regexp)
(global-set-key (kbd "C-x C-b") 'ibuffer)
;; フォント設定
(when (eq system-type 'darwin)
(set-face-attribute 'default nil :family "Monaco" :height 140))
(when (eq system-type 'gnu/linux)
(set-face-attribute 'default nil :family "DejaVu Sans Mono" :height 110))
(when (eq system-type 'windows-nt)
(set-face-attribute 'default nil :family "Consolas" :height 110))
パッケージ設定(use-package)
;; テーマ設定
(use-package doom-themes
:ensure t
:config
(setq doom-themes-enable-bold t
doom-themes-enable-italic t)
(load-theme 'doom-one t)
(doom-themes-visual-bell-config)
(doom-themes-org-config))
;; 補完フレームワーク
(use-package ivy
:ensure t
:init
(ivy-mode 1)
:config
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
(global-set-key (kbd "C-s") 'swiper)
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "C-x C-f") 'counsel-find-file))
(use-package counsel
:ensure t
:after ivy)
(use-package swiper
:ensure t
:after ivy)
;; プロジェクト管理
(use-package projectile
:ensure t
:init
(projectile-mode +1)
:bind (:map projectile-mode-map
("s-p" . projectile-command-map)
("C-c p" . projectile-command-map)))
;; Git統合
(use-package magit
:ensure t
:bind (("C-x g" . magit-status)
("C-x M-g" . magit-dispatch)))
;; 会社補完
(use-package company
:ensure t
:init
(global-company-mode)
:config
(setq company-idle-delay 0.2)
(setq company-minimum-prefix-length 1)
(setq company-selection-wrap-around t))
;; ファイルツリー
(use-package neotree
:ensure t
:config
(global-set-key [f8] 'neotree-toggle)
(setq neo-theme 'arrow))
;; Org-mode拡張
(use-package org
:ensure t
:config
(setq org-directory "~/org/")
(setq org-default-notes-file (concat org-directory "notes.org"))
(setq org-agenda-files (list org-directory))
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)
(global-set-key (kbd "C-c l") 'org-store-link))
;; Evil mode (Vim エミュレーション)
(use-package evil
:ensure t
:init
(setq evil-want-integration t)
(setq evil-want-keybinding nil)
:config
(evil-mode 1))
(use-package evil-collection
:after evil
:ensure t
:config
(evil-collection-init))
;; LSP
(use-package lsp-mode
:ensure t
:init
(setq lsp-keymap-prefix "C-c l")
:hook ((python-mode . lsp)
(javascript-mode . lsp)
(lsp-mode . lsp-enable-which-key-integration))
:commands lsp)
(use-package lsp-ui
:ensure t
:commands lsp-ui-mode)
(use-package lsp-ivy
:ensure t
:commands lsp-ivy-workspace-symbol)
Org-mode設定例
;; Org-mode詳細設定
(use-package org
:ensure t
:config
;; 基本設定
(setq org-directory "~/org/")
(setq org-default-notes-file (concat org-directory "inbox.org"))
(setq org-agenda-files (list (concat org-directory "gtd.org")
(concat org-directory "projects.org")
(concat org-directory "calendar.org")))
;; TODO キーワード
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "WAITING(w)" "|" "DONE(d)" "CANCELLED(c)")))
;; タグ
(setq org-tag-alist '(("@work" . ?w)
("@home" . ?h)
("@computer" . ?c)
("@phone" . ?p)
("@errands" . ?e)))
;; キャプチャテンプレート
(setq org-capture-templates
'(("t" "Todo" entry (file+headline org-default-notes-file "Tasks")
"* TODO %?\n %i\n %a")
("j" "Journal" entry (file+datetree "~/org/journal.org")
"* %?\nEntered on %U\n %i\n %a")
("m" "Meeting" entry (file+headline "~/org/meetings.org" "Meetings")
"* %? :meeting:\n %U\n %i")
("n" "Note" entry (file+headline "~/org/notes.org" "Notes")
"* %?\n %U\n %i")))
;; アジェンダ設定
(setq org-agenda-custom-commands
'(("d" "Daily agenda and all TODOs"
((agenda "" ((org-agenda-span 1)))
(alltodo "" ((org-agenda-overriding-header "All TODOs")))))))
;; バベル設定(コード実行)
(org-babel-do-load-languages
'org-babel-load-languages
'((python . t)
(shell . t)
(emacs-lisp . t)
(javascript . t)))
;; キーバインド
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)
(global-set-key (kbd "C-c l") 'org-store-link))
カスタム関数例
;; カスタム関数定義
;; 現在行を複製する関数
(defun duplicate-line ()
"Duplicate the current line."
(interactive)
(let ((line (buffer-substring-no-properties
(line-beginning-position)
(line-end-position))))
(end-of-line)
(newline)
(insert line)))
;; 末尾の空白を削除する関数
(defun delete-trailing-whitespace-and-save ()
"Delete trailing whitespace and save the file."
(interactive)
(delete-trailing-whitespace)
(save-buffer))
;; ウィンドウ分割
(defun split-window-below-and-switch ()
"Split window below and switch to it."
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(defun split-window-right-and-switch ()
"Split window right and switch to it."
(interactive)
(split-window-right)
(balance-windows)
(other-window 1))
;; 設定ファイルを開く関数
(defun open-init-file ()
"Open the init file."
(interactive)
(find-file user-init-file))
;; 現在のファイルをリロードする関数
(defun reload-init-file ()
"Reload the init file."
(interactive)
(load-file user-init-file))
;; キーバインド設定
(global-set-key (kbd "C-c d") 'duplicate-line)
(global-set-key (kbd "C-c s") 'delete-trailing-whitespace-and-save)
(global-set-key (kbd "C-x 2") 'split-window-below-and-switch)
(global-set-key (kbd "C-x 3") 'split-window-right-and-switch)
(global-set-key (kbd "C-c i") 'open-init-file)
(global-set-key (kbd "C-c r") 'reload-init-file)
;; バッファ管理関数
(defun kill-other-buffers ()
"Kill all buffers except the current one."
(interactive)
(mapc 'kill-buffer
(delq (current-buffer)
(remove-if-not 'buffer-file-name (buffer-list)))))
(defun switch-to-previous-buffer ()
"Switch to the previous buffer."
(interactive)
(switch-to-buffer (other-buffer (current-buffer) 1)))
(global-set-key (kbd "C-c k") 'kill-other-buffers)
(global-set-key (kbd "C-c b") 'switch-to-previous-buffer)
プログラミング環境設定
;; プログラミング言語設定
;; Python設定
(use-package python-mode
:ensure t
:mode "\\.py\\'"
:hook (python-mode . lsp-deferred)
:config
(setq python-indent-offset 4))
;; JavaScript/TypeScript設定
(use-package js2-mode
:ensure t
:mode "\\.js\\'"
:hook (js2-mode . lsp-deferred)
:config
(setq js2-basic-offset 2))
(use-package typescript-mode
:ensure t
:mode "\\.ts\\'"
:hook (typescript-mode . lsp-deferred)
:config
(setq typescript-indent-level 2))
;; Web開発
(use-package web-mode
:ensure t
:mode (("\\.html?\\'" . web-mode)
("\\.css\\'" . web-mode)
("\\.jsx?\\'" . web-mode)
("\\.tsx?\\'" . web-mode))
:config
(setq web-mode-markup-indent-offset 2)
(setq web-mode-css-indent-offset 2)
(setq web-mode-code-indent-offset 2))
;; Markdown
(use-package markdown-mode
:ensure t
:mode (("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:config
(setq markdown-command "multimarkdown"))
;; YAML
(use-package yaml-mode
:ensure t
:mode "\\.ya?ml\\'")
;; JSON
(use-package json-mode
:ensure t
:mode "\\.json\\'")
;; フライチェック(シンタックスチェック)
(use-package flycheck
:ensure t
:init (global-flycheck-mode)
:config
(setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
;; 自動フォーマット
(use-package format-all
:ensure t
:hook (prog-mode . format-all-mode))