TkEntry with { (left brace) characters

M

Mac

I've tried to boil this down to be as meaningful as possible. I'm
guessing this is a Tk issue, but since I'm using Ruby (1.8.0) I thought
I'd start here.

Type any English text character into the entry box, and the target proc
sees the character as typed (e.g. type an a and it sees an "a", type a b
and it sees the field contains "ab").

The exception is the "{" (left brace). Type one in and the entry box has
one "{", but The TkVariable @myText displays it as empty (the TkComm
object sees that as an escaped character "\{" ). Type a second left
brace and the entry field has 2 braces and the TkVariable @myText still
extracts an empty string.

Type a 3rd brace and now the @myText.to_s gives back 1 brace (all right
of the first 2?).

Thanks for any insight.

Mac


require 'tk';

def puts_KeyChar(tkcommObj);
puts 'key release - ' + tkcommObj.char() + ' -';
puts 'entry variable - ' + @myText.to_s + ' -';
end

myWindowRoot = TkRoot.new {title 'Tk Test'};
@myText = TkVariable.new('');

myEntry = TkEntry.new(myWindowRoot);
myEntry.textvariable(@myText);

myEntry.pack('side'=>'top');
myEntry.bind('Any-KeyRelease',proc {|tkcommObj| puts_KeyChar(tkcommObj)});

Tk.mainloop;
 
H

Hidetoshi NAGAI

Hi,

From: Mac <[email protected]>
Subject: TkEntry with { (left brace) characters
Date: Mon, 9 Feb 2004 03:54:59 +0900
Message-ID: said:
The exception is the "{" (left brace). Type one in and the entry box has
one "{", but The TkVariable @myText displays it as empty (the TkComm
object sees that as an escaped character "\{" ). Type a second left
brace and the entry field has 2 braces and the TkVariable @myText still
extracts an empty string.

Sorry. It's a bug of TkVariable#to_s (TkComm::string).
Please use TkVariable#value instead of TkVariable#to_s.
 
M

Mac

Hidetoshi said:
Hi,

From: Mac <[email protected]>
Subject: TkEntry with { (left brace) characters
Date: Mon, 9 Feb 2004 03:54:59 +0900



Sorry. It's a bug of TkVariable#to_s (TkComm::string).
Please use TkVariable#value instead of TkVariable#to_s.

That works, although I would feel more comfortable using the method
intended to return a string (although being relatively new at this
language, this may be the preferred way to handle this?).

I think it's interesting that the left brace character is the only one
that is returned 'escaped' by TkComm#char (e.g. I get a left bracket "["
back for the left bracket and I get an escaped left brace "\{" back for
the left brace).

Is that part of the TkVariable problem, also?


Anyway, thanks for the info.

Mac
 
H

Hidetoshi NAGAI

Hi,

From: Hidetoshi NAGAI <[email protected]>
Subject: Re: TkEntry with { (left brace) characters
Date: Mon, 9 Feb 2004 04:22:49 +0900
Message-ID: said:
Sorry. It's a bug of TkVariable#to_s (TkComm::string).
Please use TkVariable#value instead of TkVariable#to_s.

I committed the following patch to CVS head.
It makes TkVariable#to_s to call TkVariable#value.
At the same time, I think it will fix the bug to treat a
Tcl/Tk's string with escaping special characters.

However, I remain ambivalence about backporting to Ruby 1.8.x.
Although the patch fixes some problems (e.g. A validatecommand
of TkEntry cannot acquire a right string when the entry box has
a string which has unbalanced braces such as "a {"), Ruby/Tk
loses backward compatibility.

An easily understandable example of incompatibility is a return
value of TkComm::Event#char. When a key event about a left brace
occurs, Ruby/Tk without the patch returns an escaped left brace
"\{". But with the patch, returns only a left brace "{". Of cource,
it is a bug to return "\{". Though a bug, some scripts may presume
an escaped left brace.

Your comments on the patch are welcome.
 
H

Hidetoshi NAGAI

----Next_Part(Thu_Feb_12_00:45:02_2004_571)--
Content-Type: Multipart/Mixed;
boundary="--Next_Part(Thu_Feb_12_00:45:02_2004_571)--"

----Next_Part(Thu_Feb_12_00:45:02_2004_571)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

From: Hidetoshi NAGAI <[email protected]>
Subject: Re: TkEntry with { (left brace) characters
Date: Thu, 12 Feb 2004 00:41:03 +0900
Message-ID: said:
I committed the following patch to CVS head.

Sorry. I forgot to attach the patch.
--
Hidetoshi NAGAI ([email protected])

----Next_Part(Thu_Feb_12_00:45:02_2004_571)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="tk.rb-diff"

Index: tk.rb
===================================================================
RCS file: /src/ruby/ext/tk/lib/tk.rb,v
retrieving revision 1.104
diff -u -r1.104 tk.rb
--- tk.rb 13 Jan 2004 07:52:03 -0000 1.104
+++ tk.rb 11 Feb 2004 14:21:30 -0000
@@ -1,6 +1,6 @@
#
# tk.rb - Tk interface module using tcltklib
-# $Date: 2004/01/13 07:52:03 $
+# $Date: 2004/01/07 05:28:53 $
# by Yukihiro Matsumoto <[email protected]>

# use Shigehiro's tcltklib
@@ -87,9 +87,9 @@
#return Tk_CMDTBL[$1]
return TkCore::INTERP.tk_cmd_tbl[$1]
end
- if val.include? ?\s
- return val.split.collect{|v| tk_tcl2ruby(v)}
- end
+ #if val.include? ?\s
+ # return val.split.collect{|v| tk_tcl2ruby(v)}
+ #end
case val
when /^@font/
TkFont.get_obj(val)
@@ -101,12 +101,14 @@
TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val)
when /^i\d+$/
TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
- when / /
+ when /^-?\d+\.?\d*(e[-+]?\d+)?$/
+ val.to_f
+ when /[^\\] /
val.split.collect{|elt|
tk_tcl2ruby(elt)
}
- when /^-?\d+\.?\d*(e[-+]?\d+)?$/
- val.to_f
+ when /\\ /
+ val.gsub(/\\ /, ' ')
else
val
end
@@ -114,6 +116,37 @@

def tk_split_list(str)
return [] if str == ""
+ list = []
+ token = nil
+ escape = false
+ brace = 0
+ str.split('').each {|c|
+ if c == '\\' && !escape
+ escape = true
+ token = (token || "") << c
+ next
+ end
+ brace += 1 if c == '{' && !escape
+ brace -= 1 if c == '}' && !escape
+ if brace == 0 && c == ' ' && !escape
+ list << token.gsub(/^\{(.*)\}$/, '\1') if token
+ token = nil
+ else
+ token = (token || "") << c
+ end
+ escape = false
+ }
+ list << token.gsub(/^\{(.*)\}$/, '\1') if token
+
+ if list.size == 1
+ tk_tcl2ruby(list[0].gsub(/\\(\{|})/, '\1'))
+ else
+ list.collect{|token| tk_split_list(token)}
+ end
+ end
+=begin
+ def tk_split_list(str)
+ return [] if str == ""
idx = str.index('{')
while idx and idx > 0 and str[idx-1] == ?\\
idx = str.index('{', idx+1)
@@ -130,11 +163,13 @@
list = [] if list == ""
str = str[idx+1..-1]
i = -1
+ escape = false
brace = 1
str.each_byte {|c|
i += 1
- brace += 1 if c == ?{
- brace -= 1 if c == ?}
+ brace += 1 if c == ?{ && !escape
+ brace -= 1 if c == ?} && !escape
+ escape = (c == ?\\)
break if brace == 0
}
if str.size == i + 1
@@ -148,9 +183,35 @@
list += tk_split_list(str[i+1..-1])
list
end
+=end

def tk_split_simplelist(str)
return [] if str == ""
+ list = []
+ token = nil
+ escape = false
+ brace = 0
+ str.split('').each {|c|
+ if c == '\\' && !escape
+ escape = true
+ next
+ end
+ brace += 1 if c == '{' && !escape
+ brace -= 1 if c == '}' && !escape
+ if brace == 0 && c == ' ' && !escape
+ list << token.gsub(/^\{(.*)\}$/, '\1') if token
+ token = nil
+ else
+ token = (token || "") << c
+ end
+ escape = false
+ }
+ list << token.gsub(/^\{(.*)\}$/, '\1') if token
+ list
+ end
+=begin
+ def tk_split_simplelist(str)
+ return [] if str == ""
idx = str.index('{')
while idx and idx > 0 and str[idx-1] == ?\\
idx = str.index('{', idx+1)
@@ -160,11 +221,13 @@
list = str[0,idx].split
str = str[idx+1..-1]
i = -1
+ escape = false
brace = 1
str.each_byte {|c|
i += 1
- brace += 1 if c == ?{
- brace -= 1 if c == ?}
+ brace += 1 if c == ?{ && !escape
+ brace -= 1 if c == ?} && !escape
+ escape = (c == ?\\)
break if brace == 0
}
if i == 0
@@ -172,11 +235,14 @@
elsif str[0, i] == ' '
list.push ' '
else
- list.push str[0..i-1]
+ #list.push str[0..i-1]
+ list.push(str[0..i-1].gsub(/\\(\{|})/, '\1'))
end
list += tk_split_simplelist(str[i+1..-1])
list
end
+=end
+
private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist

def _symbolkey2str(keys)
@@ -236,7 +302,7 @@
def string(val)
if val == "{}"
''
- elsif val[0] == ?{
+ elsif val[0] == ?{ && val[-1] == ?}
val[1..-2]
else
val
@@ -748,6 +814,7 @@
end

INTERP.add_tk_procs('rb_out', 'args', <<-'EOL')
+ regsub -all {\\} $args {\\\\} args
regsub -all {!} $args {\\!} args
regsub -all "{" $args "\\{" args
if {[set st [catch {ruby [format "TkCore.callback %%Q!%s!" $args]} ret]] != 0} {
@@ -897,7 +964,8 @@
end

def rb_appsend(interp, async, *args)
- args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
+ #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
+ args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')}
args.push(').to_s"')
appsend(interp, async, 'ruby "(', *args)
end
@@ -912,7 +980,8 @@
end

def rb_appsend_displayof(interp, win, async, *args)
- args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
+ #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')}
+ args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')}
args.push(').to_s"')
appsend_displayof(interp, win, async, 'ruby "(', *args)
end
@@ -1550,7 +1619,8 @@
@@enc_buf = '__rb_encoding_buffer__'

def self.tk_escape(str)
- s = '"' + str.gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ #s = '"' + str.gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ s = '"' + str.gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
TkCore::INTERP.__eval(Kernel.format('global %s; set %s %s',
@@enc_buf, @@enc_buf, s))
end
@@ -1859,23 +1929,30 @@
# val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
# s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"'
val.each_with_index{|e,i| a.push(i); a.push(e)}
- s = '"' + array2tk_list(a).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ #s = '"' + array2tk_list(a).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ s = '"' + array2tk_list(a).gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
elsif val.kind_of?(Hash)
+ #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
+ # .gsub(/[\[\]$"]/, '\\\\\&') + '"'
s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
- .gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ .gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
else
- s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
INTERP._eval(format('global %s; set %s %s', @id, @id, s))
end
=end
if val.kind_of?(Hash)
+ #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
+ # .gsub(/[\[\]$"]/, '\\\\\&') + '"'
s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
- .gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ .gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
INTERP._eval(Kernel.format('global %s; array set %s %s', @id, @id, s))
else
- s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s))
end
end
@@ -1933,7 +2010,8 @@

def value=(val)
begin
- s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s))
rescue
if INTERP._eval(Kernel.format('global %s; array exists %s',
@@ -1945,12 +2023,15 @@
elsif val.kind_of?(Array)
a = []
val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
- s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ #s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ s = '"' + a.join(" ").gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s',
@id, @id, @id, s))
elsif val.kind_of?(Hash)
+ #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
+ # .gsub(/[\[\]$"]/, '\\\\\&') + '"'
s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
- .gsub(/[\[\]$"]/, '\\\\\&') + '"'
+ .gsub(/[\[\]$\\"]/, '\\\\\&') + '"'
INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s',
@id, @id, @id, s))
else
@@ -1993,7 +2074,8 @@
end

def to_s
- string(value).to_s
+ #string(value).to_s
+ value
end

def to_sym
@@ -2302,7 +2384,8 @@
@id = varname
TkVar_ID_TBL[@id] = self
if val
- s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' #"
+ #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' #"
+ s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' #"
INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s))
end
end

----Next_Part(Thu_Feb_12_00:45:02_2004_571)----
----Next_Part(Thu_Feb_12_00:45:02_2004_571)----
 
H

Hidetoshi NAGAI

Hi,

From: Hidetoshi NAGAI <[email protected]>
Subject: Re: TkEntry with { (left brace) characters
Date: Thu, 12 Feb 2004 00:45:04 +0900
Message-ID: said:
Sorry. I forgot to attach the patch.

Sorry, again. The patch has some bugs.
I fixed on CVS head. Please get the newest version from CVS.
 
M

Mac

Hidetoshi said:
Hi,

From: Hidetoshi NAGAI <[email protected]>
Subject: Re: TkEntry with { (left brace) characters
Date: Mon, 9 Feb 2004 04:22:49 +0900
Message-ID: <[email protected]>
snip
However, I remain ambivalence about backporting to Ruby 1.8.x.
Although the patch fixes some problems (e.g. A validatecommand
of TkEntry cannot acquire a right string when the entry box has
a string which has unbalanced braces such as "a {"), Ruby/Tk
loses backward compatibility.
snip
Your comments on the patch are welcome.

I don't mind if you dont' backport the patch. I went ahead with 1.8.1
and applied the patch (final version :) ) to that. I figured if I was
going to recompile I'd have the next stable release. I need to retest
anyway. Might as well get caught up.

I do think that anyone that coded around the escaped left brace could be
just as surprised when they move on to a new version as they would have
been if they found it in a supposedly "same" version.

But I might not backport it just because of needing to draw a line
somewhere. How many versions back would you go with a backport? 1.8.0?
1.6.1? ??? I'd just leave well enough alone and make sure it's documented.

Mac
 
M

Mac

Hidetoshi said:
Hi,

From: Hidetoshi NAGAI <[email protected]>
Subject: Re: TkEntry with { (left brace) characters
Date: Thu, 12 Feb 2004 00:45:04 +0900



Sorry, again. The patch has some bugs.
I fixed on CVS head. Please get the newest version from CVS.

Just got the patch and applied it to ruby 1.8.1 . It works well so far.
Got both my bugs and doesn't seem to have detrimental side effects. I'll
keep an eye on it as I continue working with it.

Thanks for the update!

Mac
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,998
Latest member
MarissaEub

Latest Threads

Top