Skip to content

Commit

Permalink
Merge pull request #6526 from csabella/issue5680
Browse files Browse the repository at this point in the history
PR: Find/replace - return match counts on unescaped characters
  • Loading branch information
ccordoba12 authored Feb 27, 2018
2 parents b32aaf0 + 6ba5356 commit d096560
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 7 deletions.
5 changes: 4 additions & 1 deletion spyder/widgets/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,14 @@ def set_source_text(self, source_text):
"""Set source text of the page. Callback for QWebEngineView."""
self.source_text = source_text

def get_number_matches(self, pattern, source_text='', case=False):
def get_number_matches(self, pattern, source_text='', case=False,
regexp=False):
"""Get the number of matches for the searched text."""
pattern = to_text_string(pattern)
if not pattern:
return 0
if not regexp:
pattern = re.escape(pattern)
if not source_text:
if WEBENGINE:
self.page().toPlainText(self.set_source_text)
Expand Down
6 changes: 4 additions & 2 deletions spyder/widgets/findreplace.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,11 @@ def regexp_error_msg(pattern):
else:
self.clear_matches()

number_matches = self.editor.get_number_matches(text, case=case)
number_matches = self.editor.get_number_matches(text, case=case,
regexp=regexp)
if hasattr(self.editor, 'get_match_number'):
match_number = self.editor.get_match_number(text, case=case)
match_number = self.editor.get_match_number(text, case=case,
regexp=regexp)
else:
match_number = 0
self.change_number_matches(current_match=match_number,
Expand Down
11 changes: 7 additions & 4 deletions spyder/widgets/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,11 +523,14 @@ def is_editor(self):
"""Needs to be overloaded in the codeeditor where it will be True"""
return False

def get_number_matches(self, pattern, source_text='', case=False):
def get_number_matches(self, pattern, source_text='', case=False,
regexp=False):
"""Get the number of matches for the searched text."""
pattern = to_text_string(pattern)
if not pattern:
return 0
if not regexp:
pattern = re.escape(pattern)
if not source_text:
source_text = to_text_string(self.toPlainText())
try:
Expand All @@ -536,21 +539,21 @@ def get_number_matches(self, pattern, source_text='', case=False):
else:
regobj = re.compile(pattern, re.IGNORECASE)
except sre_constants.error:
return
return None

number_matches = 0
for match in regobj.finditer(source_text):
number_matches += 1

return number_matches

def get_match_number(self, pattern, case=False):
def get_match_number(self, pattern, case=False, regexp=False):
"""Get number of the match for the searched text."""
position = self.textCursor().position()
source_text = self.get_text(position_from='sof', position_to=position)
match_number = self.get_number_matches(pattern,
source_text=source_text,
case=case)
case=case, regexp=regexp)
return match_number

# --- Numpy matrix/array helper / See 'spyder/widgets/arraybuilder.py'
Expand Down
101 changes: 101 additions & 0 deletions spyder/widgets/tests/test_mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
#

# Third party imports
from qtpy.QtWidgets import QPlainTextEdit

import pytest

# Local imports
from spyder.widgets import mixins


class BaseWidget(QPlainTextEdit, mixins.BaseEditMixin):
pass

# --- Fixtures
# -----------------------------------------------------------------------------


@pytest.fixture
def mixinsbot(qtbot):
widget = BaseWidget()
qtbot.addWidget(widget)
widget.show()
return qtbot, widget

# --- Tests
# -----------------------------------------------------------------------------


def test_get_number_matches(mixinsbot):
# Test get_number_matches().
qtbot, widget = mixinsbot
get = widget.get_number_matches

code = ('class C():\n'
' def __init__(self):\n'
' pass\n'
' def f(self, a, b):\n'
' pass\n')

# Empty pattern.
assert get('') == 0

# No case, no regexp.
assert get('self', source_text=code) == 2
assert get('c', source_text=code) == 2

# Case, no regexp.
assert get('self', source_text=code, case=True) == 2
assert get('c', source_text=code, case=True) == 1

# No case, regexp.
assert get('e[a-z]?f', source_text=code, regexp=True) == 4
assert get('e[A-Z]?f', source_text=code, regexp=True) == 4

# Case, regexp.
assert get('e[a-z]?f', source_text=code, case=True, regexp=True) == 4
assert get('e[A-Z]?f', source_text=code, case=True, regexp=True) == 2

# Issue 5680.
assert get('(', source_text=code) == 3
assert get('(', source_text=code, case=True) == 3
assert get('(', source_text=code, regexp=True) is None
assert get('(', source_text=code, case=True, regexp=True) is None


def test_get_match_number(mixinsbot):
# Test get_match_number().
qtbot, widget = mixinsbot
get = widget.get_match_number

code = ('class C():\n'
' def __init__(self):\n'
' pass\n'
' def f(self, a, b):\n'
' pass\n')
widget.setPlainText(code)
cursor = widget.textCursor()
cursor.setPosition(widget.get_position('sof'))

# Empty pattern.
assert get('') == 0

# Issue 5680.
widget.find_text('(')
assert get('(') == 1

# First occurrence.
widget.find_text('self')
assert get('self') == 1
assert get('self', case=True) == 1

# Second occurrence.
widget.find_text('pass')
widget.find_text('self')
assert get('self') == 2
assert get('self', case=True) == 2

0 comments on commit d096560

Please sign in to comment.