Class: Teek::UI::TextContent

Inherits:
Object
  • Object
show all
Defined in:
lib/teek/ui/text_content.rb

Overview

The rich text API for one ui.text_area widget's content - reached via Handle#text_content, the same shape Handle#tagged/Handle#line use to hand back a CanvasItem: a small, focused companion object, not a pile of widget-specific methods on Handle itself.

Indices (every +index+/+from+/+to+/+at+ parameter below) are Tk's own text index syntax, passed through verbatim as Ruby strings - "1.0", "end", "sel.first", +"insert 1 line", a mark name, "@12,34" - see the Tk text manual page for the full grammar. This is deliberately NOT wrapped in a new index type - sugar, not a wall. Two Symbol shortcuts cover the common cases: :end and :cursor (the insert mark, renamed to something that doesn't collide with #insert the method).

Naming: a Tk text "tag" is not an HTML tag - it's a named, reusable set of display properties you apply to ranges, like a CSS class. The primary vocabulary here calls that a "format" (avoiding "style", already taken by ttk's own style: widget option); the Tk-named methods (+tag_configure+, tag_add, ...) still work as plain aliases, so 1:1 Tk documentation mapping and Tk-fluent muscle memory both keep working.

Every content-mutating method (insert/delete/replace/value=/clear/ insert_image) transparently lifts a -state disabled (read-only) widget to normal for the duration of the call and restores it after - Tk itself silently no-ops a mutation against a disabled text widget, which is exactly the kind of Tk wonk this DSL exists to hide. An app author building a read-only log pane never needs to know this footgun exists.

Constant Summary collapse

INDEX_ALIASES =
{ end: 'end', cursor: 'insert' }.freeze

Instance Method Summary collapse

Constructor Details

#initialize(app, path) ⇒ TextContent

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of TextContent.



38
39
40
41
# File 'lib/teek/ui/text_content.rb', line 38

def initialize(app, path)
  @app = app
  @path = path
end

Instance Method Details

#add_marker(name, at:) ⇒ void Also known as: mark_set

This method returns an undefined value.

A marker is a named, floating position in the text that moves with edits around it - a bookmark, not a range.

Parameters:

  • name (Symbol, String)
  • at (String, Symbol)

    where to place it



184
185
186
# File 'lib/teek/ui/text_content.rb', line 184

def add_marker(name, at:)
  @app.command(@path, :mark, :set, name, resolve_index(at))
end

#apply_format(name, from, to) ⇒ void Also known as: tag_add

This method returns an undefined value.

Applies a previously-#formatted name to a range.

Parameters:

  • name (Symbol, String)
  • from (String, Symbol)
  • to (String, Symbol)


118
119
120
# File 'lib/teek/ui/text_content.rb', line 118

def apply_format(name, from, to)
  @app.command(@path, :tag, :add, name, resolve_index(from), resolve_index(to))
end

#clearvoid

This method returns an undefined value.

Empties the whole buffer.



97
98
99
# File 'lib/teek/ui/text_content.rb', line 97

def clear
  mutate { @app.command(@path, :delete, '1.0', 'end') }
end

#clear_format(name, from, to) ⇒ void Also known as: tag_remove

This method returns an undefined value.

Removes name from a range - the format definition itself is untouched, still applyable elsewhere; see #delete_format to remove the definition entirely.

Parameters:

  • name (Symbol, String)
  • from (String, Symbol)
  • to (String, Symbol)


130
131
132
# File 'lib/teek/ui/text_content.rb', line 130

def clear_format(name, from, to)
  @app.command(@path, :tag, :remove, name, resolve_index(from), resolve_index(to))
end

#cursorString

Returns the text cursor's current position (the insert mark), as "line.char".

Returns:

  • (String)

    the text cursor's current position (the insert mark), as "line.char"



258
259
260
# File 'lib/teek/ui/text_content.rb', line 258

def cursor
  index('insert')
end

#cursor=(spec) ⇒ void

This method returns an undefined value.

Moves the text cursor.

Parameters:

  • spec (String, Symbol)


265
266
267
# File 'lib/teek/ui/text_content.rb', line 265

def cursor=(spec)
  add_marker('insert', at: spec)
end

#delete(start, end_ = nil) ⇒ void

This method returns an undefined value.

Parameters:

  • start (String, Symbol)
  • end_ (String, Symbol, nil) (defaults to: nil)

    a single character at start if omitted, the range [start, end_) otherwise



66
67
68
# File 'lib/teek/ui/text_content.rb', line 66

def delete(start, end_ = nil)
  mutate { @app.command(@path, :delete, resolve_index(start), *(end_ ? [resolve_index(end_)] : [])) }
