[Tkabber-dev] r70 - throwaway/ctcomp2

tkabber-svn at jabber.ru tkabber-svn at jabber.ru
Sat Oct 6 05:33:17 MSD 2007


Author: kostix
Date: 2007-10-06 05:33:16 +0400 (Sat, 06 Oct 2007)
New Revision: 70

Added:
   throwaway/ctcomp2/README
Modified:
   throwaway/ctcomp2/ctcomp.tcl
Log:
ctcomp.tcl:
 * Searching for completions is now also performed in the input window itself.
 * Completion menu is implemented.
 * Misc fixes.

README: added extensive readme file -- documented everything but the hooks.

TODO: tasks updated.


Added: throwaway/ctcomp2/README
===================================================================
--- throwaway/ctcomp2/README	                        (rev 0)
+++ throwaway/ctcomp2/README	2007-10-06 01:33:16 UTC (rev 70)
@@ -0,0 +1,230 @@
+$Id$
+"Chat text completions" -- chat plugin for Tkabber.
+
+I. The idea
+
+This plugin adds support for "text completion" in Tkabber's chat
+input windows, i.e. it's possible to make Tkabber offer you
+possible completions of a current partially typed word in a chat
+input window. Possible completions are looked up in both the
+input window and the chat log window (also it's possible to
+provide custom list of matches, see the "Customization"
+section).
+
+This feature is loosely modelled after the text completion
+implementations found in Vim [1] and Emacs [2] text editors;
+default text completion key bindings of this plugin are the same
+as default key bindings for this feature in those editors (see
+the "Using" section).
+
+Note though, that while both Vim and Emacs offer you possible
+completions in a "recently typed -- first" manner, this
+plugin offers them in a dictionary-sorted order.
+
+
+II. Using
+
+At first, note that we'll use "Emacsish" notation of describing
+keystrokes for the sake of brevity. For those who isn't familiar
+with it here's a quick explanation:
+* "C" stands for "Control" key (also known as "Ctrl").
+* "M" stands for "Meta" key (also known as "Alt" on some
+  computers/OSes).
+* Any other key symbols stand for themselves.
+* Key combinations (groups of keys that are required to be
+  pressed simultaneously) are specified as a list of appropriate
+  key symbols joined by dashes ("-"). For example, "C-M-a"
+  stands for Control, Meta (Alt) and "a" keys pressed
+  simultaneously.
+
+There are two major modes of operation possible:
+* Requesting menu with possible completions.
+* Traversing the list of possible completions "in place".
+
+Entering each mode is requested by pressing one of the available
+keystrokes (discussed below) just after the first character(s)
+of a word you want to complete.
+For example, suppose the current chat log window and/or the
+current input window contain these words: abba, abbot,
+abbatisse. Now suppose you have just typed "ab" and want to
+complete it -- type C-M-/ to get the menu listing top 20 words
+starting from "ab" found in mentioned windows or type C-n to
+enter the "in place" mode and get the first proposed completion
+right at your insert cursor (with the completed part visually
+emphasized). Any completion mode can be cancelled -- you return
+to that piece of the word you started with.
+The completion keybindings will be described just in a moment.
+
+So, let's recap:
+* Type some first letters of the word you want to complete,
+* Engage one of the available completion modes.
+* Pick the required completion or chancel the completion mode.
+
+1. Using the completion menu
+
+The menu presenting the first 20 completions can be by default
+posted using C-M-/ (Ctrl-Alt-/). Select whatever completion
+you're happy with or cancel the menu by clicking outside of it
+or pressing the <Escape> key. If you have selected a completion,
+the word being completed in the input window will be replaced by
+the selected completion. If you have cancelled the completion
+menu no change will be made to the input window.
+
+Also the first 9 entries in the completion menu have keyboard
+accelerators: 1 through 9, so while the menu is posted you can
+press keys "1" through "9" to activate the corresponding menu
+entry.
+
+This gesture is modelled after the Emacs text editor.
+
+2. Using the "in place" traversing of possible completions
+
+This mode is modelled after the similar Vim text editor's
+facility and so the C-n and C-p keystrokes are used, they switch
+the input windows into the "completion mode" and insert the
+first or the last completion from the list of proposed
+completions at the insert cursor. The completed part of the
+inserted word is highlighted.
+
+While being in the completion mode you can:
+* Continue using the C-n and C-p keystrokes to iterate through
+  the list of proposed completions.
+* Hit the Return (Enter) key to accept the currently displayed
+  completion and return to the normal editing mode.
+* Hit the <Espace> key to remove the currently displayed
+  completion and return to the normal mode. In other words this
+  cancels the completon mode.
+
+Hitting any other key not listed above (i.e. a key which doesn't
+have special meaning in the completion mode) accepts the
+currently displayed completion, returns the input window to the
+normal mode, and then this keystroke is passed to the input
+window so that if it would result in a printable character being
+inserted this character will be inserted just after the
+completed word.
+
+
+III. Customization
+
+1. Keystrokes
+
+All the relevant bindings in Tkabber's chat input windows are
+done via Tk virtual events [3] so they are easily customizable.
+Here are these events and their default bindings:
+
+* Event: <<ChatTextCompNext>>
+  Default bindings: <Control-n>, <Alt-slash>, <Meta-slash>
+  Action: show next possible completion "in place",
+  activate the "in place" completion mode beforehang,
+  if currently in the normal mode.
+
+* Event: <<ChatTextCompPrev>>
+  Default bindings: <Control-p>
+  Action: same as above but shows the previous possible
+  completion.
+
+* Event: <<ChatTextCompAccept>>
+  Default keybindings: <Return>
+  Action: accept the completion currently proposed "in place"
+  and return to normal mode.
+
+* Event: <<ChatTextCompCancel>>
+  Default keybindings: <Escape>
+  Action: remove the completion currently proposed "in place"
+  and return to normal mode.
+
+* Event: <<ChatTextCompMenu>>
+  Default keybindings: <Alt-Control-slash>, <Meta-Control-slash>
+  Action: show menu with possible completions.
+
+
+If you're not familiar with Tk [event] [3] and [bind] [4]
+commands, here's a quick reference:
+
+* To bind your keystroke to a virtual event use
+  event add <<...event name...>> <...keystroke spec...>
+  For example, to bind posting of the completion menu to the F5
+  key, put this in the Tkabber's config file:
+  event add <<ChatTextCompMenu>> <F5>
+
+* To unbind existing binding from a virtual event use
+  event delete <<...event name...>> <...keystroke spec...>
+  For example to make the completion menu only be posted by the
+  F5 key, add also this lines to the config file:
+  event delete <<ChatTextCompMenu>> <Alt-Control-slash>
+  event delete <<ChatTextCompMenu>> <Meta-Control-slash>
+
+* To "substitute" (all) the default bindings for a virtual event
+  by yours you can use something like this:
+  event delete <<ChatTextCompMenu>>
+  event add <<ChatTextCompMenu>> <F5>
+  The first line kills all bindings for the virtual event, the
+  second adds one new.
+
+Be sure to read and understand [3] and [4] before proceeding!
+
+Specification of keystrokes is explained in [4], all keysyms
+known to Tk are listed in [5].
+
+
+2. Highlighting colors of "in place" completion
+
+Two Tk option database resources are used, both are of class
+"Chat":
+
+* Resource: Chat.textCompletionForeground
+  Default: black
+  Meaning: foreground color of the "proposed" tail of the word
+  being completed "in place".
+
+* Resourec: Chat.textCompletionBackground
+  Default: pink
+  Meaning: same as above but for the background color.
+
+
+3. Search pattern
+
+The search pattern used to search for possible completions in Tk
+Text widgets is available via the
+::plugins::ctcomp::options(pattern) setting.
+
+This is an ARE [6] pattern containing the "%s" token which is
+replaced before searching by the part of the word being
+completed. This pattern makes the searching engine to look for
+"any word starting with the specified letters".
+
+Note that you should think twice before changing this pattern:
+for example the "in place" completion mode assumes that
+completions start from the prefix being completed and if you,
+say, change the pattern so that it will match in a middle of
+words, you'll get unexpected results in this completion mode.
+
+
+IV. Limitations and bugs
+
+No "automatic" completion ("propose completions as I type" found
+in certain text editing tools like Writer from the OpenOffice.org
+suite or some mobile phones) is not possible.
+
+The same holds for the "in place" completion mode: typing a
+regular keystroke terminates the completion mode, not narrows
+the list of possible completions (this is Vim-like).
+
+No guarantees of proper work are made if the user fiddles with
+the searching regexp pattern.
+
+Not all completions will be shown in the completion menu if its
+number exceeds the hard-coded limit.
+
+
+V. Links
+
+1. http://vim.sf.net
+2. http://www.gnu.org/software/emacs/
+3. http://www.tcl.tk/man/tcl8.4/TkCmd/event.htm
+4. http://www.tcl.tk/man/tcl8.4/TkCmd/bind.htm
+5. http://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm
+6. http://www.tcl.tk/man/tcl8.4/TclCmd/re_syntax.htm
+
+
+# vim:tw=64:noet


