aboutsummaryrefslogtreecommitdiffstats
path: root/docs/General/Guide.pod
blob: a3cfe38566d4a8af7474e613ae9f722a3d9c4c23 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
__END__

=head1 NAME

Guide To Irssi Scripting.

=head1 DESCRIPTION

This page presents a bunch of additional information about scripting for Irssi
that doesn't fit well anywhere else. It contains useful tips, common pitfalls,
and a bunch of other handy things.  At least, I hope so.

=head1 LOADING AND UNLOADING SCRIPTS

=head2 File Locations

Packaged Irssi script files are usually placed in F</usr/share/irssi/scripts/>,
but custom scripts or those required by a single user can be placed in
F<~/.irssi/scripts/>.

=head3 Autorunning Scripts

If you require a script be run when Irssi starts, you can place the file (or
better, create a symlink to it) into F<~/.irssi/scripts/autorun/>.

Alternatively, if you want more control over the order in which scripts are
autoloaded, you can place

   SCRIPT LOAD script1
   SCRIPT LOAD script2
   SCRIPT LOAD script3

into your F<~/.irssi/startup> file.

I<This tip was provided by C<Rhonda> on Freenode/#irssi>.

=head2 Testing

=for comment B<TODO: Forgotten what was going to go here>

=head3 C</SCRIPT EXEC>

The C<SCRIPT EZEC> command allows you to test various simple ideas straight from
the Irssi interface.  It can also be used to register signal handlers and
commands if run with the C<-permanent> option.

B<NB: C<-permanent> only means that the script should not terminate
immediately. It is still not persistent between restarts of the Irssi client.
Truly permanent scripts should be placed in autorun scripts or added to
F<~/.irssi/startup>>


B<TODO: Using it for testing stuff out>

B<TODO: Also for very short scripts (with -permanent?)>

B<TODO: Quoting rules for vars and things?>

=head2 Loading

Scripts are loaded via C</SCRIPT LOAD I<filename>>.  A default Irssi
configuration also provides the C</RUN> alias as an alternative to C</SCRIPT
LOAD>.

Loaded scripts will exist in the Irssi namespace as:
C<Irssi::Script::I<E<lt>nameE<gt>>>, where I<name> is the filename stripped of its
F<.pl> extension.

=head2 Unloading

A script can be unloaded via the C</SCRIPT UNLOAD I<name>> command.  The name is
typically the script filename without the F<.pl> extension, so F<nickcolor.pl>
becomes C</SCRIPT UNLOAD nickcolor>.

As part of the unloading process, if the script contains a

    sub UNLOAD {
        ...
    }

function, it will be run just before the script is unloaded and all variables
destroyed. This can be used to clean up any temporary files, shut down any
network connections or processes, and restore any Irssi modifications made.

=head1 ANATOMY OF A SCRIPT

In this section, we develop a very simplistic script and look at the
necessary code.

B<Note:> This section has considerable overlap with L<Juerd's Scripting
Tutorial|http://juerd.nl/site.plp/irssiscripttut>, which you may also
wish to read.

B<TODO: Figure out a basic script to use as an example>

=head2 Preamble

All scripts should contain a header as follows:

    use strict;
    use warnings;

    use vars qw($VERSION %IRSSI);
    use Irssi;

    $VERSION = '1.00';
    %IRSSI = (
        authors     => 'Author Name(s)',
        contact     => 'author_email@example.com',
        name        => 'Script Title',
        description => 'Longer script description ',
        license     => 'Public Domain',
    );

The first two lines are optional, but strongly advised. They provide far greater
error checking and diagnostics should you make a mistake in your code.

The C<use vars qw($VERSION %IRSSI)> defines two global variables, which are then
set below to the appropriate values.

C<use Irssi> tells the script to make the various L<Irssi> support functions available.
Additional parameters passed here with C<qw/.../> can be used to import functions into
the current script namespace.


=head1 COMMONLY SCRIPTED TASKS

