tlc: implement actual TUI event loops for tlcedit and tlcview

Both open_file() functions were stubs that opened the file but never
launched the terminal interface. tlcedit/tlcview would silently exit
without displaying anything.

- editor::open_file(): create Tui, render editor, run key event loop,
  handle Save/Close/SaveThenClose/DiscardThenClose results
- viewer::open_file(): create Tui, render viewer, run key event loop,
  exit when handle_key returns true
This commit is contained in:
2026-06-19 13:00:22 +03:00
parent ab5172c7e0
commit 035304f15b
2 changed files with 80 additions and 6 deletions
+44 -4
View File
@@ -1334,18 +1334,58 @@ impl Editor {
/// Backwards-compat shim for the old `open_file` API. The new API
/// is to construct an [`Editor`] directly via [`Editor::open`].
pub fn open_file(file: &str, line: Option<u64>) -> anyhow::Result<()> {
use crate::terminal::event::translate_key;
use crate::terminal::color::DEFAULT_THEME;
use termion::event::Event as TermEvent;
use termion::input::TermReadEventsAndRaw;
let mut ed = Editor::open(file);
if let Some(n) = line {
// Move cursor to the start of line `n` (1-based).
let target = n.saturating_sub(1) as usize;
if target < ed.buffer.line_count() {
let off = ed.buffer.line_offset(target);
ed.cursor.set_position(off, &ed.buffer);
}
}
// No TTY to render to here; just return Ok so callers that just
// want to verify the path can do so.
let _ = ed;
let mut tui = crate::terminal::Tui::new()?;
let stdin = std::io::stdin();
let mut events = stdin.lock().events_and_raw();
loop {
let (w, h) = tui.size();
if w >= 10 && h >= 5 {
let area = ratatui::layout::Rect::new(0, 0, w, h);
tui.draw(|frame| {
ed.render(frame, area, &DEFAULT_THEME);
})?;
}
let (event, _) = match events.next() {
Some(Ok(pair)) => pair,
Some(Err(_)) => continue,
None => break,
};
let tk = match event {
TermEvent::Key(k) => k,
_ => continue,
};
let key = translate_key(tk);
match ed.handle_key(key) {
EditorResult::Running => {}
EditorResult::Save => {
let _ = ed.save();
}
EditorResult::Close => break,
EditorResult::SaveThenClose => {
let _ = ed.save();
break;
}
EditorResult::DiscardThenClose => break,
}
}
Ok(())
}
+36 -2
View File
@@ -438,8 +438,42 @@ impl Viewer {
/// Backwards-compat shim: `open_file` was the Phase 0 stub.
pub fn open_file(file: &str) -> Result<()> {
let mut _v = Viewer::open(file)?;
// Phase 3.2 will implement the actual TUI render loop.
use crate::terminal::event::translate_key;
use crate::terminal::color::DEFAULT_THEME;
use termion::event::Event as TermEvent;
use termion::input::TermReadEventsAndRaw;
let mut v = Viewer::open(file)?;
let mut tui = crate::terminal::Tui::new()?;
let stdin = std::io::stdin();
let mut events = stdin.lock().events_and_raw();
loop {
let (w, h) = tui.size();
if w >= 10 && h >= 5 {
let area = ratatui::layout::Rect::new(0, 0, w, h);
tui.draw(|frame| {
v.render(frame, area, &DEFAULT_THEME);
})?;
}
let (event, _) = match events.next() {
Some(Ok(pair)) => pair,
Some(Err(_)) => continue,
None => break,
};
let tk = match event {
TermEvent::Key(k) => k,
_ => continue,
};
let key = translate_key(tk);
if v.handle_key(key) {
break;
}
}
Ok(())
}