1#
2#               tk/text.rb - Tk text classes
3#                       by Yukihiro Matsumoto <matz@caelum.co.jp>
4require 'tk'
5require 'tk/itemfont'
6require 'tk/itemconfig'
7require 'tk/scrollable'
8require 'tk/txtwin_abst'
9
10module TkTextTagConfig
11  include TkTreatItemFont
12  include TkItemConfigMethod
13
14  def __item_cget_cmd(id)  # id := [ type, tagOrId ]
15    [self.path, id[0], 'cget', id[1]]
16  end
17  private :__item_cget_cmd
18
19  def __item_config_cmd(id)  # id := [ type, tagOrId ]
20    [self.path, id[0], 'configure', id[1]]
21  end
22  private :__item_config_cmd
23
24  def __item_pathname(id)
25    if id.kind_of?(Array)
26      id = tagid(id[1])
27    end
28    [self.path, id].join(';')
29  end
30  private :__item_pathname
31
32  def tag_cget_tkstring(tagOrId, option)
33    itemcget_tkstring(['tag', tagOrId], option)
34  end
35  def tag_cget(tagOrId, option)
36    itemcget(['tag', tagOrId], option)
37  end
38  def tag_cget_strict(tagOrId, option)
39    itemcget_strict(['tag', tagOrId], option)
40  end
41  def tag_configure(tagOrId, slot, value=None)
42    itemconfigure(['tag', tagOrId], slot, value)
43  end
44  def tag_configinfo(tagOrId, slot=nil)
45    itemconfiginfo(['tag', tagOrId], slot)
46  end
47  def current_tag_configinfo(tagOrId, slot=nil)
48    current_itemconfiginfo(['tag', tagOrId], slot)
49  end
50
51  def window_cget_tkstring(tagOrId, option)
52    itemcget_tkstring(['window', tagOrId], option)
53  end
54  def window_cget(tagOrId, option)
55    itemcget(['window', tagOrId], option)
56  end
57  def window_cget_strict(tagOrId, option)
58    itemcget_strict(['window', tagOrId], option)
59  end
60  def window_configure(tagOrId, slot, value=None)
61    itemconfigure(['window', tagOrId], slot, value)
62  end
63  def window_configinfo(tagOrId, slot=nil)
64    itemconfiginfo(['window', tagOrId], slot)
65  end
66  def current_window_configinfo(tagOrId, slot=nil)
67    current_itemconfiginfo(['window', tagOrId], slot)
68  end
69
70  private :itemcget_tkstring, :itemcget, :itemcget_strict
71  private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
72end
73
74class Tk::Text<TkTextWin
75  ItemConfCMD = ['tag'.freeze, 'configure'.freeze].freeze
76  #include TkTreatTextTagFont
77  include TkTextTagConfig
78  include Scrollable
79
80  #######################################
81
82  module IndexModMethods
83    def +(mod)
84      return chars(mod) if mod.kind_of?(Numeric)
85
86      mod = mod.to_s
87      if mod =~ /^\s*[+-]?\d/
88        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod)
89      else
90        Tk::Text::IndexString.new(String.new(id) << ' ' << mod)
91      end
92    end
93
94    def -(mod)
95      return chars(-mod) if mod.kind_of?(Numeric)
96
97      mod = mod.to_s
98      if mod =~ /^\s*[+-]?\d/
99        Tk::Text::IndexString.new(String.new(id) << ' - ' << mod)
100      elsif mod =~ /^\s*[-]\s+(\d.*)$/
101        Tk::Text::IndexString.new(String.new(id) << ' - -' << $1)
102      else
103        Tk::Text::IndexString.new(String.new(id) << ' ' << mod)
104      end
105    end
106
107    def chars(mod)
108      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
109      if mod < 0
110        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' chars')
111      else
112        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' chars')
113      end
114    end
115    alias char chars
116
117    def display_chars(mod)
118      # Tk8.5 feature
119      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
120      if mod < 0
121        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display chars')
122      else
123        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display chars')
124      end
125    end
126    alias display_char display_chars
127
128    def any_chars(mod)
129      # Tk8.5 feature
130      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
131      if mod < 0
132        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any chars')
133      else
134        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any chars')
135      end
136    end
137    alias any_char any_chars
138
139    def indices(mod)
140      # Tk8.5 feature
141      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
142      if mod < 0
143        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' indices')
144      else
145        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' indices')
146      end
147    end
148
149    def display_indices(mod)
150      # Tk8.5 feature
151      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
152      if mod < 0
153        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display indices')
154      else
155        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display indices')
156      end
157    end
158
159    def any_indices(mod)
160      # Tk8.5 feature
161      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
162      if mod < 0
163        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any indices')
164      else
165        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any indices')
166      end
167    end
168
169    def lines(mod)
170      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
171      if mod < 0
172        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' lines')
173      else
174        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' lines')
175      end
176    end
177    alias line lines
178
179    def display_lines(mod)
180      # Tk8.5 feature
181      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
182      if mod < 0
183        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display_lines')
184      else
185        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display lines')
186      end
187    end
188    alias display_line display_lines
189
190    def any_lines(mod)
191      # Tk8.5 feature
192      fail ArgumentError, 'expect Integer'  unless mod.kind_of?(Integer)
193      if mod < 0
194        Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any_lines')
195      else
196        Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any lines')
197      end
198    end
199    alias any_line any_lines
200
201    def linestart
202      Tk::Text::IndexString.new(String.new(id) << ' linestart')
203    end
204    def lineend
205      Tk::Text::IndexString.new(String.new(id) << ' lineend')
206    end
207
208    def display_linestart
209      # Tk8.5 feature
210      Tk::Text::IndexString.new(String.new(id) << ' display linestart')
211    end
212    def display_lineend
213      # Tk8.5 feature
214      Tk::Text::IndexString.new(String.new(id) << ' display lineend')
215    end
216
217    def wordstart
218      Tk::Text::IndexString.new(String.new(id) << ' wordstart')
219    end
220    def wordend
221      Tk::Text::IndexString.new(String.new(id) << ' wordend')
222    end
223
224    def display_wordstart
225      # Tk8.5 feature
226      Tk::Text::IndexString.new(String.new(id) << ' display wordstart')
227    end
228    def display_wordend
229      # Tk8.5 feature
230      Tk::Text::IndexString.new(String.new(id) << ' display wordend')
231    end
232  end
233
234  class IndexString < String
235    include IndexModMethods
236
237    def self.at(x,y)
238      self.new("@#{x},#{y}")
239    end
240
241    def self.new(str)
242      if str.kind_of?(String)
243        super(str)
244      elsif str.kind_of?(Symbol)
245        super(str.to_s)
246      else
247        str
248      end
249    end
250
251    def id
252      self
253    end
254  end
255
256  #######################################
257
258  TkCommandNames = ['text'.freeze].freeze
259  WidgetClassName = 'Text'.freeze
260  WidgetClassNames[WidgetClassName] ||= self
261
262  def self.new(*args, &block)
263    obj = super(*args){}
264    obj.init_instance_variable
265    if TkCore::WITH_RUBY_VM  ### Ruby 1.9 !!!!
266      obj.instance_exec(obj, &block) if defined? yield
267    else
268      obj.instance_eval(&block) if defined? yield
269    end
270    obj
271  end
272
273  def init_instance_variable
274    @cmdtbl = []
275    @tags = {}
276  end
277
278  def __destroy_hook__
279    TkTextTag::TTagID_TBL.mutex.synchronize{
280      TkTextTag::TTagID_TBL.delete(@path)
281    }
282    TkTextTag::TMarkID_TBL.mutex.synchronize{
283      TkTextMark::TMarkID_TBL.delete(@path)
284    }
285  end
286
287  def create_self(keys)
288    #if keys and keys != None
289    #  #tk_call_without_enc('text', @path, *hash_kv(keys, true))
290    #  tk_call_without_enc(self.class::TkCommandNames[0], @path,
291    #                     *hash_kv(keys, true))
292    #else
293    #  #tk_call_without_enc('text', @path)
294    #  tk_call_without_enc(self.class::TkCommandNames[0], @path)
295    #end
296    super(keys)
297    init_instance_variable
298  end
299  private :create_self
300
301  def __strval_optkeys
302    super() << 'inactiveseletcionbackground'
303  end
304  private :__strval_optkeys
305
306  def self.at(x, y)
307    Tk::Text::IndexString.at(x, y)
308  end
309
310  def at(x, y)
311    Tk::Text::IndexString.at(x, y)
312  end
313
314  def index(idx)
315    Tk::Text::IndexString.new(tk_send_without_enc('index',
316                                                  _get_eval_enc_str(idx)))
317  end
318
319  def get_displaychars(*index)
320    # Tk8.5 feature
321    get('-displaychars', *index)
322  end
323
324  def value
325    _fromUTF8(tk_send_without_enc('get', "1.0", "end - 1 char"))
326  end
327
328  def value= (val)
329    tk_send_without_enc('delete', "1.0", 'end')
330    tk_send_without_enc('insert', "1.0", _get_eval_enc_str(val))
331    val
332  end
333
334  def clear
335    tk_send_without_enc('delete', "1.0", 'end')
336    self
337  end
338  alias erase clear
339
340  def _addcmd(cmd)
341    @cmdtbl.push cmd
342  end
343
344  def _addtag(name, obj)
345    @tags[name] = obj
346  end
347
348  def tagid(tag)
349    if tag.kind_of?(TkTextTag) \
350      || tag.kind_of?(TkTextMark) \
351      || tag.kind_of?(TkTextImage) \
352      || tag.kind_of?(TkTextWindow)
353      tag.id
354    else
355      tag  # maybe an Array of configure paramters
356    end
357  end
358  private :tagid
359
360  def tagid2obj(tagid)
361    if @tags[tagid]
362      @tags[tagid]
363    else
364      tagid
365    end
366  end
367
368  def tag_names(index=None)
369    #tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag', 'names', _get_eval_enc_str(index)))).collect{|elt|
370    tk_split_simplelist(tk_send_without_enc('tag', 'names', _get_eval_enc_str(index)), false, true).collect{|elt|
371      tagid2obj(elt)
372    }
373  end
374
375  def mark_names
376    #tk_split_simplelist(_fromUTF8(tk_send_without_enc('mark', 'names'))).collect{|elt|
377    tk_split_simplelist(tk_send_without_enc('mark', 'names'), false, true).collect{|elt|
378      tagid2obj(elt)
379    }
380  end
381
382  def mark_gravity(mark, direction=nil)
383    if direction
384      tk_send_without_enc('mark', 'gravity',
385                          _get_eval_enc_str(mark), direction)
386      self
387    else
388      tk_send_without_enc('mark', 'gravity', _get_eval_enc_str(mark))
389    end
390  end
391
392  def mark_set(mark, index)
393    tk_send_without_enc('mark', 'set', _get_eval_enc_str(mark),
394                        _get_eval_enc_str(index))
395    self
396  end
397  alias set_mark mark_set
398
399  def mark_unset(*marks)
400    tk_send_without_enc('mark', 'unset',
401                        *(marks.collect{|mark| _get_eval_enc_str(mark)}))
402    self
403  end
404  alias unset_mark mark_unset
405
406  def mark_next(index)
407    tagid2obj(_fromUTF8(tk_send_without_enc('mark', 'next',
408                                            _get_eval_enc_str(index))))
409  end
410  alias next_mark mark_next
411
412  def mark_previous(index)
413    tagid2obj(_fromUTF8(tk_send_without_enc('mark', 'previous',
414                                            _get_eval_enc_str(index))))
415  end
416  alias previous_mark mark_previous
417
418  def image_cget_strict(index, slot)
419    case slot.to_s
420    when 'text', 'label', 'show', 'data', 'file'
421      _fromUTF8(tk_send_without_enc('image', 'cget',
422                                    _get_eval_enc_str(index), "-#{slot}"))
423    else
424      tk_tcl2ruby(_fromUTF8(tk_send_without_enc('image', 'cget',
425                                                _get_eval_enc_str(index),
426                                                "-#{slot}")))
427    end
428  end
429
430  def image_cget(index, slot)
431    unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
432      image_cget_strict(index, slot)
433    else
434      begin
435        image_cget_strict(index, slot)
436      rescue => e
437        begin
438          if current_image_configinfo(index).has_key?(slot.to_s)
439            # not tag error & option is known -> error on known option
440            fail e
441          else
442            # not tag error & option is unknown
443            nil
444          end
445        rescue
446          fail e  # tag error
447        end
448      end
449    end
450  end
451
452  def image_configure(index, slot, value=None)
453    if slot.kind_of?(Hash)
454      _fromUTF8(tk_send_without_enc('image', 'configure',
455                                    _get_eval_enc_str(index),
456                                    *hash_kv(slot, true)))
457    else
458      _fromUTF8(tk_send_without_enc('image', 'configure',
459                                    _get_eval_enc_str(index),
460                                    "-#{slot}",
461                                    _get_eval_enc_str(value)))
462    end
463    self
464  end
465
466  def image_configinfo(index, slot = nil)
467    if TkComm::GET_CONFIGINFO_AS_ARRAY
468      if slot
469        case slot.to_s
470        when 'text', 'label', 'show', 'data', 'file'
471          #conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}")))
472          conf = tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), false, true)
473        else
474          #conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}")))
475          conf = tk_split_list(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), 0, false, true)
476        end
477        conf[0] = conf[0][1..-1]
478        conf
479      else
480        # tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).collect{|conflist|
481        #  conf = tk_split_simplelist(conflist)
482        tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)), false, false).collect{|conflist|
483          conf = tk_split_simplelist(conflist, false, true)
484          conf[0] = conf[0][1..-1]
485          case conf[0]
486          when 'text', 'label', 'show', 'data', 'file'
487          else
488            if conf[3]
489              if conf[3].index('{')
490                conf[3] = tk_split_list(conf[3])
491              else
492                conf[3] = tk_tcl2ruby(conf[3])
493              end
494            end
495            if conf[4]
496              if conf[4].index('{')
497                conf[4] = tk_split_list(conf[4])
498              else
499                conf[4] = tk_tcl2ruby(conf[4])
500              end
501            end
502          end
503          conf[1] = conf[1][1..-1] if conf.size == 2 # alias info
504          conf
505        }
506      end
507    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
508      if slot
509        case slot.to_s
510        when 'text', 'label', 'show', 'data', 'file'
511          #conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}")))
512          conf = tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), false, true)
513        else
514          #conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}")))
515          conf = tk_split_list(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"), 0, false, true)
516        end
517        key = conf.shift[1..-1]
518        { key => conf }
519      else
520        ret = {}
521        #tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).each{|conflist|
522        #  conf = tk_split_simplelist(conflist)
523        tk_split_simplelist(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)), false, false).each{|conflist|
524          conf = tk_split_simplelist(conflist, false, true)
525          key = conf.shift[1..-1]
526          case key
527          when 'text', 'label', 'show', 'data', 'file'
528          else
529            if conf[2]
530              if conf[2].index('{')
531                conf[2] = tk_split_list(conf[2])
532              else
533                conf[2] = tk_tcl2ruby(conf[2])
534              end
535            end
536            if conf[3]
537              if conf[3].index('{')
538                conf[3] = tk_split_list(conf[3])
539              else
540                conf[3] = tk_tcl2ruby(conf[3])
541              end
542            end
543          end
544          if conf.size == 1
545            ret[key] = conf[0][1..-1]  # alias info
546          else
547            ret[key] = conf
548          end
549        }
550        ret
551      end
552    end
553  end
554
555  def current_image_configinfo(index, slot = nil)
556    if TkComm::GET_CONFIGINFO_AS_ARRAY
557      if slot
558        conf = image_configinfo(index, slot)
559        {conf[0] => conf[4]}
560      else
561        ret = {}
562        image_configinfo(index).each{|conf|
563          ret[conf[0]] = conf[4] if conf.size > 2
564        }
565        ret
566      end
567    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
568      ret = {}
569      image_configinfo(index, slot).each{|k, conf|
570        ret[k] = conf[-1] if conf.kind_of?(Array)
571      }
572      ret
573    end
574  end
575
576  def image_names
577    #tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'names'))).collect{|elt|
578    tk_split_simplelist(tk_send_without_enc('image', 'names'), false, true).collect{|elt|
579      tagid2obj(elt)
580    }
581  end
582
583  def set_insert(index)
584    tk_send_without_enc('mark','set','insert', _get_eval_enc_str(index))
585    self
586  end
587
588  def set_current(index)
589    tk_send_without_enc('mark','set','current', _get_eval_enc_str(index))
590    self
591  end
592
593  def insert(index, chars, *tags)
594    if tags[0].kind_of?(Array)
595      # multiple chars-taglist argument :: str, [tag,...], str, [tag,...], ...
596      args = [chars]
597      while tags.size > 0
598        args << tags.shift.collect{|x|_get_eval_string(x)}.join(' ')  # taglist
599        args << tags.shift if tags.size > 0                           # chars
600      end
601      super(index, *args)
602    else
603      # single chars-taglist argument :: str, tag, tag, ...
604      if tags.size == 0
605        super(index, chars)
606      else
607        super(index, chars, tags.collect{|x|_get_eval_string(x)}.join(' '))
608      end
609    end
610  end
611
612  def destroy
613    @tags = {} unless @tags
614    @tags.each_value do |t|
615      t.destroy
616    end
617    super()
618  end
619
620  def backspace
621    self.delete 'insert'
622  end
623
624  def bbox(index)
625    list(tk_send_without_enc('bbox', _get_eval_enc_str(index)))
626  end
627
628  def compare(idx1, op, idx2)
629    bool(tk_send_without_enc('compare', _get_eval_enc_str(idx1),
630                             op, _get_eval_enc_str(idx2)))
631  end
632
633  def count(idx1, idx2, *opts)
634    # opts are Tk8.5 feature
635    cnt = 0
636    args = opts.collect{|opt|
637      str = opt.to_s
638      cnt += 1 if str != 'update'
639      '-' + str
640    }
641    args << _get_eval_enc_str(idx1) << _get_eval_enc_str(idx2)
642    if cnt <= 1
643      number(tk_send_without_enc('count', *opts))
644    else
645      list(tk_send_without_enc('count', *opts))
646    end
647  end
648
649  def count_info(idx1, idx2, update=true)
650    # Tk8.5 feature
651    opts = [
652      :chars, :displaychars, :displayindices, :displaylines,
653      :indices, :lines, :xpixels, :ypixels
654    ]
655    if update
656      lst = count(idx1, idx2, :update, *opts)
657    else
658      lst = count(idx1, idx2, *opts)
659    end
660    info = {}
661    opts.each_with_index{|key, idx| info[key] = lst[idx]}
662    info
663  end
664
665  def peer_names()
666    # Tk8.5 feature
667    list(tk_send_without_enc('peer', 'names'))
668  end
669
670  def replace(idx1, idx2, *opts)
671    tk_send('replace', idx1, idx2, *opts)
672    self
673  end
674
675  def debug
676    bool(tk_send_without_enc('debug'))
677  end
678  def debug=(boolean)
679    tk_send_without_enc('debug', boolean)
680    #self
681    boolean
682  end
683
684  def dlineinfo(index)
685    list(tk_send_without_enc('dlineinfo', _get_eval_enc_str(index)))
686  end
687
688  def modified?
689    bool(tk_send_without_enc('edit', 'modified'))
690  end
691  def modified(mode)
692    tk_send_without_enc('edit', 'modified', mode)
693    self
694  end
695  def modified=(mode)
696    modified(mode)
697    mode
698  end
699
700  def edit_redo
701    tk_send_without_enc('edit', 'redo')
702    self
703  end
704  def edit_reset
705    tk_send_without_enc('edit', 'reset')
706    self
707  end
708  def edit_separator
709    tk_send_without_enc('edit', 'separator')
710    self
711  end
712  def edit_undo
713    tk_send_without_enc('edit', 'undo')
714    self
715  end
716
717  def xview_pickplace(index)
718    tk_send_without_enc('xview', '-pickplace', _get_eval_enc_str(index))
719    self
720  end
721
722  def yview_pickplace(index)
723    tk_send_without_enc('yview', '-pickplace', _get_eval_enc_str(index))
724    self
725  end
726
727  def text_copy
728    # Tk8.4 feature
729    tk_call_without_enc('tk_textCopy', @path)
730    self
731  end
732
733  def text_cut
734    # Tk8.4 feature
735    tk_call_without_enc('tk_textCut', @path)
736    self
737  end
738
739  def text_paste
740    # Tk8.4 feature
741    tk_call_without_enc('tk_textPaste', @path)
742    self
743  end
744
745  def tag_add(tag, index1, index2=None)
746    tk_send_without_enc('tag', 'add', _get_eval_enc_str(tag),
747                        _get_eval_enc_str(index1),
748                        _get_eval_enc_str(index2))
749    self
750  end
751  alias addtag tag_add
752  alias add_tag tag_add
753
754  def tag_delete(*tags)
755    tk_send_without_enc('tag', 'delete',
756                        *(tags.collect{|tag| _get_eval_enc_str(tag)}))
757    TkTextTag::TTagID_TBL.mutex.synchronize{
758      if TkTextTag::TTagID_TBL[@path]
759        tags.each{|tag|
760          if tag.kind_of?(TkTextTag)
761            TkTextTag::TTagID_TBL[@path].delete(tag.id)
762          else
763            TkTextTag::TTagID_TBL[@path].delete(tag)
764          end
765        }
766      end
767    }
768    self
769  end
770  alias deltag tag_delete
771  alias delete_tag tag_delete
772
773  #def tag_bind(tag, seq, cmd=Proc.new, *args)
774  #  _bind([@path, 'tag', 'bind', tag], seq, cmd, *args)
775  #  self
776  #end
777  def tag_bind(tag, seq, *args)
778    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
779    if TkComm._callback_entry?(args[0]) || !block_given?
780      cmd = args.shift
781    else
782      cmd = Proc.new
783    end
784    _bind([@path, 'tag', 'bind', tag], seq, cmd, *args)
785    self
786  end
787
788  #def tag_bind_append(tag, seq, cmd=Proc.new, *args)
789  #  _bind_append([@path, 'tag', 'bind', tag], seq, cmd, *args)
790  #  self
791  #end
792  def tag_bind_append(tag, seq, *args)
793    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
794    if TkComm._callback_entry?(args[0]) || !block_given?
795      cmd = args.shift
796    else
797      cmd = Proc.new
798    end
799    _bind_append([@path, 'tag', 'bind', tag], seq, cmd, *args)
800    self
801  end
802
803  def tag_bind_remove(tag, seq)
804    _bind_remove([@path, 'tag', 'bind', tag], seq)
805    self
806  end
807
808  def tag_bindinfo(tag, context=nil)
809    _bindinfo([@path, 'tag', 'bind', tag], context)
810  end
811
812=begin
813  def tag_cget(tag, key)
814    case key.to_s
815    when 'text', 'label', 'show', 'data', 'file'
816      tk_call_without_enc(@path, 'tag', 'cget',
817                          _get_eval_enc_str(tag), "-#{key}")
818    when 'font', 'kanjifont'
819      #fnt = tk_tcl2ruby(tk_send('tag', 'cget', tag, "-#{key}"))
820      fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('tag','cget',_get_eval_enc_str(tag),'-font')))
821      unless fnt.kind_of?(TkFont)
822        fnt = tagfontobj(tag, fnt)
823      end
824      if key.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/
825        # obsolete; just for compatibility
826        fnt.kanji_font
827      else
828        fnt
829      end
830    else
831      tk_tcl2ruby(_fromUTF8(tk_call_without_enc(@path,'tag','cget',_get_eval_enc_str(tag),"-#{key}")))
832    end
833  end
834
835  def tag_configure(tag, key, val=None)
836    if key.kind_of?(Hash)
837      key = _symbolkey2str(key)
838      if ( key['font'] || key['kanjifont'] \
839          || key['latinfont'] || key['asciifont'] )
840        tagfont_configure(tag, key)
841      else
842        tk_send_without_enc('tag', 'configure', _get_eval_enc_str(tag),
843                            *hash_kv(key, true))
844      end
845
846    else
847      if  key == 'font' || key == :font ||
848          key == 'kanjifont' || key == :kanjifont ||
849          key == 'latinfont' || key == :latinfont ||
850          key == 'asciifont' || key == :asciifont
851        if val == None
852          tagfontobj(tag)
853        else
854          tagfont_configure(tag, {key=>val})
855        end
856      else
857        tk_send_without_enc('tag', 'configure', _get_eval_enc_str(tag),
858                            "-#{key}", _get_eval_enc_str(val))
859      end
860    end
861    self
862  end
863
864  def tag_configinfo(tag, key=nil)
865    if TkComm::GET_CONFIGINFO_AS_ARRAY
866      if key
867        case key.to_s
868        when 'text', 'label', 'show', 'data', 'file'
869          conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}")))
870        when 'font', 'kanjifont'
871          conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}")))
872          conf[4] = tagfont_configinfo(tag, conf[4])
873        else
874          conf = tk_split_list(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}")))
875        end
876        conf[0] = conf[0][1..-1]
877        conf
878      else
879        ret = tk_split_simplelist(_fromUTF8(tk_send('tag','configure',_get_eval_enc_str(tag)))).collect{|conflist|
880          conf = tk_split_simplelist(conflist)
881          conf[0] = conf[0][1..-1]
882          case conf[0]
883          when 'text', 'label', 'show', 'data', 'file'
884          else
885            if conf[3]
886              if conf[3].index('{')
887                conf[3] = tk_split_list(conf[3])
888              else
889                conf[3] = tk_tcl2ruby(conf[3])
890              end
891            end
892            if conf[4]
893              if conf[4].index('{')
894                conf[4] = tk_split_list(conf[4])
895              else
896                conf[4] = tk_tcl2ruby(conf[4])
897              end
898            end
899          end
900          conf[1] = conf[1][1..-1] if conf.size == 2 # alias info
901          conf
902        }
903        fontconf = ret.assoc('font')
904        if fontconf
905          ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'}
906          fontconf[4] = tagfont_configinfo(tag, fontconf[4])
907          ret.push(fontconf)
908        else
909          ret
910        end
911      end
912    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
913      if key
914        case key.to_s
915        when 'text', 'label', 'show', 'data', 'file'
916          conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}")))
917        when 'font', 'kanjifont'
918          conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}")))
919          conf[4] = tagfont_configinfo(tag, conf[4])
920        else
921          conf = tk_split_list(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}")))
922        end
923        key = conf.shift[1..-1]
924        { key => conf }
925      else
926        ret = {}
927        tk_split_simplelist(_fromUTF8(tk_send('tag','configure',_get_eval_enc_str(tag)))).each{|conflist|
928          conf = tk_split_simplelist(conflist)
929          key = conf.shift[1..-1]
930          case key
931          when 'text', 'label', 'show', 'data', 'file'
932          else
933            if conf[2]
934              if conf[2].index('{')
935                conf[2] = tk_split_list(conf[2])
936              else
937                conf[2] = tk_tcl2ruby(conf[2])
938              end
939            end
940            if conf[3]
941              if conf[3].index('{')
942                conf[3] = tk_split_list(conf[3])
943              else
944                conf[3] = tk_tcl2ruby(conf[3])
945              end
946            end
947          end
948          if conf.size == 1
949            ret[key] = conf[0][1..-1]  # alias info
950          else
951            ret[key] = conf
952          end
953        }
954        fontconf = ret['font']
955        if fontconf
956          ret.delete('font')
957          ret.delete('kanjifont')
958          fontconf[3] = tagfont_configinfo(tag, fontconf[3])
959          ret['font'] = fontconf
960        end
961        ret
962      end
963    end
964  end
965
966  def current_tag_configinfo(tag, key=nil)
967    if TkComm::GET_CONFIGINFO_AS_ARRAY
968      if key
969        conf = tag_configinfo(tag, key)
970        {conf[0] => conf[4]}
971      else
972        ret = {}
973        tag_configinfo(tag).each{|conf|
974          ret[conf[0]] = conf[4] if conf.size > 2
975        }
976        ret
977      end
978    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
979      ret = {}
980      tag_configinfo(tag, key).each{|k, conf|
981        ret[k] = conf[-1] if conf.kind_of?(Array)
982      }
983      ret
984    end
985  end
986=end
987
988  def tag_raise(tag, above=None)
989    tk_send_without_enc('tag', 'raise', _get_eval_enc_str(tag),
990                        _get_eval_enc_str(above))
991    self
992  end
993
994  def tag_lower(tag, below=None)
995    tk_send_without_enc('tag', 'lower', _get_eval_enc_str(tag),
996                        _get_eval_enc_str(below))
997    self
998  end
999
1000  def tag_remove(tag, *indices)
1001    tk_send_without_enc('tag', 'remove', _get_eval_enc_str(tag),
1002                        *(indices.collect{|idx| _get_eval_enc_str(idx)}))
1003    self
1004  end
1005
1006  def tag_ranges(tag)
1007    #l = tk_split_simplelist(tk_send_without_enc('tag', 'ranges',
1008    #                                            _get_eval_enc_str(tag)))
1009    l = tk_split_simplelist(tk_send_without_enc('tag', 'ranges',
1010                                                _get_eval_enc_str(tag)),
1011                            false, true)
1012    r = []
1013    while key=l.shift
1014      r.push [Tk::Text::IndexString.new(key), Tk::Text::IndexString.new(l.shift)]
1015    end
1016    r
1017  end
1018
1019  def tag_nextrange(tag, first, last=None)
1020    simplelist(tk_send_without_enc('tag', 'nextrange',
1021                                   _get_eval_enc_str(tag),
1022                                   _get_eval_enc_str(first),
1023                                   _get_eval_enc_str(last))).collect{|idx|
1024      Tk::Text::IndexString.new(idx)
1025    }
1026  end
1027
1028  def tag_prevrange(tag, first, last=None)
1029    simplelist(tk_send_without_enc('tag', 'prevrange',
1030                                   _get_eval_enc_str(tag),
1031                                   _get_eval_enc_str(first),
1032                                   _get_eval_enc_str(last))).collect{|idx|
1033      Tk::Text::IndexString.new(idx)
1034    }
1035  end
1036
1037=begin
1038  def window_cget(index, slot)
1039    case slot.to_s
1040    when 'text', 'label', 'show', 'data', 'file'
1041      _fromUTF8(tk_send_without_enc('window', 'cget',
1042                                    _get_eval_enc_str(index), "-#{slot}"))
1043    when 'font', 'kanjifont'
1044      #fnt = tk_tcl2ruby(tk_send('window', 'cget', index, "-#{slot}"))
1045      fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('window', 'cget', _get_eval_enc_str(index), '-font')))
1046      unless fnt.kind_of?(TkFont)
1047        fnt = tagfontobj(index, fnt)
1048      end
1049      if slot.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/
1050        # obsolete; just for compatibility
1051        fnt.kanji_font
1052      else
1053        fnt
1054      end
1055    else
1056      tk_tcl2ruby(_fromUTF8(tk_send_without_enc('window', 'cget', _get_eval_enc_str(index), "-#{slot}")))
1057    end
1058  end
1059
1060  def window_configure(index, slot, value=None)
1061    if index.kind_of?(TkTextWindow)
1062      index.configure(slot, value)
1063    else
1064      if slot.kind_of?(Hash)
1065        slot = _symbolkey2str(slot)
1066        win = slot['window']
1067        # slot['window'] = win.epath if win.kind_of?(TkWindow)
1068        slot['window'] = _epath(win) if win
1069        if slot['create']
1070          p_create = slot['create']
1071          if p_create.kind_of?(Proc)
1072#=begin
1073            slot['create'] = install_cmd(proc{
1074                                           id = p_create.call
1075                                           if id.kind_of?(TkWindow)
1076                                             id.epath
1077                                           else
1078                                             id
1079                                           end
1080                                         })
1081#=end
1082            slot['create'] = install_cmd(proc{_epath(p_create.call)})
1083          end
1084        end
1085        tk_send_without_enc('window', 'configure',
1086                            _get_eval_enc_str(index),
1087                            *hash_kv(slot, true))
1088      else
1089        if slot == 'window' || slot == :window
1090          # id = value
1091          # value = id.epath if id.kind_of?(TkWindow)
1092          value = _epath(value)
1093        end
1094        if slot == 'create' || slot == :create
1095          p_create = value
1096          if p_create.kind_of?(Proc)
1097#=begin
1098            value = install_cmd(proc{
1099                                  id = p_create.call
1100                                  if id.kind_of?(TkWindow)
1101                                    id.epath
1102                                  else
1103                                    id
1104                                  end
1105                                })
1106#=end
1107            value = install_cmd(proc{_epath(p_create.call)})
1108          end
1109        end
1110        tk_send_without_enc('window', 'configure',
1111                            _get_eval_enc_str(index),
1112                            "-#{slot}", _get_eval_enc_str(value))
1113      end
1114    end
1115    self
1116  end
1117
1118  def window_configinfo(win, slot = nil)
1119    if TkComm::GET_CONFIGINFO_AS_ARRAY
1120      if slot
1121        case slot.to_s
1122        when 'text', 'label', 'show', 'data', 'file'
1123          conf = tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}")))
1124        else
1125          conf = tk_split_list(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}")))
1126        end
1127        conf[0] = conf[0][1..-1]
1128        conf
1129      else
1130        tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win)))).collect{|conflist|
1131          conf = tk_split_simplelist(conflist)
1132          conf[0] = conf[0][1..-1]
1133          case conf[0]
1134          when 'text', 'label', 'show', 'data', 'file'
1135          else
1136            if conf[3]
1137              if conf[3].index('{')
1138                conf[3] = tk_split_list(conf[3])
1139              else
1140                conf[3] = tk_tcl2ruby(conf[3])
1141              end
1142            end
1143            if conf[4]
1144              if conf[4].index('{')
1145                conf[4] = tk_split_list(conf[4])
1146              else
1147                conf[4] = tk_tcl2ruby(conf[4])
1148              end
1149            end
1150          end
1151          conf[1] = conf[1][1..-1] if conf.size == 2 # alias info
1152          conf
1153        }
1154      end
1155    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
1156      if slot
1157        case slot.to_s
1158        when 'text', 'label', 'show', 'data', 'file'
1159          conf = tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}")))
1160        else
1161          conf = tk_split_list(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}")))
1162        end
1163        key = conf.shift[1..-1]
1164        { key => conf }
1165      else
1166        ret = {}
1167        tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win)))).each{|conflist|
1168          conf = tk_split_simplelist(conflist)
1169          key = conf.shift[1..-1]
1170          case key
1171          when 'text', 'label', 'show', 'data', 'file'
1172          else
1173            if conf[2]
1174              if conf[2].index('{')
1175                conf[2] = tk_split_list(conf[2])
1176              else
1177                conf[2] = tk_tcl2ruby(conf[2])
1178              end
1179            end
1180            if conf[3]
1181              if conf[3].index('{')
1182                conf[3] = tk_split_list(conf[3])
1183              else
1184                conf[3] = tk_tcl2ruby(conf[3])
1185              end
1186            end
1187          end
1188          if conf.size == 1
1189            ret[key] = conf[0][1..-1]  # alias info
1190          else
1191            ret[key] = conf
1192          end
1193        }
1194        ret
1195      end
1196    end
1197  end
1198
1199  def current_window_configinfo(win, slot = nil)
1200    if TkComm::GET_CONFIGINFO_AS_ARRAY
1201      if slot
1202        conf = window_configinfo(win, slot)
1203        {conf[0] => conf[4]}
1204      else
1205        ret = {}
1206        window_configinfo(win).each{|conf|
1207          ret[conf[0]] = conf[4] if conf.size > 2
1208        }
1209        ret
1210      end
1211    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
1212      ret = {}
1213      window_configinfo(win, slot).each{|k, conf|
1214        ret[k] = conf[-1] if conf.kind_of?(Array)
1215      }
1216      ret
1217    end
1218  end
1219=end
1220
1221  def window_names
1222    # tk_split_simplelist(_fromUTF8(tk_send_without_enc('window', 'names'))).collect{|elt|
1223    tk_split_simplelist(tk_send_without_enc('window', 'names'), false, true).collect{|elt|
1224      tagid2obj(elt)
1225    }
1226  end
1227
1228  def _ktext_length(txt)
1229    if TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!!!
1230      return txt.length
1231    end
1232    ###########################
1233
1234    if $KCODE !~ /n/i
1235      return txt.gsub(/[^\Wa-zA-Z_\d]/, ' ').length
1236    end
1237
1238    # $KCODE == 'NONE'
1239    if JAPANIZED_TK
1240      tk_call_without_enc('kstring', 'length',
1241                          _get_eval_enc_str(txt)).to_i
1242    else
1243      begin
1244        tk_call_without_enc('encoding', 'convertto', 'ascii',
1245                            _get_eval_enc_str(txt)).length
1246      rescue StandardError, NameError
1247        # sorry, I have no plan
1248        txt.length
1249      end
1250    end
1251  end
1252  private :_ktext_length
1253
1254  def tksearch(*args)
1255    # call 'search' subcommand of text widget
1256    #   args ::= [<array_of_opts>] <pattern> <start_index> [<stop_index>]
1257    # If <pattern> is regexp, then it must be a regular expression of Tcl
1258    nocase = false
1259    if args[0].kind_of?(Array)
1260      opts = args.shift.collect{|opt|
1261        s_opt = opt.to_s
1262        nocase = true if s_opt == 'nocase'
1263        '-' + s_opt
1264      }
1265    else
1266      opts = []
1267    end
1268
1269    if args[0].kind_of?(Regexp)
1270      regexp = args.shift
1271      if !nocase && (regexp.options & Regexp::IGNORECASE) != 0
1272        opts << '-nocase'
1273      end
1274      args.unshift(regexp.source)
1275    end
1276
1277    opts << '--'
1278
1279    ret = tk_send('search', *(opts + args))
1280    if ret == ""
1281      nil
1282    else
1283      Tk::Text::IndexString.new(ret)
1284    end
1285  end
1286
1287  def tksearch_with_count(*args)
1288    # call 'search' subcommand of text widget
1289    #   args ::= [<array_of_opts>] <var> <pattern> <start_index> [<stop_index>]
1290    # If <pattern> is regexp, then it must be a regular expression of Tcl
1291    nocase = false
1292    if args[0].kind_of?(Array)
1293      opts = args.shift.collect{|opt|
1294        s_opt = opt.to_s
1295        nocase = true if s_opt == 'nocase'
1296        '-' + s_opt
1297      }
1298    else
1299      opts = []
1300    end
1301
1302    opts << '-count' << args.shift
1303
1304    if args[0].kind_of?(Regexp)
1305      regexp = args.shift
1306      if !nocase && (regexp.options & Regexp::IGNORECASE) != 0
1307        opts << '-nocase'
1308      end
1309      args.unshift(regexp.source)
1310    end
1311
1312    opts << '--'
1313
1314    ret = tk_send('search', *(opts + args))
1315    if ret == ""
1316      nil
1317    else
1318      Tk::Text::IndexString.new(ret)
1319    end
1320  end
1321
1322  def search_with_length(pat,start,stop=None)
1323    pat = pat.chr if pat.kind_of?(Integer)
1324    if stop != None
1325      return ["", 0] if compare(start,'>=',stop)
1326      txt = get(start,stop)
1327      if (pos = txt.index(pat))
1328        match = $&
1329        #pos = txt[0..(pos-1)].split('').length if pos > 0
1330        pos = _ktext_length(txt[0..(pos-1)]) if pos > 0
1331        if pat.kind_of?(String)
1332          #return [index(start + " + #{pos} chars"), pat.split('').length]
1333          return [index(start + " + #{pos} chars"),
1334                  _ktext_length(pat), pat.dup]
1335        else
1336          #return [index(start + " + #{pos} chars"), $&.split('').length]
1337          return [index(start + " + #{pos} chars"),
1338                  _ktext_length(match), match]
1339        end
1340      else
1341        return ["", 0]
1342      end
1343    else
1344      txt = get(start,'end - 1 char')
1345      if (pos = txt.index(pat))
1346        match = $&
1347        #pos = txt[0..(pos-1)].split('').length if pos > 0
1348        pos = _ktext_length(txt[0..(pos-1)]) if pos > 0
1349        if pat.kind_of?(String)
1350          #return [index(start + " + #{pos} chars"), pat.split('').length]
1351          return [index(start + " + #{pos} chars"),
1352                  _ktext_length(pat), pat.dup]
1353        else
1354          #return [index(start + " + #{pos} chars"), $&.split('').length]
1355          return [index(start + " + #{pos} chars"),
1356                  _ktext_length(match), match]
1357        end
1358      else
1359        txt = get('1.0','end - 1 char')
1360        if (pos = txt.index(pat))
1361          match = $&
1362          #pos = txt[0..(pos-1)].split('').length if pos > 0
1363          pos = _ktext_length(txt[0..(pos-1)]) if pos > 0
1364          if pat.kind_of?(String)
1365            #return [index("1.0 + #{pos} chars"), pat.split('').length]
1366            return [index("1.0 + #{pos} chars"),
1367                    _ktext_length(pat), pat.dup]
1368          else
1369            #return [index("1.0 + #{pos} chars"), $&.split('').length]
1370            return [index("1.0 + #{pos} chars"), _ktext_length(match), match]
1371          end
1372        else
1373          return ["", 0]
1374        end
1375      end
1376    end
1377  end
1378
1379  def search(pat,start,stop=None)
1380    search_with_length(pat,start,stop)[0]
1381  end
1382
1383  def rsearch_with_length(pat,start,stop=None)
1384    pat = pat.chr if pat.kind_of?(Integer)
1385    if stop != None
1386      return ["", 0] if compare(start,'<=',stop)
1387      txt = get(stop,start)
1388      if (pos = txt.rindex(pat))
1389        match = $&
1390        #pos = txt[0..(pos-1)].split('').length if pos > 0
1391        pos = _ktext_length(txt[0..(pos-1)]) if pos > 0
1392        if pat.kind_of?(String)
1393          #return [index(stop + " + #{pos} chars"), pat.split('').length]
1394          return [index(stop + " + #{pos} chars"), _ktext_length(pat), pat.dup]
1395        else
1396          #return [index(stop + " + #{pos} chars"), $&.split('').length]
1397          return [index(stop + " + #{pos} chars"), _ktext_length(match), match]
1398        end
1399      else
1400        return ["", 0]
1401      end
1402    else
1403      txt = get('1.0',start)
1404      if (pos = txt.rindex(pat))
1405        match = $&
1406        #pos = txt[0..(pos-1)].split('').length if pos > 0
1407        pos = _ktext_length(txt[0..(pos-1)]) if pos > 0
1408        if pat.kind_of?(String)
1409          #return [index("1.0 + #{pos} chars"), pat.split('').length]
1410          return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup]
1411        else
1412          #return [index("1.0 + #{pos} chars"), $&.split('').length]
1413          return [index("1.0 + #{pos} chars"), _ktext_length(match), match]
1414        end
1415      else
1416        txt = get('1.0','end - 1 char')
1417        if (pos = txt.rindex(pat))
1418          match = $&
1419          #pos = txt[0..(pos-1)].split('').length if pos > 0
1420          pos = _ktext_length(txt[0..(pos-1)]) if pos > 0
1421          if pat.kind_of?(String)
1422            #return [index("1.0 + #{pos} chars"), pat.split('').length]
1423            return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup]
1424          else
1425            #return [index("1.0 + #{pos} chars"), $&.split('').length]
1426            return [index("1.0 + #{pos} chars"), _ktext_length(match), match]
1427          end
1428        else
1429          return ["", 0]
1430        end
1431      end
1432    end
1433  end
1434
1435  def rsearch(pat,start,stop=None)
1436    rsearch_with_length(pat,start,stop)[0]
1437  end
1438
1439  def dump(type_info, *index, &block)
1440    if type_info.kind_of?(Symbol)
1441      type_info = [ type_info.to_s ]
1442    elsif type_info.kind_of?(String)
1443      type_info = [ type_info ]
1444    end
1445    args = type_info.collect{|inf| '-' + inf}
1446    args << '-command' << block if block
1447    str = tk_send('dump', *(args + index))
1448    result = []
1449    sel = nil
1450    i = 0
1451    while i < str.size
1452      # retrieve key
1453      idx = str.index(/ /, i)
1454      result.push str[i..(idx-1)]
1455      i = idx + 1
1456
1457      # retrieve value
1458      case result[-1]
1459      when 'text'
1460        if str[i] == ?{
1461          # text formed as {...}
1462          val, i = _retrieve_braced_text(str, i)
1463          result.push val
1464        else
1465          # text which may contain backslahes
1466          val, i = _retrieve_backslashed_text(str, i)
1467          result.push val
1468        end
1469      else
1470        idx = str.index(/ /, i)
1471        val = str[i..(idx-1)]
1472        case result[-1]
1473        when 'mark'
1474          case val
1475          when 'insert'
1476            result.push TkTextMarkInsert.new(self)
1477          when 'current'
1478            result.push TkTextMarkCurrent.new(self)
1479          when 'anchor'
1480            result.push TkTextMarkAnchor.new(self)
1481          else
1482            result.push tk_tcl2ruby(val)
1483          end
1484        when 'tagon'
1485          if val == 'sel'
1486            if sel
1487              result.push sel
1488            else
1489              result.push TkTextTagSel.new(self)
1490            end
1491          else
1492            result.push tk_tcl2ruby(val)
1493          end
1494        when 'tagoff'
1495            result.push tk_tcl2ruby(val)
1496        when 'window'
1497          result.push tk_tcl2ruby(val)
1498        when 'image'
1499          result.push tk_tcl2ruby(val)
1500        end
1501        i = idx + 1
1502      end
1503
1504      # retrieve index
1505      idx = str.index(/ /, i)
1506      if idx
1507        result.push(Tk::Text::IndexString.new(str[i..(idx-1)]))
1508        i = idx + 1
1509      else
1510        result.push(Tk::Text::IndexString.new(str[i..-1]))
1511        break
1512      end
1513    end
1514
1515    kvis = []
1516    until result.empty?
1517      kvis.push [result.shift, result.shift, result.shift]
1518    end
1519    kvis  # result is [[key1, value1, index1], [key2, value2, index2], ...]
1520  end
1521
1522  def _retrieve_braced_text(str, i)
1523    cnt = 0
1524    idx = i
1525    while idx < str.size
1526      case str[idx]
1527      when ?{
1528        cnt += 1
1529      when ?}
1530        cnt -= 1
1531        if cnt == 0
1532          break
1533        end
1534      end
1535      idx += 1
1536    end
1537    return str[i+1..idx-1], idx + 2
1538  end
1539  private :_retrieve_braced_text
1540
1541  def _retrieve_backslashed_text(str, i)
1542    j = i
1543    idx = nil
1544    loop {
1545      idx = str.index(/ /, j)
1546      if str[idx-1] == ?\\
1547        j += 1
1548      else
1549        break
1550      end
1551    }
1552    val = str[i..(idx-1)]
1553    val.gsub!(/\\( |\{|\})/, '\1')
1554    return val, idx + 1
1555  end
1556  private :_retrieve_backslashed_text
1557
1558  def dump_all(*index, &block)
1559    dump(['all'], *index, &block)
1560  end
1561  def dump_mark(*index, &block)
1562    dump(['mark'], *index, &block)
1563  end
1564  def dump_tag(*index, &block)
1565    dump(['tag'], *index, &block)
1566  end
1567  def dump_text(*index, &block)
1568    dump(['text'], *index, &block)
1569  end
1570  def dump_window(*index, &block)
1571    dump(['window'], *index, &block)
1572  end
1573  def dump_image(*index, &block)
1574    dump(['image'], *index, &block)
1575  end
1576end
1577
1578#TkText = Tk::Text unless Object.const_defined? :TkText
1579#Tk.__set_toplevel_aliases__(:Tk, Tk::Text, :TkText)
1580Tk.__set_loaded_toplevel_aliases__('tk/text.rb', :Tk, Tk::Text, :TkText)
1581
1582
1583#######################################
1584
1585class Tk::Text::Peer < Tk::Text
1586  # Tk8.5 feature
1587  def initialize(text, parent=nil, keys={})
1588    unless text.kind_of?(Tk::Text)
1589      fail ArgumentError, "Tk::Text is expected for 1st argument"
1590    end
1591    @src_text = text
1592    super(parent, keys)
1593  end
1594
1595  def create_self(keys)
1596    if keys and keys != None
1597      tk_call_without_enc(@src_text.path, 'peer', 'create',
1598                          @path, *hash_kv(keys, true))
1599    else
1600      tk_call_without_enc(@src_text.path, 'peer', 'create', @path)
1601    end
1602  end
1603  private :create_self
1604end
1605