=head2 Modifying an input line before sending

B<TODO: catch "send text", modify it if necessary, signal_emit it>

=head2 Responding to a public message

B<TODO: catch "messsage public", check params, generate response>

=head2 Responding to a private message

B<TODO: catch "messsage private", check params, generate response>

=head1 USEFUL THINGS


=head2 Dealing with Blocking IO

B<TODO: see F<hddtemp.pl> on SIO> - fork and use pipes to communicate. Also
remember to pidwait the child>


=head2 Getting the Response Value of a Remote Command

B<TODO: Add bazerka's snippet here>

=head2 Getting the Response Value of a Local Command

B<TODO: How?!??>

There is no simple way to achieve this.  The data backing most common activities
can be extracted through other API calls, but there are some exceptions.

Maybe, look up the format, intercept gui print text, try to match it against
what you're expecting?

Can this be generalised at all?

=head2 Sharing Code Between Scripts

There are 2 main ways for scripts to communicate, either via emitting and
handling Irssi signals, or by calling functions from one another directly.

=head3 Using Signals

In order to use custom signals, they must first be registered with Irssi.
During registration, a list of the parameters must also be specified.  Once specified,
it cannot be changed without restarting Irssi, so be warned.

After registration, your script can simply listen for signals with
L<Irssi::signal_add|Irssi/signal_add $sig_name, $func>, or generate them for
others to handle with L<Irssi::signal_emit|Irssi/signal_emit $sig_name, @params>

For example:

B<TODO: Example here>

=head3 Using Functions

Because scripts exist in a well-defined namespace of C<Irssi::Script::SOMEPACKAGE>,
it is possible to manipulate the perl symbol table to call functions directly on them,
assuming they are loaded.

Because the following code depends on I<symbolic references>, it is necessary to
tell Perl to allow them, despite normally being prohibited by C<use strict>.
The C<no strict 'refs';> line takes care of this, and reenables them at the end
of the snippet.

    no strict 'refs';
    if (defined %{ 'Irssi::Script::SOMEPACKAGE::' }) {
        if (defined &{'Irssi::Script::SOMEPACKAGE::SOME_FUNC'} ) {
            (&{'Irssi::Script::SOMEPAKAGE::SOME_FUNC'}(@args));
        } else {
            print("Err: can't find Irssi::Script::SOMEPACKAGE::SOME_FUNC");
        }
      }
    use strict 'refs';

Here, C<SOMEPACKAGE> is the name of the script package which contains the
function you want to call, and C<SOME_FUNC> is the name of the function within
it you wish to call.  The first 2 C<defined(..)> lines take care of ensuring
that the package and function exist, and generate an error otherwise. Other
error handling is possible, including executing a C</SCRIPT LOAD> to load the
necessary script and retry, but is not shown here.

I<This snippet was provided by C<Bazerka> on Freenode/#irssi>.

=head2 If In Doubt, Dump!

C<Data::Dumper> is an extremely good way to inspect Irssi internals if you're
looking for an undocumented feature.

The C<DUMP> alias by L<Wouter
Coekaerts|http://wouter.coekaerts.be/site/irssi/aliases> provides an easy way to
check object fields.

Dump perl object (e.g. C</dump Irssi::active_win>):

    /alias DUMP script exec use Data::Dumper\; print Data::Dumper->new([\\$0-])->Dump

=head2 Making Scripts Act Native

An important part of creating a good script is to make it behave as though it
were a part of Irssi. Adhering to some of the standard conventions can make this
easier.

=head3 Provide Help

Scripts commonly store information about how to use them in comments at the top
of their file.  Whilst better than no documentation at all, a preferable approach
is to allow that help to be accessed from within Irssi itself, using the C</HELP>
command.

    my $help = "this is help for b";

    Irssi::command_bind('help', sub {
            if ($_[0] eq 'test_b') {
                Irssi::print($help, MSGLEVEL_CLIENTCRAP);
                Irssi::signal_stop;
            }
      }
    );

