numbat-cli-1.9.0/.cargo_vcs_info.json0000644000000001500000000000100130720ustar { "git": { "sha1": "3adf320e8aed1d904d6009118fcf2c077090c718" }, "path_in_vcs": "numbat-cli" }numbat-cli-1.9.0/Cargo.lock0000644000001063240000000000100110570ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anstream" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys 0.48.0", ] [[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "assert_cmd" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" dependencies = [ "anstyle", "bstr", "doc-comment", "predicates", "predicates-core", "predicates-tree", "wait-timeout", ] [[package]] name = "attohttpc" version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f77d243921b0979fbbd728dd2d5162e68ac8252976797c24eb5b3a6af9090dc" dependencies = [ "http", "log", "rustls", "url", "webpki-roots", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "bstr" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" dependencies = [ "memchr", "regex-automata", "serde", ] [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", "terminal_size", ] [[package]] name = "clap_derive" version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clipboard-win" version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c57002a5d9be777c1ef967e33674dac9ebd310d8893e4e3437b14d5f0f6372cc" dependencies = [ "error-code", ] [[package]] name = "codespan-reporting" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ "termcolor", "unicode-width", ] [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", "windows-sys 0.48.0", ] [[package]] name = "cpufeatures" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] name = "difflib" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", ] [[package]] name = "dirs" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ "dirs-sys 0.3.7", ] [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys 0.4.1", ] [[package]] name = "dirs-sys" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", "redox_users", "windows-sys 0.48.0", ] [[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "endian-type" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ "libc", "windows-sys 0.48.0", ] [[package]] name = "error-code" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "281e452d3bad4005426416cdba5ccfd4f5c1280e10099e21db27f7c1c28347fc" [[package]] name = "fd-lock" version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b93f7a0db71c99f68398f80653ed05afb0b00e062e1a20c7ff849c4edfabbbcc" dependencies = [ "cfg-if", "rustix", "windows-sys 0.52.0", ] [[package]] name = "float-cmp" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ "num-traits", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", ] [[package]] name = "getrandom" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "hashbrown" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "home" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "http" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "idna" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "indexmap" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "is-terminal" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", "windows-sys 0.48.0", ] [[package]] name = "itertools" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "linux-raw-sys" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "nibble_vec" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" dependencies = [ "smallvec", ] [[package]] name = "nix" version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ "bitflags 2.4.1", "cfg-if", "libc", ] [[package]] name = "normalize-line-endings" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num-bigint" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-format" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ "arrayvec", "itoa", ] [[package]] name = "num-integer" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", ] [[package]] name = "num-rational" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", "num-bigint", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "numbat" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83726f560b5b5cedfe5121cb9087b25e09a1b55ea1fa9ae88733a554bd923dc" dependencies = [ "codespan-reporting", "heck", "itertools", "libc", "num-format", "num-integer", "num-rational", "num-traits", "numbat-exchange-rates", "pretty_dtoa", "rust-embed", "strsim", "thiserror", "unicode-ident", "unicode-width", "walkdir", ] [[package]] name = "numbat-cli" version = "1.9.0" dependencies = [ "anyhow", "assert_cmd", "clap", "colored", "dirs 5.0.1", "itertools", "numbat", "predicates", "rustyline", "serde", "terminal_size", "toml", ] [[package]] name = "numbat-exchange-rates" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45c6b00450c221baa0aa982e73bab4902cbf82f7bda8ab9b49aa497781a6340b" dependencies = [ "attohttpc", "quick-xml", ] [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "percent-encoding" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "predicates" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" dependencies = [ "anstyle", "difflib", "float-cmp", "itertools", "normalize-line-endings", "predicates-core", "regex", ] [[package]] name = "predicates-core" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" dependencies = [ "predicates-core", "termtree", ] [[package]] name = "pretty_dtoa" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a239bcdfda2c685fda1add3b4695c06225f50075e3cfb5b954e91545587edff2" dependencies = [ "ryu_floating_decimal", ] [[package]] name = "proc-macro2" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ "memchr", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "radix_trie" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" dependencies = [ "endian-type", "nibble_vec", ] [[package]] name = "redox_syscall" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_users" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", "redox_syscall", "thiserror", ] [[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "ring" version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", "getrandom", "libc", "spin", "untrusted", "windows-sys 0.48.0", ] [[package]] name = "rust-embed" version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40" dependencies = [ "rust-embed-impl", "rust-embed-utils", "walkdir", ] [[package]] name = "rust-embed-impl" version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", "shellexpand", "syn", "walkdir", ] [[package]] name = "rust-embed-utils" version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada" dependencies = [ "sha2", "walkdir", ] [[package]] name = "rustix" version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", "windows-sys 0.48.0", ] [[package]] name = "rustls" version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring", "rustls-webpki", "sct", ] [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", ] [[package]] name = "rustyline" version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02a2d683a4ac90aeef5b1013933f6d977bd37d51ff3f4dad829d4931a7e6be86" dependencies = [ "bitflags 2.4.1", "cfg-if", "clipboard-win", "fd-lock", "home", "libc", "log", "memchr", "nix", "radix_trie", "rustyline-derive", "unicode-segmentation", "unicode-width", "utf8parse", "winapi", ] [[package]] name = "rustyline-derive" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5af959c8bf6af1aff6d2b463a57f71aae53d1332da58419e30ad8dc7011d951" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "ryu_floating_decimal" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "700de91d5fd6091442d00fdd9ee790af6d4f0f480562b0f5a1e8f59e90aafe73" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "sct" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", ] [[package]] name = "serde" version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_spanned" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "shellexpand" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" dependencies = [ "dirs 4.0.0", ] [[package]] name = "smallvec" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ "rustix", "windows-sys 0.48.0", ] [[package]] name = "termtree" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ "libc", ] [[package]] name = "walkdir" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "webpki-roots" version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.0", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ "windows_aarch64_gnullvm 0.52.0", "windows_aarch64_msvc 0.52.0", "windows_i686_gnu 0.52.0", "windows_i686_msvc 0.52.0", "windows_x86_64_gnu 0.52.0", "windows_x86_64_gnullvm 0.52.0", "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] numbat-cli-1.9.0/Cargo.toml0000644000000033250000000000100110770ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70" name = "numbat-cli" version = "1.9.0" authors = ["David Peter "] description = "A statically typed programming language for scientific computations with first class support for physical dimensions and units." homepage = "https://numbat.dev/" readme = "README.md" keywords = [ "language", "compiler", "physics", "units", "calculation", ] categories = [ "command-line-utilities", "science", "mathematics", "compilers", ] license = "MIT OR Apache-2.0" repository = "https://github.com/sharkdp/numbat" [[bin]] name = "numbat" path = "src/main.rs" [dependencies.anyhow] version = "1" [dependencies.clap] version = "4" features = [ "suggestions", "color", "wrap_help", "derive", ] [dependencies.colored] version = "2" [dependencies.dirs] version = "5" [dependencies.itertools] version = "0.11" [dependencies.numbat] version = "1.9.0" [dependencies.rustyline] version = "13" features = ["derive"] [dependencies.serde] version = "1.0.190" features = ["derive"] [dependencies.terminal_size] version = "0.3.0" [dependencies.toml] version = "0.8.6" features = ["parse"] [dev-dependencies.assert_cmd] version = "2" [dev-dependencies.predicates] version = "3" numbat-cli-1.9.0/Cargo.toml.orig000064400000000000000000000020531046102023000145550ustar 00000000000000[package] name = "numbat-cli" description = "A statically typed programming language for scientific computations with first class support for physical dimensions and units." authors = ["David Peter "] categories = ["command-line-utilities", "science", "mathematics", "compilers"] keywords = ["language", "compiler", "physics", "units", "calculation"] homepage = "https://numbat.dev/" repository = "https://github.com/sharkdp/numbat" version = "1.9.0" edition = "2021" license = "MIT OR Apache-2.0" readme = "../README.md" rust-version = "1.70" [dependencies] anyhow = "1" rustyline = { version = "13", features = ["derive"] } dirs = "5" numbat = { version = "1.9.0", path = "../numbat" } colored = "2" itertools = "0.11" toml = { version = "0.8.6", features = ["parse"] } serde = { version = "1.0.190", features = ["derive"] } terminal_size = "0.3.0" [dependencies.clap] version = "4" features = ["suggestions", "color", "wrap_help", "derive"] [dev-dependencies] assert_cmd = "2" predicates = "3" [[bin]] name = "numbat" path = "src/main.rs" numbat-cli-1.9.0/README.md000064400000000000000000000145061046102023000131530ustar 00000000000000
**[Try online!] • [Documentation] • [Tutorial] • [Syntax reference] • [Installation] • [Development]** [Try online!]: https://numbat.dev/ [Features]: #key-features [Documentation]: https://numbat.dev/doc/ [Tutorial]: https://numbat.dev/doc/tutorial.html [Syntax reference]: https://numbat.dev/doc/example-numbat_syntax.html [Installation]: https://numbat.dev/doc/cli-installation.html [Development]: #development *Numbat* is a statically typed programming language for scientific computations
with first class support for physical dimensions and units.
## Key Features *Click to learn more.*
Physical dimensions as types

