Skip to content

Commit 328805d

Browse files
committed
Added keyword feature in watcher, resolve touch comman miss bug
1 parent 9113a86 commit 328805d

9 files changed

Lines changed: 830 additions & 21 deletions

File tree

docs/toml-config-reference.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ prepend_date = false
4040
action = "skip"
4141
folder_name = "Duplicates"
4242

43+
# Optional keyword routing in one block (first match wins):
44+
# [keyword_rules]
45+
# rules = [
46+
# { to = "Amazon", keywords = ["amazon"] },
47+
# { to = "Documents", keywords = ["invoice", "receipt", "statement"] },
48+
# ]
49+
4350
[rules]
4451
Archives = ["zip", "tar", "gz", "bz2", "xz", "rar", "7z", "tgz"]
4552
Audio = ["mp3", "flac", "wav", "ogg", "m4a", "aac", "opus"]
@@ -63,6 +70,7 @@ Videos = ["mp4", "mkv", "mov", "avi", "webm", "flv", "wmv", "m4v"]
6370
| `rename.prepend_date` | `bool` | `false` | `scan`, `start` (when `rename.enabled=true`) |
6471
| `duplicates.action` | `"skip" \| "move"` | `"skip"` | `scan`, `preview`, `start` |
6572
| `duplicates.folder_name` | `string` | `"Duplicates"` | `scan`, `preview`, `start` (when `duplicates.action="move"`) |
73+
| `keyword_rules.rules` | `array<table>` | `[]` | `scan`, `preview`, `start` |
6674
| `rules.<Category>` | `array<string(extension)>` | built-in per category | `scan`, `preview`, `start` |
6775

6876
## Detailed reference
@@ -175,12 +183,34 @@ All fields in this section are ignored unless `rename.enabled = true`.
175183
- Runtime behavior:
176184
Duplicate destination is `<category-dir>/<duplicates.folder_name>/...`.
177185

186+
### `[keyword_rules]`
187+
188+
#### `keyword_rules.rules`
189+
190+
- Type: `array<table>`
191+
- Default: `[]`
192+
- Meaning:
193+
Ordered keyword routing rules evaluated before extension rules.
194+
- Runtime behavior:
195+
- Rules are evaluated top-to-bottom, first matching rule wins.
196+
- Filename matching is case-insensitive substring matching.
197+
- Match mode is OR within each rule (`any` keyword hit matches).
198+
- Empty `to` values and empty keywords are ignored.
199+
- If no keyword rule matches, routing falls through to `[rules]`.
200+
- Rule fields:
201+
- `to` (`string`): destination category/folder name.
202+
- `keywords` (`array<string>`): match keywords for that rule.
203+
- Example:
204+
`[keyword_rules]` with
205+
`rules = [{ to = "Documents", keywords = ["invoice", "receipt"] }]`
206+
routes `May_RECEIPT.png` to `Documents` with first-match precedence.
207+
178208
### `[rules]`
179209

180210
- Type: map/table of category name -> extension list
181211
- Default: built-in categories from `src/config/defaults.rs`
182212
- Meaning:
183-
Routes files by extension to category folder.
213+
Routes files by extension to category folder when no keyword rule matched.
184214
- Runtime behavior:
185215
- Extension matching is case-insensitive.
186216
- Files without extensions fall back to `other_category`.
@@ -204,7 +234,7 @@ These are the built-in defaults used when no custom rules are set:
204234

205235
## What config does not control (today)
206236

207-
- `arrange` command filters (`--keyword`, `--extension`) are CLI options, not TOML.
237+
- `arrange` command filters (`--keyword`, `--extension`) are CLI options, not TOML (separate from `[keyword_rules].rules`, which affects `scan`/`preview`/`start`).
208238
- `scan`/`preview` depth is currently top-level only.
209239
- `start` watcher is currently non-recursive.
210240

@@ -235,4 +265,3 @@ Also update:
235265
- `src/config/mod.rs` (schema + serde defaults)
236266
- `src/config/defaults.rs` (constants/default maps as needed)
237267
- tests for parse/default/runtime behavior
238-

readme.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ later they're impossible to navigate. Manual cleanup is a chore nobody does.
5050
`filo` is a small, boring, reliable tool that does the chore for you.
5151

5252
It is deliberately not clever. It does not look inside files, call machine
53-
learning models, or invent names. It routes by extension, dedupes by SHA-256,
54-
and moves things into subfolders. That's the whole product — and that's the
55-
point.
53+
learning models, or invent names. It routes by keyword/extension, dedupes by
54+
SHA-256, and moves things into subfolders. That's the whole product — and
55+
that's the point.
5656

5757
---
5858

@@ -268,9 +268,17 @@ prepend_date = false
268268
action = "skip"
269269
folder_name = "Duplicates"
270270

271+
# Optional ordered keyword routing in one block (first match wins):
272+
[keyword_rules]
273+
rules = [
274+
{ to = "Amazon", keywords = ["amazon"] },
275+
{ to = "Documents", keywords = ["invoice", "receipt", "statement"] },
276+
]
277+
271278
[rules]
272279
# Category -> list of extensions (no leading dot). Case-insensitive.
273280
# Add/remove freely. Unknown extensions fall through to `other_category`.
281+
# Used only when no keyword rule matched.
274282
Archives = ["zip", "tar", "gz", "bz2", "xz", "rar", "7z", "tgz"]
275283
Audio = ["mp3", "flac", "wav", "ogg", "m4a", "aac", "opus"]
276284
Code = ["rs", "py", "js", "ts", "go", "c", "cpp", "h", "java", "rb", "sh"]

0 commit comments

Comments
 (0)