+Sun Feb 17 19:02:56 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Merged latest Irssi (0.8.1) from the irssi.org's CVS into
+ the SILC tree.
+
Sun Feb 17 15:52:30 EET 2002 Pekka Riikonen <priikone@silcnet.org>
* Added `user_count' to the SilcChannelEntry which now tells the
--- /dev/null
+Makefile
+Makefile.in
+aclocal.m4
+config.cache
+config.guess
+config.h
+config.log
+config.status
+config.sub
+configure
+configure.scan
+libtool
+libtool-shared
+ltconfig
+ltmain.sh
+stamp-h
+stamp-h.in
+stamp.h
+version.h
+config.h.in
+.exrc
+install-sh
+missing
+mkinstalldirs
+INSTALL
+intl
+ABOUT-NLS
+COPYING
+irssi.spec
+default-config.h
+default-theme.h
+irssi-version.h
+irssi-config
+colorless.theme
+build-stamp
+configure-stamp
$(theme_DATA) \
irssi-config.in \
irssi-icon.png \
+ syntax.pl \
Makefile.defines.in \
Makefile.defines_int.in
irssi, http://irssi.org
+ * INSTALLATION
+
+See INSTALL file.
+
+
* FILES
- docs/ directory contains several documents:
- startup-HOWTO.txt - new users should read this
- - manual.txt - manual I started writing but didn't get it finished :)
+ - manual.txt - manual I started writing but didn't get it very far :)
- perl.txt - Perl scripting help
- formats.txt - How to use colors, etc. with irssi
- faq.txt - Frequently Asked Questions
- Timo Sirainen
- tss@iki.fi
- - cras@ircnet/efnet/opn/silc
- - #irssi@ircnet/opn
+ - cras at ircnet/opn/silc
+ - #irssi at ircnet/opn, #irssi.fi at ircnet
fi
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(Irssi-SILC, 0.7.99)
+AM_INIT_AUTOMAKE(Irssi-SILC, 0.8.1)
AM_MAINTAINER_MODE
# check posix headers..
AC_CHECK_HEADERS(sys/time.h sys/utsname.h regex.h)
-AC_ARG_WITH(big5,
-[ --with-big5 Build with tr-Chinese Big5 support],
- if test x$withval = xyes; then
- want_big5=yes
- else
- if test "x$withval" = xno; then
- want_big5=no
- else
- want_big5=yes
- fi
- fi,
- want_big5=no)
-
AC_ARG_WITH(socks,
[ --with-socks Build with socks support],
if test x$withval = xyes; then
esac
-AC_CHECK_FUNCS(mkfifo fcntl)
+AC_CHECK_FUNCS(mkfifo fcntl nl_langinfo)
AC_CHECK_FUNC(socket, [], [
AC_CHECK_LIB(socket, socket, [
if test -f $full_glib_dir/gmodule/.libs/libgmodule.a; then
GLIB_LIBS="$GLIB_LIBS $full_glib_dir/gmodule/.libs/libgmodule.a"
AC_DEFINE(HAVE_GMODULE)
+ have_gmodule=yes
fi
else
GLIB_LIBS="$full_glib_dir/libglib.a $GLIB_LDEXTRA"
if test -f $full_glib_dir/gmodule/libgmodule.a; then
GLIB_LIBS="$GLIB_LIBS $full_glib_dir/gmodule/libgmodule.a"
AC_DEFINE(HAVE_GMODULE)
+ have_gmodule=yes
fi
fi
AC_SUBST(GLIB_CFLAGS)
AM_PATH_GLIB(1.2.0)
else
AC_DEFINE(HAVE_GMODULE)
+ have_gmodule=yes
fi
if test -z "$GLIB_LIBS"; then
AC_CHECK_FUNC(idcok, AC_DEFINE(HAVE_CURSES_IDCOK))
AC_CHECK_FUNC(resizeterm, AC_DEFINE(HAVE_CURSES_RESIZETERM))
AC_CHECK_FUNC(wresize, AC_DEFINE(HAVE_CURSES_WRESIZE))
- if test "x$want_terminfo" = "xyes"; then
- AC_CHECK_LIB(curses, setupterm,, [
- want_termcap=yes
- ])
- fi
+ AC_CHECK_FUNC(setupterm,, [
+ want_termcap=yes
+ ])
else
AC_CHECK_LIB(tinfo, setupterm, [
LIBS="$LIBS -ltinfo"
AC_SUBST(COMMON_NOUI_LIBS)
AC_SUBST(COMMON_LIBS)
-dnl **
-dnl ** tr-Chinese Big5 support
-dnl **
-
-if test "x$want_big5" = "xyes"; then
- AC_DEFINE(WANT_BIG5)
-fi
-
dnl **
dnl ** IPv6 support
dnl **
echo "Building irssi bot ......... : $want_irssibot"
echo "Building irssi proxy ....... : $want_irssiproxy"
echo "Building with IPv6 support . : $want_ipv6"
+if test "x$have_gmodule" = "xyes"; then
+ echo "Building with module support : yes"
+else
+ echo "Building with module support : NO!! /LOAD will not work!"
+ echo " - You're missing gmodule (comes with glib) for some reason,"
+ echo " or it doesn't work in your system."
+fi
if test "x$want_perl" = "xstatic"; then
echo "Building with Perl support . : static (in irssi binary)"
echo " Anyway, installing perl to this directory should work just as well."
fi
fi
+
echo "Install prefix ............. : $prefix"
Q: Why doesn't irssi display colors even when ircii etc. displays them?
-A: Irssi uses curses, ircii and others don't (no, not even if ldd says they
- use it). Curses decides if terminal supports colors based on the TERM
- variable, so changing it should help. Some values to try when running
- in xterm are: xterm, xterm-color and color_xterm.
-
-Q: Why does irssi crash when pressing Ctrl-4?
-A: Most unices are usually configured to send SIGQUIT to active process when
- Ctrl-\ is pressed. Some terminals also treat Ctrl-4 and Ctrl-\ equally, so
- Irssi will die to SIGQUIT. Two ways to fix this: change it to something
- else with stty (stty quit undef) or in irssi /SET ignore_signals quit
-
-Q: Where's the GUI version?
-A: Read http://irssi.org/?page=about
+A: They force ANSI colors even if terminal doesn't support them. By default,
+ irssi uses colors only if terminfo/termcap so says. The correct way to
+ fix this would be to change your TERM environment to a value where colors
+ work, like xterm-color or color_xterm. If this doesn't help, then use the
+ evil way of /SET term_force_colors ON.
Q: How do I easily write text to channel that starts with '/' character?
A: / /text
+Q: Why doesn't irssi update my realname (or whatever) after I change it
+ with /SET realname and reconnect with /RECONNECT or /SERVER?
+A: Irssi is trying to be too smart. This will be fixed in future, but for
+ now you should use /DISCONNECT + /CONNECT.
+
Q: I connected to some server which isn't responding but now irssi tries
to connect back to it all the time! How can I stop it?
A: Two ways. The "good way" to do it is with /DISCONNECT. Check the server
reconnections with /RMRECONNS, easier but may remove some connections
you actually wanted to reconnect (if you used multiple servers..).
+Q: How do I add seconds to timestamp?
+A: "/FORMAT timestamp {timestamp %%H:%%M:%%S} " - and remember to add the
+ trailing space :)
+
Q: Why does irssi say "Irssi: Channel not fully synchronized yet, try again
after a while" when I try to use /BAN etc?
-A: IRC server you use is coded badly, do something like this:
- /IRCNET ADD -querychans 1 quakenet
- /SERVER ADD -ircnet quakenet irc.quakenet.org
- /SAVE
- After that /CONNECT quakenet should work properly (NOTE: when you do this
- the first time you'll have to /DISCONNECT and /CONNECT again, /SERVER
- doesn't work correctly).
+A: Possibly a bug in irssi, or ircd you're using does something that irssi
+ didn't really notice. The new code should make this happen far less often
+ than before, but one known reason for this is when irssi doesn't notice
+ that you were unable to join some channel. Currently however I don't know
+ of any such events irssi doesn't know about.
+
+ Anyway, if this does happen, do "/RAWLOG SAVE ~/rawlog" soon after joining
+ to channel, and either try to figure out yourself why irssi didn't get
+ reply to WHO request, or send the whole log to tss@iki.fi. Note that the
+ rawlog is by default only 200 lines and it may not be enough to show all
+ needed information, so you might want to do /SET rawlog_lines 1000 or so.
+
+Q: Where's the GUI version?
+A: Read http://irssi.org/?page=about
+
+Q: How do I autorejoin channels after being kicked?
+A: That's evil and you shouldn't do it. If you get kicked, you should
+ stay out, at least until the channel forgot you existed :) Most channels
+ I've joined just ban you if you autorejoin after kick. If you're joined
+ to channels who kick people for fun, try changing channels or something.
+
+ Anyway, if you REALLY want to do that, and you understand that you're
+ doing evilness, you can use the autorejoin.pl script that comes with
+ irssi. You'll still need to specify the channels you wish to rejoin with
+ /SET autorejoin_channels #chan1 #chan2 ...
+
+Q: How do I announce that I'm away/back in all channels I've joined?
+ Or how do I change my nick when setting myself away/back?
+A: That's even worse than autorejoin. Who could possibly care every time you
+ come and go? Many channels will kick you for using this, and I for example
+ have added several ignores so I'd never need to see these messages. Learn
+ to use /AWAY command properly and tell it's existence to people who don't
+ know about it. /WII yournick shows your away reason much better for people
+ who actually want to know if you're there or not.
+
+ You can script these behaviours if you really wish to of course. But
+ currently there's no public scripts for either of these, and the only way
+ I'm going to add such to irssi.org is if the script contains a setting to
+ specify which specific channels the announcement is sent.
+
Irssi has by default also defined several other keys which you can use:
return - The return/enter key
+ space, backspace - Space / backspace
up, down, left, right - Arrow keys
+ cleft, cright - Ctrl-left/right
home, end, prior, next - prior = Page Up, next = Page Down
insert, delete
delete_character
delete_next_word
delete_previous_word
+ delete_to_next_space
delete_to_previous_space
erase_line
erase_to_beg_of_line
(Word completion)
word_completion
+ erase_completion
check_replaces - Check word replaces
(Misc)
yank_from_cutbuffer - "Undelete" line
transpose_characters - Swap current and previous character
insert_text - Insert data to entry line, data may contain $variables.
+ stop_irc - Send SIGSTOP to client (^Z)
Examples:
ACTIONS - Actions (/me) - usually ORed with PUBLIC or MSGS
JOINS - Someone joins a channel
PARTS - Someone parts a channel
- QUITS - Someone quits IRC
+ QUITS - Someone quits network
KICKS - Someone gets kicked from channel
MODES - Channel mode is changed
TOPICS - Channel topic is changed
--- /dev/null
+
+@SYNTAX:statusbar@
+
+Commands for modifying statusbar.
--- /dev/null
+
+@SYNTAX:upgrade@
+
+Upgrade irssi to new version on-the-fly without disconnecting from
+server, so other people won't even notice you quit from network. This ONLY
+executes the new binary, it does NOT download/compile/whatever irssi.
+
- Running Perl scripts
- --------------------
+ Installation problems
+ ---------------------
-First you'll need to have Perl support on. By default irssi compiles
-Perl as a module, so /LOAD perl probably helps. If you want to do this
-automatically at startup put the "/LOAD perl" to ~/.irssi/startup file.
-After that you can run scripts with /RUN script (you don't need to give
-the .pl extension). If /RUN complains about "unknown command", you
-don't have Perl module loaded, or maybe Perl support wasn't compiled at
-all.
+You'll need to have perl support compiled with irssi. If "/LOAD"
+doesn't show perl in list of loaded modules, you have a problem. See
+INSTALL file for information about perl problems.
-Place new scripts to ~/.irssi/scripts/ or /usr/local/lib/irssi/scripts/
-directory. Scripts in ~/.irssi/scripts/autorun/ directory are
-automatically run at startup.
-Using /PERLFLUSH closes and reopens the perl interpreter removing all
-Perl scripts from memory. There's currently no way to unload a single
-Perl script (/SCRIPT REMOVE will probably work soon). You can however
-run same script multiple times, and irssi will remove the old version
-from memory before running the new version.
+ Running scripts
+ ---------------
+
+Scripts are run with /SCRIPT LOAD command, or the default /RUN alias.
+"/SCRIPT" shows list of running script, and /SCRIPT UNLOAD can unload
+scripts.
+
+Scripts should be placed to ~/.irssi/scripts/ or
+/usr/local/lib/irssi/scripts/ (or depending on where irssi was
+installed) directories. After that /RUN script_name should work, you
+don't need to add the .pl prefix.
Irssi's signals
Server::get_nick_flags()
Returns nick flag characters in order: op, voice, halfop ("@+%" in IRC).
-Server::send_message(target, msg)
- Sends a message to nick/channel.
+Server::send_message(target, msg, target_type)
+ Sends a message to nick/channel. target_type 0 = channel, 1 = nick
*** Server reconnections
"message irc own_notice", SERVER_REC, char *msg, char *target
"message irc notice", SERVER_REC, char *msg, char *nick, char *address, char *target
"message irc own_ctcp", SERVER_REC, char *cmd, char *data, char *target
- "message irc ctcp", SERVER_REC, char *msg, char *nick, char *address, char *target
+ "message irc ctcp", SERVER_REC, char *cmd, char *data, char *nick, char *address, char *target
dcc/fe-dcc-chat-messages.c:
"message dcc own", DCC_REC *dcc, char *msg
<h3>To new Irssi users (not to new IRC users ..)</h3>
- <p>Copyright (c) 2000-2001 by Timo Sirainen</p>
+ <p>Copyright (c) 2000-2002 by Timo Sirainen</p>
<p>Index with some FAQ questions that are answered in the chapter:</p>
<ol>
<li><a href="#c1">For all the lazy people</a></li>
-<li><a href="#c2">Basic user interface usage</a></li>
+<li><a href="#c2">Basic user interface usage</a>
+ <ul>
+ <li>Split windows work in weird way</li>
+ </ul></li>
<li><a href="#c3">Server and channel automation</a>
<ul>
- <li>how do I automatically connect to servers at startup?</li>
- <li>how do I automatically join to channels at startup?</li>
+ <li>How do I automatically connect to servers at startup?</li>
+ <li>How do I automatically join to channels at startup?</li>
</ul></li>
<li><a href="#c4">Setting up windows and automatically restoring them
at startup</a></li>
<li>How can I save all texts in a window to file?</li>
</ul></li>
<li><a href="#c8">Logging</a></li>
-<li><a href="#c9">Proxies and IRC bouncers</a></li>
-<li><a href="#c10">Irssi's settings</a></li>
+<li><a href="#c9">Changing keyboard bindings</a>
+ <ul>
+ <li>How do I make F1 key do something?</li>
+ </ul></li>
+<li><a href="#c10">Proxies and IRC bouncers</a></li>
+<li><a href="#c11">Irssi's settings</a></li>
</ol>
<h3><a id="c1">1. For all the lazy people</a></h3>
You should see a list of something like:</p>
<pre>
- -!- IRCNet: irc.telia.fi:6667 (IRCNet)
+ -!- IRCNet: irc.song.fi:6667 (IRCNet)
-!- OPN: tolkien.openprojects.net:6667 (OPN)
-!- RECON-1: 192.168.0.1:6667 () (02:59 left before reconnecting)
</pre>
/LASTLOG -topics - print all topic changes
</pre>
-<p>If there's more lines to be printed than 1000, irssi doesn't thinks
-that you probably made some mistake and won't print them without -force
-option. If you want to save the full lastlog to file, use</p>
+<p>If there's more than 1000 lines to be printed, irssi thinks that you
+probably made some mistake and won't print them without -force option.
+If you want to save the full lastlog to file, use</p>
<pre>
/LASTLOG -file ~/irc.log
<p>For logging only some specific channels or nicks, see /HELP log</p>
-<h3><a id="c9">9. Proxies and IRC bouncers</a></h3>
+<h3><a id="c9">9. Changing keyboard bindings</a></h3>
+
+<p>You can change any keyboard binding that terminal lets irssi know
+about. It doesn't let irssi know everything, so for example
+shift-backspace can't be bound unless you modify xterm resources
+somehow.</p>
+
+<p>/HELP bind tells pretty much everything there is to know about
+keyboard bindings. However, there's the problem of how to bind some
+non-standard keys. They might differ a bit with each terminal, so
+you'll need to find out what exactly the keypress produces. Easiest
+way to check that would be to see what it prints in "cat". Here's
+an example for pressing F1 key:</p>
+
+<pre>
+[cras@hurina] ~% cat
+^[OP
+</pre>
+
+<p>So in irssi you would use /BIND ^[OP /ECHO F1 pressed. If you use
+multiple terminals which have different bindings for the key, it would
+be better to use eg.:</p>
+
+<pre>
+/BIND ^[OP key F1
+/BIND ^[11~ key F1
+/BIND F1 /ECHO F1 pressed.
+</pre>
+
+<h3><a id="c10">10. Proxies and IRC bouncers</a></h3>
<p>Irssi supports connecting to IRC servers via a proxy. All proxies have
these settings in common:</p>
/EVAL SET proxy_string CONNECT %s:%d\n\n
</pre>
+<p><strong>BNC</strong></p>
+
+<pre>
+ /SET proxy_password your_pass
+ /SET -clear proxy_string
+ /SET proxy_string conn %s %d
+</pre>
+
+<p><strong>dircproxy</strong></p>
+
+<p>dircproxy separates the server connections by passwords. So, if you
+for example have ircnet connection with password ircpass and
+openprojects connection with opnpass, you would do something like
+this:</p>
+
+<pre>
+ /SET -clear proxy_password
+ /SET -clear proxy_string
+
+ /SERVER ADD -auto -ircnet ircnet fake.ircnet 6667 ircpass
+ /SERVER ADD -auto -ircnet opn fake.opn 6667 opnpass
+</pre>
+
+<p>The server name and port you give isn't used anywhere, so you can
+put anything you want in there.</p>
+
<p><strong>Irssi proxy</strong></p>
<p>Irssi contains it's own proxy which you can build giving
<p>Usage in proxy side:</p>
<pre>
- /LOAD irc_proxy (/LOAD proxy in irssi 0.7.98.3 and older)
+ /LOAD proxy
/SET irssiproxy_password <password>
/SET irssiproxy_ports <ircnet>=<port> ... (eg. ircnet=2777 efnet=2778)
</pre>
one server connection, you may simply set:</p>
<pre>
- /SET irssiproxy_ports *=2777 (irssi 0.7.99 and later only)
+ /SET irssiproxy_ports *=2777
</pre>
<p>Usage in client side:</p>
/SET proxy_password <password>
</pre>
-<p>Irssi's default for connect string is</p>
+<p>Irssi's defaults for connect strings are</p>
<pre>
/SET proxy_string CONNECT %s %d
+ /SET proxy_string_after
</pre>
-<p>which you can modify according to your bouncer's needs.</p>
+<p>The proxy_string is sent before NICK/USER commands, the
+proxy_string_after is sent after them. %s and %d can be used with both
+of them.</p>
-<h3><a id="c10">10. Irssi's settings</a></h3>
+<h3><a id="c11">11. Irssi's settings</a></h3>
<p>You probably don't like Irssi's default settings. I don't like them.
But I'm still convinced that they're pretty good defaults. Here's some
<dd>Show quit message only once in some of the channel windows the
nick was in instead of in all windows.</dd>
-<dt>/SET topicbar ON</dt>
- <dd>Show the channel's topic in top of screen.</dd>
-
<dt>/SET lag_min_show 100</dt>
<dd>Show the server lag in status bar if it's bigger than this, the
unit is 1/100 of seconds (ie. the default value of 100 = 1 second).</dd>
If any highlighted text or message for you appears in that window, this
setting is ignored and the activity is shown.</dd>
-<dt>/SET mail_counter ON</dt>
- <dd>Show the number of mails in your mbox in status
- bar. The mbox file is taken from $MAIL environment setting. Only mbox
- format works for now.</dd>
-</dl>
-
<p><strong>Nick completion</strong></p>
<dl>
To new Irssi users (not to new IRC users ..)
- Copyright (c) 2000-2001 by Timo Sirainen
+ Copyright (c) 2000-2002 by Timo Sirainen
Index with some FAQ questions that are answered in the chapter:
1. For all the lazy people
2. Basic user interface usage
+ + Split windows work in weird way
3. Server and channel automation
- + how do I automatically connect to servers at startup?
- + how do I automatically join to channels at startup?
+ + How do I automatically connect to servers at startup?
+ + How do I automatically join to channels at startup?
4. Setting up windows and automatically restoring them at startup
5. Status and msgs windows & message levels
+ I want /WHOIS to print reply to current window
7. /LASTLOG and jumping around in scrollback
+ How can I save all texts in a window to file?
8. Logging
- 9. Proxies and IRC bouncers
- 10. Irssi's settings
+ 9. Changing keyboard bindings
+ + How do I make F1 key do something?
+ 10. Proxies and IRC bouncers
+ 11. Irssi's settings
1. For all the lazy people
Instead of the /SERVER which disconnects the existing connection. To
see list of all active connections, use /SERVER without any
parameters. You should see a list of something like:
- -!- IRCNet: irc.telia.fi:6667 (IRCNet)
+ -!- IRCNet: irc.song.fi:6667 (IRCNet)
-!- OPN: tolkien.openprojects.net:6667 (OPN)
-!- RECON-1: 192.168.0.1:6667 () (02:59 left before reconnecting)
/LASTLOG word 10 - print last 10 occurances of "word"
/LASTLOG -topics - print all topic changes
- If there's more lines to be printed than 1000, irssi doesn't thinks
- that you probably made some mistake and won't print them without
- -force option. If you want to save the full lastlog to file, use
+ If there's more than 1000 lines to be printed, irssi thinks that you
+ probably made some mistake and won't print them without -force option.
+ If you want to save the full lastlog to file, use
/LASTLOG -file ~/irc.log
With -file option you don't need -force even if there's more than 1000
For logging only some specific channels or nicks, see /HELP log
- 9. Proxies and IRC bouncers
+ 9. Changing keyboard bindings
+
+ You can change any keyboard binding that terminal lets irssi know
+ about. It doesn't let irssi know everything, so for example
+ shift-backspace can't be bound unless you modify xterm resources
+ somehow.
+
+ /HELP bind tells pretty much everything there is to know about
+ keyboard bindings. However, there's the problem of how to bind some
+ non-standard keys. They might differ a bit with each terminal, so
+ you'll need to find out what exactly the keypress produces. Easiest
+ way to check that would be to see what it prints in "cat". Here's an
+ example for pressing F1 key:
+[cras@hurina] ~% cat
+^[OP
+
+ So in irssi you would use /BIND ^[OP /ECHO F1 pressed. If you use
+ multiple terminals which have different bindings for the key, it would
+ be better to use eg.:
+/BIND ^[OP key F1
+/BIND ^[11~ key F1
+/BIND F1 /ECHO F1 pressed.
+
+ 10. Proxies and IRC bouncers
Irssi supports connecting to IRC servers via a proxy. All proxies have
these settings in common:
/SET -clear proxy_password
/EVAL SET proxy_string CONNECT %s:%d\n\n
+ BNC
+ /SET proxy_password your_pass
+ /SET -clear proxy_string
+ /SET proxy_string conn %s %d
+
+ dircproxy
+
+ dircproxy separates the server connections by passwords. So, if you
+ for example have ircnet connection with password ircpass and
+ openprojects connection with opnpass, you would do something like
+ this:
+ /SET -clear proxy_password
+ /SET -clear proxy_string
+
+ /SERVER ADD -auto -ircnet ircnet fake.ircnet 6667 ircpass
+ /SERVER ADD -auto -ircnet opn fake.opn 6667 opnpass
+
+ The server name and port you give isn't used anywhere, so you can put
+ anything you want in there.
+
Irssi proxy
Irssi contains it's own proxy which you can build giving --with-proxy
ports, like you can share ircnet in port 2777 and efnet in port 2778.
Usage in proxy side:
- /LOAD irc_proxy (/LOAD proxy in irssi 0.7.98.3 and older)
+ /LOAD proxy
/SET irssiproxy_password <password>
/SET irssiproxy_ports <ircnet>=<port> ... (eg. ircnet=2777 efnet=2778)
lists with /SERVER ADD and /IRCNET ADD. ..Except if you really don't
want to for some reason, and you only use one server connection, you
may simply set:
- /SET irssiproxy_ports *=2777 (irssi 0.7.99 and later only)
+ /SET irssiproxy_ports *=2777
Usage in client side:
can give it with:
/SET proxy_password <password>
- Irssi's default for connect string is
+ Irssi's defaults for connect strings are
/SET proxy_string CONNECT %s %d
+ /SET proxy_string_after
- which you can modify according to your bouncer's needs.
+ The proxy_string is sent before NICK/USER commands, the
+ proxy_string_after is sent after them. %s and %d can be used with both
+ of them.
- 10. Irssi's settings
+ 11. Irssi's settings
You probably don't like Irssi's default settings. I don't like them.
But I'm still convinced that they're pretty good defaults. Here's some
Show quit message only once in some of the channel windows the
nick was in instead of in all windows.
- /SET topicbar ON
- Show the channel's topic in top of screen.
-
/SET lag_min_show 100
Show the server lag in status bar if it's bigger than this, the
unit is 1/100 of seconds (ie. the default value of 100 = 1
message for you appears in that window, this setting is ignored
and the activity is shown.
- /SET mail_counter ON
- Show the number of mails in your mbox in status bar. The mbox
- file is taken from $MAIL environment setting. Only mbox format
- works for now.
-
- Nick completion
+ Nick completion
- /SET completion_auto OFF
- Automatically complete the nick if line begins with start of
- nick and the completion character. Learn to use the
- tab-completion instead, it's a lot better ;)
+ /SET completion_auto OFF
+ Automatically complete the nick if line begins with start
+ of nick and the completion character. Learn to use the
+ tab-completion instead, it's a lot better ;)
- /SET completion_char :
- Completion character to use.
+ /SET completion_char :
+ Completion character to use.
# automatically rejoin to channel after kicked
+# /SET autorejoin_channels #channel1 #channel2 ...
+
# NOTE: I personally don't like this feature, in most channels I'm in it
# will just result as ban. You've probably misunderstood the idea of /KICK
# if you kick/get kicked all the time "just for fun" ...
-use Irssi;
-use Irssi::Irc;
use strict;
+use Irssi::Irc;
-sub event_rejoin_kick {
- my ($server, $data) = @_;
- my ($channel, $nick) = split(/ +/, $data);
+sub channel_rejoin {
+ my ($server, $channel) = @_;
- return if ($server->{nick} ne $nick);
+ # check if channel has password
+ my $chanrec = $server->channel_find($channel);
+ my $password = $chanrec->{key} if ($chanrec);
+
+ # We have to use send_raw() because the channel record still
+ # exists and irssi won't even try to join to it with command()
+ $server->send_raw("JOIN $channel $password");
+}
+
+sub event_rejoin_kick {
+ my ($server, $data) = @_;
+ my ($channel, $nick) = split(/ +/, $data);
- # check if channel has password
- my $chanrec = $server->channel_find($channel);
- my $password = $chanrec->{key} if ($chanrec);
+ return if ($server->{nick} ne $nick);
- # We have to use send_raw() because the channel record still
- # exists and irssi won't even try to join to it with command()
- $server->send_raw("JOIN $channel $password");
+ # check if we want to autorejoin this channel
+ my @chans = split(/ ,/, Irssi::settings_get_str('autorejoin_channels'));
+ foreach my $chan (@chans) {
+ if (lc($chan) eq lc($channel)) {
+ channel_rejoin($server, $channel);
+ last;
+ }
+ }
}
+Irssi::settings_add_str('misc', 'autorejoin_channels', '');
Irssi::signal_add('event kick', 'event_rejoin_kick');
RUN = "SCRIPT LOAD";
UPTIME = "eval exec - expr `date +%s` - \\$F | awk '{print \"Irssi uptime: \"int(\\\\\\$1/3600/24)\"d \"int(\\\\\\$1/3600%24)\"h \"int(\\\\\\$1/60%60)\"m \"int(\\\\\\$1%60)\"s\" }'";
CALC = "exec - if which bc &>/dev/null\\; then echo '$*' | bc | awk '{print \"$*=\"$$1}'\\; else echo bc was not found\\; fi";
+ SBAR = "STATUSBAR";
};
#
# the "default statusbar" to be displayed at the bottom of the window.
# contains all the normal items.
window = {
+ disabled = "no";
+
# window, root
type = "window";
# top, bottom
placement = "bottom";
# number
position = "1";
- # active, inactive, always, never (disables the statusbar)
+ # active, inactive, always
visible = "active";
# list of items in statusbar in the display order
type = "root";
placement = "top";
position = "1";
- visible = "never";
+ visible = "always";
+ disabled = "yes";
items = {
barstart = { priority = "100"; };
topic = { };
--- /dev/null
+Makefile
+Makefile.in
index = g_slist_index(setupchannels, channel);
parentnode = iconfig_node_traverse("(channels", TRUE);
- node = config_node_index(parentnode, index);
+ node = config_node_nth(parentnode, index);
if (node == NULL)
node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
channels_setup_deinit();
signal_remove("event connected", (SIGNAL_FUNC) event_connected);
- module_uniq_destroy("CHANNEL");
}
return;
if (*target == '\0' || *msg == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
- server = cmd_options_get_server("msg", optlist, SERVER(server));
+ server = cmd_options_get_server("msg", optlist, server);
if (server == NULL || !server->connected)
cmd_param_error(CMDERR_NOT_CONNECTED);
cnt = PARAM_WITHOUT_FLAGS(count);
if (count & PARAM_FLAG_OPTCHAN) {
/* optional channel as first parameter */
- require_name = (count & PARAM_FLAG_OPTCHAN_NAME);
+ require_name = (count & PARAM_FLAG_OPTCHAN_NAME) ==
+ PARAM_FLAG_OPTCHAN_NAME;
arg = get_optional_channel(item, &datad, require_name);
str = (char **) va_arg(args, char **);
/* optional channel in first argument */
#define PARAM_FLAG_OPTCHAN 0x00010000
/* optional channel in first argument, but don't treat "*" as current channel */
-#define PARAM_FLAG_OPTCHAN_NAME 0x00030000
+#define PARAM_FLAG_OPTCHAN_NAME (0x00020000|PARAM_FLAG_OPTCHAN)
char *cmd_get_param(char **data);
/* get parameters from command - you should point free_me somewhere and
void core_deinit(void)
{
+ module_uniq_destroy("WINDOW ITEM TYPE");
+
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_irssi_init_finished);
if (!found && !no_fallbacks && fallbacks != NULL) {
/* not found from any items, so write it to all main logs */
- tmpstr = (level & MSGLEVEL_PUBLIC) ?
+ tmpstr = (level & MSGLEVEL_PUBLIC) && item != NULL ?
g_strconcat(item, ": ", str, NULL) :
g_strdup(str);
case 'x':
/* hex digit */
- if (!isxdigit((*data)[1]) || !isxdigit((*data)[2]))
+ if (!i_isxdigit((*data)[1]) || !i_isxdigit((*data)[2]))
return -1;
digit[0] = (*data)[1];
void queries_deinit(void)
{
- module_uniq_destroy("QUERY");
}
index = g_slist_index(setupservers, rec);
parentnode = iconfig_node_traverse("(servers", TRUE);
- node = config_node_index(parentnode, index);
+ node = config_node_nth(parentnode, index);
if (node == NULL)
node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
int brackets, nest_free;
*free_ret = FALSE;
+ if (**cmd == '\0')
+ return NULL;
command = **cmd; (*cmd)++;
switch (command) {
printtext.h \
themes.h \
translation.h \
+ window-activity.h \
window-items.h \
windows-layout.h \
fe-windows.h
#include "signals.h"
#include "commands.h"
#include "misc.h"
+#include "levels.h"
#include "settings.h"
#include "chatnets.h"
/* nick completion .. we could also be completing a nick
after /MSG from nicks in channel */
complete_window_nicks(list, window, word, linestart);
+ } else if (window->level & MSGLEVEL_MSGS) {
+ /* msgs window, complete /MSG nicks */
+ *list = g_list_concat(completion_msg(server, NULL, word, NULL), *list);
}
if (*list != NULL) signal_stop();
signal_add("complete word", (SIGNAL_FUNC) sig_complete_word);
signal_add("complete command msg", (SIGNAL_FUNC) sig_complete_msg);
signal_add("complete command query", (SIGNAL_FUNC) sig_complete_msg);
+ signal_add("complete command action", (SIGNAL_FUNC) sig_complete_msg);
signal_add("complete erase command msg", (SIGNAL_FUNC) sig_erase_complete_msg);
signal_add("complete erase command query", (SIGNAL_FUNC) sig_erase_complete_msg);
+ signal_add("complete erase command action", (SIGNAL_FUNC) sig_erase_complete_msg);
signal_add("complete command connect", (SIGNAL_FUNC) sig_complete_connect);
signal_add("complete command server", (SIGNAL_FUNC) sig_complete_connect);
signal_add("complete command topic", (SIGNAL_FUNC) sig_complete_topic);
signal_remove("complete word", (SIGNAL_FUNC) sig_complete_word);
signal_remove("complete command msg", (SIGNAL_FUNC) sig_complete_msg);
signal_remove("complete command query", (SIGNAL_FUNC) sig_complete_msg);
+ signal_remove("complete command action", (SIGNAL_FUNC) sig_complete_msg);
signal_remove("complete erase command msg", (SIGNAL_FUNC) sig_erase_complete_msg);
signal_remove("complete erase command query", (SIGNAL_FUNC) sig_erase_complete_msg);
+ signal_remove("complete erase command action", (SIGNAL_FUNC) sig_erase_complete_msg);
signal_remove("complete command connect", (SIGNAL_FUNC) sig_complete_connect);
signal_remove("complete command server", (SIGNAL_FUNC) sig_complete_connect);
signal_remove("complete command topic", (SIGNAL_FUNC) sig_complete_topic);
}
}
- if (str->len != 0) {
+ if (str->len > strlen(prefix_format)) {
printtext(channel->server, channel->name,
MSGLEVEL_CLIENTCRAP, "%s", str->str);
}
/* display the nicks */
if ((flags & CHANNEL_NICKLIST_FLAG_COUNT) == 0) {
printformat(channel->server, channel->name,
- MSGLEVEL_CRAP, TXT_NAMES, channel->name, "");
+ MSGLEVEL_CLIENTCRAP, TXT_NAMES, channel->name, nicks, ops, halfops, voices, normal);
display_sorted_nicks(channel, sorted);
}
g_slist_free(sorted);
printformat(channel->server, channel->name,
- MSGLEVEL_CRAP, TXT_ENDOFNAMES,
+ MSGLEVEL_CLIENTNOTICE, TXT_ENDOFNAMES,
channel->name, nicks, ops, halfops, voices, normal);
}
#include "translation.h"
#include "fe-channels.h"
#include "fe-windows.h"
+#include "window-activity.h"
#include "window-items.h"
#include "windows-layout.h"
void fe_settings_init(void);
void fe_settings_deinit(void);
-void window_activity_init(void);
-void window_activity_deinit(void);
-
void window_commands_init(void);
void window_commands_deinit(void);
rec = g_new0(WINDOW_REC, 1);
rec->refnum = window_get_new_refnum();
+ rec->level = level2bits(settings_get_str("window_default_level"));
windows = g_slist_prepend(windows, rec);
signal_emit("window created", 2, rec, GINT_TO_POINTER(automatic));
WINDOW_REC *window_find_closest(void *server, const char *name, int level)
{
- WINDOW_REC *window;
+ WINDOW_REC *window,*namewindow=NULL;
WI_ITEM_REC *item;
/* match by name */
item = name == NULL ? NULL :
window_item_find(server, name);
- if (item != NULL)
- return window_item_window(item);
+ if (item != NULL) {
+ namewindow = window_item_window(item);
+ if (namewindow != NULL && ((namewindow->level & level) != 0 ||
+ !settings_get_bool("window_check_level_first")))
+ return namewindow;
+ }
/* match by level */
if (level != MSGLEVEL_HILIGHT)
window = window_find_level(NULL, level);
if (window != NULL) return window;
+ /* still return item's window if we didnt find anything */
+ if (namewindow != NULL) return namewindow;
+
/* fallback to active */
return active_win;
}
daycheck = 0; daytag = -1;
settings_add_bool("lookandfeel", "window_auto_change", FALSE);
settings_add_bool("lookandfeel", "windows_auto_renumber", TRUE);
+ settings_add_bool("lookandfeel", "window_check_level_first", FALSE);
+ settings_add_str("lookandfeel", "window_default_level", "NONE");
read_settings();
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
while (*ptr != ',' && *ptr != '\0')
ptr++;
if (*ptr != '\0') *ptr++ = '\0';
+ ptr--;
signal_emit_id(signal_gui_print_text, 6,
dest->window, NULL, NULL,
GINT_TO_POINTER(GUI_PRINT_FLAG_INDENT_FUNC),
flags |= GUI_PRINT_FLAG_BOLD;
}
}
+ if (ptr[1] == '\0')
+ break;
+
ptr++;
if (*ptr != FORMAT_COLOR_NOCHANGE) {
bgcolor = *ptr-'0';
if (rec->priority > 0)
dest->hilight_priority = rec->priority;
- g_free_not_null(dest->hilight_color);
- dest->hilight_color = hilight_get_act_color(rec);
+ g_free_and_null(dest->hilight_color);
+ if (rec->act_color != NULL && strcmp(rec->act_color, "%n") == 0)
+ dest->level |= MSGLEVEL_NO_ACT;
+ else
+ dest->hilight_color = hilight_get_act_color(rec);
}
static void sig_print_text(TEXT_DEST_REC *dest, const char *text,
{ "talking_in", "You are now talking in {channel $0}", 1, { 0 } },
{ "not_in_channels", "You are not on any channels", 0 },
{ "current_channel", "Current channel {channel $0}", 1, { 0 } },
- { "names", "{names_users Users {names_channel $0}} $1", 2, { 0, 0 } },
+ { "names", "{names_users Users {names_channel $0}}", 6, { 0, 1, 1, 1, 1, 1 } },
{ "names_prefix", "{names_prefix $0}", 1, { 0 } },
{ "names_nick_op", "{names_nick_op $0 $1}", 2, { 0, 0 } },
{ "names_nick_halfop", "{names_nick_halfop $0 $1}", 2, { 0, 0 } },
msg_beep_check(dest);
- dest->window->last_line = time(NULL);
+ if ((dest->level & MSGLEVEL_NEVER) == 0)
+ dest->window->last_line = time(NULL);
/* add timestamp/server tag here - if it's done in print_line()
it would be written to log files too */
value = parse_special((char **) format, NULL, NULL,
args, &free_ret, NULL, PARSE_FLAG_ONLY_ARGS);
if (free_ret) g_free(value);
- (*format)++;
+
+ if (**format != '\0')
+ (*format)++;
/* append the variable name */
value = g_strndup(orig, (int) (*format-orig));
rec = theme_load(name);
if (rec != NULL) {
current_theme = rec;
+ signal_emit("theme changed", 1, rec);
+
if (verbose) {
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
TXT_THEME_CHANGED,
static char **hide_targets;
static int hide_level, msg_level, hilight_level;
-static void window_activity(WINDOW_REC *window, int data_level,
- const char *hilight_color)
+void window_activity(WINDOW_REC *window, int data_level,
+ const char *hilight_color)
{
int old_data_level;
GINT_TO_POINTER(old_data_level));
}
-static void window_item_activity(WI_ITEM_REC *item, int data_level,
- const char *hilight_color)
+void window_item_activity(WI_ITEM_REC *item, int data_level,
+ const char *hilight_color)
{
int old_data_level;
--- /dev/null
+#ifndef __WINDOW_ACTIVITY_H
+#define __WINDOW_ACTIVITY_H
+
+void window_activity(WINDOW_REC *window, int data_level,
+ const char *hilight_color);
+
+void window_item_activity(WI_ITEM_REC *item, int data_level,
+ const char *hilight_color);
+
+void window_activity_init(void);
+void window_activity_deinit(void);
+
+#endif
{
int set;
- if (g_strcasecmp(data, "ON") == 0)
+ if (*data == '\0')
+ set = active_win->immortal;
+ else if (g_strcasecmp(data, "ON") == 0)
set = TRUE;
else if (g_strcasecmp(data, "OFF") == 0)
set = FALSE;
else if (g_strcasecmp(data, "TOGGLE") == 0)
set = !active_win->immortal;
else {
- printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE);
+ printformat_window(active_win, MSGLEVEL_CLIENTERROR,
+ TXT_NOT_TOGGLE);
return;
}
*/
#include "module.h"
+#include "misc.h"
#include "utf8.h"
#include "formats.h"
#include "gui-printtext.h"
#include "term.h"
+const unichar empty_str[] = { 0 };
+
GUI_ENTRY_REC *active_entry;
+static void entry_text_grow(GUI_ENTRY_REC *entry, int grow_size)
+{
+ if (entry->text_len+grow_size < entry->text_alloc)
+ return;
+
+ entry->text_alloc = nearest_power(entry->text_alloc+grow_size);
+ entry->text = g_realloc(entry->text, entry->text_alloc);
+}
+
GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8)
{
GUI_ENTRY_REC *rec;
rec->xpos = xpos;
rec->ypos = ypos;
rec->width = width;
- rec->text = g_string_new(NULL);
+ rec->text_alloc = 1024;
+ rec->text = g_new(unichar, rec->text_alloc);
+ rec->text[0] = '\0';
rec->utf8 = utf8;
return rec;
}
if (active_entry == entry)
gui_entry_set_active(NULL);
- g_free_not_null(entry->prompt);
- g_string_free(entry->text, TRUE);
+ g_free(entry->text);
+ g_free(entry->prompt);
g_free(entry);
}
static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
{
- const unsigned char *p, *end;
+ const unichar *p;
int xpos, end_xpos;
- if (entry->utf8) {
- /* FIXME: a stupid kludge to make the chars output correctly */
- pos = 0;
- }
-
xpos = entry->xpos + entry->promptlen + pos;
end_xpos = entry->xpos + entry->width;
if (xpos > end_xpos)
term_set_color(root_window, ATTR_RESET);
term_move(root_window, xpos, entry->ypos);
- p = (unsigned char *) (entry->scrstart + pos >= entry->text->len ? "" :
- entry->text->str + entry->scrstart + pos);
+ p = entry->scrstart + pos < entry->text_len ?
+ entry->text + entry->scrstart + pos : empty_str;
for (; *p != '\0' && xpos < end_xpos; p++, xpos++) {
- end = p;
- if (entry->utf8)
- get_utf8_char(&end);
-
if (entry->hidden)
term_addch(root_window, ' ');
- else if (*p >= 32 && (end != p || (*p & 127) >= 32)) {
- for (; p < end; p++)
- term_addch(root_window, *p);
- term_addch(root_window, *p);
- } else {
+ else if (*p >= 32 && (entry->utf8 || (*p & 127) >= 32))
+ term_add_unichar(root_window, *p);
+ else {
term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
term_addch(root_window, *p+'A'-1);
term_set_color(root_window, ATTR_RESET);
void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str)
{
- g_return_if_fail(entry != NULL);
+ g_return_if_fail(entry != NULL);
g_return_if_fail(str != NULL);
- g_string_assign(entry->text, str);
- entry->pos = entry->text->len;
+ entry->text_len = 0;
+ entry->pos = 0;
+ entry->text[0] = '\0';
- gui_entry_redraw_from(entry, 0);
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
+ gui_entry_insert_text(entry, str);
}
char *gui_entry_get_text(GUI_ENTRY_REC *entry)
{
+ char *buf;
+ int i;
+
g_return_val_if_fail(entry != NULL, NULL);
- return entry->text->str;
+ buf = g_malloc(entry->text_len*6 + 1);
+ if (entry->utf8)
+ utf16_to_utf8(entry->text, buf);
+ else {
+ for (i = 0; i <= entry->text_len; i++)
+ buf[i] = entry->text[i];
+ }
+ return buf;
}
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str)
{
+ unichar chr;
+ int i, len;
+
g_return_if_fail(entry != NULL);
g_return_if_fail(str != NULL);
gui_entry_redraw_from(entry, entry->pos);
- g_string_insert(entry->text, entry->pos, str);
- entry->pos += strlen(str);
+
+ len = !entry->utf8 ? strlen(str) : strlen_utf8(str);
+ entry_text_grow(entry, len);
+
+ /* make space for the string */
+ g_memmove(entry->text + entry->pos + len, entry->text + entry->pos,
+ (entry->text_len-entry->pos + 1) * sizeof(unichar));
+
+ if (!entry->utf8) {
+ for (i = 0; i < len; i++)
+ entry->text[entry->pos+i] = str[i];
+ } else {
+ chr = entry->text[entry->pos+len];
+ utf8_to_utf16(str, entry->text+entry->pos);
+ entry->text[entry->pos+len] = chr;
+ }
+
+ entry->text_len += len;
+ entry->pos += len;
gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
}
-void gui_entry_insert_char(GUI_ENTRY_REC *entry, char chr)
+void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr)
{
g_return_if_fail(entry != NULL);
return; /* never insert NUL, CR or LF characters */
gui_entry_redraw_from(entry, entry->pos);
- g_string_insert_c(entry->text, entry->pos, chr);
- entry->pos++;
+
+ entry_text_grow(entry, 1);
+
+ /* make space for the string */
+ g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos,
+ (entry->text_len-entry->pos + 1) * sizeof(unichar));
+
+ entry->text[entry->pos] = chr;
+ entry->text_len++;
+ entry->pos++;
gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
}
+char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry)
+{
+ char *buf;
+ int i;
+
+ g_return_val_if_fail(entry != NULL, NULL);
+
+ buf = g_malloc(entry->cutbuffer_len*6 + 1);
+ if (entry->utf8)
+ utf16_to_utf8(entry->cutbuffer, buf);
+ else {
+ for (i = 0; i <= entry->cutbuffer_len; i++)
+ buf[i] = entry->cutbuffer[i];
+ }
+ return buf;
+}
+
void gui_entry_erase(GUI_ENTRY_REC *entry, int size)
{
g_return_if_fail(entry != NULL);
if (entry->pos < size)
return;
-#ifdef WANT_BIG5
- if (is_big5(entry->text->str[entry->pos-2],
- entry->text->str[entry->pos-1]))
- size++;
-#endif
+ /* put erased text to cutbuffer */
+ if (entry->cutbuffer == NULL || entry->cutbuffer_len < size) {
+ g_free(entry->cutbuffer);
+ entry->cutbuffer = g_new(unichar, size+1);
+ }
+
+ entry->cutbuffer_len = size;
+ entry->cutbuffer[size] = '\0';
+ memcpy(entry->cutbuffer, entry->text + entry->pos - size,
+ size * sizeof(unichar));
+
+ if (size == 0) {
+ /* we just wanted to clear the cutbuffer */
+ return;
+ }
+
+ g_memmove(entry->text + entry->pos - size, entry->text + entry->pos,
+ (entry->text_len-entry->pos+1) * sizeof(unichar));
entry->pos -= size;
- g_string_erase(entry->text, entry->pos, size);
+ entry->text_len -= size;
gui_entry_redraw_from(entry, entry->pos);
gui_entry_fix_cursor(entry);
to = entry->pos - 1;
if (to_space) {
- while (entry->text->str[to] == ' ' && to > 0)
+ while (entry->text[to] == ' ' && to > 0)
to--;
- while (entry->text->str[to] != ' ' && to > 0)
+ while (entry->text[to] != ' ' && to > 0)
to--;
} else {
- while (!i_isalnum(entry->text->str[to]) && to > 0)
+ while (!i_isalnum(entry->text[to]) && to > 0)
to--;
- while (i_isalnum(entry->text->str[to]) && to > 0)
+ while (i_isalnum(entry->text[to]) && to > 0)
to--;
}
if (to > 0) to++;
- g_string_erase(entry->text, to, entry->pos - to);
- entry->pos = to;
-
- gui_entry_redraw_from(entry, entry->pos);
- gui_entry_fix_cursor(entry);
- gui_entry_draw(entry);
+ gui_entry_erase(entry, entry->pos-to);
}
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space)
{
- int to;
+ int to, size;
g_return_if_fail(entry != NULL);
- if (entry->pos == entry->text->len)
+ if (entry->pos == entry->text_len)
return;
to = entry->pos;
if (to_space) {
- while (entry->text->str[to] == ' ' && to < entry->text->len)
+ while (entry->text[to] == ' ' && to < entry->text_len)
to++;
- while (entry->text->str[to] != ' ' && to < entry->text->len)
+ while (entry->text[to] != ' ' && to < entry->text_len)
to++;
} else {
- while (!i_isalnum(entry->text->str[to]) && to < entry->text->len)
+ while (!i_isalnum(entry->text[to]) && to < entry->text_len)
to++;
- while (i_isalnum(entry->text->str[to]) && to < entry->text->len)
+ while (i_isalnum(entry->text[to]) && to < entry->text_len)
to++;
}
- g_string_erase(entry->text, entry->pos, to - entry->pos);
+ size = to-entry->pos;
+ entry->pos = to;
+ gui_entry_erase(entry, size);
+}
- gui_entry_redraw_from(entry, entry->pos);
+void gui_entry_transpose_chars(GUI_ENTRY_REC *entry)
+{
+ unichar chr;
+
+ if (entry->pos == 0 || entry->text_len < 2)
+ return;
+
+ if (entry->pos == entry->text_len)
+ entry->pos--;
+
+ /* swap chars */
+ chr = entry->text[entry->pos];
+ entry->text[entry->pos] = entry->text[entry->pos-1];
+ entry->text[entry->pos-1] = chr;
+
+ entry->pos++;
+
+ gui_entry_redraw_from(entry, entry->pos-2);
gui_entry_fix_cursor(entry);
gui_entry_draw(entry);
}
{
g_return_if_fail(entry != NULL);
- if (pos >= 0 && pos <= entry->text->len)
+ if (pos >= 0 && pos <= entry->text_len)
entry->pos = pos;
gui_entry_fix_cursor(entry);
{
g_return_if_fail(entry != NULL);
-#ifdef WANT_BIG5
- if (pos > 0 && is_big5(entry->text->str[entry->pos],
- entry->text->str[entry->pos+1]))
- pos++;
- else if (pos < 0 && is_big5(entry->text->str[entry->pos-1],
- entry->text->str[entry->pos]))
- pos--;
-#endif
-
- if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text->len)
+ if (entry->pos+pos >= 0 && entry->pos+pos <= entry->text_len)
entry->pos += pos;
gui_entry_fix_cursor(entry);
pos = entry->pos;
while (count > 0 && pos > 0) {
if (to_space) {
- while (pos > 0 && entry->text->str[pos-1] == ' ')
+ while (pos > 0 && entry->text[pos-1] == ' ')
pos--;
- while (pos > 0 && entry->text->str[pos-1] != ' ')
+ while (pos > 0 && entry->text[pos-1] != ' ')
pos--;
} else {
- while (pos > 0 && !i_isalnum(entry->text->str[pos-1]))
+ while (pos > 0 && !i_isalnum(entry->text[pos-1]))
pos--;
- while (pos > 0 && i_isalnum(entry->text->str[pos-1]))
+ while (pos > 0 && i_isalnum(entry->text[pos-1]))
pos--;
}
count--;
int pos;
pos = entry->pos;
- while (count > 0 && pos < entry->text->len) {
+ while (count > 0 && pos < entry->text_len) {
if (to_space) {
- while (pos < entry->text->len && entry->text->str[pos] == ' ')
+ while (pos < entry->text_len && entry->text[pos] == ' ')
pos++;
- while (pos < entry->text->len && entry->text->str[pos] != ' ')
+ while (pos < entry->text_len && entry->text[pos] != ' ')
pos++;
} else {
- while (pos < entry->text->len && !i_isalnum(entry->text->str[pos]))
+ while (pos < entry->text_len && !i_isalnum(entry->text[pos]))
pos++;
- while (pos < entry->text->len && i_isalnum(entry->text->str[pos]))
+ while (pos < entry->text_len && i_isalnum(entry->text[pos]))
pos++;
}
count--;
#define __GUI_ENTRY_H
typedef struct {
- GString *text;
+ int text_len, text_alloc; /* as shorts, not chars */
+ unichar *text;
+
+ int cutbuffer_len;
+ unichar *cutbuffer;
+
+ /* all as shorts, not chars */
int xpos, ypos, width; /* entry position in screen */
int pos, scrstart, scrpos; /* cursor position */
int hidden; /* print the chars as spaces in input line (useful for passwords) */
char *gui_entry_get_text(GUI_ENTRY_REC *entry);
void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str);
-void gui_entry_insert_char(GUI_ENTRY_REC *entry, char chr);
+void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr);
+char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry);
void gui_entry_erase(GUI_ENTRY_REC *entry, int size);
void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space);
void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space);
+void gui_entry_transpose_chars(GUI_ENTRY_REC *entry);
+
int gui_entry_get_pos(GUI_ENTRY_REC *entry);
void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos);
void gui_entry_move_pos(GUI_ENTRY_REC *entry, int pos);
/* value of cutbuffer */
static char *expando_cutbuffer(SERVER_REC *server, void *item, int *free_ret)
{
- return cutbuffer;
+ *free_ret = TRUE;
+ return gui_entry_get_cutbuffer(active_entry);
}
void gui_expandos_init(void)
list = name == NULL ? NULL :
g_hash_table_lookup(indent_functions, name);
- default_indent_func = list == NULL ? NULL : list->data;
+ default_indent_func = list == NULL ? NULL :
+ (INDENT_FUNC) list->data;
gui_windows_reset_settings();
}
#include "term.h"
#include "gui-entry.h"
#include "gui-windows.h"
+#include "utf8.h"
#include <signal.h>
static KEYBOARD_REC *keyboard;
static ENTRY_REDIRECT_REC *redir;
-char *cutbuffer;
static int readtag;
static time_t idle_time;
gui_window_scroll(active_win, get_scroll_count());
}
-void handle_key(int key)
+void handle_key(unichar key)
{
- char str[3];
+ char str[20];
idle_time = time(NULL);
return;
}
- if (key >= 0 && key < 32) {
+ if (key < 32) {
/* control key */
str[0] = '^';
- str[1] = key+'@';
+ str[1] = (char)key+'@';
str[2] = '\0';
} else if (key == 127) {
str[0] = '^';
str[1] = '?';
str[2] = '\0';
- } else {
- str[0] = key;
+ } else if (!active_entry->utf8) {
+ str[0] = (char)key;
str[1] = '\0';
+ } else {
+ /* need to convert to utf8 */
+ str[utf16_char_to_utf8(key, str)] = '\0';
}
if (!key_pressed(keyboard, str)) {
/* key wasn't used for anything, print it */
- gui_entry_insert_char(active_entry, (char) key);
+ gui_entry_insert_char(active_entry, key);
}
}
char *str, *add_history;
str = gui_entry_get_text(active_entry);
- if (*str == '\0') return;
+ if (str == NULL || *str == '\0') {
+ g_free(str);
+ return;
+ }
/* we can't use gui_entry_get_text() later, since the entry might
have been destroyed after we get back */
if (active_entry != NULL)
gui_entry_set_text(active_entry, "");
command_history_clear_pos(active_win);
+
+ g_free(str);
}
static void key_combo(void)
static void key_backward_history(void)
{
const char *text;
+ char *line;
- text = command_history_prev(active_win, gui_entry_get_text(active_entry));
+ line = gui_entry_get_text(active_entry);
+ text = command_history_prev(active_win, line);
gui_entry_set_text(active_entry, text);
+ g_free(line);
}
static void key_forward_history(void)
{
const char *text;
+ char *line;
- text = command_history_next(active_win, gui_entry_get_text(active_entry));
+ line = gui_entry_get_text(active_entry);
+ text = command_history_next(active_win, line);
gui_entry_set_text(active_entry, text);
+ g_free(line);
}
static void key_beginning_of_line(void)
static void key_end_of_line(void)
{
- gui_entry_set_pos(active_entry, strlen(gui_entry_get_text(active_entry)));
+ gui_entry_set_pos(active_entry, active_entry->text_len);
}
static void key_backward_character(void)
static void key_erase_line(void)
{
- g_free_not_null(cutbuffer);
- cutbuffer = g_strdup(gui_entry_get_text(active_entry));
-
- gui_entry_set_text(active_entry, "");
+ gui_entry_set_pos(active_entry, active_entry->text_len);
+ gui_entry_erase(active_entry, active_entry->text_len);
}
static void key_erase_to_beg_of_line(void)
int pos;
pos = gui_entry_get_pos(active_entry);
- g_free_not_null(cutbuffer);
- cutbuffer = g_strndup(gui_entry_get_text(active_entry), pos);
-
gui_entry_erase(active_entry, pos);
}
int pos;
pos = gui_entry_get_pos(active_entry);
- g_free_not_null(cutbuffer);
- cutbuffer = g_strdup(gui_entry_get_text(active_entry)+pos);
-
- gui_entry_set_pos(active_entry, strlen(gui_entry_get_text(active_entry)));
- gui_entry_erase(active_entry, strlen(gui_entry_get_text(active_entry)) - pos);
+ gui_entry_set_pos(active_entry, active_entry->text_len);
+ gui_entry_erase(active_entry, active_entry->text_len - pos);
}
static void key_yank_from_cutbuffer(void)
{
+ char *cutbuffer;
+
+ cutbuffer = gui_entry_get_cutbuffer(active_entry);
if (cutbuffer != NULL)
gui_entry_insert_text(active_entry, cutbuffer);
}
static void key_transpose_characters(void)
{
- char *line, c;
- int pos;
-
- pos = gui_entry_get_pos(active_entry);
- line = gui_entry_get_text(active_entry);
- if (pos == 0 || strlen(line) < 2)
- return;
-
- if (line[pos] != '\0')
- gui_entry_move_pos(active_entry, 1);
- c = line[gui_entry_get_pos(active_entry)-1];
- gui_entry_erase(active_entry, 1);
- gui_entry_move_pos(active_entry, -1);
- gui_entry_insert_char(active_entry, c);
- gui_entry_set_pos(active_entry, pos);
- gui_entry_move_pos(active_entry, 1);
+ gui_entry_transpose_chars(active_entry);
}
static void key_delete_character(void)
{
- if (gui_entry_get_pos(active_entry) < (int)strlen(gui_entry_get_text(active_entry))) {
+ if (gui_entry_get_pos(active_entry) < active_entry->text_len) {
gui_entry_move_pos(active_entry, 1);
gui_entry_erase(active_entry, 1);
}
static void sig_input(void)
{
- unsigned char buffer[128];
+ unichar buffer[128];
int ret, i;
if (!active_entry) {
return;
}
- ret = term_gets(buffer, sizeof(buffer));
+ ret = term_gets(buffer, sizeof(buffer)/sizeof(buffer[0]));
if (ret == -1) {
/* lost terminal */
if (!term_detached)
static void key_completion(int erase)
{
- char *line;
+ char *text, *line;
int pos;
pos = gui_entry_get_pos(active_entry);
- line = word_complete(active_win, gui_entry_get_text(active_entry),
- &pos, erase);
+ text = gui_entry_get_text(active_entry);
+ line = word_complete(active_win, text, &pos, erase);
+ g_free(text);
+
if (line != NULL) {
gui_entry_set_text(active_entry, line);
gui_entry_set_pos(active_entry, pos);
static void key_check_replaces(void)
{
- char *line;
+ char *text, *line;
int pos;
pos = gui_entry_get_pos(active_entry);
- line = auto_word_complete(gui_entry_get_text(active_entry), &pos);
+ text = gui_entry_get_text(active_entry);
+ line = auto_word_complete(text, &pos);
+ g_free(text);
+
if (line != NULL) {
gui_entry_set_text(active_entry, line);
gui_entry_set_pos(active_entry, pos);
static void sig_window_auto_changed(void)
{
+ char *text;
+
if (active_entry == NULL)
return;
- command_history_next(active_win, gui_entry_get_text(active_entry));
+ text = gui_entry_get_text(active_entry);
+ command_history_next(active_win, text);
gui_entry_set_text(active_entry, "");
+ g_free(text);
}
static void sig_gui_entry_redirect(SIGNAL_FUNC func, const char *entry,
char *key, data[MAX_INT_STRLEN];
int n;
- cutbuffer = NULL;
redir = NULL;
idle_time = time(NULL);
input_listen_init(STDIN_FILENO);
key_bind("key", NULL, "^J", "return", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "^H", "backspace", (SIGNAL_FUNC) key_combo);
key_bind("key", NULL, "^?", "backspace", (SIGNAL_FUNC) key_combo);
+ key_bind("key", NULL, "^I", "tab", (SIGNAL_FUNC) key_combo);
/* meta */
key_bind("key", NULL, "^[", "meta", (SIGNAL_FUNC) key_combo);
key_bind("backward_character", "", "left", NULL, (SIGNAL_FUNC) key_backward_character);
key_bind("forward_character", "", "right", NULL, (SIGNAL_FUNC) key_forward_character);
key_bind("backward_word", "", "cleft", NULL, (SIGNAL_FUNC) key_backward_word);
+ key_bind("backward_word", NULL, "meta-b", NULL, (SIGNAL_FUNC) key_backward_word);
key_bind("forward_word", "", "cright", NULL, (SIGNAL_FUNC) key_forward_word);
+ key_bind("forward_word", NULL, "meta-f", NULL, (SIGNAL_FUNC) key_forward_word);
key_bind("backward_to_space", "", NULL, NULL, (SIGNAL_FUNC) key_backward_to_space);
key_bind("forward_to_space", "", NULL, NULL, (SIGNAL_FUNC) key_forward_to_space);
key_bind("beginning_of_line", "", "home", NULL, (SIGNAL_FUNC) key_beginning_of_line);
/* line transmitting */
key_bind("send_line", "Execute the input line", "return", NULL, (SIGNAL_FUNC) key_send_line);
- key_bind("word_completion", "", "^I", NULL, (SIGNAL_FUNC) key_word_completion);
+ key_bind("word_completion", "", "tab", NULL, (SIGNAL_FUNC) key_word_completion);
key_bind("erase_completion", "", "meta-k", NULL, (SIGNAL_FUNC) key_erase_completion);
key_bind("check_replaces", "Check word replaces", NULL, NULL, (SIGNAL_FUNC) key_check_replaces);
void gui_readline_deinit(void)
{
- g_free_not_null(cutbuffer);
input_listen_deinit();
key_configure_freeze();
gui->view = textbuffer_view_create(textbuffer_create(),
window->width, window->height,
settings_get_bool("scroll"),
- settings_get_bool("term_utf8"));
+ term_type == TERM_TYPE_UTF8);
textbuffer_view_set_default_indent(gui->view,
settings_get_int("indent"),
!settings_get_bool("indent_always"),
{
{ MODULE_NAME, "Text user interface", 0 },
+ /* ---- */
+ { NULL, "Lastlog", 0 },
+
{ "lastlog_too_long", "/LASTLOG would print $0 lines. If you really want to print all these lines use -force option.", 1, { 1 } },
{ "lastlog_count", "{hilight Lastlog}: $0 lines", 1, { 1 } },
{ "lastlog_start", "{hilight Lastlog}:", 0 },
{ "lastlog_end", "{hilight End of Lastlog}", 0 },
{ "lastlog_separator", "--", 0 },
+ /* ---- */
+ { NULL, "Windows", 0 },
+
{ "refnum_not_found", "Window number $0 not found", 1, { 0 } },
{ "window_too_small", "Not enough room to resize this window", 0 },
{ "cant_hide_last", "You can't hide the last window", 0 },
{ "window_scroll", "Window scroll mode is now $0", 1, { 0 } },
{ "window_scroll_unknown", "Unknown scroll mode $0, must be ON, OFF or DEFAULT", 1, { 0 } },
+ /* ---- */
+ { NULL, "Statusbars", 0 },
+
+ { "statusbar_list_header", "Name Type Placement Position Visible", 0 },
+ { "statusbar_list_footer", "", 0 },
+ { "statusbar_list", "$[30]0 $[6]1 $[9]2 $[8]3 $4", 5, { 0, 0, 0, 1, 0 } },
+ { "statusbar_info_name", "Statusbar: {hilight $0}", 1, { 0 } },
+ { "statusbar_info_type", "Type : $0", 1, { 0 } },
+ { "statusbar_info_placement", "Placement: $0", 1, { 0 } },
+ { "statusbar_info_position", "Position : $0", 1, { 1 } },
+ { "statusbar_info_visible", "Visible : $0", 1, { 0 } },
+ { "statusbar_info_item_header", "Items : Name Priority Alignment", 0 },
+ { "statusbar_info_item_footer", "", 0 },
+ { "statusbar_info_item_name", " : $[35]0 $[9]1 $2", 3, { 0, 1, 0 } },
+ { "statusbar_not_found", "Statusbar doesn't exist: $0", 1, { 0 } },
+ { "statusbar_not_found", "Statusbar doesn't exist: $0", 1, { 0 } },
+ { "statusbar_item_not_found", "Statusbar item doesn't exist: $0", 1, { 0 } },
+ { "statusbar_unknown_command", "Unknown statusbar command: $0", 1, { 0 } },
+ { "statusbar_unknown_type", "Statusbar type must be 'window' or 'root'", 1, { 0 } },
+ { "statusbar_unknown_placement", "Statusbar placement must be 'top' or 'bottom'", 1, { 0 } },
+ { "statusbar_unknown_visibility", "Statusbar visibility must be 'always', 'active' or 'inactive'", 1, { 0 } },
+
{ NULL, NULL, 0 }
};
enum {
TXT_MODULE_NAME,
+ TXT_FILL_1,
+
TXT_LASTLOG_TOO_LONG,
TXT_LASTLOG_COUNT,
TXT_LASTLOG_START,
TXT_LASTLOG_END,
TXT_LASTLOG_SEPARATOR,
+ TXT_FILL_2,
+
TXT_REFNUM_NOT_FOUND,
TXT_WINDOW_TOO_SMALL,
TXT_CANT_HIDE_LAST,
TXT_WINDOW_UNSET_STICKY,
TXT_WINDOW_INFO_STICKY,
TXT_WINDOW_SCROLL,
- TXT_WINDOW_SCROLL_UNKNOWN
+ TXT_WINDOW_SCROLL_UNKNOWN,
+
+ TXT_FILL_3,
+
+ TXT_STATUSBAR_LIST_HEADER,
+ TXT_STATUSBAR_LIST_FOOTER,
+ TXT_STATUSBAR_LIST,
+ TXT_STATUSBAR_INFO_NAME,
+ TXT_STATUSBAR_INFO_TYPE,
+ TXT_STATUSBAR_INFO_PLACEMENT,
+ TXT_STATUSBAR_INFO_POSITION,
+ TXT_STATUSBAR_INFO_VISIBLE,
+ TXT_STATUSBAR_INFO_ITEM_HEADER,
+ TXT_STATUSBAR_INFO_ITEM_FOOTER,
+ TXT_STATUSBAR_INFO_ITEM_NAME,
+ TXT_STATUSBAR_NOT_FOUND,
+ TXT_STATUSBAR_ITEM_NOT_FOUND,
+ TXT_STATUSBAR_UNKNOWN_COMMAND,
+ TXT_STATUSBAR_UNKNOWN_TYPE,
+ TXT_STATUSBAR_UNKNOWN_PLACEMENT,
+ TXT_STATUSBAR_UNKNOWN_VISIBILITY
};
extern FORMAT_REC gui_text_formats[];
#include "common.h"
+#include "term.h"
#define MODULE_NAME "fe-text"
*/
#include "module.h"
+#include "module-formats.h"
#include "signals.h"
+#include "commands.h"
#include "settings.h"
+#include "levels.h"
#include "lib-config/iconfig.h"
#include "statusbar.h"
+#include "printtext.h"
static void read_statusbar_config_from_node(CONFIG_NODE *node);
{
STATUSBAR_CONFIG_REC *bar;
GSList *tmp;
- int visible;
const char *visible_str;
bar = statusbar_config_find(group, node->key);
- visible = bar == NULL ? STATUSBAR_VISIBLE_ALWAYS : bar->visible;
-
- /* first make sure we want to see this statusbar */
- visible_str = config_node_get_str(node, "visible", "");
- if (strcmp(visible_str, "active") == 0)
- visible = STATUSBAR_VISIBLE_ACTIVE;
- else if (strcmp(visible_str, "inactive") == 0)
- visible = STATUSBAR_VISIBLE_INACTIVE;
- else if (strcmp(visible_str, "never") == 0) {
- /* we don't want this statusbar -
- destroy it if it already exists */
+ if (config_node_get_bool(node, "disabled", FALSE)) {
+ /* disabled, destroy it if it already exists */
if (bar != NULL)
statusbar_config_destroy(group, bar);
return;
bar->placement = STATUSBAR_BOTTOM;
bar->position = 0;
}
- bar->visible = visible;
- if (strcmp(config_node_get_str(node, "type", ""), "window") == 0)
+ visible_str = config_node_get_str(node, "visible", "");
+ if (g_strcasecmp(visible_str, "active") == 0)
+ bar->visible = STATUSBAR_VISIBLE_ACTIVE;
+ else if (g_strcasecmp(visible_str, "inactive") == 0)
+ bar->visible = STATUSBAR_VISIBLE_INACTIVE;
+ else
+ bar->visible = STATUSBAR_VISIBLE_ALWAYS;
+
+ if (g_strcasecmp(config_node_get_str(node, "type", ""), "window") == 0)
bar->type = STATUSBAR_TYPE_WINDOW;
- if (strcmp(config_node_get_str(node, "placement", ""), "top") == 0)
+ if (g_strcasecmp(config_node_get_str(node, "placement", ""), "top") == 0)
bar->placement = STATUSBAR_TOP;
bar->position = config_node_get_int(node, "position", 0);
read_statusbar_config_from_node(node);
create_root_statusbars();
+ statusbars_create_window_bars();
+}
+
+static const char *sbar_get_type(STATUSBAR_CONFIG_REC *rec)
+{
+ return rec->type == STATUSBAR_TYPE_ROOT ? "root" :
+ rec->type == STATUSBAR_TYPE_WINDOW ? "window" : "??";
+}
+
+static const char *sbar_get_placement(STATUSBAR_CONFIG_REC *rec)
+{
+ return rec->placement == STATUSBAR_TOP ? "top" :
+ rec->placement == STATUSBAR_BOTTOM ? "bottom" : "??";
+}
+
+static const char *sbar_get_visibility(STATUSBAR_CONFIG_REC *rec)
+{
+ return rec->visible == STATUSBAR_VISIBLE_ALWAYS ? "always" :
+ rec->visible == STATUSBAR_VISIBLE_ACTIVE ? "active" :
+ rec->visible == STATUSBAR_VISIBLE_INACTIVE ? "inactive" : "??";
+}
+
+static void statusbar_list_items(STATUSBAR_CONFIG_REC *bar)
+{
+ GSList *tmp;
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_ITEM_HEADER);
+
+ for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
+ SBAR_ITEM_CONFIG_REC *rec = tmp->data;
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_ITEM_NAME,
+ rec->name, rec->priority,
+ rec->right_alignment ? "right" : "left");
+ }
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_ITEM_FOOTER);
+}
+
+static void statusbar_print(STATUSBAR_CONFIG_REC *rec)
+{
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_NAME, rec->name);
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_TYPE, sbar_get_type(rec));
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_PLACEMENT,
+ sbar_get_placement(rec));
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_POSITION, rec->position);
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_INFO_VISIBLE,
+ sbar_get_visibility(rec));
+
+ if (rec->items != NULL)
+ statusbar_list_items(rec);
+}
+
+static void cmd_statusbar_list(void)
+{
+ GSList *tmp;
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_STATUSBAR_LIST_HEADER);
+
+ tmp = active_statusbar_group->config_bars;
+ for (; tmp != NULL; tmp = tmp->next) {
+ STATUSBAR_CONFIG_REC *rec = tmp->data;
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP,
+ TXT_STATUSBAR_LIST, rec->name, sbar_get_type(rec),
+ sbar_get_placement(rec), rec->position,
+ sbar_get_visibility(rec));
+ }
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_STATUSBAR_LIST_FOOTER);
+}
+
+static void cmd_statusbar_print_info(const char *name)
+{
+ GSList *tmp;
+
+ tmp = active_statusbar_group->config_bars;
+ for (; tmp != NULL; tmp = tmp->next) {
+ STATUSBAR_CONFIG_REC *rec = tmp->data;
+
+ if (g_strcasecmp(rec->name, name) == 0) {
+ statusbar_print(rec);
+ return;
+ }
+ }
+
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_STATUSBAR_NOT_FOUND, name);
+}
+
+/* SYNTAX: STATUSBAR <name> ENABLE */
+static void cmd_statusbar_enable(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ iconfig_node_set_str(node, "disabled", NULL);
+}
+
+/* SYNTAX: STATUSBAR <name> DISABLE */
+static void cmd_statusbar_disable(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ iconfig_node_set_bool(node, "disabled", TRUE);
+}
+
+/* SYNTAX: STATUSBAR <name> RESET */
+static void cmd_statusbar_reset(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ CONFIG_NODE *parent;
+
+ parent = iconfig_node_traverse("statusbar", TRUE);
+ parent = config_node_section(parent, active_statusbar_group->name,
+ NODE_TYPE_BLOCK);
+
+ iconfig_node_set_str(parent, node->key, NULL);
+}
+
+/* SYNTAX: STATUSBAR <name> TYPE window|root */
+static void cmd_statusbar_type(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ if (g_strcasecmp(data, "window") == 0)
+ iconfig_node_set_str(node, "type", "window");
+ else if (g_strcasecmp(data, "root") == 0)
+ iconfig_node_set_str(node, "type", "root");
+ else {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_STATUSBAR_UNKNOWN_TYPE, data);
+ }
+}
+
+/* SYNTAX: STATUSBAR <name> PLACEMENT top|bottom */
+static void cmd_statusbar_placement(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ if (g_strcasecmp(data, "top") == 0)
+ iconfig_node_set_str(node, "placement", "top");
+ else if (g_strcasecmp(data, "bottom") == 0)
+ iconfig_node_set_str(node, "placement", "bottom");
+ else {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_STATUSBAR_UNKNOWN_PLACEMENT, data);
+ }
+}
+
+/* SYNTAX: STATUSBAR <name> POSITION <num> */
+static void cmd_statusbar_position(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ iconfig_node_set_int(node, "position", atoi(data));
+}
+
+/* SYNTAX: STATUSBAR <name> VISIBLE always|active|inactive */
+static void cmd_statusbar_visible(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ if (g_strcasecmp(data, "always") == 0)
+ iconfig_node_set_str(node, "visible", "always");
+ else if (g_strcasecmp(data, "active") == 0)
+ iconfig_node_set_str(node, "visible", "active");
+ else if (g_strcasecmp(data, "inactive") == 0)
+ iconfig_node_set_str(node, "visible", "inactive");
+ else {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_STATUSBAR_UNKNOWN_VISIBILITY, data);
+ }
+}
+
+static CONFIG_NODE *statusbar_items_section(CONFIG_NODE *parent)
+{
+ STATUSBAR_CONFIG_REC *bar;
+ CONFIG_NODE *node;
+ GSList *tmp;
+
+ node = config_node_section(parent, "items", -1);
+ if (node != NULL)
+ return node;
+
+ /* find the statusbar configuration from memory */
+ bar = statusbar_config_find(active_statusbar_group, parent->key);
+ if (bar == NULL) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_STATUSBAR_NOT_FOUND, parent->key);
+ return NULL;
+ }
+
+ /* since items list in config file overrides defaults,
+ we'll need to copy the whole list. */
+ parent = config_node_section(parent, "items", NODE_TYPE_BLOCK);
+ for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
+ SBAR_ITEM_CONFIG_REC *rec = tmp->data;
+
+ node = config_node_section(parent, rec->name,
+ NODE_TYPE_BLOCK);
+ if (rec->priority != 0)
+ iconfig_node_set_int(node, "priority", rec->priority);
+ if (rec->right_alignment)
+ iconfig_node_set_str(node, "alignment", "right");
+ }
+
+ return parent;
+}
+
+/* SYNTAX: STATUSBAR <name> ADD [-before | -after <item>]
+ [-priority #] [-alignment left|right] <item> */
+static void cmd_statusbar_add(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ GHashTable *optlist;
+ char *name, *value;
+ void *free_arg;
+ int index;
+
+ node = statusbar_items_section(node);
+ if (node == NULL)
+ return;
+
+ if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
+ "statusbar add", &optlist, &name))
+ return;
+
+ /* get the index */
+ index = -1;
+ value = g_hash_table_lookup(optlist, "before");
+ if (value != NULL) index = config_node_index(node, value);
+ value = g_hash_table_lookup(optlist, "after");
+ if (value != NULL) index = config_node_index(node, value)+1;
+
+ /* create/move item */
+ node = config_node_section_index(node, name, index, NODE_TYPE_BLOCK);
+
+ /* set the options */
+ value = g_hash_table_lookup(optlist, "priority");
+ if (value != NULL) iconfig_node_set_int(node, "priority", atoi(value));
+
+ value = g_hash_table_lookup(optlist, "alignment");
+ if (value != NULL) {
+ iconfig_node_set_str(node, "alignment",
+ g_strcasecmp(value, "right") == 0 ?
+ "right" : NULL);
+ }
+
+ cmd_params_free(free_arg);
+}
+
+/* SYNTAX: STATUSBAR <name> REMOVE <item> */
+static void cmd_statusbar_remove(const char *data, void *server,
+ void *item, CONFIG_NODE *node)
+{
+ node = statusbar_items_section(node);
+ if (node == NULL)
+ return;
+
+ if (config_node_section(node, data, -1) != NULL)
+ iconfig_node_set_str(node, data, NULL);
+ else {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_STATUSBAR_ITEM_NOT_FOUND, data);
+ }
+}
+
+static void cmd_statusbar(const char *data)
+{
+ CONFIG_NODE *node;
+ char *name, *cmd, *params, *signal;
+ void *free_arg;
+
+ if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST,
+ &name, &cmd, ¶ms))
+ return;
+
+ if (*name == '\0') {
+ /* list all statusbars */
+ cmd_statusbar_list();
+ cmd_params_free(free_arg);
+ return;
+ }
+
+ if (*cmd == '\0') {
+ /* print statusbar info */
+ cmd_statusbar_print_info(name);
+ cmd_params_free(free_arg);
+ return;
+ }
+
+ /* lookup/create the statusbar node */
+ node = iconfig_node_traverse("statusbar", TRUE);
+ node = config_node_section(node, active_statusbar_group->name,
+ NODE_TYPE_BLOCK);
+ node = config_node_section(node, name, NODE_TYPE_BLOCK);
+
+ /* call the subcommand */
+ signal = g_strconcat("command statusbar ", cmd, NULL);
+ g_strdown(signal);
+ if (!signal_emit(signal, 4, params, NULL, NULL, node)) {
+ printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
+ TXT_STATUSBAR_UNKNOWN_COMMAND, cmd);
+ } else {
+ read_statusbar_config();
+ }
+ g_free(signal);
+
+ cmd_params_free(free_arg);
}
void statusbar_config_init(void)
{
read_statusbar_config();
- signal_add("setup reread", (SIGNAL_FUNC) read_statusbar_config);
+ signal_add_last("setup reread", (SIGNAL_FUNC) read_statusbar_config);
+ signal_add("theme changed", (SIGNAL_FUNC) read_statusbar_config);
+
+ command_bind("statusbar", NULL, (SIGNAL_FUNC) cmd_statusbar);
+ command_bind("statusbar enable", NULL, (SIGNAL_FUNC) cmd_statusbar_enable);
+ command_bind("statusbar disable", NULL, (SIGNAL_FUNC) cmd_statusbar_disable);
+ command_bind("statusbar reset", NULL, (SIGNAL_FUNC) cmd_statusbar_reset);
+ command_bind("statusbar add", NULL, (SIGNAL_FUNC) cmd_statusbar_add);
+ command_bind("statusbar remove", NULL, (SIGNAL_FUNC) cmd_statusbar_remove);
+ command_bind("statusbar type", NULL, (SIGNAL_FUNC) cmd_statusbar_type);
+ command_bind("statusbar placement", NULL, (SIGNAL_FUNC) cmd_statusbar_placement);
+ command_bind("statusbar position", NULL, (SIGNAL_FUNC) cmd_statusbar_position);
+ command_bind("statusbar visible", NULL, (SIGNAL_FUNC) cmd_statusbar_visible);
+
+ command_set_options("statusbar add", "+before +after +priority +alignment");
}
void statusbar_config_deinit(void)
{
signal_remove("setup reread", (SIGNAL_FUNC) read_statusbar_config);
+ signal_remove("theme changed", (SIGNAL_FUNC) read_statusbar_config);
+
+ command_unbind("statusbar", (SIGNAL_FUNC) cmd_statusbar);
+ command_unbind("statusbar enable", (SIGNAL_FUNC) cmd_statusbar_enable);
+ command_unbind("statusbar disable", (SIGNAL_FUNC) cmd_statusbar_disable);
+ command_unbind("statusbar reset", (SIGNAL_FUNC) cmd_statusbar_reset);
+ command_unbind("statusbar add", (SIGNAL_FUNC) cmd_statusbar_add);
+ command_unbind("statusbar remove", (SIGNAL_FUNC) cmd_statusbar_remove);
+ command_unbind("statusbar type", (SIGNAL_FUNC) cmd_statusbar_type);
+ command_unbind("statusbar placement", (SIGNAL_FUNC) cmd_statusbar_placement);
+ command_unbind("statusbar position", (SIGNAL_FUNC) cmd_statusbar_position);
+ command_unbind("statusbar visible", (SIGNAL_FUNC) cmd_statusbar_visible);
}
{
GUI_ENTRY_REC *rec;
- rec = g_hash_table_lookup(input_entries, item);
+ rec = g_hash_table_lookup(input_entries, item->bar);
if (rec == NULL) {
rec = gui_entry_create(item->xpos, item->bar->real_ypos,
- item->size,
- settings_get_bool("term_utf8"));
+ item->size, term_type == TERM_TYPE_UTF8);
gui_entry_set_active(rec);
- g_hash_table_insert(input_entries, item, rec);
+ g_hash_table_insert(input_entries, item->bar, rec);
}
if (get_size_only) {
gui_entry_redraw(rec); /* FIXME: this is only necessary with ^L.. */
}
-static void sig_statusbar_item_destroyed(SBAR_ITEM_REC *item)
+static void sig_statusbar_destroyed(STATUSBAR_REC *bar)
{
GUI_ENTRY_REC *rec;
- rec = g_hash_table_lookup(input_entries, item);
+ rec = g_hash_table_lookup(input_entries, bar);
if (rec != NULL) {
gui_entry_destroy(rec);
- g_hash_table_remove(input_entries, item);
+ g_hash_table_remove(input_entries, bar);
}
}
static void read_settings(void)
{
- if (active_entry != NULL) {
- gui_entry_set_utf8(active_entry,
- settings_get_bool("term_utf8"));
- }
+ if (active_entry != NULL)
+ gui_entry_set_utf8(active_entry, term_type == TERM_TYPE_UTF8);
}
void statusbar_items_init(void)
/* input */
input_entries = g_hash_table_new((GHashFunc) g_direct_hash,
(GCompareFunc) g_direct_equal);
- signal_add("statusbar item destroyed", (SIGNAL_FUNC) sig_statusbar_item_destroyed);
+ signal_add("statusbar destroyed", (SIGNAL_FUNC) sig_statusbar_destroyed);
read_settings();
- signal_add("setup changed", (SIGNAL_FUNC) read_settings);
+ signal_add_last("setup changed", (SIGNAL_FUNC) read_settings);
}
void statusbar_items_deinit(void)
g_source_remove(lag_timeout_tag);
/* input */
- signal_remove("statusbar item destroyed", (SIGNAL_FUNC) sig_statusbar_item_destroyed);
+ signal_remove("statusbar destroyed", (SIGNAL_FUNC) sig_statusbar_destroyed);
g_hash_table_destroy(input_entries);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}
#define SBAR_ITEM_REDRAW_NEEDED(_bar, _item, _xpos) \
- (((_bar)->dirty_xpos != -1 && \
- (_xpos) >= (_bar)->dirty_xpos) || \
+ (((_bar)->dirty_xpos != -1 && (_xpos) >= (_bar)->dirty_xpos) || \
(_item)->xpos != (_xpos) || (_item)->current_size != (_item)->size)
static void statusbar_calc_item_positions(STATUSBAR_REC *bar)
if (rec->config->right_alignment) {
if (rec->size > 0)
right_items = g_slist_prepend(right_items, rec);
- else if (rec->current_size > 0) {
+ else if (rec->current_size > 0 &&
+ (bar->dirty_xpos == -1 ||
+ rec->xpos < bar->dirty_xpos)) {
/* item was hidden - set the dirty position
to begin from the item's old xpos */
irssi_set_dirty();
g_slist_free(value);
}
-static void sig_setup_reload(void)
+void statusbars_create_window_bars(void)
{
- /* statusbar-config.c recreates root statusbars,
- we need to create window-statusbars */
g_slist_foreach(mainwindows, (GFunc) statusbars_add_visible, NULL);
}
signal_add("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
signal_add("window changed", (SIGNAL_FUNC) sig_window_changed);
signal_add("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
- signal_add_last("setup reread", (SIGNAL_FUNC) sig_setup_reload);
statusbar_items_init();
statusbar_config_init(); /* signals need to be before this call */
signal_remove("gui window created", (SIGNAL_FUNC) sig_gui_window_created);
signal_remove("window changed", (SIGNAL_FUNC) sig_window_changed);
signal_remove("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed);
- signal_remove("setup reread", (SIGNAL_FUNC) sig_setup_reload);
statusbar_items_deinit();
statusbar_config_deinit();
void statusbar_recreate_items(STATUSBAR_REC *bar);
void statusbars_recreate_items(void);
+void statusbars_create_window_bars(void);
void statusbar_redraw_dirty(void);
};
TERM_WINDOW *root_window;
-int term_width, term_height;
static int curs_x, curs_y;
static int freeze_refresh;
waddch(window->win, chr);
}
+void term_add_unichar(TERM_WINDOW *window, unichar chr)
+{
+ waddch(window->win, chr);
+}
+
void term_addstr(TERM_WINDOW *window, const char *str)
{
waddstr(window->win, (const char *) str);
irssi_redraw();
}
-int term_gets(unsigned char *buffer, int size)
+void term_auto_detach(int set)
+{
+}
+
+void term_set_input_type(int type)
+{
+}
+
+int term_gets(unichar *buffer, int size)
{
int key, count;
#include "signals.h"
#include "term.h"
#include "terminfo-core.h"
+#include "utf8.h"
#include <signal.h>
+/* returns number of characters in the beginning of the buffer being a
+ a single character, or -1 if more input is needed. The character will be
+ saved in result */
+typedef int (*TERM_INPUT_FUNC)(const unsigned char *buffer, int size,
+ unichar *result);
+
struct _TERM_WINDOW {
/* Terminal to use for window */
TERM_REC *term;
};
TERM_WINDOW *root_window;
-int term_width, term_height, term_detached;
static char *term_lines_empty; /* 1 if line is entirely empty */
static int vcmove, vcx, vcy, curs_visible;
static int redraw_needed, redraw_tag;
static int freeze_counter;
+static TERM_INPUT_FUNC input_func;
+static unsigned char term_inbuf[256];
+static int term_inbuf_pos;
+
/* SIGCONT handler */
static void sig_cont(int p)
{
term_lines_empty = g_new0(char, term_height);
+ term_set_input_type(TERM_TYPE_8BIT);
term_common_init();
g_atexit(term_deinit);
return TRUE;
putc(chr, window->term->out);
}
+static void term_addch_utf8(TERM_WINDOW *window, unichar chr)
+{
+ unsigned char buf[10];
+ int i, len;
+
+ len = utf16_char_to_utf8(chr, buf);
+ for (i = 0; i < len; i++)
+ putc(buf[i], window->term->out);
+}
+
+void term_add_unichar(TERM_WINDOW *window, unichar chr)
+{
+ if (term_detached) return;
+
+ if (vcmove) term_move_real();
+ term_printed_text(1);
+ if (vcy == term_height && vcx == 0)
+ return; /* last char in screen */
+
+ switch (term_type) {
+ case TERM_TYPE_UTF8:
+ term_addch_utf8(window, chr);
+ break;
+ case TERM_TYPE_BIG5:
+ putc((chr >> 8) & 0xff, window->term->out);
+ putc((chr & 0xff), window->term->out);
+ break;
+ default:
+ putc(chr, window->term->out);
+ break;
+ }
+}
+
void term_addstr(TERM_WINDOW *window, const char *str)
{
int len;
}
}
-int term_gets(unsigned char *buffer, int size)
+static int input_utf8(const unsigned char *buffer, int size, unichar *result)
+{
+ const unsigned char *end = buffer;
+
+ *result = get_utf8_char(&end, size);
+ switch (*result) {
+ case (unichar) -2:
+ /* not UTF8 - fallback to 8bit ascii */
+ *result = *buffer;
+ return 1;
+ case (unichar) -1:
+ /* need more data */
+ return -1;
+ default:
+ return (int) (end-buffer)+1;
+ }
+}
+
+/* XXX I didn't check the encoding range of big5+. This is standard big5. */
+#define is_big5_los(lo) (0x40 <= (lo) && (lo) <= 0x7E) /* standard */
+#define is_big5_lox(lo) (0x80 <= (lo) && (lo) <= 0xFE) /* extended */
+#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE)
+#define is_big5(hi,lo) (is_big5_hi(hi) && (is_big5_los(lo) || is_big5_lox(lo)))
+
+static int input_big5(const unsigned char *buffer, int size, unichar *result)
+{
+ if (is_big5_hi(*buffer)) {
+ /* could be */
+ if (size == 1)
+ return -1;
+
+ if (is_big5_los(buffer[1]) || is_big5_lox(buffer[1])) {
+ *result = buffer[1] + ((int) *buffer << 8);
+ return 2;
+ }
+ }
+
+ *result = *buffer;
+ return 1;
+}
+
+static int input_8bit(const unsigned char *buffer, int size, unichar *result)
{
- int ret;
+ *result = *buffer;
+ return 1;
+}
+
+void term_set_input_type(int type)
+{
+ switch (type) {
+ case TERM_TYPE_UTF8:
+ input_func = input_utf8;
+ break;
+ case TERM_TYPE_BIG5:
+ input_func = input_big5;
+ break;
+ default:
+ input_func = input_8bit;
+ }
+}
+
+int term_gets(unichar *buffer, int size)
+{
+ int ret, i, char_len;
if (term_detached)
return 0;
/* fread() doesn't work */
- ret = read(fileno(current_term->in), buffer, size);
+ if (size > sizeof(term_inbuf)-term_inbuf_pos)
+ size = sizeof(term_inbuf)-term_inbuf_pos;
+
+ ret = read(fileno(current_term->in),
+ term_inbuf + term_inbuf_pos, size);
if (ret == 0) {
/* EOF - terminal got lost */
if (auto_detach)
} else if (ret == -1 && (errno == EINTR || errno == EAGAIN))
ret = 0;
+ if (ret > 0) {
+ /* convert input to unichars. */
+ term_inbuf_pos += ret;
+ ret = 0;
+ for (i = 0; i < term_inbuf_pos; ) {
+ char_len = input_func(term_inbuf+i, term_inbuf_pos-i,
+ buffer);
+ if (char_len < 0)
+ break;
+
+ i += char_len;
+ buffer++;
+ ret++;
+ }
+
+ if (i >= term_inbuf_pos)
+ term_inbuf_pos = 0;
+ else {
+ memmove(term_inbuf+i, term_inbuf, term_inbuf_pos-i);
+ term_inbuf_pos = i;
+ }
+ }
+
return ret;
}
#include "term.h"
#include "mainwindows.h"
+#ifdef HAVE_NL_LANGINFO
+# include <locale.h>
+# include <langinfo.h>
+#endif
+
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#define MIN_SCREEN_WIDTH 20
+int term_width, term_height, term_detached;
+
int term_use_colors;
+int term_type;
static int force_colors;
static int resize_dirty;
static void read_settings(void)
{
+ const char *str;
int old_colors = term_use_colors;
+ int old_type = term_type;
term_auto_detach(settings_get_bool("term_auto_detach"));
+ /* set terminal type */
+ str = settings_get_str("term_type");
+ if (g_strcasecmp(str, "utf-8") == 0)
+ term_type = TERM_TYPE_UTF8;
+ else if (g_strcasecmp(str, "big5") == 0)
+ term_type = TERM_TYPE_BIG5;
+ else
+ term_type = TERM_TYPE_8BIT;
+
+ if (old_type != term_type)
+ term_set_input_type(term_type);
+
+ /* change color stuff */
if (force_colors != settings_get_bool("term_force_colors")) {
force_colors = settings_get_bool("term_force_colors");
term_force_colors(force_colors);
settings_add_bool("lookandfeel", "colors", TRUE);
settings_add_bool("lookandfeel", "term_force_colors", FALSE);
settings_add_bool("lookandfeel", "term_auto_detach", FALSE);
- settings_add_bool("lookandfeel", "term_utf8", FALSE);
+ settings_add_str("lookandfeel", "term_type", "8bit");
force_colors = FALSE;
term_use_colors = term_has_colors() && settings_get_bool("colors");
read_settings();
+#if defined (HAVE_NL_LANGINFO) && defined(CODESET)
+ setlocale(LC_CTYPE, "");
+ if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
+ term_type = TERM_TYPE_UTF8;
+ term_set_input_type(TERM_TYPE_UTF8);
+ }
+#endif
+
signal_add("beep", (SIGNAL_FUNC) term_beep);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
command_bind("resize", NULL, (SIGNAL_FUNC) cmd_resize);
typedef struct _TERM_WINDOW TERM_WINDOW;
+/* text attributes */
#define ATTR_RESETFG 0x0100
#define ATTR_RESETBG 0x0200
#define ATTR_BOLD 0x0400
#define ATTR_NOCOLORS (ATTR_UNDERLINE|ATTR_REVERSE)
-#ifdef WANT_BIG5
-/* XXX I didn't check the encoding range of big5+. This is standard big5. */
-# define is_big5_los(lo) (((char)0x40<=lo)&&(lo<=(char)0x7E)) /* standard */
-# define is_big5_lox(lo) (((char)0x80<=lo)&&(lo<=(char)0xFE)) /* extended */
-# define is_big5_hi(hi) (((char)0x81<=hi)&&(hi<=(char)0xFE))
-# define is_big5(hi,lo) is_big5_hi(hi) && (is_big5_los(lo) || is_big5_lox(lo))
-#endif
+/* terminal types */
+#define TERM_TYPE_8BIT 0 /* normal 8bit text */
+#define TERM_TYPE_UTF8 1
+#define TERM_TYPE_BIG5 2
+
+typedef guint32 unichar;
extern TERM_WINDOW *root_window;
-extern int term_width, term_height, term_use_colors, term_detached;
+extern int term_width, term_height;
+extern int term_use_colors, term_type, term_detached;
/* Initialize / deinitialize terminal */
int term_init(void);
void term_move(TERM_WINDOW *window, int x, int y);
void term_addch(TERM_WINDOW *window, int chr);
+void term_add_unichar(TERM_WINDOW *window, unichar chr);
void term_addstr(TERM_WINDOW *window, const char *str);
void term_clrtoeol(TERM_WINDOW *window);
void term_attach(FILE *in, FILE *out);
void term_stop(void);
-int term_gets(unsigned char *buffer, int size);
+
+/* keyboard input handling */
+void term_set_input_type(int type);
+int term_gets(unichar *buffer, int size);
/* internal */
void term_common_init(void);
}
if (view->utf8)
- get_utf8_char(&ptr);
+ get_utf8_char(&ptr, 6);
xpos++;
if (*ptr++ == ' ') {
if (xpos < term_width) {
const unsigned char *end = text;
if (view->utf8)
- get_utf8_char(&end);
+ get_utf8_char(&end, 6);
if (*text >= 32 &&
(end != text || (*text & 127) >= 32)) {
textbuffer_line_ref(line);
matches = g_list_append(matches, line);
- if (!line_matched && --match_after == 0)
+ if ((!line_matched && --match_after == 0) ||
+ (line_matched && match_after == 0 && before > 0))
matches = g_list_append(matches, NULL);
}
}
+/* utf8.c - Operations on UTF-8 strings.
+ *
+ * Copyright (C) 2002 Timo Sirainen
+ *
+ * Based on GLib code by
+ *
+ * Copyright (C) 1999 Tom Tromey
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "module.h"
#define UTF8_COMPUTE(Char, Mask, Len) \
if (Char < 128) \
(Result) |= ((Chars)[(Count)] & 0x3f); \
}
-void get_utf8_char(const unsigned char **ptr)
+unichar get_utf8_char(const unsigned char **ptr, int len)
{
- int i, mask = 0, len;
- unsigned int result;
- unsigned char c = (unsigned char) **ptr;
+ int i, result, mask, chrlen;
+
+ mask = 0;
+ UTF8_COMPUTE(**ptr, mask, chrlen);
+ if (chrlen == -1)
+ return (unichar) -2;
- UTF8_COMPUTE(c, mask, len);
- if (len == -1)
- return;
+ if (chrlen > len)
+ return (unichar) -1;
- UTF8_GET(result, *ptr, i, mask, len);
+ UTF8_GET(result, *ptr, i, mask, chrlen);
if (result == -1)
- return;
+ return (unichar) -2;
+
+ *ptr += chrlen-1;
+ return result;
+}
+
+int strlen_utf8(const char *str)
+{
+ const unsigned char *p = (const unsigned char *) str;
+ int len;
+
+ len = 0;
+ while (*p != '\0' && get_utf8_char(&p, 6) > 0) {
+ len++;
+ p++;
+ }
+ return len;
+}
+
+int utf16_char_to_utf8(unichar c, char *outbuf)
+{
+ int len, i, first;
+
+ len = 0;
+ if (c < 0x80) {
+ first = 0;
+ len = 1;
+ } else if (c < 0x800) {
+ first = 0xc0;
+ len = 2;
+ } else if (c < 0x10000) {
+ first = 0xe0;
+ len = 3;
+ } else if (c < 0x200000) {
+ first = 0xf0;
+ len = 4;
+ } else if (c < 0x4000000) {
+ first = 0xf8;
+ len = 5;
+ } else {
+ first = 0xfc;
+ len = 6;
+ }
+
+ if (outbuf) {
+ for (i = len - 1; i > 0; --i) {
+ outbuf[i] = (c & 0x3f) | 0x80;
+ c >>= 6;
+ }
+ outbuf[0] = c | first;
+ }
+
+ return len;
+}
+
+void utf8_to_utf16(const char *str, unichar *out)
+{
+ const unsigned char *p = (const unsigned char *) str;
+ int i, result, mask, len;
+
+ while (*p != '\0') {
+ mask = 0;
+ UTF8_COMPUTE(*p, mask, len);
+ if (len == -1)
+ break;
+
+ UTF8_GET(result, p, i, mask, len);
+ if (result == -1)
+ break;
+
+ p += len;
+ *out++ = result;
+ }
+
+ *out = '\0';
+}
+
+void utf16_to_utf8(const unichar *str, char *out)
+{
+ int len;
+
+ while (*str != '\0') {
+ len = utf16_char_to_utf8(*str, out);
+ out += len;
- *ptr += len-1;
+ str++;
+ }
+ *out = '\0';
}
#ifndef __UTF8_H
#define __UTF8_H
-void get_utf8_char(const unsigned char **ptr);
+/* Returns -2 = invalid, -1 = need more data, otherwise unichar. */
+unichar get_utf8_char(const unsigned char **ptr, int len);
+
+/* Returns length of UTF8 string */
+int strlen_utf8(const char *str);
+
+/* UTF-8 -> unichar string. The NUL is copied as well. */
+void utf8_to_utf16(const char *str, unichar *out);
+
+/* unichar -> UTF-8 string. outbuf must be at least 6 chars long.
+ Returns outbuf string length. */
+int utf16_char_to_utf8(unichar c, char *outbuf);
+
+/* unichar -> UTF-8 string. The NUL is copied as well.
+ Make sure out is at least 6 x length of str. */
+void utf16_to_utf8(const unichar *str, char *out);
#endif
/* find the section from node - if not found create it unless new_type is -1.
you can also specify in new_type if it's NODE_TYPE_LIST or NODE_TYPE_BLOCK */
CONFIG_NODE *config_node_section(CONFIG_NODE *parent, const char *key, int new_type)
+{
+ return config_node_section_index(parent, key, -1, new_type);
+}
+
+CONFIG_NODE *config_node_section_index(CONFIG_NODE *parent, const char *key,
+ int index, int new_type)
{
CONFIG_NODE *node;
+ int nindex;
g_return_val_if_fail(parent != NULL, NULL);
g_return_val_if_fail(is_node_list(parent), NULL);
node = key == NULL ? NULL : config_node_find(parent, key);
if (node != NULL) {
g_return_val_if_fail(new_type == -1 || new_type == node->type, NULL);
- return node;
+ nindex = g_slist_index(parent->value, node);
+ if (index >= 0 && nindex != index &&
+ nindex <= g_slist_length(parent->value)) {
+ /* move it to wanted position */
+ parent->value = g_slist_remove(parent->value, node);
+ parent->value = g_slist_insert(parent->value, node, index);
+ }
+ return node;
}
if (new_type == -1)
return NULL;
node = g_new0(CONFIG_NODE, 1);
- parent->value = g_slist_append(parent->value, node);
+ parent->value = index < 0 ? g_slist_append(parent->value, node) :
+ g_slist_insert(parent->value, node, index);
node->type = new_type;
node->key = key == NULL ? NULL : g_strdup(key);
}
/* Returns n'th node from list. */
-CONFIG_NODE *config_node_index(CONFIG_NODE *node, int index)
+CONFIG_NODE *config_node_nth(CONFIG_NODE *node, int index)
{
GSList *tmp;
return NULL;
}
+/* Returns index for given key */
+int config_node_index(CONFIG_NODE *parent, const char *key)
+{
+ CONFIG_NODE *node;
+
+ g_return_val_if_fail(parent != NULL, -1);
+ g_return_val_if_fail(key != NULL, -1);
+
+ node = config_node_find(parent, key);
+ if (node == NULL)
+ return -1;
+
+ return g_slist_index(parent->value, node);
+}
+
/* Returns the first non-comment node in list */
GSList *config_node_first(GSList *list)
{
/* Like config_list_find(), but return node instead of it's value */
CONFIG_NODE *config_list_find_node(CONFIG_REC *rec, const char *section, const char *key, const char *value, const char *value_key);
/* Returns n'th node from list. */
-CONFIG_NODE *config_node_index(CONFIG_NODE *node, int index);
+CONFIG_NODE *config_node_nth(CONFIG_NODE *node, int index);
+/* Returns index for given key */
+int config_node_index(CONFIG_NODE *parent, const char *key);
/* Returns the first non-comment node in list */
GSList *config_node_first(GSList *list);
/* Find the section from node - if not found create it unless new_type is -1.
You can also specify in new_type if it's NODE_TYPE_LIST or NODE_TYPE_BLOCK */
CONFIG_NODE *config_node_section(CONFIG_NODE *parent, const char *key, int new_type);
+CONFIG_NODE *config_node_section_index(CONFIG_NODE *parent, const char *key,
+ int index, int new_type);
/* Find the section with the whole path.
Create the path if necessary `create' is TRUE. */
CONFIG_NODE *config_node_traverse(CONFIG_REC *rec, const char *section, int create);
g_return_if_fail(node != NULL);
g_return_if_fail(is_node_list(node));
- child = config_node_index(node, index);
+ child = config_node_nth(node, index);
if (child != NULL) config_node_remove(rec, node, child);
}
fprintf(f, POPT_("Usage:"));
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
fn = con->optionStack->argv[0];
- if (strchr(fn, '/')) fn = strchr(fn, '/') + 1;
+ if (strrchr(fn, '/')) fn = strrchr(fn, '/') + 1;
fprintf(f, " %s", fn);
len += strlen(fn) + 1;
}
{ "message irc own_notice", { "iobject", "string", "string", NULL } },
{ "message irc notice", { "iobject", "string", "string", "string", "string", NULL } },
{ "message irc own_ctcp", { "iobject", "string", "string", "string", NULL } },
- { "message irc ctcp", { "iobject", "string", "string", "string", "string", NULL } },
+ { "message irc ctcp", { "iobject", "string", "string", "string", "string", "string", NULL } },
{ "message dcc own", { "siobject", "string", NULL } },
{ "message dcc own_action", { "siobject", "string", NULL } },
{ "message dcc own_ctcp", { "siobject", "string", "string", NULL } },
Irssi::UI::Window window
int level
+void
+window_activity(window, data_level, hilight_color=NULL)
+ Irssi::UI::Window window
+ int data_level
+ char *hilight_color
+
char *
window_get_active_name(window)
Irssi::UI::Window window
Irssi::Windowitem item
CODE:
window_item_set_active(window_item_window(item), item);
+
+void
+window_item_activity(item, data_level, hilight_color=NULL)
+ Irssi::Windowitem item
+ int data_level
+ char *hilight_color
+
<!--
@LIBRARY=SILC Core Library
@FILENAME=silccorelib.html
-@LINK=silcauth.html:SILC Auth API
-@LINK=silcchannel.html:SILC Channel API
-@LINK=silccommand.html:SILC Command API
-@LINK=silcid.html:SILC ID API
-@LINK=silcidcache.html:SILC ID Cache API
+@LINK=silcauth.html:SILC Authentication Interface
+@LINK=silcchannel.html:SILC Channel Interface
+@LINK=silccommand.html:SILC Command Interface
+@LINK=silcid.html:SILC ID Interface
+@LINK=silcidcache.html:SILC ID Cache Interface
@LINK=silcmode.html:SILC Modes
-@LINK=silcnotify.html:SILC Notify API
-@LINK=silcpacket.html:SILC Packet API
-@LINK=silcargument.html:SILC Argument API
-@LINK=silcprivate.html:SILC Private API
+@LINK=silcnotify.html:SILC Notify Interface
+@LINK=silcargument.html:SILC Argument Interface
+@LINK=silcprivate.html:SILC Private Message Interface
+@LINK=silcpacket.html:Packet Protocol Interface
-->
<BIG><B>SILC Core Library</B></BIG>
*
* DESCRIPTION
*
- * Implementation of the Arugment Payload, that is used to include
+ * Implementation of the Argument Payload, that is used to include
* argument to other payload that needs arguments.
*
***/
*
* DESCRIPTION
*
- * Implementations of the Silc Authentication Payload and authentication
+ * Implementations of the SILC Authentication Payload and authentication
* routines. The SILC Authentication Payload is used to deliver
* authentication data usually from client to server in purpose of
* gaining access to some service. The Payload and the authentication
<!--
@LIBRARY=SILC Crypto Library
@FILENAME=silccryptlib.html
-@LINK=silcrng_intro.html:Introduction to Random Number Generator
+@LINK=silcrng_intro.html:Introduction to SILC RNG
@LINK=silcrng.html:SILC RNG Interface
@LINK=silccipher.html:SILC Cipher API
@LINK=silchash.html:SILC Hash API
<!--
@LIBRARY=SILC Math Library
@FILENAME=silcmathlib.html
-@LINK=silcmath.html:SILC Math API
-@LINK=silcmp.html:SILC MP API
+@LINK=silcmp.html:SILC MP Interface
+@LINK=silcmath.html:SILC Math Interface
-->
<BIG><B>SILC Math Library</B></BIG>
<!--
@LIBRARY=SILC SFTP Library
@FILENAME=silcsftplib.html
-@LINK=silcsftp.html:SILC SFTP API
-@LINK=silcsftp_fs.html:SILC SFTP Filesystems
+@LINK=silcsftp.html:SILC SFTP Interface
+@LINK=silcsftp_fs.html:SFTP Filesystems Interface
-->
<BIG><B>SILC SFTP Library</B></BIG>
<!--
@LIBRARY=SILC Utility Library
@FILENAME=silcutillib.html
-@LINK=silcbuffer.html:SILC Buffer API
-@LINK=silcbuffmt.html:SILC Buffer Format API
-@LINK=silcbufutil.html:SILC Buffer Utility API
-@LINK=silchashtable.html:SILC Hash Table API
-@LINK=silclog.html:SILC Log and Debug API
-@LINK=silcmemory.html:SILC Memory API
-@LINK=silcmutex.html:SILC Mutex API
-@LINK=silcthread.html:SILC Thread API
-@LINK=silcnet.html:SILC Net API
-@LINK=silcschedule.html:SILC Schedule API
-@LINK=silcsockconn.html:SILC Socket Connection API
-@LINK=silcprotocol.html:SILC Protocol API
-@LINK=silcfileutil.html:SILC File Util API
-@LINK=silcutil.html:SILC Util API
+@LINK=silcbuffer.html:SILC Buffer Interface
+@LINK=silcbuffmt.html:SILC Buffer Format Interface
+@LINK=silcbufutil.html:SILC Buffer Utility Interface
+@LINK=silchashtable.html:SILC Hash Table Interface
+@LINK=silclog.html:SILC Logging Interface
+@LINK=silcmemory.html:SILC Memory Interface
+@LINK=silcmutex.html:SILC Mutex Interface
+@LINK=silcthread.html:SILC Thread Interface
+@LINK=silcnet.html:SILC Network Interface
+@LINK=silcschedule.html:SILC Schedule Interface
+@LINK=silcsockconn.html:SILC Socket Interface
+@LINK=silcprotocol.html:SILC Protocol Interface
+@LINK=silcconfig.html:SILC Config Interface
+@LINK=silcfileutil.html:SILC File Util Interface
+@LINK=silcutil.html:SILC Util Interface
+@LINK=silclist.html:SILC List Interface
+@LINK=silcdlist.html:SILC Dynamic List Interface
@LINK=silczip.html:SILC Zip API
-@LINK=silclist.html:SILC List API
-@LINK=silcdlist.html:SILC Dynamic List API
-->
<BIG><B>SILC Utility Library</B></BIG>
<?php
if ($type == 0) {
/* Get the index for this page */
- $len = strcspn($page, "__");
+ $len = strcspn($page, "-");
$fname = substr($page, 0, $len);
- require "$fname"."__index.tmpl";
+ require "$fname"."-index.tmpl";
}
?>
</font>
sh gen.sh $DST gen_index.php 1 $DST/$i.html $DST/$i.html
# Generate the details and the layout
- files=`find $DST -name ""$i"__*.html"`
+ files=`find $DST -name ""$i"-*.html"`
for k in $files
do
sh gen.sh $DST gen_index.php 0 $k $k
done
- rm -f $DST/$i__index.tmpl
+ rm -f $DST/$i-index.tmpl
done
# Generate the index and TOC files from the DIRECTORY files
if (output_mode == HTML)
{
- sprintf(fname, "%s__%s.html", doc_base, cur_header->function_name);
+ sprintf(fname, "%s-%s.html", doc_base, cur_header->function_name);
dest_doc = fopen(fname, "w");
if (!dest_doc)
{
#endif
/* Generate quick index file, for fast referencing */
- sprintf(iname, "%s__index.tmpl", doc_base);
+ sprintf(iname, "%s-index.tmpl", doc_base);
index = fopen(iname, "w");
if (!index)
{
{
char fname[256];
- sprintf(fname, "%s__%s.html", RB_FilePart(doc_base),
+ sprintf(fname, "%s-%s.html", RB_FilePart(doc_base),
cur_header->function_name);
if (cur_header->name && cur_header->function_name)
fprintf (dest_doc, "<A HREF=\"#%s\">%s</A>",
label_name, label_name);
#endif
- fprintf (dest_doc, "<A HREF=\"%s__%s.html\">%s</A>",
+ fprintf (dest_doc, "<A HREF=\"%s-%s.html\">%s</A>",
RB_FilePart(doc_base), label_name,
label_name);
}