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

[question] elegant way to call function in an previous instead of call script file #3599

Open
5 of 10 tasks
marslo opened this issue Jan 24, 2024 · 5 comments
Open
5 of 10 tasks

Comments

@marslo
Copy link

marslo commented Jan 24, 2024

  • I have read through the manual page (man fzf)
  • I have the latest version of fzf
  • I have searched through the existing issues

Info

  • OS
    • Linux
    • Mac OS X
    • Windows
    • Etc.
  • Shell
    • bash
    • zsh
    • fish

Problem / Steps to reproduce

The question is inspired from $ unset **<TAB>. I'd like to have a function to enhance the format and something else for environment variable.

So, theoretical basis to get value of variable value:

$ foo='SHELL'      # `SHELL` is the env var name

$ echo "${foo} - $(eval echo \$$foo)"
SHELL - /usr/local/bin/bash                  # i.e.: this is what I want to show in preview
# or
$ echo "${foo} - ${!foo}"
SHELL - /usr/local/bin/bash

I had a function ( getenv for example ) as below:

$ cat ~/ee.sh
#!/usr/bin/env bash
# shellcheck disable=SC2086

function _echo_values() { echo -e ">> $1\n.. $(eval echo \$$1)"; }
function getenv() {
  local option
  local -a array

  option='-1 --exit-0 --sort --multi --cycle'

  while read -r _env; do
    _echo_values $_env                                           # expected: show in terminal
    array+=( "${_env}=$(eval echo \$${_env})" )
  done < <( env |
            sed -r 's/^([a-zA-Z0-9_-]+)=.*$/\1/' |
            fzf ${option} \
                --prompt 'env> ' \
                --preview-window 'right,70%,wrap,rounded' \
                --preview "_echo_values {}" \                    # expected: show in preview
                --header 'TAB/SHIFT-TAB to select multiple items, CTRL-D to deselect-all, CTRL-S to select-all'
          )
  pbcopy < <( printf '%s\n' "${array[@]}" | head -c-1 )
}

# source the function and verify
$ source ~/ee.sh
$ _echo_values SHELL                                           # verify
>> SHELL
.. /usr/local/bin/bash                                         # works

however, in the fzf preview window, it shows issue:

/usr/local/bin/bash: line 1: _echo_values: command not found
getenv-1

And the bash works:
image

I've tried to move _echo_values() inside of function getenv() as below, but still no lucky:

function getenv() {
  local option
  local -a array

  option='-1 --exit-0 --sort --multi --cycle'
  _echo_values() { echo -e ">> $1\n.. $(eval echo \$$1)"; }     # moved inside of `getenv`, cannot be call in terminal, but can be identified inside the `getenv()`

  while read -r _env; do
    _echo_values $_env                                          # works here
    array+=( "${_env}=$(eval echo \$${_env})" )
  done < <( env |
            sed -r 's/^([a-zA-Z0-9_-]+)=.*$/\1/' |
            fzf ${option} \
                --prompt 'env> ' \
                --preview-window 'right,70%,wrap,rounded' \
                --preview "_echo_values {}" \                    # issue here: `/usr/local/bin/bash : line 1: _echo_values: command not found`
                --header 'TAB/SHIFT-TAB to select multiple items, CTRL-D to deselect-all, CTRL-S to select-all'
          )
  pbcopy < <( printf '%s\n' "${array[@]}" | head -c-1 )
}

So, I tried to move the _echo_values() to separate files and it works:
image

I'd like to know whether if any elegant way can handle call a function in --preview instead of call a shell script file

@marslo
Copy link
Author

marslo commented Jan 24, 2024

hmmm.... I realized that maybe I can use --nth to prevent call function/scripts to show {1} in list, and {2} in previous, and it indeed works :

$ env |
  sed -r 's/^([a-zA-Z0-9_-]+)=(.*)$/\1 \2/' |
  fzf --delimiter=' ' \
      --preview='source ~/.marslo/bin/bash-color.sh; echo -e "$(c Ys)>> {1}$(c)\n$(c Wi).. {2}$(c)"' \
      --with-nth=1
