Detect changes in a tk::text widget - widget

I want to monitor every change in a tk::text widget.
My first step was simply to get all <Key> events and send them to my monitoring routine, but if I copy some text into the text widget, this will not work.
I found a <Modified> virtual event. This will give me the ability to react on every change in the text widget, but I did not find a way to determine the kind of change.
For my actual problem it would be sufficient if I got every character or text which were inserted into my widget. It is not important to get the positions or other attributes of the insertion.
The next thing I tried was to bind the <Button-2> event. This will give me a notification but I could not get the inserted text. Is there maybe a way to get the actual selected text from X which would be copied into the widget? This would also be sufficient.

If you just want notification of inserts, deletes and replaces (which all other modifications boil down to) the simplest way is to intercept the insert, delete and replace methods. Here's how to do it with a TclOO wrapper:
oo::class create Text {
unexport destroy
constructor {w} {
rename $w [namespace current]::realwidget
bind $w <Destroy> [namespace code {my destroy}]
}
self method create {w args} {
rename [my new [::text $w {*}$args]] ::$w
return $w
}
method DoingModification args {
# Override this method to find out
}
method delete args {
my DoingModification {*}$args
tailcall realwidget delete {*}$args
}
method insert args {
my DoingModification {*}$args
tailcall realwidget insert {*}$args
}
method replace args {
my DoingModification {*}$args
tailcall realwidget replace {*}$args
}
}
# Everything else should just be forwarded; there's a lot of methods to do
# so we loop over them all...
foreach method {
bbox cget compare configure count debug dlineinfo dump edit get image
index mark peer scan search see tag window xview yview
} {
oo::define Text forward $method realwidget $method
}
After that, you can make a widget and find out the modifications pretty easily, and everything otherwise works just like normal:
set w [Text create .t]
oo::objdefine $w method DoingModification {method args} {
puts "Doing a $method on $args"
}
pack $w

Related

TclOO : What is the difference between my and self?

The documentation probably explains it very well but I do not see the difference between this 2 commands in my case :
method dir {} {
puts "method dir..."
}
method pseudomethod {} {
set vardir [my dir]
set vardir [[self] dir]
}
The only difference I can see is that with [self] I can pass it as an argument in a procedure and not with my.
What is the best solution in my case ?
Both solutions have equal performance ?
The self command (with no extra arguments) is equivalent to self object which returns the current public name of the object that is executing the method (you can rename the object). The self command overall provides access to bits of “runtime” state.
The my command is actually the object's internal name; it's created in each object's instance namespace. You can invoke all exported and non-exported methods via my, unlike with the public name. This makes it useful for both calling your internal methods directly, and also for setting up things like callbacks to internal methods (you'll need something like namespace which or namespace code when setting up the callback).
Unlike with the public name, you can delete the internal name command without automatically destroying the object. It'll likely break code (your methods most probably) if you do that, but the base system allows you to do it.
Aside: Tcl 8.7 includes this helper procedure (which also works in 8.6) for creating callback scripts within methods (the funny name means it gets mapped into your methods automatically as callback):
proc ::oo::Helpers::callback {method args} {
list [uplevel 1 {::namespace which my}] $method {*}$args
}
In this case, if the callback was exported, you'd be able to do this instead:
proc ::oo::Helpers::callback {method args} {
list [uplevel 1 self] $method {*}$args
}
but that would be more vulnerable to rename problems. (In all cases, the uplevel 1 is because we want to run a little bit of name-resolving code in the calling context, not inside the scope of the procedure itself.)
I'm not sure how they are implemented, but one reason you'd want to use my is to access non-exported (private) methods. A demo:
oo::class create Foo {
method PrivateMethod {} {puts "this is PrivateMethod"}
method publicMethod {} {puts "this is publicMethod"}
method test {} {
my publicMethod
my PrivateMethod
[self] publicMethod
[self] PrivateMethod
}
}
then:
% Foo create foo
::foo
% foo test
this is publicMethod
this is PrivateMethod
this is publicMethod
unknown method "PrivateMethod": must be destroy, publicMethod or test
my is the mechanism for an object to invoke its methods.
self is the mechanism for introspection on how the current method was called.
Spend some time with the my and self man pages.

