[Tkabber-dev] r71 - trunk/plugins/ctcomp

tkabber-svn at jabber.ru tkabber-svn at jabber.ru
Sun Oct 7 02:32:34 MSD 2007


Author: kostix
Date: 2007-10-07 02:32:33 +0400 (Sun, 07 Oct 2007)
New Revision: 71

Modified:
   trunk/plugins/ctcomp/AUTHORS
   trunk/plugins/ctcomp/ChangeLog
   trunk/plugins/ctcomp/INSTALL
   trunk/plugins/ctcomp/README
   trunk/plugins/ctcomp/TODO
   trunk/plugins/ctcomp/VERSION
   trunk/plugins/ctcomp/ctcomp.tcl
   trunk/plugins/ctcomp/license.terms
Log:
Integrated changes from "ctcomp2" hosted at svn.xmpp.ru/repos/tkabber-3rd-party/throwaway/ctcomp2

Several misc fixes and updates to documentation.

Plugin version bumped to 2.0.


Modified: trunk/plugins/ctcomp/AUTHORS
===================================================================
--- trunk/plugins/ctcomp/AUTHORS	2007-10-06 01:33:16 UTC (rev 70)
+++ trunk/plugins/ctcomp/AUTHORS	2007-10-06 22:32:33 UTC (rev 71)
@@ -1 +1 @@
-Konstantin Khomoutov <flatworm at users.sourceforge.com>
+Konstantin Khomoutov <flatworm at users.sourceforge.com>


Property changes on: trunk/plugins/ctcomp/AUTHORS
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/plugins/ctcomp/ChangeLog
===================================================================
--- trunk/plugins/ctcomp/ChangeLog	2007-10-06 01:33:16 UTC (rev 70)
+++ trunk/plugins/ctcomp/ChangeLog	2007-10-06 22:32:33 UTC (rev 71)
@@ -1,41 +1,48 @@
-2007-08-17  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
-
-	* Fixed bug in assigning handler to a chat window <Destroy>
-	  event. Now state cleanup works and the plugin don't error
-	  out when the user enters a chat with non-ASCII-clean JID.
-	  (Thanks Ruslan Rakhmanin for reporting).
-
-
-2007-02-25  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
-
-	* Fixed bug occured when chatting with JIDs containing
-	  the "%s" character.
-
-	* Stub ChangeLog file rewritten to reflect this project' state.
-
-
-2007-02-18  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
-
-	* Added support for Customize.
-
-	* Misc bugfixes.
-
-	* Added preliminary support for virtual events.
-
-	* Added preliminary support for event validity checking.
-
-	* Support for per-chat state.
-
-	* Matching algorythm reworked.
-
-	* Added keybindings for committing and cancelling the current match.
-
-	* Proper deinitialization of completion mode.
-
-	* Added files: AUTHORS, README, TODO, INSTALL, ChangeLog and license.terms
-
-
-2007-02-15  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
-
-	* Initial version.
-
+2007-10-04  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
+
+	* Heavily redone using bindtags and virtual events.
+
+	* Behaviour and keybindings are made more close to Vim/Emacs.
+
+	* Added possibility to show a menu with possible completions.
+
+	* Numerous bugfixes.
+
+	* README re-written.
+
+	* Now at version 2.0.
+
+
+2007-02-25  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
+
+	* Fixed bug occured when chatting with JIDs containing
+	  the "%s" character.
+
+	* Stub ChangeLog file rewritten to reflect this project' state.
+
+
+2007-02-18  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
+
+	* Added support for Customize.
+
+	* Misc bugfixes.
+
+	* Added preliminary support for virtual events.
+
+	* Added preliminary support for event validity checking.
+
+	* Support for per-chat state.
+
+	* Matching algorythm reworked.
+
+	* Added keybindings for committing and cancelling the current match.
+
+	* Proper deinitialization of completion mode.
+
+	* Added files: AUTHORS, README, TODO, INSTALL, ChangeLog and license.terms
+
+
+2007-02-15  Konstantin Khomoutov  <flatworm at users.sourceforge.net>
+
+	* Initial version.
+


