462 lines
13 KiB
Python
462 lines
13 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import List
|
|
|
|
import pytest
|
|
from textual.app import App
|
|
from textual.widgets.text_area import Selection
|
|
from textual_textarea import TextEditor
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"keys,text,selection,expected_text,expected_selection",
|
|
[
|
|
(
|
|
["ctrl+a"],
|
|
"select\n foo",
|
|
Selection(start=(1, 2), end=(1, 2)),
|
|
"select\n foo",
|
|
Selection(start=(0, 0), end=(1, 4)),
|
|
),
|
|
(
|
|
["ctrl+shift+right"],
|
|
"select\n foo",
|
|
Selection(start=(0, 0), end=(0, 0)),
|
|
"select\n foo",
|
|
Selection(start=(0, 0), end=(0, 6)),
|
|
),
|
|
(
|
|
["right"],
|
|
"select\n foo",
|
|
Selection(start=(0, 0), end=(0, 6)),
|
|
"select\n foo",
|
|
Selection(start=(1, 0), end=(1, 0)),
|
|
),
|
|
(
|
|
["a"],
|
|
"select\n foo",
|
|
Selection(start=(1, 4), end=(1, 4)),
|
|
"select\n fooa",
|
|
Selection(start=(1, 5), end=(1, 5)),
|
|
),
|
|
(
|
|
["a"],
|
|
"select\n foo",
|
|
Selection(start=(1, 0), end=(1, 4)),
|
|
"select\na",
|
|
Selection(start=(1, 1), end=(1, 1)),
|
|
),
|
|
(
|
|
["enter"],
|
|
"a\na",
|
|
Selection(start=(1, 0), end=(1, 0)),
|
|
"a\n\na",
|
|
Selection(start=(2, 0), end=(2, 0)),
|
|
),
|
|
(
|
|
["enter"],
|
|
"a\na",
|
|
Selection(start=(1, 1), end=(1, 1)),
|
|
"a\na\n",
|
|
Selection(start=(2, 0), end=(2, 0)),
|
|
),
|
|
(
|
|
["enter", "b"],
|
|
"a()",
|
|
Selection(start=(0, 2), end=(0, 2)),
|
|
"a(\n b\n)",
|
|
Selection(start=(1, 5), end=(1, 5)),
|
|
),
|
|
(
|
|
["enter", "b"],
|
|
" a()",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
" a(\n b\n )",
|
|
Selection(start=(1, 5), end=(1, 5)),
|
|
),
|
|
(
|
|
["delete"],
|
|
"0\n1\n2\n3",
|
|
Selection(start=(2, 1), end=(2, 1)),
|
|
"0\n1\n23",
|
|
Selection(start=(2, 1), end=(2, 1)),
|
|
),
|
|
(
|
|
["shift+delete"],
|
|
"0\n1\n2\n3",
|
|
Selection(start=(2, 1), end=(2, 1)),
|
|
"0\n1\n3",
|
|
Selection(start=(2, 0), end=(2, 0)),
|
|
),
|
|
(
|
|
["shift+delete"],
|
|
"0\n1\n2\n3",
|
|
Selection(start=(2, 0), end=(2, 1)),
|
|
"0\n1\n\n3",
|
|
Selection(start=(2, 0), end=(2, 0)),
|
|
),
|
|
(
|
|
["shift+delete"],
|
|
"0\n1\n2\n3",
|
|
Selection(start=(3, 1), end=(3, 1)),
|
|
"0\n1\n2",
|
|
Selection(start=(2, 1), end=(2, 1)),
|
|
),
|
|
(
|
|
["shift+delete"],
|
|
"foo",
|
|
Selection(start=(3, 1), end=(3, 1)),
|
|
"",
|
|
Selection(start=(0, 0), end=(0, 0)),
|
|
),
|
|
(
|
|
["ctrl+home"],
|
|
"foo\nbar",
|
|
Selection(start=(1, 2), end=(1, 2)),
|
|
"foo\nbar",
|
|
Selection(start=(0, 0), end=(0, 0)),
|
|
),
|
|
(
|
|
["ctrl+end"],
|
|
"foo\nbar",
|
|
Selection(start=(0, 1), end=(0, 1)),
|
|
"foo\nbar",
|
|
Selection(start=(1, 3), end=(1, 3)),
|
|
),
|
|
(
|
|
["("],
|
|
"foo",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"foo()",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["("],
|
|
"foo",
|
|
Selection(start=(0, 2), end=(0, 2)),
|
|
"fo(o",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
),
|
|
(
|
|
["("],
|
|
"foo.",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"foo().",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["("],
|
|
"foo-",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"foo(-",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["'"],
|
|
"foo",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"foo'",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["'"],
|
|
"ba r",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"ba '' r",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["'"],
|
|
"foo-",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"foo'-",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["'"],
|
|
"fo--",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"fo-'-",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["'"],
|
|
"fo-.",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"fo-''.",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["'"],
|
|
"fo()",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
"fo('')",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["tab"],
|
|
"bar",
|
|
Selection(start=(0, 1), end=(0, 1)),
|
|
"b ar",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["tab"],
|
|
"bar",
|
|
Selection(start=(0, 0), end=(0, 0)),
|
|
" bar",
|
|
Selection(start=(0, 4), end=(0, 4)),
|
|
),
|
|
(
|
|
["shift+tab"],
|
|
"bar",
|
|
Selection(start=(0, 0), end=(0, 0)),
|
|
"bar",
|
|
Selection(start=(0, 0), end=(0, 0)),
|
|
),
|
|
(
|
|
["shift+tab"],
|
|
" bar",
|
|
Selection(start=(0, 7), end=(0, 7)),
|
|
"bar",
|
|
Selection(start=(0, 3), end=(0, 3)),
|
|
),
|
|
(
|
|
["tab"],
|
|
"bar\n baz",
|
|
Selection(start=(0, 2), end=(1, 1)),
|
|
" bar\n baz",
|
|
Selection(start=(0, 6), end=(1, 4)),
|
|
),
|
|
(
|
|
["tab"],
|
|
"bar\n baz",
|
|
Selection(start=(0, 0), end=(1, 1)),
|
|
" bar\n baz",
|
|
Selection(start=(0, 0), end=(1, 4)),
|
|
),
|
|
(
|
|
["shift+tab"],
|
|
" bar\n baz",
|
|
Selection(start=(0, 0), end=(1, 1)),
|
|
"bar\nbaz",
|
|
Selection(start=(0, 0), end=(1, 0)),
|
|
),
|
|
],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_keys(
|
|
app: App,
|
|
keys: List[str],
|
|
text: str,
|
|
selection: Selection,
|
|
expected_text: str,
|
|
expected_selection: Selection,
|
|
) -> None:
|
|
async with app.run_test() as pilot:
|
|
ta = app.query_one("#ta", expect_type=TextEditor)
|
|
ta.text = text
|
|
ta.selection = selection
|
|
|
|
for key in keys:
|
|
await pilot.press(key)
|
|
|
|
assert ta.text == expected_text
|
|
assert ta.selection == expected_selection
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"starting_selection,expected_clipboard,expected_paste_loc",
|
|
[
|
|
(Selection((0, 5), (1, 5)), "56789\n01234", (1, 5)),
|
|
(Selection((0, 0), (1, 0)), "0123456789\n", (1, 0)),
|
|
],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_copy_paste(
|
|
app_all_clipboards: App,
|
|
starting_selection: Selection,
|
|
expected_clipboard: str,
|
|
expected_paste_loc: tuple[int, int],
|
|
) -> None:
|
|
original_text = "0123456789\n0123456789\n0123456789"
|
|
|
|
def eq(a: str, b: str) -> bool:
|
|
return a.replace("\r\n", "\n") == b.replace("\r\n", "\n")
|
|
|
|
async with app_all_clipboards.run_test() as pilot:
|
|
ta = app_all_clipboards.query_one("#ta", expect_type=TextEditor)
|
|
while ta.text_input is None:
|
|
await pilot.pause(0.1)
|
|
ti = ta.text_input
|
|
assert ti is not None
|
|
ta.text = original_text
|
|
ta.selection = starting_selection
|
|
|
|
await pilot.press("ctrl+c")
|
|
await pilot.pause()
|
|
assert eq(ti.clipboard, expected_clipboard)
|
|
assert ta.selection == starting_selection
|
|
assert ta.text == original_text
|
|
|
|
await pilot.press("ctrl+u")
|
|
await pilot.pause()
|
|
assert eq(ti.clipboard, expected_clipboard)
|
|
assert ta.selection == Selection(starting_selection.end, starting_selection.end)
|
|
assert ta.text == original_text
|
|
|
|
await pilot.press("ctrl+a")
|
|
assert ta.selection == Selection(
|
|
(0, 0),
|
|
(len(original_text.splitlines()) - 1, len(original_text.splitlines()[-1])),
|
|
)
|
|
assert eq(ti.clipboard, expected_clipboard)
|
|
assert ta.text == original_text
|
|
|
|
await pilot.press("ctrl+u")
|
|
await pilot.pause()
|
|
assert ta.selection == Selection(expected_paste_loc, expected_paste_loc)
|
|
assert eq(ti.clipboard, expected_clipboard)
|
|
assert ta.text == expected_clipboard
|
|
|
|
await pilot.press("ctrl+a")
|
|
await pilot.press("ctrl+x")
|
|
await pilot.pause()
|
|
assert ta.selection == Selection((0, 0), (0, 0))
|
|
assert eq(ti.clipboard, expected_clipboard)
|
|
assert ta.text == ""
|
|
|
|
await pilot.press("ctrl+v")
|
|
await pilot.pause()
|
|
assert eq(ti.clipboard, expected_clipboard)
|
|
assert ta.text == expected_clipboard
|
|
assert ta.selection == Selection(expected_paste_loc, expected_paste_loc)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_undo_redo(app: App) -> None:
|
|
async with app.run_test() as pilot:
|
|
ta = app.query_one("#ta", expect_type=TextEditor)
|
|
ti = ta.text_input
|
|
assert ti
|
|
assert ti.has_focus
|
|
|
|
for char in "foo":
|
|
await pilot.press(char)
|
|
await pilot.pause(0.6)
|
|
|
|
await pilot.press("enter")
|
|
for char in "bar":
|
|
await pilot.press(char)
|
|
await pilot.pause(0.6)
|
|
|
|
await pilot.press("ctrl+z")
|
|
assert ta.text == "foo\n"
|
|
assert ta.selection == Selection((1, 0), (1, 0))
|
|
|
|
await pilot.press("ctrl+z")
|
|
assert ta.text == "foo"
|
|
assert ta.selection == Selection((0, 3), (0, 3))
|
|
|
|
await pilot.press("ctrl+z")
|
|
assert ta.text == ""
|
|
assert ta.selection == Selection((0, 0), (0, 0))
|
|
|
|
await pilot.press("ctrl+y")
|
|
assert ta.text == "foo"
|
|
assert ta.selection == Selection((0, 3), (0, 3))
|
|
|
|
await pilot.press("z")
|
|
assert ta.text == "fooz"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"start_text,insert_text,selection,expected_text",
|
|
[
|
|
(
|
|
"select ",
|
|
'"main"."drivers"."driverId"',
|
|
Selection((0, 7), (0, 7)),
|
|
'select "main"."drivers"."driverId"',
|
|
),
|
|
(
|
|
"select , foo",
|
|
'"main"."drivers"."driverId"',
|
|
Selection((0, 7), (0, 7)),
|
|
'select "main"."drivers"."driverId", foo',
|
|
),
|
|
(
|
|
"aaa\naaa\naaa\naaa",
|
|
"bb",
|
|
Selection((2, 2), (2, 2)),
|
|
"aaa\naaa\naabba\naaa",
|
|
),
|
|
(
|
|
"aaa\naaa\naaa\naaa",
|
|
"bb",
|
|
Selection((2, 2), (1, 1)),
|
|
"aaa\nabba\naaa",
|
|
),
|
|
(
|
|
"01234",
|
|
"\nabc\n",
|
|
Selection((0, 2), (0, 2)),
|
|
"01\nabc\n234",
|
|
),
|
|
],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_insert_text(
|
|
app: App,
|
|
start_text: str,
|
|
insert_text: str,
|
|
selection: Selection,
|
|
expected_text: str,
|
|
) -> None:
|
|
async with app.run_test() as pilot:
|
|
ta = app.query_one("#ta", expect_type=TextEditor)
|
|
ta.text = start_text
|
|
ta.selection = selection
|
|
await pilot.pause()
|
|
|
|
ta.insert_text_at_selection(insert_text)
|
|
await pilot.pause()
|
|
|
|
assert ta.text == expected_text
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_toggle_comment(app: App) -> None:
|
|
async with app.run_test() as pilot:
|
|
ta = app.query_one("#ta", expect_type=TextEditor)
|
|
ta.text = "one\ntwo\n\nthree"
|
|
ta.selection = Selection((0, 0), (0, 0))
|
|
await pilot.pause()
|
|
|
|
await pilot.press("ctrl+underscore")
|
|
assert ta.text == "# one\ntwo\n\nthree"
|
|
|
|
await pilot.press("down")
|
|
await pilot.press("ctrl+underscore")
|
|
assert ta.text == "# one\n# two\n\nthree"
|
|
|
|
await pilot.press("ctrl+a")
|
|
await pilot.press("ctrl+underscore")
|
|
assert ta.text == "# # one\n# # two\n\n# three"
|
|
|
|
await pilot.press("ctrl+underscore")
|
|
assert ta.text == "# one\n# two\n\nthree"
|
|
|
|
await pilot.press("up")
|
|
await pilot.press("up")
|
|
await pilot.press("ctrl+underscore")
|
|
assert ta.text == "# one\ntwo\n\nthree"
|
|
|
|
await pilot.press("shift+down")
|
|
await pilot.press("shift+down")
|
|
await pilot.press("ctrl+underscore")
|
|
assert ta.text == "# one\n# two\n\n# three"
|
|
|
|
await pilot.press("ctrl+a")
|
|
await pilot.press("ctrl+underscore")
|
|
assert ta.text == "one\ntwo\n\nthree"
|