mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* ext/tk/lib/tk/itemconfig.rb: bug fix on 'itemconfiginfo' method, and
modify to make it easy to override 'itemconfiginfo' method. * ext/tk/lib/tkextlib/tile/treeview.rb : support Tile 0.7.8. * ext/tk/lib/tkextlib/version.rb : [new] add Tk::Tkextlib_RELEASE_DATE to get the information from scripts. * ext/tk/lib/tk.rb: load 'tkextlib/version.rb', and update RELEASE_DATE. * ext/tk/lib/tkextlib/SUPPORT_STATUS: update. * ext/tk/sample/editable_listbox.rb: [new] the listbox with editable items. It's one of the example about usage of Place geometry manager. * ext/tk/sample/tktextio.rb: improve the functions of TkTextIO class. Those are required by 'irbtkw.rbw'. * ext/tk/sample/irbtkw.rbw: [new] IRB on Ruby/Tk. It doesn't need any real console. IRB works on a text widget without I/O blocking. That is, thread switching on IRB will work properly, even if on Windows. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11283 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									ced53248ff
								
							
						
					
					
						commit
						2ec88c167b
					
				
					 10 changed files with 1692 additions and 206 deletions
				
			
		
							
								
								
									
										25
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								ChangeLog
									
										
									
									
									
								
							|  | @ -1,3 +1,28 @@ | |||
| Mon Nov  6 15:41:55 2006  Hidetoshi NAGAI  <nagai@ai.kyutech.ac.jp> | ||||
| 
 | ||||
| 	* ext/tk/lib/tk/itemconfig.rb: ext/tk/lib/tk/itemconfig.rb: bug | ||||
| 	  fix on 'itemconfiginfo' method, and modify to make it easy to | ||||
| 	  override 'itemconfiginfo' method. | ||||
| 
 | ||||
| 	* ext/tk/lib/tkextlib/tile/treeview.rb : support Tile 0.7.8. | ||||
| 
 | ||||
| 	* ext/tk/lib/tkextlib/version.rb : [new] add Tk::Tkextlib_RELEASE_DATE | ||||
| 	  to get the information from scripts. | ||||
| 
 | ||||
| 	* ext/tk/lib/tk.rb: load 'tkextlib/version.rb', and update RELEASE_DATE | ||||
| 
 | ||||
| 	* ext/tk/lib/tkextlib/SUPPORT_STATUS: update. | ||||
| 
 | ||||
| 	* ext/tk/sample/editable_listbox.rb: [new] the listbox with editable | ||||
| 	  items. It's one of the example about usage of Place geometry manager. | ||||
| 
 | ||||
| 	* ext/tk/sample/tktextio.rb: improve the functions of TkTextIO class.  | ||||
| 	  Those are required by 'irbtkw.rbw'. | ||||
| 
 | ||||
| 	* ext/tk/sample/irbtkw.rbw: [new] IRB on Ruby/Tk. It doesn't need any  | ||||
| 	  real console. IRB works on a text widget without I/O blocking. That | ||||
| 	  is, thread switching on IRB will work properly, even if on Windows. | ||||
| 
 | ||||
| Mon Nov  6 00:42:05 2006  Yukihiro Matsumoto  <matz@ruby-lang.org> | ||||
| 
 | ||||
| 	* parse.y (arg_dup_check): vid may be nameless internal id. | ||||
|  |  | |||
|  | @ -1,3 +1,11 @@ | |||
| 2006-11-06  Hidetoshi NAGAI  <nagai@ai.kyutech.ac.jp> | ||||
| 
 | ||||
| 	* lib/tkextlib/version.rb: keep release date of tkextlib on  | ||||
| 	  "Tk::Tkextlib_RELEASE_DATE". | ||||
| 
 | ||||
| 	* lib/tkextlib/tile/treeview.rb : support Tile 0.7.8.  | ||||
| 	  Now, you can handle tree items as objects.  | ||||
| 
 | ||||
| 2006-10-04  Hidetoshi NAGAI  <nagai@ai.kyutech.ac.jp> | ||||
| 
 | ||||
| 	* lib/tkextlib/tile.rb, lib/tkextlib/tile/* : support Tile 0.7.6. | ||||
|  |  | |||
|  | @ -4597,7 +4597,7 @@ end | |||
| #Tk.freeze | ||||
| 
 | ||||
| module Tk | ||||
|   RELEASE_DATE = '2006-09-01'.freeze | ||||
|   RELEASE_DATE = '2006-11-06'.freeze | ||||
| 
 | ||||
|   autoload :AUTO_PATH,        'tk/variable' | ||||
|   autoload :TCL_PACKAGE_PATH, 'tk/variable' | ||||
|  | @ -4609,6 +4609,7 @@ end | |||
| 
 | ||||
| # call setup script for Tk extension libraries (base configuration) | ||||
| begin | ||||
|   require 'tkextlib/version.rb' | ||||
|   require 'tkextlib/setup.rb' | ||||
| rescue LoadError | ||||
|   # ignore | ||||
|  |  | |||
|  | @ -289,7 +289,7 @@ module TkItemConfigMethod | |||
|     self | ||||
|   end | ||||
| 
 | ||||
|   def itemconfiginfo(tagOrId, slot = nil) | ||||
|   def __itemconfiginfo_core(tagOrId, slot = nil) | ||||
|     if TkComm::GET_CONFIGINFO_AS_ARRAY | ||||
|       if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/) | ||||
|         fontkey  = $2 | ||||
|  | @ -594,7 +594,7 @@ module TkItemConfigMethod | |||
|                 if v.empty? | ||||
|                   conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil | ||||
|                 else | ||||
|                   conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new | ||||
|                   conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new(v) | ||||
|                 end | ||||
|               end | ||||
| 
 | ||||
|  | @ -1020,13 +1020,18 @@ module TkItemConfigMethod | |||
|       end | ||||
|     end | ||||
|   end | ||||
|   private :__itemconfiginfo_core | ||||
| 
 | ||||
|   def itemconfiginfo(tagOrId, slot = nil) | ||||
|     __itemconfiginfo_core(tagOrId, slot) | ||||
|   end | ||||
| 
 | ||||
|   def current_itemconfiginfo(tagOrId, slot = nil) | ||||
|     if TkComm::GET_CONFIGINFO_AS_ARRAY | ||||
|       if slot | ||||
|         org_slot = slot | ||||
|         begin | ||||
|           conf = itemconfiginfo(tagOrId, slot) | ||||
|           conf = __itemconfiginfo_core(tagOrId, slot) | ||||
|           if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ | ||||
|               || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) | ||||
|             return {conf[0] => conf[-1]} | ||||
|  | @ -1037,7 +1042,7 @@ module TkItemConfigMethod | |||
|           "there is a configure alias loop about '#{org_slot}'" | ||||
|       else | ||||
|         ret = {} | ||||
|         itemconfiginfo(tagOrId).each{|conf| | ||||
|         __itemconfiginfo_core(tagOrId).each{|conf| | ||||
|           if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \ | ||||
|               || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 ) | ||||
|             ret[conf[0]] = conf[-1] | ||||
|  | @ -1047,7 +1052,7 @@ module TkItemConfigMethod | |||
|       end | ||||
|     else # ! TkComm::GET_CONFIGINFO_AS_ARRAY | ||||
|       ret = {} | ||||
|       itemconfiginfo(slot).each{|key, conf|      | ||||
|       itemconfiginfo(tagOrId, slot).each{|key, conf| | ||||
|         ret[key] = conf[-1] if conf.kind_of?(Array) | ||||
|       } | ||||
|       ret | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| 
 | ||||
|   [ current support status of Tcl/Tk extensions ] | ||||
| 
 | ||||
|   *******<<<  RELEASE_DATE of the libraries : 2006/10/04  >>>******* | ||||
|   *** RELEASE_DATE of the libraries => see 'tkextlib/version.rb' *** | ||||
| 
 | ||||
| The following list shows *CURRENT* status when this file was modifyed | ||||
| at last. If you want to add other Tcl/Tk extensions to the planed list | ||||
|  | @ -83,7 +83,7 @@ BLT          2.4z    http://sourceforge.net/projects/blt | |||
| TkTreeCtrl   CVS/Hd(2005-12-02) | ||||
|                      http://sourceforge.net/projects/tktreectrl  ==> treectrl | ||||
| 
 | ||||
| Tile         CVS/Hd(2006-10-01) | ||||
| Tile         0.7.8 | ||||
|                      http://sourceforge.net/projects/tktable     ==> tile | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										6
									
								
								ext/tk/lib/tkextlib/version.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ext/tk/lib/tkextlib/version.rb
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| # | ||||
| # release date of tkextlib | ||||
| # | ||||
| module Tk | ||||
|   Tkextlib_RELEASE_DATE = '2006-11-06'.freeze | ||||
| end | ||||
							
								
								
									
										69
									
								
								ext/tk/sample/editable_listbox.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								ext/tk/sample/editable_listbox.rb
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,69 @@ | |||
| # | ||||
| # Editable_TkListbox class | ||||
| # | ||||
| #   When "DoubleClick-1" on a listbox item, the entry box is opend on the | ||||
| #   item. And when hit "Return" key on the entry box after modifying the | ||||
| #   text, the entry box is closed and the item is changed. Or when hit  | ||||
| #   "Escape" key, the entry box is closed without modification. | ||||
| # | ||||
| #                              by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) | ||||
| # | ||||
| require 'tk' | ||||
| 
 | ||||
| class Editable_TkListbox < TkListbox | ||||
|   def _ebox_placer(coord_y) | ||||
|     idx = self.nearest(coord_y) | ||||
|     x, y, w, h = self.bbox(idx) | ||||
|     @ebox.place(:x => 0, :relwidth => 1.0,  | ||||
|                 :y => y - self.selectborderwidth,  | ||||
|                 :height => h + 2 * self.selectborderwidth) | ||||
|     @ebox.pos = idx | ||||
|     @ebox.value = self.listvariable.list[idx] | ||||
|     @ebox.focus | ||||
|   end | ||||
|   private :_ebox_placer | ||||
| 
 | ||||
| 
 | ||||
|   def create_self(keys) | ||||
|     super(keys) | ||||
| 
 | ||||
|     unless self.listvariable | ||||
|       self.listvariable = TkVariable.new(self.get(0, :end)) | ||||
|     end | ||||
| 
 | ||||
|     @ebox = TkEntry.new(self){ | ||||
|       @pos = -1 | ||||
|       def self.pos; @pos; end | ||||
|       def self.pos=(idx); @pos = idx; end | ||||
|     } | ||||
| 
 | ||||
|     @ebox.bind('Return'){ | ||||
|       list = self.listvariable.list | ||||
|       list[@ebox.pos] = @ebox.value | ||||
|       self.listvariable.value = list | ||||
|       @ebox.place_forget | ||||
|       @ebox.pos = -1 | ||||
|     } | ||||
| 
 | ||||
|     @ebox.bind('Escape'){ | ||||
|       @ebox.place_forget | ||||
|       @ebox.pos = -1 | ||||
|     } | ||||
| 
 | ||||
|     self.bind('Double-1', '%y'){|y| _ebox_placer(y) } | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| if $0 == __FILE__ | ||||
|   scr = TkScrollbar.new.pack(:side=>:right, :fill=>:y) | ||||
| 
 | ||||
|   lbox1 = Editable_TkListbox.new.pack(:side=>:left) | ||||
|   lbox2 = Editable_TkListbox.new.pack(:side=>:left) | ||||
| 
 | ||||
|   scr.assign(lbox1, lbox2) | ||||
| 
 | ||||
|   lbox1.insert(:end, *%w(a b c d e f g h i j k l m n)) | ||||
|   lbox2.insert(:end,     0,1,2,3,4,5,6,7,8,9,0,1,2,3) | ||||
| 
 | ||||
|   Tk.mainloop | ||||
| end | ||||
							
								
								
									
										119
									
								
								ext/tk/sample/irbtkw.rbw
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								ext/tk/sample/irbtkw.rbw
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,119 @@ | |||
| #!/usr/bin/env ruby | ||||
| # | ||||
| #  irbtkw.rb : IRB console with Ruby/Tk | ||||
| # | ||||
| #                                 by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) | ||||
| # | ||||
| release = '2006/11/06' | ||||
| 
 | ||||
| require 'tk' | ||||
| begin | ||||
|   require 'tktextio' | ||||
| rescue LoadError | ||||
|   require File.join(File.dirname(File.expand_path(__FILE__)), 'tktextio.rb') | ||||
| end | ||||
| 
 | ||||
| require 'irb' | ||||
| 
 | ||||
| # console setup | ||||
| top = TkToplevel.new(:title=>'IRB console') | ||||
| top.protocol(:WM_DELETE_WINDOW){ Tk.exit } | ||||
| 
 | ||||
| console = TkTextIO.new(top, :mode=>:console,  | ||||
|                        :width=>80).pack(:side=>:left,  | ||||
|                                         :expand=>true, :fill=>:both) | ||||
| console.yscrollbar(TkScrollbar.new(top, :width=>10).pack(:before=>console,  | ||||
|                                                          :side=>:right,  | ||||
|                                                          :expand=>false,  | ||||
|                                                          :fill=>:y)) | ||||
| ev_loop = Thread.new{Tk.mainloop} | ||||
| 
 | ||||
| # window position control | ||||
| root = Tk.root | ||||
| 
 | ||||
| r_x = root.winfo_rootx | ||||
| r_y = root.winfo_rooty | ||||
| r_w = root.winfo_width | ||||
| 
 | ||||
| t_x = top.winfo_rootx | ||||
| t_y = top.winfo_rooty | ||||
| t_w = top.winfo_width | ||||
| 
 | ||||
| delta = 10 | ||||
| 
 | ||||
| ratio = 0.8 | ||||
| s_w = (ratio * root.winfo_screenwidth).to_i | ||||
| 
 | ||||
| if r_x < t_x | ||||
|   r_x, t_x = t_x, r_x | ||||
| end | ||||
| if t_x + t_w + r_w + delta < s_w | ||||
|   r_x = t_x + t_w + delta | ||||
| elsif t_w + r_w + delta < s_w | ||||
|   r_x = s_w - r_w | ||||
|   t_x = r_x - t_w | ||||
| else | ||||
|   r_x = s_w - r_w | ||||
|   t_x = 0 | ||||
| end | ||||
| 
 | ||||
| root.geometry("+#{r_x}+#{r_y}") | ||||
| top.geometry("+#{t_x}+#{t_y}") | ||||
| 
 | ||||
| root.raise | ||||
| console.focus | ||||
| 
 | ||||
| # I/O setup | ||||
| $stdin  = console | ||||
| $stdout = console | ||||
| $stderr = console | ||||
| 
 | ||||
| # dummy for rubyw.exe on Windows | ||||
| def STDIN.tty? | ||||
|   true | ||||
| end | ||||
| 
 | ||||
| # IRB setup | ||||
| IRB.init_config(nil) | ||||
| IRB.conf[:USE_READLINE] = false | ||||
| IRB.init_error | ||||
| irb = IRB::Irb.new | ||||
| IRB.conf[:MAIN_CONTEXT] = irb.context | ||||
| 
 | ||||
| class IRB::StdioInputMethod | ||||
|   def gets | ||||
|     prompt = "\n" << @prompt | ||||
|     $stdin.instance_eval{ | ||||
|       flush | ||||
|       @prompt = prompt | ||||
|       _set_console_line | ||||
|       @prompt = nil | ||||
|       _see_pos | ||||
|     } | ||||
| 
 | ||||
|     @line[@line_no += 1] = $stdin.gets | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| # IRB start | ||||
| $stdout.print("*** IRB console on Ruby/Tk (#{release})  ") | ||||
| irb_thread = Thread.new{ | ||||
|   catch(:IRB_EXIT){ | ||||
|     loop { | ||||
|       begin | ||||
|         irb.eval_input | ||||
|       rescue Exception | ||||
|       end | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| console.bind('Control-c'){ | ||||
|   console.insert('end', "^C\n") | ||||
|   irb_thread.raise RubyLex::TerminateLineInput | ||||
| } | ||||
| 
 | ||||
| irb_thread.join | ||||
| 
 | ||||
| # exit | ||||
| Tk.exit | ||||
|  | @ -1,7 +1,7 @@ | |||
| #!/usr/bin/env ruby | ||||
| # | ||||
| #  sample class of handling I/O stream on a TkText widget | ||||
| #                                               by Hidetoshi NAGAI | ||||
| #  TkTextIO class :: handling I/O stream on a TkText widget | ||||
| #                             by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) | ||||
| # | ||||
| #  NOTE: TkTextIO supports 'character' (not 'byte') access only.  | ||||
| #        So, for example, TkTextIO#getc returns a character, TkTextIO#pos  | ||||
|  | @ -14,68 +14,375 @@ | |||
| #        TkTextIO.  | ||||
| # | ||||
| require 'tk' | ||||
| require 'tk/text' | ||||
| require 'tk/textmark' | ||||
| require 'thread' | ||||
| 
 | ||||
| class TkTextIO < TkText | ||||
|   def create_self(keys) | ||||
|     mode = nil | ||||
|     ovwt = false | ||||
|     text = nil | ||||
|     wrap = 'char' | ||||
|     show = :pos | ||||
|   # keep safe level | ||||
|   @@create_queues = proc{ [Queue.new, Mutex.new, Queue.new, Mutex.new] } | ||||
| 
 | ||||
|     if keys.kind_of?(Hash) | ||||
|       mode = keys.delete('mode') | ||||
|       ovwt = keys.delete('overwrite') | ||||
|       text = keys.delete('text') | ||||
|       show = keys.delete('show') if keys.has_key?('show') | ||||
|       wrap = keys.delete('wrap') || 'char' | ||||
|     end | ||||
|   OPT_DEFAULTS = { | ||||
|     'mode'       => nil, | ||||
|     'overwrite'  => false,  | ||||
|     'text'       => nil,  | ||||
|     'show'       => :pos,  | ||||
|     'wrap'       => 'char',  | ||||
|     'sync'       => true,  | ||||
|     'prompt'     => nil,  | ||||
|     'prompt_cmd' => nil,  | ||||
|     'hist_size'  => 1000,  | ||||
|   } | ||||
| 
 | ||||
|   def create_self(keys) | ||||
|     opts = _get_io_params((keys.kind_of?(Hash))? keys: {}) | ||||
| 
 | ||||
|     super(keys) | ||||
| 
 | ||||
|     self['wrap'] = wrap | ||||
|     insert('1.0', text) | ||||
|     @count_var = TkVariable.new | ||||
| 
 | ||||
|     @txtpos = TkTextMark.new(self, '1.0') | ||||
|     @write_buffer = '' | ||||
|     @read_buffer  = '' | ||||
|     @buf_size = 0 | ||||
|     @buf_max = 1024 | ||||
| 
 | ||||
|     @write_buf_queue, @write_buf_mutex,  | ||||
|     @read_buf_queue,  @read_buf_mutex  = @@create_queues.call | ||||
| 
 | ||||
|     @idle_flush  = TkTimer.new(:idle, 1, proc{ @flusher.run rescue nil }) | ||||
|     @timer_flush = TkTimer.new(250, -1, proc{ @flusher.run rescue nil }) | ||||
| 
 | ||||
|     @flusher = Thread.new{ loop { Thread.stop; flush() } } | ||||
| 
 | ||||
|     @receiver = Thread.new{ | ||||
|       begin | ||||
|         loop { | ||||
|           str = @write_buf_queue.deq | ||||
|           @write_buf_mutex.synchronize { @write_buffer << str } | ||||
|           @idle_flush.start | ||||
|         } | ||||
|       ensure | ||||
|         @flusher.kill | ||||
|       end | ||||
|     } | ||||
| 
 | ||||
|     @timer_flush.start | ||||
| 
 | ||||
|     _setup_io(opts) | ||||
|   end | ||||
|   private :create_self | ||||
| 
 | ||||
|   def destroy | ||||
|     @flusher.kill rescue nil | ||||
| 
 | ||||
|     @idle_flush.stop rescue nil | ||||
|     @timer_flush.stop rescue nil | ||||
| 
 | ||||
|     @receiver.kill rescue nil | ||||
| 
 | ||||
|     super() | ||||
|   end | ||||
| 
 | ||||
|   #################################### | ||||
| 
 | ||||
|   def _get_io_params(keys) | ||||
|     opts = {} | ||||
|     self.class.const_get(:OPT_DEFAULTS).each{|k, v|  | ||||
|       if keys.has_key?(k) | ||||
|         opts[k] = keys.delete(k) | ||||
|       else | ||||
|         opts[k] = v | ||||
|       end | ||||
|     } | ||||
|     opts | ||||
|   end | ||||
| 
 | ||||
|   def _setup_io(opts) | ||||
|     unless defined? @txtpos | ||||
|       @txtpos = TkTextMark.new(self, '1.0') | ||||
|     else | ||||
|       @txtpos.set('1.0') | ||||
|     end | ||||
|     @txtpos.gravity = :left | ||||
| 
 | ||||
|     self.show_mode = show | ||||
| 
 | ||||
|     @sync = true | ||||
|     @overwrite = (ovwt)? true: false | ||||
| 
 | ||||
|     @lineno = 0 | ||||
|     @line_offset = 0 | ||||
|     @count_var = TkVariable.new | ||||
| 
 | ||||
|     @hist_max = opts['hist_size'] | ||||
|     @hist_index = 0 | ||||
|     @history = Array.new(@hist_max) | ||||
|     @history[0] = '' | ||||
| 
 | ||||
|     self['wrap'] = wrap | ||||
| 
 | ||||
|     self.show_mode = opts['show'] | ||||
| 
 | ||||
|     self.value = opts['text'] if opts['text'] | ||||
| 
 | ||||
|     @overwrite = (opts['overwrite'])? true: false | ||||
| 
 | ||||
|     @sync = opts['sync'] | ||||
| 
 | ||||
|     @prompt = opts['prompt'] | ||||
|     @prompt_cmd = opts['prompt_cmd'] | ||||
| 
 | ||||
|     @open  = {:r => true,  :w => true}  # default is 'r+' | ||||
| 
 | ||||
|     case mode | ||||
|     when 'r' | ||||
|     @console_mode = false | ||||
|     @end_of_stream = false | ||||
|     @console_buffer = nil | ||||
| 
 | ||||
|     case opts['mode'] | ||||
|     when nil | ||||
|       # do nothing | ||||
| 
 | ||||
|     when :console, 'console' | ||||
|       @console_mode = true | ||||
|       # @console_buffer = TkTextIO.new(:mode=>'r') | ||||
|       @console_buffer = self.class.new(:mode=>'r') | ||||
|       self.show_mode = :insert | ||||
| 
 | ||||
|     when 'r', 'rb' | ||||
|       @open[:r] = true; @open[:w] = nil | ||||
| 
 | ||||
|     when 'r+' | ||||
|     when 'r+', 'rb+', 'r+b' | ||||
|       @open[:r] = true; @open[:w] = true | ||||
| 
 | ||||
|     when 'w' | ||||
|     when 'w', 'wb' | ||||
|       @open[:r] = nil;  @open[:w] = true | ||||
|       self.value='' | ||||
| 
 | ||||
|     when 'w+' | ||||
|     when 'w+', 'wb+', 'w+b' | ||||
|       @open[:r] = true; @open[:w] = true | ||||
|       self.value='' | ||||
| 
 | ||||
|     when 'a' | ||||
|     when 'a', 'ab' | ||||
|       @open[:r] = nil;  @open[:w] = true | ||||
|       @txtpos = TkTextMark.new(self, 'end - 1 char') | ||||
|       @txtpos.set('end - 1 char') | ||||
|       @txtpos.gravity = :right | ||||
| 
 | ||||
|     when 'a+' | ||||
|     when 'a+', 'ab+', 'a+b' | ||||
|       @open[:r] = true;  @open[:w] = true | ||||
|       @txtpos = TkTextMark.new(self, 'end - 1 char') | ||||
|       @txtpos.set('end - 1 char') | ||||
|       @txtpos.gravity = :right | ||||
| 
 | ||||
|     else | ||||
|       fail ArgumentError, "unknown mode `#{opts['mode']}'" | ||||
|     end | ||||
| 
 | ||||
|     unless defined? @ins_head | ||||
|       @ins_head = TkTextMark.new(self, 'insert') | ||||
|       @ins_head.gravity = :left | ||||
|     end | ||||
| 
 | ||||
|     unless defined? @ins_tail | ||||
|       @ins_tail = TkTextMark.new(self, 'insert') | ||||
|       @ins_tail.gravity = :right | ||||
|     end | ||||
| 
 | ||||
|     unless defined? @tmp_mark | ||||
|       @tmp_mark = TkTextMark.new(self, 'insert') | ||||
|       @tmp_mark.gravity = :left | ||||
|     end | ||||
| 
 | ||||
|     if @console_mode | ||||
|       _set_console_line | ||||
|       _setup_console_bindings | ||||
|     end | ||||
|   end | ||||
|   private :_get_io_params, :_setup_io | ||||
| 
 | ||||
|   def _set_console_line | ||||
|     @tmp_mark.set(@ins_tail) | ||||
| 
 | ||||
|     mark_set('insert', 'end') | ||||
| 
 | ||||
|     prompt = '' | ||||
|     prompt << @prompt_cmd.call if @prompt_cmd | ||||
|     prompt << @prompt if @prompt | ||||
|     insert(@tmp_mark, prompt) | ||||
| 
 | ||||
|     @ins_head.set(@ins_tail) | ||||
|     @ins_tail.set('insert') | ||||
| 
 | ||||
|     @txtpos.set(@tmp_mark) | ||||
| 
 | ||||
|     _see_pos | ||||
|   end | ||||
| 
 | ||||
|   def _replace_console_line(str) | ||||
|     self.delete(@ins_head, @ins_tail) | ||||
|     self.insert(@ins_head, str) | ||||
|   end | ||||
| 
 | ||||
|   def _get_console_line | ||||
|     @tmp_mark.set(@ins_tail) | ||||
|     s = self.get(@ins_head, @tmp_mark) | ||||
|     _set_console_line | ||||
|     s | ||||
|   end | ||||
|   private :_set_console_line, :_replace_console_line, :_get_console_line | ||||
| 
 | ||||
|   def _cb_up | ||||
|     @history[@hist_index].replace(self.get(@ins_head, @ins_tail)) | ||||
|     @hist_index += 1 | ||||
|     @hist_index -= 1 if @hist_index >= @hist_max || !@history[@hist_index] | ||||
|     _replace_console_line(@history[@hist_index]) if @history[@hist_index] | ||||
|     Tk.callback_break | ||||
|   end | ||||
|   def _cb_down | ||||
|     @history[@hist_index].replace(self.get(@ins_head, @ins_tail)) | ||||
|     @hist_index -= 1 | ||||
|     @hist_index = 0 if @hist_index < 0 | ||||
|     _replace_console_line(@history[@hist_index]) if @history[@hist_index] | ||||
|     Tk.callback_break | ||||
|   end | ||||
|   def _cb_left | ||||
|     if @console_mode && compare('insert', '<=', @ins_head) | ||||
|       mark_set('insert', @ins_head) | ||||
|       Tk.callback_break | ||||
|     end | ||||
|   end | ||||
|   def _cb_backspace | ||||
|     if @console_mode && compare('insert', '<=', @ins_head) | ||||
|       Tk.callback_break | ||||
|     end | ||||
|   end | ||||
|   def _cb_ctrl_a | ||||
|     if @console_mode | ||||
|       mark_set('insert', @ins_head) | ||||
|       Tk.callback_break | ||||
|     end | ||||
|   end | ||||
|   private :_cb_up, :_cb_down, :_cb_left, :_cb_backspace, :_cb_ctrl_a | ||||
| 
 | ||||
|   def _setup_console_bindings | ||||
|     @bindtag = TkBindTag.new | ||||
| 
 | ||||
|     tags = self.bindtags | ||||
|     tags[tags.index(self)+1, 0] = @bindtag | ||||
|     self.bindtags = tags | ||||
| 
 | ||||
|     @bindtag.bind('Return'){ | ||||
|       insert('end - 1 char', "\n") | ||||
|       if (str = _get_console_line) | ||||
|         @read_buf_queue.push(str) | ||||
| 
 | ||||
|         @history[0].replace(str.chomp) | ||||
|         @history.pop | ||||
|         @history.unshift('') | ||||
|         @hist_index = 0 | ||||
|       end | ||||
| 
 | ||||
|       Tk.update | ||||
|       Tk.callback_break | ||||
|     } | ||||
|     @bindtag.bind('Alt-Return'){ | ||||
|       Tk.callback_continue | ||||
|     } | ||||
| 
 | ||||
|     @bindtag.bind('FocusIn'){ | ||||
|       if @console_mode | ||||
|         mark_set('insert', @ins_tail) | ||||
|         Tk.callback_break | ||||
|       end | ||||
|     } | ||||
| 
 | ||||
|     ins_mark = TkTextMark.new(self, 'insert') | ||||
| 
 | ||||
|     @bindtag.bind('ButtonPress'){ | ||||
|       if @console_mode | ||||
|         ins_mark.set('insert') | ||||
|       end | ||||
|     } | ||||
| 
 | ||||
|     @bindtag.bind('ButtonRelease-1'){ | ||||
|       if @console_mode && compare('insert', '<=', @ins_head) | ||||
|         mark_set('insert', ins_mark) | ||||
|         Tk.callback_break | ||||
|       end | ||||
|     } | ||||
| 
 | ||||
|     @bindtag.bind('ButtonRelease-2', '%x %y'){|x, y| | ||||
|       if @console_mode | ||||
|         # paste a text at 'insert' only | ||||
|         x1, y1, x2, y2 =  bbox(ins_mark) | ||||
|         unless x == x1 && y == y1 | ||||
|           Tk.event_generate(self, 'ButtonRelease-2', :x=>x1, :y=>y1) | ||||
|           Tk.callback_break | ||||
|         end | ||||
|       end | ||||
|     } | ||||
| 
 | ||||
|     @bindtag.bind('Up'){ _cb_up } | ||||
|     @bindtag.bind('Control-p'){ _cb_up } | ||||
| 
 | ||||
|     @bindtag.bind('Down'){ _cb_down } | ||||
|     @bindtag.bind('Control-n'){ _cb_down } | ||||
| 
 | ||||
|     @bindtag.bind('Left'){ _cb_left } | ||||
|     @bindtag.bind('Control-b'){ _cb_left } | ||||
| 
 | ||||
|     @bindtag.bind('BackSpace'){ _cb_backspace } | ||||
|     @bindtag.bind('Control-h'){ _cb_backspace } | ||||
| 
 | ||||
|     @bindtag.bind('Home'){ _cb_ctrl_a } | ||||
|     @bindtag.bind('Control-a'){ _cb_ctrl_a } | ||||
|   end | ||||
|   private :_setup_console_bindings | ||||
| 
 | ||||
|   def _block_read(size = nil, ret = '', block_mode = true) | ||||
|     return '' if size == 0 | ||||
|     return nil if ! @read_buf_queue && @read_buffer.empty? | ||||
|     ret = '' unless ret.kind_of?(String) | ||||
|     ret.replace('') unless ret.empty? | ||||
| 
 | ||||
|     if block_mode == nil # partial | ||||
|       if @read_buffer.empty? | ||||
|         ret << @read_buffer.slice!(0..-1) | ||||
|         return ret | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     if size.kind_of?(Numeric) | ||||
|       loop{ | ||||
|         @read_buf_mutex.synchronize { | ||||
|           buf_len = @read_buffer.length | ||||
|           if buf_len >= size | ||||
|             ret << @read_buffer.slice!(0, size) | ||||
|             return ret | ||||
|           else | ||||
|             ret << @read_buffer.slice!(0..-1) | ||||
|             size -= buf_len | ||||
|             return ret unless @read_buf_queue | ||||
|           end | ||||
|         } | ||||
|         @read_buffer << @read_buf_queue.pop | ||||
|       } | ||||
|     else # readline | ||||
|       rs = (size)? size: $/ | ||||
|       rs = rs.to_s if rs.kind_of?(Regexp) | ||||
|       loop{ | ||||
|         @read_buf_mutex.synchronize { | ||||
|           if (str = @read_buffer.slice!(/\A(.*)(#{rs})/m)) | ||||
|             ret << str | ||||
|             return ret | ||||
|           else | ||||
|             ret << @read_buffer.slice!(0..-1) | ||||
|             return ret unless @read_buf_queue | ||||
|           end | ||||
|         } | ||||
|         @read_buffer << @read_buf_queue.pop | ||||
|       } | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def _block_write | ||||
|     ###### currently, not support | ||||
|   end | ||||
|   private :_block_read, :_block_write | ||||
| 
 | ||||
|   #################################### | ||||
| 
 | ||||
|   def <<(obj) | ||||
|     _write(obj) | ||||
|  | @ -107,14 +414,15 @@ class TkTextIO < TkText | |||
|     nil | ||||
|   end | ||||
| 
 | ||||
|   def closed? | ||||
|     close_read? && close_write? | ||||
|   end | ||||
|   def closed_read? | ||||
|     !@open[:r] | ||||
|   end | ||||
|   def closed_write? | ||||
|     !@open[:w] | ||||
|   def closed?(dir=nil) | ||||
|     case dir | ||||
|     when :r, 'r' | ||||
|       !@open[:r] | ||||
|     when :w, 'w' | ||||
|       !@open[:w] | ||||
|     else | ||||
|       !@open[:r] && !@open[:w] | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def _check_readable | ||||
|  | @ -129,7 +437,7 @@ class TkTextIO < TkText | |||
| 
 | ||||
|   def each_line(rs = $/) | ||||
|     _check_readable | ||||
|     while(s = gets) | ||||
|     while(s = self.gets(rs)) | ||||
|       yield(s) | ||||
|     end | ||||
|     self | ||||
|  | @ -138,7 +446,7 @@ class TkTextIO < TkText | |||
| 
 | ||||
|   def each_char | ||||
|     _check_readable | ||||
|     while(c = getc) | ||||
|     while(c = self.getc) | ||||
|       yield(c) | ||||
|     end | ||||
|     self | ||||
|  | @ -151,7 +459,7 @@ class TkTextIO < TkText | |||
|   alias eof eof? | ||||
| 
 | ||||
|   def fcntl(*args) | ||||
|     fail NotImplementedError, 'fcntl is not implemented on TkTextIO' | ||||
|     fail NotImplementedError, "fcntl is not implemented on #{self.class}" | ||||
|   end | ||||
| 
 | ||||
|   def fsync | ||||
|  | @ -163,11 +471,19 @@ class TkTextIO < TkText | |||
|   end | ||||
| 
 | ||||
|   def flush | ||||
|     Tk.update if @open[:w] && @sync | ||||
|     Thread.pass | ||||
|     if @open[:w] || ! @write_buffer.empty? | ||||
|       @write_buf_mutex.synchronize { | ||||
|         _sync_write_buf(@write_buffer)  | ||||
|         @write_buffer[0..-1] = '' | ||||
|       } | ||||
|     end | ||||
|     self | ||||
|   end | ||||
| 
 | ||||
|   def getc | ||||
|     return _block_read(1) if @console_mode | ||||
| 
 | ||||
|     _check_readable | ||||
|     return nil if eof? | ||||
|     c = get(@txtpos) | ||||
|  | @ -177,8 +493,10 @@ class TkTextIO < TkText | |||
|   end | ||||
| 
 | ||||
|   def gets(rs = $/) | ||||
|     return _block_read(rs) if @console_mode | ||||
| 
 | ||||
|     _check_readable | ||||
|    return nil if eof? | ||||
|     return nil if eof? | ||||
|     _readline(rs) | ||||
|   end | ||||
| 
 | ||||
|  | @ -233,7 +551,6 @@ class TkTextIO < TkText | |||
|   alias tell pos | ||||
| 
 | ||||
|   def pos=(idx) | ||||
|     # @txtpos.set((idx.kind_of?(Numeric))? "1.0 + #{idx} char": idx) | ||||
|     seek(idx, IO::SEEK_SET) | ||||
|     idx | ||||
|   end | ||||
|  | @ -306,6 +623,8 @@ class TkTextIO < TkText | |||
|   private :_read | ||||
| 
 | ||||
|   def read(len=nil, buf=nil) | ||||
|     return _block_read(len, buf) if @console_mode | ||||
| 
 | ||||
|     _check_readable | ||||
|     if len | ||||
|       return "" if len == 0 | ||||
|  | @ -321,6 +640,8 @@ class TkTextIO < TkText | |||
|   end | ||||
| 
 | ||||
|   def readchar | ||||
|     return _block_read(1) if @console_mode | ||||
| 
 | ||||
|     _check_readable | ||||
|     fail EOFError if eof? | ||||
|     c = get(@txtpos) | ||||
|  | @ -334,6 +655,7 @@ class TkTextIO < TkText | |||
|       s = get(@txtpos, 'end - 1 char') | ||||
|       @txtpos.set('end - 1 char') | ||||
|     elsif rs == '' | ||||
|       @count_var.value  # make it global | ||||
|       idx = tksearch_with_count([:regexp], @count_var,  | ||||
|                                    "\n(\n)+", @txtpos, 'end - 1 char') | ||||
|       if idx | ||||
|  | @ -345,6 +667,7 @@ class TkTextIO < TkText | |||
|         @txtpos.set('end - 1 char') | ||||
|       end | ||||
|     else | ||||
|       @count_var.value  # make it global | ||||
|       idx = tksearch_with_count(@count_var, rs, @txtpos, 'end - 1 char') | ||||
|       if idx | ||||
|         s = get(@txtpos, "#{idx} + #{@count_var.value} char") | ||||
|  | @ -363,12 +686,22 @@ class TkTextIO < TkText | |||
|   private :_readline | ||||
| 
 | ||||
|   def readline(rs = $/) | ||||
|     return _block_readline(rs) if @console_mode | ||||
| 
 | ||||
|     _check_readable | ||||
|     fail EOFError if eof? | ||||
|     _readline(rs) | ||||
|   end | ||||
| 
 | ||||
|   def readlines(rs = $/) | ||||
|     if @console_mode | ||||
|       lines = [] | ||||
|       while (line = _block_readline(rs)) | ||||
|         lines << line | ||||
|       end | ||||
|       return lines | ||||
|     end | ||||
| 
 | ||||
|     _check_readable | ||||
|     lines = [] | ||||
|     until(eof?) | ||||
|  | @ -379,7 +712,11 @@ class TkTextIO < TkText | |||
|   end | ||||
| 
 | ||||
|   def readpartial(maxlen, buf=nil) | ||||
|     #return @console_buffer.readpartial(maxlen, buf) if @console_mode | ||||
|     return _block_read(maxlen, buf, nil) if @console_mode | ||||
| 
 | ||||
|     _check_readable | ||||
|     fail EOFError if eof? | ||||
|     s = _read(maxlen) | ||||
|     buf.replace(s) if buf.kind_of?(String) | ||||
|     s | ||||
|  | @ -471,6 +808,8 @@ class TkTextIO < TkText | |||
|   end | ||||
| 
 | ||||
|   def sysread(len, buf=nil) | ||||
|     return _block_read(len, buf) if @console_mode | ||||
| 
 | ||||
|     _check_readable | ||||
|     fail EOFError if eof? | ||||
|     s = _read(len) | ||||
|  | @ -492,6 +831,13 @@ class TkTextIO < TkText | |||
|   end | ||||
| 
 | ||||
|   def ungetc(c) | ||||
|     if @console_mode | ||||
|       @read_buf_mutex.synchronize { | ||||
|         @read_buffer[0,0] = c.chr | ||||
|       } | ||||
|       return nil | ||||
|     end | ||||
| 
 | ||||
|     _check_readable | ||||
|     c = c.chr if c.kind_of?(Fixnum) | ||||
|     if compare(@txtpos, '>', '1.0') | ||||
|  | @ -506,8 +852,10 @@ class TkTextIO < TkText | |||
|     nil | ||||
|   end | ||||
| 
 | ||||
| =begin | ||||
|   def _write(obj) | ||||
|     s = _get_eval_string(obj) | ||||
|     #s = _get_eval_string(obj) | ||||
|     s = (obj.kind_of?(String))? obj: obj.to_s | ||||
|     n = number(tk_call('string', 'length', s)) | ||||
|     delete(@txtpos, @txtpos + "#{n} char") if @overwrite | ||||
|     self.insert(@txtpos, s) | ||||
|  | @ -518,6 +866,37 @@ class TkTextIO < TkText | |||
|     n | ||||
|   end | ||||
|   private :_write | ||||
| =end | ||||
| #=begin | ||||
|   def _sync_write_buf(s) | ||||
|     if (n = number(tk_call('string', 'length', s))) > 0 | ||||
|       delete(@txtpos, @txtpos + "#{n} char") if @overwrite | ||||
|       self.insert(@txtpos, s) | ||||
|       #Tk.update | ||||
| 
 | ||||
|       @txtpos.set(@txtpos + "#{n} char") | ||||
|       @txtpos.set('end - 1 char') if compare(@txtpos, '>=', :end) | ||||
| 
 | ||||
|       @ins_head.set(@txtpos) if compare(@txtpos, '>', @ins_head) | ||||
| 
 | ||||
|       _see_pos | ||||
|     end | ||||
|     self | ||||
|   end | ||||
|   private :_sync_write_buf | ||||
| 
 | ||||
|   def _write(obj) | ||||
|     s = (obj.kind_of?(String))? obj: obj.to_s | ||||
|     n = number(tk_call('string', 'length', s)) | ||||
|     @write_buf_queue.enq(s) | ||||
|     if @sync | ||||
|       Thread.pass | ||||
|       Tk.update | ||||
|     end | ||||
|     n | ||||
|   end | ||||
|   private :_write | ||||
| #=end | ||||
| 
 | ||||
|   def write(obj) | ||||
|     _check_writable | ||||
|  | @ -529,13 +908,19 @@ end | |||
| #  TEST | ||||
| #################### | ||||
| if __FILE__ == $0 | ||||
|   ev_loop = Thread.new{Tk.mainloop} | ||||
| 
 | ||||
|   f = TkFrame.new.pack | ||||
|   tio = TkTextIO.new(f, :show=>:pos,  | ||||
|   #tio = TkTextIO.new(f, :show=>:nil,  | ||||
|   #tio = TkTextIO.new(f, :show=>:pos,  | ||||
|   tio = TkTextIO.new(f, :show=>:insert,  | ||||
|                      :text=>">>> This is an initial text line. <<<\n\n"){ | ||||
|     yscrollbar(TkScrollbar.new(f).pack(:side=>:right, :fill=>:y)) | ||||
| #    yscrollbar(TkScrollbar.new(f).pack(:side=>:right, :fill=>:y)) | ||||
|     pack(:side=>:left, :fill=>:both, :expand=>true) | ||||
|   } | ||||
| 
 | ||||
|   Tk.update | ||||
| 
 | ||||
|   $stdin  = tio | ||||
|   $stdout = tio | ||||
|   $stderr = tio | ||||
|  | @ -599,5 +984,67 @@ if __FILE__ == $0 | |||
| 
 | ||||
|   tio.seek(0, IO::SEEK_END) | ||||
| 
 | ||||
|   Tk.mainloop | ||||
|   STDOUT.print("tio.sync ==  #{tio.sync}\n") | ||||
| #  tio.sync = false | ||||
| #  STDOUT.print("tio.sync ==  #{tio.sync}\n") | ||||
| 
 | ||||
|   (0..10).each{|i| | ||||
|     STDOUT.print("#{i}\n") | ||||
|     s = '' | ||||
|     (0..1000).each{ s << '*' } | ||||
|     print(s) | ||||
|   } | ||||
|   print("\n") | ||||
|   print("\n=========================================================\n\n") | ||||
| 
 | ||||
|   s = '' | ||||
|   timer = TkTimer.new(:idle, -1, proc{ | ||||
|                         #STDOUT.print("idle call\n") | ||||
|                         unless s.empty? | ||||
|                           print(s) | ||||
|                           s = '' | ||||
|                         end | ||||
|                       }).start | ||||
|   (0..10).each{|i| | ||||
|     STDOUT.print("#{i}\n") | ||||
|     (0..1000).each{ s << '*' } | ||||
|   } | ||||
| #  timer.stop | ||||
|   until s.empty? | ||||
|     sleep 0.1 | ||||
|   end | ||||
|   timer.stop | ||||
| 
 | ||||
| =begin | ||||
|   tio.sync = false | ||||
|   print("\n") | ||||
|   #(0..10000).each{ putc('*') } | ||||
|   (0..10).each{|i| | ||||
|     STDOUT.print("#{i}\n") | ||||
|     (0..1000).each{ putc('*') } | ||||
|   } | ||||
| 
 | ||||
|   (0..10).each{|i| | ||||
|     STDOUT.print("#{i}\n") | ||||
|     s = '' | ||||
|     (0..1000).each{ s << '*' } | ||||
|     print(s) | ||||
|   } | ||||
| =end | ||||
| 
 | ||||
|   num = 0 | ||||
| #  io = TkTextIO.new(:mode=>:console, :prompt=>'').pack | ||||
| #=begin | ||||
|   io = TkTextIO.new(:mode=>:console,  | ||||
|                     :prompt_cmd=>proc{ | ||||
|                       s = "[#{num}]" | ||||
|                       num += 1 | ||||
|                       s | ||||
|                     },  | ||||
|                     :prompt=>'-> ').pack | ||||
| #=end | ||||
|   Thread.new{loop{sleep 2; io.puts 'hoge'}} | ||||
|   Thread.new{loop{p io.gets}} | ||||
| 
 | ||||
|   ev_loop.join | ||||
| end | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 nagai
						nagai