Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: More find in files improvements #4599

Merged
merged 15 commits into from
Jun 22, 2017
Merged
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 80 additions & 37 deletions spyder/widgets/findinfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from spyder.config.base import _
from spyder.py3compat import getcwd, to_text_string
from spyder.utils import icon_manager as ima
from spyder.utils.qthelpers import create_toolbutton, get_filetype_icon
from spyder.utils.qthelpers import create_toolbutton
from spyder.utils.encoding import is_text_file
from spyder.widgets.comboboxes import PatternComboBox
from spyder.widgets.onecolumntree import OneColumnTree
Expand Down Expand Up @@ -128,42 +128,68 @@ def find_files_in_path(self, path):

def truncate_result(self, line, start, end):
ellipsis = '...'

max_line_length = 80
max_num_char_fragment = 40

html_escape_table = {
"&": "&",
'"': """,
"'": "'",
">": ">",
"<": "&lt;",
}

def html_escape(text):
"""Produce entities within text."""
return "".join(html_escape_table.get(c, c) for c in text)

line = to_text_string(line)
left, match, right = line[:start], line[start:end], line[end:]
max_line_length = 40
offset = (len(line) - len(match)) // 2

left = left.split(' ')
num_left_words = len(left)
if len(line) > max_line_length:
offset = (len(line) - len(match)) // 2

left = left.split(' ')
num_left_words = len(left)

if num_left_words == 1:
left = left[0]
if len(left) > max_num_char_fragment:
left = ellipsis + left[-offset:]
left = [left]

if num_left_words == 1:
left = left[0]
if len(left) > max_line_length:
left = ellipsis + left[-offset:]
left = [left]
right = right.split(' ')
num_right_words = len(right)

right = right.split(' ')
num_right_words = len(right)
if num_right_words == 1:
right = right[0]
if len(right) > max_num_char_fragment:
right = right[:offset] + ellipsis
right = [right]

if num_right_words == 1:
right = right[0]
if len(right) > max_line_length:
right = right[:offset] + ellipsis
right = [right]
left = left[-4:]
right = right[:4]

left = left[-3:]
right = right[:3]
if len(left) < num_left_words:
left = [ellipsis] + left

if len(left) < num_left_words:
left = [ellipsis] + left
if len(right) < num_right_words:
right = right + [ellipsis]

if len(right) < num_right_words:
right = right + [ellipsis]
left = ' '.join(left)
right = ' '.join(right)

left = ' '.join(left)
right = ' '.join(right)
if len(left) > max_num_char_fragment:
left = ellipsis + left[-30:]

trunc_line = '{0}<b>{1}</b>{2}'.format(left, match, right)
if len(right) > max_num_char_fragment:
right = right[:30] + ellipsis

line_match_format = to_text_string('{0}<b>{1}</b>{2}')
left = html_escape(left)
right = html_escape(right)
match = html_escape(match)
trunc_line = line_match_format.format(left, match, right)
return trunc_line

def find_string_in_file(self, fname):
Expand Down Expand Up @@ -493,23 +519,31 @@ def __ge__(self, x):


class FileMatchItem(QTreeWidgetItem):
def __init__(self, parent, filename):
def __init__(self, parent, filename, sorting_status):

self.sorting_status = sorting_status
self.filename = osp.basename(filename)

title = ('<b>{0}</b><br>'
'<small><em>{1}</em>'
'</small>'.format(osp.basename(filename),
osp.dirname(filename)))
title_format = to_text_string('<b>{0}</b><br>'
'<small><em>{1}</em>'
'</small>')
title = (title_format.format(osp.basename(filename),
osp.dirname(filename)))
QTreeWidgetItem.__init__(self, parent, [title], QTreeWidgetItem.Type)

self.setToolTip(0, filename)

def __lt__(self, x):
return self.filename < x.filename
if self.sorting_status['status']:
return self.filename < x.filename
else:
return False

def __ge__(self, x):
return self.filename >= x.filename
if self.sorting_status['status']:
return self.filename >= x.filename
else:
return False


class ItemDelegate(QStyledItemDelegate):
Expand Down Expand Up @@ -559,13 +593,15 @@ def __init__(self, parent):
self.total_matches = None
self.error_flag = None
self.completed = None
self.sorting_status = {}
self.data = None
self.files = None
self.set_title('')
self.root_items = None
self.sortByColumn(0, Qt.AscendingOrder)
self.enable_sorting(False)
self.setSortingEnabled(True)
self.header().setSectionsClickable(True)
self.root_items = None
self.sortByColumn(0, Qt.AscendingOrder)
self.setItemDelegate(ItemDelegate(self))
self.setUniformRowHeights(False)

Expand All @@ -576,6 +612,10 @@ def activated(self, item):
filename, lineno, colno = itemdata
self.parent().edit_goto.emit(filename, lineno, self.search_text)

def enable_sorting(self, flag):
"""Enable result sorting after search is complete."""
self.sorting_status['status'] = flag
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this has to be a dictionary instead of a property? I mean, you could simply have

self.sorting = True/False

instead of having a method called enable_sorting that writes to a dict.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if I modify a property, will it propagate along all elements?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then let's refactor this a bit so it's easier to understand. What about

self.sorting['status'] = 'on'/'off'

?


def clicked(self, item):
"""Click event"""
self.activated(item)
Expand All @@ -585,6 +625,7 @@ def clear_title(self, search_text):
self.num_files = 0
self.data = {}
self.files = {}
self.enable_sorting(False)
self.search_text = search_text
title = "'%s' - " % search_text
text = _('String not found')
Expand All @@ -596,7 +637,8 @@ def append_result(self, results, num_matches):
filename, lineno, colno, line = results

if filename not in self.files:
item = FileMatchItem(self, filename)
item = FileMatchItem(self, filename, self.sorting_status)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disable sorting only on file entries and not line entries, to accomplish that I use the dict

item.setExpanded(True)
self.files[filename] = item
self.num_files += 1

Expand Down Expand Up @@ -755,6 +797,7 @@ def closing_widget(self):

def search_complete(self, completed):
"""Current search thread has finished"""
self.result_browser.enable_sorting(True)
self.find_options.ok_button.setEnabled(True)
self.find_options.stop_button.setEnabled(False)
self.status_bar.hide()
Expand Down