25
25
import pida.core.service as service
26
import pida.core.registry as registry
27
import pida.pidagtk.contentbook as contentbook
28
import pida.pidagtk.contentview as contentview
29
import pida.pidagtk.filedialogs as filedialogs
30
import pida.pidagtk.tree as tree
26
from pida.pidagtk import contentview, filedialogs, tree
32
28
#import pida.utils.pygrep as pygrep
44
import pida.core.actions as actions
38
from pida.core import actions
39
from pida.utils.gthreads import locked, gcall
40
from gobject import markup_escape_text
42
from pida.model import attrtypes as types
47
43
defs = service.definitions
49
45
table = range(0,128) * 2
159
155
def cb_result_selected(self, tree, result):
160
156
#lines = self.boss.option('grepper', 'context-lines')
162
pre, match, post = [cgi.escape(s) for s in
158
pre, match, post = [markup_escape_text(s) for s in
163
159
result.value.get_context(lines)]
164
160
self.__context_label.set_markup(RESULT_CONTEXT_MU % (pre, match, post))
213
209
def cb_activated(self, entry):
214
210
self.service.grep_start()
216
class Grepper(service.service):
218
single_view_type = GrepView
219
single_view_book = 'view'
221
display_name = 'Grep Search'
213
__order__ = ['default_options', 'results']
223
214
class default_options(defs.optiongroup):
224
215
"""Options that the search will start with by default."""
216
__order__ = ['start_detailed', 'recursive_search',
217
'ignore_version_control_directories']
218
label = 'Default Search Options'
225
219
class start_detailed(defs.option):
226
220
"""Whether the detailed search options will start expanded."""
221
label = 'Start with details visible'
227
222
rtype = types.boolean
229
224
class recursive_search(defs.option):
230
225
"""Whether the search will be recursive by default."""
231
226
rtype = types.boolean
228
label = 'Recursive search'
233
229
class ignore_version_control_directories(defs.option):
234
230
"""Whether version control directories will be ignored by default."""
235
231
rtype = types.boolean
233
label = 'Ignore version control directories'
237
234
class results(defs.optiongroup):
238
235
"""Options relating to search results."""
236
__order__ = ['maximum_results']
237
label = 'Result Options'
239
238
class maximum_results(defs.option):
240
239
"""The maximum number of search results."""
240
label = 'Maximum number of results'
241
241
rtype = types.intrange(5, 5000, 5)
244
__markup__ = lambda self: 'Text Searcher'
246
class Grepper(service.service):
248
config_definition = GrepConfig
250
class GrepView(defs.View):
254
display_name = 'Grep Search'
244
256
def grep_start(self):
245
257
opts = self.single_view.get_options()
246
258
if not opts.pattern:
262
274
def cb_results_status(self, grep, status):
263
275
self.single_view.show_status(status)
266
277
def cmd_find_interactive(self, directories=None, ignorevcs=None,
268
self.create_single_view()
280
opts = self.options.default_options
281
view = self.create_view('GrepView')
269
282
options = GrepOptions()
284
self.show_view(view=view)
270
286
if directories is None:
271
287
proj = self.boss.call_command('projectmanager',
272
288
'get_current_project')
273
290
if proj is not None:
274
options.directories = [proj.source_directory]
291
options.directories = [proj.source__directory]
276
293
options.directories = [os.getcwd()]
278
295
options.directories = directories
279
296
if ignorevcs is None:
280
options.ignorevcs = self.opt(
281
'default_options', 'ignore_version_control_directories')
297
options.ignorevcs = opts.ignore_version_control_directories
283
299
options.ignorevcs = ignorevcs
284
300
if recursive is None:
285
options.recursive = self.opt(
286
'default_options', 'recursive_search')
301
options.recursive = opts.recursive_search
288
303
options.recursive = recursive
289
options.maxresults = self.opt('results', 'maximum_results')
304
options.maxresults = self.opts.results__maximum_results
290
305
self.single_view.from_options(options)
291
self.single_view.set_details_expanded(self.opt(
292
'default_options', 'start_detailed'))
306
self.single_view.set_details_expanded(opts.start_detailed)
294
308
def cmd_find(self, path, pattern):
298
311
def cb_search_clicked(self, button):
299
312
self.cmd_find_interactive()
301
314
def cb_view_action(self, view, name):
302
315
if name == 'apply':
305
318
self.__grep.stop()
307
320
@actions.action(stock_id='gtk-searchtool',
361
377
for match in matches:
362
378
prematch, line = line.split(match, 1)
363
muline = '%s%s' % (muline, cgi.escape(prematch))
364
muline = '%s%s' % (muline, MATCH_MU % cgi.escape(match))
365
self.muline = '%s%s' % (muline, cgi.escape(line))
379
muline = '%s%s' % (muline, markup_escape_text(prematch))
380
muline = '%s%s' % (muline, MATCH_MU % markup_escape_text(match))
381
self.muline = '%s%s' % (muline, markup_escape_text(line))
367
383
def get_context(self, lines=2):
380
396
def get_markup(self):
381
397
return RESULT_MU % (self.linenumber,
382
cgi.escape(self.filename),
398
markup_escape_text(self.filename),
384
400
markup = property(get_markup)
386
402
class PidaGrep(gobject.GObject):
403
"""An object that contains two signals, 'found' and 'status',
404
used to monitor its state. This object greps through a group of
388
407
__gsignals__ = {'found' : (
389
408
gobject.SIGNAL_RUN_LAST,
390
409
gobject.TYPE_NONE,
400
419
self.__pattern = re.compile(options.pattern)
402
421
self.__running = False
422
self.lock = threading.Lock()
424
running = property(lambda x: x.__running,
425
doc="Returns if this operation is running")
405
self.__t = threading.Thread(target = self.__run)
407
431
self.__running = True
432
threading.Thread(target=self._run).start()
434
def _get_files(self):
410
435
for directory in self.__options.directories:
411
436
for dirname, dirnames, filenames in os.walk(directory):
412
437
if not self.__options.recursive:
413
438
dirnames[0:] = []
415
440
if self.__options.ignorevcs:
417
if d in ['.svn', 'CVS', '_darcs']:
441
for vcs_dir in ['.svn', 'CVS', '_darcs', '.bzr']:
443
dirnames.remove(vcs_dir)
419
447
for filename in filenames:
420
448
filepath = os.path.join(dirname, filename)
422
450
for filepath in self.__options.files:
428
except StopIteration:
432
self.status(1, "searching")
434
for i, filename in enumerate(self.get_files()):
453
def _find_files(self):
454
self._status(1, "searching")
457
for i, filename in enumerate(self._get_files()):
458
if not self.running or found >= self.__options.maxresults:
461
# update status from time to time
436
self.status(self.__nfound)
438
466
f = open(filename, 'r')
441
470
for linenumber, line in enumerate(f):
442
if not self.__running:
444
475
if BINARY_RE.match(line):
446
478
line = string.translate(line, all_chars, hi_bit_chars)
447
479
line = string.translate(line, hi_lo_table)
448
480
matches = self.__pattern.findall(line)
450
self.__nfound = self.__nfound + len(matches)
451
if self.__nfound >= self.__options.maxresults:
483
found = found + len(matches)
485
# break when we have found enough values
486
if found >= self.__options.maxresults:
489
# emit the result we've found
453
490
result = GrepResult(linenumber, filename, line, matches)
455
self.emit('found', result)
491
gcall(self.emit, 'found', result)
460
def status(self, code, message=None):
462
self.emit('status', (code, message))
499
self._status(1, '%s found' % self._find_files())
502
self.__running = False
505
def _status(self, code, message=None):
506
gcall(self.emit, 'status', (code, message))
510
"""Use this method to stop this operation"""
466
511
self.__running = False
468
def __finished(self):
469
self.status(1, '%s found' % self.__nfound)
472
513
gobject.type_register(PidaGrep)
474
515
Service = Grepper