Skip to content

Persistent command sometimes breaks the command line when hiding the panels #4809

@egmontkob

Description

@egmontkob

Is there an existing issue for this?

  • I have searched the existing issues

Midnight Commander version and build configuration

current git

Operating system

Linux

Is this issue reproducible using the latest version of Midnight Commander?

  • I confirm the issue is still reproducible with the latest version of Midnight Commander

How to reproduce

Stress-test the persistent command feature. Keep typing letters and frequently (after every letter or two) press Ctrl-O to alternatingly hide and show the panels.

When hiding the panels, the command line sometimes shows the desired value twice. More precisely: Let's say the panels are off, the command line is abcd. Turn on the panels. Type e. Turn off the panels. The command line shows abcdabcde, i.e. the part that was already there when showing the panels is duplicated.

Reproducible with fish quite frequently, with bash a little bit less frequently (about 1 out of 10 for me).

It's a visual corruption, not a data corruption. If you press Enter, the shell executes abcde, i.e. the value that should be on the screen, rather than what actually is shown.


Suspected reason:

When turning on the panels, with the terminal still being on the normal screen, read_command_line_buffer() queries the buffer's contents. Then it instructs the shell to wipe out its buffer: emits Ctrl-E followed by Ctrl-U (in zsh only the latter).

The caller of this method, feed_subshell() then does one round of flush_subshell (0, VISIBLY), i.e. forwards to the host terminal whatever the subshell sent. But this is racy. At some point (in this case: it seems to me that after just one read attempt) mc has to switch to the alternate screen, at which point it can no longer receive data from the shell and update the normal screen's contents.

There's no synchronization here, we can't tell when the shell will finish updating its command line. I think the problem is simply that the shell's response to the Ctrl-E and Ctrl-U keypresses arrive too late, mc no longer processes them.

The other direction (hiding the panels) is safe: we feed the new command line to the shell and it has arbitrarily long time to visually update it.


Solution ideas:

(bad) While the panels are shown, make sure not to read anything from the shell, let alone discard it. Whatever the shell printed can stay there in the buffer for a long time, wait patiently until the panels are hidden again. Then send them to the shell. Problem: if the user resizes the window, the instructions to remove the command might very easily not work properly.

(bad) Even when on the alternate screen, keep reading data from the shell but store them in memory. Hardly different from the previous idea, with the same drawback at sigwinch.

(ugly) Keep reading data from the shell. If something arrives, switch back to the normal screen, print that data, switch back to the alternate screen. The problem is that even if we're smart to do it in a single write(), some terminals might flicker.

(good) Defer clearing the command line (sending the Ctrl-E Ctrl-U) until the panels are hidden again.

(good) Do a round of synchronization, in the same manner as the ESC _ and ESC + keystrokes (we can even reuse one of them to keep things simple): when the response arrives over its dedicated pipe we can be sure that a round of reading the tty line will give us the complete update.

Expected behavior

Properly shown command line

Actual behavior

Sometimes garbled command line

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreIssues not related to a specific subsystemprio: mediumHas the potential to affect progress

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions