editor: Add indent and dedent commands
This commit is contained in:
parent
af621a6be0
commit
c0bdb52391
3 changed files with 89 additions and 5 deletions
2
TODO
2
TODO
|
|
@ -2,7 +2,6 @@ Todo:
|
|||
- Keyboard shortcuts for resolving differences.
|
||||
- How to handle tabs?
|
||||
- Colourise file name.
|
||||
- Bulk indent/dedent.
|
||||
- Search.
|
||||
- Search and replace.
|
||||
- Large pastes.
|
||||
|
|
@ -31,6 +30,7 @@ Done:
|
|||
- tab key should align code.
|
||||
- Right align the left editor.
|
||||
- Overwrite mode.
|
||||
- Bulk indent/dedent.
|
||||
|
||||
|
||||
Shelved:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import pygments.lexers
|
|||
import pygments.styles
|
||||
import termstr
|
||||
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=100)
|
||||
def highlight_str(line, bg_color, transparency=0.6):
|
||||
def blend_style(style):
|
||||
|
|
@ -181,6 +181,7 @@ def add_highlights(self, appearance):
|
|||
|
||||
class Editor:
|
||||
|
||||
TAB_SIZE = 4
|
||||
THEMES = [pygments.styles.get_style_by_name(style)
|
||||
for style in ["monokai", "fruity", "native"]] + [None]
|
||||
|
||||
|
|
@ -538,6 +539,50 @@ class Editor:
|
|||
def toggle_overwrite(self):
|
||||
self.is_overwriting = not self.is_overwriting
|
||||
|
||||
def _work_lines(self):
|
||||
if self.mark is None:
|
||||
return [self.cursor_y]
|
||||
else:
|
||||
(start_x, start_y), (end_x, end_y) = self.get_selection_interval()
|
||||
return range(start_y + (start_x > 0), end_y + 1 - (end_x == 0))
|
||||
|
||||
def indent(self):
|
||||
indent_ = " " * Editor.TAB_SIZE
|
||||
for line_num in self._work_lines():
|
||||
if self.text_widget[line_num].strip() == "":
|
||||
self.text_widget[line_num] = ""
|
||||
continue
|
||||
self.text_widget[line_num] = indent_ + self.text_widget[line_num]
|
||||
if self.cursor_y == line_num:
|
||||
self.cursor_x += Editor.TAB_SIZE
|
||||
|
||||
def dedent(self):
|
||||
indent_ = " " * Editor.TAB_SIZE
|
||||
line_nums = self._work_lines()
|
||||
if not all(self.text_widget[line_num].startswith(indent_)
|
||||
or self.text_widget[line_num].strip() == "" for line_num in line_nums):
|
||||
self.ring_bell()
|
||||
return
|
||||
for line_num in line_nums:
|
||||
if self.cursor_y == line_num:
|
||||
self.cursor_x = max(self.cursor_x - Editor.TAB_SIZE, 0)
|
||||
if self.text_widget[line_num].strip() == "":
|
||||
self.text_widget[line_num] = ""
|
||||
continue
|
||||
self.text_widget[line_num] = self.text_widget[line_num][Editor.TAB_SIZE:]
|
||||
|
||||
def greater_than_key(self):
|
||||
if self.previous_term_code == terminal.CTRL_C:
|
||||
self.indent()
|
||||
else:
|
||||
self.insert_text(">", is_overwriting=self.is_overwriting)
|
||||
|
||||
def less_than_key(self):
|
||||
if self.previous_term_code == terminal.CTRL_C:
|
||||
self.dedent()
|
||||
else:
|
||||
self.insert_text("<", is_overwriting=self.is_overwriting)
|
||||
|
||||
def abort_command(self):
|
||||
self.mark = None
|
||||
self.ring_bell()
|
||||
|
|
@ -621,7 +666,6 @@ class Editor:
|
|||
|
||||
def appearance_for(self, dimensions):
|
||||
width, height = dimensions
|
||||
text_width = self.text_widget.max_line_length
|
||||
is_changed = self.text_widget.actual_text != self.original_text
|
||||
header = self.get_header(self.path, width, self.cursor_x, self.cursor_y, is_changed)
|
||||
self.last_width = width
|
||||
|
|
@ -650,7 +694,7 @@ class Editor:
|
|||
terminal.ALT_c: cycle_syntax_highlighting, terminal.CTRL_X: prefix, terminal.ESC: quit,
|
||||
terminal.CTRL_C: ctrl_c, terminal.CTRL_K: delete_line, terminal.TAB: tab_align,
|
||||
terminal.CTRL_UNDERSCORE: undo, terminal.CTRL_Z: undo, terminal.CTRL_G: abort_command,
|
||||
terminal.INSERT: toggle_overwrite}
|
||||
terminal.INSERT: toggle_overwrite, ">": greater_than_key, "<": less_than_key}
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
import contextlib
|
||||
import unittest
|
||||
|
||||
import diff_edit.editor as editor
|
||||
|
|
@ -90,6 +89,47 @@ class EditorTestCase(unittest.TestCase):
|
|||
self.editor.insert_text("ef", is_overwriting=True)
|
||||
self._assert_editor("aef", (3, 0))
|
||||
|
||||
def test_indent(self):
|
||||
# no selection
|
||||
self._set_editor("ab", (1, 0))
|
||||
self._assert_change(self.editor.indent, " ab", (5, 0))
|
||||
self._set_editor(" ", (1, 0))
|
||||
self._assert_change(self.editor.indent, "", (0, 0))
|
||||
# on selection
|
||||
self._set_editor("a\nb\nc", (0, 0))
|
||||
self.editor.set_mark()
|
||||
self.editor.cursor_down()
|
||||
self._assert_change(self.editor.indent, " a\nb\nc", (0, 1))
|
||||
self.assertIsNotNone(self.editor.mark)
|
||||
self._set_editor("a\nb\nc", (1, 0))
|
||||
self.editor.set_mark()
|
||||
self.editor.cursor_left()
|
||||
self.editor.cursor_down()
|
||||
self.editor.cursor_down()
|
||||
self._assert_change(self.editor.indent, "a\n b\nc", (0, 2))
|
||||
self._set_editor("a\nb\nc", (0, 1))
|
||||
self.editor.set_mark()
|
||||
self.editor.cursor_down()
|
||||
self.editor.cursor_right()
|
||||
self._assert_change(self.editor.indent, "a\n b\n c", (5, 2))
|
||||
|
||||
def test_dedent(self):
|
||||
# no selection
|
||||
self._set_editor(" ab", (2, 0))
|
||||
self._assert_change(self.editor.dedent, "ab", (0, 0))
|
||||
self._set_editor(" ab", (5, 0))
|
||||
self._assert_change(self.editor.dedent, "ab", (1, 0))
|
||||
self._set_editor(" ab", (0, 0))
|
||||
self._assert_change(self.editor.dedent, " ab", (0, 0))
|
||||
self._set_editor(" ", (1, 0))
|
||||
self._assert_change(self.editor.dedent, "", (0, 0))
|
||||
# on selection
|
||||
self._set_editor(" a\n \n b", (0, 0))
|
||||
self.editor.set_mark()
|
||||
self.editor.cursor_down()
|
||||
self.editor.cursor_down()
|
||||
self._assert_change(self.editor.dedent, "a\n\n b", (0, 2))
|
||||
|
||||
def test_enter(self):
|
||||
self._set_editor("ab", (1, 0))
|
||||
self.editor.enter()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue