use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AppMode {
Normal,
Searching,
SelectByRegex,
ExpressionInput,
TypeSelect,
Editing,
Loading,
AggregatorSelect,
GPrefix,
Chart,
Saving,
ZPrefix,
RenamingColumn,
InsertingColumn,
Calculating,
ConfirmQuit,
YPrefix,
CopyFormatSelect,
CurrencySelect,
PivotTableInput,
Help,
PartitionSelect,
ChartAggSelect,
JoinSelectSource,
JoinInputPath,
JoinSelectType,
JoinSelectLeftKeys,
JoinSelectRightKeys,
JoinOverviewSelect,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum SheetType {
Normal,
FrequencyTable { group_cols: Vec<String> },
PivotTable {
index_cols: Vec<String>,
pivot_col: String,
formula: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Action {
Quit,
ConfirmQuitYes,
ConfirmQuitNo,
PopSheet,
Undo,
Redo,
MoveUp,
MoveDown,
MoveLeft,
MoveRight,
PageUp,
PageDown,
GoTop,
GoBottom,
SortAscending,
SortDescending,
TransposeRow,
TransposeTable,
DescribeSheet,
DeduplicateByPinned,
ResetSort,
ReloadFile,
StartSearch,
SearchInput(char),
SearchBackspace,
SearchForwardDelete,
SearchCursorLeft,
SearchCursorRight,
SearchCursorStart,
SearchCursorEnd,
ApplySearch,
CancelSearch,
SearchNext,
SearchPrev,
ClearSearch,
SelectByValue,
StartSelectByRegex,
SelectRegexInput(char),
SelectRegexBackspace,
SelectRegexForwardDelete,
SelectRegexCursorLeft,
SelectRegexCursorRight,
SelectRegexCursorStart,
SelectRegexCursorEnd,
ApplySelectByRegex,
CancelSelectByRegex,
SelectRegexAutocomplete,
StartExpression,
ExpressionInputChar(char),
ExpressionBackspace,
ExpressionForwardDelete,
ExpressionCursorLeft,
ExpressionCursorRight,
ExpressionCursorStart,
ExpressionCursorEnd,
ApplyExpression,
CancelExpression,
ExpressionAutocomplete,
ExpressionHistoryPrev,
ExpressionHistoryNext,
OpenFrequencyTable,
OpenPivotTableInput,
ApplyPivotTable,
CancelPivotTable,
PivotInput(char),
PivotBackspace,
PivotForwardDelete,
PivotCursorLeft,
PivotCursorRight,
PivotCursorStart,
PivotCursorEnd,
PivotAutocomplete,
PivotHistoryPrev,
PivotHistoryNext,
OpenChart,
ChartAggSelectUp,
ChartAggSelectDown,
ApplyChartAgg,
CancelChartAgg,
OpenTypeSelect,
TypeSelectUp,
TypeSelectDown,
ApplyTypeSelect,
CancelTypeSelect,
CurrencySelectUp,
CurrencySelectDown,
ApplyCurrencySelect,
CancelCurrencySelect,
StartEdit,
ApplyEdit,
CancelEdit,
EditInput(char),
EditBackspace,
EditForwardDelete,
EditCursorLeft,
EditCursorRight,
EditCursorStart,
EditCursorEnd,
OpenRow,
SaveFile,
SavingInput(char),
SavingBackspace,
SavingForwardDelete,
SavingCursorLeft,
SavingCursorRight,
SavingCursorStart,
SavingCursorEnd,
ApplySave,
CancelSave,
SavingAutocomplete,
EnterZPrefix,
CancelZPrefix,
StartRenameColumn,
RenameColumnInput(char),
RenameColumnBackspace,
RenameColumnForwardDelete,
RenameColumnCursorLeft,
RenameColumnCursorRight,
RenameColumnCursorStart,
RenameColumnCursorEnd,
ApplyRenameColumn,
CancelRenameColumn,
DeleteColumn,
StartInsertColumn,
InsertColumnInput(char),
InsertColumnBackspace,
InsertColumnForwardDelete,
InsertColumnCursorLeft,
InsertColumnCursorRight,
InsertColumnCursorStart,
InsertColumnCursorEnd,
ApplyInsertColumn,
CancelInsertColumn,
SelectColumn,
UnselectColumn,
MoveColumnLeft,
MoveColumnRight,
AdjustColumnWidth,
AdjustAllColumnWidths,
IncreasePrecision,
DecreasePrecision,
CreatePctColumn,
OpenPartitionSelect,
ApplyPartitionedPct,
PartitionSelectUp,
PartitionSelectDown,
TogglePartitionSelection,
CancelPartitionSelect,
OpenAggregatorSelect,
ApplyAggregators,
AggregatorSelectUp,
AggregatorSelectDown,
ToggleAggregatorSelection,
ClearAggregators,
CancelAggregatorSelect,
QuickAggregate,
SelectRow, UnselectRow, EnterGPrefix, CancelGPrefix, SelectAllRows, UnselectAllRows,
PasteRows, DeleteSelectedRows, EnterYPrefix, CancelYPrefix, CopyCurrentCell, OpenCopyFormat(CopyPending), CopyFormatSelectUp,
CopyFormatSelectDown,
ApplyCopyFormat,
CancelCopyFormat,
CreateSheetFromSelection,
TogglePinColumn,
OpenMultiFrequencyTable,
ShowHelp,
CloseHelp,
OpenJoin,
JoinSourceUp,
JoinSourceDown,
JoinSourceApply,
JoinSourceCancel,
JoinPathInput(char),
JoinPathBackspace,
JoinPathForwardDelete,
JoinPathCursorLeft,
JoinPathCursorRight,
JoinPathCursorStart,
JoinPathCursorEnd,
JoinPathApply,
JoinPathCancel,
JoinPathAutocomplete,
JoinTypeUp,
JoinTypeDown,
JoinTypeApply,
JoinTypeCancel,
JoinLeftKeyUp,
JoinLeftKeyDown,
JoinLeftKeyToggle,
JoinLeftKeyApply,
JoinLeftKeyCancel,
JoinRightKeyUp,
JoinRightKeyDown,
JoinRightKeyToggle,
JoinRightKeyApply,
JoinRightKeyCancel,
OpenExternalEditor,
JoinOverviewUp,
JoinOverviewDown,
JoinOverviewToggle,
JoinOverviewApply,
JoinOverviewCancel,
None,
}
#[derive(Clone, Debug)]
pub enum JoinContextItem {
SqliteTable {
db_path: PathBuf,
table_name: String,
},
DuckdbTable {
db_path: PathBuf,
table_name: String,
},
DirectoryFile {
file_path: PathBuf,
},
XlsxSheet {
xlsx_path: PathBuf,
sheet_name: String,
},
}
impl JoinContextItem {
pub fn label(&self) -> String {
match self {
Self::SqliteTable { table_name, .. } => table_name.clone(),
Self::DuckdbTable { table_name, .. } => table_name.clone(),
Self::DirectoryFile { file_path } => file_path
.file_name()
.map(|n| n.to_string_lossy().into_owned())
.unwrap_or_default(),
Self::XlsxSheet { sheet_name, .. } => sheet_name.clone(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CopyPending {
SmartRows,
SmartColumn,
WholeColumn,
WholeTable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ColumnType {
String,
Integer,
Float,
Date,
Datetime,
Boolean,
Percentage,
Currency,
}
impl ColumnType {
pub fn all() -> &'static [ColumnType] {
&[
Self::String,
Self::Integer,
Self::Float,
Self::Date,
Self::Datetime,
Self::Boolean,
Self::Percentage,
Self::Currency,
]
}
pub fn display_name(&self) -> &'static str {
match self {
Self::String => "s String",
Self::Integer => "# Integer",
Self::Float => "~ Float",
Self::Date => "d Date",
Self::Datetime => "t Datetime",
Self::Boolean => "? Boolean",
Self::Percentage => "% Percentage",
Self::Currency => "$ Currency",
}
}
pub fn icon(&self) -> char {
match self {
Self::String => 's',
Self::Integer => '#',
Self::Float => '~',
Self::Date => 'd',
Self::Datetime => 't',
Self::Boolean => '?',
Self::Percentage => '%',
Self::Currency => '$',
}
}
}
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CurrencyKind {
USD,
EUR,
JPY,
GBP,
RUB,
CNY,
UAH,
KZT,
GEL,
AMD,
AUD,
CAD,
CHF,
HKD,
SGD,
NOK,
KRW,
SEK,
NZD,
INR,
TWD,
ZAR,
BRL,
MXN,
}
impl CurrencyKind {
pub fn all() -> &'static [CurrencyKind] {
&[
Self::USD,
Self::EUR,
Self::JPY,
Self::GBP,
Self::RUB,
Self::CNY,
Self::UAH,
Self::KZT,
Self::GEL,
Self::AMD,
Self::AUD,
Self::CAD,
Self::CHF,
Self::HKD,
Self::SGD,
Self::NOK,
Self::KRW,
Self::SEK,
Self::NZD,
Self::INR,
Self::TWD,
Self::ZAR,
Self::BRL,
Self::MXN,
]
}
pub fn symbol(self) -> &'static str {
match self {
Self::USD => "$",
Self::EUR => "€",
Self::JPY => "¥",
Self::GBP => "£",
Self::RUB => "₽",
Self::CNY => "CN¥",
Self::UAH => "₴",
Self::KZT => "₸",
Self::GEL => "₾",
Self::AMD => "֏",
Self::AUD => "A$",
Self::CAD => "C$",
Self::CHF => "CHF",
Self::HKD => "HK$",
Self::SGD => "S$",
Self::NOK => "Nkr",
Self::KRW => "₩",
Self::SEK => "Skr",
Self::NZD => "NZ$",
Self::INR => "₹",
Self::TWD => "NT$",
Self::ZAR => "R",
Self::BRL => "R$",
Self::MXN => "MX$",
}
}
pub fn is_prefix(self) -> bool {
matches!(
self,
Self::USD
| Self::GBP
| Self::JPY
| Self::CNY
| Self::AUD
| Self::CAD
| Self::HKD
| Self::SGD
| Self::NZD
| Self::INR
| Self::TWD
| Self::BRL
| Self::MXN
| Self::KRW
| Self::CHF
)
}
pub fn display_name(self) -> &'static str {
match self {
Self::USD => "$ USD (Dollar)",
Self::EUR => "€ EUR (Euro)",
Self::JPY => "¥ JPY (Yen)",
Self::GBP => "£ GBP (Pound)",
Self::RUB => "₽ RUB (Rouble)",
Self::CNY => "CN¥ CNY (Yuan)",
Self::UAH => "₴ UAH (Hryvnia)",
Self::KZT => "₸ KZT (Tenge)",
Self::GEL => "₾ GEL (Lari)",
Self::AMD => "֏ AMD (Dram)",
Self::AUD => "A$ AUD (Australian Dollar)",
Self::CAD => "C$ CAD (Canadian Dollar)",
Self::CHF => "CHF CHF (Swiss Franc)",
Self::HKD => "HK$ HKD (Hong Kong Dollar)",
Self::SGD => "S$ SGD (Singapore Dollar)",
Self::NOK => "Nkr NOK (Norwegian Krone)",
Self::KRW => "₩ KRW (Won)",
Self::SEK => "Skr SEK (Swedish Krona)",
Self::NZD => "NZ$ NZD (New Zealand Dollar)",
Self::INR => "₹ INR (Indian Rupee)",
Self::TWD => "NT$ TWD (New Taiwan Dollar)",
Self::ZAR => "R ZAR (Rand)",
Self::BRL => "R$ BRL (Real)",
Self::MXN => "MX$ MXN (Mexican Peso)",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChartAgg {
Sum,
Count,
Mean,
Median,
Min,
Max,
}
impl ChartAgg {
pub fn all() -> &'static [ChartAgg] {
&[
Self::Sum,
Self::Count,
Self::Mean,
Self::Median,
Self::Min,
Self::Max,
]
}
pub fn label(self) -> &'static str {
match self {
Self::Sum => "sum",
Self::Count => "count",
Self::Mean => "mean",
Self::Median => "median",
Self::Min => "min",
Self::Max => "max",
}
}
pub fn apply_group(self, count: usize, vals: &[f64]) -> f64 {
match self {
Self::Count => count as f64,
Self::Sum => vals.iter().sum(),
Self::Mean => {
if vals.is_empty() {
0.0
} else {
vals.iter().sum::<f64>() / vals.len() as f64
}
}
Self::Median => {
if vals.is_empty() {
return 0.0;
}
let mut s = vals.to_vec();
s.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let n = s.len();
if n.is_multiple_of(2) {
(s[n / 2 - 1] + s[n / 2]) / 2.0
} else {
s[n / 2]
}
}
Self::Min => vals.iter().cloned().fold(f64::INFINITY, f64::min),
Self::Max => vals.iter().cloned().fold(f64::NEG_INFINITY, f64::max),
}
}
}