cyrus-and / gdb-dashboard

Modular visual interface for GDB in Python
MIT License
11k stars 768 forks source link

(feature request) Output/messages #180

Open Falkgaard opened 4 years ago

Falkgaard commented 4 years ago

Hi, I love the extension -- keep up the awesome work!

A couple thoughts: Is it possible to make the "Output/messages" into a module that can be customized? In particular, the possibility of the pre-allocating N lines for output (akin to height in assembly and source) as well as the option of scrolling it (again, akin to assembly and source) would be great since it can be quite distracting if the line count changes during stepping (since it will push the rest ouf the dashboard up or down). Being able to redirect the "Output/messages" to a separate TTY would work as well. In that case I can just make a separate tmux pane that I can resize and scroll, so for me that would solve my other issue as well.

P.S. If either of these things are possible already and I've somehow missed them I apologize in advance! D.S.

Falkgaard commented 4 years ago

Also, a similar request; would it be possible to assign fixed widths to columns? The place where it's the biggest strain is in the assembly dashboard, especially with opcodes enabled since they can vary a lot in width between steps, pushing the other columns back and forth sideways.

Regards, -Falkgaard

cyrus-and commented 4 years ago

Hi, I love the extension -- keep up the awesome work!

Thanks, will do! :)

Is it possible to make the "Output/messages" into a module that can be customized?

Sadly no, see #59 for the reason why. What you can do instead is to use a separate terminal for the dashboard.

Also, a similar request; would it be possible to assign fixed widths to columns?

In what other places do you believe this is necessary? Using fixed columns for the opcodes basically means to potentially trim some of them, what's the use of having partial opcodes?

Falkgaard commented 4 years ago

I see, that's a shame. Thanks for the speedy reply!

In what other places do you believe this is necessary? Using fixed columns for the opcodes basically means to potentially trim some of them, what's the use of having partial opcodes?

Well, I was thinking of setting the width of the columns to the maximum potential widths, since I generally have columns to spare in that module... another option would be to move the column to the furthest right so that the variance in the width can't affect any of the neighbouring columns (assuming it doesn't linebreak). But then again, I rarely need it so I could just turn it off, but it could be nice to be able to assign some fixed widths for columns when applicable.

Maybe have a format string for an assemble line or something? If not, it's not the end of the world :)

Happy New Year!

Regards, -Falkgaard

cyrus-and commented 4 years ago

This is somewhat related to #178, yet in the other dimension. I'll think about it, thanks for the suggestion.

Happy New Year!

All the best!

karlp commented 3 years ago

I take it #59 is also why we can't scroll back up and see earlier output? Even just not clearing the screen so i could use my terminal scroll buffer?

cyrus-and commented 3 years ago

@karlp You should be able to scroll up, but by default the scroll back buffer is discarded at each redraw so to only show one dashboard unless the discard_scrollback option is set to False:

>>> help dashboard -style discard_scrollback
Discard the scrollback buffer at each redraw.

This makes scrolling less confusing by discarding the previously printed
dashboards but only works with certain terminals.
karlp commented 3 years ago

Thanks, that works!

PovelikinRostislav commented 1 year ago

Hi, @cyrus-and, your project is amazing! I found it very useful for my debugs.

In this thread you mentioned that scrollback can be activated, I use it and I am curious if we can keep the layout of output by calling clear (I assume CTRL+L is equal to this) before making new output?

In this case, it will not dump the previous output (so we can scroll back) and put the new output at the top of the screen

What do you think?

cyrus-and commented 1 year ago

Hi, @cyrus-and, your project is amazing! I found it very useful for my debugs.

Hi @PovelikinRostislav, glad to hear that!

In this thread you mentioned that scrollback can be activated, I use it and I am curious if we can keep the layout of output by calling clear (I assume CTRL+L is equal to this) before making new output?

In this case, it will not dump the previous output (so we can scroll back) and put the new output at the top of the screen

What do you think?

Hmm, what do you mean? Can you clarify a bit?

PovelikinRostislav commented 1 year ago

Sure, let me try to clarify.

If we set up discard_scrollback = False, then we have two main observable effects:

This last bullet is kind of reverses the layout - new output now is observed at the bottom part of the screen.

At the same time, I noticed that with discard_scrollback = False setting I can press CTRL+L and the gdb/dashboard (not terminal, because I checked, it is not terminal-wise shortcut) scrolls all the previous output above the current screen.

If the dashboard can redraw the current state, calling before it the same cmd as CTRL+L, then we can achieve two observable effects:

I hope it clarifies my thoughts

