i'm trying to implement a simple line highlighting mechanism in my tcl/tk text widget.
For this I would like to assign all characters marked with one tag to another tag.
as in
.window.text insert end "one line\n" line1
.window.text insert end "a chunk spanning\nmultiple lines" line2
.window.text insert end "thats all\n" line3
# get all text that is tagged as 'line2'
set selected [ .window.text tag ranges line2 ]
# and apply the 'highlighed' tag to it:
.window.text tag add highlighted $selected
Unfortunately this does notwork, as it gives me
bad text index "2.0 4.0"
Using the indices literally works fine:
.window.text tag add highlighted 2.0 4.0
But is not what i want. (I don't know anything about the tagged chunks apart from their tag)
So it seems that I cannot store the list of indices in a variable and use that with tag add
(or tag remove
for that matter).
Any hints how I can add a tag to an already tagged text?
Solution (in Tcl 8.5 and later):
If command A has given you a list of items to feed to command B, but command B expects each item to appear as an argument in its invocation, the list of items needs to be spliced, or expanded into separate arguments. In Tcl 8.5, this was facilitated by introducing a new syntactic rule that allowed the number of arguments provided to a command to be increased by expanding one of the existing arguments.
To borrow an example, the
destroy ?window window ...?
command cannot work with the list of windows returned bywinfo children .
, since each window path needs to be a separate argument. Writingwould be evaluated as (say)
destroy {.foo .bar .baz}
, which won't work. However, using the new expansion prefix{*}
the line will be evaluated as
destroy .foo .bar .baz
, which will work.One way to understand it is by thinking of the invocation as a list consisting of the command name and the arguments, and that the
{*}
is an instruction to splice the value of the following argument into that list at that point in the list.Documentation: {*}