RepoSense icon indicating copy to clipboard operation
RepoSense copied to clipboard

Restricting command line output to one line

Open eugenepeh opened this issue 5 years ago • 12 comments

The console output too much messages; making it difficult to differentiate important messages.

Hence, we should restrict the status message from occupying too many lines on the terminal screen, making it self contained in a single line by overwriting itself.

eugenepeh avatar May 24 '19 08:05 eugenepeh

I don't know if there's a way to overwrite the same line using logging.. AFAIK, there's no way to overwrite to same line using logging

jinyao-lee avatar May 29 '19 04:05 jinyao-lee

The logging can be reimplemented if such feature does not exist; can even write our own API too if we have to as it also provides us with greater control.

eugenepeh avatar May 29 '19 10:05 eugenepeh

Alternatively, we can try to format the output such that important messages are hard to miss. Overwriting has the downside that we lose the ability to see the sequence of events that happened before.

damithc avatar May 29 '19 10:05 damithc

Alternatively, we can try to format the output such that important messages are hard to miss.

The intention is to make it less important message to take up less space though. E.g. if we use RepoSense to analyze 50+ repos, its going to flood the CLI with bunch of messages, which can be tedious to scroll through all of them for the error messages.

So my suggestion is to have the info messages to always overwrite itself, leaving the error messages right on top of it.

E.g.

[ERROR] ...
[ERROR] ...
[INFO] ... this should always takes up only one line which inform user purely about the progress ...

If the following line is going to be another error message, delete the last [INFO] line, output the new [ERROR] message, then prints the next [INFO] line again.

Overwriting has the downside that we lose the ability to see the sequence of events that happened before.

If the user wants to keep all the messages, we can add in a verbose flag afterward to disable the overwriting. Otherwise, the log file would've contain all the necessary info in chronological order as well, in the event we need to debug the error that has occurred.

eugenepeh avatar May 29 '19 14:05 eugenepeh

I came up with something like this:

terminal_v3

Specifically, I did this in CustomLogFormatter#format, that is used by the console handler:

if (record.getLevel().equals(Level.INFO)) {
    builder.append("\r");
    builder.append("\u001b[1000D");
    builder.append("\u001b[K");
    builder.append(dateFormat.format(new Date(record.getMillis()))).append(" - ");
    builder.append(formatMessage(record))
} else {    // Level.WARNING and higher
    builder.append("\r");
    builder.append(dateFormat.format(new Date(record.getMillis()))).append(" - ");
    builder.append("\u001b[37;43m");
    builder.append("[ERROR]");
    builder.append("\u001b[0m");
    builder.append(" ");
    builder.append(formatMessage(record));
    builder.append("\n");
}

However, it is highly dependent on the width of the terminal because of using \r and \u001b[K to clear one line of printed output on the console for Level.INFO messages (and then print a new message in the same line). For smaller widths, I couldn't achieve the desired effect.

Also, there doesn't seem to be a platform-independent way to determine the width of the terminal in Java unless we want to include libraries (https://stackoverflow.com/questions/1286461/can-i-find-the-console-width-with-java). Finding the width would help to determine the number of lines a message occupies in the terminal.

Are there other ways of making Level.INFO messages (that may span multiple lines) overwrite each other?

bluein-green avatar Jul 02 '19 09:07 bluein-green

However, it is highly dependent on the width of the terminal because of using \r and \u001b[K to clear one line of printed output on the console for Level.INFO messages (and then print a new message in the same line). For smaller widths, I couldn't achieve the desired effect.

For the width problem is it that if the newly printed line is shorter than the existing one, non-overwritten chars from previous line will remain?

eugenepeh avatar Jul 03 '19 14:07 eugenepeh

No - if all messages are short enough to fit in 1 line in the terminal, we can use the escape sequence \u001b[K to clear that line before printing a new, shorter message.

The issue is when some messages are long and occupy multiple lines in the terminal due to line wrapping.

Suppose a long message occupies 2 lines on the terminal due to line wrapping. The cursor will be at the 2nd line. Using \r and \u001b[K at the start of the next message results in the 2nd line being cleared, and that new message being printed in that line.

An example: terminal_example

bluein-green avatar Jul 04 '19 03:07 bluein-green

Hmm, maybe in that case, we could probably make our own print class?

Whenever a call is made to the print function, we will record the length of the text that will be printed. With that info, when we're going to overwrite the previous line, we can backspace that amount of time.

eugenepeh avatar Jul 04 '19 14:07 eugenepeh

Yes that would help with recording the number of lines the old message occupied.

To calculate the number of lines (length of message / width of terminal), we will need the width of terminal. However, this is rather difficult to determine unless we include a library (e.g. jline). I'm not sure about the impact of including the library on performance. Would it be advisable to do so?

bluein-green avatar Jul 05 '19 09:07 bluein-green

If we do the backspace way, we wouldn't need to know the width of the terminal anymore, isnt it? At the same time, this will resolve the difference between different platform too.

eugenepeh avatar Jul 05 '19 17:07 eugenepeh

Ah. Using backspace (\b) worked only for single line messages. For multi-line messages, backspaces only moves the cursor to the left margin, and thus the non-last lines will not get overwritten.

I also tried using saving/restoring the cursor position:

  1. Save position
  2. Clear rest of screen (cursor position and below)
  3. Print
  4. Restore position

but it doesn't work when the messages reach the bottom of the terminal and the terminal has to scroll.

bluein-green avatar Jul 10 '19 03:07 bluein-green

Ah. Using backspace (\b) worked only for single line messages. For multi-line messages, backspaces only moves the cursor to the left margin, and thus the non-last lines will not get overwritten.

I guess this is also cause of the problem with your original solution; it does not have any concept of lines of text. In that case, we may have to restrict non-error messages to fit into single lines.

eugenepeh avatar Jul 10 '19 10:07 eugenepeh