Class: Tuile::Component::TextView::Region

Inherits:
Object
  • Object
show all
Defined in:
lib/tuile/component/text_view.rb

Overview

A logical section of a Tuile::Component::TextView‘s text — a contiguous run of hard lines the app wants to address as a unit (e.g. an LLM’s “thinking” output vs. its assistant message). The view always has at least one region, an internal default that owns whatever hard lines aren’t claimed by an app-created region.

Apps don’t construct regions directly; call #create_region to get one. The handle stays valid as long as the region is attached — i.e. until #text= (or #clear) wipes the slate and installs a fresh internal default. Detached regions raise RuntimeError on every mutator and reader.

A region’s position is derived from its sibling order and counts, so growing or shrinking an earlier region implicitly shifts the ranges of all later regions. Empty regions occupy zero rows but still hold a position in the sequence; ‘region.text = “”` collapses a region’s visible footprint without detaching it. Pre-creating empty placeholder regions is supported and is the natural pattern for “I’ll fill this in later” layouts.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(view, line_count = 0) ⇒ Region

Returns a new instance of Region.

Parameters:

  • view (TextView)

    the owning view (never ‘nil` at construction).

  • line_count (Integer) (defaults to: 0)

    number of hard lines this region owns.



939
940
941
942
# File 'lib/tuile/component/text_view.rb', line 939

def initialize(view, line_count = 0)
  @view = view
  @line_count = line_count
end

Instance Attribute Details

#line_countInteger

Returns number of hard lines this region owns. Safe to read on a detached region (no error raised).

Returns:

  • (Integer)

    number of hard lines this region owns. Safe to read on a detached region (no error raised).



948
949
950
# File 'lib/tuile/component/text_view.rb', line 948

def line_count
  @line_count
end

Instance Method Details

#add_line(str) ⇒ void

This method returns an undefined value.

