tlc: start_line plumbing + buttonbar in editor/viewer
Editor gains goto_line(), viewer gains jump_to_line() + open_file(start_line). Both editor and viewer now render the F-key buttonbar at the bottom (1Help 2Save... / 1Help 2Wrap...).
This commit is contained in:
@@ -299,7 +299,18 @@ bracket_flash: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrow the underlying buffer.
|
||||
/// Jump cursor to a 1-based line number and scroll the
|
||||
/// viewport so the line is visible.
|
||||
pub fn goto_line(&mut self, line: u32) {
|
||||
if line >= 1 {
|
||||
if let Ok(off) = crate::editor::goto::line_to_offset(&self.buffer, line) {
|
||||
self.buffer.set_cursor(off);
|
||||
self.cursor.set_position(self.buffer.cursor(), &self.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrow the underlying buffer.
|
||||
#[must_use]
|
||||
pub fn buffer(&self) -> &Buffer {
|
||||
&self.buffer
|
||||
|
||||
@@ -609,8 +609,24 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
// Status line (last line of the editor area).
|
||||
if area.height >= 2 {
|
||||
// Status line + buttonbar.
|
||||
if area.height >= 3 {
|
||||
let status_y = area.y + area.height - 2;
|
||||
let status = Paragraph::new(Line::from(Span::styled(
|
||||
self.status_string(),
|
||||
Style::default().fg(linestate_fg).bg(linestate_bg),
|
||||
)));
|
||||
frame.render_widget(status, Rect::new(area.x, status_y, area.width, 1));
|
||||
|
||||
let bar_y = area.y + area.height - 1;
|
||||
let bar_area = Rect::new(area.x, bar_y, area.width, 1);
|
||||
let labels: [(&str, &str); 10] = [
|
||||
("1", "Help"), ("2", "Save"), ("3", "Mark"), ("4", "Repl"),
|
||||
("5", "Copy"), ("6", "Move"), ("7", "Search"), ("8", "Delete"),
|
||||
("9", "PullDn"), ("10", "Quit"),
|
||||
];
|
||||
crate::widget::buttonbar::render_buttonbar(frame, bar_area, theme, &labels);
|
||||
} else if area.height >= 2 {
|
||||
let status_y = area.y + area.height - 1;
|
||||
let status = Paragraph::new(Line::from(Span::styled(
|
||||
self.status_string(),
|
||||
|
||||
@@ -255,6 +255,14 @@ impl Viewer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Jump to a 1-based line number.
|
||||
pub fn jump_to_line(&mut self, line: u64) {
|
||||
if line >= 1 {
|
||||
self.top = line.saturating_sub(1);
|
||||
self.sync_cursor_to_top();
|
||||
}
|
||||
}
|
||||
|
||||
fn current_line(&self) -> u64 {
|
||||
self.goto
|
||||
.resolve(self.cursor, goto::GotoKind::Offset)
|
||||
@@ -406,17 +414,26 @@ impl Viewer {
|
||||
let selected_fg = viewer_selected.map(|p| p.fg).unwrap_or(theme.cursor_fg);
|
||||
let selected_bg = viewer_selected.map(|p| p.bg).unwrap_or(theme.cursor_bg);
|
||||
|
||||
let constraints = if area.height >= 3 {
|
||||
let constraints = if area.height >= 4 {
|
||||
[
|
||||
Constraint::Length(1),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(1),
|
||||
]
|
||||
} else if area.height >= 3 {
|
||||
[
|
||||
Constraint::Length(1),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(0),
|
||||
]
|
||||
} else {
|
||||
[
|
||||
Constraint::Length(0),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(0),
|
||||
Constraint::Length(0),
|
||||
]
|
||||
};
|
||||
let chunks = Layout::default()
|
||||
@@ -465,6 +482,15 @@ impl Viewer {
|
||||
);
|
||||
}
|
||||
|
||||
if chunks[3].height > 0 {
|
||||
let labels: [(&str, &str); 10] = [
|
||||
("1", "Help"), ("2", "Wrap"), ("3", ""), ("4", "Hex"),
|
||||
("5", ""), ("6", ""), ("7", "Search"), ("8", "Magic"),
|
||||
("9", ""), ("10", "Quit"),
|
||||
];
|
||||
crate::widget::buttonbar::render_buttonbar(frame, chunks[3], theme, &labels);
|
||||
}
|
||||
|
||||
// Prompt overlay: rendered on the top row so it doesn't
|
||||
// collide with the footer area below. The body's border
|
||||
// block still owns the central chunk.
|
||||
@@ -740,13 +766,16 @@ impl Viewer {
|
||||
}
|
||||
|
||||
/// Backwards-compat shim: `open_file` was the Phase 0 stub.
|
||||
pub fn open_file(file: &str) -> Result<()> {
|
||||
pub fn open_file(file: &str, start_line: Option<u64>) -> 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 v = Viewer::open(file)?;
|
||||
if let Some(line) = start_line {
|
||||
v.jump_to_line(line);
|
||||
}
|
||||
|
||||
let mut tui = crate::terminal::Tui::new()?;
|
||||
let stdin = std::io::stdin();
|
||||
|
||||
Reference in New Issue
Block a user