jtexttags.tcl

Introduction

The jtexttags.tcl library is distributed as part of the jstools package.

It lets you:


This document describes jtexttags.tcl version 4.1/4.4.

Usage

Accessing the Library

In order to use the jtexttags.tcl library, it (and any other libraries it depends on) must be in your Tcl auto_path, described in tclvars(n). Information about how to arrange that, and other conventions common to the jstools libraries, is in the Usage section of The jstools Libraries.

Credits and Copyright

Author

Jay Sekora
js@aq.org
http://www.aq.org/~js/

Copyright

The library is copyright © 1992-1995 by Jay Sekora, but may be freely redistributed under the conditions at the top of the file.

Using Tags

The tags handled by jtexttags.tcl are of the format category:attribute:value, where category identifies what sort of function the tag serves, attribute identifies what class of thing the tag controls, and value is the particular value of that attribute for the tagged text.

This is rather abstract, but category could be things like display to control physical appearance of the text, command to control actions taken when the text is clicked on, structure to identify logical parts of a document, and so forth. attribute names a kind of attribute relevant to the category; for instance, display attributes include font and background; attributes of the hypothetical structure category could include chapter and revision_date. value is the particular value of an attribute for a chunk of text. For instance, the following tags make sense:

display:font:lucidasans-12
display:bgstipple:gray25
display:background:blue
command:click:go_back
command:click:hide_text
structure:chapter:13
structure:author:js

A section of application code can look at the category part of a tag to see whether it cares about a particular tag; for instance, code handling bindings might care about command tags but not about display tags, while code that handles indexing might look at structure tags.

Within each category, a stretch of text, or the current tag list (described below) can have only one tag with the same attribute; for instance, a particular stretch of text can be tagged both display:font:fixed and display:background:blue, but it can't be tagged both display:font:fixed and display:font:12x24; likewise it can be tagged both structure:chapter:13 and structure:revision_date:1994.09.02, but not both structure:chapter:13 and structure:chapter:2. The jtexttags.tcl procedures take care of replacing conflicting tags, but allowing compatible tags to coexist.

The display category is handled specially: the jtexttags.tcl library automatically translates display tags into tag configuration options; it uses attribute as the text tag option to configure and value as the value of that option. For instance, when you start using the tag display:font:variable, the display:font:variable tag is automatically configured as with the statement

textwidget tag configure display:font:variable \
-font variable

(In practise, you may prefer to handle multiple fonts with the jrichtext.tcl library, which uses tags like richtext:font:roman and richtext:font:italic; this lets you choose fonts dynamically, perhaps based on user preferences. However, the display tags are very handy for other display attributes, and are appropriate for fonts in applications such as word processors where the specific font displayed is a property of the document itself rather than a user preference.)

You can also do a consistency check with j:tag:configure_display_tags, forcing all display tags in a text widget to be properly configured. This is useful, for instance, after reading text and tags from a file, or manipulating values in a display tag with your own code.

The jtexttags.tcl library does not by itself guarantee that all text in a text widget has some kind of tag, so you can't assume, for instance, that all text in a widget is tagged display:font:something unless you take steps to make sure that is the case.

jtexttags.tcl keeps the display tags (only) that it manipulates at the bottom of the tag stacking order, so the visual attributes of other tags (e.g. sel) will override the attributes set with the library.

The Current Tag List

Many of the procedures in this library use and maintain a current tag list for each text widget they're used with. The j:tag:insert_string procedure inserts text into a text widget with all the tags in the current tag list (and no others). Typically, if you're working with tagged text, you'll want all text inserted into a text widget to be inserted by j:tag:insert_string (or by j:text:insert_string, which is smart enough to call j:tag:insert_string when appropriate), so that the current tag list is applied to newly inserted text.

Metainformation

This library allows you to associate arbitrary metainformation with a text widget. This can be anything: the author's name, preferred paper stock, general comments, etc. This metainformation is in the form of a list of key-value pairs; metainformation is created, stored, and retrieved by key. It is not an error to try to retrieve the value of a nonexistent key; the empty string is returned.

(The procedures in jtagconvert.tcl may make use of some of this information if available; for instance, when converting to HTML, the body_background attribute, if it exists, is used to specify a background image.)

Text Annotation

Some of the procedures in this library work with the non­textual material stored in a text widget: tags and marks. Collectively, I call this information the tag widget's annotation.

The annotation of a text is stored as a list with two sublists. The first sublist ([lindex annotation 0]) represents the tags, and the second represents the marks.

The list of tags consists of a further two­element sublist for each active tag in the widget. The first element of each tag sublist is the tag name, and the second element is a list containing the beginning and ending indices of each range. The list of marks consists of additional two­element sublists for each mark; the first element of each sublist is the mark name, and the second is its index.

