FIX: small diverse fixes (#35)
This commit is contained in:
committed by
GitHub
parent
b3b7dea930
commit
49ef846ebd
@@ -308,9 +308,9 @@ impl Lexer {
|
||||
return self.consume_range(None);
|
||||
}
|
||||
let name_upper = name.to_ascii_uppercase();
|
||||
if name_upper == self.language.booleans.true_value {
|
||||
if name_upper == self.language.booleans.r#true {
|
||||
return TokenType::Boolean(true);
|
||||
} else if name_upper == self.language.booleans.false_value {
|
||||
} else if name_upper == self.language.booleans.r#false {
|
||||
return TokenType::Boolean(false);
|
||||
}
|
||||
if self.mode == LexerMode::A1 {
|
||||
@@ -660,8 +660,8 @@ impl Lexer {
|
||||
fn consume_error(&mut self) -> TokenType {
|
||||
let errors = &self.language.errors;
|
||||
let rest_of_formula: String = self.chars[self.position - 1..self.len].iter().collect();
|
||||
if rest_of_formula.starts_with(&errors.ref_value) {
|
||||
self.position += errors.ref_value.chars().count() - 1;
|
||||
if rest_of_formula.starts_with(&errors.r#ref) {
|
||||
self.position += errors.r#ref.chars().count() - 1;
|
||||
return TokenType::Error(Error::REF);
|
||||
} else if rest_of_formula.starts_with(&errors.name) {
|
||||
self.position += errors.name.chars().count() - 1;
|
||||
|
||||
@@ -6,11 +6,11 @@ use crate::{
|
||||
token::TokenType,
|
||||
},
|
||||
language::get_language,
|
||||
locale::get_locale_fix,
|
||||
locale::get_locale,
|
||||
};
|
||||
|
||||
fn new_language_lexer(formula: &str, locale: &str, language: &str) -> Lexer {
|
||||
let locale = get_locale_fix(locale).unwrap();
|
||||
let locale = get_locale(locale).unwrap();
|
||||
let language = get_language(language).unwrap();
|
||||
Lexer::new(formula, LexerMode::A1, locale, language)
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ impl Error {
|
||||
pub fn to_localized_error_string(&self, language: &Language) -> String {
|
||||
match self {
|
||||
Error::NULL => language.errors.null.to_string(),
|
||||
Error::REF => language.errors.ref_value.to_string(),
|
||||
Error::REF => language.errors.r#ref.to_string(),
|
||||
Error::NAME => language.errors.name.to_string(),
|
||||
Error::VALUE => language.errors.value.to_string(),
|
||||
Error::DIV => language.errors.div.to_string(),
|
||||
@@ -137,7 +137,7 @@ impl Error {
|
||||
|
||||
pub fn get_error_by_name(name: &str, language: &Language) -> Option<Error> {
|
||||
let errors = &language.errors;
|
||||
if name == errors.ref_value {
|
||||
if name == errors.r#ref {
|
||||
return Some(Error::REF);
|
||||
} else if name == errors.name {
|
||||
return Some(Error::NAME);
|
||||
|
||||
@@ -5,16 +5,13 @@ use std::collections::HashMap;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Booleans {
|
||||
#[serde(rename = "true")]
|
||||
pub true_value: String,
|
||||
#[serde(rename = "false")]
|
||||
pub false_value: String,
|
||||
pub r#true: String,
|
||||
pub r#false: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Errors {
|
||||
#[serde(rename = "ref")]
|
||||
pub ref_value: String,
|
||||
pub r#ref: String,
|
||||
pub name: String,
|
||||
pub value: String,
|
||||
pub div: String,
|
||||
|
||||
@@ -80,14 +80,8 @@ static LOCALES: Lazy<HashMap<String, Locale>> = Lazy::new(|| {
|
||||
serde_json::from_str(include_str!("locales.json")).expect("Failed parsing locale")
|
||||
});
|
||||
|
||||
pub fn get_locale(_id: &str) -> Result<&Locale, String> {
|
||||
pub fn get_locale(id: &str) -> Result<&Locale, String> {
|
||||
// TODO: pass the locale once we implement locales in Rust
|
||||
let locale = LOCALES.get("en").ok_or("Invalid locale")?;
|
||||
Ok(locale)
|
||||
}
|
||||
|
||||
// TODO: Remove this function one we implement locales properly
|
||||
pub fn get_locale_fix(id: &str) -> Result<&Locale, String> {
|
||||
let locale = LOCALES.get(id).ok_or("Invalid locale")?;
|
||||
Ok(locale)
|
||||
}
|
||||
|
||||
@@ -798,7 +798,7 @@ impl Model {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns a model from a String representation of a workbook
|
||||
/// Returns a model from an internal binary representation of a workbook
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -816,9 +816,12 @@ impl Model {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
/// * [Model::to_bytes]
|
||||
pub fn from_bytes(s: &[u8]) -> Result<Model, String> {
|
||||
let workbook: Workbook =
|
||||
bitcode::decode(s).map_err(|_| "Error parsing workbook".to_string())?;
|
||||
bitcode::decode(s).map_err(|e| format!("Error parsing workbook: {e}"))?;
|
||||
Model::from_workbook(workbook)
|
||||
}
|
||||
|
||||
@@ -1760,7 +1763,10 @@ impl Model {
|
||||
.get_style(self.get_cell_style_index(sheet, row, column))
|
||||
}
|
||||
|
||||
/// Returns a JSON string of the workbook
|
||||
/// Returns an internal binary representation of the workbook
|
||||
///
|
||||
/// See also:
|
||||
/// * [Model::from_bytes]
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
bitcode::encode(&self.workbook)
|
||||
}
|
||||
|
||||
@@ -53,4 +53,5 @@ mod test_frozen_rows_and_columns;
|
||||
mod test_get_cell_content;
|
||||
mod test_percentage;
|
||||
mod test_today;
|
||||
mod test_types;
|
||||
mod user_model;
|
||||
|
||||
24
base/src/test/test_types.rs
Normal file
24
base/src/test/test_types.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::types::{Alignment, HorizontalAlignment, VerticalAlignment};
|
||||
|
||||
#[test]
|
||||
fn alignment_default() {
|
||||
let alignment = Alignment::default();
|
||||
assert_eq!(
|
||||
alignment,
|
||||
Alignment {
|
||||
horizontal: HorizontalAlignment::General,
|
||||
vertical: VerticalAlignment::Bottom,
|
||||
wrap_text: false
|
||||
}
|
||||
);
|
||||
|
||||
let s = serde_json::to_string(&alignment).unwrap();
|
||||
// defaults stringifies as an empty object
|
||||
assert_eq!(s, "{}");
|
||||
|
||||
let a: Alignment = serde_json::from_str("{}").unwrap();
|
||||
|
||||
assert_eq!(a, alignment)
|
||||
}
|
||||
@@ -25,7 +25,7 @@ fn send_queue() {
|
||||
#[test]
|
||||
fn apply_external_diffs_wrong_str() {
|
||||
let mut model1 = UserModel::from_model(new_empty_model());
|
||||
assert!(model1.apply_external_diffs("invalid").is_err());
|
||||
assert!(model1.apply_external_diffs("invalid".as_bytes()).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -155,5 +155,7 @@ fn new_sheet() {
|
||||
#[test]
|
||||
fn wrong_diffs_handled() {
|
||||
let mut model = UserModel::from_model(new_empty_model());
|
||||
assert!(model.apply_external_diffs("Hello world").is_err());
|
||||
assert!(model
|
||||
.apply_external_diffs("Hello world".as_bytes())
|
||||
.is_err());
|
||||
}
|
||||
|
||||
@@ -144,13 +144,18 @@ fn basic_fill() {
|
||||
|
||||
let style = model.get_cell_style(0, 1, 1).unwrap();
|
||||
assert_eq!(style.fill.bg_color, None);
|
||||
assert_eq!(style.fill.fg_color, None);
|
||||
|
||||
// bg_color
|
||||
model
|
||||
.update_range_style(&range, "fill.bg_color", "#F2F2F2")
|
||||
.unwrap();
|
||||
model
|
||||
.update_range_style(&range, "fill.fg_color", "#F3F4F5")
|
||||
.unwrap();
|
||||
let style = model.get_cell_style(0, 1, 1).unwrap();
|
||||
assert_eq!(style.fill.bg_color, Some("#F2F2F2".to_owned()));
|
||||
assert_eq!(style.fill.fg_color, Some("#F3F4F5".to_owned()));
|
||||
|
||||
let send_queue = model.flush_send_queue();
|
||||
|
||||
@@ -159,6 +164,7 @@ fn basic_fill() {
|
||||
|
||||
let style = model2.get_cell_style(0, 1, 1).unwrap();
|
||||
assert_eq!(style.fill.bg_color, Some("#F2F2F2".to_owned()));
|
||||
assert_eq!(style.fill.fg_color, Some("#F3F4F5".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -171,9 +177,15 @@ fn fill_errors() {
|
||||
width: 1,
|
||||
height: 1,
|
||||
};
|
||||
assert!(model
|
||||
.update_range_style(&range, "fill.bg_color", "#FFF")
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
model.update_range_style(&range, "fill.bg_color", "#FFF"),
|
||||
Err("Invalid color: '#FFF'.".to_string())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
model.update_range_style(&range, "fill.fg_color", "#FFF"),
|
||||
Err("Invalid color: '#FFF'.".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -25,6 +25,6 @@ fn errors() {
|
||||
let model_bytes = "Early in the morning, late in the century, Cricklewood Broadway.".as_bytes();
|
||||
assert_eq!(
|
||||
&UserModel::from_bytes(model_bytes).unwrap_err(),
|
||||
"Error parsing workbook"
|
||||
"Error parsing workbook: invalid packing"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,37 +4,15 @@ use std::{collections::HashMap, fmt::Display};
|
||||
|
||||
use crate::expressions::token::Error;
|
||||
|
||||
// Useful for `#[serde(default = "default_as_true")]`
|
||||
fn default_as_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_as_false() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// Useful for `#[serde(skip_serializing_if = "is_true")]`
|
||||
fn is_true(b: &bool) -> bool {
|
||||
*b
|
||||
}
|
||||
|
||||
fn is_false(b: &bool) -> bool {
|
||||
!*b
|
||||
}
|
||||
|
||||
fn is_zero(num: &i32) -> bool {
|
||||
*num == 0
|
||||
}
|
||||
|
||||
fn is_default_alignment(o: &Option<Alignment>) -> bool {
|
||||
o.is_none() || *o == Some(Alignment::default())
|
||||
}
|
||||
|
||||
fn hashmap_is_empty(h: &HashMap<String, Table>) -> bool {
|
||||
h.values().len() == 0
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Metadata {
|
||||
pub application: String,
|
||||
pub app_version: String,
|
||||
@@ -44,14 +22,13 @@ pub struct Metadata {
|
||||
pub last_modified: String, //"2020-11-20T16:24:35"
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct WorkbookSettings {
|
||||
pub tz: String,
|
||||
pub locale: String,
|
||||
}
|
||||
/// An internal representation of an IronCalc Workbook
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
|
||||
pub struct Workbook {
|
||||
pub shared_strings: Vec<String>,
|
||||
pub defined_names: Vec<DefinedName>,
|
||||
@@ -60,17 +37,14 @@ pub struct Workbook {
|
||||
pub name: String,
|
||||
pub settings: WorkbookSettings,
|
||||
pub metadata: Metadata,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "hashmap_is_empty")]
|
||||
pub tables: HashMap<String, Table>,
|
||||
}
|
||||
|
||||
/// A defined name. The `sheet_id` is the sheet index in case the name is local
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct DefinedName {
|
||||
pub name: String,
|
||||
pub formula: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sheet_id: Option<u32>,
|
||||
}
|
||||
|
||||
@@ -80,8 +54,7 @@ pub struct DefinedName {
|
||||
/// * state:
|
||||
/// 18.18.68 ST_SheetState (Sheet Visibility Types)
|
||||
/// hidden, veryHidden, visible
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub enum SheetState {
|
||||
Visible,
|
||||
Hidden,
|
||||
@@ -99,7 +72,7 @@ impl Display for SheetState {
|
||||
}
|
||||
|
||||
/// Internal representation of a worksheet Excel object
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
|
||||
pub struct Worksheet {
|
||||
pub dimension: String,
|
||||
pub cols: Vec<Col>,
|
||||
@@ -109,15 +82,10 @@ pub struct Worksheet {
|
||||
pub shared_formulas: Vec<String>,
|
||||
pub sheet_id: u32,
|
||||
pub state: SheetState,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub color: Option<String>,
|
||||
pub merge_cells: Vec<String>,
|
||||
pub comments: Vec<Comment>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "is_zero")]
|
||||
pub frozen_rows: i32,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "is_zero")]
|
||||
pub frozen_columns: i32,
|
||||
}
|
||||
|
||||
@@ -126,7 +94,7 @@ pub struct Worksheet {
|
||||
pub type SheetData = HashMap<i32, HashMap<i32, Cell>>;
|
||||
|
||||
// ECMA-376-1:2016 section 18.3.1.73
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
|
||||
pub struct Row {
|
||||
/// Row index
|
||||
pub r: i32,
|
||||
@@ -134,23 +102,19 @@ pub struct Row {
|
||||
pub custom_format: bool,
|
||||
pub custom_height: bool,
|
||||
pub s: i32,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub hidden: bool,
|
||||
}
|
||||
|
||||
// ECMA-376-1:2016 section 18.3.1.13
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
|
||||
pub struct Col {
|
||||
// Column definitions are defined on ranges, unlike rows which store unique, per-row entries.
|
||||
/// First column affected by this record. Settings apply to column in \[min, max\] range.
|
||||
pub min: i32,
|
||||
/// Last column affected by this record. Settings apply to column in \[min, max\] range.
|
||||
pub max: i32,
|
||||
|
||||
pub width: f64,
|
||||
pub custom_width: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub style: Option<i32>,
|
||||
}
|
||||
|
||||
@@ -165,32 +129,55 @@ pub enum CellType {
|
||||
CompoundData = 128,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, Clone, PartialEq)]
|
||||
#[serde(tag = "t", deny_unknown_fields)]
|
||||
#[derive(Encode, Decode, Debug, Clone, PartialEq)]
|
||||
pub enum Cell {
|
||||
#[serde(rename = "empty")]
|
||||
EmptyCell { s: i32 },
|
||||
#[serde(rename = "b")]
|
||||
BooleanCell { v: bool, s: i32 },
|
||||
#[serde(rename = "n")]
|
||||
NumberCell { v: f64, s: i32 },
|
||||
EmptyCell {
|
||||
s: i32,
|
||||
},
|
||||
|
||||
BooleanCell {
|
||||
v: bool,
|
||||
s: i32,
|
||||
},
|
||||
|
||||
NumberCell {
|
||||
v: f64,
|
||||
s: i32,
|
||||
},
|
||||
// Maybe we should not have this type. In Excel this is just a string
|
||||
#[serde(rename = "e")]
|
||||
ErrorCell { ei: Error, s: i32 },
|
||||
ErrorCell {
|
||||
ei: Error,
|
||||
s: i32,
|
||||
},
|
||||
// Always a shared string
|
||||
#[serde(rename = "s")]
|
||||
SharedString { si: i32, s: i32 },
|
||||
SharedString {
|
||||
si: i32,
|
||||
s: i32,
|
||||
},
|
||||
// Non evaluated Formula
|
||||
#[serde(rename = "u")]
|
||||
CellFormula { f: i32, s: i32 },
|
||||
#[serde(rename = "fb")]
|
||||
CellFormulaBoolean { f: i32, v: bool, s: i32 },
|
||||
#[serde(rename = "fn")]
|
||||
CellFormulaNumber { f: i32, v: f64, s: i32 },
|
||||
CellFormula {
|
||||
f: i32,
|
||||
s: i32,
|
||||
},
|
||||
|
||||
CellFormulaBoolean {
|
||||
f: i32,
|
||||
v: bool,
|
||||
s: i32,
|
||||
},
|
||||
|
||||
CellFormulaNumber {
|
||||
f: i32,
|
||||
v: f64,
|
||||
s: i32,
|
||||
},
|
||||
// always inline string
|
||||
#[serde(rename = "str")]
|
||||
CellFormulaString { f: i32, v: String, s: i32 },
|
||||
#[serde(rename = "fe")]
|
||||
CellFormulaString {
|
||||
f: i32,
|
||||
v: String,
|
||||
s: i32,
|
||||
},
|
||||
|
||||
CellFormulaError {
|
||||
f: i32,
|
||||
ei: Error,
|
||||
@@ -209,17 +196,16 @@ impl Default for Cell {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Comment {
|
||||
pub text: String,
|
||||
pub author_name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub author_id: Option<String>,
|
||||
pub cell_ref: String,
|
||||
}
|
||||
|
||||
// ECMA-376-1:2016 section 18.5.1.2
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Table {
|
||||
pub name: String,
|
||||
pub display_name: String,
|
||||
@@ -227,34 +213,24 @@ pub struct Table {
|
||||
pub reference: String,
|
||||
pub totals_row_count: u32,
|
||||
pub header_row_count: u32,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub header_row_dxf_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data_dxf_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub totals_row_dxf_id: Option<u32>,
|
||||
pub columns: Vec<TableColumn>,
|
||||
pub style_info: TableStyleInfo,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub has_filters: bool,
|
||||
}
|
||||
|
||||
// totals_row_label vs totals_row_function might be mutually exclusive. Use an enum?
|
||||
// the totals_row_function is an enum not String methinks
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct TableColumn {
|
||||
pub id: u32,
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub totals_row_label: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub header_row_dxf_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub data_dxf_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub totals_row_dxf_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub totals_row_function: Option<String>,
|
||||
}
|
||||
|
||||
@@ -272,25 +248,16 @@ impl Default for TableColumn {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Default)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, Default)]
|
||||
pub struct TableStyleInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<String>,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub show_first_column: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub show_last_column: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub show_row_stripes: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub show_column_stripes: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Styles {
|
||||
pub num_fmts: Vec<NumFmt>,
|
||||
pub fonts: Vec<Font>,
|
||||
@@ -326,7 +293,7 @@ pub struct Style {
|
||||
pub quote_prefix: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct NumFmt {
|
||||
pub num_fmt_id: i32,
|
||||
pub format_code: String,
|
||||
@@ -516,29 +483,17 @@ pub struct Alignment {
|
||||
pub wrap_text: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct CellStyleXfs {
|
||||
pub num_fmt_id: i32,
|
||||
pub font_id: i32,
|
||||
pub fill_id: i32,
|
||||
pub border_id: i32,
|
||||
#[serde(default = "default_as_true")]
|
||||
#[serde(skip_serializing_if = "is_true")]
|
||||
pub apply_number_format: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
#[serde(skip_serializing_if = "is_true")]
|
||||
pub apply_border: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
#[serde(skip_serializing_if = "is_true")]
|
||||
pub apply_alignment: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
#[serde(skip_serializing_if = "is_true")]
|
||||
pub apply_protection: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
#[serde(skip_serializing_if = "is_true")]
|
||||
pub apply_font: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
#[serde(skip_serializing_if = "is_true")]
|
||||
pub apply_fill: bool,
|
||||
}
|
||||
|
||||
@@ -559,39 +514,24 @@ impl Default for CellStyleXfs {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Default)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, Default)]
|
||||
pub struct CellXfs {
|
||||
pub xf_id: i32,
|
||||
pub num_fmt_id: i32,
|
||||
pub font_id: i32,
|
||||
pub fill_id: i32,
|
||||
pub border_id: i32,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub apply_number_format: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub apply_border: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub apply_alignment: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub apply_protection: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub apply_font: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub apply_fill: bool,
|
||||
#[serde(default = "default_as_false")]
|
||||
#[serde(skip_serializing_if = "is_false")]
|
||||
pub quote_prefix: bool,
|
||||
#[serde(skip_serializing_if = "is_default_alignment")]
|
||||
pub alignment: Option<Alignment>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct CellStyles {
|
||||
pub name: String,
|
||||
pub xf_id: i32,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use bitcode::{Decode, Encode};
|
||||
|
||||
use crate::{
|
||||
constants,
|
||||
@@ -18,19 +18,19 @@ use crate::{
|
||||
utils::is_valid_hex_color,
|
||||
};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
struct RowData {
|
||||
row: Option<Row>,
|
||||
data: HashMap<i32, Cell>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
struct ColumnData {
|
||||
column: Option<Col>,
|
||||
data: HashMap<i32, Cell>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
enum Diff {
|
||||
// Cell diffs
|
||||
SetCellValue {
|
||||
@@ -160,13 +160,13 @@ impl History {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
enum DiffType {
|
||||
Undo,
|
||||
Redo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
struct QueueDiffs {
|
||||
r#type: DiffType,
|
||||
list: DiffList,
|
||||
@@ -408,9 +408,9 @@ impl UserModel {
|
||||
///
|
||||
/// See also:
|
||||
/// * [UserModel::apply_external_diffs]
|
||||
pub fn flush_send_queue(&mut self) -> String {
|
||||
pub fn flush_send_queue(&mut self) -> Vec<u8> {
|
||||
// This can never fail :O:
|
||||
let q = serde_json::to_string(&self.send_queue).unwrap();
|
||||
let q = bitcode::encode(&self.send_queue);
|
||||
self.send_queue = vec![];
|
||||
q
|
||||
}
|
||||
@@ -421,8 +421,8 @@ impl UserModel {
|
||||
///
|
||||
/// See also:
|
||||
/// * [UserModel::flush_send_queue]
|
||||
pub fn apply_external_diffs(&mut self, diff_list_str: &str) -> Result<(), String> {
|
||||
if let Ok(queue_diffs_list) = serde_json::from_str::<Vec<QueueDiffs>>(diff_list_str) {
|
||||
pub fn apply_external_diffs(&mut self, diff_list_str: &[u8]) -> Result<(), String> {
|
||||
if let Ok(queue_diffs_list) = bitcode::decode::<Vec<QueueDiffs>>(diff_list_str) {
|
||||
for queue_diff in queue_diffs_list {
|
||||
if matches!(queue_diff.r#type, DiffType::Redo) {
|
||||
self.apply_diff_list(&queue_diff.list)?;
|
||||
@@ -845,6 +845,9 @@ impl UserModel {
|
||||
"fill.bg_color" => {
|
||||
style.fill.bg_color = color(value)?;
|
||||
}
|
||||
"fill.fg_color" => {
|
||||
style.fill.fg_color = color(value)?;
|
||||
}
|
||||
"num_fmt" => {
|
||||
style.num_fmt = value.to_owned();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user