How to pass by reference to function that won't accept new arguments?

I need to modify a parameter named test inside process_data and switch cases outside that function depending on test value.
I couldn't pass it by reference using upvar because the process_data represent a static function for processing received udp packet, and it won't accept more than two parameters 'size and data'.
Also, as far as I found, there is no returned value for the process_data function.
Code:
set test "0"
Agent/UDP instproc process_data {size data} {
//some stuff
if (...)
set test "1"
}
// switch cases depending on test value.
You don't need an extra argument to use upvar if you know the name of the variable you're going to alias. You should be able to do either of these (do not use both):
global test
upvar #0 test test
It's not really classic modular programming, but it will work.
A good place to put the command is at the beginning of the procedure body, like so:
Agent/UDP instproc process_data {size data} {
global test
# some stuff
}
Same thing if you use upvar #0 test test (those two commands are basically equivalent).
Documentation:
global,
upvar

How to resource the itcl classes to without starting a tcl shell

With this Tcl script: A.tcl
itcl::class ::A {
variable list1 {}
public method getList {} {
return $list1
}
}
I do this:
Start the tcl shell and interactively do source A.tcl
then make changes to getList method in A.tcl
To make the changes effective, I do re-source the file A.tcl
When I re-source, I get the following error
% source /home/manid/scripts/test.tcl
class "A" already exists
How can i overcome this error? Is there a way to get the latest changes in the class definition without exiting the shell?
You need to write your code somewhat differently. In particular, you have to put the definitions of the body of the methods (which can be repeated) outside the declaration of the class (which can't be repeated). Then, you do a conditional class creation (with itcl::is class as the tester) and use itcl::body to actually provide the method definitions.
According to these principles, rewriting your A.tcl to be:
if {![itcl::is class ::A]} {
itcl::class ::A {
variable list1 {}
# *Dummy* method body; method must exist, but may be empty
public method getList {} {}
}
}
itcl::body ::A::getList {} {
return $list1
}
would allow you to source that multiple times to change the method bodies however you wanted. This doesn't give you freedom to change everything (e.g., the variable declarations and scope rules are fixed); you need to switch to something like TclOO to get that sort of flexibility.

TclOO class inside namespace: calling namespace procs give errors

I'm experimenting a little with TclOO from Tcl8.6 and Rivet, but I'm in trouble, because I'm not able to do what I want.
The problem is simply reproduceable with the following code inside a .rvt file:
<?
proc dumbproc {} {
puts "this is dumbproc ([namespace current])"
}
oo::class create foo {
method bar {} {
puts "this is bar ([namespace current])"
dumbproc
}
}
set obj [foo new]
dumbproc
$obj bar
If I simply look at the code, it seems it should work as expected, but it really doesn't because a subtle behavior of the Rivet package and the specific configuration choosen.
In this example, I'm using a .rvt file whose code is executed inside the ::request namespace, so the fully qualified name of the dumbproc procedure is ::request::dumbproc. When the name resolution algorithm is called inside the bar method, it searches for dumbproc inside ::oo::Obj12, then in ::oo, and finally in ::, without finding it and giving the following error.
this is dumbproc (::request) this is bar (::oo::Obj16)
invalid command name "dumbproc"
while executing
"dumbproc"
(class "::request::foo" method "bar" line 3)
invoked from within
"$obj bar"
(in namespace eval "::request" script line 21)
invoked from within
"namespace eval request {
puts -nonewline ""
proc dumbproc {} {
puts "this is dumbproc ([namespace current])"
}
oo::class create..."
So, Tcl is right in doing what it does, a feature, then. But the behavior is unpredictable because when you write some class code, you must know the context it will be used in.
Indeed, I get the same error if I drop the starting <? Rivet magic, put the code inside a test.tcl file and use it in an interactive session:
$ tclsh
% namespace eval ::myns {source test.tcl}
this is dumbproc (::myns)
this is bar (::oo::Obj12)
invalid command name "dumbproc"
I tried to solve the issue by prepending the current namespace to the class creation code
::oo::class create [namespace current]::foo { ... }
then, I also tried to create the obj object inside the namespace
::oo::class create [namespace current]::foo { ... }
namespace eval [namespace current] {set obj [[namespace current]::foo new]}
then, I switched to the create method of the class for giving the object a qualified name which includes the namespace
foo create [namespace current]::obj
obj bar
but everything was unsuccessful. Every trial shows that, no matter how I do it, a method inside a TclOO class is always executed inside its object unique namespace. Am I wrong?
Is there a way to get what I want? Is TclOO not intended to work that way, and in this case why? What really surprise me is this context-dependend behavior, which I'm not sure it's the right thing, but maybe I'm completely wrong and there are sound cases for it, which I'm missing.
The interior of each TclOO object is in reality its own namespace. You can use self namespace or namespace current inside your methods to get the name of the namespace, or info object namespace $theobj to get the namespace from anywhere. The only command placed by default in the namespace is my (for calling private methods), and some commands in other namespaces are made available through the standard Tcl namespace path mechanism (this is how you get self and next available).
The simplest way to fix this would probably be to add this to the foo class's constructor:
namespace path [list {*}[namespace path] ::request]
In your specific case, you'd have to actually add a constructor...
constructor {} {
namespace path [list {*}[namespace path] ::request]
# If you had a non-trivial constructor in a superclass, you'd need to call
# [next] too.
}
Longer term, it may be reasonable to ask for a mechanism for adding to the list of namespaces that are used to make the default for objects of a class. If you want that, do submit a feature request…
[EDIT]: If you're just after adding the parent namespace to the current object's command resolution path, you can do that by adding a bit more magic:
oo::class create foo {
self {
method create args {
set ns [uplevel 1 {namespace current}]
next {*}[linsert $args 1 $ns]
}
method new args {
set ns [uplevel 1 {namespace current}]
next {*}[linsert $args 0 $ns]
}
}
constructor {creatorNS args} {
namespace path [list {*}[namespace path] $creatorNS]
}
method bar {} {
puts "this is bar ([namespace current])"
dumbproc
}
}
That will then automatically put the current namespace at creation on the path of the instance. If you're doing this in many classes, you probably want to create a metaclass with the majority of machinery in it, but the above technique (a self declaration of some methods on the foo class object itself) works fine for simple cases.

Add callback command on any tcl error in tcl script?

Is is possible to specify user defined command on error in tcl script?
I want to cleanup the memory on if any error comes. I know that last error is saved in errorInfo variable.
It's not quite clear what really do you want.
You can trap any error using the catch command. If you need it to work on the top level, you can evaluate the rest of your script under catch, like in
catch {
source ./the_rest_of_the_code.tcl
} err
For asynchronous programs (those using event loop, Tk included) it's not that easy as unexpected errors can be raised in callbacks. To deal with those look at the bgerror command.
The other alternative is to use an execution trace in leavestep mode, which lets you test whether each command executed failed and determine what to do if it occurs. (This is a lot like what you can do with certain types of aspects in AOP.)
proc doIt {} {
namespace eval :: {
# Your real code goes in here
}
}
trace add execution doIt leavestep {::apply {{cmd cmdArgs code result op} {
if {$code == 1} {#0 == ok, 1 == error
puts "ERROR >>$result<< from $cmdArgs"
}
}}}
doIt
It's pretty slow though.
You can also define a bgerror procedure and call your code as a background task:
proc bgerror { msg } {
puts "bgerror:$msg"
# Cleanup code here
}
proc troubleCode { } {
adjsad s ahda
}
after 1 troubleCode