Skip to content

Commit

Permalink
Merge pull request #4820 from andfoy/find_in_files_case_sens
Browse files Browse the repository at this point in the history
PR: Add a button to Find in Files to make searches case sensitive
  • Loading branch information
ccordoba12 authored Aug 13, 2017
2 parents 6b464b3 + 0df03eb commit 5b3985f
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 17 deletions.
1 change: 1 addition & 0 deletions spyder/config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@
'search_text_samples': [codeanalysis.TASKS_PATTERN],
'in_python_path': False,
'more_options': False,
'case_sensitive': True
}),
('workingdir',
{
Expand Down
17 changes: 10 additions & 7 deletions spyder/plugins/findinfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ def __init__(self, parent=None):
exclude_regexp = self.get_option('exclude_regexp')
in_python_path = self.get_option('in_python_path')
more_options = self.get_option('more_options')
case_sensitive = self.get_option('case_sensitive')
FindInFilesWidget.__init__(self, parent,
search_text, search_text_regexp, search_path,
exclude, exclude_idx, exclude_regexp,
supported_encodings,
in_python_path, more_options)
search_text, search_text_regexp,
search_path, exclude, exclude_idx,
exclude_regexp, supported_encodings,
in_python_path, more_options,
case_sensitive)
SpyderPluginMixin.__init__(self, parent)

# Initialize plugin
Expand Down Expand Up @@ -156,9 +158,9 @@ def closing_plugin(self, cancelable=False):
self.closing_widget() # stop search thread and clean-up
options = self.find_options.get_options(all=True)
if options is not None:
search_text, text_re, search_path, \
exclude, exclude_idx, exclude_re, \
in_python_path, more_options = options
(search_text, text_re, search_path,
exclude, exclude_idx, exclude_re,
in_python_path, more_options, case_sensitive) = options
hist_limit = 15
search_text = search_text[:hist_limit]
search_path = search_path[:hist_limit]
Expand All @@ -171,6 +173,7 @@ def closing_plugin(self, cancelable=False):
self.set_option('exclude_regexp', exclude_re)
self.set_option('in_python_path', in_python_path)
self.set_option('more_options', more_options)
self.set_option('case_sensitive', case_sensitive)
return True


Expand Down
39 changes: 29 additions & 10 deletions spyder/widgets/findinfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
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
from spyder.utils.encoding import is_text_file
from spyder.widgets.comboboxes import PatternComboBox
from spyder.widgets.onecolumntree import OneColumnTree
from spyder.utils.qthelpers import create_toolbutton, get_icon

from spyder.config.gui import get_font
from spyder.widgets.waitingspinner import QWaitingSpinner
Expand Down Expand Up @@ -70,12 +70,14 @@ def __init__(self, parent):
self.texts = None
self.text_re = None
self.completed = None
self.case_sensitive = True
self.get_pythonpath_callback = None
self.results = {}
self.total_matches = 0
self.is_file = False

def initialize(self, path, is_file, exclude, texts, text_re):
def initialize(self, path, is_file, exclude,
texts, text_re, case_sensitive):
self.rootpath = path
self.python_path = False
self.hg_manifest = False
Expand All @@ -85,6 +87,7 @@ def initialize(self, path, is_file, exclude, texts, text_re):
self.is_file = is_file
self.stopped = False
self.completed = False
self.case_sensitive = case_sensitive

def run(self):
try:
Expand Down Expand Up @@ -136,18 +139,23 @@ def find_string_in_file(self, fname):
try:
for lineno, line in enumerate(open(fname, 'rb')):
for text, enc in self.texts:
line_search = line
if not self.case_sensitive:
line_search = line_search.lower()
if self.text_re:
found = re.search(text, line)
found = re.search(text, line_search)
if found is not None:
break
else:
found = line.find(text)
found = line_search.find(text)
if found > -1:
break
try:
line_dec = line.decode(enc)
except UnicodeDecodeError:
line_dec = line
if not self.case_sensitive:
line = line.lower()
if self.text_re:
for match in re.finditer(text, line):
self.total_matches += 1
Expand Down Expand Up @@ -186,7 +194,8 @@ class FindOptions(QWidget):

def __init__(self, parent, search_text, search_text_regexp, search_path,
exclude, exclude_idx, exclude_regexp,
supported_encodings, in_python_path, more_options):
supported_encodings, in_python_path, more_options,
case_sensitive):
QWidget.__init__(self, parent)