end

#delete_format(name) ⇒ void Also known as: tag_delete

This method returns an undefined value.

Deletes a format's definition entirely, and with it every range it was applied to.

Parameters:

  • name (Symbol, String)


139
140
141
# File 'lib/teek/ui/text_content.rb', line 139

def delete_format(name)
  @app.command(@path, :tag, :delete, name)
end

#format(name, **opts) ⇒ void Also known as: tag_configure

This method returns an undefined value.

Defines (or redefines) a named format - a reusable set of display properties, applied to text ranges via #apply_format.

Parameters:

  • name (Symbol, String)
  • opts (Hash)

    Tk text-tag options, e.g. +foreground:+/+font:+/+underline:+



108
109
110
# File 'lib/teek/ui/text_content.rb', line 108

def format(name, **opts)
  @app.command(@path, :tag, :configure, name, **opts)
end

#format_ranges(name) ⇒ Array<String> Also known as: tag_ranges

Returns a flat list of index pairs - +[start1, end1, start2, end2, ...]+, one pair per contiguous applied range.

Parameters:

  • name (Symbol, String)

Returns:

  • (Array<String>)

    a flat list of index pairs - +[start1, end1, start2, end2, ...]+, one pair per contiguous applied range



147
148
149
# File 'lib/teek/ui/text_content.rb', line 147

def format_ranges(name)
  @app.split_list(@app.command(@path, :tag, :ranges, name))
end

#get(start = '1.0', end_ = 'end') ⇒ String

Parameters:

  • start (String, Symbol) (defaults to: '1.0')
  • end_ (String, Symbol, nil) (defaults to: 'end')

    a single character at start if omitted, the range [start, end_) otherwise

Returns:

  • (String)


58
59
60
# File 'lib/teek/ui/text_content.rb', line 58

def get(start = '1.0', end_ = 'end')
  @app.command(@path, :get, resolve_index(start), resolve_index(end_))
end

#index(spec) ⇒ String

Resolves any index expression to its canonical "line.char" form.

Parameters:

  • spec (String, Symbol)

Returns:

  • (String)


252
253
254
# File 'lib/teek/ui/text_content.rb', line 252

def index(spec)
  @app.command(@path, :index, resolve_index(spec))
end

#insert(index, text, *tags) ⇒ void

This method returns an undefined value.

Parameters:

  • index (String, Symbol)
  • text (String)
  • tags (Array<String, Symbol>)

    format name(s) to apply to the inserted text, same as Tk's own trailing tagList



50
51
52
# File 'lib/teek/ui/text_content.rb', line 50

def insert(index, text, *tags)
  mutate { @app.command(@path, :insert, resolve_index(index), text, *tags) }
end

#insert_image(index, image:) ⇒ void Also known as: image_create

This method returns an undefined value.

Embeds an image inline in the text flow at index.

Parameters:

  • index (String, Symbol)
  • image (Image, Teek::Photo)

    anything whose #to_s is a Tcl image name - a DSL Image or a raw Photo both work



290
291
292
# File 'lib/teek/ui/text_content.rb', line 290

def insert_image(index, image:)
  mutate { @app.command(@path, :image, :create, resolve_index(index), image: image) }
end

#mark_gravity(name, direction = nil) ⇒ String

Which way name drifts when text is inserted exactly at it - an advanced, rarely-needed Tk concept, so this stays under its Tk name only (no friendlier alias).

Parameters:

  • name (Symbol, String)
  • direction (String, Symbol, nil) (defaults to: nil)

    +:left+/+:right+ to set; omit to just read the current gravity

Returns:

  • (String)

    "left" or "right"



210
211
212
213
214
215
216
# File 'lib/teek/ui/text_content.rb', line 210

def mark_gravity(name, direction = nil)
  if direction
    @app.command(@path, :mark, :gravity, name, direction)
  else
    @app.command(@path, :mark, :gravity, name)
  end
end

#markersArray<String> Also known as: mark_names

Returns every marker currently defined, including the built-in +insert+/+current+ ones.

Returns:

  • (Array<String>)

    every marker currently defined, including the built-in +insert+/+current+ ones



198
199
200
# File 'lib/teek/ui/text_content.rb', line 198

def markers
  @app.split_list(@app.command(@path, :mark, :names))
end

#on_format(name, event) { ... } ⇒ void Also known as: on_tag

This method returns an undefined value.

#on_format_click, for an arbitrary Tk event pattern instead of the common left-click case.

Parameters:

  • name (Symbol, String)
  • event (String)

    a Tk bind event pattern, e.g. "Double-Button-1"