Property changes on: trunk/plugins/ctcomp/ChangeLog
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/plugins/ctcomp/INSTALL
===================================================================
--- trunk/plugins/ctcomp/INSTALL	2007-10-06 01:33:16 UTC (rev 70)
+++ trunk/plugins/ctcomp/INSTALL	2007-10-06 22:32:33 UTC (rev 71)
@@ -1,10 +1,9 @@
-As usually, copy this directory under the ~/.tkabber/plugins directory
-so that you get a hierarchy like this:
-  ~/.tkabber/plugins
-  ~/.tkabber/plugins/ctcomp/
-  ~/.tkabber/plugins/ctcomp/ctcomp.tcl
-
-Restart Tkabber, to get the plugin loaded.
-Visit the "Customize->Plugins->Chat Text Completion" block of settings.
-Consult the README file for the details about using this plugin.
-
+As usually, copy this directory under the ~/.tkabber/plugins directory
+so that you get a hierarchy like this:
+  ~/.tkabber/plugins
+  ~/.tkabber/plugins/ctcomp/
+  ~/.tkabber/plugins/ctcomp/ctcomp.tcl
+
+Restart Tkabber, to get the plugin loaded.
+Consult the README file for the details about using this plugin.
+


Property changes on: trunk/plugins/ctcomp/INSTALL
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/plugins/ctcomp/README
===================================================================
--- trunk/plugins/ctcomp/README	2007-10-06 01:33:16 UTC (rev 70)
+++ trunk/plugins/ctcomp/README	2007-10-06 22:32:33 UTC (rev 71)
@@ -1,12 +1,313 @@
-"Chat Text Completion" plugin for Tkabber ("ctcomp").
-$Id$
-
-I. The idea.
-
-IV. References:
-
-1. http://www.tcl.tk/man/tcl8.4/TkCmd/event.htm
-2. http://www.tcl.tk/man/tcl8.4/TkLib/GetColor.htm
-3. http://www.tcl.tk/man/tcl8.4/TkCmd/colors.htm
-
-vim:et:ts=4:sw=4:tw=64
+$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 modeled 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.
+
+This gesture is modeled after the Emacs text editor.
+
+2. Using the "in place" traversing of possible completions
+
+This mode is modeled 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.
+
+
+4. Hooks
+
+This plugin has four "hooks" [7] that run when certain chat text
+completion events occur. They can be used to fine-tune the
+operation of this plugin. Beware though that using them requires
+some knowledge of Tcl.
+
+These hooks are:
+
+* chat_text_completion_start_hook
+  This hook is run when the plugin enters the "in place"
+  completion mode and is about to show the first proposed
+  completion.
+  Two arguments are appended to the hook script before
+  evaluation:
+  * handle to the chat in which the completion
+    mode is entered (usually referred to as "chatid").
+  * word being completed.
+
+  Primary intent of this hook (and its "mirror" hook
+  chat_text_completion_end_hook) is to be used to provide some
+  sort of additional visual hint to the user indicating active
+  "in place" completion mode.
+
+* chat_text_completion_end_hook
+  This hook is run when the plugin leaves the "in place"
+  completion mode.
+  One argument is appended to the hook script before
+  evaluation -- handle to the chat ("chatid").
+
+* chat_text_completion_matches_hook
+  This hook is run when the plugin builds a list of possible
+  completions for the word being completed, just after the
+  proposed completions have been gathered from the relevant
+  input and chat log windows.
+  Four arguments are appended to the hook script before
+  evaluation:
+  * handle to the chat in which the completion
+    mode is entered ("chatid").
+  * word being completed.
+  * stack level containing the variable with proposed
+    completions.
+  * name of the variable holding a list with proposed
+    completions.
+  To modify this variable inside a proc use the [upvar] command,
+  for example:
+
+  proc gencomp {chatid what level compsName} {
+    upvar $level $compsName comps
+	lappend comps ${what}not ${what}sup
+  }
+  hook::add chat_text_completion_matches_hook gencomp
+
+  Note that scripts handling this hook must not do any
+  assumptions about the list of proposed completions they
+  operate on (like sorted/unsorted, uniquennes of the words,
+  etc).
+
+  Also note that while any strings can be added to the list of
+  possible completions using this hook, the "in place"
+  completion mode assumes that each proposed completion starts
+  from the word being completed; when this assumption is not
+  honored, strange things may happen.
+
+* chat_text_completion_menu_hook
+  This hook is run just before the menu with proposed
+  completions is shown to the user.
+  Three arguments are appended to the hook script before
+  evaluation:
+  * handle to the chat in which the completion
+    mode is entered ("chatid").
+  * word being completed.
+  * name of the menu window populated with proposed completions.
+
+  This hook can be used to tweak the menu before it will be
+  popped up.
+
+
+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. The same is true for the case when
+the user modifies the list of proposed completion via the
+relevant hook.
+
+Not all completions will be shown in the completion menu if its
+number exceeds the hard-coded limit.
+
+Detecting of a word to be completed in the input window is
+somewhat strange, for example, if you have this string ("|"
+denotes the cursor position):
+so what ??|
+and try to complete, the string "what ??" will be used as the
+completion prefix.
+
+
+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
+7. http://tkabber.jabber.ru/files/doc/tkabber.html#s.extensibility
+
+
+# vim:tw=64:noet


Property changes on: trunk/plugins/ctcomp/README
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/plugins/ctcomp/TODO
===================================================================
--- trunk/plugins/ctcomp/TODO	2007-10-06 01:33:16 UTC (rev 70)
+++ trunk/plugins/ctcomp/TODO	2007-10-06 22:32:33 UTC (rev 71)
@@ -1,36 +1,10 @@
 $Id$
 
-HIGH:
+* Describe hooks in README.
 
-* Sanitize completion word before buldging regexp,
-  for example, this crashes the matching:
-  ::env(FOO<C-n here...>
+* Finding of a word being completed is a bit broken:
+  for the string "mumble ??_" with the cursor denoted by "_"
+  pressing C-n will yield "mumble ??" instead of "??" or "".
+  So probably something needs to be rethought/fine-tuned.
 
-* " and other characters like this must not be taken into account
-  when determining start boundary of a word being completed.
-
-* Think about behaviour on regular keypresses when the completion
-  is active; for example:
-  * cancel;
-  * narrow, otherwise cancel;
-  * narrow, otherwise re-match, don't cancel.
-
-* Simplify code.
-
-LOW:
-
-* Provide for customization of "completion text" look
-  via Tk option database.
-
-* Validate customize settings (regexp and bindings).
-
-* Introduce virtual events for suitable keybindings.
-
-* Extensive testing.
-
-* Fill README file.
-
-* Russian message catalog.
-
-* More comments in the code.
-
+# vim:tw=64:noet


Property changes on: trunk/plugins/ctcomp/TODO
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/plugins/ctcomp/VERSION
===================================================================
--- trunk/plugins/ctcomp/VERSION	2007-10-06 01:33:16 UTC (rev 70)
+++ trunk/plugins/ctcomp/VERSION	2007-10-06 22:32:33 UTC (rev 71)
@@ -1,2 +1,2 @@
-Version: 1.2
-Date: 17-Aug-2007
+Version: 2.0
+Date: 07-Oct-2007


Property changes on: trunk/plugins/ctcomp/VERSION
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/plugins/ctcomp/ctcomp.tcl
===================================================================
--- trunk/plugins/ctcomp/ctcomp.tcl	2007-10-06 01:33:16 UTC (rev 70)
+++ trunk/plugins/ctcomp/ctcomp.tcl	2007-10-06 22:32:33 UTC (rev 71)
@@ -1,355 +1,346 @@
 # $Id$
-# "ctcomp" Tkabber plugin -- "Chat text completion".
+# "Chat text completion -- Tkabber plugin.
 # Written by Konstantin Khomoutov <flatworm at users.sourceforge.net>
-# See "lisence.terms" for distribution details.
+# See "lisence.terms" for details about distribution.
 # Consult README for the information and usage guidelines.
 
+option add *Chat.textCompletionForeground    black   widgetDefault
+option add *Chat.textCompletionBackground    pink    widgetDefault
+
 namespace eval ctcomp {
-	variable options
+    variable options
 
-	package require msgcat
-	namespace import ::msgcat::mc*
+    set options(pattern) {\m%s\w+\M}
 
-	msgcat::mcload [file join [file dir [info script]] msgs]
+    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>
 
-	custom::defgroup Plugins [mc "Plugins options."] -group Tkabber
+    bind ChatTextCompInactive <<ChatTextCompNext>> [namespace code {
+	if {[matches in %W]} {
+	    activate %W
+	    match first next in %W
+	}
+	break
+    }]
+    bind ChatTextCompInactive <<ChatTextCompPrev>> [namespace code {
+	if {[matches in %W]} {
+	    activate %W
+	    match first prev in %W
+	}
+	break
+    }]
+    bind ChatTextCompInactive <<ChatTextCompMenu>> [namespace code {
+	if {[matches in %W]} {
+	    show_matches in %W
+	    reset_state %W
+	}
+	break
+    }]
 
-	set group {Chat Text Completion}
+    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
+	break
+    }]
+    bind ChatTextCompActive <<ChatTextCompCancel>> [namespace code {
+	cancel %W
+	deactivate %W
+	break
+    }]
+    bind ChatTextCompActive <Key> [namespace code {
+	accept %W
+	deactivate %W
+    }]
 
