@@ -628,35 +628,86 @@ examples:
628628<summary >Linewise motions</summary >
629629
630630``` lua
631- local function get_line_starts (winid , skip_range )
632- local wininfo = vim .fn .getwininfo (winid )[1 ]
633- local cur_line = vim .fn .line (' .' )
631+ -- ref: https://stackoverflow.com/a/6081639/14110650
632+ local function serialize_table (val , name , skipnewlines , depth )
633+ skipnewlines = skipnewlines or false
634+ depth = depth or 0
635+ local tmp = string.rep (" " , depth )
636+ if name then
637+ tmp = tmp .. name .. " = "
638+ end
639+ if type (val ) == " table" then
640+ tmp = tmp .. " {" .. (not skipnewlines and " \n " or " " )
641+ for k , v in pairs (val ) do
642+ tmp = tmp
643+ .. serialize_table (v , k , skipnewlines , depth + 1 )
644+ .. " ,"
645+ .. (not skipnewlines and " \n " or " " )
646+ end
647+ tmp = tmp .. string.rep (" " , depth ) .. " }"
648+ elseif type (val ) == " number" then
649+ tmp = tmp .. tostring (val )
650+ elseif type (val ) == " string" then
651+ tmp = tmp .. string.format (" %q" , val )
652+ elseif type (val ) == " boolean" then
653+ tmp = tmp .. (val and " true" or " false" )
654+ else
655+ tmp = tmp .. ' "[inserializeable datatype:' .. type (val ) .. ' ]"'
656+ end
657+ return tmp
658+ end
659+
660+ local function get_line_len (bufid , line_number )
661+ local line_content =
662+ vim .api .nvim_buf_get_lines (bufid , line_number - 1 , line_number , false )[1 ]
663+ return string.len (line_content )
664+ end
665+
666+ local function get_line_targets (winid , skip_range , is_upward , keep_column )
667+ local wininfo = vim .fn .getwininfo (winid )[1 ]
668+ local bufid = vim .api .nvim_win_get_buf (winid )
669+ local cur_line = vim .fn .line " ."
670+ local cur_col = vim .fn .col " ."
634671 -- Skip lines close to the cursor.
635672 local skip_range = skip_range or 2
673+ local keep_column = keep_column or false
674+ local is_directional = is_upward ~= nil and true or false
636675
637676 -- Get targets.
638677 local targets = {}
639678 local lnum = wininfo .topline
679+ local cnum = 1
640680 while lnum <= wininfo .botline do
641681 local fold_end = vim .fn .foldclosedend (lnum )
642682 -- Skip folded ranges.
643683 if fold_end ~= - 1 then
644684 lnum = fold_end + 1
645685 else
686+ if is_directional then
687+ if is_upward and lnum > cur_line - skip_range then
688+ break
689+ elseif not is_upward and lnum < cur_line + skip_range then
690+ goto continue
691+ end
692+ end
693+ if keep_column then
694+ cnum = math.max (1 , math.min (cur_col , get_line_len (bufid , lnum )))
695+ end
646696 if (lnum < cur_line - skip_range ) or (lnum > cur_line + skip_range ) then
647- table.insert (targets , { pos = { lnum , 1 } })
697+ table.insert (targets , { pos = { lnum , cnum } })
648698 end
699+ :: continue::
649700 lnum = lnum + 1
650701 end
651702 end
652703
653704 -- Sort them by vertical screen distance from cursor.
654- local cur_screen_row = vim .fn .screenpos (winid , cur_line , 1 )[' row' ]
705+ local cur_screen_row = vim .fn .screenpos (winid , cur_line , 1 )[" row" ]
655706 local function screen_rows_from_cur (t )
656- local t_screen_row = vim .fn .screenpos (winid , t .pos [1 ], t .pos [2 ])[' row' ]
707+ local t_screen_row = vim .fn .screenpos (winid , t .pos [1 ], t .pos [2 ])[" row" ]
657708 return math.abs (cur_screen_row - t_screen_row )
658709 end
659- table.sort (targets , function (t1 , t2 )
710+ table.sort (targets , function (t1 , t2 )
660711 return screen_rows_from_cur (t1 ) < screen_rows_from_cur (t2 )
661712 end )
662713
@@ -665,23 +716,60 @@ local function get_line_starts(winid, skip_range)
665716 end
666717end
667718
668- -- You can pass an argument to specify a range to be skipped
669- -- before/after the cursor (default is +/-2).
670- function leap_line_start (skip_range )
719+ -- You can pass a table of arguments to specify the jump behavior:
720+ -- skip_range - range to be skipped before/after the cursor (default is +/-2)
721+ -- is_upward - set the jump direction, true - up, false - down (default nil - bidirectional)
722+ -- keep_column - whether to try to keep the column after the jump (default false)
723+ local function leap_vertically (args )
724+ local args = args or {}
725+ local skip_range = args .skip_range
726+ local is_upward = args .is_upward
727+ local keep_column = args .keep_column
671728 local winid = vim .api .nvim_get_current_win ()
672- require (' leap' ).leap {
729+ require (" leap" ).leap {
673730 target_windows = { winid },
674- targets = get_line_starts (winid , skip_range ),
731+ targets = get_line_targets (winid , skip_range , is_upward , keep_column ),
675732 }
676733end
677734
678735-- For maximum comfort, force linewise selection in the mappings:
679- vim .keymap .set (' x' , ' |' , function ()
680- -- Only force V if not already in it (otherwise it would exit Visual mode).
681- if vim .fn .mode (1 ) ~= ' V' then vim .cmd (' normal! V' ) end
682- leap_line_start ()
683- end )
684- vim .keymap .set (' o' , ' |' , " V<cmd>lua leap_line_start()<cr>" )
736+ -- Create mappings for "|", "<leader><leader>J", "<leader><leader>K",
737+ -- "<leader><leader>j", "<leader><leader>k" in normal, visual, and operator-pending modes.
738+ for key , args in pairs {
739+ [" |" ] = { { keep_column = true }, { desc = " Leap vertically" } },
740+ [" <leader><leader>J" ] = {
741+ { is_upward = false },
742+ { desc = " Leap to line start downwards" },
743+ },
744+ [" <leader><leader>K" ] = {
745+ { is_upward = true },
746+ { desc = " Leap to line start upwards" },
747+ },
748+ [" <leader><leader>j" ] = {
749+ { is_upward = false , keep_column = true },
750+ { desc = " Leap downwards" },
751+ },
752+ [" <leader><leader>k" ] = {
753+ { is_upward = true , keep_column = true },
754+ { desc = " Leap upwards" },
755+ },
756+ } do
757+ for mode , rhs_expr in pairs {
758+ n = function ()
759+ leap_vertically (args [1 ])
760+ end ,
761+ x = function ()
762+ -- Only force V if not already in it (otherwise it would exit Visual mode).
763+ if vim .fn .mode (1 ) ~= " V" then
764+ vim .cmd " normal! V"
765+ end
766+ leap_vertically (args [1 ])
767+ end ,
768+ o = " V<Cmd>lua leap_vertically(" .. serialize_table (args [1 ]):gsub (" \n " , " " ) .. " )<CR>" ,
769+ } do
770+ vim .keymap .set (mode , key , rhs_expr , args [2 ])
771+ end
772+ end
685773```
686774</details >
687775
0 commit comments