Rust · 2619 bytes Raw Blame History
1 //! garcalc - TI-Nspire-like calculator for gardesk
2 //!
3 //! A full-featured graphical calculator with CAS, graphing,
4 //! geometry, spreadsheet, and notes capabilities.
5
6 mod app;
7 mod config;
8 mod ipc;
9 mod ui;
10
11 use anyhow::Result;
12 use clap::Parser;
13 use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
14
15 #[derive(Parser, Debug)]
16 #[command(name = "garcalc")]
17 #[command(about = "TI-Nspire-like calculator for gardesk")]
18 #[command(version)]
19 struct Args {
20 /// Run as popup (centered, closes on focus loss)
21 #[arg(short, long)]
22 popup: bool,
23
24 /// Run as daemon (listen for IPC commands)
25 #[arg(short, long)]
26 daemon: bool,
27
28 /// Initial mode (calculator, graph, graph3d, geometry, spreadsheet, notes)
29 #[arg(short, long, default_value = "calculator")]
30 mode: String,
31
32 /// Expression to evaluate (exits after evaluation)
33 #[arg(short, long)]
34 eval: Option<String>,
35 }
36
37 fn main() -> Result<()> {
38 // Initialize logging
39 tracing_subscriber::registry()
40 .with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
41 .with(tracing_subscriber::fmt::layer())
42 .init();
43
44 let args = Args::parse();
45
46 // Quick eval mode - just evaluate and exit
47 if let Some(expr) = args.eval {
48 return eval_and_exit(&expr);
49 }
50
51 if args.daemon {
52 run_daemon()
53 } else {
54 run_calculator(&args)
55 }
56 }
57
58 fn eval_and_exit(expr: &str) -> Result<()> {
59 let parsed = garcalc_cas::parser::parse(expr)?;
60 let evaluator = garcalc_cas::Evaluator::new();
61 let result = evaluator.eval(&parsed)?;
62 println!("{result}");
63 Ok(())
64 }
65
66 fn run_daemon() -> Result<()> {
67 tracing::info!("Starting garcalc daemon");
68
69 let runtime = tokio::runtime::Runtime::new()?;
70 runtime.block_on(async {
71 let mut server = ipc::IpcServer::new().await?;
72 server.run().await
73 })
74 }
75
76 fn run_calculator(args: &Args) -> Result<()> {
77 let mode = match args.mode.to_lowercase().as_str() {
78 "calc" | "calculator" => garcalc_ipc::Mode::Calculator,
79 "graph" | "graphing" | "2d" => garcalc_ipc::Mode::Graph,
80 "graph3d" | "3d" | "surface" => garcalc_ipc::Mode::Graph3D,
81 "geo" | "geometry" => garcalc_ipc::Mode::Geometry,
82 "sheet" | "spreadsheet" => garcalc_ipc::Mode::Spreadsheet,
83 "notes" | "note" => garcalc_ipc::Mode::Notes,
84 _ => {
85 tracing::warn!("Unknown mode '{}', defaulting to calculator", args.mode);
86 garcalc_ipc::Mode::Calculator
87 }
88 };
89
90 let mut app = app::App::new(mode, args.popup)?;
91 app.run()
92 }
93