refactor: extract business logic into lib.rs
Move scan_from_root, scan_all_roots, get_projects, show_cache_status and launch_tmux_session from main.rs into a new src/lib.rs, making them pub so they are testable independently of the binary entrypoint. main.rs is now a thin entrypoint that imports from tmuxido:: and keeps only select_project_with_fzf (interactive subprocess, not unit-testable). Add tempfile = "3" to [dev-dependencies] in preparation for tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
30d6c3d1c5
commit
d35acdeb55
277
Cargo.lock
generated
277
Cargo.lock
generated
@ -164,6 +164,28 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@ -175,6 +197,28 @@ dependencies = [
|
|||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasip2",
|
||||||
|
"wasip3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
@ -187,6 +231,12 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "id-arena"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.12.0"
|
version = "2.12.0"
|
||||||
@ -194,7 +244,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
|
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.16.0",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -209,6 +261,12 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "leb128fmt"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.177"
|
version = "0.2.177"
|
||||||
@ -225,12 +283,30 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.6"
|
version = "2.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell_polyfill"
|
name = "once_cell_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
@ -243,6 +319,16 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prettyplease"
|
||||||
|
version = "0.2.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.103"
|
version = "1.0.103"
|
||||||
@ -261,13 +347,19 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.16",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
@ -278,11 +370,24 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.16",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
@ -298,6 +403,12 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.228"
|
||||||
@ -376,6 +487,19 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"getrandom 0.4.1",
|
||||||
|
"once_cell",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
@ -426,6 +550,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
|
"tempfile",
|
||||||
"toml",
|
"toml",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
@ -477,6 +602,12 @@ version = "1.0.20"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -499,6 +630,58 @@ version = "0.11.1+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip2"
|
||||||
|
version = "1.0.2+wasi-0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip3"
|
||||||
|
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-encoder"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
||||||
|
dependencies = [
|
||||||
|
"leb128fmt",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-metadata"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"indexmap",
|
||||||
|
"wasm-encoder",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmparser"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"hashbrown 0.15.5",
|
||||||
|
"indexmap",
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
@ -671,3 +854,91 @@ checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rust-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-core"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"heck",
|
||||||
|
"wit-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rust"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"heck",
|
||||||
|
"indexmap",
|
||||||
|
"prettyplease",
|
||||||
|
"syn",
|
||||||
|
"wasm-metadata",
|
||||||
|
"wit-bindgen-core",
|
||||||
|
"wit-component",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rust-macro"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"prettyplease",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wit-bindgen-core",
|
||||||
|
"wit-bindgen-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-component"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bitflags",
|
||||||
|
"indexmap",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"wasm-encoder",
|
||||||
|
"wasm-metadata",
|
||||||
|
"wasmparser",
|
||||||
|
"wit-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-parser"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"id-arena",
|
||||||
|
"indexmap",
|
||||||
|
"log",
|
||||||
|
"semver",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"unicode-xid",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|||||||
@ -3,6 +3,9 @@ name = "tmuxido"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "3"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|||||||
162
src/lib.rs
Normal file
162
src/lib.rs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
pub mod cache;
|
||||||
|
pub mod config;
|
||||||
|
pub mod session;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use cache::ProjectCache;
|
||||||
|
use config::Config;
|
||||||
|
use session::{SessionConfig, TmuxSession};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::time::UNIX_EPOCH;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
pub fn show_cache_status(config: &Config) -> Result<()> {
|
||||||
|
if !config.cache_enabled {
|
||||||
|
println!("Cache is disabled in configuration");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cache) = ProjectCache::load()? {
|
||||||
|
let age_seconds = cache.age_in_seconds();
|
||||||
|
let age_hours = age_seconds / 3600;
|
||||||
|
let age_minutes = (age_seconds % 3600) / 60;
|
||||||
|
|
||||||
|
println!("Cache status:");
|
||||||
|
println!(" Location: {}", ProjectCache::cache_path()?.display());
|
||||||
|
println!(" Projects cached: {}", cache.projects.len());
|
||||||
|
println!(" Directories tracked: {}", cache.dir_mtimes.len());
|
||||||
|
println!(" Last updated: {}h {}m ago", age_hours, age_minutes);
|
||||||
|
} else {
|
||||||
|
println!("No cache found");
|
||||||
|
println!(" Run without --cache-status to create it");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_projects(config: &Config, force_refresh: bool) -> Result<Vec<PathBuf>> {
|
||||||
|
if !config.cache_enabled || force_refresh {
|
||||||
|
let (projects, fingerprints) = scan_all_roots(config)?;
|
||||||
|
let cache = ProjectCache::new(projects.clone(), fingerprints);
|
||||||
|
cache.save()?;
|
||||||
|
eprintln!("Cache updated with {} projects", projects.len());
|
||||||
|
return Ok(projects);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut cache) = ProjectCache::load()? {
|
||||||
|
// Cache no formato antigo (sem dir_mtimes) → atualizar com rescan completo
|
||||||
|
if cache.dir_mtimes.is_empty() {
|
||||||
|
eprintln!("Upgrading cache, scanning for projects...");
|
||||||
|
let (projects, fingerprints) = scan_all_roots(config)?;
|
||||||
|
let new_cache = ProjectCache::new(projects.clone(), fingerprints);
|
||||||
|
new_cache.save()?;
|
||||||
|
eprintln!("Cache updated with {} projects", projects.len());
|
||||||
|
return Ok(projects);
|
||||||
|
}
|
||||||
|
|
||||||
|
let changed = cache.validate_and_update(&|root| scan_from_root(root, config))?;
|
||||||
|
if changed {
|
||||||
|
cache.save()?;
|
||||||
|
eprintln!(
|
||||||
|
"Cache updated incrementally ({} projects)",
|
||||||
|
cache.projects.len()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
eprintln!("Using cached projects ({} projects)", cache.projects.len());
|
||||||
|
}
|
||||||
|
return Ok(cache.projects);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sem cache ainda — scan completo inicial
|
||||||
|
eprintln!("No cache found, scanning for projects...");
|
||||||
|
let (projects, fingerprints) = scan_all_roots(config)?;
|
||||||
|
let cache = ProjectCache::new(projects.clone(), fingerprints);
|
||||||
|
cache.save()?;
|
||||||
|
eprintln!("Cache updated with {} projects", projects.len());
|
||||||
|
Ok(projects)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scan_all_roots(config: &Config) -> Result<(Vec<PathBuf>, HashMap<PathBuf, u64>)> {
|
||||||
|
let mut all_projects = Vec::new();
|
||||||
|
let mut all_fingerprints = HashMap::new();
|
||||||
|
|
||||||
|
for path_str in &config.paths {
|
||||||
|
let path = PathBuf::from(shellexpand::tilde(path_str).to_string());
|
||||||
|
|
||||||
|
if !path.exists() {
|
||||||
|
eprintln!("Warning: Path does not exist: {}", path.display());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!("Scanning: {}", path.display());
|
||||||
|
|
||||||
|
let (projects, fingerprints) = scan_from_root(&path, config)?;
|
||||||
|
all_projects.extend(projects);
|
||||||
|
all_fingerprints.extend(fingerprints);
|
||||||
|
}
|
||||||
|
|
||||||
|
all_projects.sort();
|
||||||
|
all_projects.dedup();
|
||||||
|
|
||||||
|
Ok((all_projects, all_fingerprints))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scan_from_root(
|
||||||
|
root: &Path,
|
||||||
|
config: &Config,
|
||||||
|
) -> Result<(Vec<PathBuf>, HashMap<PathBuf, u64>)> {
|
||||||
|
let mut projects = Vec::new();
|
||||||
|
let mut fingerprints = HashMap::new();
|
||||||
|
|
||||||
|
for entry in WalkDir::new(root)
|
||||||
|
.max_depth(config.max_depth)
|
||||||
|
.follow_links(false)
|
||||||
|
.into_iter()
|
||||||
|
.filter_entry(|e| {
|
||||||
|
e.file_name()
|
||||||
|
.to_str()
|
||||||
|
.map(|s| !s.starts_with('.') || s == ".git")
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
let entry = match entry {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if entry.file_type().is_dir() {
|
||||||
|
if entry.file_name() == ".git" {
|
||||||
|
// Projeto encontrado
|
||||||
|
if let Some(parent) = entry.path().parent() {
|
||||||
|
projects.push(parent.to_path_buf());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Registrar mtime para detecção de mudanças futuras
|
||||||
|
if let Ok(metadata) = entry.metadata()
|
||||||
|
&& let Ok(modified) = metadata.modified()
|
||||||
|
{
|
||||||
|
let mtime = modified
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.as_secs();
|
||||||
|
fingerprints.insert(entry.path().to_path_buf(), mtime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((projects, fingerprints))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn launch_tmux_session(selected: &Path, config: &Config) -> Result<()> {
|
||||||
|
// Try to load project-specific config, fallback to global default
|
||||||
|
let session_config = SessionConfig::load_from_project(selected)?
|
||||||
|
.unwrap_or_else(|| config.default_session.clone());
|
||||||
|
|
||||||
|
// Create tmux session
|
||||||
|
let tmux_session = TmuxSession::new(selected);
|
||||||
|
tmux_session.create(&session_config)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
161
src/main.rs
161
src/main.rs
@ -1,18 +1,10 @@
|
|||||||
mod cache;
|
|
||||||
mod config;
|
|
||||||
mod session;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use cache::ProjectCache;
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use config::Config;
|
|
||||||
use session::{SessionConfig, TmuxSession};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::time::UNIX_EPOCH;
|
use tmuxido::config::Config;
|
||||||
use walkdir::WalkDir;
|
use tmuxido::{get_projects, launch_tmux_session, show_cache_status};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(
|
#[command(
|
||||||
@ -74,141 +66,6 @@ fn main() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_cache_status(config: &Config) -> Result<()> {
|
|
||||||
if !config.cache_enabled {
|
|
||||||
println!("Cache is disabled in configuration");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(cache) = ProjectCache::load()? {
|
|
||||||
let age_seconds = cache.age_in_seconds();
|
|
||||||
let age_hours = age_seconds / 3600;
|
|
||||||
let age_minutes = (age_seconds % 3600) / 60;
|
|
||||||
|
|
||||||
println!("Cache status:");
|
|
||||||
println!(" Location: {}", ProjectCache::cache_path()?.display());
|
|
||||||
println!(" Projects cached: {}", cache.projects.len());
|
|
||||||
println!(" Directories tracked: {}", cache.dir_mtimes.len());
|
|
||||||
println!(" Last updated: {}h {}m ago", age_hours, age_minutes);
|
|
||||||
} else {
|
|
||||||
println!("No cache found");
|
|
||||||
println!(" Run without --cache-status to create it");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_projects(config: &Config, force_refresh: bool) -> Result<Vec<PathBuf>> {
|
|
||||||
if !config.cache_enabled || force_refresh {
|
|
||||||
let (projects, fingerprints) = scan_all_roots(config)?;
|
|
||||||
let cache = ProjectCache::new(projects.clone(), fingerprints);
|
|
||||||
cache.save()?;
|
|
||||||
eprintln!("Cache updated with {} projects", projects.len());
|
|
||||||
return Ok(projects);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mut cache) = ProjectCache::load()? {
|
|
||||||
// Cache no formato antigo (sem dir_mtimes) → atualizar com rescan completo
|
|
||||||
if cache.dir_mtimes.is_empty() {
|
|
||||||
eprintln!("Upgrading cache, scanning for projects...");
|
|
||||||
let (projects, fingerprints) = scan_all_roots(config)?;
|
|
||||||
let new_cache = ProjectCache::new(projects.clone(), fingerprints);
|
|
||||||
new_cache.save()?;
|
|
||||||
eprintln!("Cache updated with {} projects", projects.len());
|
|
||||||
return Ok(projects);
|
|
||||||
}
|
|
||||||
|
|
||||||
let changed = cache.validate_and_update(&|root| scan_from_root(root, config))?;
|
|
||||||
if changed {
|
|
||||||
cache.save()?;
|
|
||||||
eprintln!(
|
|
||||||
"Cache updated incrementally ({} projects)",
|
|
||||||
cache.projects.len()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
eprintln!("Using cached projects ({} projects)", cache.projects.len());
|
|
||||||
}
|
|
||||||
return Ok(cache.projects);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sem cache ainda — scan completo inicial
|
|
||||||
eprintln!("No cache found, scanning for projects...");
|
|
||||||
let (projects, fingerprints) = scan_all_roots(config)?;
|
|
||||||
let cache = ProjectCache::new(projects.clone(), fingerprints);
|
|
||||||
cache.save()?;
|
|
||||||
eprintln!("Cache updated with {} projects", projects.len());
|
|
||||||
Ok(projects)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scan_all_roots(config: &Config) -> Result<(Vec<PathBuf>, HashMap<PathBuf, u64>)> {
|
|
||||||
let mut all_projects = Vec::new();
|
|
||||||
let mut all_fingerprints = HashMap::new();
|
|
||||||
|
|
||||||
for path_str in &config.paths {
|
|
||||||
let path = PathBuf::from(shellexpand::tilde(path_str).to_string());
|
|
||||||
|
|
||||||
if !path.exists() {
|
|
||||||
eprintln!("Warning: Path does not exist: {}", path.display());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
eprintln!("Scanning: {}", path.display());
|
|
||||||
|
|
||||||
let (projects, fingerprints) = scan_from_root(&path, config)?;
|
|
||||||
all_projects.extend(projects);
|
|
||||||
all_fingerprints.extend(fingerprints);
|
|
||||||
}
|
|
||||||
|
|
||||||
all_projects.sort();
|
|
||||||
all_projects.dedup();
|
|
||||||
|
|
||||||
Ok((all_projects, all_fingerprints))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scan_from_root(root: &Path, config: &Config) -> Result<(Vec<PathBuf>, HashMap<PathBuf, u64>)> {
|
|
||||||
let mut projects = Vec::new();
|
|
||||||
let mut fingerprints = HashMap::new();
|
|
||||||
|
|
||||||
for entry in WalkDir::new(root)
|
|
||||||
.max_depth(config.max_depth)
|
|
||||||
.follow_links(false)
|
|
||||||
.into_iter()
|
|
||||||
.filter_entry(|e| {
|
|
||||||
e.file_name()
|
|
||||||
.to_str()
|
|
||||||
.map(|s| !s.starts_with('.') || s == ".git")
|
|
||||||
.unwrap_or(false)
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let entry = match entry {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
if entry.file_type().is_dir() {
|
|
||||||
if entry.file_name() == ".git" {
|
|
||||||
// Projeto encontrado
|
|
||||||
if let Some(parent) = entry.path().parent() {
|
|
||||||
projects.push(parent.to_path_buf());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Registrar mtime para detecção de mudanças futuras
|
|
||||||
if let Ok(metadata) = entry.metadata() {
|
|
||||||
if let Ok(modified) = metadata.modified() {
|
|
||||||
let mtime = modified
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.unwrap_or_default()
|
|
||||||
.as_secs();
|
|
||||||
fingerprints.insert(entry.path().to_path_buf(), mtime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((projects, fingerprints))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn select_project_with_fzf(projects: &[PathBuf]) -> Result<PathBuf> {
|
fn select_project_with_fzf(projects: &[PathBuf]) -> Result<PathBuf> {
|
||||||
let mut child = Command::new("fzf")
|
let mut child = Command::new("fzf")
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
@ -237,15 +94,3 @@ fn select_project_with_fzf(projects: &[PathBuf]) -> Result<PathBuf> {
|
|||||||
|
|
||||||
Ok(PathBuf::from(selected))
|
Ok(PathBuf::from(selected))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn launch_tmux_session(selected: &Path, config: &Config) -> Result<()> {
|
|
||||||
// Try to load project-specific config, fallback to global default
|
|
||||||
let session_config = SessionConfig::load_from_project(selected)?
|
|
||||||
.unwrap_or_else(|| config.default_session.clone());
|
|
||||||
|
|
||||||
// Create tmux session
|
|
||||||
let tmux_session = TmuxSession::new(selected);
|
|
||||||
tmux_session.create(&session_config)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user