Property changes on: throwaway/ctcomp2/README
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: throwaway/ctcomp2/ctcomp.tcl
===================================================================
--- throwaway/ctcomp2/ctcomp.tcl	2007-10-05 01:12:00 UTC (rev 69)
+++ throwaway/ctcomp2/ctcomp.tcl	2007-10-06 01:33:16 UTC (rev 70)
@@ -8,59 +8,69 @@
 option add *Chat.textCompletionBackground    pink    widgetDefault
 
 namespace eval ctcomp {
-	variable options
+    variable options
 
-	set options(pattern) {\m%s\w+\M}
+    set options(pattern) {\m%s\w+\M}
 
-	event add <<ChatTextCompNext>>    <Control-n>
-	event add <<ChatTextCompNext>>    <Alt-slash>
-	event add <<ChatTextCompNext>>    <Meta-slash>
-	event add <<ChatTextCompPrev>>    <Control-p>
-	event add <<ChatTextCompAccept>>  <Return>
-	event add <<ChatTextCompCancel>>  <Escape>
+    event add <<ChatTextCompNext>>    <Control-n>
+    event add <<ChatTextCompNext>>    <Alt-slash>
+    event add <<ChatTextCompNext>>    <Meta-slash>
+    event add <<ChatTextCompPrev>>    <Control-p>
+    event add <<ChatTextCompAccept>>  <Return>
+    event add <<ChatTextCompCancel>>  <Escape>
+    event add <<ChatTextCompMenu>>    <Alt-Control-slash>
+    event add <<ChatTextCompMenu>>    <Meta-Control-slash>
 
-	bind ChatTextCompInactive <<ChatTextCompNext>> [namespace code {
-		if {[matches in %W]} {
-			hook::run chat_text_completion_start_hook
-			activate %W
-			match first next in %W
-		}
-		break
-	}]
-	bind ChatTextCompInactive <<ChatTextCompPrev>> [namespace code {
-		if {[matches in %W]} {
-			hook::run chat_text_completion_start_hook
-			activate %W
-			match first prev in %W
-		}
-		break
-	}]
+    bind ChatTextCompInactive <<ChatTextCompNext>> [namespace code {
+	if {[matches in %W]} {
+	    hook::run chat_text_completion_start_hook
+	    activate %W
+	    match first next in %W
+	}
+	break
+    }]
+    bind ChatTextCompInactive <<ChatTextCompPrev>> [namespace code {
+	if {[matches in %W]} {
+	    hook::run chat_text_completion_start_hook
+	    activate %W
+	    match first prev in %W
+	}
+	break
+    }]
+    bind ChatTextCompInactive <<ChatTextCompMenu>> [namespace code {
+	if {[matches in %W]} {
+	    hook::run chat_text_completion_menu_hook
+	    show_matches in %W
+	    reset_state %W
+	}
+	break
+    }]
 
-	bind ChatTextCompActive <<ChatTextCompNext>> [namespace code {
-		match next next in %W
-		break
-	}]
-	bind ChatTextCompActive <<ChatTextCompPrev>> [namespace code {
-		match next prev in %W
-		break
-	}]
-	bind ChatTextCompActive <<ChatTextCompAccept>> [namespace code {
-		accept %W
-		deactivate %W
-		hook::run chat_text_completion_end_hook
-		break
-	}]
-	bind ChatTextCompActive <<ChatTextCompCancel>> [namespace code {
-		cancel %W
-		deactivate %W
-		hook::run chat_text_completion_end_hook
-		break
-	}]
-	bind ChatTextCompActive <Key> [namespace code {
-		accept %W
-		deactivate %W
-		hook::run chat_text_completion_end_hook
-	}]
+    bind ChatTextCompActive <<ChatTextCompNext>>   [namespace code {
+	match next next in %W
+	break
+    }]
+    bind ChatTextCompActive <<ChatTextCompPrev>>   [namespace code {
+	match next prev in %W
+	break
+    }]
+    bind ChatTextCompActive <<ChatTextCompAccept>> [namespace code {
+	accept %W
+	deactivate %W
+	hook::run chat_text_completion_end_hook
+	break
+    }]
+    bind ChatTextCompActive <<ChatTextCompCancel>> [namespace code {
+	cancel %W
+	deactivate %W
+	hook::run chat_text_completion_end_hook
+	break
+    }]
+    bind ChatTextCompActive <Key> [namespace code {
+	accept %W
+	deactivate %W
+	hook::run chat_text_completion_end_hook
+    }]
 }
 
 #### Glue code: TODO remove in production:
