3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

hhattoのひとりアドベントカレンダーAdvent Calendar 2021

Day 8

Rustでlessクローンを作りたい その2

Posted at

昨日の続きをやります。

Ctrl-uまたはCtrl-dでカーソルジャンプ

10行くらい一気に上下に移動したいです。
Ctrl-uで上に、Ctrl-dで下に、それぞれ10行ジャンプさせます。

crosstermではキーイベント取った際のmodifiersでCtrlやAltキーを判別して処理分岐させれるのでそれを使います。
以下のような感じです。

diff --git a/1207_less_clone/src/main.rs b/1207_less_clone/src/main.rs
index c32e219..7813975 100644
--- a/1207_less_clone/src/main.rs
+++ b/1207_less_clone/src/main.rs
@@ -4,7 +4,7 @@ use std::fs::File;
 use clap::{Parser};
 use crossterm::{
     cursor::{DisableBlinking, MoveTo, MoveUp, MoveDown, MoveLeft, MoveRight, RestorePosition, SavePosition},
-    event::{read, Event, KeyCode, KeyEvent},
+    event::{read, Event, KeyCode, KeyEvent, KeyModifiers},
     execute,
     style::Print,
     terminal,
@@ -68,6 +68,14 @@ fn less_loop(filename: &str) -> Result<()> {
                     code: KeyCode::Char('l'),
                     modifiers: _,
                 }) => execute!(stdout(), MoveRight(1))?,
+                Event::Key(KeyEvent {
+                    code: KeyCode::Char('u'),
+                    modifiers: KeyModifiers::CONTROL,
+                }) => execute!(stdout(), MoveUp(10))?,
+                Event::Key(KeyEvent {
+                    code: KeyCode::Char('d'),
+                    modifiers: KeyModifiers::CONTROL,
+                }) => execute!(stdout(), MoveDown(10))?,
                 Event::Key(KeyEvent {
                     code: KeyCode::Char('/'),
                     modifiers: _,

カーソル移動とともにスクロール表示

jkで上下に移動できるので、ターミナルの上端でkキーで上行こうとしたらスクロールしつつ前の行を表示。
逆にターミナル下端でjキーで下行こうとしたらスクロールしつつ次の行を表示。
という感じにしたい。

表示してる行数の上端と下端を管理する構造体を作った。

struct DisplayLines {
    start: u16,
    end: u16,
}

impl DisplayLines {
    fn start_mut(&mut self) -> &mut u16 {
        &mut self.start
    }
    fn end_mut(&mut self) -> &mut u16 {
        &mut self.end
    }
}

初期ファイル読み込み時に合わせて初期化しておく。

 fn less_loop(filename: &str) -> Result<()> {
     let f = File::open(filename)?;
     let lines = ropey::Rope::from_reader(f)?;
     let line_count = lines.len_lines();
     let mut is_search_mode = false;

-    let (_, rows) = terminal::size()?;
+    let (_, window_rows) = terminal::size()?;
+    let mut display_lines = DisplayLines { start: 0, end: 0 };

-    for idx in 0..rows {
+    for idx in 0..window_rows {
         println!("{}", lines.line(idx as usize));
         execute!(stdout(), MoveTo(0, idx as u16))?;
         if idx as usize >= line_count - 1 {
             break
         }
+        *display_lines.end_mut() = idx;
     }
     execute!(stdout(), MoveTo(0, 0))?;

で、スクロールと表示を実装。素直にというか思ったまんまにとりあえず実装。

@@ -50,7 +66,9 @@ fn less_loop(filename: &str) -> Result<()> {
                 _ => (),
             };
         } else {
+            let (_, row) = position()?;
             execute!(stdout(), SavePosition)?;
+
             match event {
                 Event::Key(KeyEvent {
                     code: KeyCode::Char('h'),
@@ -59,11 +77,29 @@ fn less_loop(filename: &str) -> Result<()> {
                 Event::Key(KeyEvent {
                     code: KeyCode::Char('j'),
                     modifiers: _,
-                }) => execute!(stdout(), MoveDown(1))?,
+                }) => {
+                    if window_rows-3 == row {
+                        *display_lines.start_mut() = display_lines.start + 1;
+                        *display_lines.end_mut() = display_lines.end + 1;
+                        let l = lines.line(display_lines.end.into());
+                        execute!(stdout(), ScrollUp(1), Print(l), RestorePosition)?;
+                    } else {
+                        execute!(stdout(), MoveDown(1))?;
+                    }
+                },
                 Event::Key(KeyEvent {
                     code: KeyCode::Char('k'),
                     modifiers: _,
-                }) => execute!(stdout(), MoveUp(1))?,
+                }) => {
+                    if 0 == row {
+                        *display_lines.start_mut() = display_lines.start - 1;
+                        *display_lines.end_mut() = display_lines.end - 1;
+                        let l = lines.line(display_lines.end.into());
+                        execute!(stdout(), ScrollDown(1), Print(l), RestorePosition)?;
+                    } else {
+                        execute!(stdout(), MoveUp(1))?;
+                    }
+                },
                 Event::Key(KeyEvent {
                     code: KeyCode::Char('l'),
                     modifiers: _,

ここまででスクロールっぽい動きはするようになった。
割と読み込みは速いので、もうちょっと表示周り改善してから検索機能の実装に移りたいところ。

ちなみにこれを動かすとファイル終端からさらにjキーでスクロールしようとすると、そんな行はねーよって言われてパニックで終了する。
まだまだ改善が必要である。

今日の差分はこんな感じ。今週あまり時間取れなさそうでかなりゆっくりなペースになりそう。
https://github.com/hhatto/advent-2021/compare/30a514cbf3ea7ce409af0a248ff11fc7221b12c5..3e90ddd468b1b737037cacdbe272d952b29c6d15

今日はここまで。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?