neovim
fzf-lua
local fzf_lua = require('fzf-lua')
vim.keymap.set('n', '<Leader>hh', fzf_lua.help_tags, { desc = 'find files'})
vim.keymap.set('n', '<Leader>ff', fzf_lua.files, { desc = 'find files'})
-- ctrl-y to accept, like return
fzf_lua.setup({
keymap = {
fzf = {
["ctrl-y"] = "accept"
}
},
})
lsp configuration for dart/flutter
The first part is a handler for closing tags and the second tells neovim
what to do when for a FileType
event with pattern dart
.
-- handler for dart/textDocument/publishClosingLabels
local namespace = vim.api.nvim_create_namespace("flutter_closing_tags")
local function closing_tags(error, result, ctx, config)
vim.api.nvim_buf_clear_namespace(0, namespace, 0, -1)
for _, item in ipairs(result.labels) do
local line = tonumber(item.range["end"].line)
if line <= vim.api.nvim_buf_line_count(0) then
vim.api.nvim_buf_set_extmark(0, namespace, line, -1, {
virt_text = { {
"// " .. item.label,
"Comment",
} },
virt_text_pos = "eol",
hl_mode = "combine",
})
end
end
end
vim.api.nvim_create_autocmd('FileType', {
group = lspautocmds,
pattern = 'dart',
callback = function(ev)
vim.lsp.start({
name = "dartls",
cmd = { 'dart', 'language-server', '--protocol=lsp' },
root_dir = vim.fs.root(ev.buf, { 'pubspec.yaml' }),
init_options = {
closingLabels = true,
flutterOutline = true,
onlyAnalyzeProjectsWithOpenFiles = true,
outline = true,
suggestFromUnimportedLibraries = true
},
-- capabilities = require('cmp_nvim_lsp').default_capabilities(),
capabilities = vim.lsp.protocol.make_client_capabilities(),
settings = {
dart = {
completeFunctionCalls = true,
showTodos = true,
enableSnippets = true,
documentation = "full",
},
},
handlers = {
["dart/textDocument/publishClosingLabels"] = closing_tags
}
})
vim.opt.commentstring="// %s"
end,
})
lsp configuration for lua
vim.api.nvim_create_autocmd('FileType', {
group = lspautocmds,
pattern = 'lua',
callback = function(ev)
vim.lsp.start({
name = "lua_ls",
cmd = { 'lua-language-server' },
root_dir = vim.fs.root(ev.buf, { '.luarc.json', '.luarc.jsonc' }),
on_init = function(client)
client.settings.Lua = {
runtime = {
version = "LuaJIT",
},
workspace = {
library = {
"/usr/share/nvim/runtime",
"/usr/lib/lua-language-server/meta/3rd/luv/library"
},
},
}
end,
settings = {
Lua = {},
},
})
end,
})
Note that we declare an empty settings = { Lua = {} }
. This is required and
it is the reason why we're able to set client.settings.Lua
in on_init
function.
tabs vs spaces :)
Tabs Reasoning: Tabs are for indentation. The editor decides how a tab character is displayed. I find 3 spaces to be most visually apprpriate.
-- Insert tabs but they appear like 3 spaces
vim.opt.expandtab = false
vim.opt.tabstop = 3
vim.opt.shiftwidth = 3
vim.opt.softtabstop = 3
vim.opt.list = true
vim.opt.listchars = "tab:» ,eol:↲,nbsp:+,trail:-"
Spaces reasoning: What you see is what it is: if indentation has 3 spaces, its 3 spaces. If its 8 its a tab. We only use spaces. So when we press 'Tab' for indent, we want spaces to be inserted as opposed to a tab character.
-- The representation of a tab in spaces (or more precisely, columns)
vim.opt.tabstop = 8
vim.opt.shiftwidth = 2
-- When enabled uses spaces instead of tab characters
vim.opt.expandtab = true
vim.opt.softtabstop = 2
vim.optpt.list = true
vim.opt.listchars = "tab:» ,eol:↲,nbsp:+,trail:-"
Folding dart/flutter code with treesitter in neovim
Using :InspectTree
I see that the nodes I want folded are selector
, named_argument
and list_literal
.
In the code below, I bind the function that folds to <C-f>
or Ctrl + f.
local fold_named_arg_func = function()
local allowed_types = {
["selector"] = true,
["named_argument"] = true,
["list_literal"] = true
}
local ts_utils = require('nvim-treesitter.ts_utils')
local winid = vim.fn.bufwinid(1)
local nuc = ts_utils.get_node_at_cursor(winid)
local cn = nuc
while cn ~= nil and allowed_types[cn:type()] == nil
do
cn = cn:parent()
end
local start_row
local end_row
if cn ~=nil then
start_row, _, end_row, _ = cn:range()
vim.cmd(start_row + 1 .. "," .. end_row + 1 .. "fold")
end
end
vim.keymap.set('n', '<C-f>', function()
local fold_level = vim.fn.foldlevel('.')
local fold_closed = vim.fn.foldclosed('.')
if fold_level > 0 then
if fold_closed == -1 then
fold_named_arg_func()
else
vim.cmd("foldopen")
end
else
fold_named_arg_func()
end
end)
In conjunction to the above, I also modded how folds appear in neovim because the default implementation didn't preserve code indendation.
vim.opt.fillchars = { eob = "-", fold = " " }
vim.opt.foldtext = 'v:lua.MyFoldText()'
function MyFoldText()
local start_line = vim.fn.getline(vim.v.foldstart)
local end_line = vim.fn.getline(vim.v.foldend)
end_line = end_line:gsub("^%s+", "")
return start_line .. " ... " .. end_line
end
vim.keymap.set("v", "<C-f>", ":fold<CR>", { desc = "fold" })
Alternatively (what I do now), is to fold all nodes. If the node isn't multiline, fold its parent instead.
local fold_node = function ()
local ts_utils = require('nvim-treesitter.ts_utils')
local cn = ts_utils.get_node_at_cursor(0)
while cn ~= nil
do
local node_start_row, _, node_end_row, _ = cn:range()
if node_end_row == node_start_row then
cn = cn:parent()
else
vim.cmd(node_start_row + 1 .. "," .. node_end_row + 1 .. "fold")
break
end
end
end
vim.keymap.set('n', '<C-f>', function()
local fold_level = vim.fn.foldlevel('.')
local fold_closed = vim.fn.foldclosed('.')
if fold_level > 0 then
if fold_closed == -1 then
-- fold_named_arg_func()
fold_node()
else
vim.cmd("foldopen")
end
else
-- fold_named_arg_func()
fold_node()
end
end)
Steps to use shipwright to export lush.nvim themes
source: https://github.com/rktjmp/lush.nvim/blob/main/BUILD.md#exporting-a-colorscheme-to-configurable-lua
I) Install shipwright
Since I don't use a package manager..
Create files shipwright_build.lua and colors/vectorspacexyz.lua
touch ~/.config/nvim/pack/colorschemes/start/shipwright.nvim/lua/shipwright_build.lua
mkdir ~/.config/nvim/pack/colorschemes/start/shipwright.nvim/lua/colors
touch ~/.config/nvim/pack/colorschemes/start/shipwright.nvim/lua/colors/vectorspacexyz.lua
shipwright_build.lua:
local colorscheme = require("lush_theme.vector")
local lushwright = require("shipwright.transform.lush")
run(colorscheme,
lushwright.to_lua,
{patchwrite, "colors/vectorspacexyz.lua", "-- PATCH_OPEN", "-- PATCH_CLOSE"})
How did you get "lush_theme.vector" here? vector.lua is the name of the file that contains highlight definitions in my lush colorscheme project:
vectorspacexyz.lua:
-- colors/colorscheme.lua
local colors = {
-- content here will not be touched
-- PATCH_OPEN
-- group data will be inserted here
-- PATCH_CLOSE
-- content here will not be touched
}
-- colorschemes generally want to do this
vim.cmd("highlight clear")
vim.cmd("set t_Co=256")
vim.cmd("let g:colors_name='my_theme'")
-- apply highlight groups
for group, attrs in pairs(colors) do
vim.api.nvim_set_hl(0, group, attrs)
end
And..
Need for augroups
In lua, you'd need to use { clear = true, }
local lspautocmds = vim.api.nvim_create_augroup('LSPAutoCmds', { clear = true, })
vim.api.nvim_create_autocmd("LspAttach", {
group = lspautocmds,
callback = function(args)
local bufnr = args.buf
local client = vim.lsp.get_client_by_id(args.data.client_id)
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, { buffer = bufnr, desc = '[G]o to [D]efinition' })
vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, { buffer = bufnr, desc = '[G]o to [D]eclaration' })
vim.keymap.set('n', '<Leader>ca', vim.lsp.buf.code_action, { buffer = bufnr, desc = '[C]ode [A]ction' })
vim.keymap.set('n', '<Leader>rn', vim.lsp.buf.rename, { buffer = bufnr, desc = '[R]e[n]ame' })
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr, desc = 'Hover Documentation' })
vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_)
vim.lsp.buf.format()
end, { desc = 'Format current buffer with LSP' })
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous diagnostic message' })
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next diagnostic message' })
vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float, { desc = 'Open floating diagnostic message' })
vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, { desc = 'Open diagnostics list' })
end
})
LSP Request
local function test(err, result, ctx)
vim.api.nvim_buf_set_lines(5, 0, -1, true, vim.split(result.contents.value, '\n'))
end
vim.lsp.buf_request(0, "textDocument/hover", vim.lsp.util.make_position_params(0), test)
Using LSP without nvim lspconfig
I'm not a fan of lspconfig because I think it abstracts too much of how neovim functions behind obscure lua code. Imo, you really don't need to be that proficient in lua before you can figure out what's happening behind the scenes with your editor.
If your goal is to be proficient in neovim and lua such that you can write your own scripts when the need rises, you should imo try to do without lspconfig.
All that happens really is that neovim launches a particular binary, with particular settings when a particular filetype is opened.
This is all you need to have in your init.lua
to set up lua language server:
vim.api.nvim_create_autocmd('FileType', {
pattern = 'lua',
callback = function(ev)
vim.lsp.start({
name = "lua_ls",
cmd = { 'lua-language-server' },
root_dir = vim.fs.root(ev.buf, { '.luarc.json', '.luarc.jsonc' }),
settings = {
Lua = {
runtime = {
version = "LuaJIT",
},
workspace = {
library = {
"/usr/share/nvim/runtime",
}
},
},
},
})
end,
})
Its so obvious what's going on right? We just create an autocommand. Whenever a
filetype lua is opened, the function in callback gets executed. All that
function does is launches the binary of language server. Now, if you've ever
looked into the differences between treesitter and lsp, you might know that
unlike treesitter the lsp is aware of your project as a whole. It knows what
you should import from another file so that the variables in the current file
you're editing is in scope. For that to happen, you need to let the lsp know
which directory is the root of the project. This is why there's a root_dir
argument.
You can find out what goes into settings
argument by reading the
documentation of the specific language server and by checking out server-configurations
page in nvim-lspconfig:
https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
In lua for example, this section reveals what the settings should be:
client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, {
runtime = {
-- Tell the language server which version of Lua you're using
-- (most likely LuaJIT in the case of Neovim)
version = 'LuaJIT'
},
-- Make the server aware of Neovim runtime files
workspace = {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME
-- Depending on the usage, you might want to add additional paths here.
-- "${3rd}/luv/library"
-- "${3rd}/busted/library",
}
-- or pull in all of 'runtimepath'. NOTE: this is a lot slower
-- library = vim.api.nvim_get_runtime_file("", true)
}
})
Additional example (dart language server):
vim.api.nvim_create_autocmd('FileType', {
pattern = 'dart',
callback = function(ev)
vim.lsp.start({
name = "dartls",
cmd = { 'dart', 'language-server', '--protocol=lsp' },
root_dir = vim.fs.root(ev.buf, { 'pubspec.yaml' }),
init_options = {
closingLabels = true,
flutterOutline = true,
onlyAnalyzeProjectsWithOpenFiles = true,
outline = true,
suggestFromUnimportedLibraries = true
},
settings = {
dart = {
completeFunctionCalls = true,
showTodos = true,
},
},
})
end,
})
Installing packages without package manager
Place the package in ~/.config/nvim/pack
Eg: Treesitter installation
cd ~/.config/nvim/pack
mkdir -p treesitter/start
cd treesitter/start
git clone 'https://github.com/nvim-treesitter/nvim-treesitter.git'
When you want to install a package, say nvim-treesitter, and you place it pack/
set tw=80 for markdown files
file: ~/.config/nvim/lua/core/autocmds.lua
local group = vim.api.nvim_create_augroup("VectorClearAu", { clear = true })
vim.api.nvim_create_autocmd('FileType', {
pattern = "markdown",
callback = function()
vim.opt.tw = 80
end,
group = group,
})
Autocommands
source: TJ Devries YT
test.lua:
BufEnter
is an event. Autocommands are tied to events. To see more about events :h events
To check autocmds tied to a particular event: :au BufEnter
To clear autocmds attached to particular event: au! BufEnter
As it is, if test.lua
file is executed again, it greates another autocmd. So "Hello"
gets print twice with every BufEnter
event. This is why augroup
is used.
Creating augroup
:
local group = vim.api.nvim_ceate_augroup("SmashThatLikeButton", { clear = true })
-- if it was { clear = false } we'd get the old behavior
vim.api.nvim_create_autocmd('BufEnter', { command = "echo 'Hello 1'", group = group })
vim.api.nvim_create_autocmd('BufEnter', { command = "echo 'Hello 2'", group = group })
Now every time the file gets created, the autogroup gets cleared before its created, and with it the autocmds part of the group also gets cleared.
Now, this might be the feature that we're gonna use more often —lua functions triggered
by events
.
local group = vim.api.nvim_ceate_augroup("SmashThatLikeButton", { clear = true })
-- if it was { clear = false } we'd get the old behavior
vim.api.nvim_create_autocmd('BufEnter', { command = "echo 'Hello 1'", group = group })
vim.api.nvim_create_autocmd('BufEnter', { callback = function()
print("Hello")
end, group = group })
Screenshots to markdown
This script both gets the latest file in ~/Pictures where my screenshots are and then copies them to img/
folder
in the same folder where the file is being edited.
local M = {}
M.insert_screenshot_markdown = function()
local bufno = vim.api.nvim_get_current_buf()
local winid = vim.fn.bufwinid(bufno)
local path = vim.api.nvim_buf_get_name(bufno)
local pathtofile = vim.fn.fnamemodify(path, ':h')
local img_dir = pathtofile .. "/img"
local stat = vim.loop.fs_stat(img_dir)
local dir_exists = stat and stat.type == 'directory'
if not dir_exists then
local success, err = vim.loop.fs_mkdir(img_dir, 511)
if not success then
print("Unable to create dir")
return 1
end
end
local directory = vim.fn.expand('~/Pictures')
local cmd = "ls -t " .. directory .. " | head --lines 1"
local newest_file = vim.fn.system(cmd)
newest_file = newest_file:gsub("\n", "")
local cmd2 = "cp " .. directory .. "/" .. newest_file .. " " .. img_dir
vim.fn.system(cmd2)
if newest_file ~= "" then
local markdown_link = string.format("![%s](img/%s)", newest_file, newest_file)
local row, col = unpack(vim.api.nvim_win_get_cursor(winid))
local lines = vim.api.nvim_buf_get_lines(bufno, row - 1, row, false)
-- Check if the 'lines' table is empty
local line = ""
if #lines ~= 0 then
line = lines[1]:gsub("\n", " ")
end
local new_line = line .. markdown_link
vim.api.nvim_buf_set_lines(bufno, row - 1, row, false, { new_line })
vim.api.nvim_win_set_cursor(winid, { row, col + #markdown_link })
end
end
return M
The above script is placed in ~/plugins and it gets picked up by neovim lazy.nvim because of this mention
in ~/.config/nvim/lua/plugins/vector.lua
:
{
dir = "/home/vector/plugins/markdown-screenshot.nvim",
config = function()
vim.keymap.set({ 'n', 'i' }, '<Leader>p',
function()
require("markdown-screenshot").insert_screenshot_markdown()
end,
{ desc = "Paste screenshot" })
end
},
Scripting workflow
:vnew ~/.config/nvim/lua/development/ss.lua
:echo nvim_get_current_buf()
1
local bufno = 1
local path = vim.api.nvim_buf_get_name(bufno)
Getting treesitter root
local parser = vim.treesitter.get_parser(5, "dart", {})
local tree = parser:parse()[1]
local root = tree:root()
Visual range
local cursorpos = vim.fn.getpos('.')
local vstart = vim.fn.getpos('v')
-- { 0, 31, 4, 0 jo}
-- row: cursorpos[2] row: vstart[2]
-- col: curspor[3], col: vstart[3]
Note
to
is visual selection in vim. Note the return value
local result = {} --string[]
local op1 = vim.fn.getpos('v')
local op2 = vim.fn.getpos('.')
table.insert(result, vim.inspect(op1))
table.insert(result, vim.inspect(op2))
vim.api.nvim_buf_set_text(19, 0, -1, result)
-- note 19 is output buffer
Dealing with visual ranges (incomplete)
local outputbuf = 10
local inputbuf = 1
local inputwin = 1000
local cursorpos = vim.api.nvim_win_get_cursor(1000)
local visualstart = vim.fn.getpos('v')
vim.api.nvim_buf_set_lines(outputbuf, 0, -1, false, {
string.format("Row: %s Column: %s", cursorpos[1], cursorpos[2]),
string.format("Row: %s Column: %s", visualstart[2], visualstart[3])
})
Complete init.lua
-- Essential keymaps
-- Rebind space in normal mode to leader
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
-- Make line numbers default
vim.opt.number = true
-- Save undo history
vim.opt.undofile = true
vim.opt.completeopt = "menu,menuone,noselect"
-- TABS
-- -- Insert tabs but they appear like 3 spaces
-- vim.opt.expandtab = false
-- vim.opt.tabstop = 3
-- vim.opt.shiftwidth = 3
-- vim.opt.softtabstop = 3
-- vim.opt.list = true
-- vim.opt.listchars = "tab:» ,eol:↲,nbsp:+,trail:-"
-- SPACES
-- The representation of a tab in spaces (or more precisely, columns)
vim.opt.tabstop = 8
vim.opt.shiftwidth = 2
-- When enabled uses spaces instead of tab characters
vim.opt.expandtab = true
vim.opt.softtabstop = 2
vim.opt.list = true
vim.opt.listchars = "tab:» ,eol:↲,nbsp:+,trail:-"
-- Case insensitive searching UNLESS /C or capital in search
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.termguicolors = true
vim.opt.foldopen = ""
-- C-c to copy to system clipboard
vim.keymap.set('v', '<C-c>', '"+y')
-- [[ Highlight on yank ]]
-- See `:help vim.highlight.on_yank()`
local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true })
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function()
vim.highlight.on_yank()
end,
group = highlight_group,
pattern = '*',
})
-- Copy the path to current file so I can cd into it from another terminal
vim.keymap.set('n', '<leader>cd', function()
local cwd = vim.fn.expand('%:p:h')
vim.fn.setreg('+', cwd)
print("Copied " .. cwd .. " to clipboard")
end, { desc = "Copy the directory containing file" })
-- Run the current file (lua)
vim.keymap.set('n', '<leader>cc', function()
vim.cmd(":w")
vim.cmd("so " .. vim.fn.expand('%:p'))
end, { desc = "Source the current file" })
-- H,L to switch tabs in normal mode
vim.keymap.set('n', 'H', vim.cmd.tabp, { desc = 'Switch to previous tab' })
vim.keymap.set('n', 'L', vim.cmd.tabn, { desc = 'Switch to next tab' })
-- Inspect any variable v using P(v)
function P(v)
vim.notify(vim.inspect(v))
return v
end
local lspautocmds = vim.api.nvim_create_augroup('LSPAutoCmds', { clear = true, })
vim.api.nvim_create_autocmd("LspAttach", {
group = lspautocmds,
callback = function(args)
local bufnr = args.buf
local fzf_lua = require('fzf-lua')
local client_id = args.data.client_id
local client = vim.lsp.get_client_by_id(client_id)
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, { buffer = bufnr, desc = '[G]o to [D]efinition' })
vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, { buffer = bufnr, desc = '[G]o to [D]eclaration' })
-- vim.keymap.set('n', '<Leader>ca', vim.lsp.buf.code_action, { buffer = bufnr, desc = '[C]ode [A]ction' })
vim.keymap.set('n', '<Leader>rn', vim.lsp.buf.rename, { buffer = bufnr, desc = '[R]e[n]ame' })
vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = bufnr, desc = 'Hover Documentation' })
vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_)
vim.lsp.buf.format()
end, { desc = 'Format current buffer with LSP' })
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous diagnostic message' })
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next diagnostic message' })
vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float, { desc = 'Open floating diagnostic message' })
vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, { desc = 'Open diagnostics list' })
-- fzf-lua
vim.keymap.set('n', 'gr', fzf_lua.lsp_references, { buffer = bufnr, desc = '[G]o to [D]efinition' })
vim.keymap.set('n', '<Leader>ca', fzf_lua.lsp_code_actions, { buffer = bufnr, desc = '[C]ode [A]ction' })
-- vim.lsp.completion.enable(true, client_id, bufnr, { autotrigger = true })
end
})
vim.api.nvim_create_autocmd('FileType', {
group = lspautocmds,
pattern = 'lua',
callback = function(ev)
vim.lsp.start({
name = "lua_ls",
cmd = { 'lua-language-server' },
root_dir = vim.fs.root(ev.buf, { '.luarc.json', '.luarc.jsonc' }),
on_init = function(client)
client.settings.Lua = {
runtime = {
version = "LuaJIT",
},
workspace = {
library = {
"/usr/share/nvim/runtime",
"/usr/lib/lua-language-server/meta/3rd/luv/library"
},
},
}
end,
settings = {
Lua = {},
},
})
end,
})
-- handler for dart/textDocument/publishClosingLabels
local namespace = vim.api.nvim_create_namespace("flutter_closing_tags")
local function closing_tags(error, result, ctx, config)
vim.api.nvim_buf_clear_namespace(0, namespace, 0, -1)
for _, item in ipairs(result.labels) do
local line = tonumber(item.range["end"].line)
if line <= vim.api.nvim_buf_line_count(0) then
vim.api.nvim_buf_set_extmark(0, namespace, line, -1, {
virt_text = { {
"// " .. item.label,
"Comment",
} },
virt_text_pos = "eol",
hl_mode = "combine",
})
end
end
end
vim.api.nvim_create_autocmd('FileType', {
group = lspautocmds,
pattern = 'dart',
callback = function(ev)
vim.lsp.start({
name = "dartls",
cmd = { 'dart', 'language-server', '--protocol=lsp' },
root_dir = vim.fs.root(ev.buf, { 'pubspec.yaml' }),
init_options = {
closingLabels = true,
flutterOutline = true,
onlyAnalyzeProjectsWithOpenFiles = true,
outline = true,
suggestFromUnimportedLibraries = true
},
-- capabilities = require('cmp_nvim_lsp').default_capabilities(),
capabilities = vim.lsp.protocol.make_client_capabilities(),
settings = {
dart = {
completeFunctionCalls = true,
showTodos = true,
enableSnippets = true,
documentation = "full",
},
},
handlers = {
["dart/textDocument/publishClosingLabels"] = closing_tags
}
})
vim.opt.commentstring = "// %s"
end,
})
-- Todo: Make this better.
vim.keymap.set({ 'n', 'i' }, '<M-p>', function()
local dirpath = vim.fn.expand('%:p:h') .. '/img'
local imgname = os.time() .. '.png'
-- A shell script to paste image from clipboard into subdir img
local shell_script = string.format([[
DIRPATH=%s
IMGFNAME=%s
if ! [ -d $DIRPATH ]
then
mkdir $DIRPATH
fi
xclip -selection clipboard -t image/png -o > $DIRPATH/$IMGFNAME
]], dirpath, imgname)
vim.fn.system(shell_script)
-- All this is just to insert markdown image link
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
local lines = vim.api.nvim_buf_get_lines(0, row - 1, row, false)
local markdown_link = string.format("![%s](img/%s)", imgname, imgname)
-- Check if the 'lines' table is empty
local line = ""
if #lines ~= 0 then
line = lines[1]:gsub("\n", " ")
end
local new_line = line .. markdown_link
vim.api.nvim_buf_set_lines(0, row - 1, row, false, { new_line })
vim.api.nvim_win_set_cursor(0, { row, col + #markdown_link })
end, { desc = "Paste screenshot" })
vim.cmd('colorscheme vector')
require 'nvim-treesitter.parsers'.get_parser_configs().dart = {
install_info = {
files = { "src/parser.c", "src/scanner.c" },
url = "https://github.com/vectorspacexyz/tree-sitter-dart"
},
-- Optional: list of maintainers
maintainers = { "@vectorspacexyz" }
}
require 'nvim-treesitter.configs'.setup {
ensure_installed = { "c", "lua", "vim", "vimdoc", "query", "markdown", "markdown_inline" },
highlight = {
enable = true,
additional_vim_regex_highlighting = true,
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = "gnn", -- set to `false` to disable one of the mappings
node_incremental = "grn",
scope_incremental = "grc",
node_decremental = "grm",
},
},
}
local cmp = require 'cmp'
cmp.setup {
sources = {
{ name = 'nvim_lsp' }
},
mapping = cmp.mapping.preset.insert({
["<C-n>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-p>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-b>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
-- ["<C-e>"] = cmp.mapping.abort(),
-- ["<C-y>"] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
["<C-Y>"] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
}),
}
local fold_named_arg_func = function()
local allowed_types = {
["selector"] = true,
["named_argument"] = true,
["list_literal"] = true
}
local ts_utils = require('nvim-treesitter.ts_utils')
local winid = vim.fn.win_getid()
local nuc = ts_utils.get_node_at_cursor(winid)
local cn = nuc
while cn ~= nil and allowed_types[cn:type()] == nil
do
cn = cn:parent()
end
local start_row
local end_row
if cn ~= nil then
start_row, _, end_row, _ = cn:range()
vim.cmd(start_row + 1 .. "," .. end_row + 1 .. "fold")
end
end
local fold_node = function()
local ts_utils = require('nvim-treesitter.ts_utils')
local cn = ts_utils.get_node_at_cursor(0)
while cn ~= nil
do
local node_start_row, _, node_end_row, _ = cn:range()
if node_end_row == node_start_row then
cn = cn:parent()
else
vim.cmd(node_start_row + 1 .. "," .. node_end_row + 1 .. "fold")
break
end
end
end
vim.keymap.set('n', '<C-f>', function()
local fold_level = vim.fn.foldlevel('.')
local fold_closed = vim.fn.foldclosed('.')
if fold_level > 0 then
if fold_closed == -1 then
-- fold_named_arg_func()
fold_node()
else
vim.cmd("foldopen")
end
else
-- fold_named_arg_func()
fold_node()
end
end)
local cursor_to_node_ends = function()
local ts_utils = require('nvim-treesitter.ts_utils')
local nuc = ts_utils.get_node_at_cursor(0)
local node_start_row, node_start_col, node_end_row, node_end_col = nuc:range()
local current_cursor = vim.api.nvim_win_get_cursor(0)
local current_cursor_row = current_cursor[1] - 1
local current_cursor_col = current_cursor[2]
-- print(current_cursor_row, current_cursor_col, node_start_row, node_start_col, node_end_row, node_end_col)
-- check if at beginning of node, if so go to end
if current_cursor_row == node_start_row and current_cursor_col == node_start_col then
vim.api.nvim_win_set_cursor(0, { node_end_row + 1, node_end_col - 1 })
elseif current_cursor_row == node_end_row and current_cursor_col == node_end_col then
vim.api.nvim_win_set_cursor(0, { node_start_row + 1, node_start_col })
else
vim.api.nvim_win_set_cursor(0, { node_start_row + 1, node_start_col })
end
end
vim.keymap.set('n', '<C-e>', cursor_to_node_ends)
require('mkdnflow').setup({
links = {
transform_explicit = false,
},
mappings = {
MkdnDecreaseHeading = false,
},
})
require("oil").setup()
vim.keymap.set("n", "-", ":Oil<CR>", { desc = "Open parent directory" })
vim.opt.fillchars = { eob = "-", fold = " " }
vim.opt.foldtext = 'v:lua.MyFoldText()'
function MyFoldText()
local start_line = vim.fn.getline(vim.v.foldstart)
local end_line = vim.fn.getline(vim.v.foldend)
end_line = end_line:gsub("^%s+", "")
return start_line .. " ... " .. end_line
end
vim.keymap.set("v", "<C-f>", ":fold<CR>", { desc = "fold" })
-- primeagen: https://youtu.be/w7i4amO_zaE?t=1543
-- https://github.com/ThePrimeagen/init.lua/blob/master/lua/theprimeagen/remap.lua
vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv")
vim.keymap.set("v", "K", ":m '<-2<CR>gv=gv")
vim.keymap.set("n", "J", "mzJ`z")
vim.keymap.set("n", "<C-d>", "<C-d>zz")
vim.keymap.set("n", "<C-u>", "<C-u>zz")
vim.keymap.set("n", "n", "nzzzv")
vim.keymap.set("n", "N", "Nzzzv")
-- greatest remap ever
vim.keymap.set("x", "<leader>p", [["_dP]])
require("nvim-tree").setup({
update_focused_file = {
enable = true,
update_root = false,
ignore_list = {},
},
view = {
preserve_window_proportions = true,
},
actions = {
open_file = {
resize_window = false,
},
},
})
vim.keymap.set('n', '<C-n>', require("nvim-tree.api").tree.toggle,
{ desc = "Toggle nvim-tree" })
-- require("ibl").setup({
-- debounce = 100,
-- -- indent = { char = "|" },
-- -- indent = { char = "│" },
-- indent = {
-- char = "│",
-- smart_indent_cap = true,
-- },
-- scope = {
-- enabled = true,
-- show_start = true,
-- show_end = true,
-- },
-- })
-- -- https://github.com/nvim-telescope/telescope.nvim
-- local builtin = require('telescope.builtin')
-- vim.keymap.set('n', '<leader>ff', builtin.find_files, { desc = 'Telescope find files' })
-- vim.keymap.set('n', '<leader>fg', builtin.live_grep, { desc = 'Telescope live grep' })
-- vim.keymap.set('n', '<leader>fb', builtin.buffers, { desc = 'Telescope buffers' })
-- vim.keymap.set('n', '<leader>fh', builtin.help_tags, { desc = 'Telescope help tags' })
--
-- -- This is your opts table
-- require("telescope").setup {
-- defaults = {
-- mappings = {
-- i = {
-- ["<C-y>"] = "select_default",
-- }
-- }
-- },
-- extensions = {
-- ["ui-select"] = {
-- require("telescope.themes").get_dropdown {
-- -- even more opts
-- }
--
-- -- pseudo code / specification for writing custom displays, like the one
-- -- for "codeactions"
-- -- specific_opts = {
-- -- [kind] = {
-- -- make_indexed = function(items) -> indexed_items, width,
-- -- make_displayer = function(widths) -> displayer
-- -- make_display = function(displayer) -> function(e)
-- -- make_ordinal = function(e) -> string
-- -- },
-- -- -- for example to disable the custom builtin "codeactions" display
-- -- do the following
-- -- codeactions = false,
-- -- }
-- }
-- }
-- }
-- -- To get ui-select loaded and working with telescope, you need to call
-- -- load_extension, somewhere after setup function:
-- require("telescope").load_extension("ui-select")
-- fzf-lua bindings
local fzf_lua = require('fzf-lua')
vim.keymap.set('n', '<Leader>ff', fzf_lua.files, { desc = 'find files'})