Appends ‘str` as a new entry in this region: starts a fresh hard line first (when the region is non-empty), then appends `str`. Scoped equivalent of Tuile::Component::TextView#add_line. On an empty region behaves like #append.

Parameters:

Raises:

  • (RuntimeError)

    when the region is detached.



1037
1038
1039
1040
1041
1042
1043
1044
1045
# File 'lib/tuile/component/text_view.rb', line 1037

def add_line(str)
  check_attached
  parsed = StyledString.parse(str)
  if empty?
    append(parsed)
  else
    append(StyledString.plain("\n") + parsed)
  end
end

#append(str) ⇒ void Also known as: <<

This method returns an undefined value.

Verbatim append into this region’s tail. Same semantics as Tuile::Component::TextView#append but scoped to the region: embedded ‘“n”` creates new hard lines within the region, no-leading-newline input extends the region’s last hard line. Empty / ‘nil` input is a no-op (but still raises when detached). When the region is the spatial tail of the view, this uses the incremental Tuile::Component::TextView#append path; mid-document regions splice the affected slice of the physical-row buffer (lines outside the region are not re-wrapped).

Parameters:

Raises:

  • (RuntimeError)

    when the region is detached.



993
994
995
996
# File 'lib/tuile/component/text_view.rb', line 993

def append(str)
  check_attached
  @view.send(:append_to_region, self, str)
end

#attached?Boolean

Returns ‘true` while the region is owned by its Tuile::Component::TextView. Becomes `false` permanently once detached (typically by Tuile::Component::TextView#text= / Tuile::Component::TextView#clear).

Returns:



953
954
955
# File 'lib/tuile/component/text_view.rb', line 953

def attached?
  !@view.nil?
end

#empty?Boolean

Returns true iff the region owns zero hard lines. Empty regions render nothing — they still hold a position in the sequence, so subsequent mutations route to them as usual.

Returns:

  • (Boolean)

    true iff the region owns zero hard lines. Empty regions render nothing — they still hold a position in the sequence, so subsequent mutations route to them as usual.



960
# File 'lib/tuile/component/text_view.rb', line 960

def empty? = @line_count.zero?

#insert(at, str) ⇒ void

This method returns an undefined value.

Inserts ‘str` at region-relative hard-line index `at`. Equivalent to `replace(at…at, str)`. Region-scoped counterpart of Tuile::Component::TextView#insert; `at == line_count` is allowed and appends at the region’s tail.

Parameters:

  • at (Integer)

    region-relative index in ‘[0, line_count]`.

  • str (String, StyledString, nil)

Raises:

  • (RuntimeError)

    when the region is detached.



1074
1075
1076
# File 'lib/tuile/component/text_view.rb', line 1074

def insert(at, str)
  replace(at...at, str)
end

#rangeRange

The hard-line indices this region currently occupies — ‘start…(start + line_count)`. Empty regions return a degenerate exclusive range at their position (e.g. `5…5`). The result is computed on each call and so always reflects sibling mutations.

Returns:

  • (Range)

    the hard-line indices this region currently occupies — ‘start…(start + line_count)`. Empty regions return a degenerate exclusive range at their position (e.g. `5…5`). The result is computed on each call and so always reflects sibling mutations.

Raises:

  • (RuntimeError)

    when the region is detached.



1005
1006
1007
1008
1009
# File 'lib/tuile/component/text_view.rb', line 1005

def range
  check_attached
  start = @view.send(:region_start_index, self)
  start...(start + @line_count)
end

#removevoid

This method returns an undefined value.

Removes this region from its view. The region’s hard lines (if any) are deleted from the buffer — subsequent regions’ ranges shift up by ‘line_count` — and the handle detaches permanently. The view keeps its always-≥1-region invariant: if this was the only remaining region, a fresh internal default is installed (the app doesn’t get a handle to it; call Tuile::Component::TextView#create_region again to start tracking).

Idempotent: calling ‘remove` on an already-detached region is a silent no-op (unlike the other mutators, which raise). This lets cleanup paths blindly call `remove` without first checking #attached?.



1024
1025
1026
1027
1028
# File 'lib/tuile/component/text_view.rb', line 1024

def remove
  return unless attached?

  @view.send(:remove_region, self)
end

#remove_last_n_lines(n) ⇒ void

This method returns an undefined value.

Drops the last ‘n` hard lines from this region’s tail. Subsequent regions’ ranges shift up by the number actually dropped. ‘n` is clamped to #line_count, so passing a large `n` empties the region — the handle stays attached (use #remove when the goal is to drop the region itself). `n == 0` and an already-empty region are no-ops.

Parameters:

  • n (Integer)

Raises:

  • (RuntimeError)

    when the region is detached.

  • (TypeError)

    when ‘n` is not an `Integer`.

  • (ArgumentError)

    when ‘n` is negative.



1089
1090
1091
1092
1093
1094
1095
1096
# File 'lib/tuile/component/text_view.rb', line 1089

def remove_last_n_lines(n)
  check_attached
  raise TypeError, "expected Integer, got #{n.inspect}" unless n.is_a?(Integer)
  raise ArgumentError, "n must not be negative, got #{n}" if n.negative?
  return if n.zero? || empty?

  @view.send(:remove_last_n_from_region, self, n)
end

#replace(range, str) ⇒ void

This method returns an undefined value.

Replaces a contiguous range of this region’s hard lines with the parsed content of ‘str`. Region-scoped counterpart of Tuile::Component::TextView#replace: indices are 0-based **within the region** (so `replace(0, “x”)` rewrites the region’s first line, not the buffer’s). Same range conventions apply — ‘Integer`, inclusive/exclusive `Range`, empty range as insertion at `begin`, and `begin == line_count` for end-insertion.

Parameters:

  • range (Range, Integer)

    region-relative hard-line indices.

  • str (String, StyledString, nil)

    replacement content.

Raises:

  • (RuntimeError)

    when the region is detached.

  • (TypeError)

    when ‘range` or `str` has the wrong type.

  • (ArgumentError)

    on negative, malformed, or out-of-bounds ranges.



1061
1062
1063
1064
# File 'lib/tuile/component/text_view.rb', line 1061

def replace(range, str)
  check_attached
  @view.send(:replace_in_region, self, range, str)
end

#textStyledString

Returns the joined content of just this region’s hard lines. Empty regions return StyledString::EMPTY.

Returns:

  • (StyledString)

    the joined content of just this region’s hard lines. Empty regions return StyledString::EMPTY.

Raises:

  • (RuntimeError)

    when the region is detached.



965
966
967
968
# File 'lib/tuile/component/text_view.rb', line 965

def text
  check_attached
  @view.send(:text_for_region, self)
end

#text=(value) ⇒ void

This method returns an undefined value.

Replaces all of this region’s hard lines with the parsed content of ‘value`. Accepts the same inputs as Tuile::Component::TextView#text=; empty or `nil` content collapses the region to zero hard lines.

Parameters:

Raises:

  • (RuntimeError)

    when the region is detached.



976
977
978
979
# File 'lib/tuile/component/text_view.rb', line 976

def text=(value)
  check_attached
  @view.send(:set_region_text, self, value)
end