TECO編集者:EMACS、私はあなたの父親です

私の生まれた少し前に書かれたパロディの記事「 Real Programmers Do n't Use Pascal」で初めてTECOについて読みました。 そこには、本物のプログラマーは、新しいエディターEMACSおよびVIを使用しないと書かれています。







いいえ、本物のプログラマーは「尋ねた? だからそれを手に入れてください!」-複雑で、神秘的で、強力で、寛容ではなく、危険です。 TECO、正確には。

オリジナル
いいえ、本物のプログラマは「あなたがそれを求め、あなたがそれを手に入れた」テキストエディタを望んでいます-複雑で、不可解で、強力で、容赦なく、危険です。 TECO、正確には。



興味をそそられました。 これはどんな動物ですか、触ることができますか? ウィキペディアによると、TECOはT ext Editor& CO rrectorであり、1962年にDECで作成され、PDPファミリコンピュータで使用され、後にOpenVMSシステムで使用されました。 Cにはポートがあり、最新の状態の愛好家によって維持されており、最新のオペレーティングシステムの下で組み立てられています。 それで、少なくとも少しは本物のプログラマのように感じることにしました。









Linuxでのコンパイルは問題を引き起こしませんでした(libncurses-devをインストールするだけです)。 そして、 tecoc



を実行すると、強力なエディターインターフェイスが表示されます。







 *
      
      





はい、1つ星です。 これは、コマンドを入力するための招待状です。 指示なしではできないようです。 幸いなことに、このマニュアルはインターネットで簡単に見つけることができます。 これは、VAX、PDP-11、PDP-10、およびPDP-8の標準TECOテキストエディターおよびコレクターと呼ばれる300ページ近くの本です。 ここでは、1990年の最新バージョンをPDFで読むことができます。当時、TECOはほとんど忘れられていました。







まず、この奇跡から抜け出す方法を考え出す価値があります。 EX



と入力してからEscapeを2回押す必要があることがわかりました。 一般的に、エスケープをダブルクリックすると、入力したコマンドが実行されます。 Enterキーは、単に改行として使用されます。 エスケープは画面にドルとして表示されますが、ドルを入力してもエスケープ効果は得られません。 ただし、さらに$



を記述すると、Escapeキーを押す必要があることを意味します。 したがって、 EX$$



終了します(ファイルは保存されます)。 素晴らしい、入場と退場を学んだ-仕事の半分が完了した。







一般に、TECOコマンド形式は次のようなものです。







 [[<1>,] <2>] [:] <> [<1> [ $ <2> ] $ ]
      
      





議論が左と右の両方に行くことができるのはかなり珍しいです。 ただし、別の方法で取得することをお勧めします。左側の数字はチームの一部ではなく、結果として数字(または数字のペア)を返す別のチームです。 この場合、後続のコマンドは前のコマンドの結果を使用できます。







エスケープは不便です。コピーして貼り付けると、ドルとなるだけで、区切りとして認識されないためです。 幸いなことに、テキスト引数を持つコマンドには代替構文があります: @ <> <> <> <>



、ここでセパレータは任意の文字です。 たとえば、 IHabr$



を使用して現在のカーソル位置に「Habr」というテキストを挿入できます(I、テキスト、エスケープ-似ていない?)、 IHabr$



@I/Habr/



使用できます。 人生を簡素化するために、2番目の構文に切り替えました。







素晴らしい。 ファイルにテキストを入力する方法を学ぶといいでしょう。 出力ファイルを指定するには、 EW



コマンドと入力ファイル、 ER



コマンドを使用します。 良い意味で、それらは一致しないはずです。 当時、 <FF>



記号またはフォームフィードを使用したページネーション付きのテキストファイルの複数ページ表示が一般的でした。 これは、Ctrl + Lを介して入力されたコード12(0xC)の文字です(Lは英語のアルファベットの12番目の文字です)。 これにより、ページを吐き出して新しいページを開始するようにプリンターに指示するだけでなく、適度な量のRAMで長いファイルを編集することも可能になりました。 TECOは、入力ファイルの1ページ( <FF>



文字まで)のみをメモリにロードし、編集して出力ファイルに書き込み、次のページに移動できるようにします。 ページを接着および分割する操作もあります。 ファイルが同じである場合、良いものは何もないことは明らかです。 まあ、私たちはページで遊ぶつもりはありません、最近は絶対にワイルドです。 ファイルは単一ページになります。 したがって、ファイルを最初から作成します。







 *@EW/habr.txt/$$ *@I/Hello, Habrahabr! This is TECO, the most powerful editor in the world. Stop using your fancy IDEs, TECO for the win! Bye. /$$ *EX$$
      
      





