forked from Dutchy-/irssi-nickcolor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nickcolor.pl
192 lines (165 loc) · 5.59 KB
/
nickcolor.pl
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
use strict;
use Irssi 20020101.0250 ();
use vars qw($VERSION %IRSSI);
$VERSION = "1.2";
%IRSSI = (
authors => "Timo Sirainen, Ian Peters, modified by Daniele Sluijters, Edwin \"Dutchy\" Smulders, Ed Holland",
contact => "tss\@iki.fi, mail\@dutchy.org, edjholland\@gmail.com",
name => "Nick Color",
description => "assign a different color for each nick",
license => "Public Domain",
url => "https://github.com/edholland/irssi-nickcolor",
changed => "15/11/2013"
);
# hm.. i should make it possible to use the existing one..
Irssi::theme_register([
'pubmsg_hilight', '{pubmsghinick $0 $3 $1}$2'
]);
my %saved_colors;
my %session_colors = {};
my @colors = qw/3 4 5 6 7 8 9 10 11 12 13 14/;
# This hash is used globally across all channels, so collisions may still occur where channel size <= 12
my %used;
# Prefill this hash to ensure we give out all colors later
foreach my $c (@colors) {
$used{$c} = 0;
}
my %lens;
sub load_colors {
open COLORS, "$ENV{HOME}/.irssi/saved_colors";
while (<COLORS>) {
# I don't know why this is necessary only inside of irssi
my @lines = split "\n";
foreach my $line (@lines) {
my($nick, $color) = split ":", $line;
# Set color, and keep counter for later
$saved_colors{$nick} = $color;
$used{$color} += 1;
$lens{length $nick}{$color} += 1;
}
}
close COLORS;
}
sub save_colors {
open COLORS, ">$ENV{HOME}/.irssi/saved_colors";
foreach my $nick (keys %saved_colors) {
print COLORS "$nick:$saved_colors{$nick}\n";
}
Irssi::print("Saved colors to $ENV{HOME}/.irssi/saved_colors");
close COLORS;
}
# If someone we've colored (either through the saved colors, or the hash
# function) changes their nick, we'd like to keep the same color associated
# with them (but only in the session_colors, ie a temporary mapping).
sub sig_nick {
my ($server, $newnick, $nick, $address) = @_;
my $color;
$newnick = substr ($newnick, 1) if ($newnick =~ /^:/);
if ($color = $saved_colors{$nick}) {
$session_colors{$newnick} = $color;
} elsif ($color = $session_colors{$nick}) {
$session_colors{$newnick} = $color;
}
# Dont increment the used counters here as this is 1:1 swap, and
# frequent nick changes could affect the distribution of colours otherwise
$lens{length $newnick}{$color} += 1;
$lens{length $nick}{$color} -= 1;
}
# This gave reasonable distribution values when run across
# /usr/share/dict/words
sub simple_hash {
my ($string) = @_;
chomp $string;
my @chars = split //, $string;
my ($counter, $total) = (0,0);
foreach my $char (@chars) {
$counter++;
$total += ord($char) * $counter;
}
return $colors[ $counter % scalar(@colors) ];
}
# FIXME: breaks /HILIGHT etc.
sub sig_public {
my ($server, $msg, $nick, $address, $target) = @_;
my $chanrec = $server->channel_find($target);
return if not $chanrec;
my $nickrec = $chanrec->nick_find($nick);
return if not $nickrec;
my $nickmode = $nickrec->{op} ? "@" : $nickrec->{voice} ? "+" : "";
# Has the user assigned this nick a color?
my $color = $saved_colors{$nick};
# Have -we- already assigned this nick a color?
if (!$color) {
$color = $session_colors{$nick};
}
# Let's assign this nick a color
if (!$color) {
$color = simple_hash $nick;
# If we're not trying to use the max value go ahead, else use the min value
my $max = (sort {$used{$a} cmp $used{$b} } keys %used)[-1];
my $ref = %lens->{length $nick};
my $len_max = (sort {$ref->{$a} cmp $ref->{$b} } keys %{$ref} )[-1];
if ( ($ref->{$color} == 0) || ( ($color != $max) && ($color != $len_max ) ) ) {
$session_colors{$nick} = $color;
} else {
# Pick the _least_ used color
$color = (sort {$used{$a} cmp $used{$b} } keys %used)[0];
$session_colors{$nick} = $color;
}
# Store the color used
$used{$color} += 1;
$lens{length $nick}{$color} += 1;
}
$color = "0".$color if ($color < 10);
$server->command('/^format pubmsg {pubmsgnick $2 {pubnick '.chr(3).$color.'$0}}$1');
}
sub cmd_color {
my ($data, $server, $witem) = @_;
my ($op, $nick, $color) = split " ", $data;
$op = lc $op;
if (!$op) {
Irssi::print ("Supported commands:
preview (list possible colors and their codes)
list (show current entries in saved_colors)
set <nick> <color> (associate a color to a nick)
clear <nick> (delete color associated to nick)
save (save colorsettings to saved_colors file)");
} elsif ($op eq "save") {
save_colors;
} elsif ($op eq "set") {
if (!$nick) {
Irssi::print ("Nick not given");
} elsif (!$color) {
Irssi::print ("Color not given");
} elsif ($color < 2 || $color > 14) {
Irssi::print ("Color must be between 2 and 14 inclusive");
} else {
$saved_colors{$nick} = $color;
}
} elsif ($op eq "clear") {
if (!$nick) {
Irssi::print ("Nick not given");
} else {
delete ($saved_colors{$nick});
}
} elsif ($op eq "list") {
Irssi::print ("\nSaved Colors:");
foreach my $nick (keys %saved_colors) {
Irssi::print (chr (3) . "$saved_colors{$nick}$nick" .
chr (3) . "1 ($saved_colors{$nick})");
}
Irssi::print ("\nUsed colors:");
foreach my $i (sort {$a <=> $b} keys %used) {
Irssi::print (chr (3) . "$i" . "Color #$i Number #$used{$i}");
}
} elsif ($op eq "preview") {
Irssi::print ("\nAvailable colors:");
foreach my $i (2..14) {
Irssi::print (chr (3) . "$i" . "Color #$i");
}
}
}
load_colors;
Irssi::command_bind('color', 'cmd_color');
Irssi::signal_add('message public', 'sig_public');
Irssi::signal_add('event nick', 'sig_nick');