how to set text indices via a variable

147 Views Asked by At

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?

1

There are 1 best solutions below

0
On BEST ANSWER

Solution (in Tcl 8.5 and later):

.window.text tag add highlighted {*}$selected

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 by winfo children ., since each window path needs to be a separate argument. Writing

destroy [winfo children .]

would be evaluated as (say) destroy {.foo .bar .baz}, which won't work. However, using the new expansion prefix {*}

destroy {*}[winfo children .]

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: {*}