Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patching input prompt flushing to redirect khard show to a highlighter #333

Open
tkapias opened this issue Feb 10, 2024 · 1 comment
Open
Labels
waiting Waiting for more information

Comments

@tkapias
Copy link

tkapias commented Feb 10, 2024

Introduction

Khard being console oriented is nice, but I miss some coloration, at least in khard show.
For that purpose I use hl, it colorizes any output according to a simple configuration based on regular expressions.

But, when piping khard show to hl there is an issue that I described in hl's repo, here.

I did open it at hl first, because piping to cat did not show the same issue, but I later wrote a patch for Khard which I'd like to share and, I think, also enhance the output format.

Issue

In short, the user input prompt string is not flushed before the user answer, but after, when redirected to hl, and without a newline.

image

See like the index number inputed is above the prompt, which appear later on the same line as the pretty vcard first line.

Solution

Normally python should flush every print with a newline. I suspected that piping to hl breaks this behaviour, so I tried to force it by using flush=True in different places in interactive.select, but it does not change the result.

  • So I added manually a newline to the prompt string.

  • I also added more print() after if index > 0: to erase the input prompt after the answer, rewrite the selected index number and put a newline for clarity

image
image

I find this result more pleasing, even without hl.

  • My patch for helpers/interactive.py:
diff --git a/khard/helpers/interactive.py b/khard/helpers/interactive.py
index 79db461..db36141 100644
--- a/khard/helpers/interactive.py
+++ b/khard/helpers/interactive.py
@@ -91,7 +91,7 @@ def select(items: Sequence[T], include_none: bool = False) -> Optional[T]:
     :returns: None or the selected item
     :raises Canceled: when the user canceled the selection process
     """
-    prompt = "Enter Index ({}q to quit): ".format("0 for None, "
+    prompt = "Enter Index ({}q to quit):\n".format("0 for None, "
                                                   if include_none else "")
     while True:
         try:
@@ -103,6 +103,8 @@ def select(items: Sequence[T], include_none: bool = False) -> Optional[T]:
             if include_none and index == 0:
                 return None
             if index > 0:
+                print("\033[1A" + "\033[K" + "\033[1A" + "\033[K" + "Selected Index: ", end="")
+                print(index, end="\n\n")
                 return items[index - 1]
         except (EOFError, IndexError, ValueError):
             pass

Extra

For those interested, I use the combo khard show/hl in a bash function:

contacts () { 
    echo
    khard show $@ | hl --khard
    echo
}

And my hl configuration for khard is currently this (~/.config/hl/config.d/hl_khal.cfg):

khard            :
     -e
     -3w '^[ ]{4}?[a-zA-Z][a-zA-Z -]{1,12}:'
     -3g '^Address book: (.*)$'
     -3y '^Index.*$'
     -1y '^[0-9]+'
     -2c 'Nickname:'
     -1w '[ ]{4}([a-zA-Z]+:)'
     -3r ': (\+?\(?[0-9]{1,3}\)?[0-9 -]{8,13}[0-9])'
     -3b '([^ ]+)@[^ ]+\.[^ ]+'
     -2b '[^ ]+(@[^ ]+\.[^ ]+)'

You may need to export some path for the hl config files, like this:

export HL_CONF=$HOME/.config/hl/config.d:/etc/hl/config.d

@lucc
Copy link
Owner

lucc commented Feb 23, 2024

Thanks for your report. I can confirm what you describe but I think the underlying problem is thus:

  • I assume (did not check the source) that hl waits for a newline until it start matching regexes, coloring and printing output
  • the python function print() indeed prints a newline at the end (docs), the input() function on the other hand

    If the prompt argument is present, it is written to standard output without a trailing newline. The function then reads a line from input, converts it to a string (stripping a trailing newline), and returns that.

  • so the terminal does not see the input prompt when you type (it is still buffered by hl) but the text you type already appears on the terminal (because normally the terminal is in echo mode)
  • when you press enter at the end of your input python's input() returns and then later on print()s some stuff. That is when hl sees the next newline and starts to output stuff again.

I do not really like the code changes you propose for these reasons:

  • the extra newline fixes your problem only at this specific place. The ask() function is not fixed. And if we refactor some output somewhere it might break again. So we need a decision first. Do we constraint khard to only output full lines so that we can do something with the output? (And what happens with khard edit calling e.g. nvim?)
  • If we accept that khard should always output newlines at the end of prompts, a more general solution would be to wrap builtins.input like so def input(prompt): return builtins.input(prompt+"\n") and only use that in khard
  • I do not like terminal control code stuff because I see no real value in it. Can you explain why that is needed?

@lucc lucc added the waiting Waiting for more information label Feb 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting Waiting for more information
Projects
None yet
Development

No branches or pull requests

2 participants