Repository: rcoh/angle-grinder
Pull request #224 (2025-04-24 23:19:51)

Aliases


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index bd87e91..e1bdda2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -26,7 +26,7 @@ dependencies = [
  "assert_cmd",
  "cargo-husky",
  "chrono",
- "clap 4.5.34",
+ "clap",
  "cool_asserts",
  "criterion",
  "crossbeam-channel",
@@ -35,7 +35,7 @@ dependencies = [
  "human-panic",
  "im",
  "include_dir",
- "itertools",
+ "itertools 0.14.0",
  "lazy_static",
  "logfmt",
  "maplit",
@@ -51,12 +51,12 @@ dependencies = [
  "serde",
  "serde_json",
  "strfmt",
- "strsim 0.10.0",
+ "strsim",
  "terminal_size",
  "test-generator",
  "thiserror",
  "tikv-jemallocator",
- "toml 0.5.11",
+ "toml",
 ]
 
 [[package]]
@@ -151,9 +151,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.97"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
 
 [[package]]
 name = "arrayvec"
@@ -163,9 +163,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
 
 [[package]]
 name = "assert_cmd"
-version = "2.0.16"
+version = "2.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d"
+checksum = "2bd389a4b2970a01282ee455294913c0a43724daedcd1a24c3eb0ec1c1320b66"
 dependencies = [
  "anstyle",
  "bstr",
@@ -177,17 +177,6 @@ dependencies = [
  "wait-timeout",
 ]
 
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi 0.1.19",
- "libc",
- "winapi",
-]
-
 [[package]]
 name = "autocfg"
 version = "1.4.0"
@@ -247,9 +236,9 @@ dependencies = [
 
 [[package]]
 name = "bstr"
-version = "1.11.3"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
+checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
 dependencies = [
  "memchr",
  "regex-automata",
@@ -288,9 +277,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
 dependencies = [
  "shlex",
 ]
@@ -344,21 +333,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.2.25"
+version = "4.5.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
-dependencies = [
- "bitflags 1.3.2",
- "clap_lex 0.2.4",
- "indexmap 1.9.3",
- "textwrap",
-]
-
-[[package]]
-name = "clap"
-version = "4.5.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
+checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -366,14 +343,14 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.34"
+version = "4.5.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
+checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
 dependencies = [
  "anstream",
  "anstyle",
- "clap_lex 0.7.4",
- "strsim 0.11.1",
+ "clap_lex",
+ "strsim",
 ]
 
 [[package]]
@@ -383,20 +360,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
 dependencies = [
  "heck",
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
 ]
 
-[[package]]
-name = "clap_lex"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
-dependencies = [
- "os_str_bytes",
-]
-
 [[package]]
 name = "clap_lex"
 version = "0.7.4"
@@ -449,19 +417,19 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "criterion"
-version = "0.4.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
+checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
 dependencies = [
  "anes",
- "atty",
  "cast",
  "ciborium",
- "clap 3.2.25",
+ "clap",
  "criterion-plot",
- "itertools",
- "lazy_static",
+ "is-terminal",
+ "itertools 0.10.5",
  "num-traits",
+ "once_cell",
  "oorandom",
  "plotters",
  "rayon",
@@ -480,7 +448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
 dependencies = [
  "cast",
- "itertools",
+ "itertools 0.10.5",
 ]
 
 [[package]]
@@ -535,7 +503,7 @@ version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
 ]
@@ -554,9 +522,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
 
 [[package]]
 name = "dtparse"
-version = "1.5.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68235de3c014ade82e550337b2c88a2a884361793ed3be2d74ee703bd810e401"
+checksum = "23fb403c0926d35af2cc54d961bc2696a10d40725c08360ef69db04a4c201fd7"
 dependencies = [
  "chrono",
  "lazy_static",
@@ -593,9 +561,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.10"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
  "windows-sys 0.59.0",
@@ -700,9 +668,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
 dependencies = [
  "cfg-if",
  "libc",
@@ -745,7 +713,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http",
- "indexmap 2.8.0",
+ "indexmap",
  "slab",
  "tokio",
  "tokio-util",
@@ -754,20 +722,14 @@ dependencies = [
 
 [[package]]
 name = "half"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1"
+checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
 dependencies = [
  "cfg-if",
  "crunchy",
 ]
 
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-
 [[package]]
 name = "hashbrown"
 version = "0.15.2"
@@ -782,18 +744,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "hermit-abi"
-version = "0.3.9"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
 
 [[package]]
 name = "http"
@@ -841,7 +794,7 @@ dependencies = [
  "os_info",
  "serde",
  "serde_derive",
- "toml 0.8.20",
+ "toml",
  "uuid",
 ]
 
@@ -885,9 +838,9 @@ dependencies = [
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.62"
+version = "0.1.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -1020,7 +973,7 @@ version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
 ]
@@ -1075,7 +1028,7 @@ version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
 ]
 
@@ -1087,22 +1040,12 @@ checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3"
 
 [[package]]
 name = "indexmap"
-version = "1.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
-dependencies = [
- "autocfg",
- "hashbrown 0.12.3",
-]
-
-[[package]]
-name = "indexmap"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
 dependencies = [
  "equivalent",
- "hashbrown 0.15.2",
+ "hashbrown",
 ]
 
 [[package]]
@@ -1118,23 +1061,23 @@ dependencies = [
  "web-time",
 ]
 
-[[package]]
-name = "io-lifetimes"
-version = "1.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
-dependencies = [
- "hermit-abi 0.3.9",
- "libc",
- "windows-sys 0.48.0",
-]
-
 [[package]]
 name = "ipnet"
 version = "2.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
 
+[[package]]
+name = "is-terminal"
+version = "0.4.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "windows-sys 0.59.0",
+]
+
 [[package]]
 name = "is_terminal_polyfill"
 version = "1.70.1"
@@ -1150,6 +1093,15 @@ dependencies = [
  "either",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
 version = "1.0.15"
@@ -1180,21 +1132,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.171"
+version = "0.2.172"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
 
 [[package]]
 name = "litemap"
@@ -1240,9 +1186,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
 dependencies = [
  "adler2",
 ]
@@ -1336,9 +1282,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
 
 [[package]]
 name = "ordered-float"
-version = "3.9.2"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc"
+checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01"
 dependencies = [
  "num-traits",
 ]
@@ -1354,12 +1300,6 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
-[[package]]
-name = "os_str_bytes"
-version = "6.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
-
 [[package]]
 name = "percent-encoding"
 version = "2.3.1"
@@ -1420,7 +1360,7 @@ checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
 dependencies = [
  "difflib",
  "float-cmp",
- "itertools",
+ "itertools 0.10.5",
  "normalize-line-endings",
  "predicates-core",
  "regex",
@@ -1464,25 +1404,32 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.94"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.9.6"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
+checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
 dependencies = [
  "bitflags 2.9.0",
  "getopts",
  "memchr",
+ "pulldown-cmark-escape",
  "unicase",
 ]
 
+[[package]]
+name = "pulldown-cmark-escape"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
+
 [[package]]
 name = "quantiles"
 version = "0.7.1"
@@ -1513,7 +1460,7 @@ version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
 ]
 
 [[package]]
@@ -1635,7 +1582,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
 dependencies = [
  "cc",
  "cfg-if",
- "getrandom 0.2.15",
+ "getrandom 0.2.16",
  "libc",
  "untrusted",
  "windows-sys 0.52.0",
@@ -1659,28 +1606,14 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustix"
-version = "0.37.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6"
-dependencies = [
- "bitflags 1.3.2",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys 0.3.8",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "rustix"
-version = "1.0.3"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
+checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
 dependencies = [
  "bitflags 2.9.0",
  "errno",
  "libc",
- "linux-raw-sys 0.9.3",
+ "linux-raw-sys",
  "windows-sys 0.59.0",
 ]
 
@@ -1784,7 +1717,7 @@ version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
 ]
@@ -1849,15 +1782,15 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.14.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
 
 [[package]]
 name = "socket2"
-version = "0.5.8"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -1875,12 +1808,6 @@ version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a8348af2d9fc3258c8733b8d9d8db2e56f54b2363a4b5b81585c7875ed65e65"
 
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
 [[package]]
 name = "strsim"
 version = "0.11.1"
@@ -1904,7 +1831,7 @@ version = "2.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "unicode-ident",
 ]
@@ -1921,7 +1848,7 @@ version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
 ]
@@ -1956,18 +1883,18 @@ dependencies = [
  "fastrand",
  "getrandom 0.3.2",
  "once_cell",
- "rustix 1.0.3",
+ "rustix",
  "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "terminal_size"
-version = "0.2.6"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
+checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed"
 dependencies = [
- "rustix 0.37.28",
- "windows-sys 0.48.0",
+ "rustix",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1988,37 +1915,31 @@ dependencies = [
  "syn 0.15.44",
 ]
 
-[[package]]
-name = "textwrap"
-version = "0.16.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
-
 [[package]]
 name = "thiserror"
-version = "1.0.69"
+version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.69"
+version = "2.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
 ]
 
 [[package]]
 name = "tikv-jemalloc-sys"
-version = "0.5.4+5.3.0-patched"
+version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9402443cb8fd499b6f327e40565234ff34dbda27460c5b47db0db77443dd85d1"
+checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d"
 dependencies = [
  "cc",
  "libc",
@@ -2026,9 +1947,9 @@ dependencies = [
 
 [[package]]
 name = "tikv-jemallocator"
-version = "0.5.4"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "965fe0c26be5c56c94e38ba547249074803efd52adfb66de62107d95aab3eaca"
+checksum = "4cec5ff18518d81584f477e9bfdf957f5bb0979b0bac3af4ca30b5b3ae2d2865"
 dependencies = [
  "libc",
  "tikv-jemalloc-sys",
@@ -2081,9 +2002,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-util"
-version = "0.7.14"
+version = "0.7.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
+checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
 dependencies = [
  "bytes",
  "futures-core",
@@ -2092,15 +2013,6 @@ dependencies = [
  "tokio",
 ]
 
-[[package]]
-name = "toml"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
-dependencies = [
- "serde",
-]
-
 [[package]]
 name = "toml"
 version = "0.8.20"
@@ -2128,10 +2040,11 @@ version = "0.22.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
 dependencies = [
- "indexmap 2.8.0",
+ "indexmap",
  "serde",
  "serde_spanned",
  "toml_datetime",
+ "winnow",
 ]
 
 [[package]]
@@ -2314,7 +2227,7 @@ checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
  "wasm-bindgen-shared",
@@ -2349,7 +2262,7 @@ version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
  "wasm-bindgen-backend",
@@ -2424,11 +2337,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-core"
-version = "0.52.0"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+dependencies = [
+ "proc-macro2 1.0.95",
+ "quote 1.0.40",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2 1.0.95",
+ "quote 1.0.40",
+ "syn 2.0.100",
 ]
 
 [[package]]
@@ -2437,6 +2376,24 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 
+[[package]]
+name = "windows-result"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+dependencies = [
+ "windows-link",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
@@ -2585,6 +2542,15 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
+[[package]]
+name = "winnow"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "winreg"
 version = "0.50.0"
@@ -2643,7 +2609,7 @@ version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
  "synstructure",
@@ -2664,7 +2630,7 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
  "synstructure",
@@ -2687,7 +2653,7 @@ version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
 dependencies = [
- "proc-macro2 1.0.94",
+ "proc-macro2 1.0.95",
  "quote 1.0.40",
  "syn 2.0.100",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index c9f64a2..08e1012 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,21 +22,21 @@ default = []
 self-update = ["self_update"]
 
 [target.'cfg(not(target_env = "msvc"))'.dependencies]
-tikv-jemallocator = "0.5.0"
+tikv-jemallocator = "0.6"
 
 [dependencies]
 serde_json = "1.0.33"
-itertools = "0.10.5"
+itertools = "0.14"
 nom = "7.1.1"
 nom_locate = "4.0.0"
 nom-supreme = "0.8.0"
-strsim = "0.10.0"
+strsim = "0.11"
 regex = "1.5.5"
-terminal_size = "0.2.1"
+terminal_size = "0.4"
 quantiles = "0.7.1"
 crossbeam-channel = "0.5.15"
-ordered-float = "3.3.0"
-thiserror = "1.0.37"
+ordered-float = "5"
+thiserror = "2"
 anyhow = "1"
 human-panic = "2"
 self_update = { version = "0.32.0", features = ["rustls"], default-features = false, optional = true }
@@ -46,10 +46,10 @@ im = "15.1.0"
 logfmt = "0.0.2"
 strfmt = "0.2.2"
 include_dir = "0.7.3"
-toml = "0.5.9"
+toml = "0.8"
 serde = { version = "1.0", features = ["derive"] }
 chrono = "0.4"
-dtparse = "1.1"
+dtparse = "2"
 clap = { version = "4.0.18", features = ["derive"] }
 
 [dev-dependencies]
@@ -57,8 +57,8 @@ assert_cmd = "2.0.5"
 cool_asserts = "2.0.3"
 expect-test = "1.1.0"
 predicates = "2.1.1"
-pulldown-cmark = "0.9.2"
-criterion = "0.4.0"
+pulldown-cmark = "0.13.0"
+criterion = "0.5"
 maplit = "1.0.1"
 test-generator = "0.3.0"
 [dev-dependencies.cargo-husky]
diff --git a/README.md b/README.md
index 4526a24..5067732 100644
--- a/README.md
+++ b/README.md
@@ -93,9 +93,25 @@ Sub-expressions _must_ be grouped in parenthesis. Only lines that match all filt
 ![filter.gif](/screen_shots/filter.gif)
 
 ### Aliases
-Starting with v0.12.0, angle grinder supports aliases, pre-built pipelines do simplify common tasks or formats. The only alias currently defined is `apache`, which parses apache logs. Adding more `aliases` is one of the easiest ways to [contribute](#contributing)!
+Starting with v0.12.0, angle grinder supports aliases, pre-built pipelines do simplify common tasks or formats.
+
+By default, angle-grinder will look in the `.agrind-aliases` directory in your current working directory and all parent directories.
+
+Alias files look like this:
+
+```toml
+keyword = "apache"
+template = """
+parse "* - * [*] \\"* * *\\" * *" as ip, name, timestamp, method, url, protocol, status, contentlength
+"""
+```
+
+Your operators are parsed, then expanded into the resulting pipeline. When invalid aliases are present, a warning will be displayed when running angle-grinder.
+
+Note that aliases are currently considered an experimental feature and precise behavior may change in the future.
 
 *Examples*:
+
 ```agrind
 * | apache | count by status
 ```
diff --git a/src/alias.rs b/src/alias.rs
index abb4aca..d73ab56 100644
--- a/src/alias.rs
+++ b/src/alias.rs
@@ -5,6 +5,9 @@
 //! 2. Create a new test config inside `tests/structured_tests/aliases`.
 //! 3. Add the test config to the `test_aliases()` test.
 
+use std::borrow::Cow;
+use std::path::{Path, PathBuf};
+
 use lazy_static::lazy_static;
 
 use crate::errors::{QueryContainer, TermErrorReporter};
@@ -18,40 +21,165 @@ lazy_static! {
     pub static ref LOADED_ALIASES: Vec<AliasPipeline> = ALIASES_DIR
         .files()
         .map(|file| {
-            let config: AliasConfig =
-                toml::from_str(file.contents_utf8().expect("load string")).expect("toml valid");
-            let reporter = Box::new(TermErrorReporter {});
-            let qc = QueryContainer::new(config.template, reporter);
-            let pipeline = pipeline_template(&qc).expect("valid alias");
-
-            AliasPipeline {
-                keyword: config.keyword,
-                pipeline,
-            }
+            parse_alias(
+                file.contents_utf8().expect("invalid utf-8"),
+                file.path(),
+                &[],
+            )
+            .expect("invalid toml")
         })
         .collect();
     pub static ref LOADED_KEYWORDS: Vec<&'static str> =
         LOADED_ALIASES.iter().map(|a| a.keyword.as_str()).collect();
 }
 
+#[derive(Debug)]
+pub struct InvalidAliasError {
+    pub path: PathBuf,
+    pub cause: anyhow::Error,
+    pub keyword: Option<String>,
+    pub contents: Option<String>,
+}
+
+fn parse_alias(
+    contents: &str,
+    path: &Path,
+    aliases: &[AliasPipeline],
+) -> Result<AliasPipeline, InvalidAliasError> {
+    let config: AliasConfig = toml::from_str(contents).map_err(|err| InvalidAliasError {
+        path: path.to_owned(),
+        cause: err.into(),
+        keyword: None,
+        contents: Some(contents.to_string()),
+    })?;
+    let reporter = Box::new(TermErrorReporter {});
+    let aliases = AliasCollection {
+        aliases: Cow::Borrowed(aliases),
+    };
+    let qc = QueryContainer::new_with_aliases(config.template, reporter, aliases);
+    let keyword = config.keyword;
+    let pipeline = pipeline_template(&qc).map_err(|err| InvalidAliasError {
+        path: path.to_owned(),
+        cause: err.into(),
+        keyword: Some(keyword.clone()),
+        contents: Some(contents.to_string()),
+    })?;
+
+    Ok(AliasPipeline { keyword, pipeline })
+}
+
 #[derive(Debug, Deserialize, PartialEq, Eq)]
 pub struct AliasConfig {
     keyword: String,
     template: String,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct AliasPipeline {
     keyword: String,
     pipeline: Vec<Operator>,
 }
 
-impl AliasPipeline {
-    pub fn matching_string(s: &str) -> Result<&'static AliasPipeline, ()> {
-        LOADED_ALIASES
+#[derive(Default)]
+pub struct AliasCollection<'a> {
+    aliases: Cow<'a, [AliasPipeline]>,
+}
+
+#[derive(Default)]
+struct AliasAccum {
+    valid_aliases: Vec<AliasPipeline>,
+    invalid_aliases: Vec<InvalidAliasError>,
+}
+
+impl AliasCollection<'_> {
+    pub fn get_alias(&self, name: &str) -> Option<&AliasPipeline> {
+        self.aliases
             .iter()
-            .find(|alias| alias.keyword == s)
-            .ok_or(())
+            .find(|alias| alias.keyword == name)
+            .or_else(|| AliasPipeline::matching_string(name))
+    }
+
+    pub fn valid_aliases(&self) -> impl Iterator<Item = &str> {
+        self.aliases.iter().map(|a| a.keyword.as_str())
+    }
+}
+
+impl AliasCollection<'static> {
+    pub fn load_aliases_ancestors(
+        path: Option<PathBuf>,
+    ) -> anyhow::Result<(AliasCollection<'static>, Vec<InvalidAliasError>)> {
+        let path = match path {
+            Some(path) => path,
+            None => std::env::current_dir()?,
+        };
+        let (valid, invalid) = find_all_aliases(path)?;
+        Ok((
+            AliasCollection {
+                aliases: Cow::Owned(valid),
+            },
+            invalid,
+        ))
+    }
+
+    pub fn load_aliases_from_dir(
+        path: &Path,
+    ) -> anyhow::Result<(AliasCollection<'static>, Vec<InvalidAliasError>)> {
+        let mut aliases = AliasAccum::default();
+        aliases_from_dir(path, &mut aliases)?;
+        Ok((
+            AliasCollection {
+                aliases: Cow::Owned(aliases.valid_aliases),
+            },
+            aliases.invalid_aliases,
+        ))
+    }
+}
+
+fn find_local_aliases(dir: &Path, aliases: &mut AliasAccum) -> anyhow::Result<()> {
+    if let Some(alias_dir) = dir.read_dir()?.find_map(|file| match file {
+        Ok(entry) if entry.file_name() == ".agrind-aliases" => Some(entry),
+        _else => None,
+    }) {
+        aliases_from_dir(&alias_dir.path(), aliases)?;
+    }
+    Ok(())
+}
+
+fn aliases_from_dir(dir: &Path, pipelines: &mut AliasAccum) -> anyhow::Result<()> {
+    for entry in dir.read_dir()? {
+        let entry = entry?;
+        let path = entry.path();
+        let contents = match std::fs::read_to_string(&path) {
+            Ok(s) => s,
+            Err(e) => {
+                pipelines.invalid_aliases.push(InvalidAliasError {
+                    keyword: None,
+                    path,
+                    cause: e.into(),
+                    contents: None,
+                });
+                continue;
+            }
+        };
+        match parse_alias(&contents, &path, &pipelines.valid_aliases) {
+            Ok(alias) => pipelines.valid_aliases.push(alias),
+            Err(e) => pipelines.invalid_aliases.push(e),
+        }
+    }
+    Ok(())
+}
+
+fn find_all_aliases(path: PathBuf) -> anyhow::Result<(Vec<AliasPipeline>, Vec<InvalidAliasError>)> {
+    let mut accum = AliasAccum::default();
+    for path in path.ancestors() {
+        find_local_aliases(path, &mut accum)?;
+    }
+    Ok((accum.valid_aliases, accum.invalid_aliases))
+}
+
+impl AliasPipeline {
+    pub fn matching_string(s: &str) -> Option<&'static AliasPipeline> {
+        LOADED_ALIASES.iter().find(|alias| alias.keyword == s)
     }
 
     /// Render the alias as a string that should parse into a valid operator.
diff --git a/src/bin/agrind.rs b/src/bin/agrind.rs
index 1f827ec..0ec306f 100644
--- a/src/bin/agrind.rs
+++ b/src/bin/agrind.rs
@@ -1,4 +1,7 @@
-use ag::pipeline::{OutputMode, Pipeline, QueryContainer, TermErrorReporter};
+use ag::alias::AliasCollection;
+use ag::pipeline::{ErrorReporter, OutputMode, Pipeline, QueryContainer, TermErrorReporter};
+use annotate_snippets::display_list::FormatOptions;
+use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet};
 use human_panic::setup_panic;
 
 use clap::Parser;
@@ -7,6 +10,7 @@ use self_update;
 use std::fs::File;
 use std::io;
 use std::io::{stdout, BufReader};
+use std::path::PathBuf;
 use thiserror::Error;
 
 #[cfg(not(target_env = "msvc"))]
@@ -49,6 +53,16 @@ struct Cli {
                      - `legacy` The original output format, auto aligning [k=v]"
     )]
     output: Option<String>,
+
+    #[arg(
+        long = "alias-dir",
+        short = 'a',
+        long_help = "Specifies an alternative directory to use for aliases. Defaults to `.agrind-aliases` in all parent directories."
+    )]
+    alias_dir: Option<PathBuf>,
+
+    #[arg(long = "no-alias", long_help = "Disables aliases")]
+    no_alias: bool,
 }
 
 #[derive(Debug, Error)]
@@ -64,6 +78,9 @@ pub enum InvalidArgs {
 
     #[error("Can't supply a format string and an output mode")]
     CantSupplyBoth,
+
+    #[error("Can't disable aliases and also set a directory")]
+    CantDisableAndOverride,
 }
 
 fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -73,11 +90,36 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
     if args.update {
         return update();
     }
-    let query = QueryContainer::new(
+    let (aliases, errors) = match (args.alias_dir, args.no_alias) {
+        (Some(dir), false) => AliasCollection::load_aliases_from_dir(&dir)?,
+        (None, false) => AliasCollection::load_aliases_ancestors(None)?,
+        (Some(_), true) => return Err(InvalidArgs::CantDisableAndOverride.into()),
+        (None, true) => (AliasCollection::default(), vec![]),
+    };
+    let error_reporter = Box::new(TermErrorReporter {});
+    for error in errors {
+        error_reporter.handle_error(Snippet {
+            title: Some(Annotation {
+                id: None,
+                label: Some(&format!("invalid alias: {}", error.cause)),
+                annotation_type: AnnotationType::Warning,
+            }),
+            footer: vec![],
+            slices: vec![Slice {
+                source: "",
+                line_start: 0,
+                origin: Some(error.path.to_str().unwrap()),
+                annotations: vec![],
+                fold: true,
+            }],
+            opt: FormatOptions::default(),
+        });
+    }
+    let query = QueryContainer::new_with_aliases(
         args.query.ok_or(InvalidArgs::MissingQuery)?,
-        Box::new(TermErrorReporter {}),
+        error_reporter,
+        aliases,
     );
-    //args.verbosity.setup_env_logger("agrind")?;
     let output_mode = match (args.output, args.format) {
         (Some(_output), Some(_format)) => Err(CantSupplyBoth),
         (Some(output), None) => parse_output(&output),
diff --git a/src/data.rs b/src/data.rs
index b806496..a54db06 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -269,17 +269,17 @@ impl Display for ValueDisplay<'_> {
             Value::Duration(ref d) => {
                 let mut remaining: Duration = *d;
                 let weeks = remaining.num_seconds() / Duration::weeks(1).num_seconds();
-                remaining = remaining - Duration::weeks(weeks);
+                remaining -= Duration::weeks(weeks);
                 let days = remaining.num_seconds() / Duration::days(1).num_seconds();
-                remaining = remaining - Duration::days(days);
+                remaining -= Duration::days(days);
                 let hours = remaining.num_seconds() / Duration::hours(1).num_seconds();
-                remaining = remaining - Duration::hours(hours);
+                remaining -= Duration::hours(hours);
                 let mins = remaining.num_seconds() / Duration::minutes(1).num_seconds();
-                remaining = remaining - Duration::minutes(mins);
+                remaining -= Duration::minutes(mins);
                 let secs = remaining.num_seconds() / Duration::seconds(1).num_seconds();
-                remaining = remaining - Duration::seconds(secs);
+                remaining -= Duration::seconds(secs);
                 let msecs = remaining.num_milliseconds();
-                remaining = remaining - Duration::milliseconds(msecs);
+                remaining -= Duration::milliseconds(msecs);
                 let usecs = remaining.num_microseconds().unwrap_or(0);
 
                 let pairs = &[
diff --git a/src/errors.rs b/src/errors.rs
index 792ba64..9a164f1 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,3 +1,4 @@
+use crate::alias::AliasCollection;
 use crate::lang::{query, Positioned, Query};
 use crate::pipeline::CompileError;
 use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
@@ -8,10 +9,11 @@ use std::sync::atomic::{AtomicUsize, Ordering};
 use strsim::normalized_levenshtein;
 
 /// Container for the query string that can be used to parse and report errors.
-pub struct QueryContainer {
+pub struct QueryContainer<'a> {
     pub query: String,
     pub reporter: Box<dyn ErrorReporter>,
     pub error_count: AtomicUsize,
+    pub aliases: AliasCollection<'a>,
 }
 
 /// Trait that can be used to report errors by the parser and other layers.
@@ -22,14 +24,39 @@ pub trait ErrorBuilder {
     fn get_error_count(&self) -> usize;
 }
 
-impl QueryContainer {
-    pub fn new(query: String, reporter: Box<dyn ErrorReporter>) -> QueryContainer {
+impl<'a> QueryContainer<'a> {
+    pub fn new_with_aliases(
+        query: String,
+        reporter: Box<dyn ErrorReporter>,
+        aliases: AliasCollection<'a>,
+    ) -> Self {
         QueryContainer {
             query,
             reporter,
             error_count: AtomicUsize::new(0),
+            aliases,
         }
     }
+}
+
+impl QueryContainer<'static> {
+    /*
+    pub fn new(query: String, reporter: Box<dyn ErrorReporter>) -> QueryContainer<'static> {
+        let (aliases, errs) = AliasCollection::load_aliases_ancestors(None);
+        for err in errs {
+            reporter.handle_error(Snippet {
+                title: Some(Annotation {
+                    id: None,
+                    label: Some(&format!("{err:?}")),
+                    annotation_type: AnnotationType::Warning,
+                }),
+                footer: vec![],
+                slices: vec![],
+                opt: FormatOptions::default(),
+            });
+        }
+        Self::new_with_aliases(query, reporter, aliases)
+    }*/
 
     /// Parse the contained query string.
     pub fn parse(&self) -> Result<Query, CompileError> {
@@ -37,7 +64,7 @@ impl QueryContainer {
     }
 }
 
-impl ErrorBuilder for QueryContainer {
+impl ErrorBuilder for QueryContainer<'_> {
     /// Create a SnippetBuilder for the given error
     fn report_error_for<E: ToString>(&self, error: E) -> SnippetBuilder {
         self.error_count.fetch_add(1, Ordering::Relaxed);
@@ -57,16 +84,11 @@ impl ErrorBuilder for QueryContainer {
     }
 }
 
-pub fn did_you_mean(input: &str, choices: &[&str]) -> Option<String> {
-    let similarities = choices
-        .iter()
-        .map(|choice| (choice, normalized_levenshtein(choice, input)));
+pub fn did_you_mean<'a>(input: &str, choices: impl Iterator<Item = &'a str>) -> Option<String> {
+    let similarities = choices.map(|choice| (choice, normalized_levenshtein(choice, input)));
     let mut candidates: Vec<_> = similarities.filter(|(_op, score)| *score > 0.6).collect();
     candidates.sort_by_key(|(_op, score)| (score * 100_f64) as u16);
-    candidates
-        .iter()
-        .map(|(choice, _score)| (**choice).to_owned())
-        .next()
+    candidates.first().map(|(choice, _scoe)| choice.to_string())
 }
 
 /// Callback for handling error Snippets.
@@ -97,11 +119,11 @@ pub struct SnippetData {
 
 #[must_use = "the send_report() method must eventually be called for this builder"]
 pub struct SnippetBuilder<'a> {
-    query: &'a QueryContainer,
+    query: &'a QueryContainer<'a>,
     data: SnippetData,
 }
 
-impl<'a> SnippetBuilder<'a> {
+impl SnippetBuilder<'_> {
     /// Adds an annotation to a portion of the query string.  The given position will be
     /// highlighted with the accompanying label.
     pub fn with_code_pointer<T, S: ToString>(mut self, pos: &Positioned<T>, label: S) -> Self {
diff --git a/src/lang.rs b/src/lang.rs
index ab37200..d1973df 100644
--- a/src/lang.rs
+++ b/src/lang.rs
@@ -26,7 +26,7 @@ use nom_supreme::error::ErrorTree;
 use nom_supreme::parser_ext::ParserExt;
 use nom_supreme::tag::complete::tag;
 
-use crate::alias::{self, AliasPipeline};
+use crate::alias::{self, AliasCollection};
 use crate::data;
 use crate::errors::{ErrorBuilder, QueryContainer};
 use crate::pipeline::CompileError;
@@ -68,7 +68,7 @@ lazy_static! {
 pub const RESERVED_FILTER_WORDS: &[&str] = &["AND", "OR", "NOT"];
 
 /// Type used to track the current fragment being parsed and its location in the original input.
-pub type Span<'a> = LocatedSpan<&'a str, &'a QueryContainer>;
+pub type Span<'a> = LocatedSpan<&'a str, &'a QueryContainer<'a>>;
 
 pub type LResult<I, O, E = ErrorTree<I>> = Result<(I, O), nom::Err<E>>;
 
@@ -101,7 +101,7 @@ trait ToRange {
     fn to_whitespace(&self) -> Range<usize>;
 }
 
-impl<'a> ToRange for Span<'a> {
+impl ToRange for Span<'_> {
     fn to_range(&self) -> Range<usize> {
         let start = self.location_offset();
         let end = start + self.fragment().len();
@@ -1421,7 +1421,26 @@ fn skip_to_end_of_query(input: Span) -> IResult<Span, Operator> {
     }
 }
 
-fn parse_operators(input: Span) -> IResult<Span, Vec<Operator>> {
+struct ValidOperators<'a> {
+    aliases: &'a AliasCollection<'a>,
+}
+
+impl<'a> ValidOperators<'a> {
+    fn valid_aggs(&self) -> impl Iterator<Item = &'a str> {
+        VALID_AGGREGATES.iter().copied()
+    }
+
+    fn valid_operators(&self) -> impl Iterator<Item = &'a str> {
+        self.valid_aggs()
+            .chain(VALID_INLINE.iter().copied())
+            .chain(self.aliases.valid_aliases())
+    }
+}
+
+fn parse_operators<'a>(
+    input: Span<'a>,
+    aliases: &AliasCollection,
+) -> IResult<Span<'a>, Vec<Operator>> {
     let json = with_pos(
         oper_0_args("json")
             .precedes(kw_expr("from", "a JSON-encoded string"))
@@ -1570,7 +1589,9 @@ fn parse_operators(input: Span) -> IResult<Span, Vec<Operator>> {
     .map(Operator::Inline);
 
     let alias = recognize(ident).map_res(|span| {
-        AliasPipeline::matching_string(span.fragment())
+        aliases
+            .get_alias(span.fragment())
+            .ok_or(())
             .map(|pipe| Operator::RenderedAlias(pipe.render()))
     });
 
@@ -1593,15 +1614,13 @@ fn parse_operators(input: Span) -> IResult<Span, Vec<Operator>> {
                 } else if VALID_OPERATORS.contains(&i) {
                     continue;
                 }
+                let valid_operators = ValidOperators { aliases };
 
-                let m = crate::errors::did_you_mean(
-                    &i,
-                    if is_agg {
-                        VALID_AGGREGATES
-                    } else {
-                        &VALID_OPERATORS
-                    },
-                );
+                let m = if is_agg {
+                    crate::errors::did_you_mean(&i, valid_operators.valid_aggs())
+                } else {
+                    crate::errors::did_you_mean(&i, valid_operators.valid_operators())
+                };
 
                 let mut builder = input
                     .extra
@@ -1646,18 +1665,20 @@ fn parse_operators(input: Span) -> IResult<Span, Vec<Operator>> {
 
 pub fn pipeline_template(input: &QueryContainer) -> Result<Vec<Operator>, CompileError> {
     let span = Span::new_extra(input.query.as_str(), input);
-    let (_input, operators) = parse_operators(span).map_err(|_| CompileError::Parse)?;
+    let (_input, operators) =
+        parse_operators(span, &input.aliases).map_err(|_| CompileError::Parse)?;
 
     Ok(operators)
 }
 
-pub fn query(input: &QueryContainer) -> Result<Query, CompileError> {
-    let span = Span::new_extra(input.query.as_str(), input);
+pub fn query(container: &QueryContainer) -> Result<Query, CompileError> {
+    let span = Span::new_extra(container.query.as_str(), container);
     let (input, search) = parse_search(span).map_err(|_| CompileError::Parse)?;
-    let (input, operators) = opt(tag("|").precedes(parse_operators))
-        .map(|ops| ops.unwrap_or_default())
-        .parse(input)
-        .map_err(|_| CompileError::Parse)?;
+    let (input, operators) =
+        opt(tag("|").precedes(|span| parse_operators(span, &container.aliases)))
+            .map(|ops| ops.unwrap_or_default())
+            .parse(input)
+            .map_err(|_| CompileError::Parse)?;
 
     if input.extra.get_error_count() > 0 {
         Err(CompileError::Parse)
@@ -1684,9 +1705,10 @@ mod tests {
     fn check_query(query_in: &str, expect: Expect) {
         let errors = Arc::new(Mutex::new(vec![]));
         let parsed = {
-            let qc = QueryContainer::new(
+            let qc = QueryContainer::new_with_aliases(
                 query_in.to_string(),
                 Box::new(VecErrorReporter::new(errors.clone())),
+                AliasCollection::default(),
             );
             let r = query(&qc);
 
diff --git a/src/lib.rs b/src/lib.rs
index 5e459c7..ec4b09d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,7 @@
 #[macro_use]
 extern crate include_dir;
 
-mod alias;
+pub mod alias;
 pub mod data;
 mod errors;
 mod filter;
@@ -130,7 +130,7 @@ pub mod pipeline {
         }
 
         pub fn new<W: 'static + Write + Send>(
-            pipeline: &QueryContainer,
+            pipeline: &QueryContainer<'static>,
             output: W,
             output_mode: OutputMode,
         ) -> Result<Self, Error> {
diff --git a/src/operator/max.rs b/src/operator/max.rs
index 9350afc..36c7c87 100644
--- a/src/operator/max.rs
+++ b/src/operator/max.rs
@@ -9,7 +9,7 @@ pub struct Max {
 impl Max {
     pub fn empty<T: Into<Expr>>(column: T) -> Max {
         Max {
-            max: std::f64::NEG_INFINITY,
+            max: f64::NEG_INFINITY,
             column: column.into(),
         }
     }
diff --git a/src/operator/min.rs b/src/operator/min.rs
index 2c4ea35..ea5a95b 100644
--- a/src/operator/min.rs
+++ b/src/operator/min.rs
@@ -9,7 +9,7 @@ pub struct Min {
 impl Min {
     pub fn empty<T: Into<Expr>>(column: T) -> Min {
         Min {
-            min: std::f64::INFINITY,
+            min: f64::INFINITY,
             column: column.into(),
         }
     }


Test patch:
diff --git a/benches/e2e.rs b/benches/e2e.rs
index 507efeb..f833094 100644
--- a/benches/e2e.rs
+++ b/benches/e2e.rs
@@ -1,3 +1,4 @@
+use ag::alias::AliasCollection;
 use ag::pipeline::{ErrorReporter, OutputMode, Pipeline, QueryContainer};
 use annotate_snippets::snippet::Snippet;
 use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
@@ -49,7 +50,11 @@ pub fn criterion_benchmark(c: &mut Criterion) {
         },
     ];
     tests.into_iter().for_each(|test| {
-        let query_container = QueryContainer::new(test.query, Box::new(NopErrorReporter {}));
+        let query_container = QueryContainer::new_with_aliases(
+            test.query,
+            Box::new(NopErrorReporter {}),
+            AliasCollection::default(),
+        );
         let mut group = c.benchmark_group("e2e_query");
         let num_elems = BufReader::new(File::open(&test.file).unwrap())
             .lines()
diff --git a/tests/code_blocks.rs b/tests/code_blocks.rs
index 5da7a67..1d51553 100644
--- a/tests/code_blocks.rs
+++ b/tests/code_blocks.rs
@@ -23,7 +23,7 @@ fn extract_blocks<'md, I: Iterator<Item = Event<'md>>>(md_events: I) -> Vec<Code
             (Event::Text(code), true) => {
                 current_block += &code;
             }
-            (Event::End(Tag::CodeBlock(_lang)), true) => {
+            (Event::End(pulldown_cmark::TagEnd::CodeBlock), true) => {
                 blocks.push(CodeBlock {
                     flag: current_flag.to_string(),
                     code: current_block.to_string(),
diff --git a/tests/integration.rs b/tests/integration.rs
index 17e56b7..ada70c1 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -21,6 +21,7 @@ struct TestDefinition {
 #[cfg(test)]
 mod integration {
     use super::*;
+    use ag::alias::AliasCollection;
     use ag::pipeline::{ErrorReporter, OutputMode, Pipeline, QueryContainer};
     use assert_cmd::Command;
     use predicates::prelude::predicate;
@@ -62,6 +63,7 @@ mod integration {
             .write_stdin(conf.input)
             .arg(&conf.query)
             .args(conf.flags)
+            .arg("--no-alias")
             .assert();
 
         let asserter = asserter.stdout(conf.output).stderr(err);
@@ -215,7 +217,11 @@ warn | Fetcher failed to start        module=kafka.consumer.ConsumerFetcherManag
     }
 
     fn ensure_parses(query: &str) {
-        let query_container = QueryContainer::new(query.to_string(), Box::new(EmptyErrorReporter));
+        let query_container = QueryContainer::new_with_aliases(
+            query.to_string(),
+            Box::new(EmptyErrorReporter),
+            AliasCollection::default(),
+        );
         Pipeline::new(&query_container, stdout(), OutputMode::Legacy).unwrap_or_else(|err| {
             panic!(
                 "Query: `{}` from the README should have parsed {}",