cyrus-and commented 1 year ago

Hmm, when discard_scrollback = False, there is no cleanup of the terminal's scrollback buffer, this means that if the dashboard is displayed n times, you'll have:

DASHBOARD_1
DASHBOARD_2
[...]
DASHBOARD_n

All this is scrollable, according to your terminal and that's the natural order. I do nothing to reverse the layout. Likewise I do nothing to intercept CTRL+L, that's responsibility of GDB and ultimately of your terminal. What it usually does is to scroll the screen so that the prompt moves to the very top, the scrollback buffer is not cleared though, in fact you can scroll up to find it.

Also notice that the dashboard is not a curses application, the only way to redraw its status is to print another instance, thus causing another DASHBOARD_i in the above example.

PovelikinRostislav commented 1 year ago

Thanks for quick replies and detailed explanation. Sorry for confusion when I used "reverse" to describe the state. I meant it only in a logical way.

When discard_scrollback = True, we observe the new status at the top of the screen. When discard_scrollback = False, we observe the new status at the bottom of the screen. This behavior is totally natural, but it logically reverses the user experience.

If dashboard sends CTRL+L before every status update when discard_scrollback = False, we will be able to revise previous statuses and, at the same time, the new status will be shown at the top of the screen keeping the same user experience as when the scrollback is disabled.

PovelikinRostislav commented 1 year ago

Actually it all goes to the following changes:

   @staticmethod
    def clear_screen():
        # ANSI: move the cursor to top-left corner and discard the scrollback if set
        return '\x1b[H\x1b[J' + '\x1b[3J' if R.discard_scrollback else '\x1b[H\x1b[J'

What do you think of this?

cyrus-and commented 1 year ago

Oh I see what you mean, I guess we could simply put the parenthesis around the if:

return '\x1b[H\x1b[J' + ('\x1b[3J' if R.discard_scrollback else '')

Feel free to file a PR if you want.

PovelikinRostislav commented 1 year ago

Hey @cyrus-and, I used our change today and noticed that this sequence of symbols \x1b[H\x1b[J actually doesn't preserve the history (maybe on my terminal?). I am not familiar with the meaning of this sequence so I want to double check it, but do not know how - can you please help me to understand which docs you used as a base to choose this particular sequence? Also I am wondering what does CTRL+L actually send, but I am not sure of how to track it. It should be terminal-wise, if I understand correctly

To showcase the incorrect behavior, here are two screenshots of the case with '\x1b[H\x1b[J' + ('\x1b[3J' if R.discard_scrollback else '') and discard_scrollback False.

  1. start of the program, first status first_status
  2. next, second status and scrollback with mouse. We can see that previous status is gone (in other experiments it might be even some trash from previous runs) second_status_scrollbacked

In comparison, what we see after the next with discard_scrollback False if we revert the PR. History is preserved and no corruptions. In this case we are not sending '\x1b[H\x1b[J' both_statuses_without_discarded_scrollback

Also I made some experiments to send the clear as it is described in the man clear using '\033[2J':

return '\033[2J' + ('\x1b[3J' if R.discard_scrollback else '')

The result is way different and still not what we want. It clears the screen, but cursor is kept on the bottom. Thus, when we print new status - it produces one empty screen after the previous. In this case the history becomes with big holes between statuses

Here are the sample screenshots:

  1. start of the program, first status first_status_clear
  2. next, second status second_status_clear
  3. Zoom out from second status to see the gap between 1st and 2nd statuses second_status_scrollbacked_clear
cyrus-and commented 1 year ago

Hey @cyrus-and, I used our change today and noticed that this sequence of symbols \x1b[H\x1b[J actually doesn't preserve the history (maybe on my terminal?).

Right, it doesn't work as intended... I think I fixed it in 0a5335de84d0221ae4631cfe885d2fc730a44b40. What do you think?

I am not familiar with the meaning of this sequence so I want to double check it, but do not know how - can you please help me to understand which docs you used as a base to choose this particular sequence?

These are ANSI sequences, read more here.

Also you can inspect what clear does with:

$ clear | od -a
0000000  esc   [   H esc   [   2   J
0000007

Also I am wondering what does CTRL+L actually send, but I am not sure of how to track it. It should be terminal-wise, if I understand correctly

Instead CTRL+L is implemented in readline:

       clear-screen (C-l)
              Clear the screen, then redraw the current line, leaving
              the current line at the top of the screen.  With an
              argument, refresh the current line without clearing the
PovelikinRostislav commented 1 year ago

Nice, I like it.

Thank you a lot for your time, explanation and the links!