No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jeremie Fraeys 7332be5b8f
perf(utils): make basename linear by scanning from the end
The pattern ([^/\\]+)[/\\]*$ is unanchored at the start and goes quadratic
on long paths: ~8 ms per 600 paths, paid on every maps rebuild. A
backwards byte scan takes ~0.16 ms. Behaviour is covered by equivalence
tests against the original pattern.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 13:12:15 -04:00
.github/ISSUE_TEMPLATE refactored to use apply_to_config 2025-07-17 12:14:24 -04:00
src perf(utils): make basename linear by scanning from the end 2026-10-17 13:12:15 -04:00
tests perf(utils): make basename linear by scanning from the end 2026-10-17 13:12:15 -04:00
.gitignore feat: prepare sessionizer for release - remove debug logging and add features 2026-04-02 14:05:30 -04:00
init.lua refactor: split ui.lua into focused modules, add workspace tab picker and history-on-spawn 2026-09-10 11:06:49 -04:00
LICENSE refactored to use apply_to_config 2025-07-17 12:14:24 -04:00
README.md feat(cache): refresh a stale project cache in the background 2026-10-17 12:47:50 -04:00

Sessionizer for WezTerm

Lightweight workspace/session switcher inspired by ThePrimeagen's tmux-sessionizer. It scans your project directories, remembers recent workspaces, and lets you jump between them with fuzzy search inside WezTerm.

Features

  • Quick Access history: recently opened workspaces bubble to the top with a configurable cap.
  • Async directory scans: project discovery runs in the background so the UI never blocks.
  • Glob project roots: project path entries support shell-style globs (for example ~/src/*) and expand to all matching directories.
  • Safe defaults: configuration is validated, labels are sanitized, and the history file lives wherever you choose.
  • Notifications: human-friendly toasts (or log fallbacks) when scans fail or no projects are found.

Platform support

Works on macOS, Linux, and Windows. macOS and Linux scan directories with fd (falling back to find if fd isn't installed); fd is checked in common Homebrew/package-manager locations, so no PATH setup is required. Windows uses PowerShell's Get-ChildItem -Recurse, which is noticeably slower than fd/find on large directory trees — keep max_depth/projects scoped tightly on Windows if scans feel slow.

Installation

local wezterm = require "wezterm"
local sessionizer = wezterm.plugin.require(
  "https://github.com/jfaeys/sessionizer.wezterm"
)

local config = wezterm.config_builder and wezterm.config_builder() or {}

sessionizer.apply_to_config(config, {
  key = "f",
  mods = "LEADER",
  workspace_switcher_key = "s",
  workspace_switcher_mods = "LEADER",
  tab_picker_key = "t",
  tab_picker_mods = "LEADER",
  add_to_launch_menu = true,
  projects = {
    { path = "~/personal", max_depth = 3 },
    { path = "~/work", max_depth = 2 },
  },
  history_file = "~/.local/share/sessionizer-history.txt",
  history_max_entries = 8,
})

return config

Configuration Reference

All options are optional; reasonable defaults live in plugins/sessionizer/src/config.lua.

Option Description
key / mods Key binding that opens the sessionizer InputSelector.
workspace_switcher_key / workspace_switcher_mods Key binding that opens the unified workspace switcher (active workspaces + all discovered projects).
tab_picker_key / tab_picker_mods Key binding that opens a picker of the tabs open in your current workspace, so you can jump straight to one instead of landing on the last-active tab.
ascii_glyphs When true, use plain ASCII markers (*, o, +, |, ~) instead of ●/○/★/·/…, for fonts that lack those glyphs. Default false.
add_to_launch_menu When true, cached projects are added to the wezterm launch menu.
projects Array of strings or { path, max_depth } tables describing directories to scan. Relative paths expand relative to $HOME.
exclude_dirs Directory names to skip while scanning (see plugins/sessionizer/src/state.lua).
default_depth Fallback depth when a project entry omits max_depth.
history_file Location of the plain-text history log. Can live outside $HOME if desired.
history_max_entries Number of Quick Access entries surfaced and persisted.
cache_ttl Seconds before the cached project list counts as stale. Opening a switcher then refreshes it in the background while showing the cached list. Default 600; 0 disables auto-refresh (use refresh_projects).
warmup When true (default), a background scan is started after config load to make first open faster. Set to false for fastest startup.

Project roots and wildcards

projects[*].path supports glob patterns like *, ?, and character classes (for example ~/src/* or ~/work/**/repos). If a glob matches multiple paths, sessionizer scans each match.

max_depth accepts a number, -1 (unlimited), or "*" (treated as a very large depth).

Usage

Press the configured key combo (e.g. LEADER + F) to open the sessionizer. Fuzzy search through the list of discovered projects. Recently opened projects show a Quick Access: prefix for fast navigation.

The unified workspace switcher (workspace_switcher_key) marks active workspaces with ● and shows a dim N tabs: name · name · name summary next to any active workspace with open tabs (truncated to fit your terminal width). Selecting a workspace row lands you on its most-recently-active tab, same as before.

To jump straight to a specific tab instead, use the standalone tab picker (tab_picker_key): it fuzzy-searches the tabs open in your current workspace as its own list.

Launch-menu entries (when enabled) spawn new wezterm windows directly into the chosen project directory.

Tests

cache.lua, disk_cache.lua, sanitizer.lua, and utils.lua are pure Lua (no live WezTerm process required), so they have a small unit test suite under tests/, run against a mocked wezterm global:

lua tests/run_all.lua

Contributions and suggestions are welcome—keep the footprint small and the workflow fast.