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

possibility to suppress output if stdin is empty and set header manually #2916

Open
marslo opened this issue Mar 27, 2024 · 5 comments
Open
Labels
feature-request New feature or request

Comments

@marslo
Copy link

marslo commented Mar 27, 2024

I'm using sed commandline to fetch all of TODO in source code and shows via batcat as below:

$ fd -tf --color never |
  xargs -r -I{} bash -c "sed -ne '/TODO:/,/^\s*$/p' {} | bat -l groovy"

However, the bat shows STDIN <EMPTY> if sed command returns nothing.

currently I'm using if..else.. to show content via bat as below:

$ while read -r file; do
  _content=$(sed -ne '/TODO:/,/^\s*$/p' "${file}");
  [[ -n "${_content}" ]] && echo "${_content}" | bat -l groovy;
done < <(fd -tf --color never)

Any better solution to suppress output if stdin is empty, and by the way, it's nice to have a feature to setup header manually if content is from stdin to easier identify where the output comes from

thanks.

@marslo marslo added the feature-request New feature or request label Mar 27, 2024
@eth-p
Copy link
Collaborator

eth-p commented Mar 30, 2024

I think having an extra opt-in command line flag to disable printing the header for binary and/or empty files would be fine. It would be especially useful when using bat in bash scripts, like with what you're doing here.

It's nice to have a feature to setup header manually if content is from stdin to easier identify where the output comes from

The --file-name option may be helpful here. It's even used to detect the language type :)

image


For your specific example of finding TODOs in source code files, ripgrep might be a more performant approach compared to fd+sed:

rg --vimgrep --with-filename 'TODO' | cut -d':' -f1 | uniq | xargs bat

There's also batgrep if you want a bit more of a tailored experience:

image


@marslo
Copy link
Author

marslo commented Apr 16, 2024

Hi @eth-p ,

for me, it's just show ALL contents of files contains TODO, for my understanding:

  • rg --vimgrep --with-filename 'TODO' | cut -d':' -f1 | uniq: list all filepath contains TODO
  • xargs bat: bat all contents

using sed -ne '/TODO:/,/^\s*$/p', means print lines between TODO line to first empty line ^\s*$, since almost of all TODO is added before function, so using sed will show whole function body

base on your example, following commands resolved STDIN <EMPTY> issue:

rg --vimgrep --with-filename 'TODO' --color never |
   cut -d':' -f1 |
   uniq |
   xargs -r -I{} bash -c "sed -ne '/TODO:/,/^\s*$/p' {} |
   bat -l groovy"

However, it still didn't show the exact file name... i.e.:

TODO

here is my batconfig

$ cat ~/.config/bat/config | sed -r '/^(#.*)$/d' | sed -r '/^\s*$/d'
--theme="gruvbox-dark"
--style="numbers,changes,header"
--italic-text=always
--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse"
--map-syntax "*.ino:C++"
--map-syntax ".ignore:Git Ignore"
--map-syntax='*.conf:INI'
--map-syntax='/etc/apache2/**/*.conf:Apache Conf'
--map-syntax "**/jenkinsfile/**/*:Groovy"

more on sed && sed+bat:

TODO-with-sed

@eth-p
Copy link
Collaborator

eth-p commented Apr 17, 2024

Hi @marslo

Your understanding of both of those is correct, yes.

For your issue with bat displaying the file name as "STDIN", you can use the --file-name argument in bat to have it change the name in the header. Let me know if the modified code below works for you:

rg --vimgrep --with-filename 'TODO' --color never |
   cut -d':' -f1 |
   uniq |
   xargs -r -I{} bash -c "sed -ne '/TODO:/,/^\s*$/p' {} |
   bat -l groovy --file-name='{}'"

@marslo
Copy link
Author

marslo commented May 2, 2024

ops... forgot to let you know, your solution works like charm, you can close this issue.
thanks again.

image

marslo added a commit to marslo/dotfiles that referenced this issue May 2, 2024
marslo added a commit to marslo/dotfiles that referenced this issue May 2, 2024
@marslo
Copy link
Author

marslo commented May 2, 2024

btw to show the correct line number in the file, it can be handled by nl {} and without -l groovy to let bat automatic use:

rg --vimgrep --with-filename 'TODO:' --color never |
   cut -d':' -f1 |
   uniq |
   xargs -r -I{} bash -c "sed -ne '/TODO:/,/^\s*$/p' < <(nl {}) |
   bat --style="grid,changes,header" --file-name='{}'"

Since we haven lot of files/dotfiles has not extension, so, to identify the language automatically, I'm using the following function ( a little bit ugly, but I don't how to handle via complex shell logic in xargs, so using while read instead of ):

function showTODO() {
  local option='--style="grid,changes,header"'
  while [[ $# -gt 0 ]]; do
    case "$1" in
         -p | --plain ) option+=" $1"    ; shift 1 ;;
                   -* ) option+=" $1 $2" ; shift 2 ;;
    esac
  done

  rg --vimgrep --with-filename 'TODO:' --color never |
     cut -d':' -f1 |
     uniq |
     while read -r _file; do
       # identify language automatically
       local lang='';
       lang="$(sed -r 's/^.+\.(.+)$/\1/' <<< "${_file}")";
       if ! bat --list-languages | command grep -iE -q "[,:]${lang}|${lang},"; then
         # check shebang and reset to empty if shebang not found
         lang=$(sed -rn 's/^#!.*[/\ ](\w+)$/\1/p' < <(head -n1 "${_file}"));
       fi
       sed -ne '/TODO:/,/^\s*$/p' < <(nl "${_file}") |
           eval "bat -l ${lang:-groovy} ${option} --file-name=\"${_file}\"" ;
     done

if bat can detect filetype via shebang line ( i.e.: #!/usr/bin/env bash or #!/bin/bash, via ^#!.*[/\ ](\w+)$), then the simple version will be the best answer.

Screenshot 2024-05-02 at 16 36 43

btw, just curious why bat will using _fzf_path_completion as completion function by default.

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

No branches or pull requests

2 participants