From ee8399ba563f8841a86abef934c127e456eb5260 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 17 Oct 2023 20:21:22 +0530 Subject: [PATCH] Port the mouse_demo kitten to Go --- kittens/mouse_demo/__init__.py | 0 kittens/mouse_demo/main.go | 66 ++++++++++++++++++++++++++++ kittens/mouse_demo/main.py | 79 ---------------------------------- kittens/runner.py | 2 +- tools/cmd/tool/main.go | 10 +++++ 5 files changed, 77 insertions(+), 80 deletions(-) delete mode 100644 kittens/mouse_demo/__init__.py create mode 100644 kittens/mouse_demo/main.go delete mode 100644 kittens/mouse_demo/main.py diff --git a/kittens/mouse_demo/__init__.py b/kittens/mouse_demo/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/kittens/mouse_demo/main.go b/kittens/mouse_demo/main.go new file mode 100644 index 000000000..539c92bf9 --- /dev/null +++ b/kittens/mouse_demo/main.go @@ -0,0 +1,66 @@ +// License: GPLv3 Copyright: 2023, Kovid Goyal, + +package mouse_demo + +import ( + "fmt" + + "kitty/tools/tui/loop" +) + +var _ = fmt.Print + +func Run(args []string) (rc int, err error) { + lp, err := loop.New() + if err != nil { + return 1, err + } + lp.MouseTrackingMode(loop.FULL_MOUSE_TRACKING) + var current_mouse_event *loop.MouseEvent + + draw_screen := func() { + lp.StartAtomicUpdate() + defer lp.EndAtomicUpdate() + if current_mouse_event == nil { + lp.Println(`Move the mouse or click to see mouse events`) + return + } + lp.ClearScreen() + lp.Printf("Position: %d, %d (pixels)\r\n", current_mouse_event.Pixel.X, current_mouse_event.Pixel.Y) + lp.Printf("Cell : %d, %d\r\n", current_mouse_event.Cell.X, current_mouse_event.Cell.Y) + lp.Printf("Type : %s\r\n", current_mouse_event.Event_type) + if current_mouse_event.Buttons != loop.NO_MOUSE_BUTTON { + lp.Println(current_mouse_event.Buttons.String()) + } + if mods := current_mouse_event.Mods.String(); mods != "" { + lp.Printf("Modifiers: %s\r\n", mods) + } + } + + lp.OnInitialize = func() (string, error) { + lp.SetCursorVisible(false) + draw_screen() + return "", nil + } + lp.OnFinalize = func() string { + lp.SetCursorVisible(true) + return "" + } + + lp.OnMouseEvent = func(ev *loop.MouseEvent) error { + current_mouse_event = ev + draw_screen() + return nil + } + lp.OnKeyEvent = func(ev *loop.KeyEvent) error { + if ev.MatchesPressOrRepeat("esc") || ev.MatchesPressOrRepeat("ctrl+c") { + lp.Quit(0) + } + return nil + } + err = lp.Run() + if err != nil { + rc = 1 + } + return +} diff --git a/kittens/mouse_demo/main.py b/kittens/mouse_demo/main.py deleted file mode 100644 index bf407d3f8..000000000 --- a/kittens/mouse_demo/main.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python -# License: GPLv3 Copyright: 2021, Kovid Goyal - -import sys -from typing import List, Optional - -from kitty.key_encoding import ALT, CAPS_LOCK, CTRL, HYPER, META, NUM_LOCK, SHIFT, SUPER - -from ..tui.handler import Handler -from ..tui.loop import Loop, MouseEvent -from ..tui.operations import MouseTracking - -mod_names = { - SHIFT: 'Shift', - ALT: 'Alt', - CTRL: 'Ctrl', - SUPER: 'Super', - HYPER: 'Hyper', - META: 'Meta', - NUM_LOCK: 'NumLock', - CAPS_LOCK: 'CapsLock', -} - - -def format_mods(mods: int) -> str: - if not mods: - return '' - lmods = [] - for m, name in mod_names.items(): - if mods & m: - lmods.append(name) - return '+'.join(lmods) - - -class Mouse(Handler): - mouse_tracking = MouseTracking.full - - def __init__(self) -> None: - self.current_mouse_event: Optional[MouseEvent] = None - - def initialize(self) -> None: - self.cmd.set_cursor_visible(False) - self.draw_screen() - - def finalize(self) -> None: - self.cmd.set_cursor_visible(True) - - def on_mouse_event(self, ev: MouseEvent) -> None: - self.current_mouse_event = ev - self.draw_screen() - - @Handler.atomic_update - def draw_screen(self) -> None: - self.cmd.clear_screen() - ev = self.current_mouse_event - if ev is None: - self.print('Move the mouse or click to see mouse events') - return - self.print(f'Position: {ev.pixel_x}, {ev.pixel_y}') - self.print(f'Cell: {ev.cell_x}, {ev.cell_y}') - self.print(f'{ev.type}') - if ev.buttons: - self.print(ev.buttons) - if ev.mods: - self.print(f'Modifiers: {format_mods(ev.mods)}') - - def on_interrupt(self) -> None: - self.quit_loop(0) - on_eot = on_interrupt - - -def main(args: List[str]) -> None: - loop = Loop() - handler = Mouse() - loop.loop(handler) - - -if __name__ == '__main__': - main(sys.argv) diff --git a/kittens/runner.py b/kittens/runner.py index 3cee69fbd..5b4bbafd5 100644 --- a/kittens/runner.py +++ b/kittens/runner.py @@ -133,7 +133,7 @@ def run_kitten(kitten: str, run_name: str = '__main__') -> None: def all_kitten_names() -> FrozenSet[str]: ans = [] for name in list_kitty_resources('kittens'): - if '__' not in name and '.' not in name and name != 'tui': + if '__' not in name and '.' not in name and name not in ('tui', 'mouse_demo'): ans.append(name) return frozenset(ans) diff --git a/tools/cmd/tool/main.go b/tools/cmd/tool/main.go index 76e62a6d7..71a480b8f 100644 --- a/tools/cmd/tool/main.go +++ b/tools/cmd/tool/main.go @@ -11,6 +11,7 @@ import ( "kitty/kittens/hints" "kitty/kittens/hyperlinked_grep" "kitty/kittens/icat" + "kitty/kittens/mouse_demo" "kitty/kittens/show_key" "kitty/kittens/ssh" "kitty/kittens/themes" @@ -50,6 +51,15 @@ func KittyToolEntryPoints(root *cli.Command) { unicode_input.EntryPoint(root) // show_key show_key.EntryPoint(root) + // mouse_demo + root.AddSubCommand(&cli.Command{ + Name: "mouse_demo", + ShortDescription: "Demo the mouse handling kitty implements for terminal programs", + OnlyArgsAllowed: true, + Run: func(cmd *cli.Command, args []string) (rc int, err error) { + return mouse_demo.Run(args) + }, + }) // hyperlinked_grep hyperlinked_grep.EntryPoint(root) // ask