summaryrefslogtreecommitdiffstats
authorRaghavendra D Prabhu <[email protected]>2010-10-17 21:18:29 (GMT)
committer Raghavendra D Prabhu <[email protected]>2010-10-17 21:18:29 (GMT)
commit9dacbb1960add439f6d2b8a3a587b0613d4798f9 (patch) (unidiff)
treedab8f90c530c6846361f3dd52943271867c40c85
downloadweescripts-9dacbb1960add439f6d2b8a3a587b0613d4798f9.zip
weescripts-9dacbb1960add439f6d2b8a3a587b0613d4798f9.tar.gz
weescripts-9dacbb1960add439f6d2b8a3a587b0613d4798f9.tar.bz2
Initial commit
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--README1
-rw-r--r--buffers.pl336
-rw-r--r--grep.py1583
-rw-r--r--notify.py117
4 files changed, 2037 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..d8c7653
--- a/dev/null
+++ b/README
@@ -0,0 +1 @@
some scripts I modified/improved  I
diff --git a/buffers.pl b/buffers.pl
new file mode 100644
index 0000000..155bf62
--- a/dev/null
+++ b/buffers.pl
@@ -0,0 +1,336 @@
1#
2# Copyright (c) 2008-2010 by FlashCode <[email protected]>
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17
18#
19# Display sidebar with list of buffers.
20#
21# History:
22# 2010-04-12, FlashCode <[email protected]>:
23# v1.9: replace call to log() by length() to align buffer numbers
24# 2010-04-02, FlashCode <[email protected]>:
25# v1.8: fix bug with background color and option indenting_number
26# 2010-04-02, Helios <[email protected]>:
27# v1.7: add indenting_number option
28# 2010-02-25, m4v <[email protected]>:
29# v1.6: add option to hide empty prefixes
30# 2010-02-12, FlashCode <[email protected]>:
31# v1.5: add optional nick prefix for buffers like IRC channels
32# 2009-09-30, FlashCode <[email protected]>:
33# v1.4: remove spaces for indenting when bar position is top/bottom
34# 2009-06-14, FlashCode <[email protected]>:
35# v1.3: add option "hide_merged_buffers"
36# 2009-06-14, FlashCode <[email protected]>:
37# v1.2: improve display with merged buffers
38# 2009-05-02, FlashCode <[email protected]>:
39# v1.1: sync with last API changes
40# 2009-02-21, FlashCode <[email protected]>:
41# v1.0: remove timer used to update bar item first time (not needed any more)
42# 2009-02-17, FlashCode <[email protected]>:
43# v0.9: fix bug with indenting of private buffers
44# 2009-01-04, FlashCode <[email protected]>:
45# v0.8: update syntax for command /set (comments)
46# 2008-10-20, Jiri Golembiovsky <[email protected]>:
47# v0.7: add indenting option
48# 2008-10-01, FlashCode <[email protected]>:
49# v0.6: add default color for buffers, and color for current active buffer
50# 2008-09-18, FlashCode <[email protected]>:
51# v0.5: fix color for "low" level entry in hotlist
52# 2008-09-18, FlashCode <[email protected]>:
53# v0.4: rename option "show_category" to "short_names",
54# remove option "color_slash"
55# 2008-09-15, FlashCode <[email protected]>:
56# v0.3: fix bug with priority in hotlist (var not defined)
57# 2008-09-02, FlashCode <[email protected]>:
58# v0.2: add color for buffers with activity and config options for
59# colors, add config option to display/hide categories
60# 2008-03-15, FlashCode <[email protected]>:
61# v0.1: script creation
62#
63# Help about settings:
64# display short names (remove text before first "." in buffer name):
65# /set plugins.var.perl.buffers.short_names on
66# use indenting for some buffers like IRC channels:
67# /set plugins.var.perl.buffers.indenting on
68# use indenting for numbers:
69# /set plugins.var.perl.buffers.indenting_number on
70# hide merged buffers:
71# /set plugins.var.perl.buffers.hide_merged_buffers on
72# show prefix:
73# /set plugins.var.perl.buffers.show_prefix on
74# /set plugins.var.perl.buffers.show_prefix_empty on
75# change colors:
76# /set plugins.var.perl.buffers.color_number color
77# /set plugins.var.perl.buffers.color_default color
78# /set plugins.var.perl.buffers.color_hotlist_low color
79# /set plugins.var.perl.buffers.color_hotlist_message color
80# /set plugins.var.perl.buffers.color_hotlist_private color
81# /set plugins.var.perl.buffers.color_hotlist_highlight color
82# /set plugins.var.perl.buffers.color_current color
83# (replace "color" by your color, which may be "fg" or "fg,bg")
84#
85
86use strict;
87
88my $version = "1.9";
89
90# -------------------------------[ config ]-------------------------------------
91
92my %default_options = ("short_names" => "on",
93 "indenting" => "on",
94 "indenting_number" => "on",
95 "max_length" => "10",
96 "hide_merged_buffers" => "off",
97 "show_prefix" => "off",
98 "show_prefix_empty" => "on",
99 "color_hotlist_low" => "white",
100 "color_hotlist_message" => "yellow",
101 "color_hotlist_private" => "lightgreen",
102 "color_hotlist_highlight" => "magenta",
103 "color_current" => "lightcyan,red",
104 "color_default" => "default",
105 "color_number" => "lightgreen",
106 );
107my %options;
108my %hotlist_level = (0 => "low", 1 => "message", 2 => "private", 3 => "highlight");
109
110# --------------------------------[ init ]--------------------------------------
111
112weechat::register("buffers", "FlashCode <flashcode\@flashtux.org>", $version,
113 "GPL3", "Sidebar with list of buffers", "", "");
114
115foreach my $option (keys %default_options)
116{
117 if (!weechat::config_is_set_plugin($option))
118 {
119 weechat::config_set_plugin($option, $default_options{$option});
120 }
121}
122buffers_read_options();
123
124weechat::bar_item_new("buffers", "build_buffers", "");
125weechat::bar_new("buffers", "0", "0", "root", "", "left", "horizontal",
126 "vertical", "0", "0", "default", "default", "default", "1",
127 "buffers");
128weechat::hook_signal("buffer_*", "buffers_signal_buffer", "");
129weechat::hook_signal("hotlist_*", "buffers_signal_hotlist", "");
130weechat::hook_config("plugins.var.perl.buffers.*", "buffers_signal_config", "");
131weechat::bar_item_update("buffers");
132
133# ------------------------------------------------------------------------------
134
135sub buffers_read_options
136{
137 foreach my $option (keys %default_options)
138 {
139 $options{$option} = weechat::config_get_plugin($option);
140 }
141}
142
143sub build_buffers
144{
145 my $str = "";
146
147 # get bar position (left/right/top/bottom)
148 my $position = "left";
149 my $option_position = weechat::config_get("weechat.bar.buffers.position");
150 if ($option_position ne "")
151 {
152 $position = weechat::config_string($option_position);
153 }
154
155 # read hotlist
156 my %hotlist;
157 my $infolist = weechat::infolist_get("hotlist", "", "");
158 while (weechat::infolist_next($infolist))
159 {
160 $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")} =
161 weechat::infolist_integer($infolist, "priority");
162 }
163 weechat::infolist_free($infolist);
164
165 # read buffers list
166 my @buffers;
167 my @current1 = ();
168 my @current2 = ();
169 my $old_number = -1;
170 my $max_number = 0;
171 my $max_number_digits = 0;
172 my $active_seen = 0;
173 $infolist = weechat::infolist_get("buffer", "", "");
174 while (weechat::infolist_next($infolist))
175 {
176 my $buffer = {};
177 my $number = weechat::infolist_integer($infolist, "number");
178 if ($number ne $old_number)
179 {
180 @buffers = (@buffers, @current2, @current1);
181 @current1 = ();
182 @current2 = ();
183 $active_seen = 0;
184 }
185 if ($number > $max_number)
186 {
187 $max_number = $number;
188 }
189 $old_number = $number;
190 my $active = weechat::infolist_integer($infolist, "active");
191 if ($active)
192 {
193 $active_seen = 1;
194 }
195 $buffer->{"pointer"} = weechat::infolist_pointer($infolist, "pointer");
196 $buffer->{"number"} = $number;
197 $buffer->{"active"} = $active;
198 $buffer->{"current_buffer"} = weechat::infolist_integer($infolist, "current_buffer");
199 $buffer->{"short_name"} = weechat::infolist_string($infolist, "short_name");
200 $buffer->{"name"} = weechat::infolist_string($infolist, "name");
201 if ($active_seen)
202 {
203 push(@current2, $buffer);
204 }
205 else
206 {
207 push(@current1, $buffer);
208 }
209 }
210 if ($max_number >= 1)
211 {
212 $max_number_digits = length(int($max_number));
213 }
214 @buffers = (@buffers, @current2, @current1);
215 weechat::infolist_free($infolist);
216
217
218 # build string with buffers
219 $old_number = -1;
220 for my $buffer (@buffers)
221 {
222 if (($options{"hide_merged_buffers"} eq "on") && (! $buffer->{"active"}))
223 {
224 next;
225 }
226 my $color = $options{"color_default"};
227 $color = "default" if ($color eq "");
228 my $bg = "";
229 if (exists $hotlist{$buffer->{"pointer"}})
230 {
231 $color = $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}};
232 }
233 if ($buffer->{"current_buffer"})
234 {
235 $color = $options{"color_current"};
236 $bg = $1 if ($color =~ /.*,(.*)/);
237 }
238 my $color_bg = "";
239 $color_bg = weechat::color(",".$bg) if ($bg ne "");
240 if (($options{"indenting_number"} eq "on")
241 && (($position eq "left") || ($position eq "right")))
242 {
243 $str .= weechat::color("default").$color_bg
244 .(" " x ($max_number_digits - length(int($buffer->{"number"}))));
245 }
246 if ($old_number ne $buffer->{"number"})
247 {
248 $str .= weechat::color($options{"color_number"})
249 .$color_bg
250 .$buffer->{"number"}
251 .weechat::color("default")
252 .$color_bg
253 .".";
254 }
255 else
256 {
257 my $indent = "";
258 $indent = ((" " x length($buffer->{"number"}))." ") if (($position eq "left") || ($position eq "right"));
259 $str .= weechat::color("default")
260 .$color_bg
261 .$indent;
262 }
263 if (($options{"indenting"} eq "on")
264 && (($position eq "left") || ($position eq "right")))
265 {
266 my $type = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type");
267 if (($type eq "channel") || ($type eq "private"))
268 {
269 $str .= " ";
270 }
271 }
272 if ($options{"show_prefix"} eq "on")
273 {
274 my $nickname = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_nick");
275 if ($nickname ne "")
276 {
277 # with version >= 0.3.2, this infolist will return only nick
278 # with older versions, whole nicklist is returned for buffer, and this can be very slow
279 my $infolist_nick = weechat::infolist_get("nicklist", $buffer->{"pointer"}, "nick_".$nickname);
280 if ($infolist_nick ne "")
281 {
282 while (weechat::infolist_next($infolist_nick))
283 {
284 if ((weechat::infolist_string($infolist_nick, "type") eq "nick")
285 && (weechat::infolist_string($infolist_nick, "name") eq $nickname))
286 {
287 my $prefix = weechat::infolist_string($infolist_nick, "prefix");
288 if (($prefix ne " ") or ($options{"show_prefix_empty"} eq "on"))
289 {
290 $str .= weechat::color(weechat::config_color(
291 weechat::config_get(
292 weechat::infolist_string($infolist_nick, "prefix_color"))))
293 .$prefix;
294 }
295 last;
296 }
297 }
298 weechat::infolist_free($infolist_nick);
299 }
300 }
301 }
302 $str .= weechat::color($color);
303 if ($options{"short_names"} eq "on")
304 {
305 $str .= substr($buffer->{"short_name"},0,$options{"max_length"});
306 }
307 else
308 {
309 $str .= substr($buffer->{"name"},0,$options{"max_length"});
310 }
311 $str .= "\n";
312 $old_number = $buffer->{"number"};
313 }
314
315
316 return $str;
317}
318
319sub buffers_signal_buffer
320{
321 weechat::bar_item_update("buffers");
322 return weechat::WEECHAT_RC_OK;
323}
324
325sub buffers_signal_hotlist
326{
327 weechat::bar_item_update("buffers");
328 return weechat::WEECHAT_RC_OK;
329}
330
331sub buffers_signal_config
332{
333 buffers_read_options();
334 weechat::bar_item_update("buffers");
335 return weechat::WEECHAT_RC_OK;
336}
diff --git a/grep.py b/grep.py
new file mode 100644
index 0000000..aef4c82
--- a/dev/null
+++ b/grep.py
@@ -0,0 +1,1583 @@
1# -*- coding: utf-8 -*-
2###
3# Copyright (c) 2009-2010 by Elián Hanisch <[email protected]>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17###
18
19###
20# Search in Weechat buffers and logs (for Weechat 0.3.*)
21#
22# Inspired by xt's grep.py
23# Originally I just wanted to add some fixes in grep.py, but then
24# I got carried away and rewrote everything, so new script.
25#
26# Commands:
27# * /grep
28# Search in logs or buffers, see /help grep
29# * /logs:
30# Lists logs in ~/.weechat/logs, see /help logs
31#
32# Settings:
33# * plugins.var.python.grep.clear_buffer:
34# Clear the results buffer before each search. Valid values: on, off
35#
36# * plugins.var.python.grep.go_to_buffer:
37# Automatically go to grep buffer when search is over. Valid values: on, off
38#
39# * plugins.var.python.grep.log_filter:
40# Coma separated list of patterns that grep will use for exclude logs, e.g.
41# if you use '*server/*' any log in the 'server' folder will be excluded
42# when using the command '/grep log'
43#
44# * plugins.var.python.grep.show_summary:
45# Shows summary for each log. Valid values: on, off
46#
47# * plugins.var.python.grep.max_lines:
48# Grep will only print the last matched lines that don't surpass the value defined here.
49#
50# * plugins.var.python.grep.size_limit:
51# Size limit in KiB, is used for decide whenever grepping should run in background or not. If
52# the logs to grep have a total size bigger than this value then grep run as a new process.
53# It can be used for force or disable background process, using '0' forces to always grep in
54# background, while using '' (empty string) will disable it.
55#
56# * plugins.var.python.grep.default_tail_head:
57# Config option for define default number of lines returned when using --head or --tail options.
58# Can be overriden in the command with --number option.
59#
60#
61# TODO:
62# * try to figure out why hook_process chokes in long outputs (using a tempfile as a
63# workaround now)
64# * predefined regexp templates for common searches, like urls
65# * possibly add option for defining time intervals
66#
67#
68# History:
69# 2010-04-08
70# version 0.6.6: bug fixes
71# * use WEECHAT_LIST_POS_END in log file completion, makes completion faster
72# * disable bytecode if using python 2.6
73# * use single quotes in command string
74# * fix bug that could change buffer's title when using /grep stop
75#
76# 2010-01-24
77# version 0.6.5: disable bytecode is a 2.6 feature, instead, resort to delete the bytecode manually
78#
79# 2010-01-19
80# version 0.6.4: bug fix
81# version 0.6.3: added options --invert --only-match (replaces --exact, which is still available
82# but removed from help)
83# * use new 'irc_nick_color' info
84# * don't generate bytecode when spawning a new process
85# * show active options in buffer title
86#
87# 2010-01-17
88# version 0.6.2: removed 2.6-ish code
89# version 0.6.1: fixed bug when grepping in grep's buffer
90#
91# 2010-01-14
92# version 0.6.0: implemented grep in background
93# * improved context lines presentation.
94# * grepping for big (or many) log files runs in a weechat_process.
95# * added /grep stop.
96# * added 'size_limit' option
97# * fixed a infolist leak when grepping buffers
98# * added 'default_tail_head' option
99# * results are sort by line count
100# * don't die if log is corrupted (has NULL chars in it)
101# * changed presentation of /logs
102# * log path completion doesn't suck anymore
103# * removed all tabs, because I learned how to configure Vim so that spaces aren't annoying
104# anymore. This was the script's original policy.
105#
106# 2010-01-05
107# version 0.5.5: rename script to 'grep.py' (FlashCode <[email protected]>).
108#
109# 2010-01-04
110# version 0.5.4.1: fix index error when using --after/before-context options.
111#
112# 2010-01-03
113# version 0.5.4: new features
114# * added --after-context and --before-context options.
115# * added --context as a shortcut for using both -A -B options.
116#
117# 2009-11-06
118# version 0.5.3: improvements for long grep output
119# * grep buffer input accepts the same flags as /grep for repeat a search with different
120# options.
121# * tweaks in grep's output.
122# * max_lines option added for limit grep's output.
123# * code in update_buffer() optimized.
124# * time stats in buffer title.
125# * added go_to_buffer config option.
126# * added --buffer for search only in buffers.
127# * refactoring.
128#
129# 2009-10-12, omero
130# version 0.5.2: made it python-2.4.x compliant
131#
132# 2009-08-17
133# version 0.5.1: some refactoring, show_summary option added.
134#
135# 2009-08-13
136# version 0.5: rewritten from xt's grep.py
137# * fixed searching in non weechat logs, for cases like, if you're
138# switching from irssi and rename and copy your irssi logs to %h/logs
139# * fixed "timestamp rainbow" when you /grep in grep's buffer
140# * allow to search in other buffers other than current or in logs
141# of currently closed buffers with cmd 'buffer'
142# * allow to search in any log file in %h/logs with cmd 'log'
143# * added --count for return the number of matched lines
144# * added --matchcase for case sensible search
145# * added --hilight for color matches
146# * added --head and --tail options, and --number
147# * added command /logs for list files in %h/logs
148# * added config option for clear the buffer before a search
149# * added config option for filter logs we don't want to grep
150# * added the posibility to repeat last search with another regexp by writing
151# it in grep's buffer
152# * changed spaces for tabs in the code, which is my preference
153#
154###
155
156import sys, getopt, time, os
157path = os.path
158stat = os.stat
159
160try:
161 import weechat
162 WEECHAT_RC_OK = weechat.WEECHAT_RC_OK
163 import_ok = True
164except ImportError:
165 import_ok = False
166
167SCRIPT_NAME = "grep"
168SCRIPT_AUTHOR = "Elián Hanisch <[email protected]>"
169SCRIPT_VERSION = "0.6.6"
170SCRIPT_LICENSE = "GPL3"
171SCRIPT_DESC = "Search in buffers and logs"
172SCRIPT_COMMAND = "grep"
173
174### Default Settings ###
175settings = {
176'clear_buffer' : 'off',
177'log_filter' : '',
178'go_to_buffer' : 'on',
179'max_lines' : '4000',
180'show_summary' : 'on',
181'size_limit' : '2048',
182'default_tail_head' : '10',
183}
184
185### Class definitions ###
186class linesDict(dict):
187 """
188 Class for handling matched lines in more than one buffer.
189 linesDict[buffer_name] = matched_lines_list
190 """
191 def __setitem__(self, key, value):
192 assert isinstance(value, list)
193 if key not in self:
194 dict.__setitem__(self, key, value)
195 else:
196 dict.__getitem__(self, key).extend(value)
197
198 def get_matches_count(self):
199 """Return the sum of total matches stored."""
200 if dict.__len__(self):
201 return sum(map(lambda L: L.matches_count, self.itervalues()))
202 else:
203 return 0
204
205 def __len__(self):
206 """Return the sum of total lines stored."""
207 if dict.__len__(self):
208 return sum(map(len, self.itervalues()))
209 else:
210 return 0
211
212 def __str__(self):
213 """Returns buffer count or buffer name if there's just one stored."""
214 n = len(self.keys())
215 if n == 1:
216 return self.keys()[0]
217 elif n > 1:
218 return '%s logs' %n
219 else:
220 return ''
221
222 def items(self):
223 """Returns a list of items sorted by line count."""
224 items = dict.items(self)
225 items.sort(key=lambda i: len(i[1]))
226 return items
227
228 def items_count(self):
229 """Returns a list of items sorted by match count."""
230 items = dict.items(self)
231 items.sort(key=lambda i: i[1].matches_count)
232 return items
233
234 def strip_separator(self):
235 for L in self.itervalues():
236 L.strip_separator()
237
238 def get_last_lines(self, n):
239 total_lines = len(self)
240 #debug('total: %s n: %s' %(total_lines, n))
241 if n >= total_lines:
242 # nothing to do
243 return
244 for k, v in reversed(self.items()):
245 l = len(v)
246 if n > 0:
247 if l > n:
248 del v[:l-n]
249 v.stripped_lines = l-n
250 n -= l
251 else:
252 del v[:]
253 v.stripped_lines = l
254
255class linesList(list):
256 """Class for list of matches, since sometimes I need to add lines that aren't matches, I need an
257 independent counter."""
258 _sep = '...'
259 def __init__(self, *args):
260 list.__init__(self, *args)
261 self.matches_count = 0
262 self.stripped_lines = 0
263
264 def append(self, item):
265 """Append lines, can be a string or a list with strings."""
266 if isinstance(item, str):
267 list.append(self, item)
268 else:
269 self.extend(item)
270
271 def append_separator(self):
272 """adds a separator into the list, makes sure it doen't add two together."""
273 s = self._sep
274 if (self and self[-1] != s) or not self:
275 self.append(s)
276
277 def count_match(self, item=None):
278 if item is None or isinstance(item, str):
279 self.matches_count += 1
280 else:
281 self.matches_count += len(item)
282
283 def strip_separator(self):
284 """removes separators if there are first or/and last in the list."""
285 if self:
286 s = self._sep
287 if self[0] == s:
288 del self[0]
289 if self[-1] == s:
290 del self[-1]
291
292### Misc functions ###
293now = time.time
294def get_size(f):
295 try:
296 return stat(f).st_size
297 except OSError:
298 return 0
299
300sizeDict = {0:'b', 1:'KiB', 2:'MiB', 3:'GiB', 4:'TiB'}
301def human_readable_size(size):
302 power = 0
303 while size > 1024:
304 power += 1
305 size /= 1024.0
306 return '%.2f %s' %(size, sizeDict.get(power, ''))
307
308def color_nick(nick):
309 """Returns coloured nick, with coloured mode if any."""
310 if not nick: return ''
311 wcolor = weechat.color
312 config_string = lambda s : weechat.config_string(weechat.config_get(s))
313 config_int = lambda s : weechat.config_integer(weechat.config_get(s))
314 # prefix and suffix
315 prefix = config_string('irc.look.nick_prefix')
316 suffix = config_string('irc.look.nick_suffix')
317 prefix_c = suffix_c = wcolor(config_string('weechat.color.chat_delimiters'))
318 if nick[0] == prefix:
319 nick = nick[1:]
320 else:
321 prefix = prefix_c = ''
322 if nick[-1] == suffix:
323 nick = nick[:-1]
324 suffix = wcolor(color_delimiter) + suffix
325 else:
326 suffix = suffix_c = ''
327 # nick mode
328 modes = '@!+%'
329 if nick[0] in modes:
330 mode, nick = nick[0], nick[1:]
331 mode_color = wcolor(config_string('weechat.color.nicklist_prefix%d' \
332 %(modes.find(mode) + 1)))
333 else:
334 mode = mode_color = ''
335 # nick color
336 nick_color = weechat.info_get('irc_nick_color', nick)
337 if not nick_color:
338 # probably we're in WeeChat 0.3.0
339 #debug('no irc_nick_color')
340 color_nicks_number = config_int('weechat.look.color_nicks_number')
341 idx = (sum(map(ord, nick))%color_nicks_number) + 1
342 nick_color = wcolor(config_string('weechat.color.chat_nick_color%02d' %idx))
343 return ''.join((prefix_c, prefix, mode_color, mode, nick_color, nick, suffix_c, suffix))
344
345### Config and value validation ###
346boolDict = {'on':True, 'off':False}
347def get_config_boolean(config):
348 value = weechat.config_get_plugin(config)
349 try:
350 return boolDict[value]
351 except KeyError:
352 default = settings[config]
353 error("Error while fetching config '%s'. Using default value '%s'." %(config, default))
354 error("'%s' is invalid, allowed: 'on', 'off'" %value)
355 return boolDict[default]
356
357def get_config_int(config, allow_empty_string=False):
358 value = weechat.config_get_plugin(config)
359 try:
360 return int(value)
361 except ValueError:
362 if value == '' and allow_empty_string:
363 return value
364 default = settings[config]
365 error("Error while fetching config '%s'. Using default value '%s'." %(config, default))
366 error("'%s' is not a number." %value)
367 return int(default)
368
369def get_config_log_filter():
370 filter = weechat.config_get_plugin('log_filter')
371 if filter:
372 return filter.split(',')
373 else:
374 return []
375
376def get_home():
377 home = weechat.config_string(weechat.config_get('logger.file.path'))
378 return home.replace('%h', weechat.info_get('weechat_dir', ''))
379
380def strip_home(s, dir=''):
381 """Strips home dir from the begging of the log path, this makes them sorter."""
382 if not dir:
383 global home_dir
384 dir = home_dir
385 l = len(dir)
386 if s[:l] == dir:
387 return s[l:]
388 return s
389
390### Messages ###
391def debug(s, prefix='', buffer_name=None):
392 """Debug msg"""
393 if not weechat.config_get_plugin('debug'): return
394 if not buffer_name:
395 buffer_name = SCRIPT_NAME + '_debug'
396 buffer = weechat.buffer_search('python', buffer_name)
397 if not buffer:
398 buffer = weechat.buffer_new(buffer_name, '', '', '', '')
399 weechat.buffer_set(buffer, 'nicklist', '0')
400 weechat.buffer_set(buffer, 'localvar_set_no_log', '1')
401 weechat.prnt(buffer, '%s\t%s' %(prefix, s))
402
403def error(s, prefix=None, buffer='', trace=''):
404 """Error msg"""
405 prefix = prefix or script_nick
406 weechat.prnt(buffer, '%s%s %s' %(weechat.prefix('error'), prefix, s))
407 if weechat.config_get_plugin('debug'):
408 if not trace:
409 import traceback
410 if traceback.sys.exc_type:
411 trace = traceback.format_exc()
412 not trace or weechat.prnt('', trace)
413
414def say(s, prefix=None, buffer=''):
415 """normal msg"""
416 prefix = prefix or script_nick
417 weechat.prnt(buffer, '%s\t%s' %(prefix, s))
418
419### Log files and buffers ###
420cache_dir = {} # note: don't remove, needed for completion if the script was loaded recently
421def dir_list(dir, filter_list=(), filter_excludes=True, include_dir=False):
422 """Returns a list of files in 'dir' and its subdirs."""
423 global cache_dir
424 from os import walk
425 from fnmatch import fnmatch
426 #debug('dir_list: listing in %s' %dir)
427 key = (dir, include_dir)
428 try:
429 return cache_dir[key]
430 except KeyError:
431 pass
432
433 filter_list = filter_list or get_config_log_filter()
434 dir_len = len(dir)
435 if filter_list:
436 def filter(file):
437 file = file[dir_len:] # pattern shouldn't match home dir
438 for pattern in filter_list:
439 if fnmatch(file, pattern):
440 return filter_excludes
441 return not filter_excludes
442 else:
443 filter = lambda f : not filter_excludes
444
445 file_list = []
446 extend = file_list.extend
447 join = path.join
448
449 def walk_path():
450 for basedir, subdirs, files in walk(os.path.expanduser(dir)):
451 #if include_dir:
452 # subdirs = map(lambda s : join(s, ''), subdirs)
453 # files.extend(subdirs)
454 files_path = map(lambda f : join(basedir, f), files)
455 files_path = [ file for file in files_path if not filter(file) ]
456 extend(files_path)
457
458 walk_path()
459 cache_dir[key] = file_list
460 #debug('dir_list: got %s' %str(file_list))
461 return file_list
462
463def get_file_by_pattern(pattern, all=False):
464 """Returns the first log whose path matches 'pattern',
465 if all is True returns all logs that matches."""
466 if not pattern: return []
467 #debug('get_file_by_filename: searching for %s.' %pattern)
468 # do envvar expandsion and check file
469 file = path.expanduser(pattern)
470 file = path.expandvars(file)
471 if path.isfile(file):
472 return [file]
473 # lets see if there's a matching log
474 global home_dir
475 file = path.join(home_dir, pattern)
476 if path.isfile(file):
477 return [file]
478 else:
479 import fnmatch
480 file = []
481 file_list = dir_list(home_dir)
482 n = len(home_dir)
483 for log in file_list:
484 basename = log[n:]
485 if fnmatch.fnmatch(basename, pattern):
486 file.append(log)
487 if not all: break
488 #debug('get_file_by_filename: got %s.' %file)
489 return file
490
491def get_file_by_buffer(buffer):
492 """Given buffer pointer, finds log's path or returns None."""
493 #debug('get_file_by_buffer: searching for %s' %buffer)
494 infolist = weechat.infolist_get('logger_buffer', '', '')
495 if not infolist: return
496 try:
497 while weechat.infolist_next(infolist):
498 pointer = weechat.infolist_pointer(infolist, 'buffer')
499 if pointer == buffer:
500 file = weechat.infolist_string(infolist, 'log_filename')
501 if weechat.infolist_integer(infolist, 'log_enabled'):
502 #debug('get_file_by_buffer: got %s' %file)
503 return file
504 #else:
505 # debug('get_file_by_buffer: got %s but log not enabled' %file)
506 finally:
507 #debug('infolist gets freed')
508 weechat.infolist_free(infolist)
509
510def get_file_by_name(buffer_name):
511 """Given a buffer name, returns its log path or None. buffer_name should be in 'server.#channel'
512 or '#channel' format."""
513 #debug('get_file_by_name: searching for %s' %buffer_name)
514 # common mask options
515 config_masks = ('logger.mask.irc', 'logger.file.mask')
516 # since there's no buffer pointer, we try to replace some local vars in mask, like $channel and
517 # $server, then replace the local vars left with '*', and use it as a mask for get the path with
518 # get_file_by_pattern
519 for config in config_masks:
520 mask = weechat.config_string(weechat.config_get(config))
521 #debug('get_file_by_name: mask: %s' %mask)
522 if '$name' in mask:
523 mask = mask.replace('$name', buffer_name)
524 elif '$channel' in mask or '$server' in mask:
525 if '.' in buffer_name and \
526 '#' not in buffer_name[:buffer_name.find('.')]: # the dot isn't part of the channel name
527 # ^ I'm asuming channel starts with #, i'm lazy.
528 server, channel = buffer_name.split('.', 1)
529 else:
530 server, channel = '*', buffer_name
531 if '$channel' in mask:
532 mask = mask.replace('$channel', channel)
533 if '$server' in mask:
534 mask = mask.replace('$server', server)
535 # change the unreplaced vars by '*'
536 if '$' in mask:
537 chars = 'abcdefghijklmnopqrstuvwxyz_'
538 masks = mask.split('$')
539 masks = map(lambda s: s.lstrip(chars), masks)
540 mask = '*'.join(masks)
541 if mask[0] != '*':
542 mask = '*' + mask
543 #debug('get_file_by_name: using mask %s' %mask)
544 file = get_file_by_pattern(mask)
545 #debug('get_file_by_name: got file %s' %file)
546 if file:
547 return file
548 return None
549
550def get_buffer_by_name(buffer_name):
551 """Given a buffer name returns its buffer pointer or None."""
552 #debug('get_buffer_by_name: searching for %s' %buffer_name)
553 pointer = weechat.buffer_search('', buffer_name)
554 if not pointer:
555 try:
556 infolist = weechat.infolist_get('buffer', '', '')
557 while weechat.infolist_next(infolist):
558 short_name = weechat.infolist_string(infolist, 'short_name')
559 name = weechat.infolist_string(infolist, 'name')
560 if buffer_name in (short_name, name):
561 #debug('get_buffer_by_name: found %s' %name)
562 pointer = weechat.buffer_search('', name)
563 return pointer
564 finally:
565 weechat.infolist_free(infolist)
566 #debug('get_buffer_by_name: got %s' %pointer)
567 return pointer
568
569def get_all_buffers():
570 """Returns list with pointers of all open buffers."""
571 buffers = []
572 infolist = weechat.infolist_get('buffer', '', '')
573 while weechat.infolist_next(infolist):
574 buffers.append(weechat.infolist_pointer(infolist, 'pointer'))
575 weechat.infolist_free(infolist)
576 grep_buffer = weechat.buffer_search('python', SCRIPT_NAME)
577 if grep_buffer and grep_buffer in buffers:
578 # remove it from list
579 del buffers[buffers.index(grep_buffer)]
580 return buffers
581
582### Grep ###
583def make_regexp(pattern, matchcase=False):
584 """Returns a compiled regexp."""
585 if pattern in ('.', '.*', '.?', '.+'):
586 # because I don't need to use a regexp if we're going to match all lines
587 return None
588 try:
589 import re
590 if not matchcase:
591 regexp = re.compile(pattern, re.IGNORECASE)
592 else:
593 regexp = re.compile(pattern)
594 except Exception, e:
595 raise Exception, 'Bad pattern, %s' %e
596 return regexp
597
598def check_string(s, regexp, hilight='', exact=False):
599 """Checks 's' with a regexp and returns it if is a match."""
600 if not regexp:
601 return s
602 elif exact:
603 matchlist = regexp.findall(s)
604 if matchlist:
605 return matchlist
606 elif hilight:
607 matchlist = regexp.findall(s)
608 if matchlist:
609 matchlist = list(set(matchlist)) # remove duplicates if any
610 # apply hilight
611 color_hilight, color_reset = hilight.split(',', 1)
612 for m in matchlist:
613 s = s.replace(m, '%s%s%s' %(color_hilight, m, color_reset))
614 return s
615 # no need for findall() here
616 elif regexp.search(s):
617 return s
618
619def grep_file(file, head, tail, after_context, before_context, count, regexp, hilight, exact, invert):
620 """Return a list of lines that match 'regexp' in 'file', if no regexp returns all lines."""
621 if count:
622 tail = head = after_context = before_context = False
623 hilight = ''
624 elif exact:
625 before_context = after_context = False
626 hilight = ''
627 elif invert:
628 hilight = ''
629 #debug(' '.join(map(str, (file, head, tail, after_context, before_context))))
630
631 lines = linesList()
632 # define these locally as it makes the loop run slightly faster
633 append = lines.append
634 count_match = lines.count_match
635 separator = lines.append_separator
636 if invert:
637 def check(s):
638 if check_string(s, regexp, hilight, exact):
639 return None
640 else:
641 return s
642 else:
643 check = lambda s: check_string(s, regexp, hilight, exact)
644
645 try:
646 file_object = open(file, 'r')
647 except IOError:
648 # file doesn't exist
649 return lines
650 if tail or before_context:
651 # for these options, I need to seek in the file, but is slower and uses a good deal of
652 # memory if the log is too big, so we do this *only* for these options.
653 file_lines = file_object.readlines()
654
655 if before_context:
656 before_context_range = range(1, before_context + 1)
657 before_context_range.reverse()
658
659 if tail:
660 # instead of searching in the whole file and later pick the last few lines, we
661 # reverse the log, search until count reached and reverse it again, that way is a lot
662 # faster
663 file_lines.reverse()
664 limit = tail or head
665
666 line_idx = 0
667 while line_idx < len(file_lines):
668 line = file_lines[line_idx]
669 line = check(line)
670 if line:
671 if before_context:
672 separator()
673 trimmed = False
674 for id in before_context_range:
675 try:
676 context_line = file_lines[line_idx - id]
677 if check(context_line):
678 # match in before context, that means we appended these same lines in a
679 # previous match, so we delete them merging both paragraphs
680 if not trimmed:
681 del lines[id - before_context - 1:]
682 trimmed = True
683 else:
684 append(context_line)
685 except IndexError:
686 pass
687 append(line)
688 count_match(line)
689 if after_context:
690 id, offset = 0, 0
691 while id < after_context + offset:
692 id += 1
693 try:
694 context_line = file_lines[line_idx + id]
695 _context_line = check(context_line)
696 if _context_line:
697 offset = id
698 context_line = _context_line # so match is hilighted with --hilight
699 count_match()
700 append(context_line)
701 except IndexError:
702 pass
703 separator()
704 line_idx += id
705 if limit and lines.matches_count >= limit:
706 break
707 line_idx += 1
708
709 if tail:
710 lines.reverse()
711 else:
712 # do a normal grep
713 limit = head
714
715 for line in file_object:
716 line = check(line)
717 if line:
718 count or append(line)
719 count_match(line)
720 if after_context:
721 id, offset = 0, 0
722 while id < after_context + offset:
723 id += 1
724 try:
725 context_line = file_object.next()
726 _context_line = check(context_line)
727 if _context_line:
728 offset = id
729 context_line = _context_line
730 count_match()
731 count or append(context_line)
732 except StopIteration:
733 pass
734 separator()
735 if limit and lines.matches_count >= limit:
736 break
737
738 file_object.close()
739 return lines
740
741def grep_buffer(buffer, head, tail, after_context, before_context, count, regexp, hilight, exact,
742 invert):
743 """Return a list of lines that match 'regexp' in 'buffer', if no regexp returns all lines."""
744 lines = linesList()
745 if count:
746 tail = head = after_context = before_context = False
747 hilight = ''
748 elif exact:
749 before_context = after_context = False
750 #debug(' '.join(map(str, (tail, head, after_context, before_context, count, exact, hilight))))
751
752 # Using /grep in grep's buffer can lead to some funny effects
753 # We should take measures if that's the case
754 def make_get_line_funcion():
755 """Returns a function for get lines from the infolist, depending if the buffer is grep's or
756 not."""
757 string_remove_color = weechat.string_remove_color
758 infolist_string = weechat.infolist_string
759 grep_buffer = weechat.buffer_search('python', SCRIPT_NAME)
760 if grep_buffer and buffer == grep_buffer:
761 def function(infolist):
762 prefix = infolist_string(infolist, 'prefix')
763 message = infolist_string(infolist, 'message')
764 if prefix: # only our messages have prefix, ignore it
765 return None
766 return message
767 else:
768 infolist_time = weechat.infolist_time
769 def function(infolist):
770 prefix = string_remove_color(infolist_string(infolist, 'prefix'), '')
771 message = string_remove_color(infolist_string(infolist, 'message'), '')
772 date = infolist_time(infolist, 'date')
773 return '%s\t%s\t%s' %(date, prefix, message)
774 return function
775 get_line = make_get_line_funcion()
776
777 infolist = weechat.infolist_get('buffer_lines', buffer, '')
778 if tail:
779 # like with grep_file() if we need the last few matching lines, we move the cursor to
780 # the end and search backwards
781 infolist_next = weechat.infolist_prev
782 infolist_prev = weechat.infolist_next
783 else:
784 infolist_next = weechat.infolist_next
785 infolist_prev = weechat.infolist_prev
786 limit = head or tail
787
788 # define these locally as it makes the loop run slightly faster
789 append = lines.append
790 count_match = lines.count_match
791 separator = lines.append_separator
792 if invert:
793 def check(s):
794 if check_string(s, regexp, hilight, exact):
795 return None
796 else:
797 return s
798 else:
799 check = lambda s: check_string(s, regexp, hilight, exact)
800
801 if before_context:
802 before_context_range = range(1, before_context + 1)
803 before_context_range.reverse()
804
805 while infolist_next(infolist):
806 line = get_line(infolist)
807 if line is None: continue
808 line = check(line)
809 if line:
810 if before_context:
811 separator()
812 trimmed = False
813 for id in before_context_range:
814 if not infolist_prev(infolist):
815 trimmed = True
816 for id in before_context_range:
817 context_line = get_line(infolist)
818 if check(context_line):
819 if not trimmed:
820 del lines[id - before_context - 1:]
821 trimmed = True
822 else:
823 append(context_line)
824 infolist_next(infolist)
825 count or append(line)
826 count_match(line)
827 if after_context:
828 id, offset = 0, 0
829 while id < after_context + offset:
830 id += 1
831 if infolist_next(infolist):
832 context_line = get_line(infolist)
833 _context_line = check(context_line)
834 if _context_line:
835 context_line = _context_line
836 offset = id
837 count_match()
838 append(context_line)
839 else:
840 # in the main loop infolist_next will start again an cause an infinite loop
841 # this will avoid it
842 infolist_next = lambda x: 0
843 separator()
844 if limit and lines.matches_count >= limit:
845 break
846 weechat.infolist_free(infolist)
847
848 if tail:
849 lines.reverse()
850 return lines
851
852### this is our main grep function
853hook_file_grep = None
854def show_matching_lines():
855 """
856 Greps buffers in search_in_buffers or files in search_in_files and updates grep buffer with the
857 result.
858 """
859 global pattern, matchcase, number, count, exact, hilight, invert
860 global tail, head, after_context, before_context
861 global search_in_files, search_in_buffers, matched_lines, home_dir
862 global time_start
863 matched_lines = linesDict()
864 #debug('buffers:%s \nlogs:%s' %(search_in_buffers, search_in_files))
865 time_start = now()
866
867 # buffers
868 if search_in_buffers:
869 regexp = make_regexp(pattern, matchcase)
870 for buffer in search_in_buffers:
871 buffer_name = weechat.buffer_get_string(buffer, 'name')
872 matched_lines[buffer_name] = grep_buffer(buffer, head, tail, after_context,
873 before_context, count, regexp, hilight, exact, invert)
874
875 # logs
876 if search_in_files:
877 size_limit = get_config_int('size_limit', allow_empty_string=True)
878 background = False
879 if size_limit or size_limit == 0:
880 size = sum(map(get_size, search_in_files))
881 if size > size_limit * 1024:
882 background = True
883 elif size_limit == '':
884 background = False
885
886 if not background:
887 # run grep normally
888 regexp = make_regexp(pattern, matchcase)
889 for log in search_in_files:
890 log_name = strip_home(log)
891 matched_lines[log_name] = grep_file(log, head, tail, after_context, before_context,
892 count, regexp, hilight, exact, invert)
893 buffer_update()
894 else:
895 # we hook a process so grepping runs in background.
896 #debug('on background')
897 global hook_file_grep, script_path, bytecode
898 timeout = 1000*60*10 # 10 min
899
900 quotify = lambda s: '"%s"' %s
901 files_string = ', '.join(map(quotify, search_in_files))
902
903 cmd = grep_proccess_cmd %dict(logs=files_string, head=head, pattern=pattern, tail=tail,
904 hilight=hilight, after_context=after_context, before_context=before_context,
905 exact=exact, matchcase=matchcase, home_dir=home_dir, script_path=script_path,
906 count=count, invert=invert, bytecode=bytecode)
907
908 #debug(cmd)
909 hook_file_grep = weechat.hook_process(cmd, timeout, 'grep_file_callback', '')
910 if hook_file_grep:
911 buffer_create("Searching for '%s' in %s worth of data..." %(pattern,
912 human_readable_size(size)))
913 else:
914 buffer_update()
915
916# defined here for commodity
917grep_proccess_cmd = """python -%(bytecode)sc '
918import sys, cPickle
919sys.path.append("%(script_path)s") # add WeeChat script dir so we can import grep
920from grep import make_regexp, grep_file, strip_home
921logs = (%(logs)s, )
922try:
923 regexp = make_regexp("%(pattern)s", %(matchcase)s)
924 d = {}
925 for log in logs:
926 log_name = strip_home(log, "%(home_dir)s")
927 lines = grep_file(log, %(head)s, %(tail)s, %(after_context)s, %(before_context)s,
928 %(count)s, regexp, "%(hilight)s", %(exact)s, %(invert)s)
929 d[log_name] = lines
930 fdname = "/tmp/grep_search.tmp"
931 fd = open(fdname, "wb")
932 print fdname
933 cPickle.dump(d, fd, -1)
934 fd.close()
935except Exception, e:
936 print >> sys.stderr, e'
937"""
938
939grep_stdout = grep_stderr = ''
940def grep_file_callback(data, command, rc, stdout, stderr):
941 global hook_file_grep, grep_stderr, grep_stdout
942 global matched_lines
943 #debug("rc: %s\nstderr: %s\nstdout: %s" %(rc, repr(stderr), repr(stdout)))
944 if stdout:
945 grep_stdout += stdout
946 if stderr:
947 grep_stderr += stderr
948 if int(rc) >= 0:
949
950 def set_buffer_error():
951 grep_buffer = buffer_create()
952 title = weechat.buffer_get_string(grep_buffer, 'title')
953 title = title + ' %serror' %color_title
954 weechat.buffer_set(grep_buffer, 'title', title)
955
956 try:
957 if grep_stderr:
958 error(grep_stderr)
959 set_buffer_error()
960 elif grep_stdout:
961 #debug(grep_stdout)
962 file = grep_stdout.strip()
963 if file:
964 try:
965 import cPickle, os
966 #debug(file)
967 fd = open(file, 'rb')
968 d = cPickle.load(fd)
969 matched_lines.update(d)
970 fd.close()
971 except Exception, e:
972 error(e)
973 set_buffer_error()
974 else:
975 os.remove(file)
976 buffer_update()
977 finally:
978 grep_stdout = grep_stderr = ''
979 hook_file_grep = None
980 return WEECHAT_RC_OK
981
982def get_grep_file_status():
983 global search_in_files, matched_lines, time_start
984 elapsed = now() - time_start
985 if len(search_in_files) == 1:
986 log = '%s (%s)' %(strip_home(search_in_files[0]),
987 human_readable_size(get_size(search_in_files[0])))
988 else:
989 size = sum(map(get_size, search_in_files))
990 log = '%s log files (%s)' %(len(search_in_files), human_readable_size(size))
991 return 'Searching in %s, running for %.4f seconds. Interrupt it with "/grep stop" or "stop"' \
992 ' in grep buffer.' %(log, elapsed)
993
994### Grep buffer ###
995def buffer_update():
996 """Updates our buffer with new lines."""
997 global matched_lines, pattern, count, hilight, invert
998 time_grep = now()
999
1000 buffer = buffer_create()
1001 if get_config_boolean('clear_buffer'):
1002 weechat.buffer_clear(buffer)
1003 matched_lines.strip_separator() # remove first and last separators of each list
1004 len_total_lines = len(matched_lines)
1005 max_lines = get_config_int('max_lines')
1006 if not count and len_total_lines > max_lines:
1007 weechat.buffer_clear(buffer)
1008
1009 def _make_summary(log, lines, note):
1010 return '%s matches "%s%s%s"%s in %s%s%s%s' \
1011 %(lines.matches_count, color_summary, pattern, color_info,
1012 invert and ' (inverted)' or '',
1013 color_summary, log, color_reset, note)
1014
1015 if count:
1016 make_summary = lambda log, lines : _make_summary(log, lines, ' (not shown)')
1017 else:
1018 def make_summary(log, lines):
1019 if lines.stripped_lines:
1020 if lines:
1021 note = ' (last %s lines shown)' %len(lines)
1022 else:
1023 note = ' (not shown)'
1024 else:
1025 note = ''
1026 return _make_summary(log, lines, note)
1027
1028 global weechat_format
1029 if hilight:
1030 # we don't want colors if there's match highlighting
1031 format_line = lambda s : '%s %s %s' %split_line(s)
1032 else:
1033 def format_line(s):
1034 global nick_dict, weechat_format
1035 date, nick, msg = split_line(s)
1036 if weechat_format:
1037 try:
1038 nick = nick_dict[nick]
1039 except KeyError:
1040 # cache nick
1041 nick_c = color_nick(nick)
1042 nick_dict[nick] = nick_c
1043 nick = nick_c
1044 return '%s%s %s%s %s' %(color_date, date, nick, color_reset, msg)
1045 else:
1046 #no formatting
1047 return msg
1048
1049 prnt = weechat.prnt
1050 prnt(buffer, '\n')
1051 print_line('Search for "%s%s%s"%s in %s%s%s.' %(color_summary, pattern, color_info,
1052 invert and ' (inverted)' or '', color_summary, matched_lines, color_reset),
1053 buffer)
1054 # print last <max_lines> lines
1055 if matched_lines.get_matches_count():
1056 if count:
1057 # with count we sort by matches lines instead of just lines.
1058 matched_lines_items = matched_lines.items_count()
1059 else:
1060 matched_lines_items = matched_lines.items()
1061
1062 matched_lines.get_last_lines(max_lines)
1063 for log, lines in matched_lines_items:
1064 if lines.matches_count:
1065 # matched lines
1066 if not count:
1067 # print lines
1068 weechat_format = True
1069 for line in lines:
1070 #debug(repr(line))
1071 if line == linesList._sep:
1072 # separator
1073 prnt(buffer, context_sep)
1074 else:
1075 if '\x00' in line:
1076 # log was corrupted
1077 error("Found garbage in log '%s', maybe it's corrupted" %log,
1078 trace=repr(line))
1079 line = line.replace('\x00', '')
1080 prnt(buffer, format_line(line))
1081
1082 # summary
1083 if count or get_config_boolean('show_summary'):
1084 summary = make_summary(log, lines)
1085 print_line(summary, buffer)
1086
1087 # separator
1088 if not count and lines:
1089 prnt(buffer, '\n')
1090 else:
1091 print_line('No matches found.', buffer)
1092
1093 # set title
1094 global time_start
1095 time_end = now()
1096 # total time
1097 time_total = time_end - time_start
1098 # percent of the total time used for grepping
1099 time_grep_pct = (time_grep - time_start)/time_total*100
1100 #debug('time: %.4f seconds (%.2f%%)' %(time_total, time_grep_pct))
1101 if not count and len_total_lines > max_lines:
1102 note = ' (last %s lines shown)' %len(matched_lines)
1103 else:
1104 note = ''
1105 title = "Search in %s%s%s %s matches%s | pattern \"%s%s%s\"%s %s | %.4f seconds (%.2f%%)" \
1106 %(color_title, matched_lines, color_reset, matched_lines.get_matches_count(), note,
1107 color_title, pattern, color_reset, invert and ' (inverted)' or '', format_options(),
1108 time_total, time_grep_pct)
1109 weechat.buffer_set(buffer, 'title', title)
1110
1111 if get_config_boolean('go_to_buffer'):
1112 weechat.buffer_set(buffer, 'display', '1')
1113
1114 # free matched_lines so it can be removed from memory
1115 del matched_lines
1116
1117def split_line(s):
1118 """Splits log's line 's' in 3 parts, date, nick and msg."""
1119 global weechat_format
1120 if weechat_format and s.count('\t') >= 2:
1121 date, nick, msg = s.split('\t', 2) # date, nick, message
1122 else:
1123 # looks like log isn't in weechat's format
1124 weechat_format = False # incoming lines won't be formatted
1125 date, nick, msg = '', '', s
1126 # remove tabs
1127 if '\t' in msg:
1128 msg = msg.replace('\t', ' ')
1129 return date, nick, msg
1130
1131def print_line(s, buffer=None, display=False):
1132 """Prints 's' in script's buffer as 'script_nick'. For displaying search summaries."""
1133 if buffer is None:
1134 buffer = buffer_create()
1135 say('%s%s' %(color_info, s), buffer=buffer)
1136 if display and get_config_boolean('go_to_buffer'):
1137 weechat.buffer_set(buffer, 'display', '1')
1138
1139def format_options():
1140 global matchcase, number, count, exact, hilight, invert
1141 global tail, head, after_context, before_context
1142 options = []
1143 append = options.append
1144 insert = options.insert
1145 chars = 'cHmov'
1146 for i, flag in enumerate((count, hilight, matchcase, exact, invert)):
1147 if flag:
1148 append(chars[i])
1149
1150 if head or tail:
1151 n = get_config_int('default_tail_head')
1152 if head:
1153 append('h')
1154 if head != n:
1155 insert(-1, ' -')
1156 append('n')
1157 append(head)
1158 elif tail:
1159 append('t')
1160 if tail != n:
1161 insert(-1, ' -')
1162 append('n')
1163 append(tail)
1164
1165 if before_context and after_context and (before_context == after_context):
1166 append(' -C')
1167 append(before_context)
1168 else:
1169 if before_context:
1170 append(' -B')
1171 append(before_context)
1172 if after_context:
1173 append(' -A')
1174 append(after_context)
1175
1176 s = ''.join(map(str, options)).strip()
1177 if s and s[0] != '-':
1178 s = '-' + s
1179 return s
1180
1181def buffer_create(title=None):
1182 """Returns our buffer pointer, creates and cleans the buffer if needed."""
1183 buffer = weechat.buffer_search('python', SCRIPT_NAME)
1184 if not buffer:
1185 buffer = weechat.buffer_new(SCRIPT_NAME, 'buffer_input', '', '', '')
1186 weechat.buffer_set(buffer, 'time_for_each_line', '0')
1187 weechat.buffer_set(buffer, 'nicklist', '0')
1188 weechat.buffer_set(buffer, 'title', title or 'grep output buffer')
1189 weechat.buffer_set(buffer, 'localvar_set_no_log', '1')
1190 elif title:
1191 weechat.buffer_set(buffer, 'title', title)
1192 return buffer
1193
1194def buffer_input(data, buffer, input_data):
1195 """Repeats last search with 'input_data' as regexp."""
1196 try:
1197 cmd_grep_stop(buffer, input_data)
1198 except:
1199 return WEECHAT_RC_OK
1200
1201 global search_in_buffers, search_in_files
1202 global pattern
1203 try:
1204 if pattern and (search_in_files or search_in_buffers):
1205 # check if the buffer pointers are still valid
1206 for pointer in search_in_buffers:
1207 infolist = weechat.infolist_get('buffer', pointer, '')
1208 if not infolist:
1209 del search_in_buffers[search_in_buffers.index(pointer)]
1210 weechat.infolist_free(infolist)
1211 try:
1212 cmd_grep_parsing(input_data)
1213 except Exception, e:
1214 error('Argument error, %s' %e, buffer=buffer)
1215 return WEECHAT_RC_OK
1216 try:
1217 show_matching_lines()
1218 except Exception, e:
1219 error(e)
1220 except NameError:
1221 error("There isn't any previous search to repeat.", buffer=buffer)
1222 return WEECHAT_RC_OK
1223
1224### Commands ###
1225def cmd_init():
1226 """Resets global vars."""
1227 global home_dir, cache_dir, nick_dict
1228 global pattern, matchcase, number, count, exact, hilight, invert
1229 global tail, head, after_context, before_context
1230 hilight = ''
1231 head = tail = after_context = before_context = invert = False
1232 matchcase = count = exact = False
1233 pattern = number = None
1234 home_dir = get_home()
1235 cache_dir = {} # for avoid walking the dir tree more than once per command
1236 nick_dict = {} # nick cache for don't calculate nick color every time
1237
1238def cmd_grep_parsing(args):
1239 """Parses args for /grep and grep input buffer."""
1240 global pattern, matchcase, number, count, exact, hilight, invert
1241 global tail, head, after_context, before_context
1242 global log_name, buffer_name, only_buffers, all
1243 opts, args = getopt.gnu_getopt(args.split(), 'cmHeahtivn:bA:B:C:o', ['count', 'matchcase', 'hilight',
1244 'exact', 'all', 'head', 'tail', 'number=', 'buffer', 'after-context=', 'before-context=',
1245 'context=', 'invert', 'only-match'])
1246 #debug(opts, 'opts: '); debug(args, 'args: ')
1247 if len(args) >= 2:
1248 if args[0] == 'log':
1249 del args[0]
1250 log_name = args.pop(0)
1251 elif args[0] == 'buffer':
1252 del args[0]
1253 buffer_name = args.pop(0)
1254 args = ' '.join(args) # join pattern for keep spaces
1255 if args:
1256 pattern = args
1257 elif not pattern:
1258 raise Exception, 'No pattern for grep the logs.'
1259
1260 def positive_number(opt, val):
1261 try:
1262 number = int(val)
1263 if number < 0:
1264 raise ValueError
1265 return number
1266 except ValueError:
1267 if len(opt) == 1:
1268 opt = '-' + opt
1269 else:
1270 opt = '--' + opt
1271 raise Exception, "argument for %s must be a positive integer." %opt
1272
1273 for opt, val in opts:
1274 opt = opt.strip('-')
1275 if opt in ('c', 'count'):
1276 count = not count
1277 elif opt in ('m', 'matchcase'):
1278 matchcase = not matchcase
1279 elif opt in ('H', 'hilight'):
1280 # hilight must be always a string!
1281 if hilight:
1282 hilight = ''
1283 else:
1284 hilight = '%s,%s' %(color_hilight, color_reset)
1285 # we pass the colors in the variable itself because check_string() must not use
1286 # weechat's module when applying the colors (this is for grep in a hooked process)
1287 elif opt in ('e', 'exact', 'o', 'only-match'):
1288 exact = not exact
1289 invert = False
1290 elif opt in ('a', 'all'):
1291 all = not all
1292 elif opt in ('h', 'head'):
1293 head = not head
1294 tail = False
1295 elif opt in ('t', 'tail'):
1296 tail = not tail
1297 head = False
1298 elif opt in ('b', 'buffer'):
1299 only_buffers = True
1300 elif opt in ('n', 'number'):
1301 number = positive_number(opt, val)
1302 elif opt in ('C', 'context'):
1303 n = positive_number(opt, val)
1304 after_context = n
1305 before_context = n
1306 elif opt in ('A', 'after-context'):
1307 after_context = positive_number(opt, val)
1308 elif opt in ('B', 'before-context'):
1309 before_context = positive_number(opt, val)
1310 elif opt in ('i', 'v', 'invert'):
1311 invert = not invert
1312 exact = False
1313 # number check
1314 if number is not None:
1315 if number == 0:
1316 head = tail = False
1317 number = None
1318 elif head:
1319 head = number
1320 elif tail:
1321 tail = number
1322 else:
1323 n = get_config_int('default_tail_head')
1324 if head:
1325 head = n
1326 elif tail:
1327 tail = n
1328
1329def cmd_grep_stop(buffer, args):
1330 global hook_file_grep, pattern, matched_lines
1331 if hook_file_grep:
1332 if args == 'stop':
1333 weechat.unhook(hook_file_grep)
1334 hook_file_grep = None
1335 s = 'Search for \'%s\' stopped.' %pattern
1336 say(s, buffer=buffer)
1337 grep_buffer = weechat.buffer_search('python', SCRIPT_NAME)
1338 if grep_buffer:
1339 weechat.buffer_set(grep_buffer, 'title', s)
1340 del matched_lines
1341 else:
1342 say(get_grep_file_status(), buffer=buffer)
1343 raise Exception
1344
1345def cmd_grep(data, buffer, args):
1346 """Search in buffers and logs."""
1347 global pattern, matchcase, head, tail, number, count, exact, hilight
1348 try:
1349 cmd_grep_stop(buffer, args)
1350 except:
1351 return WEECHAT_RC_OK
1352
1353 if not args:
1354 weechat.command('', '/help %s' %SCRIPT_COMMAND)
1355 return WEECHAT_RC_OK
1356
1357 cmd_init()
1358 global log_name, buffer_name, only_buffers, all
1359 log_name = buffer_name = ''
1360 only_buffers = all = False
1361
1362 # parse
1363 try:
1364 cmd_grep_parsing(args)
1365 except Exception, e:
1366 error('Argument error, %s' %e)
1367 return WEECHAT_RC_OK
1368
1369 # find logs
1370 log_file = search_buffer = None
1371 if log_name:
1372 log_file = get_file_by_pattern(log_name, all)
1373 if not log_file:
1374 error("Couldn't find any log for %s. Try /logs" %log_name)
1375 return WEECHAT_RC_OK
1376 elif all:
1377 search_buffer = get_all_buffers()
1378 elif buffer_name:
1379 search_buffer = get_buffer_by_name(buffer_name)
1380 if not search_buffer:
1381 # there's no buffer, try in the logs
1382 log_file = get_file_by_name(buffer_name)
1383 if not log_file:
1384 error("Logs or buffer for '%s' not found." %buffer_name)
1385 return WEECHAT_RC_OK
1386 else:
1387 search_buffer = [search_buffer]
1388 else:
1389 search_buffer = [buffer]
1390
1391 # make the log list
1392 global search_in_files, search_in_buffers
1393 search_in_files = []
1394 search_in_buffers = []
1395 if log_file:
1396 search_in_files = log_file
1397 elif not only_buffers:
1398 #debug(search_buffer)
1399 for pointer in search_buffer:
1400 log = get_file_by_buffer(pointer)
1401 #debug('buffer %s log %s' %(pointer, log))
1402 if log:
1403 search_in_files.append(log)
1404 else:
1405 search_in_buffers.append(pointer)
1406 else:
1407 search_in_buffers = search_buffer
1408
1409 # grepping
1410 try:
1411 show_matching_lines()
1412 except Exception, e:
1413 error(e)
1414 return WEECHAT_RC_OK
1415
1416def cmd_logs(data, buffer, args):
1417 """List files in Weechat's log dir."""
1418 cmd_init()
1419 global home_dir
1420 sort_by_size = False
1421 filter = []
1422
1423 try:
1424 opts, args = getopt.gnu_getopt(args.split(), 's', ['size'])
1425 if args:
1426 filter = args
1427 for opt, var in opts:
1428 opt = opt.strip('-')
1429 if opt in ('size', 's'):
1430 sort_by_size = True
1431 except Exception, e:
1432 error('Argument error, %s' %e)
1433 return WEECHAT_RC_OK
1434
1435 # is there's a filter, filter_excludes should be False
1436 file_list = dir_list(home_dir, filter, filter_excludes=not filter)
1437 if sort_by_size:
1438 file_list.sort(key=get_size)
1439 else:
1440 file_list.sort()
1441
1442 file_sizes = map(lambda x: human_readable_size(get_size(x)), file_list)
1443 # calculate column lenght
1444 if file_list:
1445 L = file_list[:]
1446 L.sort(key=len)
1447 bigest = L[-1]
1448 column_len = len(bigest) + 3
1449 else:
1450 column_len = ''
1451
1452 buffer = buffer_create()
1453 if get_config_boolean('clear_buffer'):
1454 weechat.buffer_clear(buffer)
1455 file_list = zip(file_list, file_sizes)
1456 msg = 'Found %s logs.' %len(file_list)
1457
1458 print_line(msg, buffer, display=True)
1459 for file, size in file_list:
1460 separator = column_len and '.'*(column_len - len(file))
1461 weechat.prnt(buffer, '%s %s %s' %(strip_home(file), separator, size))
1462 if file_list:
1463 print_line(msg, buffer)
1464 return WEECHAT_RC_OK
1465
1466### Completion ###
1467def completion_log_files(data, completion_item, buffer, completion):
1468 #debug('completion: %s' %', '.join((data, completion_item, buffer, completion)))
1469 global home_dir
1470 l = len(home_dir)
1471 completion_list_add = weechat.hook_completion_list_add
1472 WEECHAT_LIST_POS_END = weechat.WEECHAT_LIST_POS_END
1473 for log in dir_list(home_dir):
1474 completion_list_add(completion, log[l:], 0, WEECHAT_LIST_POS_END)
1475 return WEECHAT_RC_OK
1476
1477def completion_grep_args(data, completion_item, buffer, completion):
1478 for arg in ('count', 'all', 'matchcase', 'hilight', 'exact', 'head', 'tail', 'number', 'buffer',
1479 'after-context', 'before-context', 'context', 'invert', 'only-match'):
1480 weechat.hook_completion_list_add(completion, '--' + arg, 0, weechat.WEECHAT_LIST_POS_SORT)
1481 return WEECHAT_RC_OK
1482
1483### Main ###
1484def delete_bytecode():
1485 global script_path
1486 bytecode = path.join(script_path, SCRIPT_NAME + '.pyc')
1487 if path.isfile(bytecode):
1488 os.remove(bytecode)
1489 return WEECHAT_RC_OK
1490
1491if __name__ == '__main__' and import_ok and \
1492 weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, \
1493 SCRIPT_DESC, 'delete_bytecode', ''):
1494 home_dir = get_home()
1495
1496 # for import ourselves
1497 global script_path
1498 script_path = path.dirname(__file__)
1499 sys.path.append(script_path)
1500 delete_bytecode()
1501
1502 # check python version
1503 import sys
1504 global bytecode
1505 if sys.version_info > (2, 6):
1506 bytecode = 'B'
1507 else:
1508 bytecode = ''
1509
1510
1511 weechat.hook_command(SCRIPT_COMMAND, cmd_grep.__doc__,
1512 "[log <file> | buffer <name> | stop] [-a|--all] [-b|--buffer] [-c|--count] [-m|--matchcase] "
1513 "[-H|--hilight] [-o|--only-match] [-i|-v|--invert] [(-h|--head)|(-t|--tail) [-n|--number <n>]] "
1514 "[-A|--after-context <n>] [-B|--before-context <n>] [-C|--context <n> ] <expression>",
1515# help
1516"""
1517 log <file>: Search in one log that matches <file> in the logger path.
1518 Use '*' and '?' as wildcards.
1519 buffer <name>: Search in buffer <name>, if there's no buffer with <name> it will
1520 try to search for a log file.
1521 stop: Stops a currently running search.
1522 -a --all: Search in all open buffers.
1523 If used with 'log <file>' search in all logs that matches <file>.
1524 -b --buffer: Search only in buffers, not in file logs.
1525 -c --count: Just count the number of matched lines instead of showing them.
1526 -m --matchcase: Don't do case insensible search.
1527 -H --hilight: Colour exact matches in output buffer.
1528-o --only-match: Print only the matching part of the line.
1529 -v -i --invert: Print lines that don't match the regular expression.
1530 -t --tail: Print the last 10 matching lines.
1531 -h --head: Print the first 10 matching lines.
1532-n --number <n>: Overrides default number of lines for --tail or --head.
1533-A --after-context <n>: Shows <n> lines of trailing context after matching lines.
1534-B --before-context <n>: Shows <n> lines of leading context before matching lines.
1535-C --context <n>: Same as using both --after-context and --before-context simultaneously.
1536 <expression>: Expression to search.
1537
1538Grep buffer:
1539 Input line accepts most arguemnts of /grep, it'll repeat last search using the new
1540 arguments provided. You can't search in different logs from the buffer's input.
1541 Boolean arguments like --count, --tail, --head, --hilight, ... are toggleable
1542
1543Python regular expression syntax:
1544 See http://docs.python.org/lib/re-syntax.html
1545""",
1546 # completion template
1547 "buffer %(buffers_names) %(grep_arguments)|%*"
1548 "||log %(grep_log_files) %(grep_arguments)|%*"
1549 "||stop"
1550 "||%(grep_arguments)|%*",
1551 'cmd_grep' ,'')
1552 weechat.hook_command('logs', cmd_logs.__doc__, "[-s|--size] [<filter>]",
1553 "-s --size: Sort logs by size.\n"
1554 " <filter>: Only show logs that match <filter>. Use '*' and '?' as wildcards.", '--size', 'cmd_logs', '')
1555
1556 weechat.hook_completion('grep_log_files', "list of log files",
1557 'completion_log_files', '')
1558 weechat.hook_completion('grep_arguments', "list of arguments",
1559 'completion_grep_args', '')
1560
1561 # settings
1562 for opt, val in settings.iteritems():
1563 if not weechat.config_is_set_plugin(opt):
1564 weechat.config_set_plugin(opt, val)
1565
1566 # colors
1567 color_date = weechat.color('brown')
1568 color_info = weechat.color('cyan')
1569 color_hilight = weechat.color('lightred')
1570 color_reset = weechat.color('reset')
1571 color_title = weechat.color('yellow')
1572 color_summary = weechat.color('lightcyan')
1573 color_delimiter = weechat.color('chat_delimiters')
1574 color_script_nick = weechat.color('chat_nick')
1575
1576 # pretty [grep]
1577 script_nick = '%s[%s%s%s]%s' %(color_delimiter, color_script_nick, SCRIPT_NAME, color_delimiter,
1578 color_reset)
1579 script_nick_nocolor = '[%s]' %SCRIPT_NAME
1580 # paragraph separator when using context options
1581 context_sep = '%s\t%s--' %(script_nick, color_info)
1582
1583# vim:set shiftwidth=4 tabstop=4 softtabstop=4 expandtab textwidth=100:
diff --git a/notify.py b/notify.py
new file mode 100644
index 0000000..c8b91e9
--- a/dev/null
+++ b/notify.py
@@ -0,0 +1,117 @@
1# Author: lavaramano <lavaramano AT gmail DOT com>
2# Improved by: BaSh - <bash.lnx AT gmail DOT com>
3# Ported to Weechat 0.3.0 by: Sharn - <sharntehnub AT gmail DOT com)
4# This Plugin Calls the libnotify bindings via python when somebody says your nickname, sends you a query, etc.
5# To make it work, you may need to download: python-notify (and libnotify - libgtk)
6# Requires Weechat 0.3.0
7# Released under GNU GPL v2
8#
9# 2010-09-22, Raghavendra Prabhu
10# Added some stuff.
11# 2010-02-20, Aron Griffis <[email protected]>
12# version 0.0.5: Add nick_separator, don't call show_notification twice on
13# privmsg, fix spelling s/nofify/notify/, use nick as "summary" for privmsg
14# notification, fit in 80 columns, tweak vim modeline.
15# 2010-01-24, David Rubin <[email protected]>
16# version 0.0.4.2 Fixed issue with self notifications when used with out "smart_notification"
17# 2010-01-19, Didier Roche <[email protected]>
18# version 0.0.4.1: add private message sender name
19# 2010-01-19, Didier Roche <[email protected]>
20# version 0.0.4: add smart notification:
21# be notified only if you're not in the current channel/pv window (off by default)
22# 2009-06-16, kba <[email protected]>:
23# version 0.0.3: added config options for icon and urgency
24# 2009-05-02, FlashCode <[email protected]>:
25# version 0.0.2.1: sync with last API changes
26
27import weechat, pynotify, string
28weechat.register("notify", "lavaramano", "0.0.5", "GPL", "notify: A real time notification system for weechat", "", "")
29
30# script options
31settings = {
32 "show_hilights" : "on",
33 "show_priv_msg" : "on",
34 "nick_separator" : ": ",
35 "icon" : "/usr/share/pixmaps/weechat.xpm",
36 "path" : "~/logs/me.log",
37 "urgency" : "normal",
38 "smart_notification" : "off",
39}
40
41urgencies = {
42 "low" : pynotify.URGENCY_LOW,
43 "critical" : pynotify.URGENCY_CRITICAL,
44 "normal" : pynotify.URGENCY_NORMAL,
45}
46
47# Init everything
48for option, default_value in settings.items():
49 if weechat.config_get_plugin(option) == "":
50 weechat.config_set_plugin(option, default_value)
51
52# Hook privmsg/hilights
53weechat.hook_print("", "irc_privmsg", "", 1, "notify_show", "")
54
55# Functions
56def notify_show(data, bufferp, uber_empty, tagsn, isdisplayed,
57 ishilight, prefix, message):
58 """Sends highlighted message to be printed on notification"""
59 try:
60 if (weechat.config_get_plugin('smart_notification') == "on" and
61 bufferp == weechat.current_buffer() and focussed()):
62 pass
63
64 elif (weechat.buffer_get_string(bufferp, "localvar_type") == "private" and
65 weechat.config_get_plugin('show_priv_msg') == "on"):
66 show_notification(prefix, message)
67
68 elif (ishilight == "1" and
69 weechat.config_get_plugin('show_hilights') == "on"):
70 buffer = (weechat.buffer_get_string(bufferp, "short_name") or
71 weechat.buffer_get_string(bufferp, "name"))
72 show_notification(buffer, prefix +
73 weechat.config_get_plugin('nick_separator') + message)
74 except ex:
75 writetofile(weechat.config_get_plugin('path'),prefix,message,str(ex))
76
77 return weechat.WEECHAT_RC_OK
78
79def show_notification(chan,message):
80 print('\a')
81 pynotify.init("wee-notifier")
82 writetofile(weechat.config_get_plugin('path'),chan,message)
83 wn = pynotify.Notification(chan, message, weechat.config_get_plugin('icon'))
84 wn.set_urgency(urgencies[weechat.config_get_plugin('urgency')] or
85 pynotify.URGENCY_NORMAL)
86 wn.show()
87
88def writetofile(path,chan,message,exception=""):
89 import os
90 import datetime
91 fullpath = os.path.expanduser(path)
92 file = open(fullpath,"a")
93 file.writelines(str(datetime.datetime.now().ctime()))
94 if exception:
95 file.writelines("\n\n --------> "+exception+"<------------\n")
96 file.writelines(" \n\nWeechat priv:==============>\n")
97 file.writelines(str(chan+" : "+message+"\n"))
98 file.writelines("<==============\n\n")
99 file.close()
100
101
102
103def focussed():
104 import subprocess
105 import re
106 # tmux display-message -p and xdotool getactivewindow getwindowpid
107 x,y=subprocess.Popen("\
108 [[ `xdotool getactivewindow getwindowpid` == `pidof urxvtd` ]];\
109 echo -n $?",shell=True,stdout=subprocess.PIPE).communicate()
110 if(x == 0):
111 current,discard = subprocess.Popen("tmux display-message -p",shell=True\
112 ,stdout=subprocess.PIPE).communicate()
113 if re.match(".*weechat.*",current):
114 return True
115 return False
116
117# vim: autoindent expandtab smarttab shiftwidth=4