フルスクリーンエディタ FE ver.1.1

松藤秀史
 
 「Full Screen Editor for S-OS“SWORD" FE ver.1.1」(以下FE)は,S-OS“SWORD"環境下て動くスクリーンエディタです。ESCシーケンスを用いたシングルウィンドウのエディタで,すっきりとした簡単なものです。
 

◆使用方法

 FEではスクリーンエディットモードとコマンドモードに分かれています。FEを起動すると,まずスクリーンエディットモードになります。
 そのときにRUN&SUBMITの拡張を行っていれば,起動時に編集したいファイル名を指定することもできます。
例) # FE.OBJ FE.ASM
 

◆機能説明

 現在FEがサポ一トしている機能を説明していきます。
●エディットモード
 実際にテキストの編集を行うモードです。
●コマンドモード
 コマンドモードでは,ファイルの操作,テキストの検索,置換などを行います。スクリーンエディットモードからESC+8でコマンドモードに移り,画面の一番下にコマンドプロンプトが表示されます(使えるコマンドは表1のとおり)。
 
表1 コマンド一覧
コマンド 機能
E[n] コマンドモードを抜け.エディットモードに移る。nを指定するとn行へカーソルを移動してからエディットモードに移る。E0でテキストの最後へカーソルを移動する
Q ファイルを閉じてエディタを終了する
L file 現在編集しているァキストを閉じて,fileをロードする
S [file] 現在編集しているテキストをファイル名fileでセーブする
N [Iile] 現在編集しているテキストを閉じて新規ファイルfileを編集する
F "str" 現在位置から文字列strを検索する
FM 現在位置から以前入力された検索文字列strを検索する
C“strl"“str2" 現在位置から文字列str1をstr2に置換する
B 現在位置まをテキスト先頭とする
●ESC(SHIFT+BREAK)シーケンス
 FEでは,ほかのエディタと同様にESCシーケンスを採用(表2)。そして,このESCキーには2つの役割があります。ひとつは,エディタにコントロールコードを送ることです(ESCモード)。ESCモードでは,カーソル移動に関するコントロールコードが入力され続けるかぎり,モードを継続します。そのほかのコントロールコードが入力された場合は,実行後ESCモードを抜けます。また,ESCモード中にもう一度ESCキーを押すとESCモードを抜けます。そして,もうひとつの機能は,ブロックオペレーションモードです(カット,コピー,ぺースト機能を参照)。
 
表2 コントロールコード一覧
キー 機能番号 機能
→、ESC+D 1 カーソルを右へ移動する
←。ESC+S 2 カーソルを左へ移動する
↑、ESC+E 3 カーソルを上へ移動する
↓、ESC+X 4 カーソルを下へ移動する
ESC+W 5 1ページ上へ移動する
ESC+Z 6 1ページ下へ移動する
ESC+F 11 カーソルをlワード右へ移動する
ESC+A 12 カーソルをlワード左へ移動する
ESC+, 24 カーソルを行の最後へ移動する
ESC+. 23 カーソルを行の先頭へ移動する
ESC+M 15 改行
ESC+I 13 タプ
ESC+O(or R) 9 インサート/デリートモードの切り替え
ESC+H 14 バックスペース
ESC+0 16 フロックデリート
ESC+1 17 ブロックカット
ESC+2 18 ブロックコピー
ESC+3 19 ブロックベースト
ESC+4 20 改行コード表示/非表示
ESC+5 10 タブコード表示/非表示
ESC+6 22 タプ幅4/8文字切り替え
ESC+8 21 コマンドモード
ESC+9 8 エディタ終了
●カット,コピー,ペースト機能
 カット,コピー,ペースト機能は文字単位でサポートしています。これらの機能を利用するには,まず,ESCキーを押します。すると,カーソル位置を示すカラムの上にマーク位置が表示されます(この状態をブロックオペレーションモードといいます)。この状態でカーソルを移動し,カット,コピーする領域を指定します。要するに,ESCキーを押したときのカーソル位置が,カットもしくはコピー機能の先頭位置の指定を兼ねている,ということです。
 なお,テキストを操作するコントロールコードを入力すると,ブロックオペレーションモードを抜けます。
