Sagents.TextLines (Sagents v0.8.0-rc.5)
Copy MarkdownPure helper for line-number math on text content.
Shared by file system tools, document editing tools, and any other surface that needs consistent line-numbered text operations. All line numbers are 1-indexed.
The line-numbered format uses right-aligned 6-char numbers with a tab separator:
" 1 First line of content"
" 2 "
" 3 Third line"
Summary
Functions
Counts occurrences of old_string in body.
Finds matches of pattern in body, returning structured results
with line numbers and optional context.
Renders lines with right-aligned 6-char line numbers and a tab separator.
Replaces lines start_line..end_line (1-indexed, inclusive) with
new_lines_text and returns the rejoined body.
Replaces old_string in body.
Splits body on newlines and returns the total line count.
An empty or nil body is treated as a single empty line.
Functions
@spec count_occurrences(String.t(), String.t()) :: non_neg_integer()
Counts occurrences of old_string in body.
@spec find(String.t() | nil, String.t(), keyword()) :: {:ok, [map()], boolean()} | {:error, String.t()}
Finds matches of pattern in body, returning structured results
with line numbers and optional context.
Options:
:regex- treat pattern as regex (default false):case_sensitive- (default true):context_lines- lines of context before/after each match (default 2):max_matches- cap on returned matches (default 20)
Returns {:ok, matches, truncated?} or {:error, reason}.
Each match is %{line_number: n, line: text, context_before: [...], context_after: [...]}.
@spec render( String.t() | nil, keyword() ) :: {String.t(), pos_integer(), pos_integer(), pos_integer()}
Renders lines with right-aligned 6-char line numbers and a tab separator.
Options:
:start_line- 1-indexed start line (default 1):limit- max lines to return (default: all)
Returns {formatted_string, start_line, end_line, total_lines}.
@spec replace_range(String.t() | nil, pos_integer(), pos_integer(), String.t()) :: {:ok, String.t(), non_neg_integer()} | {:error, String.t()}
Replaces lines start_line..end_line (1-indexed, inclusive) with
new_lines_text and returns the rejoined body.
new_lines_text semantics:
""deletes the targeted range (zero lines inserted)"\n"inserts exactly one blank line- A trailing
"\n"on non-empty content is a line terminator, not an extra blank line:"foo\n"and"foo"both insert one line"foo"
Returns {:ok, new_body, lines_replaced} or {:error, reason}.
@spec replace_text(String.t(), String.t(), String.t(), boolean()) :: {:ok, String.t(), pos_integer()} | {:error, String.t()}
Replaces old_string in body.
When replace_all is false, requires exactly one occurrence.
Returns {:ok, new_body, replacement_count} or {:error, reason}.
@spec split(String.t() | nil) :: {[String.t()], non_neg_integer()}
Splits body on newlines and returns the total line count.
An empty or nil body is treated as a single empty line.