File: completion.tcl

package info (click to toggle)
tkabber 0.9.7-5
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 4,756 kB
  • ctags: 1,593
  • sloc: tcl: 32,453; xml: 1,847; sh: 1,408; makefile: 72
file content (202 lines) | stat: -rw-r--r-- 5,634 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# $Id: completion.tcl,v 1.6 2003/11/06 21:19:26 aleksey Exp $

namespace eval completion {
    set options(prefix) ""
    set options(suffix) " "
    set options(nlprefix) ""
    set options(nlsuffix) ": "
}

proc completion::complete {chatid} {
    variable completion
    variable options
    variable comps {}
    global grouproster

    if {![info exists completion(state,$chatid)] || \
	    [cequal $completion(state,$chatid) normal]} {
	set completion(state,$chatid) completed
    }

    set iw [chat::input_win $chatid]

    if {$completion(state,$chatid) == "menu_next" && \
	    [$iw compare insert == compins]} {
	set word $completion(word,$chatid)

	hook::run generate_completions_hook \
	    $chatid [namespace current]::comps \
	        [clength [$iw get 1.0 compstart]] \
	        [$iw get 1.0 "end -1c"]
	set len [clength $word]
	set matches {}
	foreach comp $comps {
	    if {[string equal -nocase -length $len $word $comp]} {
		lappend matches $comp
	    }
	}
	set n [llength $matches]
	if {!$n} {return}
	set completion(idx,$chatid) [expr ($completion(idx,$chatid)+1) % $n]
	set comp [lindex $matches $completion(idx,$chatid)]

	$iw delete compstart compend
	$iw insert compstart $comp
	return
    } elseif {$completion(state,$chatid) == "menu_next"} {
	set completion(state,$chatid) completed
    }

    set ins [lindex [split [$iw index insert] .] 1]
    set line [$iw get "insert linestart" "insert lineend"]
    set lbefore [crange $line 0 [expr $ins - 1]]
    #set lafter [crange $line $ins end]
    regexp {(\S*)$} $lbefore temp word
    set wordstart [expr $ins - [clength $word]]

    #set word [$iw get "insert -1 chars wordstart" insert]
    debugmsg plugins "COMPLETION: $word"

    if {1 || $word != ""} {
	hook::run generate_completions_hook \
	    $chatid [namespace current]::comps \
	        [clength [$iw get 1.0 "insert linestart +$wordstart chars"]] \
	        [$iw get 1.0 "end -1c"]
	set len [clength $word]
	set matches {}
	foreach comp $comps {
	    if {[string equal -nocase -length $len $word $comp]} {
		lappend matches $comp
	    }
	}
	debugmsg plugins "COMPLETION: $matches"

	if {[llength [lrmdups $matches]] == 1 || \
		$completion(state,$chatid) == "menu_start"} {
	    set comp [lindex $matches 0]

	    $iw delete "insert linestart +$wordstart chars" insert
	    $iw insert insert $comp

	    if {$completion(state,$chatid) == "menu_start"} {
		set compstart $wordstart
		set compend [expr $compstart + [clength $comp]]
		$iw mark set compstart "insert linestart +$compstart chars"
		$iw mark gravity compstart left
		$iw mark set compend "insert linestart +$compend chars"
		$iw mark gravity compend right
		$iw mark set compins insert
		set completion(state,$chatid) menu_next
		set completion(word,$chatid) $word
		set completion(idx,$chatid) 0
	    }
	} elseif {[llength [lrmdups $matches]] > 1} {
	    set app ""
	    while {[set ch [same_char $matches $len]] != ""} {
		debugmsg plugins "COMPLETION APP: $len; $ch"
		append app $ch
		incr len
	    }
	    $iw insert insert $app
	    set completion(state,$chatid) menu_start
	}
    }
}

proc completion::same_char {strings pos} {
    if {![llength $strings]} {
	return ""
    }

    set strs [lassign $strings str1]
    set ch [string index $str1 $pos]

    foreach str $strs {
	if {![string equal -nocase $ch [string index $str $pos]]} {
	    return ""
	}
    }
    return $ch
}

proc completion::nick_comps {chatid compsvar wordstart line} {
    if {![chat::is_groupchat $chatid]} return

    variable options
    global grouproster
    upvar 0 $compsvar comps
    debugmsg plugins "COMPLETION N: $comps"

    if {!$wordstart} {
	set prefix $options(nlprefix)
	set suffix $options(nlsuffix)
    } else {
	set prefix $options(prefix)
	set suffix $options(suffix)
    }

    set nickcomps {}
    foreach jid $grouproster(users,$chatid) {
	lappend nickcomps $prefix[chat::get_nick $jid groupchat]$suffix
    }
    set nickcomps [lsort -dictionary -unique $nickcomps]
    set comps [concat $nickcomps $comps]
    debugmsg plugins "COMPLETION N: $comps"
}

hook::add generate_completions_hook \
    [namespace current]::completion::nick_comps 90

proc completion::sort_comps {chatid compsvar wordstart line} {
    upvar 0 $compsvar comps

    set comps [lsort -dictionary -unique $comps]

    debugmsg plugins "COMPLETION S: $comps"
}

hook::add generate_completions_hook \
    [namespace current]::completion::sort_comps 75

proc completion::delete_suffix {chatid} {
    variable completion
    variable options

    set iw [chat::input_win $chatid]

    if {![info exists completion(state,$chatid)]} return

    if {([cequal $completion(state,$chatid) menu_next] || \
	    [cequal $completion(state,$chatid) completed]) && \
	    [$iw compare insert == {end - 1 chars}]} {
	set ind [list insert - [string length $options(suffix)] chars]
	if {[cequal [$iw get $ind insert] $options(suffix)]} {
	    $iw delete $ind insert
	}
    }
    set completion(state,$chatid) normal
}

proc completion::setup_bindings {chatid type} {
    variable history

    set iw [chat::input_win $chatid]
    set cc CompCtl$iw

    set bt [bindtags $iw]
    set bt [lreplace $bt -1 -1 $cc]
    bindtags $iw $bt
    debugmsg plugins "COMPLETION TAGS: $bt"

    bind $cc <Key-Tab> \
	[list [namespace current]::complete [double% $chatid]]
    bind $cc <Key-Tab> +break
    bind $cc <Key-Return> [list [namespace current]::delete_suffix [double% $chatid]]
    bind $cc <KeyPress> \
	[list set \
	     [double% [namespace current]::completion(state,$chatid)] \
	     normal]
}

hook::add open_chat_post_hook [namespace current]::completion::setup_bindings