●ファインド,リプレイス機能
 使用法は従来のエディタとほとんど同じですが,タブコードも検索,置換文字に使うことができます。また,セパレータは,ダブルクォーテーション以外の文字であればなんでもかまいません。ファインドモア機能は,いちばん最後に入力された検索文字列を参照して検索を行うものです。
●特殊文字の表示
 FEでは特殊文字(改行コード,タプコード,EOF)を表示する機能がついています。起動時にはすべての特殊文字が表示されていますが,改行コード,タブコードについては,ESC+4,ESC+5で非表示にすることができます。また,コンフィグレーションにより,特殊文字の置き換え文字を変更することができます。
●そのほか
 タプ幅は4文字または8文字に固定されています(ESC+6で切り替え)。また,1行255文字以内に制限されています。255文字を超えて文字を入力しようtすると警告を発しますが,置き換えなどによって255文字を超えてしまった場合は,自動的に改行コードを挿入します。
 

◆ラインプリントルーチン

 このFEは,もともと機種別のラインプリントルーチンを作成することを前提に作られています。そのため,標準のラインプリントルーチンのままでは非常に低速てす。改造する部分は,次の2カ所です。
1) プログラムの1文字表示部分(CALL _PRINT)
2) 表示位置初期化部分(locate_init)
 なお,多色表示が可能な機種については,本体プログラムワークエリア内のchr_atriにキャラクターのカラーコードを格納しているので,特殊文字の色づけが可能となります。
 

◆コンフィグレーション

 FEでは,ワークエリアを直接書き換えることにより,各種設定を変更することができます。
1) テキストの格納アドレス
2) 起動時のタブ幅
3) カーソルが画面横からはみ出したときの画面の移動量
4) タブコードの置き換え文字およびカラーコード
5) 改行コードの置き換え文字およびカラーコード
6) 空白文字
7) そのほかの特殊文字の置き換え文字およびカラーコード
8) EOFの置き換え文字およびカラーコード
9) 新規ファイルのファイル名
10) コントロールコードの割りつけ
 なおタブコードの置き換え文字と改行コードの置き換え文字のカラーコードは同一になります(それぞれのアドレス,詳しい内容は表3)。
 
表3 コンフィグレーション
アドレス 初期値 機能
3003H 4800H テキストの格納アドレス
3005H 8 起勤時のタブ幅
3006H 20 横方向の画面の移動量
3007H "-" タブコードの置き換え文字
3008H “」" 改行コードの置き換え文字
3009H " " 空白文字
300AH “." そのほかのコードの置き換え文字
300BH "[EOF]",26,0,0 ファイル終端コード(00H)の置き換え文字
3013H 3 そのほかのコードのカラーコード
3014H 5 EOFのカラーコード
3015H 6 タブ改行コードのカラーコード
3016H 7 通常文字のカラーコード
3017H “UNTITLED.",0 新規ファイルのファイル名
3029H   コントロールコードのキ一割りつけ
 :    
30XXH    
注)EOFの置き換え文字の最後には必ず26Hを入れてください。キー割りつけの並びは@,A〜Z,という順番になっています。該当するキーのアドレスに機能番号を書き込むようにしてください。
 

◆応用

 FEは基本的な機能しか備えていません。したがって,行削除やカーソル以降の文字列削除,カーソル位置文字削除は,コントロールコードの組み合わせで実現します。
・行削除
 行削除をするためには,まずカーソルを行の先頭に移動します。
I don't have an orange today.
[EOF]
 ここでESCキーを押して,カーソルを下の方へ移動します。
I don't have an orange today.
[EOF]
 そして,ブロックデリート“0"キーを押すと行削除ができます。
・カーソル以降の文字列削除
 削除したい位置にカーソルを移動し,ESCキーを抑します。
