diff --git a/rexi/cli.py b/rexi/cli.py index 0c1c641..35d60ae 100644 --- a/rexi/cli.py +++ b/rexi/cli.py @@ -8,6 +8,7 @@ app = typer.Typer() + def is_stdin_a_tty() -> bool: """Wrapper for sys.stdin.isatty. @@ -16,6 +17,7 @@ def is_stdin_a_tty() -> bool: """ return sys.stdin.isatty() + # noinspection SpellCheckingInspection @app.command("rexi") def rexi_cli( diff --git a/rexi/regex_help.py b/rexi/regex_help.py new file mode 100644 index 0000000..c2bd320 --- /dev/null +++ b/rexi/regex_help.py @@ -0,0 +1,12 @@ +REGEX_HELP = { + r"^": "Start of line", + r"$": "End of line", + r"(a|b)": "a or b", + r"[abc]": "Range (a or b or c)", + r"[^abc]": "Not (a or b or c)", + r"[a-q]": "Lower case letter from a to q", + r"[0-7]": "Digit from 0 to 7", + r"\\x": "Group/subpattern number x", + r".*": "0 or more characters", + r".": "Any chrarcter except \\n", +} diff --git a/rexi/rexi.py b/rexi/rexi.py index 7db04c7..6834cc0 100644 --- a/rexi/rexi.py +++ b/rexi/rexi.py @@ -5,8 +5,11 @@ from colorama import Fore from textual import on from textual.app import App, ComposeResult, ReturnType -from textual.containers import Horizontal, ScrollableContainer -from textual.widgets import Header, Input, Select, Static +from textual.containers import Container, Horizontal, ScrollableContainer +from textual.screen import ModalScreen +from textual.widgets import Button, Header, Input, Label, Select, Static + +from .regex_help import REGEX_HELP UNDERLINE = "\033[4m" RESET_UNDERLINE = "\033[24m" @@ -33,6 +36,22 @@ def __repr__(self) -> str: return f"Group \"{'|'.join(map(str, self.keys))}\": \"{self.value}\"" +class Help(ModalScreen[ReturnType]): + def compose(self) -> ComposeResult: + with Container(): + yield Label("Help for regex:") + with Horizontal(): + help_keys = "\n".join(REGEX_HELP.keys()) + help_values = "\n".join(REGEX_HELP.values()) + yield Static(help_keys, classes="helpKeys") + yield Static(help_values, classes="helpValues") + yield Button("Close", id="exitHelp", variant="success") + + @on(Button.Pressed, "#exitHelp") + def back_to_app(self) -> None: + self.app.pop_screen() + + # noinspection SpellCheckingInspection class RexiApp(App[ReturnType]): CSS_PATH = "rexi.tcss" @@ -67,7 +86,7 @@ def compose(self) -> ComposeResult: allow_blank=False, value=self.regex_current_mode, ) - + yield Button("Help", id="help") with ScrollableContainer(id="result"): with ScrollableContainer(id="output-container"): with Header(): @@ -78,6 +97,10 @@ def compose(self) -> ComposeResult: yield Static("Groups") yield Static(id="groups") + def on_button_pressed(self, event: Button.Pressed) -> None: + if event.button.id == "help": + self.push_screen(Help()) + @on(Input.Changed) async def on_input_changed(self, message: Input.Changed) -> None: self.pattern = message.value diff --git a/rexi/rexi.tcss b/rexi/rexi.tcss index cc9364e..dfe05a6 100644 --- a/rexi/rexi.tcss +++ b/rexi/rexi.tcss @@ -1,6 +1,5 @@ Input { - dock: top; - width: 100%; + width: 70%; } #output-container { @@ -8,10 +7,47 @@ Input { } #select { - dock: right; - width: 20%; + width: 15%; +} + +#help { + width: 15%; } #inputs { height: 4; +} + +Help { + align: center middle; +} + +Help > Container { + width: 50%; + height: 70%; + border: thick $background 80%; + background: $surface; + +} + +Help > Container > Label{ + margin: 1 1; +} + +Help > Container > Horizontal { + overflow-y: auto; +} + +Help > Container > Horizontal > .helpKeys { + width: 10%; + margin: 0 1 +} + +Help > Container > Horizontal > .helpValues { + width: 90%; +} + +Help > Container > Button { + align: center middle; + margin: 2 2; } \ No newline at end of file diff --git a/tests/test_cli.py b/tests/test_cli.py index 8729254..004b0da 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -92,10 +92,10 @@ def test_no_stdin_error(monkeypatch: MonkeyPatch) -> None: assert "Invalid value" in result.output -@pytest.mark.parametrize('input_value', [True, False]) +@pytest.mark.parametrize("input_value", [True, False]) def test_is_stdin_a_tty(monkeypatch: MonkeyPatch, input_value: bool) -> None: isatty_mock = Mock() with monkeypatch.context(): isatty_mock.return_value = input_value monkeypatch.setattr("rexi.cli.sys.stdin.isatty", isatty_mock) - assert is_stdin_a_tty() == input_value \ No newline at end of file + assert is_stdin_a_tty() == input_value diff --git a/tests/test_ui.py b/tests/test_ui.py index 139a0a9..55eb4f9 100644 --- a/tests/test_ui.py +++ b/tests/test_ui.py @@ -53,7 +53,8 @@ async def test_switch_modes() -> None: async with app.run_test() as pilot: assert app.regex_current_mode == "finditer" await pilot.click("SelectCurrent") - await pilot.click("SelectOverlay", offset=(2, 2)) + await pilot.press("down") + await pilot.press("enter") await pilot.wait_for_animation() assert app.regex_current_mode == "match"