これは機能し、 habr.txt



ファイルはテキストとともに実際に表示されました。 各コマンドを2つのEscapeで完了しましたが、実際にはこれは必要ありません。 さて、しかし既存のファイルをどのように編集できますか? 毎回新しい名前を発明することに消極的。 これを行うには、最初の記録で入力ファイルの名前を*.bak



に変更する特別なEB



コマンドがあります。したがって、入力ファイルと出力ファイルが異なることが*.bak



ます。 ファイルを開いた後、最初のページ(コマンドY



)に切り替えることを忘れないでくださいHT



コマンドを使用すると、ファイルの内容全体を表示できます。







 *@EB/habr.txt/YHT$$ Hello, Habrahabr! This is TECO, the most powerful editor in the world. Stop using your fancy IDEs, TECO for the win! Bye. *
      
      





厳密に言えば、 HT



は2つのチームです。 H



コマンドは、数値のペア-0とテキストバッファーの長さ、つまり現在メモ​​リにあるページを返します。 また、 T



コマンドは、指定されたオフセット範囲でファイルのフラグメントを出力します。







 *0,5T$$ Hello*7,17T$$ Habrahabr!*
      
      





はい、誰もラインフィードを再度追加しません。5文字を要求しました。 しかし、すべてが明確です。 T



コマンドに1つの数値のみが渡された場合、それは印刷される行数として解釈され、カーソル位置から前後にカウントされます。 さらに、カーソルが行の中央にある場合、 0T



は現在の行の先頭からカーソルにフラグメントを印刷し、パラメータなしのT



カーソルから行の末尾までを印刷します。







 *5J$$ *0T$$ Hello*T$$ , Habrahabr! *
      
      





上で使用したJ



コマンドは、指定された絶対オフセットにカーソルを移動します(カーソルは常に文字の間にあります)。 見た目がいので、このカーソルを見たいです。 0T



T



間にスティックを印刷することはできますか? はい、できます。 印刷コマンドは^A



(Ctrl + Aを入力するか、直接チェックして文字Aを順番に入力できます)。







 *0T@^A/|/T$$ Hello|, Habrahabr! *
      
      





これで、カーソルの位置を確認できます。 このコマンドを記録し、必要に応じて実行するとよいでしょう。 コマンドを実行した後にすぐに*



、次に文字または数字を入力すると、前のコマンドのテキストが対応するQレジスタに書き込まれます(なぜそれが単なるレジスタではなくQレジスタであるかはまだわかりません)。 たとえば、 *Z



レジスタZ



の内容は、 MZ



コマンドを使用してコマンドとして実行できます。







 *MZ$$ Hello|, Habrahabr! *
      
      





さて、最初のTECOマクロを記録しました。 まあ、ポジションを駆け抜けるのは退屈です。何かを探すことができたらいいですね。 たとえば、IDEという単語を探しましょう。 ヘルプには、このためのS



コマンドがあります。







 *@S/IDE/$$ *
      
      





それで何? 何も裏切りませんでした 見つかりましたか? そして、見つかった場合、どこに? はい、インタラクティブエディタは破損しています。 何もしなかったら、見つけました。 TECOは、見つかったテキストの後にカーソルを移動しました。 繰り返して、すぐにカーソルで線を引きましょう:







 *@S/IDE/MZ$$ ?SRH Search failure "IDE"
      
      





ああ、そして今何? ええ、彼は現在のカーソル位置から何かを探していますが、2番目のIDEはありませんでした。 最初にファイルの先頭に移動する必要があります( J



だけでできます)。







 *J@S/IDE/MZ$$ Stop using your fancy IDE|s, TECO for the win!
      
      





で、美。 両側にあるテキストを強調表示するのはどうですか? それから私はほとんどドキュメントを調べなければなりませんでした。 そのようなことが便利になりました:









したがって、 ^SC



を使用すると、見つかった行の先頭に移動できます。その後、使い慣れた0T



プレフィックスを出力し、 [



ます。 次に、位置からフラグメントを印刷する必要があります.



to .-^S



^S



は負の数であることを思い出してください)。 次に]



と入力し、カーソルを-^SC



で元の位置に戻し、 T



行の残りを印刷しますT



プログラム全体は次のとおりです。







 *^SC0T@^A/[/.,.-^ST@^A/]/-^SCT$$ Stop using your fancy [IDE]s, TECO for the win! *
      
      





素晴らしい、私たちはすでにパールをやっています。 実際のプログラマーに関する記事から次の引用をする時が来ました:







TECOコマンドシーケンスは、読み取り可能なテキストというよりもノイズ伝送に似ていることに注意してください。 楽しいのは、チームとしてTECOに名前を入力し、何が起こるかを推測することです。 TECOと話をするときのほとんどのタイプミスは、プログラムを破壊したり、さらに悪いことに、かつて働いていた手順にとらえどころのない不思議なバグを導入したりする可能性があります。

オリジナル
TECOコマンドシーケンスは、読み取り可能なテキストよりも伝送ラインノイズに似ていることが確認されています。 TECOでプレイするより面白いゲームの1つは、コマンドラインとして名前を入力し、その動作を推測することです。 TECOとの会話中に発生する可能性のある入力エラーは、おそらくプログラムを破壊するか、さらに悪いことに、一度動作するサブルーチンに微妙で神秘的なバグを導入します。



ところで、TECOの正規表現の類似性も利用できます。 たとえば、 [AZ]\d+



の類似物は^EW^EM^ED



です。 正規表現が気に入らない場合は、TECOで少し働いてください 。 その後、あなたは愛するでしょう。







今、私はいくつかの制御構造が欲しいです。 この問題を考えてみましょう:カーソルが行の先頭にあると仮定して、美しいフレームで行のテキストを取得します。 ちなみに、行を下に移動します-コマンドL



、上に-L



です。 Ctrl + HおよびCtrl + Jを押して、 -LT



およびLT



コマンドをすばやく実行し、テキストを前後に実行することもできます。







このタスクでは、現在の行にある文字と同じ数のマイナス記号を挿入する必要があります。 それを測定するには? あなたは呼び出すことができます.



L



前後に2回、差を計算します。 Qレジスタでの数字の書き込みと読み取りは便利です(数字とテキストは同じ名前でQレジスタに個別に保存されます)。 UA



はレジスタA



に数値を書き込み、 QA



それを読み取ります。 n回の繰り返しでの単純なループはn<...>



です。 たとえば、マイナス記号をA



回挿入する場合は、 QA<@I/-/>



と記述します。 マクロ全体は次のようになります。







 .UAL.-QA-2UA-L@I/+/QA<@I/-/>@I/+ |/L2R@I/| +/QA<@I/-/>@I/+ /-LC
      
      





おそらく、このマクロで最もわかりにくいのは-2です。 そして2R



。 すべてが非常に単純です。当時のラインフィードは常に2文字'\r\n'



占めていました。 意見の相違はなく、素晴らしかった。 行の先頭の座標の差からそれを減算する必要があり、右のフレームを描画するには、2文字左に移動する必要があります。







このマクロを保存して、 Y



を登録しますY



ちなみに、これはコマンド実行後の*Y



だけでなく、 ^U



コマンドを使用して文字列をレジスタに書き込むことができます: @^UY/ /



。 バッファーの先頭にあるそれを実行してみましょう。







 *MY$$ *HT$$ +-----------------+ |Hello, Habrahabr!| +-----------------+ This is TECO, the most powerful editor in the world. Stop using your fancy IDEs, TECO for the win! Bye. *
      
      





いいね! 変数、ループ-これはすでに実際のプログラミングのようです。 シニアTECO開発者の地位についてのインタビューに行くことができます。 インタビューといえば。 TECOでFizzBu​​zzマクロを書きましょう。 私の前に誰かがこれをしたかどうかはわかりません。







ここで、15による剰余による除算は有用ですが、残念なことに、剰余による除算の操作は役に立ちません。 しかし、除算は完全に存在するため、 xx/15*15



で表現できます。 確かに、操作の優先順位も存在しないため、 -x/15*15+x



と記述する必要があります。 次に、残りに応じて、異なることを行う必要があります。 余りが0の場合、 FizzBuzz



または12の場合はFizzBuzz



、5または10の場合はFizz



、それ以外の場合は入力番号を印刷します。 O



コマンドはこれに役立ちます。 数値引数がない場合、これは無条件ジャンプ(つまりGOTO)であり、数値引数がある場合はスイッチのようなものですnO



