DEV Community

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

Posted on • Edited on

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

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.