davatorium / rofi

Rofi: A window switcher, application launcher and dmenu replacement
https://davatorium.github.io/rofi/
Other
12.81k stars 610 forks source link

Option to continuously print selected line in dmenu mode #997

Open Sohalt opened 4 years ago

Sohalt commented 4 years ago

Version

1.5.2

Description

It would be cool to have a flag to have rofi continuously print the currently selected line in dmenu mode.

My usecase is a menu for choosing a colorscheme with https://github.com/toggle-corp/alacritty-colorscheme. alacritty-colorscheme -l gives me a list of available colorschemes, which I then pipe into rofi. I can then select a colorscheme and apply it with alacritty-colorscheme -a $theme. A simple menu would look like this:

alacritty-colorscheme -a $(alacritty-colorscheme -l | rofi -dmenu)

I now would like to be able to cycle through the menu and get a live preview of the colorscheme which is currently selected. If rofi would continuously print the currently selected line I could do something like:

alacritty-colorscheme -l | rofi -dmenu -special-flag-for-continuous-output |
while read theme; do
  alacritty-colorscheme -a $theme
done
carnager commented 4 years ago

It's relatively easy to make Enter loop through your list.

#!/bin/bash

main () {
    # store first argument in variable "$selected"
    local selected
    local string
    selected="${1}"

    # use -format to get selected line number and the actual string, separated by ":"
    # rofi knows of i and d for line numbers. d starts with 1 and i with 0.
    # the "-selected-row" argument counts from zero, so we can simply use the output of "d"
    # to get to the next line without further calculation
    menu=$(alacritty-colorscheme -l  | rofi -format 'd:s' -dmenu -selected-row $selected)

    # store exit code so we can escape the loop with ESC
    exit_code=$?

    # store line number and string in variables
    selected="${menu%:*}"
    string="${menu##*:}"

    # check if ESC was pressed and exit
    if [[ $exit_code == "1" ]]; then exit; fi

    # actually do something useful with the string
    alacritty-colorscheme -a "${string}"

    # run loop again, select next line this time
    main "${selected}"
}

# Run main function and select first row
main 0
Sohalt commented 4 years ago

Thanks, this kind of works, but it is slightly annoying if I want to go back and forth between options to compare them (I have to press up and then Enter).

carnager commented 4 years ago

Somewhat more complex and can possibly be done cleaner:

#!/bin/bash

main () {
    local selected
    local string
    selected="${1}"

    schemes="$(alacritty-colorscheme -l)"
    lines=$(printf '%s\n' "${schemes}" | wc -l)
    menu=$(printf '%s\n' "${schemes}"  | rofi -kb-row-up "" -kb-row-down "" -kb-custom-1 "Up" -kb-custom-2 "Down" -format 'd:s' -dmenu -selected-row $selected)

    exit_code=$?

    selected="${menu%:*}"
    string="${menu##*:}"

    case "${exit_code}" in
        "1") exit ;;
        "0") alacrity-colorscheme -a "${string}" ;;
        "10") 
            if [[ $selected == "1" ]]; then
                foo_selected="${lines}"
                call="3"
            else
                foo_selected="$(echo -e $(( ${selected} - 1 )))";
                call=$(echo $(( ${selected} - 2 )))
            fi
            foo="$(printf '%s' "${schemes}" | sed -n "${foo_selected}"p)";
            alacritty-colorscheme -a "${foo}" ;;
        "11") 
            if [[ "${selected}" -ge "${lines}" ]]; then
                foo_selected="1"
                call="0"
            else
                foo_selected="$(echo -e $(( ${selected} + 1 )))";
                call="${selected}"
            fi
            foo="$(printf '%s' "${schemes}" | sed -n "${foo_selected}"p)";
            alacritty-colorscheme -a "${foo}"
    esac

    main "${call}"
}

main 0
Sohalt commented 4 years ago

This works, but it's super hacky imho. It also has the downside of restarting rofi on every selection change, which results in flickering. I would still be very much in favor of having rofi handle this use case natively.

sardemff7 commented 4 years ago

You can do that as a script mode quite easily, and it won’t flicker. Not perfectly sure about the bindings but if you don’t mind a wrapper script it’ll surely work. You can also create a plugin in C.

digitalsignalperson commented 1 year ago

You can do that as a script mode quite easily, and it won’t flicker. Not perfectly sure about the bindings but if you don’t mind a wrapper script it’ll surely work. You can also create a plugin in C.

I've been scratching my head for awhile how this might be done in a rofi script and I can't figure it out. From what I can tell, a script cannot monitor the current row changes in any way.

digitalsignalperson commented 1 year ago

I couldn't figure out how to do it with a script, so I made changes to the app for my specific use-case: https://github.com/davatorium/rofi/compare/next...digitalsignalperson:rofi-kwin-highlight:kwin_highlight

As the selection changes it outputs data over stderr