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

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

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

@param view — the owning view (never nil at construction).

@param line_count — number of hard lines this region owns.

Parameters:

  • view (TextView)
  • line_count (Integer) (defaults to: 0)


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

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

Instance Attribute Details

#line_count ⇒ Integer, untyped

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

Returns:

  • (Integer, untyped)


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

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.

@param str

Parameters:



1059
1060
1061
1062
1063
1064
1065
1066
1067
# File 'lib/tuile/component/text_view.rb', line 1059

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: embedded "\n" creates new hard lines within the region, other input extends the region's last hard line. Empty / nil is a no-op (but still raises when detached).

@param str

Parameters:



1015
1016
1017
1018
# File 'lib/tuile/component/text_view.rb', line 1015

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

#attached? ⇒ Boolean

@return — 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:

  • (Boolean)


980
981
982
# File 'lib/tuile/component/text_view.rb', line 980

def attached?
  !@view.nil?
end

#check_attached ⇒ void

This method returns an undefined value.



1130
1131
1132
# File 'lib/tuile/component/text_view.rb', line 1130

def check_attached
  raise "region is detached" unless attached?
end

#detach! ⇒ void

This method returns an undefined value.



1125
1126
1127
# File 'lib/tuile/component/text_view.rb', line 1125

def detach!
  @view = nil
end

#empty? ⇒ Boolean

@return — 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)


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

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.

@param at — region-relative index in [0, line_count].

@param str

Parameters:



1096
1097
1098
# File 'lib/tuile/component/text_view.rb', line 1096

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

#range ⇒ ::Range[untyped]

@return — 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[untyped])


1027
1028
1029
1030
1031
# File 'lib/tuile/component/text_view.rb', line 1027

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

#remove ⇒ void

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?.



1046
1047
1048
1049
1050
# File 'lib/tuile/component/text_view.rb', line 1046

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.

@param n

Parameters:

  • n (Integer)


1111
1112
1113
1114
1115
1116
1117
1118
# File 'lib/tuile/component/text_view.rb', line 1111

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.

@param range — region-relative hard-line indices.

@param str — replacement content.

Parameters:

  • range (::Range[untyped], Integer)
  • str (String, StyledString, nil)


1083
1084
1085
1086
# File 'lib/tuile/component/text_view.rb', line 1083

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

#text ⇒ StyledString

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

Returns:



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

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.

@param value

Parameters:



1003
1004
1005
1006
# File 'lib/tuile/component/text_view.rb', line 1003

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