Pentiment.Source (pentiment v0.1.5)
Represents a source of text that diagnostics can reference.
Sources provide the content needed to display source code context in diagnostic output. There are three ways to create a source:
Source Types
from_file/1 - File on disk
Reads content from a file path. The source name is the file path.
source = Pentiment.Source.from_file("lib/my_app.ex")from_string/2 - In-memory content
Creates a source from a string with a display name. Useful for code that isn't on disk (user input, test fixtures, generated code).
source = Pentiment.Source.from_string("<stdin>", user_input)
source = Pentiment.Source.from_string("generated.ex", generated_code)named/1 - Deferred content
Creates a source with just a name, no content. Content is provided later when formatting. Useful when accumulating diagnostics and deferring file reads.
source = Pentiment.Source.named("lib/app.ex")
# Later, when formatting:
Pentiment.format(report, %{"lib/app.ex" => File.read!("lib/app.ex")})Accessing Content
Use lines/1 to get the source as a list of lines (for rendering), and
content/1 to get the raw string content.
Summary
Functions
Converts a byte offset to a line and column position.
Returns the raw string content of the source.
Creates a source from a file path.
Creates a source from a string with a display name.
Returns true if the source has content available.
Returns a specific line from the source (1-indexed).
Returns the total number of lines, or nil if content is not available.
Returns a range of lines from the source (1-indexed, inclusive).
Returns the source content as a list of lines.
Returns the source name (file path or display name).
Creates a named source without content.
Types
Functions
@spec byte_to_position(t(), non_neg_integer()) :: {pos_integer(), pos_integer()} | nil
Converts a byte offset to a line and column position.
Returns {line, column} where both are 1-indexed, or nil if the offset
is out of bounds or no content is available.
Examples
iex> source = Pentiment.Source.from_string("test", "hello\nworld")
iex> Pentiment.Source.byte_to_position(source, 0)
{1, 1}
iex> source = Pentiment.Source.from_string("test", "hello\nworld")
iex> Pentiment.Source.byte_to_position(source, 6)
{2, 1}
iex> source = Pentiment.Source.from_string("test", "hello\nworld")
iex> Pentiment.Source.byte_to_position(source, 100)
nil
Returns the raw string content of the source.
Returns nil if no content is available.
Creates a source from a file path.
Reads the file content immediately. Raises if the file cannot be read.
Examples
iex> source = Pentiment.Source.from_file("lib/my_app.ex")
%Pentiment.Source{name: "lib/my_app.ex", content: "..."}
Creates a source from a string with a display name.
Use this for content that isn't on disk, like user input or generated code.
Examples
iex> source = Pentiment.Source.from_string("<stdin>", "x = 1 + 2")
%Pentiment.Source{name: "<stdin>", content: "x = 1 + 2"}
Returns true if the source has content available.
@spec line(t(), pos_integer()) :: String.t() | nil
Returns a specific line from the source (1-indexed).
Returns nil if the line doesn't exist or content is not available.
Examples
iex> source = Pentiment.Source.from_string("test", "line1\nline2\nline3")
iex> Pentiment.Source.line(source, 2)
"line2"
iex> Pentiment.Source.line(source, 100)
nil
@spec line_count(t()) :: non_neg_integer() | nil
Returns the total number of lines, or nil if content is not available.
@spec line_range(t(), pos_integer(), pos_integer()) :: [{pos_integer(), String.t()}]
Returns a range of lines from the source (1-indexed, inclusive).
Returns an empty list if content is not available.
Examples
iex> source = Pentiment.Source.from_string("test", "a\nb\nc\nd\ne")
iex> Pentiment.Source.line_range(source, 2, 4)
[{2, "b"}, {3, "c"}, {4, "d"}]
Returns the source content as a list of lines.
Lines are 1-indexed when accessed (line 1 is at index 0).
Returns nil if no content is available.
Examples
iex> source = Pentiment.Source.from_string("test", "line1\nline2\nline3")
iex> Pentiment.Source.lines(source)
["line1", "line2", "line3"]
Returns the source name (file path or display name).
Creates a named source without content.
The content must be provided later when formatting the diagnostic. This is useful when you want to defer file reads or when the content comes from an external source.
Examples
iex> source = Pentiment.Source.named("lib/app.ex")
%Pentiment.Source{name: "lib/app.ex", content: nil}