-	custom::defgroup $group \
-		[mc "Chat Text Completion provides for auto-completing\
-			words in chat input windows using matching words\
-			from their paired chat log windows."] \
-		-group Chat \
-		-group Plugins
+    hook::add open_chat_post_hook [namespace current]::prepare
+}
 
-	custom::defvar options(pattern) {\m%s\w*\M} \
-		[mc "Pattern to find words matching to the word being\
-			auto-completed. This is a regular expression.\
-			%s denotes the word being auto-completed."] \
-		-group $group \
-		-type string
+proc ctcomp::initialize iw {
+    set btags [bindtags $iw]
+    set ix [lsearch -exact $btags $iw]
+    bindtags $iw [linsert $btags $ix ChatTextCompInactive]
 
-	custom::defvar options(next_match) <Control-Key-n> \
-		[mc "Tk event in the chat input window which generates\
-			the next possible completion, firstly activating\
-			the completion mode if necessary."] \
-		-group $group \
-		-type string \
-		-command [namespace current]::on_event_spec_changed
+    reset_state $iw
+}
 
-	custom::defvar options(prev_match) <Control-Key-p> \
-		[mc "Tk event in the chat input window which generates\
-			previous possible completion, firstly activating\
-			the completion mode if necessary."] \
-		-group $group \
-		-type string \
-		-command [namespace current]::on_event_spec_changed
+proc ctcomp::activate iw {
+    variable $iw
+    upvar 0 $iw state
 
-	custom::defvar options(cancel_match) <Escape> \
-		[mc "Cancels active completion mode, removing any currently\
-			proposed completion."] \
-		-group $group \
-		-type string \
-		-command [namespace current]::on_event_spec_change
+    set btags [bindtags $iw]
+    set ix [lsearch -exact $btags ChatTextCompInactive]
+    bindtags $iw [lreplace $btags $ix $ix ChatTextCompActive]
 
-	custom::defvar options(space_cancels_completion) 0 \
-		[mc "Typing the space character while in completion mode\
-			cancels the completion mode and inserts the space\
-			character in the input buffer. The default behaviour\
-			is opposite: the current completion is committed."] \
-		-group $group \
-		-type boolean
+    hook::run chat_text_completion_start_hook $state(chatid) $state(what)
+}
 
-	unset group
+proc ctcomp::deactivate iw {
+    variable $iw
+    upvar 0 $iw state
 
-	event add <<ChatTextCompNext>>   $options(next_match)
-	event add <<ChatTextCompPrev>>   $options(prev_match)
-	event add <<ChatTextCompCancel>> $options(cancel_match)
-#	event add <<ChatTextCompCommit>> ?
-}
+    set btags [bindtags $iw]
+    set ix [lsearch -exact $btags ChatTextCompActive]
+    bindtags $iw [lreplace $btags $ix $ix ChatTextCompInactive]
 
