📄 tabkey.jm
字号:
# tabkey.jm: a full-featured tab key script for epic4## written by nsx## this script features:## * target history cycling for /msg and /notice# * match possibility cycling (zsh-style completion)# * reverse cycling (ctrl + r)# * shell-like completion for /exec# * script name completion for /load# * the ability to complete words anywhere in the input line# * proper handling of file names that contain spaces# * multi-server support# * completion of aliases, command names, channel names, nicknames,# /set variables, /help topics and file names### /set variables this script uses:## NICK_COMPLETION_CHAR -- the value of this set will be appended each time# nickname completion occurs as the first word of the# input line. a typical value might be ':'.## TAB_HISTORY_CYCLE_SIZE -- how many nicknames to keep in the /msg history## ZSH_STYLE_COMPLETION -- turning this on allows you to cycle through completion# possibilities, when there is more than one completion# possibility, similar to how zsh behaves for tab# completion### note: this script uses the serial number 110 for its serial hooks## *** config variables ***@nick_completion_char = []@tab_history_cycle_size = 10@zsh_style_completion = [off]# *** global variables ***@last_input_line = []@match_index = -1@match_cycle_list = []@target_index = 0@target_cycle_list = []bind ^I parse_command do_tabkey 1bind ^R parse_command do_tabkey -1xdebug +extractwalias add_target (msg_cmd, target) { if (numwords($myservers()) > 1 && count(: $target) == 0 && left(1 $target) != [=]) { @:target = [${servernum()}:${target}] } @target_cycle_list = remw("$msg_cmd $target" $target_cycle_list) if (#target_cycle_list > ((tab_history_cycle_size * 2) -1)) { @target_cycle_list = restw(2 $target_cycle_list) } @target_index = 0 @push(target_cycle_list $msg_cmd) @push(target_cycle_list $target)}alias current_fragment_start { @:i = 0 @:j = curpos() - 1 @:last_space = 0 @:last_quote = 0 @:quotes = 0 while (i < j) { @:char = mid($i 1 $L) if (char == [ ]) { @:last_space = i } elsif (char == ["]) { @:last_quote = i @:quotes++ } @:i++ } if (quotes % 2) { if (mid($curpos() 1 $L) == ["] || last_quote > last_space) { return ${last_quote + 1} } elsif (mid(${curpos() - 1} 1 $L) == ["]) { parsekey backward_character return ${last_quote + 1} } else { return ${last_space + 1} } } else { if (mid(${curpos() - 1} 1 $L) == [ ]) { return $curpos() } elsif (last_space) { return ${last_space + 1} } else { return 0 } }}alias do_match_cycle (direction) { @:frag_start = current_fragment_start() if (frag_start == -1) { return } @:fraglen = curpos() - frag_start if (mid($curpos() 1 $L) == ["]) { parsekey forward_character repeat ${fraglen + 1} parsekey backspace } elsif (mid(${curpos() - 1} 1 $L) == ["]) { repeat ${fraglen + 1} parsekey backspace } else { repeat $fraglen parsekey backspace } if (mid(${curpos() - 1} 1 $L) == ["]) { parsekey backspace } @match_index += direction if (match_index == #match_cycle_list) { @match_index = 0 } elsif (match_index < 0) { @match_index = #match_cycle_list - 1 } @:new_match = word($match_index $match_cycle_list) if (index("$chr(32)" $new_match) == -1) { xtype -l $new_match } else { xtype -l "$new_match" parsekey backward_character } @last_input_line = L}alias do_msg_cycle (direction) { if (#target_cycle_list < 2) { return } @target_index -= (direction * 2) if (target_index == #target_cycle_list) { @target_index = 0 } elsif (target_index < 0) { @target_index = #target_cycle_list - 2 } @:msg_cmd = word($target_index $target_cycle_list) @:msg_targ = word(${target_index + 1} $target_cycle_list) parsekey erase_line xtype -l /${msg_cmd} ${msg_targ}${chr(32)} @last_input_line = []}alias do_set (variable, value) { if (value == []) { ^eval @:setval = $variable if (setval == []) { xecho -b No value for $variable has been set } else { xecho -b Current value of $variable is $setval } return } switch ($variable) { (NICK_COMPLETION_CHAR) { if (value == [<unset>]) { @nick_completion_char = [] xecho -b Value of NICK_COMPLETION_CHAR set to <EMPTY> } else { @nick_completion_char = value xecho -b Value of NICK_COMPLETION_CHAR set to $value } } (TAB_HISTORY_CYCLE_SIZE) { if (!isnumber($value)) { xecho -b Value of TAB_HISTORY_CYCLE_SIZE must be numeric! } elsif (value < 1) { xecho -b Value of TAB_HISTORY_CYCLE_SIZE cannot be less than 1 } else { @tab_history_cycle_size = value @target_cycle_list = rightw(${value * 2} $target_cycle_list) xecho -b Value of TAB_HISTORY_CYCLE_SIZE set to $value } } (ZSH_STYLE_COMPLETION) { if (value == [on]) { @zsh_style_completion = [ON] xecho -b Value of ZSH_STYLE_COMPLETION set to ON } elsif (value == [off]) { @zsh_style_completion = [OFF] xecho -b Value of ZSH_STYLE_COMPLETION set to OFF } else { xecho -b Value of ZSH_STYLE_COMPLETION must be ON or OFF! } } (*) { xecho -b I don't know how to handle "$variable" } }}alias do_tabkey (cycle_direction) { @:input_line = left($curpos() $L) if (L == []) { @target_index = #target_cycle_list @do_msg_cycle($cycle_direction) return } elsif (encode($L) == encode($last_input_line)) { if (zsh_style_completion == [ON] && #match_cycle_list > 1) { @do_match_cycle($cycle_direction) return } else { return } } elsif (leftw(1 $L) == [/msg] || leftw(1 $L) == [/notice]) { if (#L == 2 && mid(${@L - 1} 1 $L) == [ ]) { @do_msg_cycle($cycle_direction) return } } @:frag_start = current_fragment_start() if (frag_start == -1 || cycle_direction == -1) { return } @:fragment = mid($frag_start ${curpos() - frag_start} $L) @:fraglen = strlen($fragment) @:padding = [] switch ($input_line) { (/dcc %) { @:matches = match_dcc($fragment) if (#matches == 1) { @:padding = [ ] } } (/dcc send % *) (/exec % *) { @:matches = match_file($fragment) if (#matches == 1 && !isdirectory($matches)) { @:padding = [ ] } } (/exec %) { @:matches = match_exec($fragment) if (#matches == 1 && !isdirectory($matches)) { @:padding = [ ] } } (/help %) { @:matches = match_help($fragment) if (#matches == 1) { if (!isdirectory(${getset(HELP_PATH)}/${matches})) { @:padding = [ ] } } } (/load *) (/unload *) { @:matches = match_load($fragment) if (#matches == 1 && !isdirectory($matches)) { @:padding = [ ] } } (/notify -%) { @:fragment = rest($fragment) @:fraglen-- @:matches = match_notify($fragment) if (#matches == 1) { @:padding = [ ] } } (/set -%) { @:fragment = rest($fragment) @:fraglen-- @:matches = match_set($fragment) if (#matches == 1) { @:padding = [ ] } } (/set %) { @:matches = match_set($fragment) if (#matches == 1) { @:padding = [ ] } } (/%) { @:fragment = rest($fragment) @:fraglen-- @:matches = match_command($fragment) if (#matches == 1) { @:padding = [ ] } } (*) { @:matches = [] @push(matches $match_chan($fragment)) @push(matches $match_nick($fragment)) if (#matches == 1) { if (#L == 1 && !ischannel($matches)) { if (nick_completion_char != []) { @:padding = [$nick_completion_char ] } } else { @:padding = [ ] } } } } @last_input_line = L @match_index = -1 @:match_prefix = prefix($matches) if (@match_prefix <= fraglen && #matches > 1) { xecho -c Possible matches: xecho -c -- $matches xecho -c return } if (match_prefix != []) { @:new_fragment = left($fraglen $match_prefix) if (encode($fragment) != encode($new_fragment)) { repeat $fraglen parsekey backspace xtype -l $new_fragment } } @:completion = rest($fraglen $match_prefix) if (completion == [] && padding == []) { return } if (index("$chr(32)" $fragment) == -1) { if (index("$chr(32)" $match_prefix) > -1) { repeat $fraglen parsekey backspace if (mid($curpos() 1 $L) == ["] && mid(${curpos() - 1} 1 $L) == ["]) { xtype -l $match_prefix if (padding != []) { parsekey forward_character } } else { xtype -l "$match_prefix" if (padding == []) { parsekey backward_character } } } else { xtype -l $completion } } else { xtype -l $completion if (padding == []) { if (mid($curpos() 1 $L) != ["]) { xtype -l " parsekey backward_character } } else { if (mid($curpos() 1 $L) == ["]) { parsekey forward_character } else { xtype -l " } } } if (mid(${curpos()} 1 $L) != padding) { xtype -l $padding } @last_input_line = []}alias isdirectory (pathname) { @:statret = stat("$pathname") @:file_type = left(1 $word(2 $statret)) if (file_type & 4) { return 1 } else { return 0 }}alias isexe (pathname) { @:statret = stat("$pathname") @:file_mode = word(2 $statret) @:file_type = left(1 $file_mode) @:permissions = right(3 $file_mode) @:user_perm = left(1 $permissions) @:group_perm = mid(1 1 $permissions) @:other_perm = right(1 $permissions) if (file_type == 1) { if ((user_perm & 1) || (group_perm & 1) || (other_perm & 1)) { return 1 } else { return 0 } } else { return 0 }}alias match_chan (fragment) { @:matches = pattern("${fragment}*" $mychannels()) @match_cycle_list = matches return $matches}alias match_command (fragment) { @:matches = [] @:command_matches = [] @push(matches $getcommands(${fragment}*)) @push(matches $aliasctl(alias pmatch ${fragment}*)) fe ($matches) match { @push(command_matches /${match}) } @match_cycle_list = uniq($command_matches) return $uniq($matches)}alias match_dcc (fragment) { @:dcc_cmds = [chat close closeall get list raw rename resume send] @:matches = pattern(${fragment}% $dcc_cmds) @match_cycle_list = matches return $matches}alias match_exec (fragment) { @:matches = [] if (index(/ $fragment) == -1) { @:path_list = PATH while (path_list != []) { @:pathname = before(: $path_list) if (pathname == []) { @:pathname = path_list @:path_list = [] } else { @:path_list = after(: $path_list) } fe ($glob("${pathname}/${fragment}*")) filename { if (isexe($filename)) { @push(matches $after(-1 / $filename)) } } } fe ($glob("${fragment}*")) filename { if (isdirectory($filename)) { @push(matches $filename) } } } else { fe ($glob("${fragment}*")) filename { if (isexe($filename) || isdirectory($filename)) { @push(matches $filename) } } } @match_cycle_list = matches = uniq($matches) return $matches}alias match_file (fragment) { @:matches = glob("${fragment}*") @match_cycle_list = matches return $matches}alias match_help (fragment) { @:matches = [] @:help_path = getset(HELP_PATH) @:help_matches = globi("${help_path}/${fragment}*") fe ($help_matches) match { @push(matches $rest(${@help_path + 1} $match)) } @match_cycle_list = matches return $matches}alias match_load (fragment) { @:matches = [] if (index(/ $fragment) == -1) { @:path_list = LOAD_PATH while (path_list != []) { @:pathname = before(: $path_list) if (pathname == []) { @:pathname = path_list @:path_list = [] } else { @:path_list = after(: $path_list) } fe ($glob("${pathname}/${fragment}*")) filename { @push(matches $after(-1 / $filename)) } } } @push(matches $glob("${fragment}*")) @match_cycle_list = matches = uniq($matches) return $matches} alias match_nick (fragment) { @:nick_matches = pattern("${fragment}*" $onchannel()) if (nick_matches == []) { @:nick_list = [] fe ($remw($C $mychannels())) chan { @push(nick_list $onchannel($chan)) } @push(nick_list $notify(on)) @:nick_matches = pattern(${fragment}* $nick_list) } if (nick_completion_char != [] && #matches > 1 && #L == 1) { fe ($nick_matches) nickname { @push(matches ${nickname}${nick_completion_char}) } } else { @:matches = nick_matches } @:matches = uniq($matches) @match_cycle_list = matches return $matches}alias match_notify (fragment) { @:matches = pattern(${fragment}* $notify()) @match_cycle_list = matches return $matches}alias match_set (fragment) { @:matches = [] @:my_sets = [NICK_COMPLETION_CHAR TAB_HISTORY_CYCLE_SIZE ZSH_STYLE_COMPLETION] @push(matches $getsets(${fragment}*)) @push(matches $pattern(${fragment}* $my_sets)) @match_cycle_list = matches return $matches}alias match_theme (fragment) { @:matches = [] @:theme_matches = globi("${theme_directory}/${fragment}*.theme") fe ($theme_matches) match { @push(matches $before(-1 . $rest(${@theme_directory + 1} $match))) } @match_cycle_list = matches return $matches}alias tclear { @target_cycle_list = [] @target_index = -2 xecho target history cleared }# *** hooks ***on #^action 110 "*" { if (!rmatch($1 #* &* +*) ) { @add_target(msg $0) }}on #^dcc_chat 110 "*" { @add_target(msg =$0)}on #^dcc_connect 110 "% CHAT *" { @add_target(msg =$0)}on #^general_notice 110 "% *" { @add_target(notice $1)}on #^msg 110 "*" { @add_target(msg $0)}on #^send_action 110 "*" { if (!rmatch($0 #* &* +*) ) { @add_target(msg $0) }}on #^send_dcc_chat 110 "*" { @add_target(msg =$0)}on #^send_msg 110 "*" { @add_target(msg $0)}on #^send_notice 110 "*" { @add_target(notice $0)}on ?send_to_server "% % NOTICE %:% *" { if (ischannel($3)) { return 0 } @:refnum = before(: $3) @:target = after(: $3) xquote -server $refnum NOTICE $target $4- return 1}on ?send_to_server "% % PRIVMSG %:% *" { if (ischannel($3)) { return 0 } @:refnum = before(: $3) @:target = after(: $3) xquote -server $refnum PRIVMSG $target $4- return 1}on ^set "NICK_COMPLETION_CHAR *" { @do_set(NICK_COMPLETION_CHAR $1)}on ^set "TAB_HISTORY_CYCLE_SIZE *" { @do_set(TAB_HISTORY_CYCLE_SIZE $1)}on ^set "ZSH_STYLE_COMPLETION *" { @do_set(ZSH_STYLE_COMPLETION $1)}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -