defmodule Raxol.Terminal.Buffer.LineEditor do @moduledoc """ Provides functionality for line editing operations in the terminal buffer. """ alias Raxol.Terminal.ANSI.TextFormatting alias Raxol.Terminal.Cell alias Raxol.Terminal.ScreenBuffer @doc """ Inserts a specified number of blank lines at the given row index using the provided default_style. Existing lines from the insertion point downwards are shifted down. Lines shifted off the bottom of the buffer are discarded. Uses the buffer's default style for new lines. """ @spec insert_lines( ScreenBuffer.t(), integer(), integer(), TextFormatting.text_style() ) :: ScreenBuffer.t() def insert_lines(%{__struct__: _} = buffer, row, count, default_style) when row >= 0 and count > 0 do # Ensure row is within bounds eff_row = min(row, buffer.height - 1) # Create blank lines with the provided default style blank_cell = %Cell{style: default_style, char: " "} blank_line = List.duplicate(blank_cell, buffer.width) blank_lines_to_insert = List.duplicate(blank_line, count) # Split the buffer cells at the insertion row {top_part, bottom_part} = Enum.split(buffer.cells, eff_row) # Take lines from the bottom part that will fit after insertion # We want to keep as many lines as possible, but ensure we don't exceed buffer height max_lines_after_insertion = buffer.height - eff_row - count kept_bottom_part = Enum.take(bottom_part, max_lines_after_insertion) # Combine the parts new_cells = top_part ++ blank_lines_to_insert ++ kept_bottom_part # Ensure we don't exceed the buffer height final_cells = Enum.take(new_cells, buffer.height) %{buffer | cells: final_cells} end def insert_lines(buffer, _row, _count, _blank_cell) when is_tuple(buffer) do raise ArgumentError, "Expected buffer struct, got tuple (did you pass result of get_dimensions/1?)" end @doc """ Deletes a specified number of lines starting from the given row index. Lines below the deleted lines are shifted up. Blank lines are added at the bottom of the buffer to fill the space using the provided default_style. Uses the buffer's default style for new lines. """ @spec delete_lines( ScreenBuffer.t(), integer(), integer(), TextFormatting.text_style() ) :: ScreenBuffer.t() def delete_lines(%ScreenBuffer{} = buffer, row, count, default_style) when row >= 0 and count > 0 do # Ensure row is within bounds eff_row = min(row, buffer.height - 1) # Calculate actual number of lines to delete eff_count = min(count, buffer.height - eff_row) # Create blank lines with the provided default style to add at the bottom blank_cell = %Cell{style: default_style, char: " "} blank_line = List.duplicate(blank_cell, buffer.width) blank_lines_to_add = List.duplicate(blank_line, eff_count) # Split the buffer cells at the deletion row {top_part, part_to_modify} = Enum.split(buffer.cells, eff_row) # Skip the deleted lines and take the rest bottom_part_kept = Enum.drop(part_to_modify, eff_count) # Combine the parts new_cells = top_part ++ bottom_part_kept ++ blank_lines_to_add %{buffer | cells: new_cells} end # No-op for invalid input def delete_lines(buffer, _row, _count, _default_style), do: buffer end