I don't have an orange today.
[EOF]
ここで“."を押し,行の最後へ移動します。
I don't have an orange today. 
[EOF]
 そして,ブロックデリート“0"キーを押すと以下のようになります。
I don't have an orange
[EOF]
 同様にしてブロックカットおよびブロックコピーも行えますので,使い慣れてくればかなり重宝するでしょう。
 
〈参考文献〉
1) Oh!X1988年8月号「マルチウィンドウエディ タWINER」
2) Oh!X1990年11月号「タブコード対応エディタEDC-T」
3) MIA X1マシン語プロクラミング入門
 

FEver.1.1ラインプリントルーチン詳細

 FEver.1.1は,ラインプリントルーチンを各機種用に書き換えることで,高速な動作を期待できます。一応,X1/turbo専用のラインプリントルーチンは用意されているのですが,そのほかの機種はまだサポートされていません。そこで,無いものは作ってしまおうということで,FEver.1.1のラインプリントルーチンを制作するために必要な情報を解説します。
 

◆概要説明

 まず,全機種共通ラインプリントルーチン(リスト1)とX1/turbo専用ルーチン(リスト2)を見比ぺてください。ひととおり見るとすぐにわかると思いますが,両リストともに結構似ています。しかし,全機種共通ルーチンでは,
  CALL _PRINT
となっているところが,専用ルーチンでは,なにやらI/Oポートに書き込みを行っている点と,ラベルlocate_init以降の内容が異なっている点です。
 つまり,表示位置設定のサブルーチンであるlocate_initを,各機種専用の画面アドレス計算ルーチンに差し替え,さらにCALL _PRINTの代わりに各機種専用の一文字描画ルーチンを埋め込めば,完成となります(その際には,とりあえずレジスタを全部保存しておくこと)。
 これだけ理解していれば,各機種専用のラインプリントルーチンを制作できるでしょう。
 

◆深く探ってみる

 以上の情報だけでも各機種専用のラインプリントルーチンが制作できますが,それだけでは物足りないので,もうちょっと,ラインプリントルーチン周りの動作原理を探ってみることにします。
 リスト1の全機種共通ラインプリントルーチンを見てください。まず,8〜26行のラベル定義部分の内容を説明しましょう。
  8 _PRINT EQU 1FF4H
  9 _LOC EQU 201EH
 この2行は問題ありませんね。S-OS用の1文字表示ルーチンとカーソル位置設定用のサブルーチンです。
  11 next_chr EQU 3069H
 このルーチンはFE本体にあるサブルーチンで結構重要なものです。とりあえず,名前のとおり次にある文字を取り出すルーチンだと解釈しておきましょう。詳しくは,リスト全体を把握したあとに説明します。
  13 console_x EQU 4591H
  14 console_y EQU 4592H
  15 console_width EQU 4593H
  16 console_length EQU 4594H
 以上はFE内のワークエリアアドレスを定義しています。名前のとおり表示座標関係のものです。上から順番に,現在いるカーソルのX座標,カーソルのY座標,カーソルの動ける範囲(横),そして最後は……解読していません。実際,サブルーチン内で使用されていないものなので,ラインプリントルーチン内では無視してかまわないと判断してしまいました。
  18 line_data_adr EQU 45D2H
  19 line_print_y EQU 45D1H
  20 view_offset EQU 45A9H
  21 tab_info_table EQU 45FCH
 上から順番に,表示する1行分のデータが格納されている先頭アドレス,画面の一番上のY座標(かな?ちょっと自信ないけど),横スクロールのオフセット座標,タブ情報テーブルの先頭アドレスを格納しているアドレスです。
 そして,29行からいよいよプログラムが始まります。30〜33行は説明するまでもありませんね。レジスタの保存を行っているだけです。で,問題なのが次にある1行です。
  34 LD E,(IX)
 解析するときに最後まで困ったのがこのIXレジスタの役割でした。とりあえず,Eレジスタの役割がわかれば問題なしと判断し,IXレジスタは深く追求していません(つまりわからなかったのだ)。次にある,
  35 CALL locate_init
