add multiline-hidden prompt for both ui and cli
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import enum
|
||||
import logging
|
||||
import sys
|
||||
import termios
|
||||
import tty
|
||||
from dataclasses import dataclass
|
||||
from getpass import getpass
|
||||
from typing import Any
|
||||
@@ -15,6 +17,7 @@ class PromptType(enum.Enum):
|
||||
LINE = "line"
|
||||
HIDDEN = "hidden"
|
||||
MULTILINE = "multiline"
|
||||
MULTILINE_HIDDEN = "multiline-hidden"
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -36,6 +39,63 @@ class Prompt:
|
||||
)
|
||||
|
||||
|
||||
def get_multiline_hidden_input() -> str:
|
||||
"""
|
||||
Get multiline input from the user without echoing the input.
|
||||
This function allows the user to enter multiple lines of text,
|
||||
and it will return the concatenated string of all lines entered.
|
||||
The user can finish the input by pressing Ctrl-D (EOF).
|
||||
"""
|
||||
|
||||
# Save terminal settings
|
||||
fd = sys.stdin.fileno()
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
|
||||
lines = []
|
||||
current_line: list[str] = []
|
||||
|
||||
try:
|
||||
# Change terminal settings - disable echo
|
||||
tty.setraw(fd)
|
||||
|
||||
while True:
|
||||
char = sys.stdin.read(1)
|
||||
|
||||
# Check for Ctrl-D (ASCII value 4 or EOF)
|
||||
if not char or ord(char) == 4:
|
||||
# Add last line if not empty
|
||||
if current_line:
|
||||
lines.append("".join(current_line))
|
||||
break
|
||||
|
||||
# Check for Ctrl-C (KeyboardInterrupt)
|
||||
if ord(char) == 3:
|
||||
raise KeyboardInterrupt
|
||||
|
||||
# Handle Enter key
|
||||
if char == "\r" or char == "\n":
|
||||
lines.append("".join(current_line))
|
||||
current_line = []
|
||||
# Print newline for visual feedback
|
||||
sys.stdout.write("\r\n")
|
||||
sys.stdout.flush()
|
||||
# Handle backspace
|
||||
elif ord(char) == 127 or ord(char) == 8:
|
||||
if current_line:
|
||||
current_line.pop()
|
||||
# Regular character
|
||||
else:
|
||||
current_line.append(char)
|
||||
|
||||
finally:
|
||||
# Restore terminal settings
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
# Print a final newline for clean display
|
||||
print()
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def ask(
|
||||
ident: str,
|
||||
input_type: PromptType,
|
||||
@@ -53,6 +113,9 @@ def ask(
|
||||
case PromptType.MULTILINE:
|
||||
print(f"{text} (Finish with Ctrl-D): ")
|
||||
result = sys.stdin.read()
|
||||
case PromptType.MULTILINE_HIDDEN:
|
||||
print("Enter multiple lines (press Ctrl-D to finish or Ctrl-C to cancel):")
|
||||
result = get_multiline_hidden_input()
|
||||
case PromptType.HIDDEN:
|
||||
result = getpass(f"{text} (hidden): ")
|
||||
|
||||
|
||||
@@ -33,19 +33,19 @@ def set_var(machine: str | Machine, var: str | Var, value: bytes, flake: Flake)
|
||||
)
|
||||
|
||||
|
||||
def set_via_stdin(machine: str, var_id: str, flake: Flake) -> None:
|
||||
var = get_var(str(flake.path), machine, var_id)
|
||||
def set_via_stdin(machine_name: str, var_id: str, flake: Flake) -> None:
|
||||
machine = Machine(name=machine_name, flake=flake)
|
||||
var = get_var(str(flake.path), machine_name, var_id)
|
||||
if sys.stdin.isatty():
|
||||
new_value = ask(
|
||||
var.id,
|
||||
PromptType.HIDDEN,
|
||||
PromptType.MULTILINE_HIDDEN,
|
||||
None,
|
||||
).encode("utf-8")
|
||||
else:
|
||||
new_value = sys.stdin.buffer.read()
|
||||
|
||||
_machine = Machine(name=machine, flake=flake)
|
||||
set_var(_machine, var, new_value, flake)
|
||||
set_var(machine, var, new_value, flake)
|
||||
|
||||
|
||||
def _set_command(args: argparse.Namespace) -> None:
|
||||
|
||||
Reference in New Issue
Block a user