MingaAgent.FileMention (Minga v0.1.0)

Copy Markdown View Source

Handles @file mentions in chat input.

Users type @path/to/file.ex in the chat input to attach file content as context to their prompt. This module extracts those references and resolves them to content blocks prepended to the prompt text.

Mention format

A mention is @ followed by a file path. The @ must appear at the start of the input or after whitespace (not mid-word). The path extends until the next whitespace or end of string.

Resolution

Each @path is:

  1. Resolved relative to the project root
  2. Read from disk
  3. Prepended to the prompt as a fenced code block with the file path

If any mentioned file does not exist, resolution fails with an error message listing the missing files.

Summary

Types

Completion state for the @-mention popup.

A single extracted mention: the file path and its character range in the text.

Functions

Extracts @path mentions from prompt text.

Returns true if the path has an image file extension.

Creates a new completion state from the current file list.

Resolves all @path mentions in the text and returns an augmented prompt.

Resolves mentions with options.

Moves selection down (wraps around).

Moves selection up (wraps around).

Returns the currently selected candidate path, or nil if none.

Updates the prefix and re-filters candidates.

Types

completion()

@type completion() :: %{
  prefix: String.t(),
  all_files: [String.t()],
  candidates: [String.t()],
  selected: non_neg_integer(),
  anchor_line: non_neg_integer(),
  anchor_col: non_neg_integer()
}

Completion state for the @-mention popup.

mention()

@type mention() :: %{
  path: String.t(),
  start: non_neg_integer(),
  stop: non_neg_integer()
}

A single extracted mention: the file path and its character range in the text.

Functions

extract_mentions(text)

@spec extract_mentions(String.t()) :: [mention()]

Extracts @path mentions from prompt text.

Returns a list of mention maps with the file path and its character position range (for potential highlighting or removal).

Examples

iex> MingaAgent.FileMention.extract_mentions("@lib/foo.ex what does this do?")
[%{path: "lib/foo.ex", start: 0, stop: 14}]

iex> MingaAgent.FileMention.extract_mentions("look at @a.ex and @b.ex")
[%{path: "a.ex", start: 8, stop: 14}, %{path: "b.ex", start: 19, stop: 24}]

iex> MingaAgent.FileMention.extract_mentions("no mentions here")
[]

iex> MingaAgent.FileMention.extract_mentions("email@example.com is not a mention")
[]

image_path?(path)

@spec image_path?(String.t()) :: boolean()

Returns true if the path has an image file extension.

new_completion(all_files, anchor_line, anchor_col)

@spec new_completion([String.t()], non_neg_integer(), non_neg_integer()) ::
  completion()

Creates a new completion state from the current file list.

anchor_line and anchor_col mark where the @ was typed so the completion popup knows where to render and where to insert the result.

resolve_prompt(text, project_root)

@spec resolve_prompt(String.t(), String.t()) ::
  {:ok, String.t()}
  | {:ok, [ReqLLM.Message.ContentPart.t()]}
  | {:error, String.t()}

Resolves all @path mentions in the text and returns an augmented prompt.

Each mentioned text file is prepended as a fenced code block. Image files (PNG, JPEG, GIF, WebP) are returned as ContentPart structs for multi-modal API requests.

Returns:

  • {:ok, String.t()} when only text files are mentioned
  • {:ok, [ContentPart.t()]} when images are present (mixed text + image parts)
  • {:error, message} if any file doesn't exist or can't be read

resolve_prompt(text, project_root, opts)

@spec resolve_prompt(String.t(), String.t(), keyword()) ::
  {:ok, String.t()}
  | {:ok, [ReqLLM.Message.ContentPart.t()]}
  | {:error, String.t()}

Resolves mentions with options.

Options:

  • :model — the model string for vision capability checking

select_next(c)

@spec select_next(completion()) :: completion()

Moves selection down (wraps around).

select_prev(c)

@spec select_prev(completion()) :: completion()

Moves selection up (wraps around).

selected_path(map)

@spec selected_path(completion()) :: String.t() | nil

Returns the currently selected candidate path, or nil if none.

update_prefix(completion, new_prefix)

@spec update_prefix(completion(), String.t()) :: completion()

Updates the prefix and re-filters candidates.