mirror of
https://github.com/zaphar/sheetsui.git
synced 2025-07-22 13:00:22 -04:00
wip: convert named colors to hex strings and fix off by one
This commit is contained in:
parent
e798350cd2
commit
e7169dcb44
@ -7,9 +7,9 @@ pub enum Cmd<'a> {
|
||||
Write(Option<&'a str>),
|
||||
InsertRows(usize),
|
||||
InsertColumns(usize),
|
||||
ColorRows(Option<usize>, &'a str),
|
||||
ColorColumns(Option<usize>, &'a str),
|
||||
ColorCell(&'a str),
|
||||
ColorRows(Option<usize>, String),
|
||||
ColorColumns(Option<usize>, String),
|
||||
ColorCell(String),
|
||||
RenameSheet(Option<usize>, &'a str),
|
||||
NewSheet(Option<&'a str>),
|
||||
SelectSheet(&'a str),
|
||||
@ -165,10 +165,7 @@ fn try_consume_color_cell<'cmd, 'i: 'cmd>(
|
||||
if input.remaining() > 0 && !is_ws(&mut input) {
|
||||
return Err("Invalid command: Did you mean to type `color-cell <color>`?");
|
||||
}
|
||||
let arg = input.span(0..).trim();
|
||||
if arg.len() == 0 {
|
||||
return Err("Invalid command: Did you mean to type `color-cell <color>`?");
|
||||
}
|
||||
let arg = parse_color(input.span(0..).trim())?;
|
||||
return Ok(Some(Cmd::ColorCell(arg)));
|
||||
}
|
||||
|
||||
@ -330,10 +327,7 @@ fn try_consume_color_rows<'cmd, 'i: 'cmd>(
|
||||
return Err("Invalid command: Did you mean to type `color-rows [count] <color>`?");
|
||||
}
|
||||
let (idx, rest) = try_consume_usize(input.clone());
|
||||
let arg = rest.span(0..).trim();
|
||||
if arg.is_empty() {
|
||||
return Err("Invalid command: `color-rows` requires a color argument");
|
||||
}
|
||||
let arg = parse_color(rest.span(0..).trim())?;
|
||||
return Ok(Some(Cmd::ColorRows(idx, arg)));
|
||||
}
|
||||
|
||||
@ -350,19 +344,59 @@ fn try_consume_color_columns<'cmd, 'i: 'cmd>(
|
||||
return Err("Invalid command: Did you mean to type `color-columns [count] <color>`?");
|
||||
}
|
||||
let (idx, rest) = try_consume_usize(input.clone());
|
||||
let arg = rest.span(0..).trim();
|
||||
if arg.is_empty() {
|
||||
return Err("Invalid command: `color-columns` requires a color argument");
|
||||
}
|
||||
let arg = parse_color(rest.span(0..).trim())?;
|
||||
return Ok(Some(Cmd::ColorColumns(idx, arg)));
|
||||
}
|
||||
|
||||
fn try_consume_usize<'cmd, 'i: 'cmd>(
|
||||
mut input: StrCursor<'i>,
|
||||
) -> (Option<usize>, StrCursor<'i>) {
|
||||
pub(crate) fn parse_color(color: &str) -> Result<String, &'static str> {
|
||||
use colorsys::{Ansi256, Rgb};
|
||||
if color.is_empty() {
|
||||
return Err("Invalid command: `color-columns` requires a color argument");
|
||||
}
|
||||
let parsed = match color.to_lowercase().as_str() {
|
||||
"black" => Ansi256::new(0).as_rgb().to_hex_string(),
|
||||
"red" => Ansi256::new(1).as_rgb().to_hex_string(),
|
||||
"green" => Ansi256::new(2).as_rgb().to_hex_string(),
|
||||
"yellow" => Ansi256::new(3).as_rgb().to_hex_string(),
|
||||
"blue" => Ansi256::new(4).as_rgb().to_hex_string(),
|
||||
"magenta" => Ansi256::new(5).as_rgb().to_hex_string(),
|
||||
"cyan" => Ansi256::new(6).as_rgb().to_hex_string(),
|
||||
"gray" | "grey" => Ansi256::new(7).as_rgb().to_hex_string(),
|
||||
"darkgrey" | "darkgray" => Ansi256::new(8).as_rgb().to_hex_string(),
|
||||
"lightred" => Ansi256::new(9).as_rgb().to_hex_string(),
|
||||
"lightgreen" => Ansi256::new(10).as_rgb().to_hex_string(),
|
||||
"lightyellow" => Ansi256::new(11).as_rgb().to_hex_string(),
|
||||
"lightblue" => Ansi256::new(12).as_rgb().to_hex_string(),
|
||||
"lightmagenta" => Ansi256::new(13).as_rgb().to_hex_string(),
|
||||
"lightcyan" => Ansi256::new(14).as_rgb().to_hex_string(),
|
||||
"white" => Ansi256::new(15).as_rgb().to_hex_string(),
|
||||
candidate => {
|
||||
if candidate.starts_with("#") {
|
||||
candidate.to_string()
|
||||
} else if candidate.starts_with("rgb(") {
|
||||
if let Ok(rgb) = <Rgb as std::str::FromStr>::from_str(candidate) {
|
||||
// Note that the colorsys rgb model clamps the f64 values to no more
|
||||
// than 255.0 so the below casts are safe.
|
||||
rgb.to_hex_string()
|
||||
} else {
|
||||
return Err("Invalid color");
|
||||
}
|
||||
} else {
|
||||
return Err("Invalid color");
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(parsed)
|
||||
}
|
||||
|
||||
fn try_consume_usize<'cmd, 'i: 'cmd>(mut input: StrCursor<'i>) -> (Option<usize>, StrCursor<'i>) {
|
||||
let mut out = String::new();
|
||||
let original_input = input.clone();
|
||||
while input.peek_next().map(|c| (*c as char).is_ascii_digit()).unwrap_or(false) {
|
||||
while input
|
||||
.peek_next()
|
||||
.map(|c| (*c as char).is_ascii_digit())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
out.push(*input.next().unwrap() as char);
|
||||
}
|
||||
if out.len() > 0 {
|
||||
|
@ -469,7 +469,7 @@ impl<'ws> Workspace<'ws> {
|
||||
let row_count = _count.unwrap_or(1);
|
||||
let row = self.book.location.row;
|
||||
for r in row..(row+row_count) {
|
||||
self.book.set_row_style(&[("fill.bg_color", color)], self.book.current_sheet, r)?;
|
||||
self.book.set_row_style(&[("fill.bg_color", &color)], self.book.current_sheet, r)?;
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
@ -477,7 +477,7 @@ impl<'ws> Workspace<'ws> {
|
||||
let col_count = _count.unwrap_or(1);
|
||||
let col = self.book.location.col;
|
||||
for c in col..(col+col_count) {
|
||||
self.book.set_col_style(&[("fill.bg_color", color)], self.book.current_sheet, c)?;
|
||||
self.book.set_col_style(&[("fill.bg_color", &color)], self.book.current_sheet, c)?;
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
@ -488,8 +488,8 @@ impl<'ws> Workspace<'ws> {
|
||||
sheet,
|
||||
row: start.row as i32,
|
||||
column: start.col as i32,
|
||||
width: (end.col - start.col) as i32,
|
||||
height: (end.row - start.row) as i32
|
||||
width: (end.col - start.col + 1) as i32,
|
||||
height: (end.row - start.row + 1) as i32
|
||||
}
|
||||
} else {
|
||||
let address = self.book.location.clone();
|
||||
@ -501,7 +501,7 @@ impl<'ws> Workspace<'ws> {
|
||||
height: 1
|
||||
}
|
||||
};
|
||||
self.book.set_cell_style(&[("fill.bg_color", color)], &area)?;
|
||||
self.book.set_cell_style(&[("fill.bg_color", &color)], &area)?;
|
||||
Ok(None)
|
||||
}
|
||||
Ok(None) => {
|
||||
|
@ -2,6 +2,7 @@ use std::process::ExitCode;
|
||||
|
||||
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
|
||||
|
||||
use crate::ui::cmd::parse_color;
|
||||
use crate::ui::{Address, Modality};
|
||||
|
||||
use super::cmd::{parse, Cmd};
|
||||
@ -33,6 +34,10 @@ impl InputScript {
|
||||
self.event(construct_key_event(KeyCode::Tab))
|
||||
}
|
||||
|
||||
pub fn enter(self) -> Self {
|
||||
self.event(construct_key_event(KeyCode::Enter))
|
||||
}
|
||||
|
||||
pub fn modified_char(self, c: char, mods: KeyModifiers) -> Self {
|
||||
self.event(construct_modified_key_event(KeyCode::Char(c), mods))
|
||||
}
|
||||
@ -42,10 +47,6 @@ impl InputScript {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn enter(self) -> Self {
|
||||
self.event(construct_key_event(KeyCode::Enter))
|
||||
}
|
||||
|
||||
pub fn esc(self) -> Self {
|
||||
self.event(construct_key_event(KeyCode::Esc))
|
||||
}
|
||||
@ -267,7 +268,7 @@ fn test_cmd_color_rows_with_color() {
|
||||
let output = result.unwrap();
|
||||
assert!(output.is_some());
|
||||
let cmd = output.unwrap();
|
||||
assert_eq!(cmd, Cmd::ColorRows(None, "red"));
|
||||
assert_eq!(cmd, Cmd::ColorRows(None, parse_color("red").unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -278,7 +279,7 @@ fn test_cmd_color_rows_with_idx_and_color() {
|
||||
let output = result.unwrap();
|
||||
assert!(output.is_some());
|
||||
let cmd = output.unwrap();
|
||||
assert_eq!(cmd, Cmd::ColorRows(Some(1), "red"));
|
||||
assert_eq!(cmd, Cmd::ColorRows(Some(1), parse_color("red").unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -289,7 +290,7 @@ fn test_cmd_color_columns_with_color() {
|
||||
let output = result.unwrap();
|
||||
assert!(output.is_some());
|
||||
let cmd = output.unwrap();
|
||||
assert_eq!(cmd, Cmd::ColorColumns(None, "red"));
|
||||
assert_eq!(cmd, Cmd::ColorColumns(None, parse_color("red").unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -300,7 +301,7 @@ fn test_cmd_color_columns_with_idx_and_color() {
|
||||
let output = result.unwrap();
|
||||
assert!(output.is_some());
|
||||
let cmd = output.unwrap();
|
||||
assert_eq!(cmd, Cmd::ColorColumns(Some(1), "red"));
|
||||
assert_eq!(cmd, Cmd::ColorColumns(Some(1), parse_color("red").unwrap()));
|
||||
}
|
||||
|
||||
|
||||
@ -1152,6 +1153,25 @@ fn test_extend_to_range() {
|
||||
assert_eq!("=B2+1".to_string(), extended_cell);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_color_cells() {
|
||||
let mut ws = new_workspace();
|
||||
script()
|
||||
.char('v')
|
||||
.chars("jjll")
|
||||
.char(':')
|
||||
.chars("color-cell red")
|
||||
.enter()
|
||||
.run(&mut ws)
|
||||
.expect("Unable to run script");
|
||||
for ri in 1..=3 {
|
||||
for ci in 1..=3 {
|
||||
let style = ws.book.get_cell_style(ws.book.current_sheet, &Address { row: ri, col: ci }).expect("failed to get style");
|
||||
assert_eq!("#800000", style.fill.bg_color.expect(&format!("No background color set for {}:{}", ri, ci)).as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_workspace<'a>() -> Workspace<'a> {
|
||||
Workspace::new_empty("en", "America/New_York").expect("Failed to get empty workbook")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user