+    hook::run chat_text_completion_end_hook $state(chatid)
 
+    reset_state $iw
+}
 
 proc ctcomp::prepare {chatid type} {
-	variable options
-	set token [namespace current]::state$chatid
-	variable $token
-	upvar 0 $token state
+    variable options
 
-	array set state [list chatid $chatid]
+    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
 
-	set btoken [string map {% %%} $token] ;# % is special in bindings
+    initialize $iw
 
-	bind $iw $options(next_match) \
-		[namespace code [list match next for $btoken]]
+    bind $iw <Destroy> +[list [namespace current]::cleanup $iw %W]
+}
 
-	bind $iw $options(prev_match) \
-		[namespace code [list match prev for $btoken]]
+proc ctcomp::cleanup {w1 w2} {
+    if {![string equal $w1 $w2]} return
 
-	bind $iw $options(cancel_match) \
-		[namespace code [list cancel $btoken]]
+    variable $w1
+    unset $w1
+}
 
-	set prev [bind $iw <Key>]
-	bind $iw <Key> \
-		[namespace code [list keypress_any $btoken]]
-	bind $iw <Key> \
-		+$prev
+proc ctcomp::reset_state iw {
+    variable $iw
+    upvar 0 $iw state
 
-	bind $iw <space> \
-		[namespace code [list keypress_space $btoken]]
+    set state(matches) [list]
+    set state(last)    ""
+    set state(what)    ""
+}
 
-	set prev [bind $iw <Return>]
-	bind $iw <Return> \
-		[namespace code [list keypress_return $btoken]]
-	bind $iw <Return> \
-		+$prev
+proc ctcomp::accept iw {
+    $iw tag remove ctcomp/submatch comp_start comp_end
+    $iw mark unset comp_start
+    $iw mark unset comp_end
+}
 
-	# Set initial state -- inactive:
-	reset_state $token
-
-	# Kind of destructor for per-chat state:
-	bind $iw <Destroy> \
-		+[namespace code [list array unset $btoken]]
-
-	$iw tag configure ctcomp/submatch -background pink
+proc ctcomp::cancel iw {
+    $iw delete comp_start comp_end
+    $iw mark unset comp_start
+    $iw mark unset comp_end
 }
 
-hook::add open_chat_post_hook \
-	[namespace current]::ctcomp::prepare 99
-
-
-
 proc ctcomp::pattern what {
-	variable options
-	format $options(pattern) $what
-}
+    variable options
 
-proc ctcomp::yield {"from" t} {
-	set from [tk::TextPrevPos $t insert tcl_startOfPreviousWord]
-	$t get $from insert
+    format $options(pattern) [string map {
+	\\  \\\\
+	[   \\[
+	]   \\]
+	\{  \\\{
+	\}  \\\}
+	(   \\(
+	)   \\)
+	$   \\$
+	.   \\.
+	*   \\*
+	?   \\?
+    } $what]
 }
 