getenv-preview.mov

but I'm still curious how to call function instead of scripts, for more complex process to preview

@marslo
Copy link
Author

marslo commented Jan 24, 2024

suddenly realized that, I'm struggling for so long is because of " and ' are different behavior in --preview !

I was using " ( double quotes ) in the very beginning, and it's not working, so I decided to using function instead of cmd. Accidental I was using ' ( single quote ) and it worked !!

here are details:

  • double quotes
    $ env |
      sed -rn 's/^([a-zA-Z0-9]+)=.*$/\1/p' |
      fzf --preview-window 'up,30%,wrap,rounded' \
          --preview "_i={}; echo ${_i}"
  • single quote
    $ env |
      sed -rn 's/^([a-zA-Z0-9]+)=.*$/\1/p' |
      fzf --preview-window 'up,30%,wrap,rounded' \
          --preview '_i={}; echo ${_i}'

details:

fzf-preview-single-double-quotes.mov

my environment:

$ sw_vers
ProductName:		macOS
ProductVersion:		14.2.1
BuildVersion:		23C71

$ bash --version
GNU bash, version 5.2.26(1)-release (x86_64-apple-darwin23.2.0)
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ fzf --version
0.45.0 (brew)

marslo added a commit to marslo/dotfiles that referenced this issue Jan 24, 2024
@LangLangBart
Copy link
Contributor

LangLangBart commented Jan 24, 2024

I'd like to know whether if any elegant way can handle call a function in --preview instead of call a shell script file

Functions are not visible to child processes unless they are exported with export -f.

#!/usr/bin/env bash
foo() {
	echo foo
}
export -f foo
fzf --preview 'foo'

Note

Please note, if your login shell isn't bash (for example, on macOS the default is zsh), the
function still won't work unless you change the SHELL environment variable to bash.

SHELL="$(which bash)" fzf --preview 'foo'

fzf starts child processes using $SHELL -c COMMAND


Alternatives:

  1. make it a string and call the variable
foo=$'echo foo'
: | fzf --preview "$foo"
  1. place the function in a file and source it
foo() {
     echo foo
}
: | fzf --preview 'source /path/to/file/with/function; foo'

@marslo
Copy link
Author

marslo commented Jan 24, 2024

I'd like to know whether if any elegant way can handle call a function in --preview instead of call a shell script file

Functions are not visible to child processes unless they are exported with export -f.

#!/usr/bin/env bash
foo() {
	echo foo
}
export -f foo
fzf --preview 'foo'

export -f foo work like a charm !

Alternatives:

  1. make it a string and call the variable
foo=$'echo foo'
: | fzf --preview "$foo"
  1. place the function in a file and source it
foo() {
     echo foo
}
: | fzf --preview 'source /path/to/file/with/function'; foo'

for alternatives solution, how to handle fzf get from pip ( | ) ?
i.e.:

$ foo() { echo ${!1}; }

# fzf from `env | sed`:
$ env | sed -rn 's/^([a-zA-Z0-9]+)=.*$/\1/p' | fzf --preview-window 'up,30%,wrap,rounded' --preview "foo {} "

I've tried:

: | env | sed ... | fzf      # < not working
env | sed ... | : | fzf      # < not working

@LangLangBart
Copy link
Contributor

I've tried:

: | env | sed ... | fzf      # < not working
env | sed ... | : | fzf      # < not working

I'm not entirely clear on the problem. The colon :1 signifies nothing and can be omitted. It's
only useful if you want to initiate fzf with an empty list.

foo=$'input={};echo "${!input}"'
command env | sed -rn 's/^([a-zA-Z0-9]+)=.*$/\1/p' | SHELL=bash fzf --preview "$foo"

Footnotes

  1. Bourne Shell Builtins (Bash Reference Manual)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants