DEV Community

Sérgio Araújo
Sérgio Araújo

Posted on • Edited on

5 2

VIM: Enhancing focus on vim

Keep your cursor in the middle of the screen in normal mode

:nnoremap j jzz
:nnoremap k kzz
Enter fullscreen mode Exit fullscreen mode

Jump back

As you know, vim has a jump list, and you can access previous jumping with Ctrlo and use Ctrli to go to the newer positions on the jump list.

Normally j and k do not change the jumplist but we can change this behavior:

" source: https://www.vi-improved.org/vim-tips/
nnoremap <expr> j v:count ? (v:count > 5 ? "m'" . v:count : '') . 'j' : 'gj'
nnoremap <expr> k v:count ? (v:count > 5 ? "m'" . v:count : '') . 'k' : 'gk'
Enter fullscreen mode Exit fullscreen mode

Now if you type 5j your jump will be added to the jump list.

Flash Cursorline Function

I am using lua to config my neovim and I have cursorline disabled. I have created a function to flash the cursorline and associate (map) it to some jumps:

-- ~/.config/nvim/lua/core/utils.lua
local M = {} -- M stands for module

-- https://vi.stackexchange.com/questions/31206
-- https://vi.stackexchange.com/a/36950/7339
M.flash_cursorline = function()
    local cursorline_state = lua print(vim.opt.cursorline:get())
    vim.opt.cursorline = true
    vim.cmd([[hi CursorLine guifg=#FFFFFF guibg=#FF9509]])
    vim.fn.timer_start(200, function()
        vim.cmd([[hi CursorLine guifg=NONE guibg=NONE]])
        if cursorline_state == false then
            vim.opt.cursorline = false
        end
    end)
end

-- map helper
M.map = function(mode, lhs, rhs, opts)
    local options = { noremap = true }
    if opts then
        options = vim.tbl_extend("force", options, opts)
    end
    vim.api.nvim_set_keymap(mode, lhs, rhs, options)
end

map('n', 'n', 'nzz:lua require("core.utils").flash_cursorline()<CR>Nn')
map('n', 'N', 'Nzz:lua require("core.utils").flash_cursorline()Beacon<CR>nN')

-- Why nzzNn: https://vi.stackexchange.com/a/36950/7339
-- zz will remove the count display ([n/nn]) in the statusbar if the view is changed. 
-- A quick and dirty solution to show the count again is to hit n or N again, ie.
-- nnoremap n nzzNn

map("n", "<C-o>", '<C-o>zv:lua require("core.utils").flash_cursorline()<CR>')
map("n", "<C-i>", '<C-i>zv:lua require("core.utils").flash_cursorline()<CR>')


return M
Enter fullscreen mode Exit fullscreen mode

Keep your cursor position during some actions:

To call any lua function we need to add our functions to a namespace and return this namespace, this means, at the beginning of the our module use:

M = {}
Enter fullscreen mode Exit fullscreen mode

And at the end of it:

return M
Enter fullscreen mode Exit fullscreen mode

Inside our module we add functions to this namesmapce prepending M. the the function we are creating.

-- file: ~/.config/nvim/lua/utils.lua
M.preserve = function(arguments)
    local arguments = string.format("keepjumps keeppatterns execute %q", arguments)
    -- local original_cursor = vim.fn.winsaveview()
    local line, col = unpack(vim.api.nvim_win_get_cursor(0))
    vim.api.nvim_command(arguments)
    local lastline = vim.fn.line("$")
    -- vim.fn.winrestview(original_cursor)
    if line > lastline then
        line = lastline
    end
    vim.api.nvim_win_set_cursor(0, { line, col })
end
Enter fullscreen mode Exit fullscreen mode

You can use the above function this way:

-- dos2unix
M.dosToUnix = function()
    M.preserve("%s/\\%x0D$//e")
    vim.bo.fileformat = "unix"
    vim.bo.bomb = true
    vim.opt.encoding = "utf-8"
    vim.opt.fileencoding = "utf-8"
end
vim.cmd([[command! Dos2unix lua require('core.utils').dosToUnix()]])
Enter fullscreen mode Exit fullscreen mode

The command outside the Dos2unix function creates a command that calls the function, of course you also can create mappings to do the same.

Reduce to or more spaces to one keeping the cursor position:

M.squeeze_blank_lines = function()
-- references: https://vi.stackexchange.com/posts/26304/revisions
    if vim.bo.binary == false and vim.opt.filetype:get() ~= "diff" then
        local old_query = vim.fn.getreg("/") -- save search register
        M.preserve("sil! 1,.s/^\\n\\{2,}/\\r/gn") -- set current search count number
        local result = vim.fn.searchcount({ maxcount = 1000, timeout = 500 }).current
        local line, col = unpack(vim.api.nvim_win_get_cursor(0))
        M.preserve("sil! keepp keepj %s/^\\n\\{2,}/\\r/ge")
        M.preserve("sil! keepp keepj %s/^\\s\\+$/\\r/ge")
        M.preserve("sil! keepp keepj %s/\\v($\\n\\s*)+%$/\\r/e")
        if result > 0 then
            vim.api.nvim_win_set_cursor(0, { (line - result), col })
        end
        vim.fn.setreg("/", old_query) -- restore search register
    end
end
Enter fullscreen mode Exit fullscreen mode

Change the "Last Change: dd/mm/yy" at the begining of your file each time you save it (it needs an autocommand for it):

--> :lua changeheader()
-- This function is called with the BufWritePre event (autocmd)
-- and when I want to save a file I use ":update" which
-- only writes a buffer if it was modified
M.changeheader = function()
    -- We only can run this function if the file is modifiable
    if not vim.api.nvim_buf_get_option(vim.api.nvim_get_current_buf(), "modifiable") then
        return
    end
    if vim.fn.line("$") >= 7 then
        os.setlocale("en_US.UTF-8") -- show Sun instead of dom (portuguese)
        time = os.date("%a, %d %b %Y %H:%M")
        M.preserve("sil! keepp keepj 1,7s/\\vlast (modified|change):\\zs.*/ " .. time .. "/ei")
    end
end
Enter fullscreen mode Exit fullscreen mode

To see an autocmd.lua file you can follow this link.

We can even reindent the whole file keeping the cursor position:

vim.cmd([[command! Reindent lua require('core.utils').preserve("sil keepj normal! gg=G")]])
Enter fullscreen mode Exit fullscreen mode

Jump to the alternate file:

When you have the buffer list opened it will be like this:

Image description

To alternate between the current file and the alternate file, wich is the last one you were on, just press Ctrl-6

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (2)

Collapse
 
meleu profile image
meleu • Edited

wow! pretty cool and simple solution the nnoremap j jzz

I have a suggestion to improve it even more:

nnoremap j gjzz
nnoremap j gkzz
Enter fullscreen mode Exit fullscreen mode

It's useful when you have a line bigger than the width of your viewport.

See it in action:

Collapse
 
mxgrn profile image
Max Gorin

Quickly realized I'm getting a "whole screen movement fatigue" with this.

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay