add numbat as calculator engine

This commit is contained in:
mat 2024-04-13 00:52:28 -05:00
parent 052e266985
commit afef2e25ff
9 changed files with 676 additions and 10 deletions

467
Cargo.lock generated
View File

@ -82,6 +82,12 @@ dependencies = [
"libc",
]
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "async-compression"
version = "0.4.6"
@ -129,6 +135,19 @@ dependencies = [
"syn 2.0.52",
]
[[package]]
name = "attohttpc"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "184f5e6cce583a9db6b6f8d772a42cfce5b78e7c3ef26118cec3ce4c8c14969b"
dependencies = [
"http 1.0.0",
"log",
"rustls 0.22.3",
"url",
"webpki-roots 0.26.1",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -227,6 +246,15 @@ version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[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 = "brotli"
version = "3.4.0"
@ -316,6 +344,16 @@ dependencies = [
"uncased",
]
[[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 = "core-foundation"
version = "0.9.4"
@ -332,6 +370,15 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.4.0"
@ -341,6 +388,16 @@ dependencies = [
"cfg-if",
]
[[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 = "cssparser"
version = "0.31.2"
@ -375,6 +432,37 @@ dependencies = [
"syn 1.0.109",
]
[[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 = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
dependencies = [
"dirs-sys",
]
[[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 = "dtoa"
version = "1.0.9"
@ -396,6 +484,12 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591"
[[package]]
name = "either"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
[[package]]
name = "encoding_rs"
version = "0.8.33"
@ -560,6 +654,16 @@ dependencies = [
"byteorder",
]
[[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 = "getopts"
version = "0.2.21"
@ -630,6 +734,15 @@ version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "html-escape"
version = "0.2.13"
@ -774,7 +887,7 @@ dependencies = [
"futures-util",
"http 0.2.12",
"hyper 0.14.28",
"rustls",
"rustls 0.21.10",
"tokio",
"tokio-rustls",
]
@ -850,6 +963,15 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.10"
@ -871,6 +993,16 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.4.2",
"libc",
]
[[package]]
name = "lock_api"
version = "0.4.11"
@ -940,6 +1072,7 @@ dependencies = [
"fend-core",
"futures",
"html-escape",
"numbat",
"once_cell",
"rand",
"regex",
@ -986,6 +1119,48 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[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.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"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.18"
@ -995,6 +1170,43 @@ dependencies = [
"autocfg",
]
[[package]]
name = "numbat"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a54ccd3e33759b0171c20adfa0d8b0d2709fe131067faabcfcc1c35621a30b4b"
dependencies = [
"chrono",
"chrono-tz",
"codespan-reporting",
"heck",
"iana-time-zone",
"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-exchange-rates"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd1e3c3e4f9f22d0d7cdcb413f01194f6506a302a9029d95deedcd1c25df7718"
dependencies = [
"attohttpc",
"quick-xml",
]
[[package]]
name = "object"
version = "0.32.2"
@ -1010,6 +1222,12 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -1183,6 +1401,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[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.79"
@ -1192,6 +1419,15 @@ 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.35"
@ -1240,6 +1476,17 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_users"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "regex"
version = "1.10.3"
@ -1293,7 +1540,7 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls 0.21.10",
"rustls-pemfile",
"serde",
"serde_json",
@ -1308,7 +1555,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots",
"webpki-roots 0.25.4",
"winreg",
]
@ -1327,6 +1574,41 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rust-embed"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"shellexpand",
"syn 2.0.52",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581"
dependencies = [
"sha2",
"walkdir",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -1341,10 +1623,24 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
"ring",
"rustls-webpki",
"rustls-webpki 0.101.7",
"sct",
]
[[package]]
name = "rustls"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c"
dependencies = [
"log",
"ring",
"rustls-pki-types",
"rustls-webpki 0.102.2",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.4"
@ -1354,6 +1650,12 @@ dependencies = [
"base64 0.21.7",
]
[[package]]
name = "rustls-pki-types"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
[[package]]
name = "rustls-webpki"
version = "0.101.7"
@ -1364,6 +1666,17 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustls-webpki"
version = "0.102.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610"
dependencies = [
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.14"
@ -1376,6 +1689,21 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[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 = "scopeguard"
version = "1.2.0"
@ -1498,6 +1826,26 @@ dependencies = [
"stable_deref_trait",
]
[[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 = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
dependencies = [
"dirs",
]
[[package]]
name = "siphasher"
version = "0.3.11"
@ -1567,6 +1915,18 @@ dependencies = [
"quote",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "1.0.109"
@ -1627,6 +1987,35 @@ dependencies = [
"utf-8",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1675,7 +2064,7 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls",
"rustls 0.21.10",
"tokio",
]
@ -1790,6 +2179,12 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "uncased"
version = "0.9.10"
@ -1820,6 +2215,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "unicode-width"
version = "0.1.11"
@ -1867,6 +2268,16 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"
@ -1964,6 +2375,46 @@ version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]]
name = "webpki-roots"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009"
dependencies = [
"rustls-pki-types",
]
[[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-core"
version = "0.52.0"
@ -2143,3 +2594,9 @@ dependencies = [
"quote",
"syn 2.0.52",
]
[[package]]
name = "zeroize"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"

View File

@ -23,6 +23,7 @@ eyre = "0.6.12"
fend-core = "1.4.5"
futures = "0.3.30"
html-escape = "0.2.13"
numbat = "1.11.0"
once_cell = "1.19.0"
rand = "0.8.5"
regex = "1.10.3"

2
README
View File

@ -14,7 +14,7 @@ build it with `cargo b -r`, the resulting binary will be at
`target/release/metasearch2`.
the config.toml file is created in your current working directory on the first
run of metasearch2. alternatively, you can copy the example-config.toml in the
run of metasearch2. alternatively, you can copy the default-config.toml in the
repo and rename it to config.toml.
the default port is port 28019.

View File

@ -5,6 +5,10 @@ google = { weight = 1.05 }
bing = { weight = 1.0 }
brave = { weight = 1.25 }
# calculators (give them a high weight so they're always the first thing in autocomplete)
numbat = { weight = 10 }
fend = { enabled = false, weight = 10 }
[engines.marginalia]
args = { profile = "corpo", js = "default", adtech = "default" }
weight = 0.15

View File

@ -1,6 +1,7 @@
pub mod calc;
pub mod dictionary;
pub mod fend;
pub mod ip;
pub mod numbat;
pub mod thesaurus;
pub mod timezone;
pub mod useragent;

View File

@ -0,0 +1,196 @@
use std::collections::HashSet;
use fend_core::SpanKind;
use numbat::{
markup::{FormatType, FormattedString, Markup},
pretty_print::PrettyPrint,
resolver::CodeSource,
InterpreterResult, InterpreterSettings, Statement,
};
use once_cell::sync::Lazy;
use crate::engines::EngineResponse;
pub fn request(query: &str) -> EngineResponse {
let query = clean_query(query);
let Some(NumbatResponse {
query_html,
result_html,
}) = evaluate(&query)
else {
return EngineResponse::new();
};
EngineResponse::answer_html(format!(
r#"<p class="answer-query">{query_html} =</p>
<h3><b>{result_html}</b></h3>"#
))
}
pub fn request_autocomplete(query: &str) -> Vec<String> {
let mut results = Vec::new();
let query = clean_query(query);
if let Some(result) = evaluate_for_autocomplete(&query) {
results.push(format!("= {result}"));
}
results
}
fn clean_query(query: &str) -> String {
query.strip_suffix('=').unwrap_or(query).trim().to_string()
}
#[derive(Debug)]
pub struct Span {
pub text: String,
pub kind: SpanKind,
}
fn is_potential_request(query: &str) -> bool {
// allow these short constants, they're fine
if matches!(query.to_lowercase().as_str(), "pi" | "e" | "c") {
return true;
}
// at least 3 characters
if query.len() < 3 {
return false;
}
// must have numbers
if !query.chars().any(|c| c.is_numeric()) {
return false;
}
// if it starts and ends with quotes then the person was just searching in
// quotes and didn't mean to evaluate a string
if query.starts_with('"')
&& query.ends_with('"')
&& query.chars().filter(|c| *c == '"').count() == 2
{
return false;
}
true
}
fn interpret(query: &str) -> Option<(Statement, InterpreterResult)> {
if !is_potential_request(query) {
return None;
}
let mut ctx = NUMBAT_CTX.clone();
let (statements, res) = match ctx.interpret_with_settings(
&mut InterpreterSettings {
print_fn: Box::new(move |_: &Markup| {}),
},
query,
CodeSource::Text,
) {
Ok(r) => r,
Err(_) => {
return None;
}
};
Some((statements.into_iter().last()?, res))
}
fn evaluate_for_autocomplete(query: &str) -> Option<String> {
let (_statements, res) = interpret(query)?;
let res_markup = match res {
InterpreterResult::Value(val) => val.pretty_print(),
InterpreterResult::Continue => return None,
};
Some(res_markup.to_string())
}
pub struct NumbatResponse {
pub query_html: String,
pub result_html: String,
}
fn evaluate(query: &str) -> Option<NumbatResponse> {
let (statement, res) = interpret(query)?;
let res_markup = match res {
InterpreterResult::Value(val) => val.pretty_print(),
InterpreterResult::Continue => return None,
};
let statement_markup = statement.pretty_print();
let query_html = markup_to_html(statement_markup);
let result_html = markup_to_html(res_markup);
Some(NumbatResponse {
query_html,
result_html,
})
}
fn markup_to_html(markup: Markup) -> String {
let mut html = String::new();
for FormattedString(_output_type, format_type, content) in markup.0 {
let class = match format_type {
FormatType::Value => "answer-calc-constant",
FormatType::String => "answer-calc-string",
FormatType::Identifier => "answer-calc-func",
_ => "",
};
if class.is_empty() {
html.push_str(&html_escape::encode_safe(&content));
} else {
html.push_str(&format!(
r#"<span class="{class}">{content}</span>"#,
content = html_escape::encode_safe(&content)
));
}
}
html
}
pub static NUMBAT_CTX: Lazy<numbat::Context> = Lazy::new(|| {
let mut ctx = numbat::Context::new(numbat::module_importer::BuiltinModuleImporter {});
let _ = ctx.interpret("use prelude", CodeSource::Internal);
let _ = ctx.interpret("use units::currencies", CodeSource::Internal);
ctx.load_currency_module_on_demand(true);
// a few hardcoded aliases
// (the lowercase alias code won't work for these because they have prefixes)
for (alias, canonical) in &[
("kb", "kB"),
("mb", "MB"),
("gb", "GB"),
("tb", "TB"),
("pb", "PB"),
] {
let _ = ctx.interpret(&format!("unit {alias} = {canonical}"), CodeSource::Internal);
}
// lowercase aliases (so for example usd and USD are the same unit)
let mut unit_names = HashSet::new();
for names in ctx.unit_names() {
unit_names.extend(names.iter().map(|name| name.to_owned()));
}
for name in &unit_names {
// taken_unit_names.insert(alias_name);
let name_lower = name.to_lowercase();
// add every lowercase aliases for every unit as long as that alias isn't
// already taken
if !unit_names.contains(&name_lower) {
let _ = ctx.interpret(&format!("unit {name_lower} = {name}"), CodeSource::Internal);
}
}
ctx
});

View File

@ -33,7 +33,8 @@ engines! {
// answer
Useragent = "useragent",
Ip = "ip",
Calc = "calc",
Fend = "fend",
Numbat = "numbat",
Wikipedia = "wikipedia",
Dictionary = "dictionary",
Thesaurus = "thesaurus",
@ -53,7 +54,8 @@ engine_requests! {
// answer
Useragent => answer::useragent::request, None,
Ip => answer::ip::request, None,
Calc => answer::calc::request, None,
Fend => answer::fend::request, None,
Numbat => answer::numbat::request, None,
Wikipedia => answer::wikipedia::request, parse_response,
Dictionary => answer::dictionary::request, parse_response,
Thesaurus => answer::thesaurus::request, parse_response,
@ -62,7 +64,8 @@ engine_requests! {
engine_autocomplete_requests! {
Google => search::google::request_autocomplete, parse_autocomplete_response,
Calc => answer::calc::request_autocomplete, None,
Fend => answer::fend::request_autocomplete, None,
Numbat => answer::numbat::request_autocomplete, None,
}
engine_postsearch_requests! {

View File

@ -26,6 +26,7 @@
--syntax-special: #e6b673;
--syntax-constant: #d2a6ff;
--syntax-comment: #acb6bf8c;
--syntax-func: #ffb454;
}
html {
@ -237,6 +238,9 @@ h1 {
.answer-calc-special {
color: var(--syntax-special);
}
.answer-calc-func {
color: var(--syntax-func);
}
.answer-dictionary-word,
.answer-thesaurus-word {