I spend a lot of time with NeoVim because it is my main tool for development. It suits me more than others primarily because it has lua and the ability to write your plugins and automation in a convenient and uncomplicated way. Why do I need this when there are already many ready-made solutions for the most common problems? Because sooner or later, there are cases that are not among the ready. And there are also project-specific cases that will never be among the ready. In this article I will show in two examples how it is relatively easy to expand NeoVim and make your work more productive. All examples below can be viewed live in mydotfile.
Curl
None of the query UIs I know will give me a Vim-like environment. For example, I need to be able to search and navigate the answer from the API using the same hotkeys that I already have configured in my Vim. Previously, I always had to switch to Postman, write a query there and copy the answer to my editor to be able to analyze it. And all this with a mouse, which is very unusual for someone who used to use a lot of hot keys.
localutils={}functionutils.getCurrentParagraph()localrow,col=unpack(vim.api.nvim_win_get_cursor(0))-- search forwardlocalrowi=rowwhiletruedolocallastLine=vim.api.nvim_buf_get_lines(0,rowi,rowi+1,false)or{""}iflastLine[1]==""thenbreakendiflastLine[1]==nilthenbreakendrowi=rowi+1end-- search backlocalrowj=rowwhiletruedolocallastLine=vim.api.nvim_buf_get_lines(0,rowj,rowj+1,false)or{""}iflastLine[1]==""thenbreakendiflastLine[1]==nilthenbreakendrowj=rowj-1ifrowj<1thenbreakendendlocallines=vim.api.nvim_buf_get_lines(0,rowj+1,rowi,false)localresult=table.concat(lines," ")result=result:gsub('[%c]','')returnresultendreturnutils
This function searches for the first empty line after the cursor position and then the same line until the cursor position. The empty line at the beginning and at the end I consider the border of the paragraph. I will take a step-by-step look at what happens in the function above.
localrow,col=unpack(vim.api.nvim_win_get_cursor(0))
So I get the current cursor position in the buffer 0. Buffer 0 is always the current buffer. This API method returns a row and a column, but I’m only interested in a row.
localrowi=rowwhiletruedolocallastLine=vim.api.nvim_buf_get_lines(0,rowi,rowi+1,false)or{""}iflastLine[1]==""thenbreakendiflastLine[1]==nilthenbreakendrowi=rowi+1end
By getting one line and increasing the count by 1 I check the row that it is empty and that it exists at all (for example if the end of the file is reached). All I need to do is memorize the row number.False
in function arguments means that you do not want to throw an error if there is no index.
Then I look in the opposite direction and I find the top of the paragraph.
Then all I have to do is get the lines along the lines and merge them into one.
locallines=vim.api.nvim_buf_get_lines(0,rowj+1,rowi,false)localresult=table.concat(lines," ")result=result:gsub('[%c]','')
Here I additionally delete the template[%c]
The fact is that the buffer will have a large number of different special characters, which when placed in the console breed a lot of errors. Such as
line 1 v curl -X POST https://jsonplaceholder.typicode.com/commentsline 2 v ^I-H 'Content-Type: application/json'line 3 v ^I-d '{line 4 v ^I^I"postId": 1line 5 v ^I}'
Okay, now I have the current paragraph.
To allow this function to be imported into other lua scripts I made it as a module and return it when the file is imported. Below in this article in another example I again use this module in another script. And so far I send the command to the terminal. As a terminal emulator I liketoggleterm because it is flexible enough and has a convenient API.
localutils=require("apg.utils")functionexecCurl()localcommand=utils.getCurrentParagraph()localTerminal=require('toggleterm.terminal').Terminallocalrun=Terminal:new({cmd=command,hidden=true,direction="float",close_on_exit=false,on_open=function(term)vim.api.nvim_buf_set_keymap(term.bufnr,"t","q","<cmd>close<CR>",{noremap=true,silent=true})end,})run:toggle()end
And now let me show you how it works.
SQL
To work with SQL databases already there are a huge number of excellent tools. Every IDE I’m familiar with has database plugins. Vim is included.LSP server already exists. But sometimes I just need to run a simple query, without getting distracted by going to other tools, looking for the right connection, or the prepared SQL query. Therefore, using thegetCurrentParagraph
function discussed above, I implemented a simple and fast start of SQL queries for PostgreSQL
localutils=require("apg.utils")functionexecPgSql()localquery=utils.getCurrentParagraph()localcfg=vim.api.nvim_buf_get_lines(0,0,1,false)localcommand='psql '..cfg[1]..' -c "'..query..'"'localTerminal=require('toggleterm.terminal').Terminallocalrun=Terminal:new({cmd=command,hidden=true,direction="float",close_on_exit=false,on_open=function(term)vim.api.nvim_buf_set_keymap(term.bufnr,"t","q","<cmd>close<CR>",{noremap=true,silent=true})end,})run:toggle()end
Now I have in the project files with prepared SQL queries, which I can reach and run unrealistically fast. Here is an example of such a file
-hlocalhost-p5432-Upostgres-ddemo-WSELECTa.aircraft_code,a.model,s.seat_no,s.fare_conditionsFROMaircraftsaJOINseatssONa.aircraft_code=s.aircraft_codeWHEREa.model='Cessna 208 Caravan'ORDERBYs.seat_no;SELECTs2.aircraft_code,string_agg(s2.fare_conditions||'('||s2.num::text||')',', ')asfare_conditionsFROM(SELECTs.aircraft_code,s.fare_conditions,count(*)asnumFROMseatssGROUPBYs.aircraft_code,s.fare_conditionsORDERBYs.aircraft_code,s.fare_conditions)s2GROUPBYs2.aircraft_codeORDERBYs2.aircraft_code;
Here you can see the additional first line. It includes the parameters of connection to the database server and is substituted before query
localcfg=vim.api.nvim_buf_get_lines(0,0,1,false)localcommand='psql '..cfg[1]..' -c "'..query..'"'
I would still like to have a separate file for the configuration of the connection to the base and select the desired one before executing the request. But so far, it’s working fine for me. Maybe in the future I’ll work on this script. I’ll show you how it works.
And now let me show you how it works.
Conclusion
With these scripts, I speed up my work and make it more pleasant. Because I don’t get distracted by unnecessary actions, like switching to other tools and memorizing their features. I hope my examples have helped you understand the general principle of writing extensions for NeoVim and maybe find new opportunities for yourself.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse