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

unattended forced auto scrolling upward in Vim v8.2 #9236

Open
egberts opened this issue Nov 28, 2021 · 8 comments
Open

unattended forced auto scrolling upward in Vim v8.2 #9236

egberts opened this issue Nov 28, 2021 · 8 comments

Comments

@egberts
Copy link

egberts commented Nov 28, 2021

Steps to reproduce

Very difficult to reproduce this VIM editor session

  1. vim /tmp/xxxx
  2. Enter INSERT mode (i)
  3. Insert in a couple more blank lines than what the terminal screen has (ENTERx28)
  4. exit INSERT mode (ESC)
  5. attempt to go to the bottom of the buffer using ANY known navigation keystroke for going toward the bottom of the buffer
  6. VIM editor will fight me by scrolling upward toward the top until the 1st line appears.

Feels like keyboard is stuck but this behavior does not show in earlier VIM 8.1 or v7s.

This bizzare behavior does not happen when executing vim -u NONE /tmp/xxxx but remains a normal edit session (that we all come to know of).

I did a strace of the command in question (blind man approach) to investigate WHICH file got opened for my default VIM editor session.

    strace -f /usr/bin/vim /tmp/xxxx >/tmp/vim.default.strace 2>&1

and with a bit of grep filtering, I get the following VIM files being opened for my default session:

/usr/share/vim/vim82# grep open /tmp/vim.default.strace | grep -v LC_ | grep -v x86_64 | grep -v "No such" | grep -v "Not a dir"     
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vimrc", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 4
openat(AT_FDCWD, "/usr/share/vim/vim82/debian.vim", O_RDONLY) = 4
openat(AT_FDCWD, "/etc/papersize", O_RDONLY|O_NONBLOCK) = 5
openat(AT_FDCWD, "/etc/papersize", O_RDONLY) = 5
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/defaults.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 4
openat(AT_FDCWD, "/usr/share/vim/vim82/filetype.vim", O_RDONLY) = 4
openat(AT_FDCWD, ".", O_RDONLY)         = 4
openat(AT_FDCWD, "/usr/share/vim/vim82/ftplugin.vim", O_RDONLY) = 4
openat(AT_FDCWD, ".", O_RDONLY)         = 4
openat(AT_FDCWD, "/usr/share/vim/vim82/indent.vim", O_RDONLY) = 4
openat(AT_FDCWD, ".", O_RDONLY)         = 4
openat(AT_FDCWD, "/usr/share/vim/vim82/syntax/syntax.vim", O_RDONLY) = 4
openat(AT_FDCWD, ".", O_RDONLY)         = 5
openat(AT_FDCWD, "/usr/share/vim/vim82/syntax/synload.vim", O_RDONLY) = 5
openat(AT_FDCWD, ".", O_RDONLY)         = 6
openat(AT_FDCWD, "/usr/share/vim/vim82/syntax/syncolor.vim", O_RDONLY) = 6
openat(AT_FDCWD, "/usr/share/vim/vim82/rgb.txt", O_RDONLY) = 7
openat(AT_FDCWD, "/usr/share/vim/vim82/pack/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/getscriptPlugin.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/gzip.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/logiPat.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/manpager.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/matchparen.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/netrwPlugin.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/rrhelper.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/spellfile.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/tarPlugin.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/tohtml.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/vimballPlugin.vim", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/plugin/zipPlugin.vim", O_RDONLY) = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/pack/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
openat(AT_FDCWD, "/home/wolfe/.viminfo", O_RDONLY) = 3
openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/xxxx", O_RDONLY) = 3
openat(AT_FDCWD, "/tmp/.xxxx.swp", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
openat(AT_FDCWD, "/tmp/.xxxx.swpx", O_RDWR|O_CREAT|O_EXCL, 0600) = 5
openat(AT_FDCWD, "/tmp/.xxxx.swp", O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = 4
openat(AT_FDCWD, "/tmp/xxxx", O_RDONLY) = 3
openat(AT_FDCWD, "/home/wolfe/.viminfo", O_RDONLY) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/usr/share/vim/vim82/scripts.vim", O_RDONLY) = 3
openat(AT_FDCWD, "/home/wolfe/.viminfo", O_RDONLY) = 3
openat(AT_FDCWD, "/home/wolfe/.viminfo.tmp", O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = 5

I removed the following entries for /strace -f usr/bin/vim -u NONE /tmp/xxxx:

/usr/share/vim/vim82# grep open /tmp/vim.NONE.strace | grep -v LC_ | grep -v x86_64 | grep -v "No such" | grep -v "Not a dir"
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, ".", O_RDONLY)         = 3
openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY) = 3
openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/xxxx", O_RDONLY) = 3
openat(AT_FDCWD, "/tmp/.xxxx.swp", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
openat(AT_FDCWD, "/tmp/.xxxx.swpx", O_RDWR|O_CREAT|O_EXCL, 0600) = 5
openat(AT_FDCWD, "/tmp/.xxxx.swp", O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = 4
openat(AT_FDCWD, "/tmp/xxxx", O_RDONLY) = 3

Then went to work on the first suspect /usr/share/vim/vim82/scripts.vim.

  1. cd /usr/share/vim/vim82
  2. mv scripts.vim scripts.vim.disabled
  3. vi /tmp/xxxx

IT WORKS! So ithere is something about this /usr/share/vim/vim82/scripts.vim that is forcing me into autoscroll.

Now, here comes the mysterious part:

I put the scripts.vim back in.

All is well.

No bug, everything is fine.

Most mysterious behavior EVAH!

Details:
Desktop: KDE Plasma
Terminal: KDE Console
$HOME bashrc: none
System bashrc: none
$HOME .vim: none

Expected behaviour

I expect the default editor session to remain stationary upon no keystroke; not to move the buffer to the first line all by itself.

Operating system

KDE Console/KDE Plasma/Linux 5.10.0-9-amd64 #1 SMP Debian 5.10.70-1 (2021-09-30) x86_64 GNU/Linux

Version of Vim

VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Mar 02 2021 02:58:09) Included patches: 1-2434

Logs and stack traces

VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Mar 02 2021 02:58:09)
Included patches: 1-2434
Modified by team+vim@tracker.debian.org
Compiled by team+vim@tracker.debian.org
Huge version without GUI.  Features included (+) or not (-):
+acl               -farsi             +mouse_sgr         +tag_binary
+arabic            +file_in_path      -mouse_sysmouse    -tag_old_static
+autocmd           +find_in_path      +mouse_urxvt       -tag_any_white
+autochdir         +float             +mouse_xterm       -tcl
-autoservername    +folding           +multi_byte        +termguicolors
-balloon_eval      -footer            +multi_lang        +terminal
+balloon_eval_term +fork()            -mzscheme          +terminfo
-browse            +gettext           +netbeans_intg     +termresponse
++builtin_terms    -hangul_input      +num64             +textobjects
+byte_offset       +iconv             +packages          +textprop
+channel           +insert_expand     +path_extra        +timers
+cindent           +ipv6              -perl              +title
-clientserver      +job               +persistent_undo   -toolbar
-clipboard         +jumplist          +popupwin          +user_commands
+cmdline_compl     +keymap            +postscript        +vartabs
+cmdline_hist      +lambda            +printer           +vertsplit
+cmdline_info      +langmap           +profile           +virtualedit
+comments          +libcall           -python            +visual
+conceal           +linebreak         -python3           +visualextra
+cryptv            +lispindent        +quickfix          +viminfo
+cscope            +listcmds          +reltime           +vreplace
+cursorbind        +localmap          +rightleft         +wildignore
+cursorshape       -lua               -ruby              +wildmenu
+dialog_con        +menu              +scrollbind        +windows
+diff              +mksession         +signs             +writebackup
+digraphs          +modify_fname      +smartindent       -X11
-dnd               +mouse             -sound             -xfontset
-ebcdic            -mouseshape        +spell             -xim
+emacs_tags        +mouse_dec         +startuptime       -xpm
+eval              +mouse_gpm         +statusline        -xsmp
+ex_extra          -mouse_jsbterm     -sun_workshop      -xterm_clipboard
+extra_search      +mouse_netterm     +syntax            -xterm_save
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -Wdate-time -g -O2 -ffile-prefix-map=/build/vim-wroKTq/vim-8.2.2434=. -fstack-protector-strong -Wformat -Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 
Linking: gcc -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -o vim -lm -ltinfo -lselinux -lacl -lattr -lgpm -ldl
@egberts
Copy link
Author

egberts commented Nov 28, 2021

Fixed in VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Oct 31 2021 15:40:05)
Included patches: 1-3565

by pulling in apt install -t testing vim while on a stable Debian 11.

closing this issue

@egberts egberts closed this as completed Nov 28, 2021
@egberts
Copy link
Author

egberts commented Dec 7, 2021

Ouch, lasted unstable Debian (bookworms) has this problem.

Not file name-specific, but file-content is triggering this.

And to disable it, I have narrowed it down to

/usr/share/vim/vim82/scripts.vim

Will continue to track this down as it is a sporadically occurring bug.

@egberts egberts reopened this Dec 7, 2021
@egberts egberts changed the title unattended forced auto scrolling upward in Debian bullseye vim unattended forced auto scrolling upward in Debian bullseye+bookworm vim Dec 7, 2021
@chrisbra
Copy link
Member

chrisbra commented Dec 7, 2021

check your terminal configuration, specifically $TERM and can you check, whether this happens in xterm?

@egberts
Copy link
Author

egberts commented Dec 7, 2021

check your terminal configuration, specifically $TERM and can you check, whether this happens in xterm?

KDE Console, at the moment. will revert to xterm next and therein.

And have a KDE keyboard event monitor up as well. Stay tune.

@lacygoill
Copy link

Insert in a couple more blank lines than what the terminal screen has (ENTERx28)
exit INSERT mode (ESC)
attempt to go to the bottom of the buffer using ANY known navigation keystroke for going toward the bottom of the buffer

If I press Enter 28 times while in insert mode then press Escape, I'm already at the end of the buffer. Are you at the end of the buffer when you execute a normal command which is documented to move to the bottom of the buffer?

So there is something about this /usr/share/vim/vim82/scripts.vim that is forcing me into autoscroll.

This file does not do much by itself. It's only meant to detect the filetype of a buffer when it can't be inferred from the extension in its name. But when the filetype is set, the FileType event is fired which might cause the filetype plugins, syntax plugins, and indent plugins to be sourced. It depends on what you can read when you run :filetype and :echo g:syntax_on:

:filetype
filetype detection:ON  plugin:ON  indent:ON

:echo g:syntax_on
1
  • ON after plugin: means that filetype plugins are sourced automatically when the filetype of a buffer is set
  • ON after indent: means that indent plugins are sourced automatically when the filetype of a buffer is set
  • g:syntax_on having the value 1, means that syntax plugins are sourced automatically when the filetype of a buffer is set

You can check which scripts have been sourced during the current Vim session with :help :scriptnames.

If possible, try to compare the output of :scriptnames before and after the issue starts. You can dump it in a buffer with:

:new | scriptnames

Or better yet, write it in a file, before the issue:

:call execute('scriptnames')->split('\n')->writefile('/tmp/vim.scriptnames1.log')

Then again, in a second file, after the issue:

:call execute('scriptnames')->split('\n')->writefile('/tmp/vim.scriptnames2.log')

Then, diff the 2 log files:

$ vimdiff /tmp/vim.scriptnames1.log /tmp/vim.scriptnames2.log

KDE Console, at the moment.

What is the output of echo $TERM in the shell? What is the output of :echo &term in Vim?

@lacygoill
Copy link

It's possible that the key that you press after Escape is joined with the latter and recognized as some other function key. If that's the issue, then this command might help:

:set timeout timeoutlen=3000 ttimeoutlen=100

You can find it at :help 'ttimeoutlen'.


You might also try to log the keys received by Vim:

:call ch_logfile('/tmp/logfile', 'w')

This requires the patch 7.4.1310.

You can follow the file with tail(1) in another terminal window:

$ tail -f /tmp/logfile

Inside this log, you want to look for all the lines matching the pattern "raw key input":

:vglobal/raw key input/delete _

Look for lines starting with a timestamp which matches a time after the issue has started to occur.
For each key that you press to move the cursor and which behaves unexpectedly, check out the raw key codes that Vim actually received. For example, here are 2 lines that I've copied and pasted here from a log obtained with ch_logfile():

19.147411 : raw key input: "^[OA"
57.163398 : raw key input: "^[OB"

They match respectively an <Up> keypress, and a <Down> keypress. Which is OK because that's how they're set in my termcap database:

:set <up>?
t_ku <Up>        ^[OA
                 ^--^
                  ✔

:set <down>?
t_kd <Down>      ^[OB
                 ^--^
                  ✔

If you can't reproduce the issue in xterm, it might mean that the issue is influenced by a terminal option. In that case, run this command in xterm (make sure you use a recent Vim version with the patch 8.2.3731):

:vim9 execute('set! termcap')->split('\n')->map((_, v) => v->substitute('^\s*\%(t_\|<\)\@=', 'set ', '')->substitute('set \zs\%(t_..\s\+\)\=\(<\S\+>\)\s\+', '\1=', '')->substitute('\^\[', "\<Esc>", 'g')->substitute('^---', '" ---', ''))->writefile('/tmp/termcap.OK.log')

Then run this other command in a terminal where you can reproduce the issue:

:vim9 execute('set! termcap')->split('\n')->map((_, v) => v->substitute('^\s*\%(t_\|<\)\@=', 'set ', '')->substitute('set \zs\%(t_..\s\+\)\=\(<\S\+>\)\s\+', '\1=', '')->substitute('\^\[', "\<Esc>", 'g')->substitute('^---', '" ---', ''))->writefile('/tmp/termcap.NOT.OK.log')

Now, diff the 2 logs:

$ vimdiff /tmp/termcap.OK.log /tmp/termcap.NOT.OK.log

And check out the differences.

To make the process easier, I have a script which can turn the output of :set! termcap into a machine-readable code (again you need the patch 8.2.3731).

Source it while Vim is running in xterm (or whatever terminal where you cannot reproduce the issue), and run the custom command that it installs: :DebugTermcap. It should write a script in /tmp/termcap.vim which restores all the terminal options with their current values.

Next, start Vim in a terminal where you can reproduce the issue, and source /tmp/termcap.vim. Confirm that the issue is fixed. If it's not, then there is no point going further. If it's fixed, all you have to do is to bisect /tmp/termcap.vim (i.e. comment out half of the script repeatedly) until you find the line(s) which actually does fix the issue.

If you're interested, here is the script installing :DebugTermcap:

vim9script noclear

const LOGFILE: string = '/tmp/termcap.vim'

command -bar -bang DebugTermcap DebugTermcap(<bang>0)

# Interface {{{1
def DebugTermcap(use_curfile: bool) #{{{2
    if use_curfile
        SetFt()
    else
        SplitWindow()
    endif

    DumpTermcap(use_curfile)
    SeparateTerminalKeysWithoutOptions()
    MoveKeynamesIntoInlineComments()
    AddAssignmentOperators()
    CommentSectionHeaders()
    AlignInlineComment()
    AddSetCommands()
    EscapeSpacesInOptionsValues()
    TrimTrailingWhitespace()
    TranslateSpecialKeys()
    SortLines()
    Fold()
    InstallMappings()

    # turn into Vim9 script
    ['vim9script', '']->append(0)
    if exists('g:syntax_on')
        doautocmd Syntax
    endif

    # bang to  suppress error  when we  don't have our  autocmd which  creates a
    # missing directory
    silent! update
enddef
#}}}1
# Core {{{1
def SetFt() #{{{2
    if &filetype != 'vim'
        &filetype = 'vim'
    endif
enddef

def SplitWindow() #{{{2
    execute 'split ' .. LOGFILE
enddef

def DumpTermcap(use_curfile: bool) #{{{2
    execute('set! termcap')->split('\n')->setline(1)
    # The bang  after silent is necessary  to suppress `E486` in  the GUI, where
    # there may be no `Terminal keys` section.
    search('Terminal codes')
    append('.', '')
    search('Terminal keys')
    append(line('.') - 1, '')
    append('.', '')
    silent keepjumps keeppatterns :% substitute/^ *//e
enddef

def SeparateTerminalKeysWithoutOptions() #{{{2
    # move terminal keys not associated to any terminal option at the end of the buffer
    silent! keepjumps keeppatterns :/Terminal keys/,$ global/^</move $
    # separate them from the terminal keys associated with a terminal option{{{
    #
    #     t_kP <PageUp>    ^[[5~ 
    #     <í>        ^[m
    #
    #     →
    #
    #     t_kP <PageUp>    ^[[5~ 
    #
    #     <í>        ^[m
    #}}}
    silent! :1/^<\%(.*# t_\S\S\)\@!/ put! _
enddef

def MoveKeynamesIntoInlineComments() #{{{2
    #     t_#2 <S-Home>    ^[[1;2H
    #     →
    #     <S-Home>    ^[[1;2H  # t_#2
    silent! keepjumps keeppatterns :/Terminal keys/,$ substitute/^\(t_\S\+ \+\)\(<.\{-1,}>\)\(.*\)/\2\3# \1/e
enddef

def AddAssignmentOperators() #{{{2
    # Only necessary for terminal keys (not codes):
    #
    #     <S-Home>    ^[[1;2H  # t_#2
    #     →
    #     <S-Home>=^[[1;2H  # t_#2
    silent! keepjumps keeppatterns :/Terminal keys/,$ substitute/^<.\{-1,}>\zs \+/=/e
enddef

def AlignInlineComment() #{{{2
# https://developer.ibm.com/tutorials/l-vim-script-2/#a-function-to-help-you-code

#     <S-Home>=^[[1;2H  # t_#2
#     <F4>=^[OS     # t_k4
#
#     →
#
#     <S-Home>=^[[1;2H # t_#2
#     <F4>=^[OS        # t_k4

    # locate block of code to be considered
    var firstline: number = search('# Terminal keys', 'n') + 1
    var lastline: number = search('^<.*\n\n\%>' .. firstline .. 'l', 'n')
    if lastline == 0
        lastline = line('$')
    endif
    if firstline <= 0 || lastline <= 0
        return
    endif

    # find the column at which the inline comments should be aligned
    var max_align_col: number
    for line: string in getline(firstline, lastline)
        # Does this line have an inline comment in it?
        var left_width: number = line->match('\s*#')

        # if so, track the maximal comment column
        if left_width >= 0
            max_align_col = [max_align_col, left_width]->max()
         endif
    endfor

    # to take into account the comment leader
    ++max_align_col

    # code needed to reformat lines so as to align inline comments
    var Formatter: func = (m: list<string>): string =>
        printf('%-*s%s', max_align_col, m[1], m[2])

    # reformat lines with inline comments aligned in the appropriate column
    for linenum: number in range(firstline, lastline)
        var oldline: string = getline(linenum)
        var newline: string = oldline->substitute('^\(^.\{-}\)\s*\(#\)', Formatter, '')
        newline->setline(linenum)
    endfor
enddef

def AddSetCommands() #{{{2
    silent keepjumps keeppatterns :% substitute/^\ze\%(t_\|<\)/set /e
enddef

def EscapeSpacesInOptionsValues() #{{{2
    #     set t_EI=^[[2 q
    #     →
    #     set t_EI=^[[2\ q
    #                  ^
    silent keepjumps keeppatterns :% substitute/\%(set.\{-}=.*[^#]\)\@<= [^# ]/\\&/ge
enddef

def TrimTrailingWhitespace() #{{{2
    silent! keepjumps keeppatterns :/Terminal keys/,$ substitute/ \+$//e
enddef

def TranslateSpecialKeys() #{{{2
    # translate caret notation of control characters
    Ref = (): string => eval('"' .. '\x' .. (submatch(1)->char2nr() - 64) .. '"')
    silent keepjumps keeppatterns :% substitute/\^\[/\="\<Esc>"/ge
    silent keepjumps keeppatterns :% substitute/\^\(\u\)/\=Ref()/ge
    silent keepjumps keeppatterns :% substitute/\^?/\="\x7f"/ge

    #     <á>=^[a    →    <M-a>=^[a
    silent keepjumps keeppatterns :% substitute/^set <\zs.\ze>=\e\(\l\)/M-\1/e
enddef
var Ref: func: string

def SortLines() #{{{2
    # sort terminal codes: easier to find a given terminal option name
    # sort terminal keys: useful later when vimdiff'ing the output with another one
    silent! keepjumps :1/Terminal codes/+1,/Terminal keys/-2 sort
    silent! keepjumps :1/Terminal keys/+2;/^$/-1 sort
    silent! keepjumps :1/Terminal keys//^$//^$/+1;$ sort
enddef

def CommentSectionHeaders() #{{{2
    #     --- Terminal codes ---    →    # Terminal codes
    #     --- Terminal keys ---     →    # Terminal keys
    silent keepjumps keeppatterns :% substitute/^--- Terminal \(\S*\).*/# Terminal \1/e
enddef

def Fold() #{{{2
    silent keepjumps keeppatterns :% substitute/^# .*\zs/\=' {{' .. '{1'/e
enddef

def InstallMappings() #{{{2
    # make sure `K` opens a help page (necessary if filetype detection is OFF)
    &l:keywordprg = ':help'
    # mapping to compare value on current line with the one in output of `:set! termcap`{{{
    #
    # Note that  `:filter` is able  to filter the "Terminal  codes" section,
    # but not the "Terminal keys" section.
    # So, no  matter the line  where you press  `!!`, you'll always  get the
    # whole "Terminal codes" section.
    # The  mapping is  still useful:  if you  press `!!`  on a  line in  the
    # "Terminal codes" section,  it will correctly filter out  all the other
    # terminal codes.
    #}}}
    nnoremap <buffer><nowait> !!
        \ <Cmd>execute 'filter /' .. getline('.')->matchstr('t_[^=]*') .. '/ set! termcap'<CR>
    # open relevant help tag to get more info about the terminal option under the cursor
    nnoremap <buffer><nowait> <CR> <Cmd>call <SID>GetHelp()<CR>
    # get help about mappings
    nnoremap <buffer><nowait> g? <Cmd>call <SID>PrintHelp()<CR>
enddef

def GetHelp() #{{{2
    var tag: string = getline('.')->matchstr('\%(^set \|# \)\@4<=t_[^=]*')
    if tag != ''
        try
            execute "help '" .. tag
        # some terminal options have no help tags (e.g. `'t_FL'`)
        catch /^Vim\%((\a\+)\)\=:E149:/
            echohl ErrorMsg
            echomsg v:exception
            echohl NONE
        endtry
    else
        echo 'no help tag on this line'
    endif
enddef

def PrintHelp() #{{{2
    var help: list<string> =<< trim END
        Enter    open relevant help tag to get more info about the terminal option under the cursor
        !!       compare value on current line with the one in output of `:set! termcap`
        g?       print this help
    END
    echo help->join("\n")
enddef

@egberts
Copy link
Author

egberts commented Jan 5, 2022

Before I perform the suggested investigative work, I wanted to report that this is now happening in ArchLinux vim v8.2.3890

Filetype used with this same issue experience:

  • .md
  • .sh
  • .conf
  • .txt

I removed 'Debian" from the issue title.

No $HOME/.vim* file exists. No vim plugins, no bash shell defines related to 'vi'. Virgin ArchLinux install.

@egberts
Copy link
Author

egberts commented Jan 5, 2022

Before I perform the suggested investigative work, another quick workaround to this issue for me on ArchLinux (and possibly other distros) is to reinstate the following line in global /etc/vimrc file.

let skip_defaults_vim=1

EDITED:
ARGH! Once I comment back OUT the above line from /etc/vimrc, the problem went away. ARGH!

@lacygoill, by any chance, would my removal of $HOME/.vimlocal accidentially improve my scenario?

I now have your DebugTermCap poised and ready. Running v8.2.3890. Will clone all relevant VIM-related files before embarking on a debug (perhaps try to recreate on another host?)

@egberts egberts changed the title unattended forced auto scrolling upward in Debian bullseye+bookworm vim unattended forced auto scrolling upward in Vim v8.2 Jan 6, 2022
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

3 participants