Here's an example annotation, reformatted for clarity:
{
{
{
richtext:font:italic {1.10 1.14}
} {
sel {1.0 2.0}
}
} {
{insert 1.22}
{current 1.0}
}
}
In this example, the 11th through 14th characters of the first line are tagged richtext:font:italic, the entire first line is selected, the insertion point is before the 23d character on the first line, and the mouse (which controls the current tag) is over the first character on the first line.

Although the most recent version of Tk supports embedding windows in text widgets (this is another form of annotation), this library doesn't support text widgets with embdded windows. If you try to use an annotation returned by j:tag:get_annotation for a text widget containing embedded windows, you'll find that the indices of tags and marks are likely to be incorrect.

File Format

The j:tag:archive_text_widget and j:tag:restore_text_widget procedures work with a file format for storing tagged text. This format is simply a Tcl list whose first element is the textual content of the widget, whose second element is the annotation (as described above under Text Annotation), and whose third element is the metainformation (as described above under Metainformation).

For instance, the annotation described above is from a text widget archived as the following (slightly reformatted):
{This is a very simple test.
}
{{{richtext:font:italic {1.10 1.14}} {sel {1.0 2.0}}}
{{insert 1.22} {current 1.0}}}
The word `very' is tagged italic, and the insertion point is before the word `test'.

Overview

Procedures

j:tag:insert_string - insert tagged text into text widget at insert point
j:tag:move - move to a particular position, setting current tag list appropriately
j:tag:set_tags - set tags to use when inserting new text
j:tag:clear_tags - clear tag list for inserting new text
j:tag:set_tag - add a tag to current tag list, overriding any conflicting tag
j:tag:tag_text - apply tag to text, overriding any conflicting tag
j:tag:untag_text - remove tags matching pattern from text range
j:tag:configure_display_tags - configure display tags to display properly
j:tag:configure_fonts - configure standard fonts per user's preferences
j:tag:get_annotation - return non-text content (tags and marks) of text widget
j:tag:set_annotation - set non-text content (tags and marks) of a text widget
j:tag:get_metainfo - get metainformation for a widget, as list or a single value
j:tag:set_metainfo - set the value for a particular metainformation key
j:tag:delete_metainfo - delete a particular metainformation key and its value
j:tag:archive_text_widget - save text widget to file, including state
j:tag:restore_text_widget - read text widget from file, including state

See Also

jtext.tcl
jrichtext.tcl, especially j:rt:textfonts
jfileio.tcl

j:tag:insert_string

Usage

j:tag:insert_string w text

Arguments

w is the text widget to insert into
text is the text to insert

Example

see j:tag:set_tags

Description

This procedure inserts text into w at w's insertion point, tagged with all the tags in the current tag list, and no others.

