IngoMeyer441 / simple-term-menu

A Python package which creates simple interactive menus on the command line.
MIT License
492 stars 43 forks source link

Add support for vertical split preview #51

Open plainas opened 2 years ago

plainas commented 2 years ago

Tittle is self explanatory.

IngoMeyer441 commented 2 years ago

Hey, interesting idea. Do you want to display multiple previews in parallel?

plainas commented 2 years ago

No, I mean the main layout with the list of entries and the preview. Instead of an horizontal split, a vertical one. like https://github.com/junegunn/fzf

IngoMeyer441 commented 2 years ago

Ah, I see. This would definitely be more compact, but also needs many code changes. I can add it to my todo list, but do not expect it to land in a release in the near future. The main problem is that the current code is too simple for this kind of feature. Every terminal line only gets one element. I think we need a mechanism to place boxes into the terminal to make this right. With this the preview box could be placed at different locations in the terminal.

plainas commented 2 years ago

I just skimmed to the code briefly and I am not sure how interactivity is implemented. Is it done only by outputing escape sequences and calls to termios for things like flushing the screen?

I should say that I am not too familiar with with low level text terminal protocol. I see there the signal module is used, probably to take in key presses, so I believe there should be a main loop somewhere to do this?

I am getting a bit off topic. Where I wanted to get is that perhaps this program has reached the point where being based on ncurses would start to make sense. And at that point, spiting the screen in boxes is relatively simple. Here's an example:

https://www.viget.com/articles/c-games-in-ncurses-using-multiple-windows/

It's in C, but it is straightforward to port to python as the wrapper retains the functions names.

But I totally understand the motivation for keeping things low level instead of relying on a UI library (ncurses). Notice however, that ncurses is part of python's standard lib.

This module is still small and relatively unknown, but I think its usefulness is tremendous. I have been using percol for many years and rely on it to an almost abusive level in shellscripts. The other day I needed to port a script I wrote to python and, while percol can be used as a python library, I wanted preview functionality. So I googled a little bit and found this module. In a few minutes, and with just 3 lines of code or so, I had a nice UI to run some tests on a project I am working on. I am mentioning this because it is very close to be a just perfect module to hack together quick terminal UIs.

Here are a couple of example applications using fzf

Both are just quick shellscripts and rely on a bit hacky usage of fzf. While sometimes a shellscript is the best and most direct option, often times, doing these things in python opens many possibilities and becomes a bit cleaner in terms of string escaping and such things.

IngoMeyer441 commented 2 years ago

I just skimmed to the code briefly and I am not sure how interactivity is implemented. Is it done only by outputing escape sequences and calls to termios for things like flushing the screen? I should say that I am not too familiar with with low level text terminal protocol. I see there the signal module is used, probably to take in key presses, so I believe there should be a main loop somewhere to do this?

The script uses tput to query the terminfo database for all needed escape sequences (moving the cursor, deleting lines, text formatting and so on) and then uses them to create the menu display; so yes, it is done by only outputing raw escape sequences depending on the used terminal emulator.

The signal module is used to catch terminal signals like SIGWINCH which is raised when the terminal size changes.

termios is only used to put stdin in a non-buffered mode and to suppress character output of pressed keys. This way, single key presses can be read from stdin in the main loop. So yes, there is a main loop to read key presses, change the internal state and repaint the menu.

I am getting a bit off topic. Where I wanted to get is that perhaps this program has reached the point where being based on ncurses would start to make sense.

ncurses is a very common library and should be available on every *nix host so it should be fine to depend on it. The reasons why I initially decided against ncurses were:

If the second point is not true and there is a port for Windows, then ncurses would be a real alternative for me.

This module is still small and relatively unknown, but I think its usefulness is tremendous. I have been using percol for many years and rely on it to an almost abusive level in shellscripts. The other day I needed to port a script I wrote to python and, while percol can be used as a python library, I wanted preview functionality. So I googled a little bit and found this module. In a few minutes, and with just 3 lines of code or so, I had a nice UI to run some tests on a project I am working on. I am mentioning this because it is very close to be a just perfect module to hack together quick terminal UIs.

Nice! :smile:

Here are a couple of example applications using fzf

I also use fzf every day. :+1: The idea for a preview window for this project came from fzf. I put the preview below the entries to gain more width for the preview lines. Don't know why I didn't think about implementing another layout like in fzf...

Both are just quick shellscripts and rely on a bit hacky usage of fzf. While sometimes a shellscript is the best and most direct option, often times, doing these things in python opens many possibilities and becomes a bit cleaner in terms of string escaping and such things.

simple-term-menu can also be used in shell scripts. When you installed it with pip you got a simple-term-menu command. It either returns the selected menu entry by its exit code or prints it to stdout.

plainas commented 2 years ago

There are ncurses wrappers out there that support windows. I came across this one the other day which appears to be feature complete. I am not sure there are more out there. https://github.com/unicurses/unicurses

But on that note, is support for windows really that important? I would guess windows usage is negotiable. The default python installation on windows doesn't even put the binary accessible to the command line environment.

I wanted a solution which can be very compact and retains the previous screen contents.

I am not sure this is the same, but most applications that use ncurses, including a couple I wrote myself, restore the previous terminal state on finish.

IngoMeyer441 commented 2 years ago

There are ncurses wrappers out there that support windows. I came across this one the other day which appears to be feature complete. I am not sure there are more out there.

unicurses looks really useful!

But on that note, is support for windows really that important? I would guess windows usage is negotiable. The default python installation on windows doesn't even put the binary accessible to the command line environment.

A good question. I wouldn't use it in Windows cmd or powershell myself :sweat_smile: But some users requested it and there is even a version of simple-term-menu which works on Windows (but not on Linux any more, see the PR). I think most people use it on macOS and Linux.

I wanted a solution which can be very compact and retains the previous screen contents.

I mean something like this: Untitled

You can still see the previous terminal contents while using simple-term-menu. IMHO, it is a bit disturbing to open a full screen application for a menu selection.

plainas commented 2 years ago

I see. I agree it is less disturbing, specially in large screens. Sounds like the way to go is a way to draw boxes. Perhaps at the end of each repaint cycle, a box can be drawn on top of existing contents, on the right side.