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

Spinner breaks on multiline message #43

Open
d4rky-pl opened this issue Oct 4, 2020 · 6 comments
Open

Spinner breaks on multiline message #43

d4rky-pl opened this issue Oct 4, 2020 · 6 comments

Comments

@d4rky-pl
Copy link

d4rky-pl commented Oct 4, 2020

Describe the problem

Right now tty-spinner does not support multiline messages so this code will result in the spinner continuously outputting to the terminal:

require 'tty-spinner'
spinner = TTY::Spinner.new("abc\ndef")
spinner.run do
  sleep 5
end

It would be great if the spinner was smart enough to check the number of the lines of the message and moved the cursor accordingly when cleaning.

An example use case for this would be to keep the output of the command from tty-command on the screen without making it into an output salad:

require 'tty-spinner'
require 'tty-command'

spinner = TTY::Spinner.new("Running command\n:output")

cmd = TTY::Command.new
cmd.run("yarn") do |out, err|
  buffer << out if out
  buffer << err if err
  spinner.update(output: buffer)
end
@piotrmurach
Copy link
Owner

Hi Michał 👋

Thanks for the issue report, and of course, big thank you for the sponsorship! ❤️

Supporting multiline content sounds good but there is a bit 'trickiness' involved in how the multi spinner works. I should have some time to investigate next week unless you have time to submit PR in the meantime?

I wonder if your use case wouldn't be better served by adding new api for logging as suggested in this issue. Any thoughts?

@d4rky-pl
Copy link
Author

d4rky-pl commented Oct 11, 2020

I tried looking into this and implementing this myself but I didn't manage to get far which is why I ultimately reported this as an issue. I'm not sure if I'll find time soon to look into this again but if I do I'll definitely send a PR :)

And yeah, I totally think the API for logging would solve my issue as well.

@piotrmurach
Copy link
Owner

There is a new log method in the master branch that handles printing multiline content above a spinner animation. Please give it a try. I changed your example to use this method. The notable change is that the TTY::Command instance doesn't log any output by providing :null printer. The logging in tty-command runs in a separate thread and would mingle with the spinner output. I also added auto_spin call to ensure animation during yarn install with a small delay.

require "tty-spinner"
require "tty-command"

spinner = TTY::Spinner.new("[:spinner] Running :cmd command", format: :bouncing_ball)
cmd = TTY::Command.new(printer: :null)

spinner.auto_spin
spinner.update(cmd: "yarn")

cmd.run("yarn") do |out, err|
  buffer = []
  buffer << out if out
  buffer << err if err
  spinner.log(buffer.join)
  sleep(0.5)
end

spinner.stop("Done")

@d4rky-pl
Copy link
Author

d4rky-pl commented Nov 3, 2020

@piotrmurach for starters - apologies for such a long delay in responding, I had so many other things that I had to implement into our CLI tool that I didn't get around to testing this.

Anyway - this sort of works, as in, it does output things properly for simple commands but it really hates cursor movement shell codes. If I just output the err as-is then it kind of works, just misses several lines. If I push it to the buffer and output the buffer like you proposed then it results in the same lines showing up multiple times.

Here's a simple repro repository: https://github.com/d4rky-pl/tty-spinner-log-test

My use-case here is a tool that wraps docker and docker-compose and sets up our local development environment and I wanted to output whatever the tools setting up things are doing. Unfortunately my knowledge of shell magic is painfully lacking so I'm afraid I have no idea if this an be resolved anyhow or if I should just strip the codes and deduplicate lines manually (or just drop the idea altogether and make --verbose` flag disable the spinner).

@piotrmurach
Copy link
Owner

@d4rky-pl This is well overdue! In future please ping me if you don't hear from me.

I looked into your docker-compose example. The output from docker-compose produces a lot of escape codes that, for example, move the cursor up and down the terminal to update output in place similar to TTY::Spinner::Multi. Any extra character such as a newline will throw the output off and make it look broken.

Now, the spinner log method is rather simple so I was rather surprised for it to not work correctly and mingle the output. The culprit turns out to be this line

write("#{cleared_text}#{"\n" unless cleared_text.end_with?("\n")}", false)

In particular, the bit that adds a new line when it's missing. So when I replaced the above with:

write(cleared_text, false)

and removed the buffering from your example,

cmd.run("docker-compose up") do |out, err|
  spinner.log(out) if out
  spinner.log(err) if err
end

the output from the docker-compose was correct.

Why the log method didn't work with the new line appending? As it turns out docker-compose adds, for better or worse, escape codes after the newline.

So given the above how should the log method work?

  • Should it require the user to add a newline themselves?
  • Should there be a keyword that disables the automatic addition of a new line?
  • Should there be a keyword that enables the automatic addition of a new line?
  • Any other ideas?

@capripot
Copy link

capripot commented Oct 7, 2022

Probably most of users will appreciate having a new line added automatically.

I think best option is an option that would disable new line: trailing_newline: false. Option is true by default.

cmd.run("docker-compose up") do |out, err|
  spinner.log(out, trailing_newline: false) if out
  spinner.log(err, trailing_newline: false) if err
end

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

No branches or pull requests

3 participants