mirror of
https://github.com/zaphar/sheetsui.git
synced 2025-07-22 13:00:22 -04:00
parent
b2034e7f2b
commit
8f902d63f2
@ -215,14 +215,15 @@ impl Book {
|
||||
|
||||
/// Select a sheet by name.
|
||||
pub fn select_sheet_by_name(&mut self, name: &str) -> bool {
|
||||
if let Some(sheet) = self
|
||||
if let Some((idx, _sheet)) = self
|
||||
.model
|
||||
.workbook
|
||||
.worksheets
|
||||
.iter()
|
||||
.find(|sheet| sheet.name == name)
|
||||
.enumerate()
|
||||
.find(|(_idx, sheet)| sheet.name == name)
|
||||
{
|
||||
self.current_sheet = sheet.sheet_id;
|
||||
self.current_sheet =idx as u32;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
@ -233,16 +234,37 @@ impl Book {
|
||||
self.model.workbook.get_worksheet_names()
|
||||
}
|
||||
|
||||
pub fn select_next_sheet(&mut self) {
|
||||
let len = self.model.workbook.worksheets.len() as u32;
|
||||
let mut next = self.current_sheet + 1;
|
||||
if next == len {
|
||||
next = 0;
|
||||
}
|
||||
self.current_sheet = next;
|
||||
}
|
||||
|
||||
pub fn select_prev_sheet(&mut self) {
|
||||
let len = self.model.workbook.worksheets.len() as u32;
|
||||
let next = if self.current_sheet == 0 {
|
||||
len - 1
|
||||
} else {
|
||||
self.current_sheet - 1
|
||||
};
|
||||
self.current_sheet = next;
|
||||
}
|
||||
|
||||
|
||||
/// Select a sheet by id.
|
||||
pub fn select_sheet_by_id(&mut self, id: u32) -> bool {
|
||||
if let Some(sheet) = self
|
||||
if let Some((idx, _sheet)) = self
|
||||
.model
|
||||
.workbook
|
||||
.worksheets
|
||||
.iter()
|
||||
.find(|sheet| sheet.sheet_id == id)
|
||||
.enumerate()
|
||||
.find(|(_idx, sheet)| sheet.sheet_id == id)
|
||||
{
|
||||
self.current_sheet = sheet.sheet_id;
|
||||
self.current_sheet = idx as u32;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
@ -254,7 +276,7 @@ impl Book {
|
||||
.model
|
||||
.workbook
|
||||
.worksheet(self.current_sheet)
|
||||
.map_err(|s| anyhow!("Invalid Worksheet: {}", s))?)
|
||||
.map_err(|s| anyhow!("Invalid Worksheet id: {}: error: {}", self.current_sheet, s))?)
|
||||
}
|
||||
|
||||
pub(crate) fn get_sheet_mut(&mut self) -> Result<&mut Worksheet> {
|
||||
|
@ -9,6 +9,7 @@ pub enum Cmd<'a> {
|
||||
InsertColumns(usize),
|
||||
RenameSheet(Option<usize>, &'a str),
|
||||
NewSheet(Option<&'a str>),
|
||||
SelectSheet(&'a str),
|
||||
Edit(&'a str),
|
||||
Help(Option<&'a str>),
|
||||
Quit,
|
||||
@ -24,6 +25,9 @@ pub fn parse<'cmd, 'i: 'cmd>(input: &'i str) -> Result<Option<Cmd<'cmd>>, &'stat
|
||||
if let Some(cmd) = try_consume_new_sheet(cursor.clone())? {
|
||||
return Ok(Some(cmd));
|
||||
}
|
||||
if let Some(cmd) = try_consume_select_sheet(cursor.clone())? {
|
||||
return Ok(Some(cmd));
|
||||
}
|
||||
// try consume insert-row command.
|
||||
if let Some(cmd) = try_consume_insert_row(cursor.clone())? {
|
||||
return Ok(Some(cmd));
|
||||
@ -114,6 +118,25 @@ fn try_consume_new_sheet<'cmd, 'i: 'cmd>(
|
||||
})));
|
||||
}
|
||||
|
||||
fn try_consume_select_sheet<'cmd, 'i: 'cmd>(
|
||||
mut input: StrCursor<'i>,
|
||||
) -> Result<Option<Cmd<'cmd>>, &'static str> {
|
||||
const LONG: &'static str = "select-sheet";
|
||||
|
||||
if compare(input.clone(), LONG) {
|
||||
input.seek(LONG.len());
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
if input.remaining() > 0 && !is_ws(&mut input) {
|
||||
return Err("Invalid command: Did you mean to type `write <sheet-name>`?");
|
||||
}
|
||||
let arg = input.span(0..).trim();
|
||||
if arg.is_empty() {
|
||||
return Err("Invalid command: Did you forget the sheet name? `write <sheet-name>`?");
|
||||
}
|
||||
return Ok(Some(Cmd::SelectSheet(arg)));
|
||||
}
|
||||
|
||||
fn try_consume_insert_row<'cmd, 'i: 'cmd>(
|
||||
mut input: StrCursor<'i>,
|
||||
|
@ -293,6 +293,10 @@ impl<'ws> Workspace<'ws> {
|
||||
self.book.new_sheet(name)?;
|
||||
Ok(true)
|
||||
}
|
||||
Ok(Some(Cmd::SelectSheet(name))) => {
|
||||
self.book.select_sheet_by_name(name);
|
||||
Ok(true)
|
||||
}
|
||||
Ok(Some(Cmd::Quit)) => {
|
||||
// TODO(zaphar): We probably need to do better than this
|
||||
std::process::exit(0);
|
||||
@ -323,6 +327,12 @@ impl<'ws> Workspace<'ws> {
|
||||
KeyCode::Char('?') => {
|
||||
self.enter_dialog_mode(self.render_help_text());
|
||||
}
|
||||
KeyCode::Char('n') if key.modifiers == KeyModifiers::CONTROL => {
|
||||
self.book.select_next_sheet();
|
||||
}
|
||||
KeyCode::Char('p') if key.modifiers == KeyModifiers::CONTROL => {
|
||||
self.book.select_prev_sheet();
|
||||
}
|
||||
KeyCode::Char('s')
|
||||
if key.modifiers == KeyModifiers::HYPER
|
||||
|| key.modifiers == KeyModifiers::SUPER =>
|
||||
@ -467,47 +477,6 @@ impl<'ws> Workspace<'ws> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_render_parts(
|
||||
&mut self,
|
||||
area: Rect,
|
||||
) -> Vec<(Rect, Box<dyn Fn(Rect, &mut Buffer, &mut Self)>)> {
|
||||
use ratatui::widgets::StatefulWidget;
|
||||
let mut cs = vec![Constraint::Fill(4), Constraint::Fill(30)];
|
||||
let mut rs: Vec<Box<dyn Fn(Rect, &mut Buffer, &mut Self)>> = vec![
|
||||
Box::new(|rect: Rect, buf: &mut Buffer, ws: &mut Self| ws.text_area.render(rect, buf)),
|
||||
Box::new(move |rect: Rect, buf: &mut Buffer, ws: &mut Self| {
|
||||
let sheet_name = ws.book.get_sheet_name().unwrap_or("Unknown");
|
||||
let table_block = Block::bordered().title_top(sheet_name);
|
||||
let viewport = Viewport::new(&ws.book).with_selected(ws.book.location.clone()).block(table_block);
|
||||
StatefulWidget::render(viewport, rect, buf, &mut ws.state.viewport_state);
|
||||
}),
|
||||
];
|
||||
|
||||
if self.state.modality() == &Modality::Command {
|
||||
cs.push(Constraint::Max(1));
|
||||
rs.push(Box::new(|rect: Rect, buf: &mut Buffer, ws: &mut Self| {
|
||||
StatefulWidget::render(
|
||||
TextPrompt::from("Command"),
|
||||
rect,
|
||||
buf,
|
||||
&mut ws.state.command_state,
|
||||
)
|
||||
}));
|
||||
}
|
||||
let rects: Vec<Rect> = Vec::from(
|
||||
Layout::vertical(cs)
|
||||
.vertical_margin(2)
|
||||
.horizontal_margin(2)
|
||||
.flex(Flex::Legacy)
|
||||
.split(area.clone())
|
||||
.as_ref(),
|
||||
);
|
||||
rects
|
||||
.into_iter()
|
||||
.zip(rs.into_iter())
|
||||
.map(|(rect, f)| (rect, f))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn load_book(path: &PathBuf, locale: &str, tz: &str) -> Result<Book, anyhow::Error> {
|
||||
|
@ -2,7 +2,7 @@ use ratatui::{
|
||||
self,
|
||||
layout::Rect,
|
||||
text::{Line, Text},
|
||||
widgets::{Block, Widget},
|
||||
widgets::{Block, Tabs, Widget},
|
||||
Frame,
|
||||
};
|
||||
use tui_popup::Popup;
|
||||
@ -15,6 +15,61 @@ pub use viewport::Viewport;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
impl<'ws> Workspace<'ws> {
|
||||
fn get_render_parts(
|
||||
&mut self,
|
||||
area: Rect,
|
||||
) -> Vec<(Rect, Box<dyn Fn(Rect, &mut Buffer, &mut Self)>)> {
|
||||
use ratatui::widgets::StatefulWidget;
|
||||
let mut cs = vec![
|
||||
Constraint::Length(2),
|
||||
Constraint::Length(3),
|
||||
Constraint::Fill(1),
|
||||
];
|
||||
let mut rs: Vec<Box<dyn Fn(Rect, &mut Buffer, &mut Self)>> = vec![
|
||||
Box::new(|rect: Rect, buf: &mut Buffer, ws: &mut Self| {
|
||||
let tabs = Tabs::new(ws.book.get_sheet_names())
|
||||
.select(Some(ws.book.current_sheet as usize));
|
||||
tabs.render(rect, buf);
|
||||
}),
|
||||
Box::new(|rect: Rect, buf: &mut Buffer, ws: &mut Self| ws.text_area.render(rect, buf)),
|
||||
Box::new(move |rect: Rect, buf: &mut Buffer, ws: &mut Self| {
|
||||
let sheet_name = ws.book.get_sheet_name().unwrap_or("Unknown");
|
||||
let table_block = Block::bordered().title_top(sheet_name);
|
||||
let viewport = Viewport::new(&ws.book)
|
||||
.with_selected(ws.book.location.clone())
|
||||
.block(table_block);
|
||||
StatefulWidget::render(viewport, rect, buf, &mut ws.state.viewport_state);
|
||||
}),
|
||||
];
|
||||
|
||||
if self.state.modality() == &Modality::Command {
|
||||
cs.push(Constraint::Max(1));
|
||||
rs.push(Box::new(|rect: Rect, buf: &mut Buffer, ws: &mut Self| {
|
||||
StatefulWidget::render(
|
||||
TextPrompt::from("Command"),
|
||||
rect,
|
||||
buf,
|
||||
&mut ws.state.command_state,
|
||||
)
|
||||
}));
|
||||
}
|
||||
let rects: Vec<Rect> = Vec::from(
|
||||
Layout::vertical(cs)
|
||||
.vertical_margin(2)
|
||||
.horizontal_margin(2)
|
||||
.flex(Flex::Legacy)
|
||||
.split(area.clone())
|
||||
.as_ref(),
|
||||
);
|
||||
rects
|
||||
.into_iter()
|
||||
.zip(rs.into_iter())
|
||||
.map(|(rect, f)| (rect, f))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'widget, 'ws: 'widget> Widget for &'widget mut Workspace<'ws> {
|
||||
fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer)
|
||||
where
|
||||
|
Loading…
x
Reference in New Issue
Block a user