Yields:

  • called with no arguments



172
173
174
# File 'lib/teek/ui/text_content.rb', line 172

def on_format(name, event, &block)
  bind_format_event(name, resolve_event(event), block)
end

#on_format_click(name) { ... } ⇒ void Also known as: on_tag_click

This method returns an undefined value.

Fires on a left click anywhere text carrying name is displayed. Wired through tag bind (not a raw tcl_eval), so the existing leak-safe reconcile (teek core's TagBindInterceptor, already registered for the text widget) releases the callback if name stops being applied anywhere - the same leak-safety every other DSL event binding already gets.

Parameters:

  • name (Symbol, String)

Yields:

  • called with no arguments



161
162
163
# File 'lib/teek/ui/text_content.rb', line 161

def on_format_click(name, &block)
  bind_format_event(name, '<Button-1>', block)
end

#read_onlyBoolean

Returns whether this widget currently rejects direct typing/edits (its Tk -state is disabled) - #insert/ #delete/etc still work regardless, temporarily lifting this for their own duration (see the class docs).

Returns:

  • (Boolean)

    whether this widget currently rejects direct typing/edits (its Tk -state is disabled) - #insert/ #delete/etc still work regardless, temporarily lifting this for their own duration (see the class docs)



273
274
275
# File 'lib/teek/ui/text_content.rb', line 273

def read_only
  @app.command(@path, :cget, '-state') == 'disabled'
end

#read_only=(value) ⇒ void

This method returns an undefined value.

Parameters:

  • value (Boolean)


279
280
281
# File 'lib/teek/ui/text_content.rb', line 279

def read_only=(value)
  @app.command(@path, :configure, state: value ? :disabled : :normal)
end

#remove_marker(name) ⇒ void Also known as: mark_unset

This method returns an undefined value.

Parameters:

  • name (Symbol, String)


191
192
193
# File 'lib/teek/ui/text_content.rb', line 191

def remove_marker(name)
  @app.command(@path, :mark, :unset, name)
end

#replace(start, end_, text) ⇒ void

This method returns an undefined value.

Atomic delete-then-insert over [start, end_).

Parameters:

  • start (String, Symbol)
  • end_ (String, Symbol)
  • text (String)


75
76
77
# File 'lib/teek/ui/text_content.rb', line 75

def replace(start, end_, text)
  mutate { @app.command(@path, :replace, resolve_index(start), resolve_index(end_), text) }
end

#scroll_to(index) ⇒ void Also known as: see

This method returns an undefined value.

Scrolls the view so index is visible.

Parameters:

  • index (String, Symbol)


244
245
246
# File 'lib/teek/ui/text_content.rb', line 244

def scroll_to(index)
  @app.command(@path, :see, resolve_index(index))
end

#search(pattern, from: 'insert', to: 'end', backwards: false, regexp: false, nocase: false) ⇒ String?

Returns the matching index, or nil if not found.

Parameters:

  • pattern (String)
  • from (String, Symbol) (defaults to: 'insert')

    where to start searching

  • to (String, Symbol) (defaults to: 'end')

    the search boundary - with backwards: true this is the earliest index the search may reach, same as plain Tk search

  • backwards (Boolean) (defaults to: false)
  • regexp (Boolean) (defaults to: false)

    treat pattern as a regular expression

  • nocase (Boolean) (defaults to: false)

Returns:

  • (String, nil)

    the matching index, or nil if not found



229
230
231
232
233
234
235
236
237
# File 'lib/teek/ui/text_content.rb', line 229

def search(pattern, from: 'insert', to: 'end', backwards: false, regexp: false, nocase: false)
  args = []
  args << '-backward' if backwards
  args << '-regexp' if regexp
  args << '-nocase' if nocase
  args << '--'
  result = @app.command(@path, :search, *args, pattern, resolve_index(from), resolve_index(to))
  result.empty? ? nil : result
end

#valueString

Returns the whole buffer's text, without the synthetic trailing newline Tk always keeps at end.

Returns:

  • (String)

    the whole buffer's text, without the synthetic trailing newline Tk always keeps at end



81
82
83
# File 'lib/teek/ui/text_content.rb', line 81

def value
  get('1.0', 'end-1c')
end

#value=(text) ⇒ void

This method returns an undefined value.

Replaces the whole buffer's content outright.

Parameters:

  • text (String)


88
89
90
91
92
93
# File 'lib/teek/ui/text_content.rb', line 88

def value=(text)
  mutate {
    @app.command(@path, :delete, '1.0', 'end')
    @app.command(@path, :insert, '1.0', text)
  }
end