-
Notifications
You must be signed in to change notification settings - Fork 1
Collectors
Collectors are the starting point of every SmartMotion pipeline. Their job is to gather a raw dataset — often lines of text from the current buffer — that can later be filtered, extracted, and visualized.
Tip
Think of collectors as input sources. They define where to look before SmartMotion decides what to act on.
A collector receives context (e.g. buffer, window) and returns a list (or stream) of strings or objects that represent the data to process.
This could be:
- All lines in the current buffer
- Just visible lines in the window
- Lines from multiple open buffers
- Results from Telescope or git
Anything that produces a list of “searchable units” can be a collector.
SmartMotion collectors are Lua coroutines — they yield data as it's needed.
This has two big benefits:
-
Early-exit performance: Extractors can pull just one match without collecting the full buffer.
- When looking for the first valid target, the extractor runs once, and the collector yields only once — super efficient.
- Streaming scalability: When building the full target list (for label generation), the entire collector output is walked, but only once.
This means the entire pipeline only needs 2 loops total:
- One loop to find the first match
- One loop to get all targets (if needed for hint labels)
Important
This is why both collectors and extractors are coroutines. It avoids unnecessary memory allocations and keeps everything responsive even with huge buffers.
| Name | Description |
|---|---|
lines |
Yields every line in the current buffer |
Note
Additional built-in collectors like visible_lines, multi_buffer_lines, or telescope_results are planned or may be available in user modules.
In a motion definition:
pipeline = {
collector = "lines",
extractor = "words",
visualizer = "hint_start",
}The collector here yields all lines in the buffer. The extractor pulls word targets from those lines.
A collector is a module that implements a coroutine-style run(ctx, cfg, motion_state) function.
---@type SmartMotionCollectorModule
local M = {}
function M.run(ctx, cfg, motion_state)
return coroutine.create(function()
local lines = vim.api.nvim_buf_get_lines(ctx.bufnr, 0, -1, false)
for i, line in ipairs(lines) do
coroutine.yield({
text = line,
line_number = i - 1,
})
end
end)
end
return MNote
This version yields structured line objects with metadata (text, line_number) — which is required by extractors like lines.
Register your collector like this:
require("smart-motion.core.registries")
:get().collectors.register("my_lines", MyCollector)All modules and wrappers receive:
| Param | Description |
|---|---|
ctx |
Context object (bufnr, winid, etc.) |
cfg |
User-defined plugin configuration from setup(opts) - includes global fields like keys, presets, and highlight. Rarely needed inside modules, but useful if global toggles or flags are introduced. |
motion_state |
Mutable state that persists across pipeline steps and ferries shared data |
Warning
Only motion_state is intended to be mutated. Use it to store extracted targets, intermediate results, or flags shared between modules.
Collectors could be written to fetch from:
- Git changes (e.g., jump to modified lines)
- Telescope search results
- LSP diagnostics or references
- Multiple buffers or project-wide files
SmartMotion is designed to accommodate all of these.
For the next step in the pipeline, check out: