Minga.Project.Detector (Minga v0.1.0)

Copy Markdown View Source

Detects the project root by walking up from a file path and looking for root marker files or directories.

This is the shared detection logic used by both Minga.Project (editor-wide project awareness) and Minga.LSP.RootDetector (per-language-server roots).

Pure functions, no process state.

Detection order

Walks up from the file's parent directory. The first directory containing any marker wins. Markers are checked in the order given, but since we stop at the nearest directory, the marker list order only matters when multiple markers exist in the same directory.

Default markers

default_markers/0 returns a broad set covering common project types: .git, mix.exs, Cargo.toml, package.json, go.mod, pyproject.toml, .minga (sentinel file users can drop into any directory to mark a project root).

Summary

Types

Project type inferred from the marker that matched.

Detection result.

Functions

Returns the default marker list as {filename, project_type} tuples.

Detects the project root for a file using the default marker list.

Detects the project root for a file using a custom marker list.

Finds the project root for a file given a flat list of marker filenames.

Types

project_type()

@type project_type() :: atom()

Project type inferred from the marker that matched.

result()

@type result() :: {:ok, root :: String.t(), project_type()} | :none

Detection result.

Functions

default_markers()

@spec default_markers() :: [{String.t(), project_type()}]

Returns the default marker list as {filename, project_type} tuples.

Combines sentinel markers (.git, .minga) with root markers from all registered languages. Pass a custom list to detect/2 if you need different markers.

detect(file_path)

@spec detect(String.t()) :: result()

Detects the project root for a file using the default marker list.

Returns {:ok, root_path, project_type} or :none.

Examples

iex> {:ok, root, _type} = Minga.Project.Detector.detect("lib/minga/editor.ex")
iex> File.exists?(Path.join(root, "mix.exs"))
true

detect(file_path, markers)

@spec detect(String.t(), [{String.t(), project_type()}]) :: result()

Detects the project root for a file using a custom marker list.

Each marker is a {filename, project_type} tuple. The walk stops at the first directory containing any marker file.

Returns {:ok, root_path, project_type} or :none.

find_root(file_path, root_markers)

@spec find_root(String.t(), [String.t()]) :: String.t()

Finds the project root for a file given a flat list of marker filenames.

This is the compatibility API used by Minga.LSP.RootDetector. It returns just the root path (no project type), falling back to File.cwd!/0 when no marker is found.