Numbat has a static type system where physical dimensions like `Length` and `Time` act as types. Definitions of constants and functions can optionally contain type annotations that will be statically enforced. If the types are not specified, they will be inferred (`Speed`, `Money` and `Frequency` in the screenshot). See [this article](https://numbat.dev/doc/type-system.html) to learn more about Numbat's type system.
First-class physical units

Numbat is focused on computations with units. Units are therefore treated as first-class citizens. They can be [entered in various ways](https://numbat.dev/doc/unit-notation.html) (`km/h` or `kilometer/hour`, `GiB` or `gibibytes`, `°` or `degree`, `m²` or `m^2`). New units can be [introduced](https://numbat.dev/doc/unit-definitions.html) on the spot (`unit pixel`). Compatible units can be converted easily [using the `->` operator](https://numbat.dev/doc/unit-conversions.html) (`30 km/h -> mph`, `1 mrad -> degree`, `5 in + 2 ft -> cm`, `27 weeks -> days`). And unit expressions are simplified using various heuristics (`15 km/h * 30 min = 7.5 km`).
Comprehensive standard library

Numbat's [standard library](https://numbat.dev/doc/prelude.html) comes with a large number of physical dimensions and units (SI, US Customary, Imperial, Nautical, Astronomical, Atomic, Nuclear, …). See [this reference page](https://numbat.dev/doc/list-units.html) for a complete overview. It also contains a lot of [mathematical and physical constants](https://numbat.dev/doc/list-constants.html) as well as a large range of [pre-defined functions](https://numbat.dev/doc/list-functions.html).
Strict syntax

Numbat's parser never tries to be "smart" on syntactically incorrect input. This means you will either get a (descriptive) error message, or you can trust the result of your calculation.
Excellent error messages

Numbat aims to provide [descriptive and helpful error messages](https://github.com/sharkdp/numbat/blob/master/assets/numbat-error.png).
Interactive terminal

Numbat has been designed for an interactive use-case with small "one off" computations. Opening the `numbat` interpreter without any arguments starts a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) with a familiar readline interface, including all the usual features like a command history, Ctrl-R search or tab completion.
Modular and customizable

The whole system of physical dimensions and units is specified Numbat's standard library, which is [written in the Numbat language](https://github.com/sharkdp/numbat/tree/master/numbat/modules) itself. It is therefore easily extensible by [providing a `init.nbt` file](https://numbat.dev/doc/cli-customization.html). For example, a single line (`unit bathtub = 150 L`) is usually enough to add a new unit. Users can even choose to write their own `prelude` module, allowing for arbitrary modifications to the unit system.
Assertions

With its static type system, Numbat already enforces correctness of your calculations on a physical dimension level. But some checks can only be made at runtime. Numbat provides an `assert_eq` procedure that allows you to check for exact equality using `assert_eq(12 ft, 1 in)` or approximate equality using `assert_eq(c, 300_000 km/s, 1% × c)`. This can be useful to make sure that intermediate results do not change during a restructuring of your calculation.
Non-features

Numbat is a scientific calculator. It's not a computer algebra system that solves differential equations or computes intergrals. Try [WolframAlpha](http://www.wolframalpha.com/) instead.
There is no graphical user interface with buttons like `x²`, `1/x` or `DEG/RAD`. [Qalculate!](http://qalculate.github.io/) is a fantastic tool that supports both text as well as graphical input.
Numbat supports a huge range of physical units. If you need something even more comprehensive, please consider contributing. Or try [GNU units](https://www.gnu.org/software/units/).

 

 

 

 

## Installation See [this page](https://numbat.dev/doc/cli-installation.html) for details on how to install the native command-line version of Numbat. ## Development Run Numbat CLI ``` cargo run -- ``` Install the CLI version ``` cargo install -f --path numbat-cli ``` Run all tests ``` cargo test ``` ### Working on the `prelude` If you are working on [Numbat's standard library](numbat/modules/), it is convenient to point the `NUMBAT_MODULES_PATH` environment variable to the `numbat/modules/` folder. This way, you don't have to recompile Numbat to see your changes. Alternatively, you can create a symlink from `~/.config/numbat/modules` to the `numbat/modules/` folder in the repository (see [this page](https://numbat.dev/doc/cli-customization.html#module-paths) for the standard paths on other operating systems). ## Contact us To contact us, either [open a GitHub issue](https://github.com/sharkdp/numbat/issues/new/choose) or [discussion](https://github.com/sharkdp/numbat/discussions), or pop into `#numbat` on [Libera.Chat](https://libera.chat) ([link to webchat](https://web.libera.chat/gamja/#numbat)). numbat-cli-1.9.0/src/ansi_formatter.rs000064400000000000000000000020471046102023000160430ustar 00000000000000use numbat::markup::{FormatType, FormattedString, Formatter, Markup}; use colored::Colorize; pub struct ANSIFormatter; impl Formatter for ANSIFormatter { fn format_part( &self, FormattedString(_output_type, format_type, text): &FormattedString, ) -> String { (match format_type { FormatType::Whitespace => text.normal(), FormatType::Emphasized => text.bold(), FormatType::Dimmed => text.dimmed(), FormatType::Text => text.normal(), FormatType::String => text.green(), FormatType::Keyword => text.magenta(), FormatType::Value => text.yellow(), FormatType::Unit => text.cyan(), FormatType::Identifier => text.normal(), FormatType::TypeIdentifier => text.blue().italic(), FormatType::Operator => text.bold(), FormatType::Decorator => text.green(), }) .to_string() } } pub fn ansi_format(m: &Markup, indent: bool) -> String { ANSIFormatter {}.format(m, indent) } numbat-cli-1.9.0/src/completer.rs000064400000000000000000000061701046102023000150210ustar 00000000000000use std::sync::{Arc, Mutex}; use numbat::{unicode_input::UNICODE_INPUT, Context}; use rustyline::{ self, completion::{extract_word, Completer, Pair}, }; pub struct NumbatCompleter { pub context: Arc>, pub modules: Vec, } impl Completer for NumbatCompleter { type Candidate = Pair; fn complete( &self, line: &str, pos: usize, _: &rustyline::Context<'_>, ) -> rustyline::Result<(usize, Vec)> { for (patterns, replacement) in UNICODE_INPUT { for pattern in *patterns { let backslash_pattern = format!("\\{}", pattern); if line[..pos].ends_with(&backslash_pattern) { return Ok(( pos - (1 + pattern.len()), vec![Pair { display: backslash_pattern.to_string(), replacement: replacement.to_string(), }], )); } } } if line.starts_with("use ") { return Ok(( 0, self.modules .iter() .map(|m| { let line = format!("use {m}"); Pair { display: m.to_string(), replacement: line, } }) .filter(|p| p.replacement.starts_with(line)) .collect(), )); } else if line.starts_with("list ") || line.starts_with("ls ") { let command = if line.starts_with("list ") { "list" } else { "ls" }; return Ok(( 0, ["functions", "dimensions", "units", "variables"] .iter() .map(|category| { let line = format!("{command} {category}"); Pair { display: category.to_string(), replacement: line, } }) .filter(|p| p.replacement.starts_with(line)) .collect(), )); } let (pos_word, word_part) = extract_word(line, pos, None, |c| { // TODO: we could use is_identifier_char here potentially match c { c if c.is_alphanumeric() => false, '_' => false, _ => true, } }); // don't add an opening paren if we're completing after a reverse function call let add_paren = !line[..pos].find("//").is_some(); let candidates = self .context .lock() .unwrap() .get_completions_for(word_part, add_paren); Ok(( pos_word, candidates .map(|w| Pair { display: w.to_string(), replacement: w.to_string(), }) .collect(), )) } } numbat-cli-1.9.0/src/config.rs000064400000000000000000000037511046102023000142760ustar 00000000000000use clap::ValueEnum; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, PartialEq, Eq, Default, Debug, Clone, Copy, ValueEnum)] #[serde(rename_all = "kebab-case")] pub enum IntroBanner { #[default] Long, Short, Off, } #[derive(Debug, Clone, Copy, PartialEq, ValueEnum, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum PrettyPrintMode { Always, Never, Auto, } #[derive(Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct MainConfig { pub intro_banner: IntroBanner, pub prompt: String, pub pretty_print: PrettyPrintMode, #[serde(skip_serializing)] pub load_prelude: bool, #[serde(skip_serializing)] pub load_user_init: bool, } impl Default for MainConfig { fn default() -> Self { Self { prompt: ">>> ".to_owned(), intro_banner: IntroBanner::default(), pretty_print: PrettyPrintMode::Auto, load_prelude: true, load_user_init: true, } } } #[derive(Serialize, Deserialize, PartialEq, Eq, Default)] #[serde(rename_all = "kebab-case")] pub enum ExchangeRateFetchingPolicy { /// Always fetch exchange rates in the background when the application is started #[default] OnStartup, /// Fetch exchange rates when a currency symbol is used OnFirstUse, /// Never fetch exchange rates Never, } #[derive(Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct ExchangeRateConfig { pub fetching_policy: ExchangeRateFetchingPolicy, } impl Default for ExchangeRateConfig { fn default() -> Self { Self { fetching_policy: ExchangeRateFetchingPolicy::default(), } } } #[derive(Default, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct Config { #[serde(flatten)] pub main: MainConfig, pub exchange_rates: ExchangeRateConfig, } numbat-cli-1.9.0/src/highlighter.rs000064400000000000000000000033651046102023000153300ustar 00000000000000use colored::Colorize; use numbat::keywords::KEYWORDS; use numbat::{markup, Context}; use rustyline::{highlight::Highlighter, CompletionType}; use std::{ borrow::Cow, sync::{Arc, Mutex}, }; use crate::ansi_formatter::ansi_format; pub struct NumbatHighlighter { pub context: Arc>, } impl Highlighter for NumbatHighlighter { fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> { Cow::Borrowed(line) } fn highlight_prompt<'b, 's: 'b, 'p: 'b>( &self, prompt: &'p str, _default: bool, ) -> Cow<'b, str> { Cow::Owned(format!("{}", prompt.bold())) } fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { Cow::Borrowed(hint) } fn highlight_candidate<'c>( &self, candidate: &'c str, _completion: CompletionType, ) -> Cow<'c, str> { let ctx = self.context.lock().unwrap(); if ctx.variable_names().iter().any(|n| n == candidate) || ctx .function_names() .iter() .any(|n| format!("{}(", n) == candidate) { Cow::Owned(ansi_format(&markup::identifier(candidate), false)) } else if ctx .unit_names() .iter() .any(|un| un.iter().any(|n| n == candidate)) { Cow::Owned(ansi_format(&markup::unit(candidate), false)) } else if ctx.dimension_names().iter().any(|n| n == candidate) { Cow::Owned(ansi_format(&markup::type_identifier(candidate), false)) } else if KEYWORDS.iter().any(|k| k == &candidate) { Cow::Owned(ansi_format(&markup::keyword(candidate), false)) } else { Cow::Borrowed(candidate) } } } numbat-cli-1.9.0/src/main.rs000064400000000000000000000506471046102023000137630ustar 00000000000000mod ansi_formatter; mod completer; mod config; mod highlighter; use ansi_formatter::ansi_format; use completer::NumbatCompleter; use config::{Config, ExchangeRateFetchingPolicy, IntroBanner, PrettyPrintMode}; use highlighter::NumbatHighlighter; use itertools::Itertools; use numbat::diagnostic::ErrorDiagnostic; use numbat::help::help_markup; use numbat::markup as m; use numbat::module_importer::{BuiltinModuleImporter, ChainedImporter, FileSystemImporter}; use numbat::pretty_print::PrettyPrint; use numbat::resolver::CodeSource; use numbat::{Context, NumbatError}; use numbat::{InterpreterSettings, NameResolutionError}; use anyhow::{bail, Context as AnyhowContext, Result}; use clap::Parser; use rustyline::config::Configurer; use rustyline::{ self, error::ReadlineError, history::DefaultHistory, Completer, Editor, Helper, Hinter, Validator, }; use rustyline::{EventHandler, Highlighter, KeyCode, KeyEvent, Modifiers}; use toml; use std::io::IsTerminal; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::{fs, thread}; #[derive(Debug, PartialEq, Eq)] pub enum ExitStatus { Success, Error, } type ControlFlow = std::ops::ControlFlow; #[derive(Parser, Debug)] #[command(version, about, name("numbat"), max_term_width = 90)] struct Args { /// Path to source file with Numbat code. If none is given, an interactive /// session is started. file: Option, /// Evaluate a single expression. Can be specified multiple times to evaluate several expressions in sequence. #[arg( short, long, value_name = "CODE", conflicts_with = "file", action = clap::ArgAction::Append )] expression: Option>, /// Do not load the user configuration file. #[arg(long, hide_short_help = true)] no_config: bool, /// Do not load the prelude with predefined physical dimensions and units. This implies --no-init. #[arg(long, hide_short_help = true)] no_prelude: bool, /// Do not load the user init file. #[arg(long, hide_short_help = true)] no_init: bool, /// Whether or not to pretty-print every input expression. #[arg(long, value_name = "WHEN")] pretty_print: Option, /// What kind of intro banner to show (if any). #[arg(long, value_name = "MODE")] intro_banner: Option, /// Generate a default configuration file #[arg(long, hide_short_help = true)] generate_config: bool, /// Turn on debug mode and print disassembler output (hidden, mainly for development) #[arg(long, short, hide = true)] debug: bool, } #[derive(Debug, Clone, Copy, PartialEq)] enum ExecutionMode { Normal, Interactive, } impl ExecutionMode { fn exit_status_in_case_of_error(&self) -> ControlFlow { if matches!(self, ExecutionMode::Normal) { ControlFlow::Break(ExitStatus::Error) } else { ControlFlow::Continue(()) } } } #[derive(Completer, Helper, Hinter, Validator, Highlighter)] struct NumbatHelper { #[rustyline(Completer)] completer: NumbatCompleter, #[rustyline(Highlighter)] highlighter: NumbatHighlighter, } struct Cli { config: Config, context: Arc>, file: Option, expression: Option>, } impl Cli { fn new(args: Args) -> Result { let user_config_path = Self::get_config_path().join("config.toml"); let mut config = if args.no_config { Config::default() } else if let Ok(contents) = fs::read_to_string(&user_config_path) { toml::from_str(&contents).context(format!( "Error while loading {}", user_config_path.to_string_lossy() ))? } else { Config::default() }; config.main.load_prelude &= !args.no_prelude; config.main.load_user_init &= !(args.no_prelude || args.no_init); config.main.intro_banner = args.intro_banner.unwrap_or(config.main.intro_banner); config.main.pretty_print = args.pretty_print.unwrap_or(config.main.pretty_print); let mut fs_importer = FileSystemImporter::default(); for path in Self::get_modules_paths() { fs_importer.add_path(path); } let importer = ChainedImporter::new( Box::new(fs_importer), Box::::default(), ); let mut context = Context::new(importer); context.set_debug(args.debug); context.set_terminal_width( terminal_size::terminal_size().map(|(terminal_size::Width(w), _)| w as usize), ); Ok(Self { context: Arc::new(Mutex::new(context)), config, file: args.file, expression: args.expression, }) } fn run(&mut self) -> Result<()> { if self.config.main.load_prelude { let result = self.parse_and_evaluate( "use prelude", CodeSource::Internal, ExecutionMode::Normal, PrettyPrintMode::Never, ); if result.is_break() { bail!("Interpreter error in Prelude code") } } if self.config.main.load_user_init { let user_init_path = Self::get_config_path().join("init.nbt"); if let Ok(user_init_code) = fs::read_to_string(&user_init_path) { let result = self.parse_and_evaluate( &user_init_code, CodeSource::File(user_init_path), ExecutionMode::Normal, PrettyPrintMode::Never, ); if result.is_break() { bail!("Interpreter error in user initialization code") } } } if self.config.main.load_prelude && self.config.exchange_rates.fetching_policy != ExchangeRateFetchingPolicy::Never { { self.context .lock() .unwrap() .load_currency_module_on_demand(true); } if self.config.exchange_rates.fetching_policy == ExchangeRateFetchingPolicy::OnStartup { thread::spawn(move || { numbat::Context::prefetch_exchange_rates(); }); } } let code_and_source: Option<(String, CodeSource)> = if let Some(ref path) = self.file { Some(( fs::read_to_string(path).context(format!( "Could not load source file '{}'", path.to_string_lossy() ))?, CodeSource::File(path.clone()), )) } else { self.expression .as_ref() .map(|exprs| (exprs.iter().join("\n"), CodeSource::Text)) }; if let Some((code, code_source)) = code_and_source { let result = self.parse_and_evaluate( &code, code_source, ExecutionMode::Normal, self.config.main.pretty_print, ); match result { std::ops::ControlFlow::Continue(()) => Ok(()), std::ops::ControlFlow::Break(ExitStatus::Success) => Ok(()), std::ops::ControlFlow::Break(ExitStatus::Error) => { bail!("Interpreter stopped due to error") } } } else { self.repl() } } fn repl(&mut self) -> Result<()> { let interactive = std::io::stdin().is_terminal(); let history_path = self.get_history_path()?; let mut rl = Editor::::new()?; rl.set_max_history_size(1000) .context("Error while configuring history size")?; rl.set_completion_type(rustyline::CompletionType::List); rl.set_helper(Some(NumbatHelper { completer: NumbatCompleter { context: self.context.clone(), modules: self.context.lock().unwrap().list_modules().collect(), }, highlighter: NumbatHighlighter { context: self.context.clone(), }, })); rl.bind_sequence( KeyEvent(KeyCode::Enter, Modifiers::ALT), EventHandler::Simple(rustyline::Cmd::Newline), ); rl.load_history(&history_path).ok(); if interactive { match self.config.main.intro_banner { IntroBanner::Long => { println!(); println!( " █▄░█ █░█ █▀▄▀█ █▄▄ ▄▀█ ▀█▀ Numbat {}", env!("CARGO_PKG_VERSION") ); println!( " █░▀█ █▄█ █░▀░█ █▄█ █▀█ ░█░ {}", env!("CARGO_PKG_HOMEPAGE") ); println!(); } IntroBanner::Short => { println!("Numbat {}", env!("CARGO_PKG_VERSION")); } IntroBanner::Off => {} } } let result = self.repl_loop(&mut rl, interactive); if interactive { rl.save_history(&history_path).context(format!( "Error while saving history to '{}'", history_path.to_string_lossy() ))?; } result } fn repl_loop( &mut self, rl: &mut Editor, interactive: bool, ) -> Result<()> { loop { let readline = rl.readline(&self.config.main.prompt); match readline { Ok(line) => { if !line.trim().is_empty() { rl.add_history_entry(&line)?; match line.trim() { "list" | "ls" => { println!( "{}", ansi_format( &self.context.lock().unwrap().print_environment(), false ) ); } "list functions" | "ls functions" => { println!( "{}", ansi_format( &self.context.lock().unwrap().print_functions(), false ) ); } "list dimensions" | "ls dimensions" => { println!( "{}", ansi_format( &self.context.lock().unwrap().print_dimensions(), false ) ); } "list variables" | "ls variables" => { println!( "{}", ansi_format( &self.context.lock().unwrap().print_variables(), false ) ); } "list units" | "ls units" => { println!( "{}", ansi_format(&self.context.lock().unwrap().print_units(), false) ); } "clear" => { rl.clear_screen()?; } "quit" | "exit" => { return Ok(()); } "help" | "?" => { let help = help_markup(); print!("{}", ansi_format(&help, true)); // currently, the ansi formatter adds indents // _after_ each newline and so we need to manually // add an extra blank line to absorb this indent println!(); } _ => { if let Some(keyword) = line.strip_prefix("info") { let help = self .context .lock() .unwrap() .print_info_for_keyword(keyword.trim()); println!("{}", ansi_format(&help, true)); continue; } let result = self.parse_and_evaluate( &line, CodeSource::Text, if interactive { ExecutionMode::Interactive } else { ExecutionMode::Normal }, self.config.main.pretty_print, ); match result { std::ops::ControlFlow::Continue(()) => {} std::ops::ControlFlow::Break(ExitStatus::Success) => { return Ok(()); } std::ops::ControlFlow::Break(ExitStatus::Error) => { bail!("Interpreter stopped due to error") } } } } } } Err(ReadlineError::Interrupted) => {} Err(ReadlineError::Eof) => { return Ok(()); } Err(err) => { bail!(err); } } } } #[must_use] fn parse_and_evaluate( &mut self, input: &str, code_source: CodeSource, execution_mode: ExecutionMode, pretty_print_mode: PrettyPrintMode, ) -> ControlFlow { let to_be_printed: Arc>> = Arc::new(Mutex::new(vec![])); let to_be_printed_c = to_be_printed.clone(); let mut settings = InterpreterSettings { print_fn: Box::new(move |s: &m::Markup| { to_be_printed_c.lock().unwrap().push(s.clone()); }), }; let (result, registry) = { let mut ctx = self.context.lock().unwrap(); let registry = ctx.dimension_registry().clone(); // TODO: get rid of this clone ( ctx.interpret_with_settings(&mut settings, input, code_source), registry, ) }; let interactive = execution_mode == ExecutionMode::Interactive; let pretty_print = match pretty_print_mode { PrettyPrintMode::Always => true, PrettyPrintMode::Never => false, PrettyPrintMode::Auto => interactive, }; match result { Ok((statements, interpreter_result)) => { if interactive || pretty_print { println!(); } if pretty_print { for statement in &statements { let repr = ansi_format(&statement.pretty_print(), true); println!("{}", repr); println!(); } } let to_be_printed = to_be_printed.lock().unwrap(); for s in to_be_printed.iter() { println!("{}", ansi_format(s, interactive)); } if interactive && !to_be_printed.is_empty() { println!(); } let result_markup = interpreter_result.to_markup( statements.last(), ®istry, interactive || pretty_print, ); print!("{}", ansi_format(&result_markup, false)); if (interactive || pretty_print) && interpreter_result.is_value() { println!(); } ControlFlow::Continue(()) } Err(NumbatError::ResolverError(e)) => { self.print_diagnostic(e.clone()); execution_mode.exit_status_in_case_of_error() } Err(NumbatError::NameResolutionError( e @ (NameResolutionError::IdentifierClash { .. } | NameResolutionError::ReservedIdentifier(_)), )) => { self.print_diagnostic(e); execution_mode.exit_status_in_case_of_error() } Err(NumbatError::TypeCheckError(e)) => { self.print_diagnostic(e); execution_mode.exit_status_in_case_of_error() } Err(NumbatError::RuntimeError(e)) => { self.print_diagnostic(e); execution_mode.exit_status_in_case_of_error() } } } fn print_diagnostic(&mut self, error: impl ErrorDiagnostic) { self.context.lock().unwrap().print_diagnostic(error) } fn get_config_path() -> PathBuf { let config_dir = dirs::config_dir().unwrap_or_else(|| PathBuf::from(".")); config_dir.join("numbat") } fn get_modules_paths() -> Vec { let mut paths = vec![]; if let Some(modules_path) = std::env::var_os("NUMBAT_MODULES_PATH") { for path in modules_path.to_string_lossy().split(':') { paths.push(path.into()); } } paths.push(Self::get_config_path().join("modules")); // We read the value of this environment variable at compile time to // allow package maintainers to control the system-wide module path // for Numbat. if let Some(system_module_path) = option_env!("NUMBAT_SYSTEM_MODULE_PATH") { if !system_module_path.is_empty() { paths.push(system_module_path.into()); } } else if cfg!(unix) { paths.push("/usr/share/numbat/modules".into()); } else { paths.push("C:\\Program Files\\numbat\\modules".into()); } paths } fn get_history_path(&self) -> Result { let data_dir = dirs::data_dir() .unwrap_or_else(|| PathBuf::from(".")) .join("numbat"); fs::create_dir(&data_dir).ok(); Ok(data_dir.join("history")) } } fn generate_config() -> Result<()> { let config_folder_path = Cli::get_config_path(); let config_file_path = config_folder_path.join("config.toml"); if config_file_path.exists() { bail!( "The file '{}' exists already.", config_file_path.to_string_lossy() ); } std::fs::create_dir_all(&config_folder_path).context(format!( "Error while creating folder '{}'", config_folder_path.to_string_lossy() ))?; let config = Config::default(); let content = toml::to_string(&config).context("Error while creating TOML from config")?; std::fs::write(&config_file_path, content)?; println!( "A default configuration has been written to '{}'.", config_file_path.to_string_lossy() ); println!("Open the file in a text editor. Modify whatever you want to change and remove the other fields"); Ok(()) } fn main() { let args = Args::parse(); if args.generate_config { if let Err(e) = generate_config() { eprintln!("{:#}", e); std::process::exit(1); } std::process::exit(0); } if let Err(e) = Cli::new(args).and_then(|mut cli| cli.run()) { eprintln!("{:#}", e); std::process::exit(1); } } numbat-cli-1.9.0/tests/examples/parser_error.nbt000064400000000000000000000000071046102023000200550ustar 00000000000000(3+4)) numbat-cli-1.9.0/tests/examples/pendulum.nbt000064400000000000000000000001761046102023000172100ustar 00000000000000fn oscillation_time(length: Length) -> Time = 2 pi × sqrt(length / g0) assert_eq(oscillation_time(30 cm), 1.1 s, 0.1 s) numbat-cli-1.9.0/tests/examples/print.nbt000064400000000000000000000001311046102023000165020ustar 00000000000000print(1) print(2 meter) print("hello world") print("pi = {pi}") print("1 + 2 = {1 + 2}") numbat-cli-1.9.0/tests/integration.rs000064400000000000000000000064561046102023000157340ustar 00000000000000use std::path::Path; use assert_cmd::Command; use predicates::boolean::PredicateBooleanExt; fn numbat() -> Command { let module_path = Path::new(&std::env::var_os("CARGO_MANIFEST_DIR").unwrap()) .parent() .unwrap() .join("numbat") .join("modules"); std::env::set_var("NUMBAT_MODULES_PATH", module_path); let mut cmd = Command::cargo_bin("numbat").unwrap(); cmd.arg("--no-init"); cmd.arg("--no-config"); cmd } #[test] fn pass_expression_on_command_line() { numbat() .arg("--expression") .arg("2 meter + 3 meter") .assert() .success() .stdout(predicates::str::contains("5 m")); numbat() .arg("-e") .arg("let x = 2") .arg("-e") .arg("x^3") .assert() .success() .stdout(predicates::str::contains("8")); numbat() .arg("--expression") .arg("2 +/ 3") .assert() .stderr(predicates::str::contains("while parsing")); numbat() .arg("--expression") .arg("2 meter + 3 second") .assert() .failure() .stderr(predicates::str::contains("while type checking")); numbat() .arg("--expression") .arg("1/0") .assert() .failure() .stderr(predicates::str::contains("runtime error")); numbat() .arg("--expression") .arg("type(2 m/s)") .assert() .success() .stdout(predicates::str::contains("Length / Time")); } #[test] fn read_code_from_file() { numbat() .arg("tests/examples/pendulum.nbt") .assert() .success(); numbat() .arg("tests/examples/parser_error.nbt") .assert() .failure() .stderr(predicates::str::contains("while parsing")); } #[test] fn print_calls() { numbat() .arg("tests/examples/print.nbt") .assert() .success() .stdout(predicates::str::contains( "1 \n2 m\nhello world\npi = 3.14159\n1 + 2 = 3\n", )); } #[test] fn without_prelude() { numbat() .arg("--no-prelude") .arg("--expression") .arg("2.1 + 3.1") .assert() .success() .stdout(predicates::str::contains("5.2")); numbat() .arg("--no-prelude") .arg("--expression") .arg("1 meter") .assert() .failure() .stderr(predicates::str::contains("unknown identifier")); } #[test] fn pretty_printing() { numbat() .arg("--pretty-print=always") .arg("--expression") .arg("let v=30km/h") .assert() .success() .stdout(predicates::str::contains( "let v: Velocity = 30 kilometre / hour", )); } #[test] fn help_text() { numbat() .write_stdin("help") .assert() .success() .stdout(predicates::str::contains( "Energy of red photons: 1.87855 eV", )); } #[test] fn info_text() { numbat().write_stdin("info g0").assert().success().stdout( predicates::str::contains("Standard acceleration of gravity on earth") .and(predicates::str::contains("9.80665 m/s²")), ); numbat().write_stdin("info C").assert().success().stdout( predicates::str::contains("Coulomb").and(predicates::str::contains("1 coulomb = ")), ); }