-proc ctcomp::get_matches {"for" what "in" token} {
-	variable $token
-	upvar 0 $token state
+proc ctcomp::matches {"in" iw} {
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(what)    what
+    upvar 0 state(matches) matches
 
-	set t [chat::chat_win $state(chatid)]
-	set pos 1.0
+    set what [word from $iw]
+    if {[string length $what] == 0} { return false }
 
-	while 1 {
-		set at [$t search -count len -regexp [pattern $what] $pos end]
-		if {$at == {}} break
+    set matches [get_matches for $what in $iw]
+    if {[llength $matches] == 0} {
+	show info $iw "No match for $what"
+	return false
+    }
 
-		set match [$t get $at "$at + $len chars"]
-		set seen($match) {}
-
-		set pos [$t index "$at + 1 char"]
-	}
-
-	lsort -dictionary [array names seen]
+    return true
 }
 
-proc ctcomp::wraparound {"in" token} {
-	show info $token "Wrapped around"
+proc ctcomp::word {"from" t} {
+    set from [tk::TextPrevPos $t insert tcl_startOfPreviousWord]
+    $t get $from insert
 }
 
-proc ctcomp::advance {"to" where "in" token} {
-	variable $token
-	upvar 0 $token state
-	upvar 0 state(last) last
+proc ctcomp::get_matches {"for" what "in" iw} {
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(chatid) chatid
 
-	switch -- $where {
-		next {
-			incr last
-			if {$last > [llength $state(matches)]} {
-				set last 0
-				wraparound in $token
-			}
-		}
-		prev {
-			incr last -1
-			if {$last < 0} {
-				set last [expr {[llength $state(matches)] - 1}]
-				wraparound in $token
-			}
-		}
-		default {
-			error "bad match: $match; should be \"next\" or \"prev\""
-		}
-	}
-}
+    set completions [concat \
+	[get_text_matches for $what in [chat::chat_win $chatid]] \
+	[get_text_matches for $what in $iw]]
 
-proc ctcomp::match {where "for" token} {
-	variable $token
-	upvar 0 $token state
-	upvar 0 state(chatid)  chatid
-	upvar 0 state(what)    what
-	upvar 0 state(matches) matches
-	upvar 0 state(last)    last
+    hook::run chat_text_completion_matches_hook \
+	$chatid $what #[info level] completions
 
-	set iw [chat::input_win $chatid]
-	set cw [chat::chat_win  $chatid]
+    lsort -dictionary -unique $completions
+}
 
-	if {!$state(active)} {
-		set what [yield from $iw]
-		if {[string length $what] == 0} return
+proc ctcomp::get_text_matches {"for" what "in" t} {
+    set pos 1.0
+    set matches [list]
 
-		set state(matches) [get_matches for $what in $token]
-		if {[llength $matches] == 0} {
-			show info $token "No match for $what"
-			return
-		}
+    while 1 {
+	set at [$t search -count len -regexp [pattern $what] $pos end]
+	if {$at == {}} break
 
-		set last 0
-	} else {
-		advance to $where in $token
-	}
+	lappend matches [$t get $at "$at + $len chars"]
 
-	set match [lindex $matches $last]
-	set submatch [string range $match [string length $what] end]
+	set pos [$t index "$at + 1 char"]
+    }
 
-	if {$state(active)} {
-		$iw delete comp_start comp_end
-	} else {
-		$iw mark set comp_start insert
-		$iw mark gravity comp_start left
-	}
-	$iw insert comp_start $submatch ctcomp/submatch
-	$iw mark set comp_end insert
-	$iw mark gravity comp_end right
+    set matches
+}
 
-	set state(active) 1
-
-	return -code break ;# prevent further keypress processing
+proc ctcomp::last L {
+    expr {[llength $L] - 1}
 }
 
-proc ctcomp::cancel {token} {
-	variable $token
-	upvar 0 $token state
+proc ctcomp::getopt {iw opt} {
+    variable $iw
+    upvar 0 $iw state
 
-	if {!$state(active)} return
-
-	set iw [chat::input_win $state(chatid)]
-
-	$iw delete comp_start comp_end
-	$iw mark unset comp_start
-	$iw mark unset comp_end
-
-	reset_state $token
+    option get [chat::winid $state(chatid)] $opt Chat
 }
 
-proc ctcomp::reset_state {token} {
-	variable $token
-	upvar 0 $token state
-
-	set state(active) 0
-	set state(matches) {}
-	set state(last) ""
-	set state(what) ""
+proc ctcomp::tail {what match} {
+    string range $match [string length $what] end
 }
 
-proc ctcomp::commit token {
-	variable $token
-	upvar 0 $token state
-	
-	#if {!$state(active)} return
-	if {!$state(active)} { return -code continue }
+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
 
-	set iw [chat::input_win $state(chatid)]
+    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
+	}
+    }
 
-	$iw tag remove ctcomp/submatch comp_start comp_end
-	$iw mark unset comp_start
-	$iw mark unset comp_end
+    set submatch [tail $what [lindex $matches $last]]
 
-	reset_state $token
-}
+    $iw tag configure ctcomp/submatch \
+	-foreground [getopt $iw textCompletionForeground] \
+	-background [getopt $iw textCompletionBackground]
 
-proc ctcomp::keypress_any token {
-	variable $token
-	upvar 0 $token state
-	
-	if {!$state(active)} return
-
-	cancel $token
+    $iw insert comp_start $submatch ctcomp/submatch
+    $iw mark set comp_end insert
+    $iw mark gravity comp_end right
 }
 
-proc ctcomp::keypress_space token {
-	variable options
-	variable $token
-	upvar 0 $token state
-	
-	if {!$state(active)} return
+proc ctcomp::advance {"to" where "in" iw} {
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(last)    last
+    upvar 0 state(matches) matches
 
-	if {$options(space_cancels_completion)} {
-		cancel $token
-	} else {
-		commit $token
+    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
+	    }
+	}
+    }
 }
 
-proc ctcomp::keypress_return token {
-	variable $token
-	upvar 0 $token state
-	
-	if {!$state(active)} return
+proc ctcomp::wraparound {"in" iw} {
+    show info $iw "Wrapped around"
+}
 
-	commit $token
+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]
+    }
 
-	return -code break
+    lassign [lrange [$iw bbox insert] 0 1] x y
+    set x [expr {[winfo rootx $iw] + $x}]
+    set y [expr {[winfo rooty $iw] + $y}]
+    tk_popup $m $x $y 0
 }
 
