プログラミング
e: Chez Schemeで書かれた、カスタマイズ可能で自己認識的なEmacs風エディタ
e is a customizable self-aware Emacs-like editor written in Chez Scheme (github.com)
要約
eはChez Schemeで書かれた、Emacsに似た精神を持つ軽量なコンソールテキストエディタです。Emacsの機能を取り入れつつ、小さく保つことに重点を置いています。エディタ自体がSchemeシステムとして機能し、モジュールのホットリロードや、エディタ内でのSchemeコード評価など、高度なカスタマイズ性と自己拡張性を備えています。依存関係はChez Schemeのみで、インストール不要で即座に実行可能です。
全文翻訳
e Chez Schemeで書かれた、小さなコンソールテキストエディタです。
バッファ、ウィンドウ、キルリング、インクリメンタルサーチ、Schemeトップレベルなど、Emacs風の精神を持っていますが、Emacsのクローンではありません。小さく保つというアイデアを取り入れ、それ以上のことはしません。
エディタはSchemeシステムです。すべてがR6RSライブラリです。公開された不変のAPIを持つ最小限のコアと、その上に構築された拡張モジュール(シンタックスモード、ブラケットマッチング、編集ヘルパー、M-x自体)です。
コアは規律ではなく言語によって境界を強制します。内部は不可視で、エクスポートは再割り当てできません。
M-xは、シンボル補完、入力中のパラメータヒント、履歴、トランスクリプトバッファを備えた、エディタのライブトップレベルに対してSchemeを評価します。
モジュールはホットリロードされます。エディタ内でモジュールのソースを保存すると、実行中のセッションにリロードされます。外部で編集されたソースはreload-module!で検出されます。登録は置き換えられ、依存モジュールは再コンパイルされ、バッファはそのまま保持されます。
eはそれ自体の中から開発されています。
Chez SchemeとUnixライクなターミナル以外の依存関係はありません。
ビルドやインストールのステップはありません。チェックアウトすればそのまま実行できます。
最初の起動時にライブラリがコンパイルされます。それ以降の起動は約100ミリ秒です。
Undoは、Undo insert "hello"、Undo (replace-all! "xx" "yy") のように、何を取り消したかを報告します。
入力された文字は一連の操作としてまとまり、ペーストは単一のステップ、M-xコマンドはラベル付きの1つのステップになります。
クイックスタート
日常のエディタとして、~/.e にクローンします。
git clone https://github.com/paveluv/e ~/.e
~/.e/e file.txt # 単純な`e`のために~/.eをPATHに追加
またはプロジェクト内にベンダーとして組み込むことで、プロジェクトをクローンした誰もが動作するエディタを入手できます。
git clone https://github.com/paveluv/e ~/git/your_project/.e
rm -rf ~/git/your_project/.e/.git # リポジトリの通常のファイルにする
~/git/your_project/.e/e file.txt
すべてのインストールは自己完結型です。ローダーはスクリプト自体の隣にあるlib/のみを厳密に使用し、コンパイルされたオブジェクトはeo/内にローカルに留まり、ソースはそれら(またはそれらがインポートするもの)が変更されると自動的に再コンパイルされます。
ベンダー化されたチェックアウトのlib/にドロップされたプロジェクト固有のモジュールは、そのプロジェクトにローカルに留まります。
ターミナルサイズはioctl経由で検出され、リサイズ時に追跡されます。それが利用できない場合は、LINESとCOLUMNSを設定します。
FreeBSDでは、Chezポートがscheme-scriptインタプリタの名前を変更するため、shebangを#! /usr/bin/env -S chez-scheme --script に変更するか、chez-scheme --script e を実行します(詳細はローダーのヘッダーコメントを参照)。
キーバインディング
ファイルと終了
キー アクション
C-x C-s 保存(名前のないバッファで名前をプロンプト表示)
C-x C-w 名前を付けて保存:パスをプロンプト表示し、バッファがそれを訪問します
C-x C-f ファイルを独自のバッファで訪問(必要なら作成)
C-x C-c 終了(バッファがファイルと異なる場合にのみ質問)
バッファとウィンドウ
キー アクション
C-x b バッファを切り替え(デフォルト:直前の他のバッファ;新しい名前はバッファを作成)
C-x C-b *buffers*を開く:上下で移動、Enterで選択;クリックで即時選択
M-Up アルファベット順で前のバッファに切り替え
M-Down アルファベット順で次のバッファに切り替え
C-x k バッファをキル(デフォルト:カレント;変更されている場合は質問)
C-x 2 現在のウィンドウを2つに分割(スタック)
C-x 3 現在のウィンドウを2つに分割(横並び)
C-x 1 他のすべてのウィンドウを削除
C-x 0 現在のウィンドウを削除
C-x o 次のウィンドウに移動
C-x t このウィンドウで長い行のソフトラップをトグル
各ウィンドウには独自のステータスライン、ポイント、スクロール位置があります。同じバッファを複数のウィンドウに同時に表示できます。
バッファにはバッファごとの履歴とマークがあり、ウィンドウには独立したポイント、スクロール、ラップ、ステータスがあります。
デフォルトでは右側にスクロールバーが表示されます。C-x l はバッファ所有の行番号ガターをトグルします。
バッファの切り替え、*buffers*、ファイル整合性、ターゲットウィンドウ、マウス動作、スクロールバー、ラップ、分割、公開APIについては、Buffersを参照してください。
移動
キー アクション
C-b / C-f / arrows 左 / 右に1文字
C-p / C-n / arrows 上 / 下に1行
C-a / C-e, Home/End 行の先頭 / 末尾
C-v / M-v, PgDn/PgUp ページダウン / アップ
M-< / M-> バッファの先頭 / 末尾
編集
キー アクション
C-d, Delete ポイントの後の文字を削除
Backspace ポイントの前の文字を削除
C-o ポイントをその場に残して下の行を開く
C-k 行末までキル(繰り返しで累積)
C-@ (C-Space) マークを設定
C-w マークとポイントの間の領域をキル
C-y 直前のキルをヤンク
C-_ Undo
C-M-_ Redo
TAB モードのルールに従って行をインデント
M-% ポイントからクエリ置換:y/SPCで置換、n/DELでスキップ、q/RET/C-gで停止
M-. ポイントのシンボルを説明(Schemeバッファ;以下参照)
C-x C-e 現在のバッファをSchemeとして評価
C-l 画面を再描画し、サイズを再読み込み
C-g キャンセル(プロンプト、検索、マーク、実行中の評価)
C-h k キーとそのバインディングの出所を説明
キーカスタマイズ
すべてのキーボードコマンドはconfig.eで再バインドできます。
ユーザーバインディングは組み込みおよびモジュールのデフォルトをオーバーライドし、C-h kはキー、そのソース、およびコンテキスト上の意味を説明します。
(bind-key! "C-c s" save!!)
(unbind-key! "C-v")
キー構文、コンテキストマップ、利用可能なアクション、優先順位、バインド解除、モジュールのデフォルトについては、Key binding configurationを参照してください。
検索
C-s はインクリメンタルサーチを開始します。入力してニードルを拡張し、再度C-sを押すと次のマッチにジャンプします(ラップアラウンド)、Backspaceでニードルを短縮、RET/ESCでサイレントに受け入れ、C-gでキャンセルしてポイントを検索開始位置に戻します。
新しく空の検索で、C-sは前のニードルを呼び出して検索します。ポイントは現在のマッチのすぐ後ろに位置するため、検索前に設定されたマークは、見つかったテキストをリージョン内に残します。
検索中は、現在のウィンドウでのニードルのマッチがハイライトされます。
マッチングはEmacsのようにスマートにケースを無視します。ニードルがすべて小文字の間はケースを無視し、1文字の大文字を入力すると正確になります(プロンプトはI-search (exact):と表示されます)。
M-c は現在の検索をどちらかの方向にトグルし、config.eの(search-fold-case #f)はすべての検索を正確にします。
すべてその他(M-%クエリ置換を含む)は常に正確にマッチします。
インデントとフォーマット
インデントは強制される唯一のものです。行内のスペースは作者のものです(テーブル、アラインメント、手作業のレイアウトが構造を伝えます)。行は結合されたり分割されたりしません。
SchemeのルールはEmacs風です。ボディフォーム(define、lambda、letファミリー、whenなど)は、ボディをオープナーの2列後ろにインデントします。単独のクローザーはオープナーの下に配置され、アプリケーションの継続行には2つの停止位置があります:オープナーの2列後ろ、またはオープナーと同じ行にある最初の引数の下にアラインされた位置です。
作者が選択します。
(very-long-function-name param1 param2 param3)
(very-long-function-name param1 param2 param3)
TAB は現在の行を、その停止位置を循環させながら(右側の最も近い停止位置、ラップアラウンド)、ポイントをインデントに配置します(空行がそれにパディングされます)。モードはインデンターを登録する際にオプトインし、scheme-modeもそうします。
indent-region! および indent-buffer! は、上から順に行ごとに1つのUndoステップとしてインデントし、各行は現在のインデントに最も近い停止位置に落ち着きます。停止位置にある場合はそこに留まり、最初の位置の前にある場合は最初の位置を取り、最後の位置の後ろにある場合は最後の位置を取ります。
format-region! および format-buffer! は、さらに文字列の外側のタブをスペースに広げます((scheme-tab-width 2); #fはタブを保持します)、末尾の空白をトリムし、末尾の空行を削除してファイルが正確に1つの改行で終わるようにし、ブラケットの規則を適用します。letファミリー、do、parameterize、with-syntaxのバインディング、およびcond、case、case-lambda、guard、syntax-rules、syntax-caseの句には[ ]を使用し、それ以外はすべて( )を使用します。scheme-format-bracketsパラメータはそれをオフにします。
リージョンフォーマットは、完全に含むブラケットペアのみを書き換えるため、バッファのバランスを崩すことは決してありません。文字列の内部とマージンコメントは決して触られません。
モジュールは、register-indenter! および register-formatter! を使用して、モードごとにルールを提供します。
Schemeエンジンは純粋な(scheme-format)ライブラリであり、これはtools/scheme-formatも駆動します。シェルからscheme-format [-i] [file ...] で同じ処理を行うか、引数なしで標準入力から標準出力に処理します。(scheme-format-on-save #t)(デフォルトでオン)を使用すると、Schemeバッファのすべての保存時にまずフォーマットされます。