(This procedure is used by j:text:insert in jtext.tcl if there's a tag list defined.)

j:tag:move

Usage

j:tag:move w index

Arguments

w is the text widget to move in
index is the new position to move to

Description

This procedure sets w's insertion point to index, and sets the current tag list (applied to text inserted at the new position) based on the current tags of the characters next to index. Any tags shared by the character at index (after the insertion point) and the character just before index will be added to the current tag list (with a couple of special­purpose exceptions). Font and display tags (tags whose names begin with richtext:) are inherited from the character before index (unless index is the beginning of the text widget, in which case they are inherited from the character at index).

The upshot of this is that if you have an blue italicised word and you click at the end of it (after the last italicised character) and type, you'll be typing in blue italics. If you click at the beginning you won't.

If the word has some other kind of tag (say a hypertext link), that tag will be applied to newly­typed text if you click in the middle of the word (between two characters that both have it), but not if you click at either end.

j:tag:set_tags

Usage

j:tag:set_tags w tag...

Arguments

t is the text widget whose tag list you're setting
tag... is one or more tags to set the tag list to

Example

text .t
pack .t
j:tag:set_tags .t display:foreground:red display:font:12x24
j:tag:insert_string .t "This is large red text.\n"
j:tag:set_tags .t display:background:yellow
j:tag:insert_string .t \
"This is plain text on a yellow background.\n"
j:tag:configure_display_tags .t

Description

This procedure sets the current tag list for text widget t to to a list containing tag... . Any text later inserted into t with j:tag:insert_string will be tagged with the tags specified (and only those tags). (The tag arguments should be in the category:attribute:value format described above under Using Tags.)

It's more usual (at least in my code :-) to use j:tag:set_tag (with no s on the end) to work with the tag list. That lets you set or change a particular attribute without having to keep track of everything that's in the tag list.

Any display tags in tag... will be configured properly in the same fashion as by j:tag:configure_display_tags.

j:tag:clear_tags

Usage

j:tag:clear_tags t

Arguments

t is the text widget whose tag list you're clearing

Description

This procedure clears the tag list completely for t. This is different from setting it to an empty list, which you can do by calling `j:tag:set_tags t' with no tag arguments. If you're using jtext.tcl to insert text, setting the tag list to an empty list means that newly inserted text won't have any tags at all, whereas clearing the tag list will restore the normal Tk behaviour in which newly inserted text inherits tags from the character to its left (under Tk 3).

j:tag:set_tag

Usage

j:tag:set_tag t tag

Arguments

t is the text widget whose tag list you're setting
tag is a tag to add to the current tag list

Description

This procedure adds tag to the current tag list for text widget t, replacing any incompatible tag, i.e., a tag with the same category and attribute, but leaving any other tags in the tag list. (The tag argument should be in the category:attribute:value format described above under Using Tags.)

New text later inserted with j:tag:insert_string will be tagged with tag, as well as any other (compatible) tags in the tag list.

If tag is a display tag, it will be configured properly in the same fashion as by j:tag:configure_display_tags.

j:tag:clear_tag

Usage

j:tag:clear_tag t pattern

Arguments

t is the text widget whose tag list you want to affect
pattern is a pattern selecting tags you want to remove from the tag list

Description

This procedure removes any tags matching pattern from the tag list, so new text inserted with j:tag:insert_string won't receive them. pattern is a matching pattern in the format used by Tcl's string match command, such as `display:background:*' or `*:link:*' (or, of course, simply `sel' or `richtext:font:bold').

Typically, pattern will only match one tag in the tag list; it's a pattern rather than a simple string so that code using j:tag:clear_tag doesn't need to know exactly what tags are in the current tag list if it just wants to stop applying, for instance, a display:background:... tag. However, you can match more than one tag; saying `j:tag:clear_tag .text *' will remove all tags from .text's tag list.

j:tag:tag_text

Usage

j:tag:tag_text t tag first last

Arguments

t is the text widget where you want to tag text
tag is a tag to be added to the text range
first is the index of the first character to be tagged
last is the index after the last character to be tagged

Description

This procedure applies tag to the range of text from from to to in text widget t, removing any incompatible tag, i.e., a tag with the same category and attribute as tag, but leaving any other tags that may be applied to the text. (The tag argument should be in the category:attribute:value format described above under Using Tags.)

This procedure does not affect the current tag list, so it won't affect text later inserted with j:tag:insert_string.

j:tag:untag_text

Usage

j:tag:untag_text t pattern first last

Arguments

t is the text widget with the text you want to un­tag
pattern is a pattern selecting tags you want to remove from the text
first is the index of the first character to be un­tagged
last is the index after the last character to be un­tagged

Description

This procedure is used to selectively remove tags from a range of text. It removes any tags that match pattern from the range of text in t from first (inclusive) to last (exclusive). See j:text:clear_tag for details about pattern.

You can remove all tags from a range of text by specifying `*' for pattern.

j:tag:configure_display_tags

Usage

j:tag:configure_display_tags t

Argument

t is the text widget whose display tags you want to configure

Example

see j:tag:set_tags

See Also

j:tag:configure_fonts
j:rt:textfonts in jrichtext.tcl

Description

For all the current display tags in t (i.e., tags of the form display:attribute:value), this procedure configures the tag so it's appearance matches the tag name. The actual command executed for each display tag is
catch {
t tag configure display:attribute:value -attribute value
}
t tag lower display:attribute:value
Display tags are maintained properly by the other procedures in this library, so you should only need to call this procedure explicitly after manipulating tags with explicit widget commands.

j:tag:configure_fonts

Usage

j:tag:configure_fonts t

Argument

t is the text widget whose font tags you want to configure

Example

see j:tag:set_tags

See Also

j:tag:configure_display_tags
j:rt:textfonts in jrichtext.tcl

Description

This procedure sets rich­text font tags for text widget t according to the user's font preferences (as set on the jstools Global Preferences panel). It should be called whenever you will be displaying rich text in a text widget.

The correspondence between styles (some of which are HTML­style logical styles) and font preferences is as follows:
{roman screen_roman_font}
{italic screen_italic_font}
{bold screen_bold_font}
{bolditalic screen_bolditalic_font}
{typewriter screen_monospace_font}
{heading0 screen_heading0_font}
{heading1 screen_heading1_font}
{heading2 screen_heading2_font}
{heading3 screen_heading3_font}
{heading4 screen_heading4_font}
{heading5 screen_heading5_font}
{l_em screen_italic_font}
{l_cite screen_italic_font}
{l_var screen_italic_font}
{l_dfn screen_italic_font}
{l_strong screen_bold_font}
{l_kbd screen_bold_font}
{l_code screen_monospace_font}
{l_samp screen_monospace_font}
where the actual tag is richtext:font:style and the font is taken from the value of $J_PREFS(preference).

j:tag:get_annotation

Usage

j:tag:get_annotation t

Arguments

t is the text widget whose state you need

Description

This procedure returns information about the current annotation of text widget t, describing all the active tags and marks in it, in the format described above under Text Annotation. It's used by j:tag:archive_text_widget, and you can also use it to squirrel away the state of a text widget temporarily.

j:tag:set_annotation

Usage

j:tag:set_annotation t annotation

Arguments

t is the text widget whose state you want to change
annotation contains the tags and marks to apply to t

Description

This procedure restores the tags and marks in annotation to the text in text widget t. All tags and marks in annotation will be restored to their original locations. It then calls j:tag:configure_display_tags to make sure display tags appear correct, and makes sure the new insertion point is visible.

Since the locations of tags and marks are stored as absolute indices, it probably won't be useful to call j:tag:set_annotation when the text in a text widget is different from what it was when the annotation was stored.

See Text Annotation for a description of the format of annotation.

j:tag:get_metainfo

Usage

j:tag:get_metainfo t [key] [options]

Arguments

t is the text widget the metainformation is associated with
key, if given, is the particular key whose value you want

Options

-default default (default {})

Examples

set status [j:tag:get_metainfo $w.t status]
if [string match Urgent $status] {
$w.msg configure -text Urgent -foreground red
} else {
$w.msg configure -text $status -foreground black
}

# following will not change the title if it exists,
# but will set it to Untitled otherwise:
j:tag:set_metainfo $t title \
[j:tag:get_metainfo $t title -default Untitled]

Description

If key is given, this procedure will return the value corresponding to key in the metainformation associated with text widget t. If key does not occur in t's metainformation (i.e. it hasn't been given a value yet), it returns default if specified, or the empty string.

If key is not given, the procedure returns a list containing all the currently­defined metainformation for t; this list contains two­element sublists, where the first element of each sublist is a key, and the second element is the corresponding value.

j:tag:set_metainfo

Usage

j:tag:set_metainfo t key value

Arguments

t is the text widget the metainformation is to be associated with
key is the particular key whose value you're setting
value is the value for that key

Description

This procedure sets the value of a piece of metainformation associated with text widget t. The element indexed by key is set to value.

j:tag:delete_metainfo

Usage

j:tag:delete_metainfo t key

Arguments

t is the text widget the metainformation is associated with
key is the particular key whose value you're deleting

Description

This procedure removes the piece of text widget t's metainformation indexed by key. Both the key and the value are deleted.

j:tag:archive_text_widget

Usage

j:tag:archive_text_widget t filename

Arguments

t is the text widget to write
filename is the name of the file to write it to

Description

This procedure saves the contents of text widget t, including all active tags and marks, into filename. (It will generate an error if filename can't be written.) It doesn't save information about the current configuration of tags in the widget, but it does save their names and positions.

The file format saved by j:tag:archive_text_widget is a two­element Tcl list whose first element is the textual contents of the widget and whose second element is the annotation (tags and marks) of the widget, in the form returned by j:tag:get_annotation.

A text widget saved by this procedure can be restored with j:tag:restore_text_widget, although tag configurations will have to be set explicitly.

Limitations Under Tk 4

Under Tk 4.0 or greater, this procedure should not be used on text widgets with embedded windows, because (1) information about the windows won't be saved, and (2) because the windows take up a character position, but no character corresponds to them, they will cause the positioning of tags to be inaccurate when the text widget's contents are restored.

j:tag:restore_text_widget

Usage

j:tag:restore_text_widget t filename

Arguments

t is the text widget to read
filename is the name of the file to read it from

Description

This procedure reads the contents of a text widget saved with j:tag:archive_text_widget from file filename into text widget t. Text annotation, including marks and tags, is restored along with the textual contents.

Tag configurations (the appearance and command bindings of tags) is only restored for display tags (i.e., tags of the format display:option:value). If you want other tags to be distinguished visually, you need to configure them yourself. In particular, if you've used the jrichtext.tcl library to create multi­font text, you'll need to use its j:rt:textfonts procedure to configure the font tags properly.

Note that the sel tag, which corresponds to the selection, and the insert mark, which corresponds to the insertion point, are restored by this procedure. If you don't want the restored text to have the selection and the insertion point where they were when the widget was archived, you should explicitly clear the selection and set the insertion point after restoring the widget.

Bugs and Misfeatures

Future Directions