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

Terminal not reset correctly when executing a shell command from autocmd #3692

Open
barlik opened this issue Dec 15, 2018 · 7 comments
Open

Comments

@barlik
Copy link

barlik commented Dec 15, 2018

I'm trying to use ranger as a replacement for builtin netrw explorer. Here's a code to do so:

function! Ranger()
        exec '!ranger'
endfunction
command! -bar Ranger call Ranger()

augroup ranger
    au!
    au VimEnter * sil! au! FileExplorer *
    au BufEnter * if isdirectory(expand('%')) | bd | exe 'Ranger' | endif
augroup END

My terminal emulator of choice is urxvt.
Contrary to some other terminal emulators, urxvt uses different keycodes for arrow-keys in Application Cursor Keys (DECCKM) mode (ESC [ ?1h). When the DECCKM mode is, arrow keys stop working in applications like ranger.

When executing :!ranger command directly from the normal mode, the terminal is properly reset to normal cursor mode and the arrow keys work as expected. However, when :!ranger command is triggered using the above snippet, the terminal is not longer reset correctly to Normal mode (\ESC ?1l), but stays in Application Cursor Mode (I guess, the default mode for vim), and that causes the arrow keys to stop working.

@brammool
Copy link
Contributor

brammool commented Dec 15, 2018 via email

@barlik
Copy link
Author

barlik commented Dec 15, 2018

I've tried simplifying it to barebones, but it still happens. The only line in my vimrc:

au BufEnter * !ranger

Still no luck. However, I'm able to get the arrow keys working by resetting cursor mode before running the command:

au BufEnter * !echo "\e[?1l"; ranger

I've also tried a few different autocmd types, but it happens with all of them. My guess is that autocmd use a different code path than regular :! commands or that terminal reset in only applied based on some condition, which is not met in this case.

@barlik
Copy link
Author

barlik commented Dec 15, 2018

Looking at the code, I think that the culprit is this:
ex_cmds.c:1568

    /*
     * For autocommands we want to get the output on the current screen, to
     * avoid having to type return below.
     */

    if (!autocmd_busy)
    {
...
	    stoptermcap();
    }

so when auto commands are active stoptermcap(), a function that sends KS_KE code, is never called.

@brammool
Copy link
Contributor

brammool commented Dec 15, 2018 via email

@barlik
Copy link
Author

barlik commented Dec 16, 2018

Yes, that's one way to fix the problem.

Alternatively, we could send the T_KS and T_KE unconditionally. That wouldn't require any new 'interactive' flag and would keep the backwards compatibility.

Something like:

diff --git i/src/ex_cmds.c w/src/ex_cmds.c
index cd243a5ef..10adb288d 100644
--- i/src/ex_cmds.c
+++ w/src/ex_cmds.c
@@ -1572,6 +1572,12 @@ do_shell(
 #endif
 	    stoptermcap();
     }
+    else
+    {
+	/* reset keypad mode in case we run interactive commands */
+	out_str(T_KE);
+	out_flush();
+    }
 #ifdef MSWIN
     if (!winstart)
 #endif
@@ -1617,6 +1623,9 @@ do_shell(
     {
 	if (msg_silent == 0)
 	    redraw_later_clear();
+	/* restore keypad mode in case we run interactive commands */
+	out_str(T_KS);
+	out_flush();
     }
     else
     {
diff --git i/src/globals.h w/src/globals.h
index 131c13be9..561bc87dd 100644

Note: this is just a sample patch, we probably want to reset bracketed mode and maybe some other things as well. Point being, apart from changing the termcap mode any other control characters shouldn't really affect non-interactive commands.

@brammool
Copy link
Contributor

brammool commented Dec 16, 2018 via email

@barlik
Copy link
Author

barlik commented Dec 16, 2018

This won't always work, because T_KE can also contain an escape sequence to switch screens, or anything else. One can't assume the termcap entries are used as they were originally intended.

Do you mean terminals that do not follow the spec or people redefining T_KE entry?

I guess to solve my problem, I can just echo the T_KE myself before running the application.

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

No branches or pull requests

2 participants