Version 45 of Ctext

Updated 2008-09-09 11:47:14 by SL

Documentation at [L1 ]

Ctext is

  • part of tklib.
  • a megawidget that is built upon the Tk text widget. It provides syntax highlighting, and can be used to highlight a variety of languages. It provides a simple API and more radical changes (other than color) can be made by modifying the tag attributes. By default matching pairs of characters are flashed on the screen, like the popular Emacs and Lisp editors can do.
  • licensed like Tcl (BSDish), but copyrighted

 What: custom text widget
 Where: http://tcllib.sf.net/ (within the tklib module)
 Description: Fast syntax highlighting text megawidget.
        Provides a way to control the highlighting colors for classes
        of keywords.  Latest version has electric braces/quotes/brackets
        and a new edit modified instance command.
        Has been tested with Tcl/Tk 8.3.2 and 8.4b1.
 Updated: 05/2004
 Contact: tklib maintainers

RLH - I just looked at the docs (which I somehow missed before). What a great widget!

AK: The docs were actually added last week, so you could not find them before.

KJN: Thanks for the docs. In case anyone else is looking, they were added to CVS on 2005-04-08, and are not yet in a released version of Tcllib. See the link at the top of the page for the HTML version.


TR: A real-life example using ctext and BWidget for interactive debugging and introspection is here: a debugger with syntax highlighting using ctext


MSH: 2006-05-05 I have just discovered a major drawback with Ctext. Using the linemap to display linenumbers all works OK till I change the size of the font used (I have highlighting using 4 fonts, normal, bold, italic and bolditalic). When the font increases (CTRL-Mousewheel), the numbers no longer line up !! After investigation I found that the -linespace font metrics is not identical for a given point size on all four fonts !!

I am working on a proc to adjust the sizes of the fonts individually to maintain a nominal linespacing UNLESS someone knows better ? ;-)

George Peter Staplin Unfortunately that's a known problem. The linemap wasn't designed for varying fonts, and different offsets for lines. I have some ideas relating to this, but they involve lots of redesign.


MSH: 2006-06-21 Me again, Font resizing is implemented but under linux the fixed fonts are reeealy ugly when scaled up. I have since discovered another problem, I have an application which uses two text widgets one for a help system with images and another with a fixed font line numbered ctext widget. I saw that the text widget of 8.5 does pixel scrolling with images so I repacked with 8.5a2 and the help is ok but now the fixed text can scroll by a few pixels and the line numbers no longer line up!! Is there any way to force the new text widget to only scroll by whole text lines? Or has someone found another way to update the numbers in ctext ?

George Peter Staplin I think a better approach would be to make ctext actually insert line numbers into the actual text widget, rather than having a separate widget for the linemap. If we then iterate the dump results we could extract the text, and trim these line numbers (perhaps with a special tag).


MB: 2006-07-27 I would like to use ctext but I am failing to figure out how to use the undo feature. This is my example :

 package require ctext
 ctext .t -undo 1
 pack .t
 .t insert 1.0 "This is a sentence."
 .t edit undo
 if {[.t edit modified]==1} then {
     puts "Ctext Failed"
 } else {
     puts "Ctext Pass"
 }
 destroy .t

With the current version of ctext (3.1), this prints out "Ctext Failed". Am I wrong or there is a bug in line 475 of ctext.tcl where the ar(modified) value is not updated even if a ".t edit undo" is called? This is the wrong version :

 return [uplevel 1 [linsert $args 0 $self._t $cmd]]

This is what I think fixes it:

 set result [uplevel 1 [linsert $args 0 $self._t $cmd]]
 set ar(modified) [$self._t edit modified]
 return $result

Am I wrong ?

George Peter Staplin You're probably not wrong. I don't use the undo feature very often. I may look into the problem, unless someone has already applied a patch to tklib/ctext.


Gong Ding: The edit modified command should be fixed like this:

                        if {"modified" == $subCmd} {
                                if {$argsLength == 1} {
                                        return $ar(modified)
                                } elseif {$argsLength == 2} {
                                        set value [lindex $args 1]
                                        set ar(modified) $value
                                        $self._t edit modified $value
                                } else {
                                        return -code error "invalid arg(s) to $self edit modified: $args"
                                }
                        }  else {
                                #Tk 8.4 has other edit subcommands that I don't want to emulate.
                                #return [uplevel 1 [linsert $args 0 $self._t $cmd]]
                                set result [uplevel 1 [linsert $args 0 $self._t $cmd]]
                                set ar(modified) [$self._t edit modified]
                                return $result
                        }

Paul Danielson: Almost. To get the <<Modified>> event notification to work properly, I had to add event generation to the instanceCmd. Here's a proc that fixes it for me in ctext 3.1:

    proc patchCtext {} {
      # fixes problem with modified notification in ctext widget v3.1

      if { [catch {package require -exact ctext 3.1}] } {
        return "patch only works for ctext 3.1"
      } 
      set b [info body ctext::instanceCmd]

      set pat1    {set ar\(modified\) \$value}
      set rep1    {set ar(modified) $value}
      append rep1 {\n$self._t edit modified $value}
      append rep1 {\nevent generate $self <<Modified>>}
      append rep1 {\nputs "instance 1: $value"}
      set rep1    [subst -novariables $rep1]
      set b1 [regsub $pat1 $b $rep1]

      set pat2    {return \[uplevel 1 \[linsert \$args 0 \$self._t \$cmd]]}
      set rep2    {set result [uplevel 1 [linsert $args 0 $self._t $cmd]]}
      append rep2 {\nset ar(modified) [$self._t edit modified]}
      append rep2 {\nevent generate $self <<Modified>>}
      append rep2 {\nputs "instance 2: $ar(modified)"}
      append rep2 {\nreturn $result}
      set rep2    [subst -nocommands -novariables $rep2]
      set b2 [regsub $pat2 $b1 $rep2]

      proc boo { self cmd args } $b2
      rename ::ctext::instanceCmd {}
      rename boo ::ctext::instanceCmd
    }