は、n番目のマークにジャンプします(カンマがある場合)。 タグは次のように見えます!!



(コメントも書かれています-これは、誰も飛び乗っていないラベルです)。 タグを作成する!f!



(フィズ用)、! !b!



(バズ用)および!fb!



(FizzBu​​zz用)および!e!



-飛び出しの終わり、 break



。 QレジスタF



に書き込むコマンドを含むマクロ全体を次に示します。







 *^UF UA-QA/15*15+QA@O/fb,,,f,,b,f,,,f,b,,f/QA=@O/e/!fb!@^A/Fizz/!b!@^A/Buzz /@O/e/!f!@^A/Fizz /!e!$$
      
      





^A



コマンドに改行を渡して表示することに注意してください。 Javaにはまだ複数行リテラルがありませんが、TECOにはすでに半世紀以上前のものがあります。 また、 !fb!



Fbブランチの後に「フォールスルー」を実行して、少し節約しました!fb!



2つの半分からFizzBu​​zzと入力します。 通常のswitch-caseステートメントのように。







興味深いことに、マクロはUA



始まりますA



レジスタA



数値を書き込みますA



そして何番? 非常にシンプル-このマクロの引数。 呼び出しの直前に指定する必要があります。 私たちはチェックします:







 *4MF$$ 4 *5MF$$ Buzz *105MF$$ FizzBuzz *87MF$$ Fizz *44MF$$ 44 *
      
      





素晴らしい、インタビューを受けました! この記事のKDPVを作成するには、最後の実験が必要でした。 必要な文字を表示するプログラムを書く方法は? この言語には配列とデータ構造がないようです。 しかし、テキストバッファがあります! ここで、文字ジェネレーターを<>< ><>< >...



という形式で駆動しました( HK



コマンドはバッファーの現在の内容をクリアします):







 *HK@I/H130H130H124H130H130A62A66A254A130A130B254B128B252B130B252R252R130R252R128R128R/$$
      
      





J< >@S/<>/



を使用して、目的の番号に自分自身を配置できます。これは、数値パラメーターSを使用すると、指定した文字列のn番目の出現を検索できるためです。 任意のテキストパラメーターでパラメーター化されたコマンドを実行する方法が見つからなかったため、QレジスタDでコマンドを作成し( :^UD



は末尾に追加しますが、単に^UD



はQレジスタ内のテキストを置き換えます)、マクロとして実行しました。 その後、バックスラッシュ\



コマンドを使用して数値を解析できます。 条件演算子も必要です。 "N<>'



-数値引数がゼロでない場合に実行し、 "E<>'



-数値引数がゼロの場合に実行します。 「別の方法で」ブランチは、パイプで分離することによって作成することもできます。 したがって、スペースまたはラティスの出力は"E32^T|35^T'



で行われます。 ^T



は対応するASCIIコードで文字を出力します。別の便利なコマンドは%<>



で、対応するQレジスタの数値を1つ増やします。







私はこのようなレジスタを使用しました(混乱しないように、それぞれが数字または文字列にのみ使用されました):









 @^UC/HABRAHABR/1UF!bl!0UE!bm!J@^UD/@S|/QEQC:^UD@:^UD/|/QFMD$ \UAC128UB!br!QB&QA"E32^T|35^T'QB/2UBQB"N@O/br/'%E^[QE-:QC"N@O/bm/'@^A/ /%F^[QF-6"N@O/bl/'$$
      
      





多くのマクロはTECOで記述されており、非常に複雑なものです。 もちろん、少なくとも何かを理解するためには、マクロを構造化し、改行、インデント、コメントを挿入するとよいでしょう。 ただし、これによりマクロ処理が大幅に遅くなることがわかります。 したがって、彼らはミニマイザーを思いついた。 ミニファイの前のミニマイザーのコードを次に示します 。 JavaScriptの世界で今日見られているのと似たようなもの。







興味深いことに、キーボードから文字を読み取るためのコマンドがあるため、マクロをインタラクティブにすることができます。 エスケープシーケンスを介した端末出力の機能を使用すると、画面上にカーソルを簡単に配置し、フラグメントを使用してテキストを更新し、色を切り替えることができます。 したがって、マクロを使用して、各入力文字または特殊キーを処理し、インタラクティブな編集モードを作成できます。 これが、元々はTECOのマクロだったEmacsの誕生方法であり、その後、別のアプリケーションとして書き直されました。








All Articles