プログラミング
Emacsでは、すべてがサービスのように見える
In Emacs, Everything Looks Like a Service (yummymelon.com)
要約
この記事は、Emacsが単なるテキストエディタではなく、OSカーネルレベルを超えてアプリケーションやユーティリティを連携させる能力を持つため、オペレーティングシステム(OS)と比較される理由を解説しています。Emacsは、ファイルシステムやネットワークなどのOSサービスへの組み込みアクセスと、他のプログラムを実行する能力を組み合わせることで、ユーザーが計算ニーズの多くをEmacs内で実現できる「Emacs内で生きる」という概念を支持しています。クライアント・サーバーモデルの定義と、EmacsがUI、クライアントエッジ、ローカルデータベースといったクライアントの責任を果たすために提供する豊富なライブラリ(Minibuffers、Buffers、URL、Socket、JSON、XMLなど)について説明し、wttr.inのような外部サービスをElispで統合する具体的な例を示しています。
全文翻訳
notes from /dev/null by Charles Choi 최민수
In Emacs, Everything Looks Like a Service
09 Jul 2026
Charles Choi
よく言われることですが、Emacsはオペレーティングシステム(OS)だという意見があります。これは事実ではありませんが、OSと比較される要因となっているのは、OSカーネルレベルを超えてアプリケーションやユーティリティを連携させる能力です。下の図は、EmacsがOSとその機能とどのように関連しているかを示す、より正確な絵を示唆しています。
EmacsのOSシステムサービス(ファイルシステム、ネットワークなど)への組み込みアクセスと、他のプログラムを実行する能力を組み合わせることで、Emacs内でクライアントの動作を即興で作ることが日常的になります。このため、Emacsユーザーは、それのために作られたさまざまなクライアントモードから、多くのコンピューティングニーズを達成することができます。これは、「Emacs内で生きる」という考えに信憑性を与えます。
この記事では、Emacsがクライアントを構築する方法をいくつか調べます。この記事の終わりまでには、Emacs内ではすべてがサービスのように見えるということに、おそらく納得していただけるでしょう。
クライアント・サーバーモデル
まず、いくつかの定義を提供しましょう。クライアント・サーバーモデルは、リソースの提供者(サービス)とリソースの要求者(クライアント)の間でタスクが分割される、一般的なコンピューターインタラクションパターンです。クライアントはサーバーにリクエストを発行し、サーバーは応答を返します(下の図に示すように)。実装によっては、トランザクション(リクエスト+応答)はネットワークを介して発生することも、システムローカルであることもあります。ネットワークを使用したクライアント・サーバーモデルは、RESTスタイルのソフトウェアアーキテクチャで最も詳細に説明されています。下のシーケンス図に示すのは、RESTスタイルのクライアントサーバーアーキテクチャの一般的な実装パターンです。
Emacsとしてのクライアント
上記の図から、クライアントが通常担当する3つの懸念事項があります。
UI: ユーザーインターフェース(もしあれば)。
クライアントエッジ: サービスとの通信を担当するサブシステム。ネットワーククライアントの場合、これはネットワークサブシステムです。
ローカルデータベース: サーバーと交換または同期されるデータの表現。このデータの管理方法は、実装要件によります。
上記の懸念事項について、Emacsは組み込みおよびサードパーティの両方で多数のライブラリを提供しており、これらを使用してクライアントを実装できます。以下に、組み込みライブラリとその詳細を読むためのリンクをいくつか示します。
UI
Minibuffers
Buffers
Completion
Tabulated List Mode
Transient
クライアントエッジ
URL
Socket (TCP/UDP)
SMTP
シリアライゼーション/デシリアライゼーション
JSON
XML
ローカルデータベース
Collections
Association Lists
Property Lists
Hash Tables
SQLite
Emacsクライアントを実装するために必要な複雑さは、要件によって決まります。既存のコマンドラインユーティリティが「重い作業」を行うことができる場合、そのユーティリティはシェル呼び出しを介してアクセスできる「サービス」として再構成できます。
Elisp
上記で言及されたすべてのライブラリは、Emacs Lisp(Elisp)プログラミング言語を介してアクセスされます。Elispは動的プログラミング言語であり、実行時に高度な即興性を可能にします。この機能により、Elisp関数からシェルコマンドまで、Emacsで利用可能なあらゆる動作の複雑なオーケストレーションが可能になります。
例: wttr.inクライアント
wttr.inは、コンソール指向の天気予報ウェブサービスです。JSON出力をサポートしているため、場所を尋ね、HTTPリクエストを行い、JSON応答を処理し、結果をミニバッファに表示するEmacsのwttrコマンドを構築できます。トップレベルコマンドwttrを以下に示します。
(defun wttr (location)
"Show weather conditions for LOCATION from `https://wttr.in' in mini-buffer. Result is also stored in `kill-ring'."
(interactive "sWhere (default: local): ")
(condition-case err
(let* ((url (wttr--request-url location))
(jsondb (fetch-json-as-hash-table url))
(msg (wttr--report-message jsondb)))
(kill-new msg)
(message "%s" msg))
(error (message "ERROR: %s" (cdr err)))))
wttr.in URLは、以下に示すwttr--request-url関数によって構築されます。
(defun wttr--request-url (location)
"Construct wttr.in URL with LOCATION."
(let* ((base-url (url-generic-parse-url "https://wttr.in"))
(encoded-location (string-replace " " "+" location))
(query (format "/%s?0&format=j1" encoded-location))
(_dummy (setf (url-filename base-url) query)))
(url-recreate-url base-url)))
次に、そのURLをfetch-json-as-hash-tableに渡すことができます。これは、URLの取得とJSON応答のElispハッシュテーブルへの解析という重い作業を行います。
(defun fetch-json-as-hash-table (url)
"Fetch URL with expected JSON response and return a `hash-table'."
(let ((data-buffer (url-retrieve-synchronously url)))
(if (not data-buffer)
(error "Failed to fetch data from %s" url)
(unwind-protect
(with-current-buffer data-buffer
;; Move point past the HTTP metadata headers
(goto-char url-http-end-of-headers)
;; Parse the remaining JSON buffer into a hash-table
(json-parse-buffer :object-type 'hash-table))
;; Always kill the downloaded network buffer to prevent memory leaks
(kill-buffer data-buffer)))))
最後に、JSON応答(jsondb)から目的の値を取り出して、ミニバッファに送信されるメッセージを生成できます。
(defun wttr--report-message (jsondb)
"Generate weather report message from JSONDB."
(let* ((area-buflist ())
(nearest-area (wttr--get-first jsondb "nearest_area"))
(area-name (map-elt (wttr--get-first nearest-area "areaName") "value"))
(region (map-elt (wttr--get-first nearest-area "region") "value"))
(country (map-elt (wttr--get-first nearest-area "country") "value"))
(current-condition (wttr--get-first jsondb "current_condition"))
(temp_c (map-elt current-condition "temp_C"))
(temp_f (map-elt current-condition "temp_F"))
(weather-description (map-elt (wttr--get-first current-condition "weatherDesc") "value")))
(mapc (lambda (x) (if (and x (not (string-equal x ""))) (push x area-buflist))) (list area-name region country))
(format "%s: %s°C, %s°F %s" (string-join (reverse area-buflist) ", ") temp_c temp_f weather-description)))
wttr.el source
締めくくり
この時点で、Emacs内ではすべてがサービスのように見えるというタイトルの主張に納得していただけたことでしょう。さらに、Emacsが提供するAPIの多くは高レベルの抽象化で機能します。wttr.elのコード行数が67行であることを考慮してください(clocユーティリティを使用した結果)。
それが多すぎる場合は、実際のネットワークリクエストとJSON処理がweatherというPythonスクリプトで行われる代替実装を想像してみてください。その場合、それを呼び出すElispコマンドは、以下に示すコードだけになります。
(defun weather (location)
"Call weather script with LOCATION and show result in minibuffer."
(interactive "sWhere (default: local): ")
(let* ((weather-cmd "weather")
(cmd (if location (format "%s %s" weather-cmd location) weather-cmd))
(result (shell-command-to-string cmd)))
(kill-new result)
(message result)))
上記の Среализацией では、シェルコマンドがリクエストを行うための「サービス」として効果的に機能します。Elispは動的プログラミング言語であるため、Elispライブラリとコマンドラインユーティリティを即興的な方法で統合できます。この機能は、それが提供できる機会を認識するユーザーにとって魅力的です。
emacs
Scheduling Future Tasks in Emacs →
About • Mastodon • Bluesky • GitHub
Feeds & Tags • Get Scrim for macOS • Get Captee for macOS
© 2009-2026 Charles Y. Choi
Powered by Pelican