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

[BUG] pipe bc make the content dissapear #4559

Closed
CharlesGueunet opened this issue Feb 21, 2022 · 9 comments
Closed

[BUG] pipe bc make the content dissapear #4559

CharlesGueunet opened this issue Feb 21, 2022 · 9 comments
Labels

Comments

@CharlesGueunet
Copy link
Contributor

CharlesGueunet commented Feb 21, 2022

Version of Kakoune

commit e04a14c Date: Wed Feb 16 07:55:56 2022 +1100

Reproducer

Pipe any valid selection to bc:

kak -n
3o           // 3 new lines
<c-r>#    // insert numeric value
-1           // add calculus
<esc>h<i-w> // select each calculus
|bc<cr>          // call bc

This should call bc on three selections: 1-1, 2-1 and 3-1

Outcome

Expected:

0
1
2

Expectations

Result in removed selection instead.

Additional information

The bug also occurs when a single selection is made.
OS: Arch linux

@alexherbo2
Copy link
Contributor

Hello Charles,

It is due to #3669.

Kakoune no longer adds newline to the input when piping.

The bc program expects its input to end with a newline. However—and surprisingly—it does not exit with error in this case.

printf 1+1 | bc
# (standard_in) 1: parse error ⇐ however exit status is 0

In Kakoune, you now have to add the newline yourself with the following pattern:

{ cat; echo; }

For your convenience, you can add the following shortcuts to your kakrc:

map -docstring 'increment selection' global normal <c-a> ': increment-selection %val{count}<ret>'
map -docstring 'decrement selection' global normal <c-x> ': decrement-selection %val{count}<ret>'

define-command -override increment-selection -params 1 -docstring 'increment-selection <count>: increment selection by count' %{
  execute-keys "a+%sh{expr $1 '|' 1}<esc>|{ cat; echo; } | bc<ret>"
}

define-command -override decrement-selection -params 1 -docstring 'decrement-selection <count>: decrement selection by count' %{
  execute-keys "a-%sh{expr $1 '|' 1}<esc>|{ cat; echo; } | bc<ret>"
}

@CharlesGueunet
Copy link
Contributor Author

Hoo thank you, you are right.

For posterity, if we press L after selecting each expression to include the new line, things are working again.
This is a bit less convenient for my usage, but I suppose this change allow for some other tools to works as expected :)

Thank @alexherbo2 , this issue is solved then !

@mawww
Copy link
Owner

mawww commented Feb 22, 2022

bc is the reason hesitated so long to do this change, this is what the POSIX standard mandates (commands must end if an EOL, EOF is not good enough). In the end, we can workaround bc's pedantic behaviour, but we could not easily know if the last eol in the piped content was added by Kakoune or was part of the initial selection.

@CharlesGueunet
Copy link
Contributor Author

Thanks for this explanation, and I see for the mentioned issue the case where this newline lead to wrong result, so it make sense for kakoune to omit it.

Cheers.

@arrufat
Copy link
Contributor

arrufat commented Aug 27, 2022

Hi, I am trying to make this work in the example from the Wiki:

define-command -hidden -params 2 inc %{
  evaluate-commands %sh{
    if [ "$1" = 0 ]
    then
	count=1
    else
	count="$1"
    fi
    # old
    # printf '%s%s\n' 'exec h"_/\d<ret><a-i>na' "$2($count)<esc>|bc<ret>h"
    # new: doesn't work yet
    printf '%s%s' 'exec h"_/\d<ret><a-i>na' "$2($count)<esc>|{ cat\; echo\; }|bc<ret>h"
  }
}
map global normal <c-a> ':inc %val{count} +<ret>'
map global normal <c-x> ':inc %val{count} -<ret>'

Is there a way to make it work here? I've been trying several ways, but it always ends up in removing the number.

EDIT:
I also tried with printf '%s%s' 'exec h"_/\d<ret><a-i>na' "$2($count)<esc>|qalc -n -t -f -<ret>h" and doesn't work… However, it works in the shell:

printf 1+1 | qalc -n -t -f -

I might be doing something wrong.

@arrufat
Copy link
Contributor

arrufat commented Sep 1, 2022

I think one of the problems might be that I need to escape the braces, so I tried this... Now it behaves differently: it does nothing instead of erasing the number.

printf '%s%s' %[ 'exec h"_/\d<ret><a-i>na' "$2($count)<esc>|{ cat\; echo\; }|bc<ret>h" ]

Any help is apprecied.

@krobelus
Copy link
Contributor

krobelus commented Sep 1, 2022

If I try your <c-a> I get this message in the debug buffer

sh: 1: Syntax error: "}" unexpected

braces for grouping are only valid in specific positions.
I think } is only valid after a newline.
One workaround is to use a subshell instead:

( cat\; echo )

Another workaround is to add a newline to the commandline

{ cat\; echo<c-q><ret>}

for whatever reason this doesn't work but you can use set-register:

set-register | %{
	{
		cat; echo
	} | bc
}
execute-keys |<ret>

@arrufat
Copy link
Contributor

arrufat commented Sep 1, 2022

@krobelus thank you! I somehow forgot to check the debug buffer 😅...
This is the final version that works for me, using the subshell:

# simulate <c-a> and <c-x> to increment/decrement the number under the cursor
define-command -hidden -params 2 inc %{ try %{
    evaluate-commands %sh{
        if [ "$1" = 0 ]
        then
            count=1
        else
            count="$1"
        fi
        printf '%s%s' 'exec h"_/\d<ret><a-i>na' "$2($count)<esc>|( cat\; echo )|bc<ret>"
    }
} catch %{
    # Prevent the cursor from moving left if no number is found
    execute-keys l
}}
map global normal <c-a> ':inc %val{count} +<ret>'
map global normal <c-x> ':inc %val{count} -<ret>'

Maybe, after the new release, we need to update the related bc wiki page.

@arrufat
Copy link
Contributor

arrufat commented Dec 6, 2022

Hi, sorry for bumping this again, I figured out why it was not working: we can't use spaces and semicolons when we're not using a subshell. The final command, without a subshell looks like this:

define-command -hidden -params 2 inc %{ try %{
    evaluate-commands %sh{
        [ "$1" = 0 ] && count=1 || count="$1"
        printf '%s%s' 'exec h"_/\d<ret><a-i>na' "$2($count)<esc>|{<space>cat<semicolon>echo<semicolon>}|bc<ret>"
    }
} catch %{
    execute-keys l
}}
map global normal <c-a> ': inc %val{count} +<ret>'
map global normal <c-x> ': inc %val{count} -<ret>'

I will be able to sleep at night better now.

I've also updated it in the bc wiki.

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

No branches or pull requests

5 participants