Skip to content

Commit

Permalink
Merge pull request #19 from nakagami/re_search
Browse files Browse the repository at this point in the history
reglar expression search forward #12
  • Loading branch information
nakagami authored Jul 14, 2024
2 parents 55615c4 + 581b795 commit ec76394
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: [3.8, 3.9, '3.10', '3.11', '3.12']
python-version: ['3.10', '3.11', '3.12']
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ We have already many nice things, for instance:

- All of the functionality of `prompt_toolkit
<http://github.com/prompt-toolkit/python-prompt-toolkit>`_. This includes a
lot of Vi key bindings, it's platform independent and runs on Python 3.8+ .
lot of Vi key bindings, it's platform independent and runs on Python 3.10+ .

- Several ``:set ...`` commands have been implemented, like ``incsearch``,
``number``, ``ignorecase``, ``wildmenu``, ``expandtab``, ``hlsearch``,
Expand Down
99 changes: 99 additions & 0 deletions pyvim/key_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,105 @@
document._FIND_CURRENT_WORD_RE = re.compile(r"^([a-zA-Z0-9_]+|[^a-zA-Z0-9_\t\f\v]+)")


def _document_find(
self,
sub: str,
in_current_line: bool = False,
include_current_position: bool = False,
ignore_case: bool = False,
count: int = 1,
) -> int | None:
"""
Find `text` after the cursor, return position relative to the cursor
position. Return `None` if nothing was found.
:param count: Find the n-th occurrence.
"""
assert isinstance(ignore_case, bool)

if in_current_line:
text = self.current_line_after_cursor
else:
text = self.text_after_cursor

if not include_current_position:
if len(text) == 0:
return None # (Otherwise, we always get a match for the empty string.)
else:
text = text[1:]

flags = re.MULTILINE
if ignore_case:
flags |= re.IGNORECASE
try:
iterator = re.finditer(sub, text, flags)
except re.error:
iterator = re.finditer(re.escape(sub), text, flags)

try:
for i, match in enumerate(iterator):
if i + 1 == count:
if include_current_position:
return match.start(0)
else:
return match.start(0) + 1
except StopIteration:
pass
return None


def _document_find_all(self, sub: str, ignore_case: bool = False) -> list[int]:
"""
Find all occurrences of the substring. Return a list of absolute
positions in the document.
"""
flags = re.MULTILINE
if ignore_case:
flags |= re.IGNORECASE
try:
return [a.start() for a in re.finditer(sub, self.text, flags)]
except re.error:
return [a.start() for a in re.finditer(re.escape(sub), self.text, flags)]


def _document_find_backwards(
self,
sub: str,
in_current_line: bool = False,
ignore_case: bool = False,
count: int = 1,
) -> int | None:
"""
Find `text` before the cursor, return position relative to the cursor
position. Return `None` if nothing was found.
:param count: Find the n-th occurrence.
"""
if in_current_line:
before_cursor = self.current_line_before_cursor[::-1]
else:
before_cursor = self.text_before_cursor[::-1]

flags = re.MULTILINE
if ignore_case:
flags |= re.IGNORECASE
# TODO: search backword with regular expression like _document_find() and _document_find_all()
iterator = re.finditer(re.escape(sub[::-1]), before_cursor, flags)

try:
for i, match in enumerate(iterator):
if i + 1 == count:
return -match.start(0) - len(sub)
except StopIteration:
pass
return None


document.Document.find = _document_find
document.Document.find_all = _document_find_all
document.Document.find_backwards = _document_find_backwards


def create_key_bindings(editor):
"""
Create custom key bindings.
Expand Down

0 comments on commit ec76394

Please sign in to comment.