という行は,先ほども説明したとおり,表示すぺきラインのカーソル位置を指定するサブルーチンをコールしています。
  36 LD A,(nm_chr_atri)
  37 LD (chr_atri),A
 通常キャラクタのアトリビュート(色情報)を取り出し,ワークに格納しています。
  38 LD HL,(line_data_adr)
  39 LD IY,tab_info_table
 HLレジスタに表示する1行データが格納されているアドレスをセットし,そして,IYレジスタにタプ情報テーブルの先頭アドレスをセットしています。
 以上がいわゆる初期化部分ですね。
 次にプログラムのメイン部分に移ります。41~47行は,横スクロールのオフセット分だけ,1行データのポインタであるHLレジスタを進めています。そして,49〜57行で実際の表示を行っています。横幅に応じて表示回数を変えているところがポイントです。
 なお,以上のプログラムでは,Dレジスタをカウンタに使用していることがわかれば,簡単に理解できるでしょう。最後は,レジスタ内容を復帰させてリターンしているだけです。
 

◆next_chr

これで全体の構造がだいたいわかりました。あとは,説明を先送りにしていた,next_chrというサブルーチンを理解できれば完璧です。といってもちょっとだけ処理が複雑だったので,いちばん解析に時間がかかってしまいました。
 簡単にいうとnext_chrでは,バッファからキャラクタを取り出し,そして特殊文字の判別とそれに応じたアトリビュートの設定を行っています。
 引数と返り値は,
[引数]
Eレジスタ:通常モード(0),タプモード(1),改行モード(2)の判別フラグ
HLレジスタ:表示しようとしている文字列バッファのポインタ
IYレジスタ:タブ情報テーブルのポインタ
[返り値]
Aレジスタ:表示するキャラクタコード
chr_atri:表示するキャラクタの色情報
以上のようになっています。
 そして,ここでの押さえておきたいポイントは,
1) 通常文字コードの場合は,バッファから文字コードを取り出すだけ
2) タブコードはタブ位置にくるまでスペースを表示し続ける
3) 改行コードを表示したら,そのあとは画面右端までスペースを表示し続ける
4) エンドコード(00H)がきたらエンドコード文字列([EOF])にバッファポインタを移す
以上,4つです。
 それでは,具体的に処理の流れを追いかけてみます。
 まず,1)〜3)の処理の振り分けを行うために参照されるのが,Eレジスタです(振り分けは,105〜107行で行っています)。
・Eレジスタ=0の場合
 まず,文字コードを取り出します(108行)。そしてバッファポインタとタブ情報テーブルポインタを進めます(109〜110行)。取り出した文字コードが,通常キャラクタかコントロールコードかチェックし,通常キャラクタならばサブルーチンからリターンします(111〜112行)。
 次にある113〜120行では,タブ,改行,終端コードの判別とそれぞれの処理へジャンプしていて,それ以外のコントロールコードであればunknown characterとして処理されます(121〜124行)。
 それぞれの処理では,タブ,改行コードであればEレジスタ(フラグ)の内容を書き換え,それぞれに応じたキャラクタをセットしてリターンしています(126〜136行)。終端コードであればバッファアドレスをstr_EOFに変え,アトリビュートを設定してから(138〜141行),さらに文字列を取り出しに108行へジャンプしています。
 このような構造だと終端コードで、永久ループになりそうなものですが(なぜならたいていの文字列終端コードは00Hであるからです),そのへんはぬかりありません。EOFの文字列のエンドコードを1AHと設定することにより,終了チェックを行っています(143〜147行)。ここで,なんでEレジスタに改行コードと同じフラグをセットしているのかがわかれば,完壁です。
・Eレジスタ=1の場合
 まず,107行から149行へジャンプして,さらに154行へジャンプします。154〜156行でタブコード位置まで表示が終わったかチェックし,終わっていなかったらタブ情報テーブルポインタを進めてから,スペースの文字コードを設定してリターン(157〜159行)。タプ位置に到達したら,Eレジスタを通常モードに戻し,さらにアトリビュートを通常文字コードに戻して,さらにバッファから文字コードを取り出すために108行へジャンプしています(161〜164行)。
・Eレジスタ=2の場合
 Eレジスタ=1の場合と同じく,107行から149行へジャンプしています。そのあとは,Aレジスタにスペースの文字コードを設定してリターンしているだけです(151〜152行)。なぜここでEレジスタの初期化やアトリビュートの初期化を行わないか疑問に思うかもしれません。これは,ちょっと考えるとわかると思います。改行コードというものは,文字どおり次の行へ移ることを示す文字コードです。
 つまり,改行コードのあとには絶対に文字列を表示することがないのです。
これで,FEのラインプリントルーチンのだいたいの概要がわかりました。最終的にどのようなルーチンを作ればいいのかまとめてみます。
1) 文字の色情報(アトリビュート)はchr_atriに格納されている
2) 表示すべき文字コードは,next_chrの返り値のAレジスタの内容を使う
3) 表示アドレスは,使用されていないBCレジスタに格納しておく
4) 表示アドレス計算は,画面の桁数に応じて変化させる
 以上のことを守れば,FEのラインプリントルーチンを制作できます。
 とりあえず,全機種共通ルーチンでも使えなくはないですが,やはり専用ルーチンを使用したときの快適さにはかないません。それほどテクニックを必要としないものですので,制作にチャレンジしてみてください。
 
リスト1 全機種共通ラインプリントルーチン
リスト2 X1専用ラインプリントルーチン
1: ;----------------------------------
2: ;
3: ; line_print routine for FE v1.04
4: ; for general
5: ;
6: ;----------------------------------
7:
8: _PRINT EQU 1FF4H
9: _LOC EQU 201EH
10:
11: next_chr EQU 3069H
12:
13: console_x EQU 4591H
14: console_y EQU 4592H
15: console_width EQU 4593H
16: console_length EQU 4594H
17:
18: line_data_adr EQU 45D2H
19: line_print_y EQU 45D1H
20: view_offset EQU 45A9H
21: tab_info_table EQU 45FCH
22:
23: nm_chr_atri EQU 3016H
24: chr_atri EQU 45D4H
25:
26: OFFSET 0C000H-4400H
27: ORG 4400H
28:
29: line_print:
30: PUSH BC
31: PUSH DE
32: PUSH HL
33: PUSH IY
34: LD E,(IX)
35: CALL locate_init
36: LD A,(nm_chr_atri)
37: LD (chr_atri),A
38: LD HL,(line_data_adr)
39: LD IY,tab_info_table
40: ;
41: LD A,(view_offset)
42: LD D,A
43: INC D
44: lp1: DEC D
45: JP Z,lp2
46: CALL next_chr
47: JP lp1
48: ;
49: lp2: LD A,(console_width)
50: LD D,A
51: DEC D
52: lp3: CALL next_chr
53: ;
54: CALL _PRINT
55: ;
56: DEC D
57: JP NZ,lp3
58: POP IY
59: POP HL
60: POP DE
61: POP BC
62: RET
63:
64: locate_init:
65: LD A,(line_print_y)
66: LD H,A
67: LD A,(console_y)
68: ADD A,H
69: LD A,(console x)
70: LD L,A
71: ;
72: CALL _LOC
73: RET
1: ;----------------------------------
2: ;
3: ; line_print routine for FE v1.05
4: ; for X1/X1turbo non Kanji
5: ;
6: ;----------------------------------
7:
8: _WIDTH EQU 1F5CH
9:
10: next_chr EQU 3069H
11:
12: console_x EQU 4591H
13: console_y EQU 4592H
14: console_width EQU 4593H
15: console_length EQU 4594H
16:
17: line_data_adr EQU 45D2H
18: line_print_y EQU 45D1H
19: view_offset EQU 45A9H
20: tab_info_table EQU 45FCH
21:
22: nm_chr_atri EQU 3016H
23: chr_atri EQU 45D4H
24:
25: OFFSET 0C000H-4400H
26: ORG 4400H
27:
28: line_print:
29: PUSH BC
30: PUSH DE
31: PUSH HL
32: PUSH IY
33: LD E,(IX)
34: CALL locate_init
35: LD A,(nm_chr_atri)
36: LD (chr_atri),A
37: LD HL,(line_data_adr)
38: LD IY,tab_info_table
39: ;
40: LD A,(view_offset)
41: LD D,A
42: INC D
43: lp1: DEC D
44: JP Z,lp2
45: CALL next_chr
46: JP lp1
47: ;
48: lp2: LD A,(console_width)
49: LD D,A
50: DEC D
51: lp3: CALL next_chr
52: ;
53: OUT (C),A
54: RES 4,B
55: LD A,(chr_atri)
56: OUT (C),A
57: SET 4,B
58: SET 3,B
59: XOR A
60: OUT (C),A
61: RES 3,B
62: INC BC
63: ;
64: DEC D
65: JP NZ,lp3
66: POP IY
67: POP HL
68: POP DE
69: POP BC
70: RET
71:
72: locate_init:
73: LD A,(line_print_y)
74: LD H,A
75: LD A,(console_y)
76: ADD A,H
77: LD A,(console_x)
78: LD L,A
79: ;
80: LD C,L
81: LD A,H
82: ADD A,A
83: ADD A,A
84: ADD A,H
85: LD H,0
86: LD L,A
87: ADD HL,HL
88: ADD HL,HL
89: ADD HL,HL
90: LD A,(_WIDTH)
91: CP 80
92: JR NZ,loc_i1
93: ADD HL,HL
94: loc_i1: LD B,30H
95: ADD HL,BC
96: LD B,H
97: LD C,L
98: RET
 
リスト3 next_chr
100: ;----------------------------
101: ; Subroutine for line_print
102:
103:
104: next_chr:
105: LD A,E
106: OR A
107: JP NZ,nxt_c1
108: nxt_c4: LD A,(HL)
109: INC HL
110: INC IY
111: CP 32
112: RET NC
113: CP __TAB
114: JP Z,nxt_c5
115: CP __CR
116: JP Z,nxt_c6
117: OR A
118: JP Z,nxt_c7
119: CP __EOF
120: JP Z,nxt_c8
121: LD A,(un_chr_atri)
122: LD (chr_atri),A
123: LD A,(chr_OTHER)
124: RET
125: ;
126: nxt_c5: LD E,1
127: LD A,(sp_chr_atri)
128: LD (chr_atri),A
129: LD A,(chr_TAB)
130: RET
131: ;
132: nxt_c6: LD E,2
133: LD A,(sp_chr_atri)
134: LD (chr_atri),A
135: LD A,(chr_CR)
136: RET
137: ;
138: nxt_c7: LD HL,str_EOF
139: LD A,(EOF_str_atri)
140: LD (chr_atri),A
141: JP nxt_c4
142: ;
143: nxt_c8: LD E,2
144: LD A,(nm_chr_atri)
145: LD (chr_atri),A
146: LD A,(chr_SPACE)
147: RET
148: ;
149: nxt_cl: CP 1
150: JP Z,nxt_c2
151: LD A,(chr_SPACE)
152: RET
153: ;
154: nxt_c2: LD A,(IY)
155: OR A
156: JP NZ,nxt_c3
157: INC IY
158: LD A, (chr_SPACE)
159: RET
160: ;
161: nxt_c3: LD E,0
162: LD A,(nm_chr_atri)
163: LD (chr_atri),A
164: JP nxt_c4
165:
166:
 
(C)1995 Hideshi Matsuhuji(original)
(C)1997 Junji Okazaki(edited)
(C)2024 Oh!Ishi,Nibbles Lab.(formatted)