diff --git a/pyvim/commands/commands.py b/pyvim/commands/commands.py index c2c9e93..ae4d781 100644 --- a/pyvim/commands/commands.py +++ b/pyvim/commands/commands.py @@ -1,4 +1,7 @@ from prompt_toolkit.application import run_in_terminal +from prompt_toolkit.application.current import get_app +from prompt_toolkit.clipboard import ClipboardData +from prompt_toolkit.selection import SelectionType from prompt_toolkit.document import Document import os @@ -740,7 +743,7 @@ def set_all(editor): editor.show_set_all() -def _get_line_index_iterator(editor, cursor_position_row, range_start, range_end): +def _get_line_index(editor, cursor_position_row, range_start, range_end): if not range_start: assert not range_end range_start = range_end = cursor_position_row @@ -758,7 +761,7 @@ def _get_line_index_iterator(editor, cursor_position_row, range_start, range_end range_end = int(range_end) - 1 else: range_end = range_start - return range(range_start, range_end + 1) + return range_start, range_end + 1 def substitute(editor, range_start, range_end, search, replace, flags): @@ -779,7 +782,8 @@ def get_transform_callback(search, replace, flags): if replace is None: replace = editor.last_substitute_text - line_index_iterator = _get_line_index_iterator(editor, cursor_position_row, range_start, range_end) + start, end = _get_line_index(editor, cursor_position_row, range_start, range_end) + line_index_iterator = range(start, end) transform_callback = get_transform_callback(search, replace, flags) new_text = buffer.transform_lines(line_index_iterator, transform_callback) @@ -797,3 +801,34 @@ def get_transform_callback(search, replace, flags): # update editor state editor.last_substitute_text = replace search_state.text = search + + +def yank(editor, range_start, range_end): + buffer = editor.current_editor_buffer.buffer + cursor_position_row = buffer.document.cursor_position_row + start, end = _get_line_index(editor, cursor_position_row, range_start, range_end) + lines = buffer.document.lines + + yanked = "\n".join(lines[start: end]) + get_app().clipboard.set_data(ClipboardData(yanked, SelectionType.LINES)) + + +def delete(editor, range_start, range_end): + buffer = editor.current_editor_buffer.buffer + cursor_position_row = buffer.document.cursor_position_row + start, end = _get_line_index(editor, cursor_position_row, range_start, range_end) + + lines = buffer.document.lines + + before = "\n".join(lines[: start]) + deleted = "\n".join(lines[start: end]) + after = "\n".join(lines[end:]) + get_app().clipboard.set_data(ClipboardData(deleted, SelectionType.LINES)) + + new_text = before + after + # update text buffer + buffer.document = Document( + new_text, + Document(new_text).translate_row_col_to_index(start, 0), + ) + buffer.cursor_position += start diff --git a/pyvim/commands/grammar.py b/pyvim/commands/grammar.py index 14fe754..94bfffd 100644 --- a/pyvim/commands/grammar.py +++ b/pyvim/commands/grammar.py @@ -12,6 +12,12 @@ # Substitute command ((?P\d+|\.|\'[a-z])(,(?P\d+|\.|\'[a-z]|\$))?)? (?Ps|substitute) \s* / (?P[^/]*) ( / (?P[^/]*) (?P /(g)? )? )? | + # Yank command + ((?P\d+|\.|\'[a-z])(,(?P\d+|\.|\'[a-z]|\$))?)? (?Pya|yank[^\s]+) | + + # Delete command + ((?P\d+|\.|\'[a-z])(,(?P\d+|\.|\'[a-z]|\$))?)? (?Pd|delete[^\s]+) | + # Commands accepting a location. (?P%(commands_taking_locations)s)(?P!?) \s+ (?P[^\s]+) | diff --git a/pyvim/commands/handler.py b/pyvim/commands/handler.py index b7d1443..8041850 100644 --- a/pyvim/commands/handler.py +++ b/pyvim/commands/handler.py @@ -1,6 +1,6 @@ import asyncio from .grammar import COMMAND_GRAMMAR -from .commands import call_command_handler, has_command_handler, substitute +from .commands import call_command_handler, has_command_handler, substitute, yank, delete __all__ = ( 'handle_command', @@ -44,7 +44,10 @@ def handle_command(editor, input_string): elif command in ('s', 'substitute'): flags = flags.lstrip('/') substitute(editor, range_start, range_end, search, replace, flags) - + elif command in ('ya', 'yank'): + yank(editor, range_start, range_end) + elif command in ('d', 'delete'): + delete(editor, range_start, range_end) else: # For unknown commands, show error message. editor.show_message('Not an editor command: %s' % input_string)