You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `filetype_overrides` system lets a single motion adapt its pipeline per filetype. Combined with the `patterns` collector, you can target structured text in any buffer — even without a treesitter parser.
435
+
436
+
### Remote Yank Across Filetypes
437
+
438
+
One keymap that yanks the "interesting thing" in any buffer:
**How it works:** In code files, this yanks treesitter identifiers and strings remotely (without moving the cursor). In a fugitive `gitcommit` buffer, it switches to the `patterns` collector and targets modified file paths instead. One keymap, two completely different data sources, same action.
**How it works:** In code, this jumps to functions. In `.log` files, it jumps to error keywords and ISO timestamps. The `patterns` collector handles the regex matching; the rest of the pipeline (filter, visualizer, action) stays the same.
506
+
507
+
### Per-Language Treesitter Customization
508
+
509
+
You don't need the `patterns` collector to use filetype overrides. You can swap treesitter config per language:
**How it works:** Same treesitter collector everywhere, but each language gets the node types that make sense for it. Python includes `class_definition` and `decorated_definition`. Go includes `type_declaration`. SQL uses a raw query instead of node types. Languages without an override use the default `ts_node_types`.
549
+
550
+
### Standalone Patterns Motion
551
+
552
+
The `patterns` collector works independently — no filetype dispatch needed:
**How it works:** The `patterns` collector matches `https://...` URLs across visible buffer lines. No treesitter, no filetype dispatch — just a regex collector with standard pipeline stages.
573
+
574
+
---
575
+
432
576
## Next Steps
433
577
434
578
-> **[Recipes](Recipes.md)**: Pipeline basics, filter swaps, and preset overrides
Copy file name to clipboardExpand all lines: docs/Building-Custom-Motions.md
+93Lines changed: 93 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -58,6 +58,7 @@ Each stage is optional (except collector, extractor, visualizer, action). Each s
58
58
|-----------|------------------|
59
59
|`lines`| All lines in the buffer |
60
60
|`treesitter`| Treesitter syntax nodes |
61
+
|`patterns`| Vim regex matches against buffer lines |
61
62
|`diagnostics`| LSP diagnostics |
62
63
|`git_hunks`| Git changed regions |
63
64
|`quickfix`| Quickfix/location list entries |
@@ -637,6 +638,98 @@ Now `ghw`, `ghj`, `ghs` etc. all work automatically.
637
638
638
639
---
639
640
641
+
## Filetype-Aware Motions
642
+
643
+
A single motion can adapt its entire pipeline based on the current buffer's filetype. This is useful when:
644
+
645
+
- A filetype has no treesitter parser (e.g., fugitive's `gitcommit`)
646
+
- A language needs a custom treesitter query (e.g., SQL with non-standard node types)
647
+
- You want one keymap that behaves differently in different languages
648
+
649
+
### How It Works
650
+
651
+
Add `filetype_overrides` to your motion's `motion_state`. Each key is a filetype, and the value can override any pipeline module or motion_state field:
652
+
653
+
```lua
654
+
require("smart-motion").register_motion("]]", {
655
+
collector="treesitter", -- default: use treesitter
|`motion_state`| Deep-merged into motion_state (patterns, ts_query, etc.) |
704
+
705
+
### Using the Patterns Collector
706
+
707
+
The `patterns` collector finds targets using vim regex. It reads two fields from `motion_state`:
708
+
709
+
-**`patterns`** — Array of vim regex strings (required)
710
+
-**`patterns_whole_line`** — If `true`, the entire matching line is the target (default `false`)
711
+
712
+
```lua
713
+
-- Jump to file paths
714
+
motion_state= {
715
+
patterns= { "\\v\\f+" },
716
+
}
717
+
718
+
-- Jump to lines containing TODO (whole-line targets)
719
+
motion_state= {
720
+
patterns= { "TODO" },
721
+
patterns_whole_line=true,
722
+
}
723
+
```
724
+
725
+
Use `pass_through` as the extractor since the patterns collector already produces complete targets. All standard filters, visualizers, and actions work with pattern targets.
726
+
727
+
### Operator Composition
728
+
729
+
Filetype dispatch runs before the infer system. If you have a composable operator like `d` and a filetype-overridden motion like `]]`, pressing `d]]` in a gitcommit buffer automatically uses the pattern-based pipeline. No extra configuration needed.
730
+
731
+
---
732
+
640
733
## Tips
641
734
642
735
1.**Start simple.** Get a basic motion working, then add complexity.
|`patterns`| Targets matching vim regex patterns against buffer lines |
62
63
|`diagnostics`| LSP diagnostic entries |
63
64
|`git_hunks`| Git changed regions (via gitsigns or git diff) |
64
65
|`quickfix`| Quickfix or location list entries |
65
66
|`marks`| Vim marks (a-z local, A-Z global) |
66
67
|`history`| Previous SmartMotion jump targets |
67
68
69
+
### Patterns Collector
70
+
71
+
The `patterns` collector finds targets using vim regex. It reads from `motion_state`:
72
+
73
+
-**`patterns`** (string[]) — Array of vim regex strings to match
74
+
-**`patterns_whole_line`** (boolean) — If `true`, the entire matching line is the target instead of just the match
75
+
76
+
```lua
77
+
motion_state= {
78
+
patterns= { "\\v\\f+" }, -- match file paths
79
+
}
80
+
```
81
+
82
+
Multiple patterns are matched in order. Multiple matches per line are supported (the collector advances past each match). Invalid regex is safely caught via `pcall`.
83
+
84
+
The patterns collector yields standard targets, so it composes with any extractor, filter, visualizer, and action. Use `pass_through` as the extractor since the collector already produces complete targets.
85
+
86
+
### Filetype Dispatch
87
+
88
+
A pre-pipeline middleware that swaps any pipeline module based on the current buffer's filetype. This allows a single motion to adapt its behavior per filetype — e.g., using regex patterns for filetypes without treesitter parsers.
89
+
90
+
Configure it via `filetype_overrides` in a motion's `motion_state`:
The override can swap any pipeline module (`collector`, `extractor`, `modifier`, `filter`, `visualizer`, `action`) and/or deep-merge `motion_state` fields. Overrides are per-motion, so different motions can have different filetype behavior. When no override matches the current filetype, the middleware is a no-op.
112
+
68
113
### Treesitter Collector Modes
69
114
70
115
The `treesitter` collector is powerful. It supports four modes:
0 commit comments