Packages

Terminal emulation and driver infrastructure for Raxol. ANSI parsing, screen buffers, command processing, cursor management, input handling, session management, and termbox2 NIF integration.

Current section

Files

Jump to
raxol_terminal lib raxol terminal buffer line_operations insertion.ex
Raw

lib/raxol/terminal/buffer/line_operations/insertion.ex

defmodule Raxol.Terminal.Buffer.LineOperations.Insertion do
@moduledoc """
Line insertion operations for terminal buffers.
Handles insertion of single and multiple lines with style support.
"""
@doc """
Insert empty lines at the current cursor position.
"""
def insert_lines(buffer, count) do
{_x, y} = buffer.cursor_position
insert_lines(buffer, y, count)
end
def insert_lines(buffer, y, count) do
do_insert_lines(buffer, y, count, %{})
end
def insert_lines(buffer, y, count, style) do
do_insert_lines(buffer, y, count, style)
end
def insert_lines(buffer, y, count, scroll_top, scroll_bottom) do
do_insert_lines_with_style(buffer, y, count, scroll_top, scroll_bottom)
end
def insert_lines(buffer, y, count, scroll_top, scroll_bottom, _style) do
# do_insert_lines_in_region already creates blank lines with style
do_insert_lines_in_region(buffer, y, count, scroll_top, scroll_bottom)
end
@doc """
Internal insertion with default style.
"""
def do_insert_lines(buffer, y, count, style) do
alias Raxol.Terminal.ScreenBuffer.DataAdapter
DataAdapter.with_lines_format(buffer, fn buffer_with_lines ->
lines = Map.get(buffer_with_lines, :lines, %{})
height = Map.get(buffer_with_lines, :height, 24)
width = Map.get(buffer_with_lines, :width, 80)
# Build new lines using pattern matching
new_lines =
0..(height - 1)
|> Enum.map(fn line_y ->
{line_y, build_line_at_position(lines, line_y, y, count, width, style, height)}
end)
|> Enum.reject(fn {_line_y, line} -> is_nil(line) end)
|> Enum.into(%{})
%{buffer_with_lines | lines: new_lines}
end)
end
@doc """
Insert lines with style in a scroll region.
"""
def do_insert_lines_with_style(buffer, y, count, scroll_top, scroll_bottom) do
do_insert_lines_in_region(buffer, y, count, scroll_top, scroll_bottom)
end
# Helper functions
defp do_insert_lines_in_region(buffer, y, count, top, bottom) do
alias Raxol.Terminal.ScreenBuffer.DataAdapter
DataAdapter.with_lines_format(buffer, fn buffer_with_lines ->
lines = Map.get(buffer_with_lines, :lines, %{})
height = Map.get(buffer_with_lines, :height, 24)
width = Map.get(buffer_with_lines, :width, 80)
new_lines =
Enum.reduce(0..(height - 1), %{}, fn line_y, acc ->
cond do
# Outside scroll region - keep unchanged
line_y < top or line_y > bottom ->
original_line = Map.get(lines, line_y)
Map.put(acc, line_y, original_line)
# Before insertion point - keep unchanged
line_y < y ->
Map.put(acc, line_y, Map.get(lines, line_y))
# New inserted lines
line_y < y + count ->
Map.put(acc, line_y, create_empty_line(width, %{}))
# Shifted lines within region
line_y <= bottom ->
source_y = line_y - count
if source_y <= bottom - count do
Map.put(acc, line_y, Map.get(lines, source_y))
else
acc
end
true ->
acc
end
end)
%{buffer_with_lines | lines: new_lines}
end)
end
defp create_empty_line(width, style) do
Enum.map(0..(width - 1), fn _ -> %{char: " ", style: style} end)
end
# Pattern match on line position relative to insertion point
defp build_line_at_position(
lines,
line_y,
insert_y,
_count,
_width,
_style,
_height
)
when line_y < insert_y do
# Lines before insertion point stay the same
Map.get(lines, line_y)
end
defp build_line_at_position(
_lines,
line_y,
insert_y,
count,
width,
style,
_height
)
when line_y >= insert_y and line_y < insert_y + count do
# Insert new empty lines
create_empty_line(width, style)
end
defp build_line_at_position(
lines,
line_y,
_insert_y,
count,
_width,
_style,
height
)
when line_y < height do
# Shift remaining lines down if they fit
source_y = line_y - count
build_shifted_line(lines, source_y, height - count)
end
defp build_line_at_position(
_lines,
_line_y,
_insert_y,
_count,
_width,
_style,
_height
) do
nil
end
defp build_shifted_line(lines, source_y, max_source)
when source_y < max_source do
Map.get(lines, source_y)
end
defp build_shifted_line(_lines, _source_y, _max_source), do: nil
end