if search_path is None:
Expand All @@ -212,6 +221,11 @@ def __init__(self, parent, search_text, search_text_regexp, search_path,
self.edit_regexp = create_toolbutton(self,
icon=ima.icon('advanced'),
tip=_('Regular expression'))
self.case_button = create_toolbutton(self,
icon=get_icon("upper_lower.png"),
tip=_("Case Sensitive"))
self.case_button.setCheckable(True)
self.case_button.setChecked(case_sensitive)
self.edit_regexp.setCheckable(True)
self.edit_regexp.setChecked(search_text_regexp)
self.more_widgets = ()
Expand All @@ -233,7 +247,7 @@ def __init__(self, parent, search_text, search_text_regexp, search_path,
tip=_("Stop search"),
text_beside_icon=True)
self.stop_button.setEnabled(False)
for widget in [self.search_text, self.edit_regexp,
for widget in [self.search_text, self.edit_regexp, self.case_button,
self.ok_button, self.stop_button, self.more_options]:
hlayout1.addWidget(widget)

Expand Down Expand Up @@ -340,8 +354,12 @@ def get_options(self, all=False):
text_re = self.edit_regexp.isChecked()
exclude = to_text_string(self.exclude_pattern.currentText())
exclude_re = self.exclude_regexp.isChecked()
case_sensitive = self.case_button.isChecked()
python_path = False

if not case_sensitive:
texts = [(text[0].lower(), text[1]) for text in texts]

global_path_search = self.global_path_search.isChecked()
project_search = self.project_search.isChecked()
file_search = self.file_search.isChecked()
Expand Down Expand Up @@ -380,9 +398,9 @@ def get_options(self, all=False):
more_options = self.more_options.isChecked()
return (search_text, text_re, [],
exclude, exclude_idx, exclude_re,
python_path, more_options)
python_path, more_options, case_sensitive)
else:
return (path, file_search, exclude, texts, text_re)
return (path, file_search, exclude, texts, text_re, case_sensitive)

@Slot()
def select_directory(self):
Expand Down Expand Up @@ -716,7 +734,8 @@ def __init__(self, parent,
exclude=r"\.pyc$|\.orig$|\.hg|\.svn", exclude_idx=None,
exclude_regexp=True,
supported_encodings=("utf-8", "iso-8859-1", "cp1252"),
in_python_path=False, more_options=False):
in_python_path=False, more_options=False,
case_sensitive=True):
QWidget.__init__(self, parent)

self.setWindowTitle(_('Find in files'))
Expand All @@ -731,7 +750,7 @@ def __init__(self, parent,
search_path,
exclude, exclude_idx, exclude_regexp,
supported_encodings, in_python_path,
more_options)
more_options, case_sensitive)
self.find_options.find.connect(self.find)
self.find_options.stop.connect(self.stop_and_reset_thread)

Expand Down
10 changes: 10 additions & 0 deletions spyder/widgets/tests/data/ham.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
ham(N) -> ham(N, 1, 1).

ham(0, F1, _) -> F1;
ham(N, F1, F2) when N > 0 ->
ham(N - 1, F2, F2 + F1).

Eggs = 10.
Sausage = atom.
HaM = false.
Ham = Eggs + Sausage.
31 changes: 31 additions & 0 deletions spyder/widgets/tests/test_findinfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ def expected_results():
return results


def expected_case_unsensitive_results():
results = {'spam.txt': [(1, 10)],
'ham.txt': [(1, 0), (1, 10), (3, 0), (4, 0),
(5, 4), (9, 0), (10, 0)]}
return results


def test_findinfiles(qtbot):
"""Run find in files widget."""
find_in_files = setup_findinfiles(qtbot)
Expand Down Expand Up @@ -99,5 +106,29 @@ def test_exclude_extension(qtbot):
assert files_filtered


def test_case_unsensitive_search(qtbot):
find_in_files = setup_findinfiles(qtbot, case_sensitive=False)
find_in_files.set_search_text('ham')
find_in_files.find_options.set_directory(osp.join(LOCATION, "data"))
find_in_files.find()
blocker = qtbot.waitSignal(find_in_files.sig_finished)
blocker.wait()
matches = process_search_results(find_in_files.result_browser.data)
print(matches)
assert expected_case_unsensitive_results() == matches


def test_case_sensitive_search(qtbot):
find_in_files = setup_findinfiles(qtbot)
find_in_files.set_search_text('HaM')
find_in_files.find_options.set_directory(osp.join(LOCATION, "data"))
find_in_files.find()
blocker = qtbot.waitSignal(find_in_files.sig_finished)
blocker.wait()
matches = process_search_results(find_in_files.result_browser.data)
print(matches)
assert matches == {'ham.txt': [(9, 0)]}


if __name__ == "__main__":
pytest.main()

0 comments on commit 5b3985f

Please sign in to comment.