@@ -84,225 +94,261 @@
 #### Real code:
 
 proc ctcomp::initialize iw {
-	set btags [bindtags $iw]
-	set ix [lsearch -exact $btags $iw]
-	bindtags $iw [linsert $btags $ix ChatTextCompInactive]
+    set btags [bindtags $iw]
+    set ix [lsearch -exact $btags $iw]
+    bindtags $iw [linsert $btags $ix ChatTextCompInactive]
 
-	reset_state $iw
+    reset_state $iw
 }
 
 proc ctcomp::activate iw {
-	set btags [bindtags $iw]
-	set ix [lsearch -exact $btags ChatTextCompInactive]
-	bindtags $iw [lreplace $btags $ix $ix ChatTextCompActive]
+    set btags [bindtags $iw]
+    set ix [lsearch -exact $btags ChatTextCompInactive]
+    bindtags $iw [lreplace $btags $ix $ix ChatTextCompActive]
 }
 
 proc ctcomp::deactivate iw {
-	set btags [bindtags $iw]
-	set ix [lsearch -exact $btags ChatTextCompActive]
-	bindtags $iw [lreplace $btags $ix $ix ChatTextCompInactive]
+    set btags [bindtags $iw]
+    set ix [lsearch -exact $btags ChatTextCompActive]
+    bindtags $iw [lreplace $btags $ix $ix ChatTextCompInactive]
 
-	reset_state $iw
+    reset_state $iw
 }
 
 proc ctcomp::prepare {chatid type} {
-	variable options
+    variable options
 
-	set iw [chat::input_win $chatid]
-	set cw [chat::chat_win $chatid]
+    set iw [chat::input_win $chatid]
+    set cw [chat::chat_win $chatid]
 
-	variable $iw
-	upvar 0 $iw state
-	set state(chatid) $chatid
+    variable $iw
+    upvar 0 $iw state
+    set state(chatid) $chatid
 
-	initialize $iw
+    initialize $iw
 
-	# Kind of destructor for per-chat state:
-	bind $iw <Destroy> +[list [namespace current]::cleanup $iw %W]
+    bind $iw <Destroy> +[list [namespace current]::cleanup $iw %W]
 }
 
 proc ctcomp::cleanup {w1 w2} {
-	if {![string equal $w1 $w2]} return
+    if {![string equal $w1 $w2]} return
 
-	variable $w1
-	unset $w1
+    variable $w1
+    unset $w1
 }
 
 proc ctcomp::reset_state iw {
-	variable $iw
-	upvar 0 $iw state
+    variable $iw
+    upvar 0 $iw state
 
-	set state(active) 0
-	set state(matches) [list]
-	set state(last) ""
-	set state(what) ""
+    set state(matches) [list]
+    set state(last)    ""
+    set state(what)    ""
 }
 
 proc ctcomp::accept iw {
-	$iw tag remove ctcomp/submatch comp_start comp_end
-	$iw mark unset comp_start
-	$iw mark unset comp_end
+    $iw tag remove ctcomp/submatch comp_start comp_end
+    $iw mark unset comp_start
+    $iw mark unset comp_end
 }
 
 proc ctcomp::cancel iw {
-	$iw delete comp_start comp_end
-	$iw mark unset comp_start
-	$iw mark unset comp_end
+    $iw delete comp_start comp_end
+    $iw mark unset comp_start
+    $iw mark unset comp_end
 }
 
 proc ctcomp::pattern what {
-	variable options
+    variable options
 
-	format $options(pattern) [string map {
-		\\  \\\\
-		[   \\[
-		\{  \\\{
-		(   \\(
-		$   \\$
-		.   \\.
-		*   \\*
-		?   \\?
-	} $what]
+    format $options(pattern) [string map {
+	\\  \\\\
+	[   \\[
+	\{  \\\{
+	(   \\(
+	$   \\$
+	.   \\.
+	*   \\*
+	?   \\?
+    } $what]
 }
 
 proc ctcomp::matches {"in" iw} {
-	variable $iw
-	upvar 0 $iw state
-	upvar 0 state(chatid)  chatid
-	upvar 0 state(what)    what
-	upvar 0 state(matches) matches
-	upvar 0 state(last)    last
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(what)    what
+    upvar 0 state(matches) matches
 
-	set what [word from $iw]
-	if {[string length $what] == 0} { return false }
+    set what [word from $iw]
+    if {[string length $what] == 0} { return false }
 
-	set matches [get_matches for $what in $iw]
-	if {[llength $matches] == 0} {
-		show info $iw "No match for $what"
-		return false
-	}
+    set matches [get_matches for $what in $iw]
+    if {[llength $matches] == 0} {
+	show info $iw "No match for $what"
+	return false
+    }
 
-	return true
+    return true
 }
 
 proc ctcomp::word {"from" t} {
-	set from [tk::TextPrevPos $t insert tcl_startOfPreviousWord]
-	$t get $from insert
+    set from [tk::TextPrevPos $t insert tcl_startOfPreviousWord]
+    $t get $from insert
 }
 
 proc ctcomp::get_matches {"for" what "in" iw} {
-	variable $iw
-	upvar 0 $iw state
-	upvar 0 state(chatid) chatid
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(chatid) chatid
 
-	foreach item [hook::run chat_text_completion_complete_hook $chatid $what] {
-		set seen($item) {}
-	}
+    lsort -dictionary -unique [concat \
+	[hook::run chat_text_completion_complete_hook $chatid $what] \
+	[get_text_matches for $what in [chat::chat_win $chatid]] \
+	[get_text_matches for $what in $iw]]
+}
 
-	set t [chat::chat_win $chatid]
-	set pos 1.0
+proc ctcomp::get_text_matches {"for" what "in" t} {
+    set pos 1.0
+    set matches [list]
 
-	while 1 {
-		set at [$t search -count len -regexp [pattern $what] $pos end]
-		if {$at == {}} break
+    while 1 {
+	set at [$t search -count len -regexp [pattern $what] $pos end]
+	if {$at == {}} break
 
-		set match [$t get $at "$at + $len chars"]
-		set seen($match) {}
+	lappend matches [$t get $at "$at + $len chars"]
 
-		set pos [$t index "$at + 1 char"]
-	}
+	set pos [$t index "$at + 1 char"]
+    }
 
-	lsort -dictionary [array names seen]
+    set matches
 }
 
 proc ctcomp::last L {
-	expr {[llength $L] - 1}
+    expr {[llength $L] - 1}
 }
 
 proc ctcomp::getopt {iw opt} {
-	variable $iw
-	upvar 0 $iw state
+    variable $iw
+    upvar 0 $iw state
 
-	option get [chat::winid $state(chatid)] $opt Chat
+    option get [chat::winid $state(chatid)] $opt Chat
 }
 
 proc ctcomp::match {seq dir "in" iw} {
-	variable $iw
-	upvar 0 $iw state
-	upvar 0 state(what)    what
-	upvar 0 state(matches) matches
-	upvar 0 state(last)    last
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(what)    what
+    upvar 0 state(matches) matches
+    upvar 0 state(last)    last
 
-	switch -- $seq {
-		first {
-			switch -- $dir {
-				next { set last 0 }
-				prev { set last [last $matches] }
-			}
-			$iw mark set comp_start insert
-			$iw mark gravity comp_start left
-		}
-		next {
-			advance to $dir in $iw
-			$iw delete comp_start comp_end
-		}
+    switch -- $seq {
+	first {
+	    switch -- $dir {
+		next { set last 0 }
+		prev { set last [last $matches] }
+	    }
+	    $iw mark set comp_start insert
+	    $iw mark gravity comp_start left
 	}
+	next {
+	    advance to $dir in $iw
+	    $iw delete comp_start comp_end
+	}
+    }
 
-	set match [lindex $matches $last]
-	set submatch [string range $match [string length $what] end]
+    set match [lindex $matches $last]
+    set submatch [string range $match [string length $what] end]
 
-	$iw tag configure ctcomp/submatch \
-		-foreground [getopt $iw textCompletionForeground] \
-		-background [getopt $iw textCompletionBackground]
+    $iw tag configure ctcomp/submatch \
+	-foreground [getopt $iw textCompletionForeground] \
+	-background [getopt $iw textCompletionBackground]
 
-	$iw insert comp_start $submatch ctcomp/submatch
-	$iw mark set comp_end insert
-	$iw mark gravity comp_end right
+    $iw insert comp_start $submatch ctcomp/submatch
+    $iw mark set comp_end insert
+    $iw mark gravity comp_end right
 }
 
 proc ctcomp::advance {"to" where "in" iw} {
-	variable $iw
-	upvar 0 $iw state
-	upvar 0 state(last)    last
-	upvar 0 state(matches) matches
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(last)    last
+    upvar 0 state(matches) matches
 
-	set end [last $matches]
+    set end [last $matches]
 
-	switch -- $where {
-		next {
-			incr last
-			if {$last > $end} {
-				set last 0
-				wraparound in $iw
-			}
-		}
-		prev {
-			incr last -1
-			if {$last < 0} {
-				set last $end
-				wraparound in $iw
-			}
-		}
-		default {
-			return -code error "Bad match \"$match\":\
-				should be next or prev"
-		}
+    switch -- $where {
+	next {
+	    incr last
+	    if {$last > $end} {
+		set last 0
+		wraparound in $iw
+	    }
 	}
+	prev {
+	    incr last -1
+	    if {$last < 0} {
+		set last $end
+		wraparound in $iw
+	    }
+	}
+    }
 }
 
 proc ctcomp::wraparound {"in" iw} {
-	show info $iw "Wrapped around"
+    show info $iw "Wrapped around"
 }
 
+proc ctcomp::show_matches {"in" iw} {
+    set m $iw.matches
+    if {![winfo exists $m]} {
+	menu $iw.matches -tearoff no -postcommand [list \
+	    [namespace current]::repopulate_matches_menu $iw $m]
+    }
+
+    # TODO change to lassign:
+    foreach {x y} [lrange [$iw bbox insert] 0 1] {
+	set x [expr {[winfo rootx $iw] + $x}]
+	set y [expr {[winfo rooty $iw] + $y}]
+    }
+    tk_popup $m $x $y 0
+}
+
+proc ctcomp::repopulate_matches_menu {iw m} {
+    variable $iw
+    upvar 0 $iw state
+
+    $m delete 0 end
+
+    set i 0
+    foreach match $state(matches) {
+	if {[incr i] > 20} break
+	$m add command -label "$i. $match" -command [list \
+	    [namespace current]::menu_insert_match $iw $match]
+	if {$i < 10} {
+	    $m entryconfigure end -underline 0
+	}
+    }
+}
+
+
+proc ctcomp::menu_insert_match {iw match} {
+    variable $iw
+    upvar 0 $iw state
+
+    $iw insert insert \
+	[string range $match [string length $state(what)] end]
+}
+
 # $type should be either "info" or "error"
-proc ctcomp::show {type token msg} {
-	variable $token
-	upvar 0 ${token}(chatid) chatid
+proc ctcomp::show {type iw msg} {
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(chatid) chatid
 
-	set jid [chat::get_jid $chatid]
-	set cw [chat::chat_win $chatid]
+    set jid [chat::get_jid $chatid]
+    set cw [chat::chat_win $chatid]
 
-	chat::add_message $chatid $jid $type $msg {}
+    chat::add_message $chatid $jid $type $msg {}
 }
 
 #### Action:
@@ -323,25 +369,30 @@
 grid columnconfigure .f 0 -weight 1
 
 if {[string equal $tcl_platform(platform) windows]} {
-	console eval { wm protocol . WM_DELETE_WINDOW exit }
-	console show
+    console eval { wm protocol . WM_DELETE_WINDOW exit }
+    console show
 }
 
 foreach line [split [string trim {
-	abbot
-	abbatisse
-	abba
-	foo
-	foobar
-	foobargrill
-	grill
-	grille pitch
-	$environmental
-	[delete quux]
-	????
+    abbot
+    abbatisse
+    abba
+    foo
+    foobar
+    foobargrill
+    fooyey
+    grill
+    grille pitch
+    fogrill
+    _grill_
+    grill?
+    $environmental
+    [delete quux]
+    ????
 }] \n] {
-	.f.cw insert end [string trim $line]\n
+    .f.cw insert end [string trim $line]\n
 }
+.f.cw see end
 
 .f.cw tag config info -foreground blue
 .f.cw tag config error -foreground red
@@ -353,3 +404,4 @@
 
 focus -force .f.iw
 
+# vim:ts=8:sw=4:sts=4:noet



More information about the Tkabber-dev mailing list