Balancing Open and Close Quotes in a Gnocl Text Widget

WJG (04/11/07) Here's the gnocl::text equivalent. Those who already use gnocl may be aware that the current release has no text bindings for either the widget or tags. I use a development version which has the appropriate bindings. For those who are interested, before the next official release occurs, send me an email and I can forward details.

# gncolBalanceQuotes.tcl
# William J Giddings
# 04/11/07
# Enable context sensitive quotations.
# If the input quote mark is preceded by a printable character,
# then closequote otherwise openquote!
# Notes:
# This is not "smart" and so does attempt to balance quote marks.
# The swap is made on the KeyRelease event so the swap will only
# effect the final quote if a key repeat event occurs.

#!/bin/sh \
exec tclsh  "$0" "$@"

package require Gnocl     ;# Tcl-Gtk+ bindings

# w    text widget into which the substition is to be made
# c    character currently inserted
# Codes:
#        single openquote        `   \u2018
#        closequote                  '   \u2019
#        double openquote           "   \u201C
#        closequote                  "   \u201D
#        '        quoteright
#        "   quotedbl

proc balanceQuotes {w c} {
    # get the character before the quotation mark, if any 
    set str [ $w get cursor-1 cursor-2 ]
    if {$str == "" || [string is space $str] || $str == "\u2018" || $str == "\u201C" } { set str " "  }

    # if the last code entered was '
    if {$c == "quoteright" } {
                $w erase cursor cursor-1
                if { [string is space $str] } {
                        $w insert cursor "\u2018"        ;# openquote
                } else  {
                        $w insert cursor "\u2019"        ;# closequote

    # or, if was "
    if {$c == "quotedbl" } {
                $w erase cursor cursor-1
                if {[string is space $str]} {
                        $w insert cursor "\u201C"        ;# openquote
                } else  {
                        $w insert cursor "\u201D"        ;# closequote


# Demo
set txt [gnocl::text -baseFont {Sans 25} \
        -onKeyRelease {balanceQuotes %w %K}]
gnocl::window -title BalanceQuotes \
        -child $txt \
        -onDestroy exit \
        -width 250

FF 2008-07-19 - I tried running that demo, bt I encountered some errors:

 bad option "-baseFont": must be -scrollbar, -pixelsInsideWrap, -pixelsBelowLines, -pixelsAboveLines, -editable,
      -wrapMode, -justify, -leftMargin, -rightMargin, -indent, -cursorVisible, -hasFocus, -tooltip, -onShowHelp,
      -name, -visible, or -sensitive


 bad option "-onKeyRelease": must be -scrollbar, -pixelsInsideWrap, -pixelsBelowLines, -pixelsAboveLines, -editable,
      -wrapMode, -justify, -leftMargin, -rightMargin, -indent, -cursorVisible, -hasFocus, -tooltip, -onShowHelp,
      -name, -visible, or -sensitive

my Gnocl version is 0.9.91, is not latest version?

WJG (20/07/08) Firstly, thanks for trying the script and I hope that you continue to explore the use of gnocl. The options that you list there are available on the next release of gnocl which I'm currently working on. In fact there a number of feature enhancements to the text widget including the inclusion of two additional tag commands "add" and "remove" and mouse event trapping with a new switch -onEvent. I'm planning to make a release of these changes plus some additional Gtk widgets not available at the moment (toggleButton, linkButton, scaleButton, volumeButton and hnadleBox) but, if you want a copy of the working version I'm currently using I'd be happy to email this to you, email:[email protected].

FF 2008-07-20 - I'm very happy to hear that Gnocl development is currently active! :-) I'd like to help for what I can. I obviously know Tcl, but also have a little knowledge of the C API. I started looking at Gnocl very recently; I'll report you my suggestions and my findings if you are interested. For now, what I'd like to change is:

  • make the programming syntax for gnocl as closest as possible to the tk one.
  • I found cget is missing for widgets

WJG (20/07/08) FF, I would be grateful for any contributions! As you mention, the aim is to produce an interface to the Gtk/Gnome using the Tcl style. There are some benefits, and tradeoffs in using Gnocl which simply arise from the Gtk widget set itself. The immediate difference is the lack of a equivalent to the Tk "bind" command. It is possible to replicate the command, though not necessarily desirable using a Tcl script package. Some of the terminology used in Gnocl relates to the Gtk options and commands and not those of Tk. I would not be advisable to try and tweak a Tk GUI in Gnocl, the packing of widgets in Gnocl, for instance, is different to that of Tk. It's better to star from scratch, which is not that so problematic in either Tk or Gnocl.

In terms of moving the whole package forward my time has been focussed on: i) getting to know my way around the source code (I'm still lost in many places), ii) implementing features that I personally needed and iii) produce some working developer documentation.

I'm pleased that you are glad to hear that Gnocl is not 'dead and buried'. In fact, I've just come back from the LugRadio Live 2008 conference/meet where I made a presentation on Gnocl bindings. Most people that I met there in fact thought that Tcl was 'dead and burried'. But then, I think that programmers tend to take a pride in the amount of code they write, the latest software fashion and and the more complicated it appears to other programmer's the greater the pride they take in themselves! I like simplicity and not complication for complication's sake.

I'll put my slides up on Google as soon as I can. The presentation was recorded but I don't know what the quality was like and whether or not it will be available on line.

Finally, you mentioned the "cget" command not working, Which widget(s) was this for? The command may not yet be consistently applied to all widgets.

FF 2008-07-20 - for example:

 % package require Gnocl
 % set t [gnocl::text]
 % $t configure -scrollbar yes
 % $t cget -scrollbar
 bad command "cget": must be delete, configure, scrollToPosition, erase, select, get, cut, copy, paste, getLength,
      setCursor, getCursor, insert, or tag

about the syntax, there are two main things:

  • bind (as opposed to -on<Event> {...})
  • geometry managers (i have no experience on Gtk+, but I see widgets are arranged using nested HBoxes and VBoxes, achieving a functionality similar to a table geometry manager (but more flexible perhaps)

but you are right, this is Gtk+, not Tk, so it not has to necessarily replicate all the Tk things. eventually, a third-party package, even written in pure-tcl, could implement that layer of compatibility. (although bind is nice to have :))

also: would be nice to name widgets (like happens in Tk), instead of picking up an automatically generated name. example:

 % gnocl::text .t -text "Hello"
 % .t configure ...

instead of:

 % gnocl::text -text "Hello"
 % ::gnocl::_WIDn configure ...

but this, again, blurs with what Tk and Gtk+ are. in Tk dot and hierarchy has a proper meaning. here just the name could make a bit of sense

WJG (20/07/08) Thanks for so many questions. Its good to see some real interest gathering in the project. Firstly, whenever a Gnocl widget is created, the calling function does return a 'serialized name' which, of course can effectively 'aliased'. For instance, if one has two text widgets in a container these could be given humanly meaningful names. For example:

 proc makeText {} {
   global SLTEXT ,TLTEXT
   set SLTEXT [gnocl::text...
   set TLTEXT [gnocl::text...

Which of course, is what is done in Tk. Although the script may specify a widget path, when that widget is successfully created, then the pathName is returned. I've not tried it myself, but perhaps you could try naming widgets in a Tk way, ie.

set . [gnocl::window... set .SLTEXT [gnocl::text... set .TLTEXT [gnocl::text...

However, why do this? The Gnocl knows which widget is what, paths are no longer necessary.

On the matter of 'bind' I have a package for that, well for the text widget at least. Here it is.... [L1 ]