]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
tests(commondumps): Mark and fold lines in screendump views
authorAliaksei Budavei <0x000c70@gmail.com>
Tue, 10 Feb 2026 21:55:36 +0000 (22:55 +0100)
committerChristian Brabandt <cb@256bit.org>
Tue, 10 Feb 2026 21:55:36 +0000 (22:55 +0100)
- Dynamically set mark "`" to pair disparate lines and
  initially set marks "`a", "`b", etc. for as many lines in
  the difference part.  Note that users are free to delete
  or change any set alphabetic marks without it affecting
  the dynamic updating of mark "`"; alphabetic marks only
  serve to help with arriving at "summary" lines, e.g.
  "`a````".
- Create a fold for the difference part (but defer to users
  the closing of it) so that disparate lines that fit real
  estate can be viewed at the same time, as an alternative
  to the builtin "s" keystroke that swaps top and bottom
  parts in place.
- Fold and mark lines with the "git difftool" extension too.

closes: #19380

Signed-off-by: Aliaksei Budavei <0x000c70@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/testdir/commondumps.vim

index 3dbdab5328af126c1e44e7e0c57cad59b3025700..cdf56597f01ea25e267ba11911c29a869b968fef 100644 (file)
@@ -1,5 +1,78 @@
 vim9script
 
+# Query the paired position for the cursor line and use it, if available, for
+# mark "`".
+def TryChangingLastJumpMark(marks: dict<list<number>>)
+  const pos: list<number> = get(marks, line('.'), [])
+  if !empty(pos)
+    setpos("'`", [0, pos[0], pos[1], 0])
+  endif
+enddef
+
+# Fold the difference part and the bottom part when the top and the bottom
+# parts are identical; otherwise, create a fold for the difference part and
+# manage marks for disparate lines: dynamically set mark "`" to pair such
+# lines and initially set "`a", "`b", etc. marks for difference part lines.
+def FoldAndMarkDumpDiffParts()
+  defer call('setpos', ['.', getpos('.')])
+  # Shape the pattern after get_separator() from "terminal.c".
+  const separator: string = '^\(=\+\)\=\s\S.*\.dump\s\1$'
+  const start_lnum: number = search(separator, 'eW', (line('$') / 2))
+  if start_lnum > 0
+    const end_lnum: number = search(separator, 'eW')
+    if end_lnum > 0
+      # Collect [line_nr, col_nr] pairs (matching the first non-blank column)
+      # from the difference part "bs" and assemble corresponding pairs for the
+      # top part "as" and the bottom part "cs".
+      const parts: list<list<list<number>>> =
+                               getline((start_lnum + 1), (end_lnum - 1))
+         ->map((idx: number, s: string) =>
+             [matchlist(s, '\(^\s*\S\)')->get(1, '')->strwidth(), idx])
+         ->reduce(((as: list<number>, bs: list<number>, cs: list<number>) =>
+             (xs: list<list<list<number>>>, pair: list<number>) => {
+                 const col_nr: number = pair[0]
+                 if col_nr != 0
+                   const idx: number = pair[1]
+                   xs[0]->add([get(as, idx, as[-1]), col_nr])
+                   xs[1]->add([bs[idx], col_nr])
+                   xs[2]->add([get(cs, idx, cs[-1]), col_nr])
+                 endif
+                 return xs
+               })(range(1, (start_lnum - 1)),
+                   range((start_lnum + 1), (end_lnum - 1)),
+                   range((end_lnum + 1), line('$'))),
+             [[], [], []])
+      if empty(parts[1])
+       setlocal foldenable foldmethod=manual
+       exec 'normal ' .. start_lnum .. 'GzfG'
+      else
+       setlocal nofoldenable foldmethod=manual
+       exec ':' .. start_lnum .. ',' .. end_lnum .. 'fold'
+       var marks: dict<list<number>> = {}
+       var names: list<string> = range(97, (97 + 25))
+           ->map((_: number, n: number) => nr2char(n, true))
+       for idx in range(parts[1]->len())
+         if !empty(names)
+           setpos(("'" .. remove(names, 0)),
+               [0, parts[1][idx][0], parts[1][idx][1], 0])
+         endif
+         # Point "bs" to "cs", "cs" to "as", "as" to "cs".
+         marks[parts[1][idx][0]] = parts[2][idx]
+         marks[parts[2][idx][0]] = parts[0][idx]
+         marks[parts[0][idx][0]] = parts[2][idx]
+       endfor
+       autocmd_add([{
+         replace:      true,
+         group:        'viewdumps',
+         event:        'CursorMoved',
+         bufnr:        bufnr(),
+         cmd:          printf('TryChangingLastJumpMark(%s)', string(marks)),
+       }])
+      endif
+    endif
+  endif
+enddef
+
 # See below on how to configure the git difftool extension
 
 # Extend "git difftool" with the capability for loading screendump files.
@@ -16,6 +89,7 @@ if v:progname =~? '\<g\=vimdiff$'
        term_dumpload(argv(0))
       else
        term_dumpdiff(argv(0), argv(1))
+       FoldAndMarkDumpDiffParts()
       endif
     finally
       silent bwipeout 1 2
@@ -83,30 +157,6 @@ endif
 #      :all
 
 
-# Script-local functions
-#
-# Fold the difference part and the bottom part when the top and the bottom
-# parts are identical.
-def FoldDumpDiffCopy()
-  try
-    normal mc
-    # Shape the pattern after get_separator() from "terminal.c".
-    const separator: string = '^\(=\+\)\=\s\S.*\.dump\s\1$'
-    const start_lnum: number = search(separator, 'eW', (line('$') / 2))
-    if start_lnum > 0
-      const end_lnum: number = search(separator, 'eW')
-      if end_lnum > 0 && getline((start_lnum + 1), (end_lnum - 1))
-         ->filter((_: number, line: string) => line !~ '^\s\+$')
-         ->empty()
-       setlocal foldenable foldmethod=manual
-       exec 'normal ' .. start_lnum .. 'GzfG'
-      endif
-    endif
-  finally
-    normal `c
-  endtry
-enddef
-
 # Render a loaded screendump file or the difference of a loaded screendump
 # file and its namesake file from the "dumps" directory.
 def Render()
@@ -118,7 +168,7 @@ def Render()
                        fnamemodify(failed_fname, ':p:h:h') .. '/dumps')
     if filereadable(dumps_fname)
       term_dumpdiff(failed_fname, dumps_fname)
-      FoldDumpDiffCopy()
+      FoldAndMarkDumpDiffParts()
     else
       term_dumpload(failed_fname)
     endif