This example demonstrates overriding the C</HELP> command, and if the argument
matches our command, print some custom help and prevent the internal Irssi help
function from being called.  Otherwise, it falls back to the default help.


I<This snippet was provided by C<culb> on Freenode/#irssi>.

=head3 Use Tab Completion

One of the great features of Irssi is the ability to complete commands,
subcommands and even certain arguments.  Using the subcommands processing feature
described below automatically allows those subcommands to be tab-completed, but
for more complex tasks, you can hook into the autocompletion system itself.

In order to create your own completions, you must intercept the C<"complete
word"> signal and return a list of completion candidates.

    sub do_complete {
        my ($strings, $window, $word, $linestart, $want_space) = @_;

        # only provide these completions if the input line is otherwise empty.
        return unless ($linestart eq '' && $word eq '');

        # add the completion candidates
        push @$strings, qw/foo bar baz bacon/;

        # indicate that we want to include a space after the completion
        $$want_space = 1;

        # prevent internal Irssi completion from responding
        Irssi::signal_stop;
    }

    Irssi::signal_add_first('complete word',  \&do_complete);

I<This snippet taken from
L<F<complete_lastspoke.pl>|http://scripts.irssi.org/scripts/complete_lastspoke.pl>
by Daenyth>

=head3 Use Settings for Customisation

Many scripts require the setting of various parameters to affect how they behave.
One approach is to require the user to directly edit the script file, but this
is less than ideal for a number of reasons. Firstly, it is easy to introduce
errors into a script by accidentally deleting closing quotes or semicolons.
Secondly, it has no effect until the script is reloaded, leading to confusion.

A much better alternative is to use Irssi's inbuilt settings mechanism to allow
users to set these parameters from within Irssi, as well as to C</SAVE> their
settings for subsequent invocations.

B<TODO: different types of settings>

B<TODO: register/set/get>

B<TODO: Listening for changes and acting accordingly>

=head3 Use Subcommands to Group Script Functionality

A common theme in Irssi scripts is to define commands with a prefix, such as
C</myscript_foo>, C<myscript_bar>, etc.  This helps to avoid accidentally clobbering
native commands and those defined by other scripts, but is a problem better solved
with I<subcommands>.

Subcommands allow you to bind commands such as C</myscript foo> and C</myscript bar>.
Completions are automatically handled for both the primary command, and any
subcommands contained within it.

The following example demonstrates how to use subcommands from within a script:

    Irssi::command_bind("foo bar", \&subcmd_bar);
    Irssi::command_bind("foo", \&subcmd_handler);

    sub subcmd_handler {
        my ($data, $server, $item) = @_;
        $data =~ s/\s+$//g; # strip trailing whitespace.
        Irssi::command_runsub('foo', $data, $server, $item);
    }

    sub subcmd_bar {
        my ($args) = @_;
        print "subcommand called with: $args";
    }

=head1 AUTHOR & THANKS

This page was written by Tom Feist C<shabble+irssi@metavore.org>, but draws
on the help of many many people.

The denizens of Freenode/#irssi have been particularly helpful, especially
C<Bazerka> and C<culb>.

To report bugs or suggestions, email me at the address before, or come talk to
me in C<#irssi> on C<irc.freenode.net>.

=head1 OTHER RESOURCES

The documentation assembled here and elsewhere on this site has been drawn from
many different places, and a lot of valuable information is available from the
following sites.


=over

=item L<http://irssi.org/documentation/perl>

=item L<http://irssi.org/documentation/signals>

=item L<http://irssi.org/documentation/special_vars>

=item L<http://irssi.org/documentation/formats>

=item L<http://irssi.org/documentation/settings>

=item L<http://juerd.nl/site.plp/irssiscripttut>

=item L<http://irchelp.org/irchelp/rfc/rfc.html>

=item L<http://wouter.coekaerts.be/site/irssi/irssi>

=back