上書き、とくれば挿入も必要でしょう。挿入機能を追加しましょう。
現状は上書きのみを想定していたので、上書きと挿入を切り替えるようにする必要があります。
つまり、書き込みモードの管理と表示を実装していきます。
書き込みモードの管理
上書きと挿入の2パターンしかありませんが、これをコードとして表現するならば列挙型が便利でしょう。
enum WriteMode を下記のように定義してみました。
// 書き込みモード
pub(crate) enum WriteMode {
OverWrite,
Insert,
}
// 状態管理
pub(crate) struct Message {
bin_data: BinData,
cursor: CursorPosition,
scroll: Scroll,
write_mode: WriteMode,
layout: [Rc<[Rect]>; 4], // main_layout, sub_layout, inner_main, inner_sub
}
関係ないですがMessage という名前を使っていますが状態管理をしているのでStateとか名前を変えたほうがいい気がしています。後ほどの検討項目としたいと思います。
書き込みモードの切り替え
// 書き込みモード変更
KeyCode::Char('i') => {
message.toggle_mode();
}
// 数値データ入力
KeyCode::Char(char_code @ ('0'..='9' | 'a'..='f' | 'A'..='F')) => {
// 入力データをミニバッファへ書き込み
self.input_buf.add(char_code);
// 16進数へ変換が成功なら
let res = self.input_buf.to_hex();
if let Ok(val) = res {
use crate::message::WriteMode::*;
let index = message.cursor().index();
match message.write_mode() {
OverWrite => {
message.bin_data_mut().update(index, val);
}
Insert => {
// 最初の桁に入力あり
if self.input_buf.index() != 0 {
// 下の桁を0にしたい
self.input_buf.set_value(0);
self.input_buf.add(char_code);
let res = self.input_buf.to_hex();
if let Ok(val) = res {
message.bin_data_mut().insert(index, val);
}
}
// 最後の桁に入力あり
if self.input_buf.index() == 0 {
message.bin_data_mut().update(index, val);
}
}
}
}
}
// 書き込みモード変更
pub(crate) fn toggle_mode(&mut self) -> &WriteMode {
use WriteMode::*;
let mode = &self.write_mode;
self.write_mode = match mode {
OverWrite => Insert,
Insert => OverWrite,
};
&self.write_mode
}
新しくKeyCode::Char('i')
を追加して書き込みモードの切り替えキーとしました。
また、KeyCode::Char(char_code)の中の処理を書き込みモード別に処理するように変更しています。
挿入処理はちょっと複雑で、最初の桁(つまり2桁目)の入力があった場合は新しい値の挿入が行われます。ミニバッファは古い値が残っているので0でリセットしてから改めて値を追加して編集バッファにinsertしています。
最後の桁(つまり1桁目)の入力の場合は既に挿入が終わっているのでupdateの処理に切り替えています。
今見返してみると、if self.input_buf.index() != 0の条件式が良くないですね。コメントと合っていないです。if self.input_buf.index() – 1 == 0というような条件が良さそうです。
書き込みモードの表示
let mode = {
use crate::message::WriteMode::*;
match message.write_mode() {
OverWrite => " OVR ",
Insert => " INT ",
}
};
let status_bar_left = Line::from(vec![" Mode:".into(), mode.green().bold()]).left_aligned();
let status_bar_mid = Line::from("").centered();
let status_bar_right =
Line::from(vec![" Quit ".into(), "<Ctrl+Q> ".blue().bold()]).right_aligned();
// パネルブロック
let block = Block::default()
.title(title)
.title_bottom(status_bar_left)
.title_bottom(status_bar_mid)
.title_bottom(status_bar_right)
書き込みモードをステータスバーに反映させるように表示処理もアップデートします。
モードによってOVR、INTを表示するように処理を変更しています。
表示ポジションによってstatus_bar_left 、status_bar_mid 、status_bar_right を分けました。status_bar_mid は使っていませんが将来の予約的な位置付けとしておきます。
TOC
- 準備
- ターミナル入出力を試す
- ターミナル系crateを利用する
- 編集データと表示処理
- 画面制御
- 編集データへの入出力
- その他
GitHubにコードをアップロードしています。
コードのコメントに書かれているfirst_stepなどをcargoコマンドに渡すと実行できます。
# Example
$ cargo run --example first_step