Add :expandtabs and :noexpandtabs

This commit is contained in:
Andrew Lane
2020-08-28 18:20:49 -04:00
parent 9c5f28d475
commit 5df223f81e
5 changed files with 92 additions and 7 deletions

View File

@@ -59,6 +59,7 @@ class DelModification(NamedTuple):
class Buf:
def __init__(self, lines: List[str], tab_size: int = 4) -> None:
self._lines = lines
self.expandtabs = True
self.tab_size = tab_size
self.file_y = self.y = self._x = self._x_hint = 0
@@ -242,6 +243,13 @@ class Buf:
# rendered lines
@property
def tab_string(self) -> str:
if self.expandtabs:
return ' ' * self.tab_size
else:
return '\t'
def rendered_line(self, idx: int, margin: Margin) -> str:
x = self._cursor_x if idx == self.y else 0
expanded = self._lines[idx].expandtabs(self.tab_size)

View File

@@ -524,20 +524,29 @@ class File:
assert self.selection.start is not None
sel_y, sel_x = self.selection.start
(s_y, _), (e_y, _) = self.selection.get()
tab_string = self.buf.tab_string
tab_size = len(tab_string)
for l_y in range(s_y, e_y + 1):
if self.buf[l_y]:
self.buf[l_y] = ' ' * self.buf.tab_size + self.buf[l_y]
self.buf[l_y] = tab_string + self.buf[l_y]
if l_y == self.buf.y:
self.buf.x += self.buf.tab_size
self.buf.x += tab_size
if l_y == sel_y and sel_x != 0:
sel_x += self.buf.tab_size
sel_x += tab_size
self.selection.set(sel_y, sel_x, self.buf.y, self.buf.x)
@edit_action('insert tab', final=False)
def _tab(self, margin: Margin) -> None:
n = self.buf.tab_size - self.buf.x % self.buf.tab_size
tab_string = self.buf.tab_string
if tab_string == '\t':
n = 1
else:
n = self.buf.tab_size - self.buf.x % self.buf.tab_size
tab_string = tab_string[:n]
line = self.buf[self.buf.y]
self.buf[self.buf.y] = line[:self.buf.x] + n * ' ' + line[self.buf.x:]
self.buf[self.buf.y] = (
line[:self.buf.x] + tab_string + line[self.buf.x:]
)
self.buf.x += n
self.buf.restore_eof_invariant()
@@ -548,9 +557,9 @@ class File:
self._tab(margin)
def _dedent_line(self, s: str) -> int:
bound = min(len(s), self.buf.tab_size)
bound = min(len(s), len(self.buf.tab_string))
i = 0
while i < bound and s[i] == ' ':
while i < bound and s[i] in (' ', '\t'):
i += 1
return i

View File

@@ -457,6 +457,14 @@ class Screen:
for file in self.files:
file.buf.set_tab_size(parsed_tab_size)
self.status.update('updated!')
elif response.startswith(':expandtabs'):
for file in self.files:
file.buf.expandtabs = True
self.status.update('updated!')
elif response.startswith(':noexpandtabs'):
for file in self.files:
file.buf.expandtabs = False
self.status.update('updated!')
elif response == ':comment' or response.startswith(':comment '):
_, _, comment = response.partition(' ')
comment = (comment or '#').strip()

View File

@@ -0,0 +1,45 @@
from testing.runner import and_exit
from testing.runner import trigger_command_mode
def test_set_expandtabs(run, tmpdir):
f = tmpdir.join('f')
f.write('a')
with run(str(f)) as h, and_exit(h):
h.press('Left')
trigger_command_mode(h)
h.press_and_enter(':expandtabs')
h.await_text('updated!')
h.press('Tab')
h.press('^S')
assert f.read() == ' a\n'
def test_set_noexpandtabs(run, tmpdir):
f = tmpdir.join('f')
f.write('a')
with run(str(f)) as h, and_exit(h):
h.press('Left')
trigger_command_mode(h)
h.press_and_enter(':noexpandtabs')
h.await_text('updated!')
h.press('Tab')
h.press('^S')
assert f.read() == '\ta\n'
def test_indent_with_expandtabs(run, tmpdir):
f = tmpdir.join('f')
f.write('a\nb\nc')
with run(str(f)) as h, and_exit(h):
trigger_command_mode(h)
h.press_and_enter(':noexpandtabs')
h.await_text('updated!')
for _ in range(3):
h.press('S-Down')
h.press('Tab')
h.press('^S')
assert f.read() == '\ta\n\tb\n\tc\n'

View File

@@ -1,4 +1,5 @@
from testing.runner import and_exit
from testing.runner import trigger_command_mode
def test_indent_at_beginning_of_line(run):
@@ -87,6 +88,20 @@ def test_dedent_selection(run, tmpdir):
h.await_text('\n1\n2\n 3\n')
def test_dedent_selection_with_noexpandtabs(run, tmpdir):
f = tmpdir.join('f')
f.write('1\n\t2\n\t\t3\n')
with run(str(f)) as h, and_exit(h):
trigger_command_mode(h)
h.press_and_enter(':noexpandtabs')
h.await_text('updated!')
for _ in range(3):
h.press('S-Down')
h.press('BTab')
h.press('^S')
assert f.read() == '1\n2\n\t3\n'
def test_dedent_beginning_of_line(run, tmpdir):
f = tmpdir.join('f')
f.write(' hi\n')