Class: VER::Text::Tag
Overview
The first form of annotation in text widgets is a tag. A tag is a textual string that is associated with some of the characters in a text. Tags may contain arbitrary characters, but it is probably best to avoid using the characters “ ” (space), “+” (plus), or “-” (minus): these characters have special meaning in indices, so tags containing them cannot be used as indices. There may be any number of tags associated with characters in a text. Each tag may refer to a single character, a range of characters, or several ranges of characters. An individual character may have any number of tags associated with it.
A priority order is defined among tags, and this order is used in implementing some of the tag-related functions described below. When a tag is defined (by associating it with characters or setting its display options or binding commands to it), it is given a priority higher than any existing tag. The priority order of tags may be redefined using the “pathName tag raise” and “pathName tag lower” widget commands.
Tags serve three purposes in text widgets. First, they control the way information is displayed on the screen. By default, characters are displayed as determined by the -background, -font, and -foreground options for the text widget. However, display options may be associated with individual tags using the “pathName tag configur” widget command. If a character has been tagged, then the display options associated with the tag override the default display style.
Constant Summary
Constants inherited from Struct
Instance Attribute Summary collapse
-
#buffer ⇒ Object
Returns the value of attribute buffer.
-
#name ⇒ Object
Returns the value of attribute name.
Instance Method Summary collapse
-
#add(*indices) ⇒ Object
FIXME: yes, i know i’m calling ‘tag add` for every line, which makes things slower, but it seems like there is a bug in the text widget.
- #bind(*args, &block) ⇒ Object
- #cget(option) ⇒ Object
-
#comment ⇒ Object
Comment all lines that the selection touches.
- #configure(*options) ⇒ Object
- #copy ⇒ Object
- #delete ⇒ Object (also: #tag_delete)
- #each_line ⇒ Object
- #each_range(&block) ⇒ Object
- #encode_rot13! ⇒ Object
-
#evaluate! ⇒ Object
Eval contents of tag and insert them into the buffer.
- #first ⇒ Object
- #get ⇒ Object
- #indent ⇒ Object
- #inspect ⇒ Object
- #kill ⇒ Object
- #last ⇒ Object
- #lower(below_this = Tk::None) ⇒ Object (also: #tag_lower)
-
#lower_case! ⇒ Object
(also: #downcase!)
Convert all characters within the tag to lower-case using String#downcase.
- #next_range(from_index, to_index = Tk::None) ⇒ Object (also: #nextrange)
-
#pipe!(*cmd) ⇒ Object
Replace contents of tag with stdout output of a command.
- #prev_range(from_index, to_index = Tk::None) ⇒ Object (also: #prevrange)
- #raise(above_this = Tk::None) ⇒ Object (also: #tag_raise)
- #ranges ⇒ Object
- #remove(index, *indices) ⇒ Object (also: #tag_remove)
- #replace(*args) ⇒ Object
- #to_s ⇒ Object
- #to_tcl ⇒ Object
-
#toggle_case! ⇒ Object
Toggle case within the selection.
- #uncomment ⇒ Object
- #unindent ⇒ Object
-
#upper_case! ⇒ Object
(also: #upcase!)
Convert all characters within the tag to upper-case using String#upcase.
- #wrap(width = buffer.prefix_count(80)) ⇒ Object
Methods inherited from Struct
Instance Attribute Details
#buffer ⇒ Object
Returns the value of attribute buffer
31 32 33 |
# File 'lib/ver/text/tag.rb', line 31 def buffer @buffer end |
#name ⇒ Object
Returns the value of attribute name
31 32 33 |
# File 'lib/ver/text/tag.rb', line 31 def name @name end |
Instance Method Details
#add(*indices) ⇒ Object
FIXME: yes, i know i’m calling ‘tag add` for every line, which makes
things slower, but it seems like there is a bug in the text widget.
So we aggregate the information into a single eval.
35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/ver/text/tag.rb', line 35 def add(*indices) code = [%(set win "#{buffer.tk_pathname}")] indices.each_slice(2) do |first, last| if last code << %($win tag add #{name} "#{first}" "#{last}") else code << %($win tag add #{name} "#{first}") end end Tk.execute_only(Tk::TclString.new(code.join("\n"))) end |
#bind(*args, &block) ⇒ Object
49 50 51 |
# File 'lib/ver/text/tag.rb', line 49 def bind(*args, &block) buffer.tag_bind(to_tcl, *args, &block) end |
#cget(option) ⇒ Object
53 54 55 |
# File 'lib/ver/text/tag.rb', line 53 def cget(option) buffer.tag_cget(self, option) end |
#comment ⇒ Object
Comment all lines that the selection touches. Tries to maintain indent.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/ver/text/tag.rb', line 59 def comment comment = buffer..comment_line.to_s indent = nil lines = [] each_line do |line, fc, tc| line_fc, line_tc = "#{line}.#{fc}", "#{line}.#{tc}" next if buffer.at_end == line_tc lines << line next if indent == 0 # can't get lower line = buffer.get("#{line}.#{fc}", "#{line}.#{tc}") next unless start = line =~ /\S/ indent ||= start indent = start if start < indent end indent ||= 0 buffer.undo_record do |record| lines.each do |line| record.insert("#{line}.#{indent}", comment) end end end |
#configure(*options) ⇒ Object
90 91 92 |
# File 'lib/ver/text/tag.rb', line 90 def configure(*) buffer.tag_configure(self, *) end |
#copy ⇒ Object
94 95 96 97 |
# File 'lib/ver/text/tag.rb', line 94 def copy chunks = ranges.map{|range| range.get } buffer.with_register{|reg| reg.value = chunks.at(1) ? chunks : chunks.first } end |
#delete ⇒ Object Also known as: tag_delete
99 100 101 |
# File 'lib/ver/text/tag.rb', line 99 def delete buffer.tag_delete(self) end |
#each_line ⇒ Object
108 109 110 111 112 113 114 115 116 117 |
# File 'lib/ver/text/tag.rb', line 108 def each_line return Enumerator.new(self, :each_line) unless block_given? each_range do |range| fy, fx, ty, tx = *range.first, *range.last fy.upto(ty) do |y| yield y, fx, tx end end end |
#each_range(&block) ⇒ Object
104 105 106 |
# File 'lib/ver/text/tag.rb', line 104 def each_range(&block) ranges.each(&block) end |
#encode_rot13! ⇒ Object
119 120 121 122 123 124 125 |
# File 'lib/ver/text/tag.rb', line 119 def encode_rot13! buffer.undo_record do |record| each_range do |range| range.encode_rot13!(record) end end end |
#evaluate! ⇒ Object
Eval contents of tag and insert them into the buffer.
128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/ver/text/tag.rb', line 128 def evaluate! file = buffer.filename each_range do |range| code = range.get Methods::Control.stdout_capture_evaluate(code, file, binding) do |res, out| range.last.lineend.insert("\n%s%p" % [out, res]) end end end |
#first ⇒ Object
140 141 142 |
# File 'lib/ver/text/tag.rb', line 140 def first buffer.index("#{self}.first") end |
#get ⇒ Object
144 145 146 147 |
# File 'lib/ver/text/tag.rb', line 144 def get values = ranges.map{|range| range.get } values.size == 1 ? values.first : values unless values.empty? end |
#indent ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/ver/text/tag.rb', line 149 def indent indent_size = buffer..shiftwidth indent = ' ' * indent_size buffer.undo_record do |record| each_line do |y, fx, tx| tx = fx + indent_size next if buffer.get("#{y}.#{fx}", "#{y}.#{tx}").empty? record.insert("#{y}.#{fx}", indent) end end end |
#inspect ⇒ Object
162 163 164 |
# File 'lib/ver/text/tag.rb', line 162 def inspect "#<VER::Text::Tag %p on %p>" % [name, buffer] end |
#kill ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/ver/text/tag.rb', line 166 def kill indices = [] chunks = ranges.map{|range| indices << range.first << range.last range.get } # A bit of duplication, but if we use copy here we have to iterate the # ranges again. buffer.with_register do |register| register.value = chunks.at(1) ? chunks : chunks.first end buffer.delete(*indices) end |
#last ⇒ Object
183 184 185 |
# File 'lib/ver/text/tag.rb', line 183 def last buffer.index("#{self}.last") end |
#lower(below_this = Tk::None) ⇒ Object Also known as: tag_lower
187 188 189 |
# File 'lib/ver/text/tag.rb', line 187 def lower(below_this = Tk::None) buffer.tag_lower(self, below_this) end |
#lower_case! ⇒ Object Also known as: downcase!
Convert all characters within the tag to lower-case using String#downcase. Usually only works for alphabetic ASCII characters.
195 196 197 198 199 200 201 |
# File 'lib/ver/text/tag.rb', line 195 def lower_case! buffer.undo_record do |record| each_range do |range| range.lower_case!(record) end end end |
#next_range(from_index, to_index = Tk::None) ⇒ Object Also known as: nextrange
204 205 206 |
# File 'lib/ver/text/tag.rb', line 204 def next_range(from_index, to_index = Tk::None) buffer.tag_nextrange(self, from_index, to_index) end |
#pipe!(*cmd) ⇒ Object
Replace contents of tag with stdout output of a command
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/ver/text/tag.rb', line 210 def pipe!(*cmd) require 'open3' Open3.popen3(*cmd) do |si, so, thread| queue = [] each_range do |range| si.write(range.get) queue.concat(range.to_a) end si.close output = so.read return if queue.empty? buffer.undo_record do |record| record.delete(*queue) record.insert(queue.first, output.chomp) end end end |
#prev_range(from_index, to_index = Tk::None) ⇒ Object Also known as: prevrange
232 233 234 |
# File 'lib/ver/text/tag.rb', line 232 def prev_range(from_index, to_index = Tk::None) buffer.tag_prevrange(self, from_index, to_index) end |
#raise(above_this = Tk::None) ⇒ Object Also known as: tag_raise
237 238 239 |
# File 'lib/ver/text/tag.rb', line 237 def raise(above_this = Tk::None) buffer.tag_raise(above_this) end |
#ranges ⇒ Object
242 243 244 |
# File 'lib/ver/text/tag.rb', line 242 def ranges buffer.tag_ranges(self) end |
#remove(index, *indices) ⇒ Object Also known as: tag_remove
246 247 248 |
# File 'lib/ver/text/tag.rb', line 246 def remove(index, *indices) buffer.tag_remove(self, index, *indices) end |
#replace(*args) ⇒ Object
251 252 253 |
# File 'lib/ver/text/tag.rb', line 251 def replace(*args) buffer.range("#{self}.first", "#{self}.last").replace(*args) end |
#to_s ⇒ Object
255 256 257 |
# File 'lib/ver/text/tag.rb', line 255 def to_s name.to_s end |
#to_tcl ⇒ Object
259 260 261 |
# File 'lib/ver/text/tag.rb', line 259 def to_tcl name.to_tcl end |
#toggle_case! ⇒ Object
Toggle case within the selection. This only works for alphabetic ASCII characters, no other encodings.
265 266 267 268 269 270 271 |
# File 'lib/ver/text/tag.rb', line 265 def toggle_case! buffer.undo_record do |record| each_range do |range| range.toggle_case!(record) end end end |
#uncomment ⇒ Object
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/ver/text/tag.rb', line 273 def uncomment comment = buffer..comment_line.to_s regex = /#{Regexp.escape(comment)}/ buffer.undo_record do |record| each_line do |y, fx, tx| from, to = "#{y}.0 linestart", "#{y}.0 lineend" line = buffer.get(from, to) if line.sub!(regex, '') record.replace(from, to, line) end end end end |
#unindent ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/ver/text/tag.rb', line 289 def unindent indent_size = buffer..shiftwidth indent = ' ' * indent_size queue = [] each_line do |y, fx, tx| tx = fx + indent_size left, right = "#{y}.#{fx}", "#{y}.#{tx}" next unless buffer.get(left, right) == indent queue << left << right end buffer.delete(*queue) end |
#upper_case! ⇒ Object Also known as: upcase!
Convert all characters within the tag to upper-case using String#upcase. Usually only works for alphabetic ASCII characters.
307 308 309 310 311 312 313 |
# File 'lib/ver/text/tag.rb', line 307 def upper_case! buffer.undo_record do |record| each_range do |range| range.upper_case!(record) end end end |
#wrap(width = buffer.prefix_count(80)) ⇒ Object
316 317 318 319 |
# File 'lib/ver/text/tag.rb', line 316 def wrap(width = buffer.prefix_count(80)) wrapped = Methods::Control.wrap_lines_of(get, width) replace(wrapped.join("\n")) end |