defmodule Raxol.Terminal.ScreenBuffer.WriteOps do @moduledoc false alias Raxol.Terminal.Cell alias Raxol.Terminal.Buffer.Writer def resize(buffer, new_width, new_height) do default_cell = %Cell{ char: " ", style: nil, dirty: nil, wide_placeholder: false } new_cells = List.duplicate(List.duplicate(default_cell, new_width), new_height) cells = buffer.cells || [] new_cells = Enum.reduce(0..min(buffer.height - 1, new_height - 1), new_cells, fn row, acc -> row_data = Enum.at(cells, row, []) Enum.reduce(0..min(buffer.width - 1, new_width - 1), acc, fn col, row_acc -> existing_cell = Enum.at(row_data, col) || default_cell current_row = Enum.at(row_acc, row, List.duplicate(default_cell, new_width)) updated_row = List.replace_at(current_row, col, existing_cell) List.replace_at(row_acc, row, updated_row) end) end) %{ buffer | width: new_width, height: new_height, cells: new_cells, selection: nil, scroll_region: nil } end def write_char(buffer, x, y, char) do write_char(buffer, x, y, char, buffer.default_style) end def write_char(buffer, x, y, char, style) when x >= 0 and y >= 0 do case {x < buffer.width, y < buffer.height} do {true, true} -> Writer.write_char(buffer, x, y, char, style) _ -> buffer end end def write_string(buffer, x, y, string), do: write_string(buffer, x, y, string, nil) def write_string(buffer, x, y, string, style) when x >= 0 and y >= 0 do case {x < buffer.width, y < buffer.height} do {true, true} -> Writer.write_string(buffer, x, y, string, style) _ -> buffer end end def get_char(buffer, x, y) do case {x >= 0 and x < buffer.width, y >= 0 and y < buffer.height} do {true, true} -> row = Enum.at(buffer.cells, y, []) cell = Enum.at(row, x) case cell do %{char: char} -> char _ -> " " end _ -> " " end end def get_cell(buffer, x, y) when x >= 0 and y >= 0 do cell = if x < buffer.width and y < buffer.height do case buffer.cells do nil -> Cell.new() cells -> cells |> Enum.at(y, []) |> Enum.at(x, Cell.new()) end else Cell.new() end Map.from_struct(cell) end def get_cell(_, _, _), do: Map.from_struct(Cell.new()) def get_content(buffer) do case buffer.cells do nil -> "" cells when is_list(cells) -> cells |> Enum.map(fn line when is_list(line) -> line |> Enum.map_join("", fn %Cell{char: char} -> char cell -> case Map.get(cell, :char) do nil -> " " char -> char end end) |> String.trim_trailing() end) |> Enum.reverse() |> Enum.drop_while(&(&1 == "")) |> Enum.reverse() |> case do [] -> "" lines -> Enum.join(lines, "\n") end _ -> "" end end def put_line(buffer, y, line) when y >= 0 and y < buffer.height do new_cells = List.replace_at(buffer.cells || [], y, line) %{buffer | cells: new_cells} end def put_line(buffer, _, _), do: buffer end