Project awareness GenServer, modeled after Emacs projectile.
Tracks the current project root, caches the file list, and persists a
known-projects list to ~/.config/minga/known-projects so that SPC p p
works across editor sessions.
State
current_root— the active project root (detected from the first opened file)project_type— the type of project (:git,:mix,:cargo, etc.)cached_files— the file list for the current project (populated by a background Task)known_projects— list of all project roots the user has visited, persisted to diskrecent_files— per-project list of recently opened files, most recent first, persisted to diskrebuilding?— true while a background Task is rebuilding the file cache
File cache
The cached file list lives in GenServer state (not ETS). Only one consumer
(the picker, running inside the Editor process) reads it at a time, so a
GenServer is simpler and sufficient. Cache rebuilds run in a supervised
Task to keep the GenServer responsive during the shell-out to fd or
git ls-files.
Summary
Types
Per-project recent files map: project root => list of relative paths (most recent first).
Project GenServer state.
Functions
Adds a directory as a known project.
Finds alternate files (test <> implementation) for the given file.
Returns a specification to start this module under a supervisor.
Detects the project root for a file and sets it as the current project.
Detects the test runner for a project.
Returns the cached file list for the current project.
Invalidates the file cache and triggers a rebuild.
Returns the list of known project roots.
Lists all files in the given directory, respecting .gitignore.
Returns the list of recently opened files for the current project (relative paths, most recent first).
Records a file as recently opened in the current project.
Removes a project from the known-projects list.
Returns the current project root, falling back to File.cwd!().
Returns the current project root, or nil if none is detected.
Starts the project GenServer.
Switches to a known project root, triggering a cache rebuild.
Generates a command to run all tests.
Generates a command to run test at cursor position.
Generates a command to run tests in a file.
Types
Per-project recent files map: project root => list of relative paths (most recent first).
@type t() :: %Minga.Project{ cached_files: [String.t()], current_root: String.t() | nil, known_projects: [String.t()], project_type: Minga.Project.Detector.project_type() | nil, rebuild_ref: reference() | nil, rebuilding?: boolean(), recent_files: recent_files_map() }
Project GenServer state.
Functions
@spec add(GenServer.server(), String.t()) :: :ok
Adds a directory as a known project.
Finds alternate files (test <> implementation) for the given file.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec detect_and_set(GenServer.server(), String.t()) :: :ok
Detects the project root for a file and sets it as the current project.
Automatically adds the detected root to the known-projects list and triggers a background cache rebuild. No-op if detection finds no project markers.
@spec detect_test_runner(atom(), String.t()) :: {:ok, Minga.Project.TestRunner.Runner.t()} | :none
Detects the test runner for a project.
@spec files(GenServer.server()) :: [String.t()]
Returns the cached file list for the current project.
@spec invalidate(GenServer.server()) :: :ok
Invalidates the file cache and triggers a rebuild.
@spec known_projects(GenServer.server()) :: [String.t()]
Returns the list of known project roots.
Lists all files in the given directory, respecting .gitignore.
@spec recent_files(GenServer.server()) :: [String.t()]
Returns the list of recently opened files for the current project (relative paths, most recent first).
@spec record_file(GenServer.server(), String.t()) :: :ok
Records a file as recently opened in the current project.
The file path should be absolute. It is stored relative to the project root. Most recent files appear first. Duplicates are moved to the front. No-op if no project root is set or the file is outside the current project.
@spec remove(GenServer.server(), String.t()) :: :ok
Removes a project from the known-projects list.
@spec resolve_root() :: String.t()
Returns the current project root, falling back to File.cwd!().
Safe to call even when the Project GenServer is not running (e.g., during
early startup or in tests): catches :exit from the GenServer call and
falls back to the working directory.
@spec root(GenServer.server()) :: String.t() | nil
Returns the current project root, or nil if none is detected.
@spec start_link(keyword()) :: GenServer.on_start()
Starts the project GenServer.
@spec switch(GenServer.server(), String.t()) :: :ok
Switches to a known project root, triggering a cache rebuild.
@spec test_all_command(Minga.Project.TestRunner.Runner.t()) :: String.t()
Generates a command to run all tests.
@spec test_at_point_command( Minga.Project.TestRunner.Runner.t(), String.t(), pos_integer() ) :: String.t() | nil
Generates a command to run test at cursor position.
@spec test_file_command(Minga.Project.TestRunner.Runner.t(), String.t()) :: String.t() | nil
Generates a command to run tests in a file.