From 0afa6d5b3ded8573097df1ce9df3e7eebf5d9ee1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 20 Mar 2025 12:49:28 +0530 Subject: [PATCH] Fix shebang viewing of short scripts not working --- tools/cmd/tool/confirm_and_run_shebang.go | 18 ++++++++++++++++-- tools/tty/tty.go | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/tools/cmd/tool/confirm_and_run_shebang.go b/tools/cmd/tool/confirm_and_run_shebang.go index 502b3572a..f8102bae9 100644 --- a/tools/cmd/tool/confirm_and_run_shebang.go +++ b/tools/cmd/tool/confirm_and_run_shebang.go @@ -16,6 +16,7 @@ import ( "kitty/kittens/ask" "kitty/tools/cli" "kitty/tools/cli/markup" + "kitty/tools/tty" "kitty/tools/utils" ) @@ -39,6 +40,10 @@ func ask_for_permission(script_path string) (response string, err error) { return response, err } +func permission_denied(script_path string) error { + return fmt.Errorf("Execution of %s was denied by user", script_path) +} + func confirm_and_run_shebang(args []string, confirm_policy ConfirmPolicy) (rc int, err error) { script_path := args[len(args)-1] do_confirm := true @@ -57,14 +62,23 @@ func confirm_and_run_shebang(args []string, confirm_policy ConfirmPolicy) (rc in } switch response { default: - return 1, fmt.Errorf("Execution of %s was denied by user", script_path) + return 1, permission_denied(script_path) case "v": raw, err := os.ReadFile(script_path) if err != nil { return 1, err } cli.ShowHelpInPager(utils.UnsafeBytesToString(raw)) - return confirm_and_run_shebang(args, ConfirmIfNeeded) + // The pager might have exited automatically if there is less than + // one screen of text, so confirm manually, here, where output from + // pager will still be visible. + fmt.Print("Execute the script? (y/n): ") + q, err := tty.ReadSingleByteFromTerminal() + if q != 'y' && q != 'Y' { + fmt.Println() + return 1, permission_denied(script_path) + } + fmt.Print("\x1b[H\x1b[2J") // clear screen case "e": exe, err := os.Executable() if err != nil { diff --git a/tools/tty/tty.go b/tools/tty/tty.go index 4d45c7e18..a2e2bb148 100644 --- a/tools/tty/tty.go +++ b/tools/tty/tty.go @@ -78,6 +78,10 @@ func SetReadTimeout(d time.Duration) TermiosOperation { var SetBlockingRead TermiosOperation = SetReadTimeout(0) +var SetNoCanonical TermiosOperation = func(t *unix.Termios) { + t.Lflag &^= unix.ICANON +} + var SetRaw TermiosOperation = func(t *unix.Termios) { // This attempts to replicate the behaviour documented for cfmakeraw in // the termios(3) manpage, as Go doesn't wrap cfmakeraw probably because its not in POSIX @@ -380,3 +384,21 @@ func DebugPrintln(a ...any) { term.DebugPrintln(a...) } } + +func ReadSingleByteFromTerminal() (b byte, err error) { + term, err := OpenControllingTerm(SetBlockingRead, SetNoCanonical) + if err != nil { + return 0, err + } + defer term.Close() + ans := []byte{b} + for { + n, err := term.Read(ans) + if err != nil { + return 0, err + } + if n > 0 { + return ans[0], nil + } + } +}