またもや少し時間が空いてしまいました。どこまで実装が進んだのか忘れてしまっていたのですがいよいよエディターの根本的な部分、編集機能を作り込んでいきたいと思います。
先を見越して編集用バッファであるBinDataには既にupdate()が実装されており、値の入力があれば上書きできるようにしてあります。
つまり、キーボードからの入力受取 -> 16進数に変換 -> BinDataのupdate()で上書き、という流れで上書きができそうです。
キーボードからの入力受取
数値の入力を受け付けるために、数値キーのイベントを処理できるようにEventHandlerをアップデートします。
// 数値データ入力
KeyCode::Char(char_code @ ('0'..='9' | 'a'..='f' | 'A'..='F')) => {
self.input_buf.add(char_code);
let res = self.input_buf.to_hex();
if let Ok(val) = res.into() {
let index = message.cursor().index();
message.bin_data_mut().update(index, val);
message.cursor_mut().input_buf_x(self.input_buf.index());
}
}
ここので見慣れないのはchar_code @ ('0'..='9' | 'a'..='f' | 'A'..='F')
の部分でしょうか。
これは@束縛という書き方でマッチガードと変数への束縛を組み合わせたような書き方です。これで16進数に使う00-FFの入力を受けた時に編集処理に進むようにしています。
入力は2桁になる可能性があるので入力用のミニバッファinput_bufへ一旦値を追加します。
なにも入力がなくてaddされた場合は最初の入力となり、2桁目の値として扱われます。既にaddが実行されていて2桁目の値がある場合に再びaddされた場合は1桁目の値として扱われます。
このようなちょっと複雑な処理になるのでInputBufとして新しい構造体とメソッドを実装しています。
// 入力用ミニバッファ
#[derive(Debug)]
struct InputBuf {
buf: [char; 2],
index: usize,
}
use std::num::ParseIntError;
impl InputBuf {
fn new() -> Self {
// let mut buf : [char; 2] = Default::default();
let mut buf: [char; 2] = ['0'; 2];
let mut index = 0;
Self { buf, index }
}
// バッファにキーボードからの入力を入れる
fn add(&mut self, value: char) {
self.buf[self.index] = value;
self.index = (self.index + 1) % 2;
}
// バッファの内容を16進数へ変換
fn to_hex(&self) -> Result<u8, ParseIntError> {
let str: String = self.buf.iter().collect();
let res = u8::from_str_radix(&str, 16);
// if let Ok(str) = &res {
// dbg!(format!("{:X}", str));
// }
res
}
// バッファに値をセット
fn set_value(&mut self, value: u8) {
// 16進数へ変換
let mut str = format!("{:02X}", value);
self.index = 0;
for x in str.chars() {
self.add(x);
}
self.index = 0;
}
fn index(&self) -> usize {
self.index
}
}
16進数に変換
charの配列を一旦Stringに変換して、Stringからu8へu8::from_str_radix()
を使うことで16進数へ変換しています。その部分はto_hex()になります。
set_value()は逆の処理でu8からcharの配列に変換しています。ちょっとネーミングが悪いですね。self.index = 0も2回目はいらないでしょう。
indexは2桁目と1桁目のどちらのポジションになるのか管理するためのものです。表示カーソルの位置決めにも使用しています。
BinDataのupdate()で上書き
to_hex()で変換した結果、成功なら上書きを実行するようにします。
つまり、if let Ok(val) = res.into()にマッチした場合に上書きを実行します。
res.into()のinto()が意味不明なので後で修正しておきます。
CursorPositionにinput_buf_x()を新たに追加しています。先程のindexによりカーソルの位置をずらすためのものになります。
// 数値データ入力
KeyCode::Char(char_code @ ('0'..='9' | 'a'..='f' | 'A'..='F')) => {
self.input_buf.add(char_code);
let res = self.input_buf.to_hex();
if let Ok(val) = res.into() {
let index = message.cursor().index();
message.bin_data_mut().update(index, val);
message.cursor_mut().input_buf_x(self.input_buf.index());
}
}
TOC
- 準備
- ターミナル入出力を試す
- ターミナル系crateを利用する
- 編集データと表示処理
- 画面制御
- その他
GitHubにコードをアップロードしています。
コードのコメントに書かれているfirst_stepなどをcargoコマンドに渡すと実行できます。
# Example
$ cargo run --example first_step