-# $type should be either "info" or "error"
-proc ctcomp::show {type token msg} {
-	variable $token
-	upvar 0 ${token}(chatid) chatid
+proc ctcomp::repopulate_matches_menu {iw m} {
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(what) what
 
-	set jid [chat::get_jid $chatid]
-	set cw [chat::chat_win $chatid]
+    $m delete 0 end
 
-	chat::add_message $chatid $jid $type $msg {}
+    set i 0
+    foreach match $state(matches) {
+	if {[incr i] > 20} break
+	$m add command -label $match -command [list \
+	    [namespace current]::menu_insert_match $iw [tail $what $match]]
+    }
+
+    hook::run chat_text_completion_menu_hook $state(chatid) $state(what) $m
 }
 
-proc ctcomp::on_event_spec_changed {where what op} {
-	return
 
-	variable $where
-	upvar 0 ${where}($what) this
-	upvar 0 ${where}(prev_$what) prev
-	if {![info exists prev]} { set prev "" }
+proc ctcomp::menu_insert_match {iw tail} {
+    variable $iw
 
-	if {$this == $prev} return ;# no change
-
-	if {$this == ""} { # empty value => remove binding
-		event delete $event $prev
-		set prev ""
-		return
-	}
-
-	if {[is_valid_event_spec $this]} {
-		event delete $event $prev
-		event add $event $this
-		set prev $this
-	} else {
-		set this $prev
-	}
+    $iw insert insert $tail
 }
 
-proc ctcomp::is_valid_event_spec spec {
-	set f [frame .testframemustnotexist]
+# $type should be either "info" or "error"
+proc ctcomp::show {type iw msg} {
+    variable $iw
+    upvar 0 $iw state
+    upvar 0 state(chatid) chatid
 
-	set ok [catch {bind $f $spec bogus}]
+    set jid [chat::get_jid $chatid]
+    set cw [chat::chat_win $chatid]
 
-	if {!$ok} {
-		global errorInfo
-		set errorInfo [::msgcat::mc "...testing event valididy..."]
-		bgerror [::msgcat::mc "Bad event: $options(binding)"]
-	}
-
-	destroy $f
-	return $ok
+    chat::add_message $chatid $jid $type $msg {}
 }
 
+# vim:ts=8:sw=4:sts=4:noet


Property changes on: trunk/plugins/ctcomp/ctcomp.tcl
___________________________________________________________________
Name: svn:eol-style
   + native


Property changes on: trunk/plugins/ctcomp/license.terms
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Tkabber-dev mailing list