Visualizers - FluxxField/smart-motion.nvim GitHub Wiki

Visualizers

Visualizers are the fourth stage of the SmartMotion pipeline. They are responsible for rendering the targets to the user — whether through hints, buffers, floating windows, or any custom UI.

[!TIP] Visualizers decide how your targets are displayed. They are not limited to hint labels — they can open popups, buffer views, Telescope pickers, or more.


✅ What a Visualizer Does

A visualizer receives a list of targets and can:

  • Assign and render in-place hint labels (default behavior)
  • Open a floating window with selectable targets
  • Populate Telescope with target results
  • Display overlays, custom UI, or diagnostics views

The possibilities are completely open. Hints are just the default visual form.


✨ Dynamic Labeling (Hint Visualizer Example)

The built-in hint visualizer automatically decides whether to:

  • Use 1-character or 2-character labels based on number of targets
  • Brighten, dim, or fade label segments based on input

These hint labels are what most users start with, and they support advanced feedback states like flow transitions and partial input filtering.


📦 Built-in Visualizers

Name Description
hint_start Applies hint labels to the start of the target
hint_end Applies hint labels to the end of the target

[!NOTE] These are just two examples. You can build any kind of visualization system you want.


🧱 Example Usage

Defined in a pipeline:

pipeline = {
  collector = "lines",
  extractor = "words",
  visualizer = "hint_start",
}

With highlight overrides:

highlight = {
  hint = { fg = "#E06C75" },
  first_char = { fg = "#98C379" },
  second_char = { fg = "#61AFEF" },
  first_char_dim = { fg = "#6F8D57" },
}

🧠 Feedback Mechanics (Hints Only)

The default hint visualizers support dynamic feedback:

  • Before any input: first_char is bright, second_char is dimmed
  • After first character is pressed: first_char dims, second_char brightens

This makes chaining labels intuitive and clear.

[!TIP] This feedback system is managed entirely by the visualizer.


🔧 Creating a Custom Visualizer

A visualizer implements a run(ctx, cfg, motion_state) method and can render the UI however you choose.

---@type SmartMotionVisualizerModule
local M = {}

function M.run(ctx, cfg, motion_state)
  local targets = motion_state.targets
  -- Show floating window, populate Telescope, assign labels, etc.
end

return M

Then register it:

require("smart-motion.core.registries")
  :get().visualizers.register("custom_visualizer", M)

🔮 Future Possibilities

Custom visualizers could:

  • Populate Telescope pickers with motion targets
  • Open side panels for jumping
  • Show ghost overlays in virtual text
  • Display diagnostic or LSP-aware UI
  • Combine jump targets with semantic token overlays

[!IMPORTANT] The visualizer system is intentionally unopinionated. You can use it to create entirely different interaction models.


Next: