summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/essentials/vis/Makefile9
-rw-r--r--config/essentials/vis/format.lua217
-rw-r--r--config/essentials/vis/fzf-mru.lua75
-rw-r--r--config/essentials/vis/fzf-open.lua81
-rw-r--r--config/essentials/vis/vis-go.lua102
-rw-r--r--config/essentials/vis/vis-ultisnips/init.lua149
-rw-r--r--config/essentials/vis/vis-ultisnips/snipmate-parser.lua128
-rw-r--r--config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua160
-rw-r--r--config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua230
-rw-r--r--config/essentials/vis/vis-ultisnips/ultisnips-parser.lua211
-rw-r--r--config/essentials/vis/visrc.lua33
-rw-r--r--config/essentials/vis/yank-highlight.lua37
12 files changed, 1311 insertions, 121 deletions
diff --git a/config/essentials/vis/Makefile b/config/essentials/vis/Makefile
index 1599b58..f2d386b 100644
--- a/config/essentials/vis/Makefile
+++ b/config/essentials/vis/Makefile
@@ -1,11 +1,6 @@
-.PHONY: check format all
+.PHONY: check
-LUA_FILES := $(shell find . -name "*.lua")
-
-all: format check
+LUA_FILES := $(shell find . -type f -name "*.lua")
check:
luacheck --no-color --globals=vis -- $(LUA_FILES)
-
-format:
- lua-format -i $(LUA_FILES)
diff --git a/config/essentials/vis/format.lua b/config/essentials/vis/format.lua
index 15488dd..e39320e 100644
--- a/config/essentials/vis/format.lua
+++ b/config/essentials/vis/format.lua
@@ -1,131 +1,134 @@
-local global_options = {check_same = true}
+local global_options = { check_same = true }
local function stdio_formatter(cmd, options)
- local function apply(win, range, pos)
- local size = win.file.size
- local all = {start = 0, finish = size}
- if range == nil then range = all end
- local command = type(cmd) == 'function' and cmd(win, range, pos) or cmd
- local check_same = (options and options.check_same ~= nil) and
- options.check_same or global_options.check_same
- local check = check_same == true or
- (type(check_same) == 'number' and check_same >= size)
- local status, out, err = vis:pipe(win.file, all, command)
- if status ~= 0 then
- vis:message(err)
- elseif out == nil or out == '' then
- vis:info('No output from formatter')
- elseif not check or win.file:content(all) ~= out then
- local start, finish = range.start, range.finish
- win.file:delete(range)
- win.file:insert(start,
- out:sub(start + 1, finish + (out:len() - size)))
- end
- return pos
- end
- return {
- apply = apply,
- options = options or {ranged = type(cmd) == 'function'}
- }
+ local function apply(win, range, pos)
+ local size = win.file.size
+ local all = { start = 0, finish = size }
+ if range == nil then
+ range = all
+ end
+ local command = type(cmd) == "function" and cmd(win, range, pos) or cmd
+ local check_same = (options and options.check_same ~= nil) and options.check_same or global_options.check_same
+ local check = check_same == true or (type(check_same) == "number" and check_same >= size)
+ local status, out, err = vis:pipe(win.file, all, command)
+ if status ~= 0 then
+ vis:message(err)
+ elseif out == nil or out == "" then
+ vis:info("No output from formatter")
+ elseif not check or win.file:content(all) ~= out then
+ local start, finish = range.start, range.finish
+ win.file:delete(range)
+ win.file:insert(start, out:sub(start + 1, finish + (out:len() - size)))
+ end
+ return pos
+ end
+ return {
+ apply = apply,
+ options = options or { ranged = type(cmd) == "function" },
+ }
end
local function with_filename(win, option)
- if win.file.path then
- return option .. "'" .. win.file.path:gsub("'", "\\'") .. "'"
- else
- return ''
- end
+ if win.file.path then
+ return option .. "'" .. win.file.path:gsub("'", "\\'") .. "'"
+ else
+ return ""
+ end
end
local formatters = {}
formatters = {
- bash = stdio_formatter(function(win)
- return 'shfmt ' .. with_filename(win, '--filename ') .. ' -'
- end),
- csharp = stdio_formatter('dotnet csharpier'),
- go = stdio_formatter('gofmt'),
- lua = {
- pick = function(win)
- local _, out = vis:pipe(win.file,
- {start = 0, finish = win.file.size},
- 'test -e .lua-format && echo luaformatter || echo stylua')
- return formatters[out:gsub('\n$', '')]
- end
- },
- luaformatter = stdio_formatter('lua-format'),
- markdown = stdio_formatter(function(win)
- if win.options and win.options.colorcolumn ~= 0 then
- return 'prettier --parser markdown --prose-wrap always ' ..
- ('--print-width ' .. (win.options.colorcolumn - 1) .. ' ') ..
- with_filename(win, '--stdin-filepath ')
- else
- return 'prettier --parser markdown ' ..
- with_filename(win, '--stdin-filepath ')
- end
- end, {ranged = false}),
- powershell = stdio_formatter([[
+ bash = stdio_formatter(function(win)
+ return "shfmt " .. with_filename(win, "--filename ") .. " -"
+ end),
+ csharp = stdio_formatter("dotnet csharpier"),
+ go = stdio_formatter("gofmt"),
+ lua = {
+ pick = function(win)
+ local _, out = vis:pipe(
+ win.file,
+ { start = 0, finish = win.file.size },
+ "test -e .lua-format && echo luaformatter || echo stylua"
+ )
+ return formatters[out:gsub("\n$", "")]
+ end,
+ },
+ luaformatter = stdio_formatter("lua-format"),
+ markdown = stdio_formatter(function(win)
+ if win.options and win.options.colorcolumn ~= 0 then
+ return "prettier --parser markdown --prose-wrap always "
+ .. ("--print-width " .. (win.options.colorcolumn - 1) .. " ")
+ .. with_filename(win, "--stdin-filepath ")
+ else
+ return "prettier --parser markdown " .. with_filename(win, "--stdin-filepath ")
+ end
+ end, { ranged = false }),
+ powershell = stdio_formatter([[
"$( (command -v powershell.exe || command -v pwsh) 2>/dev/null )" -c '
Invoke-Formatter -ScriptDefinition `
([IO.StreamReader]::new([Console]::OpenStandardInput()).ReadToEnd())
' | sed -e :a -e '/^[\r\n]*$/{$d;N;};/\n$/ba'
]]),
- rust = stdio_formatter('rustfmt'),
- stylua = stdio_formatter(function(win, range)
- if range and (range.start ~= 0 or range.finish ~= win.file.size) then
- return
- 'stylua -s --range-start ' .. range.start .. ' --range-end ' ..
- range.finish .. with_filename(win, ' --stdin-filepath ') ..
- ' -'
- else
- return 'stylua -s ' .. with_filename(win, '--stdin-filepath ') ..
- ' -'
- end
- end),
- text = stdio_formatter(function(win)
- if win.options and win.options.colorcolumn ~= 0 then
- return 'fmt -w ' .. (win.options.colorcolumn - 1)
- else
- return 'fmt'
- end
- end, {ranged = false})
+ rust = stdio_formatter("rustfmt"),
+ stylua = stdio_formatter(function(win, range)
+ if range and (range.start ~= 0 or range.finish ~= win.file.size) then
+ return "stylua -s --range-start "
+ .. range.start
+ .. " --range-end "
+ .. range.finish
+ .. with_filename(win, " --stdin-filepath ")
+ .. " -"
+ else
+ return "stylua -s " .. with_filename(win, "--stdin-filepath ") .. " -"
+ end
+ end),
+ text = stdio_formatter(function(win)
+ if win.options and win.options.colorcolumn ~= 0 then
+ return "fmt -w " .. (win.options.colorcolumn - 1)
+ else
+ return "fmt"
+ end
+ end, { ranged = false }),
}
local function getwinforfile(file)
- for win in vis:windows() do
- if win and win.file and win.file.path == file.path then
- return win
- end
- end
+ for win in vis:windows() do
+ if win and win.file and win.file.path == file.path then
+ return win
+ end
+ end
end
local function apply(file_or_keys, range, pos)
- local win =
- type(file_or_keys) ~= 'string' and getwinforfile(file_or_keys) or
- vis.win
- local ret = type(file_or_keys) ~= 'string' and function() return pos end or
- function() return 0 end
- pos = pos or win.selection.pos
- local formatter = formatters[win.syntax]
- if formatter and formatter.pick then formatter = formatter.pick(win) end
- if formatter == nil then
- vis:info('No formatter for ' .. win.syntax)
- return ret()
- end
- if range ~= nil and not formatter.options.ranged and range.start ~= 0 and
- range.finish ~= win.file.size then
- vis:info('Formatter for ' .. win.syntax .. ' does not support ranges')
- return ret()
- end
- pos = formatter.apply(win, range, pos) or pos
- vis:insert('') -- redraw and friends don't work
- win.selection.pos = pos
- return ret()
+ local win = type(file_or_keys) ~= "string" and getwinforfile(file_or_keys) or vis.win
+ local ret = type(file_or_keys) ~= "string" and function()
+ return pos
+ end or function()
+ return 0
+ end
+ pos = pos or win.selection.pos
+ local formatter = formatters[win.syntax]
+ if formatter and formatter.pick then
+ formatter = formatter.pick(win)
+ end
+ if formatter == nil then
+ vis:info("No formatter for " .. win.syntax)
+ return ret()
+ end
+ if range ~= nil and not formatter.options.ranged and range.start ~= 0 and range.finish ~= win.file.size then
+ vis:info("Formatter for " .. win.syntax .. " does not support ranges")
+ return ret()
+ end
+ pos = formatter.apply(win, range, pos) or pos
+ vis:redraw()
+ win.selection.pos = pos
+ return ret()
end
return {
- formatters = formatters,
- options = global_options,
- apply = apply,
- stdio_formatter = stdio_formatter,
- with_filename = with_filename
+ formatters = formatters,
+ options = global_options,
+ apply = apply,
+ stdio_formatter = stdio_formatter,
+ with_filename = with_filename,
}
diff --git a/config/essentials/vis/fzf-mru.lua b/config/essentials/vis/fzf-mru.lua
new file mode 100644
index 0000000..6c2510d
--- /dev/null
+++ b/config/essentials/vis/fzf-mru.lua
@@ -0,0 +1,75 @@
+local module = {}
+module.fzfmru_filepath = os.getenv("XDG_CACHE_HOME") .. "/vis-fzf-mru"
+module.fzfmru_path = "fzf"
+module.fzfmru_args = "--height=40%"
+module.fzfmru_history = 20
+
+local function read_mru()
+ local mru = {}
+ local f = io.open(module.fzfmru_filepath)
+ if f == nil then return end
+ for line in f:lines() do table.insert(mru, line) end
+ f:close()
+
+ return mru
+end
+
+local function write_mru(win)
+ local file_path = win.file.path
+ local mru = read_mru()
+
+ -- check if mru data exists
+ if mru == nil then mru = {} end
+ -- check if we opened any file
+ if file_path == nil then return end
+ -- check duplicate
+ if file_path == mru[1] then return end
+
+ local f = io.open(module.fzfmru_filepath, "w+")
+ if f == nil then return end
+
+ table.insert(mru, 1, file_path)
+
+ for i, k in ipairs(mru) do
+ if i > module.fzfmru_history then break end
+ if i == 1 or k ~= file_path then
+ f:write(string.format("%s\n", k))
+ end
+ end
+
+ f:close()
+end
+
+vis.events.subscribe(vis.events.WIN_OPEN, write_mru)
+
+vis:command_register("fzfmru", function(argv)
+ local command = "cat " .. module.fzfmru_filepath .. " | " ..
+ module.fzfmru_path .. " " .. module.fzfmru_args .. " " ..
+ table.concat(argv, " ")
+
+ local file = io.popen(command)
+ local output = file:read()
+ local _, _, status = file:close()
+
+ if status == 0 then
+ vis:command(string.format("e '%s'", output))
+ elseif status == 1 then
+ vis:info(string.format(
+ "fzf-open: No match. Command %s exited with return value %i.",
+ command, status))
+ elseif status == 2 then
+ vis:info(string.format(
+ "fzf-open: Error. Command %s exited with return value %i.",
+ command, status))
+ elseif status ~= 130 then
+ vis:info(string.format(
+ "fzf-open: Unknown exit status %i. command %s exited with return value %i",
+ status, command, status, status))
+ end
+
+ vis:redraw()
+
+ return true
+end)
+
+return module
diff --git a/config/essentials/vis/fzf-open.lua b/config/essentials/vis/fzf-open.lua
new file mode 100644
index 0000000..1c9d1e6
--- /dev/null
+++ b/config/essentials/vis/fzf-open.lua
@@ -0,0 +1,81 @@
+-- Copyright (C) 2017 Guillaume Chérel
+-- Copyright (C) 2023 Matěj Cepl
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as
+-- published by the Free Software Foundation, either version 3 of the
+-- License, or (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+local M = {}
+
+M.fzf_path = "fzf"
+M.fzf_args = "--height=40%"
+
+vis:command_register("fzf", function(argv)
+ local fzf_path = M.fzf_path
+ if argv[1] == "--search-path" then
+ table.remove(argv, 1)
+ local dir = table.remove(argv, 1)
+ fzf_path = ([[FZF_DEFAULT_COMMAND="$FZF_DEFAULT_COMMAND --search-path ]] .. dir .. [[" fzf]])
+ end
+
+ local command = string.gsub(
+ [[
+ $fzf_path \
+ --header="Enter:edit,^s:split,^v:vsplit" \
+ --expect="ctrl-s,ctrl-v" \
+ $fzf_args $args
+ ]],
+ "%$([%w_]+)",
+ {
+ fzf_path = fzf_path,
+ fzf_args = M.fzf_args,
+ args = table.concat(argv, " "),
+ }
+ )
+
+ local file = io.popen(command)
+ local output = {}
+ for line in file:lines() do
+ table.insert(output, line)
+ end
+ local _, _, status = file:close()
+
+ if status == 0 then
+ local action = "e"
+
+ if output[1] == "ctrl-s" then
+ action = "split"
+ elseif output[1] == "ctrl-v" then
+ action = "vsplit"
+ end
+
+ vis:feedkeys(string.format(":%s '%s'<Enter>", action, output[2]))
+ elseif status == 1 then
+ vis:info(string.format("fzf-open: No match. Command %s exited with return value %i.", command, status))
+ elseif status == 2 then
+ vis:info(string.format("fzf-open: Error. Command %s exited with return value %i.", command, status))
+ elseif status ~= 130 then
+ vis:info(
+ string.format(
+ "fzf-open: Unknown exit status %i. command %s exited with return value %i",
+ status,
+ command,
+ status
+ )
+ )
+ end
+
+ vis:redraw()
+
+ return true
+end, "Select file to open with fzf")
+
+return M
diff --git a/config/essentials/vis/vis-go.lua b/config/essentials/vis/vis-go.lua
new file mode 100644
index 0000000..b0b383f
--- /dev/null
+++ b/config/essentials/vis/vis-go.lua
@@ -0,0 +1,102 @@
+local function jump_to(path, line, col)
+ if path then
+ vis:command(string.format("e %s", path))
+ end
+ vis.win.selection:to(line, col)
+end
+
+local Gostack = { s = {}, i = 1 }
+
+function Gostack:push(v)
+ self.s[self.i] = v
+ self.i = self.i + 1
+end
+
+function Gostack:pop()
+ if self.i == 1 then
+ return nil
+ end
+ self.i = self.i - 1
+ return self.s[self.i]
+end
+
+local function godef()
+ local win = vis.win
+ if win.syntax ~= "go" then
+ return 0
+ end
+
+ local file = win.file
+ local pos = win.selection.pos
+ local cmd = string.format("godef -i -o %d", pos)
+ local status, out, err = vis:pipe(file, { start = 0, finish = file.size }, cmd)
+ if status ~= 0 or not out then
+ if err then
+ vis:info(err)
+ end
+ return status
+ end
+
+ Gostack:push({ path = file.path, line = win.selection.line, col = win.selection.col })
+
+ local path, line, col = string.match(out, "([^:]+):([^:]+):([^:]+)")
+ if not path then
+ -- same file
+ line, col = string.match(out, "([^:]+):([^:]+)")
+ end
+ jump_to(path, line, col)
+end
+
+local function godef_back()
+ if vis.win.syntax ~= "go" then
+ return 0
+ end
+
+ local pos = Gostack:pop()
+ if pos then
+ jump_to(pos.path, pos.line, pos.col)
+ end
+end
+
+vis:map(vis.modes.NORMAL, "gd", godef, "Jump to Go symbol/definition")
+vis:map(vis.modes.NORMAL, "gD", godef_back, "Jump back to previous Go symbol/definition")
+
+local function gorename(argv, force, win, selection)
+ if win.syntax ~= "go" then
+ return true
+ end
+
+ local name = argv[1]
+ if not name then
+ vis:info("empty new name provided")
+ return false
+ end
+
+ local forceFlag = ""
+ if force then
+ forceFlag = "-force"
+ end
+
+ local pos = selection.pos
+ local f =
+ io.popen(string.format("gorename -offset %s:#%d -to %s %s 2>&1", win.file.path, pos, name, forceFlag), "r")
+ local out = f:read("*all")
+ local success, _, _ = f:close()
+ if not success then
+ vis:message(out)
+ return false
+ end
+
+ -- refresh current file
+ vis:command("e")
+ win.selection.pos = pos
+
+ vis:info(out)
+ return true
+end
+
+vis:command_register(
+ "gorename",
+ gorename,
+ "Perform precise type-safe renaming of identifiers in Go source code: :gorename newName"
+)
diff --git a/config/essentials/vis/vis-ultisnips/init.lua b/config/essentials/vis/vis-ultisnips/init.lua
new file mode 100644
index 0000000..52faa55
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/init.lua
@@ -0,0 +1,149 @@
+--------------------------------------------------------------------------------
+-- Modules
+
+local M = {}
+local cwd = ...
+local SnipMate = require(cwd .. '.snipmate-parser')
+local UltiSnips = require(cwd .. '.ultisnips-parser')
+
+
+
+--------------------------------------------------------------------------------
+-- Config
+
+M.snipmate = ''
+M.ultisnips = ''
+
+
+
+--------------------------------------------------------------------------------
+-- Helper functions
+
+-- Takes list of snippets and concatenates them into the string suitable
+-- for passing to dmenu (or, very probably, vis-menu)
+local function snippetslist(snippets)
+ local list = ''
+
+ for k,v in pairs(snippets) do
+ if not v.description then
+ list = list .. k .. '\n'
+ else
+ list = list .. k .. ' - ' .. v.description .. '\n'
+ end
+ end
+
+ return list
+end
+
+
+
+local function load_ultisnips()
+ local snippetfile = M.ultisnips .. vis.win.syntax .. '.snippets'
+ local snippets, success = UltiSnips.load_snippets(snippetfile)
+ if not success then
+ vis:info('Failed to load a correct UltiSnip: ' .. snippetfile)
+ end
+ return snippets, success
+end
+
+
+
+local function load_snipmate()
+ local snippetfile = M.snipmate .. vis.win.syntax .. '.snippets'
+ local snippets, success = SnipMate.load_snippets(snippetfile)
+ if not success then
+ vis:info('Failed to load a correct SnipMate: ' .. snippetfile)
+ end
+ return snippets, success
+end
+
+
+
+-- Second will append to first using suffix for distinguishing
+local function merge_and_override(snips1, snips2, suffix)
+ for k,v in pairs(snips2) do
+ snips1[k .. suffix] = v
+ end
+ return snips1
+end
+
+
+
+--------------------------------------------------------------------------------
+-- Plugging it all in
+
+vis:map(vis.modes.INSERT, "<C-x><C-j>", function()
+ local snippets = merge_and_override(load_snipmate(), load_ultisnips(), '_us')
+
+ local win = vis.win
+ local file = win.file
+ local pos = win.selection.pos
+
+ if not pos then
+ return
+ end
+ -- TODO do something clever here
+
+ -- Use prefix W if exists
+ local initial = ' '
+ local range = file:text_object_longword(pos > 0 and pos - 1 or pos)
+ if range then
+ initial = initial .. file:content(range)
+ end
+
+ -- Note, for one reason or another, using vis-menu corrupts my terminal
+ -- (urxvt) for exact amount of lines that vis-menu takes
+ -- dmenu has no such problems, but can't take initial input :-\
+ --local stdout = io.popen("echo '" .. snippetslist(snippets) .. "' | dmenu -l 5", "r")
+ local stdout = io.popen("echo '" .. snippetslist(snippets) .. "' | vis-menu " .. initial, "r")
+ local chosen = stdout:lines()()
+ local _, msg, status = stdout:close()
+ if status ~= 0 or not chosen then
+ vis:message(msg)
+ return
+ end
+
+ local trigger = chosen:gmatch('[^ ]+')()
+ local snipcontent = snippets[trigger].content
+ if range then
+ file:delete(range)
+ -- Update position after deleting the range
+ pos = pos - (range.finish - range.start)
+ vis:redraw()
+ end
+
+ vis:insert(snipcontent.str)
+
+
+ if #snipcontent.tags > 0 then
+ vis:info("Use 'g>' and 'g<' to navigate between anchors.")
+
+ -- Create selections iteratively using `:#n,#n2 p` command and `gs` to
+ -- save it in the jumplist
+ for _,v in ipairs(snipcontent.tags) do
+ -- Can't use 'x' command because it'd select stuff across
+ -- whole file
+ vis:command('#' .. pos + v.selstart ..',#' .. pos + v.selend .. ' p')
+ --vis:feedkeys('gs') -- Tested, works without this too, but just in case
+ --vis:message('Command: ' .. cmd)
+ end
+
+ -- Backtrack through all selections we've made first
+ -- (so that we can use g> to move us forward)...
+ for _ in ipairs(snipcontent.tags) do
+ vis:feedkeys('g<')
+ end
+
+ -- ... then set us on the first selection
+ vis:feedkeys('g>')
+ else
+ win.selection.pos = pos + #snipcontent.str
+ end
+end, "Insert a snippet")
+
+
+
+--------------------------------------------------------------------------------
+-- End module
+
+return M \ No newline at end of file
diff --git a/config/essentials/vis/vis-ultisnips/snipmate-parser.lua b/config/essentials/vis/vis-ultisnips/snipmate-parser.lua
new file mode 100644
index 0000000..9d735f1
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/snipmate-parser.lua
@@ -0,0 +1,128 @@
+--------------------------------------------------------------------------------
+-- Module table
+
+local M = {}
+
+local lpeg = require('lpeg')
+
+
+
+--------------------------------------------------------------------------------
+-- lpeg rules
+
+-- Base definitions
+-- local tws = lpeg.S' ' ^ 1
+local tnewline = lpeg.S'\n'
+-- local tlowcasedword = lpeg.R'az' ^ 1
+local tdigit = lpeg.locale()['digit']
+local talphanum = lpeg.locale()['alnum']
+local tanyprintable = lpeg.locale()['print']
+-- local tcontrol = lpeg.locale()['cntrl']
+local ttabtrigger = tanyprintable ^ 1
+local ttag = lpeg.Cg(lpeg.Cp(), 'selstart')
+ * lpeg.P'${'
+ * lpeg.Cg(tdigit^1, 'tag-order')
+ * (
+ (lpeg.S':' * lpeg.Cg(talphanum^1, 'default-value') * lpeg.S'}')
+ + lpeg.S'}'
+ )
+ * lpeg.Cg(lpeg.Cp(), 'selend')
+local tsnippetdecl = lpeg.P'snippet' * lpeg.S' ' * lpeg.Cg(ttabtrigger, 'tabtrigger') * tnewline
+local tsnippetcontent = lpeg.C(
+ lpeg.Cp() *
+ (lpeg.S'\t '^1
+ * (lpeg.Ct(ttag) + tanyprintable)^1
+ * tnewline
+ )^1
+ )
+
+-- Constructs
+local tsnippet = tsnippetdecl * tsnippetcontent
+local tcomment = lpeg.S'#' * tanyprintable^0 * tnewline
+
+-- The way grammar captures:
+-- Every snippet gets its own table, and every table has:
+-- 'tabtrigger' - the tabtrigger
+-- [1] - full content
+-- [2] - start of snippet content (need to subtract from selstart/selend
+-- [3..n] - tags
+local tsnippetsfile = lpeg.Ct((tcomment + lpeg.Ct(tsnippet) + tnewline) ^1)
+
+--------------------------------------------------------------------------------
+-- Functions
+
+local function trim_tabs(content)
+ local trim = function (s)
+ return (string.gsub(s, "^\t(.-)$", "%1"))
+ end
+
+ local ret=''
+ for str in string.gmatch(content, '([^\n]+)') do
+ ret = ret .. trim(str) .. '\n'
+ end
+ return ret
+end
+
+-- Tags are on the top level of th table,
+-- defined starting with index '3'
+-- Index '2' is start of the content
+-- Structure:
+-- { tag-order: int
+-- , selstart: int
+-- , selend: int
+-- , default-value: str
+-- }
+local function extract_tags(tableau)
+ local tags = {}
+ for k,v in ipairs(tableau) do
+ if k >= 3 then -- Only process starting with ix 2
+ tags[k - 2] = { selstart = v.selstart - tableau[2] - 1
+ , selend = v.selend - tableau[2] - 1
+ , default = v['default-value']
+ , order = v['tag-order']
+ }
+-- vis:message('snippet ' .. tableau.tabtrigger .. ' tag ' ..
+-- tostring(tags[k - 1].order) .. ' has start/end: ' ..
+-- tostring(tags[k - 1].selstart) .. '/' ..
+-- tostring(tags[k - 1].selend))
+ end
+ end
+ return tags
+end
+
+M.load_snippets = function(snippetfile)
+ local snippets = {}
+
+ local f = io.open(snippetfile, 'r')
+ if f then
+ local content = f:read("*all")
+
+ -- TODO hmmm, this'll make whole file unsuable, when it could
+ -- in fact have usable snippets
+ local m = tsnippetsfile:match(content)
+ if not m then
+ vis:info('Failed to parse SnipMate file: '.. snippetfile)
+ return nil
+ else
+ -- k is index of snippet definition, v is table of snippet def
+ for _,v in pairs(m) do
+ snippets[v.tabtrigger] = { description = nil
+ , options = {}
+ , content = { str = trim_tabs(v[1])
+ , tags = extract_tags(v)
+ }
+ }
+ end
+ end
+
+ f:close()
+ return snippets, true
+ else
+ return snippets, false
+ end
+end
+
+--------------------------------------------------------------------------------
+-- End module
+
+return M
diff --git a/config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua b/config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua
new file mode 100644
index 0000000..997365f
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/testlpeg-snipmate.lua
@@ -0,0 +1,160 @@
+local lpeg = require("lpeg")
+
+--------------------------------------------------------------------------------
+
+-- Base definitions
+-- local tws = lpeg.S(" ") ^ 1
+local tnewline = lpeg.S("\n")
+-- local tlowcasedword = lpeg.R("az") ^ 1
+local tdigit = lpeg.locale()["digit"]
+local talphanum = lpeg.locale()["alnum"]
+local tanyprintable = lpeg.locale()["print"]
+-- local tcontrol = lpeg.locale()["cntrl"]
+local ttabtrigger = tanyprintable ^ 1
+local ttag = lpeg.Cg(lpeg.Cp(), "selstart")
+ * lpeg.P("${")
+ * lpeg.Cg(tdigit ^ 1, "tag-order")
+ * ((lpeg.S(":") * lpeg.Cg(talphanum ^ 1, "default-value") * lpeg.S("}")) + lpeg.S("}"))
+ * lpeg.Cg(lpeg.Cp(), "selend")
+local tsnippetdecl = lpeg.P("snippet") * lpeg.S(" ") * lpeg.Cg(ttabtrigger, "tabtrigger") * tnewline
+local tsnippetcontent = lpeg.C(lpeg.Cp() * (lpeg.S("\t ") ^ 1 * (lpeg.Ct(ttag) + tanyprintable) ^ 1 * tnewline) ^ 1)
+
+-- Constructs
+local tsnippet = tsnippetdecl * tsnippetcontent
+local tcomment = lpeg.S("#") * tanyprintable ^ 0 * tnewline
+
+-- The way grammar captures:
+-- Every snippet gets its own table, and every table has:
+-- 'tabtrigger' - the tabtrigger
+-- [1] - full content
+-- [2..n] - tags
+local tsnippetsfile = lpeg.Ct((tcomment + lpeg.Ct(tsnippet) + tnewline) ^ 1)
+--------------------------------------------------------------------------------
+
+-- local testsingle = [[
+-- snippet sim
+-- ${1:public} static int Main(string[] args)
+-- {
+-- ${0}
+-- return 0;
+-- }
+-- ]]
+
+-- local testmulti = [[
+-- snippet sim
+-- ${1:public} static int Main(string[] args)
+-- {
+-- ${0}
+-- return 0;
+-- }
+-- snippet simc
+-- public class Application
+-- {
+-- ${1:public} static int Main(string[] args)
+-- {
+-- ${0}
+-- return 0;
+-- }
+-- }
+-- snippet svm
+-- ${1:public} static void Main(string[] args)
+-- {
+-- ${0}
+-- }
+-- ]]
+
+local testfile = [[
+# I'll most propably add more stuff in here like
+# * List/Array constructio
+# * Mostly used generics
+# * Linq
+# * Funcs, Actions, Predicates
+# * Lambda
+# * Events
+#
+# Feedback is welcome!
+#
+# Main
+snippet sim
+ ${1:public} static int Main(string[] args)
+ {
+ ${0}
+ return 0;
+ }
+snippet simc
+ public class Application
+ {
+ ${1:public} static int Main(string[] args)
+ {
+ ${0}
+ return 0;
+ }
+ }
+snippet svm
+ ${1:public} static void Main(string[] args)
+ {
+ ${0}
+ }
+# if condition
+snippet if
+ if (${1:true})
+ {
+ ${0:${VISUAL}}
+ }
+snippet el
+ else
+ {
+ ${0:${VISUAL}}
+ }
+]]
+
+--------------------------------------------------------------------------------
+-- Test
+
+local function print_table(tableau, tabwidth)
+ if tabwidth == nil then
+ tabwidth = 0
+ end
+
+ -- Iterate
+ for k, v in pairs(tableau) do
+ local tabs = ("\t"):rep(tabwidth)
+
+ print(tabs .. k .. ':"' .. tostring(v) .. '"')
+ if type(v) == "table" then
+ print_table(v, tabwidth + 1)
+ end
+ end
+end
+
+--print("------------ header ------------------------------------")
+--p = lpeg.Ct(tsnippetdecl)
+--t = p:match([[
+--snippet classy
+--]])
+--print_table(t)
+--print("--------------------------------------------------------------")
+
+--print("------------ tag ------------------------------------")
+--print_table(
+-- lpeg.Ct(ttag):match('${0:VISUAL}')
+--)
+--print_table(
+-- lpeg.Ct(ttag):match('${12:Badonkadong}')
+--)
+--print_table(
+-- lpeg.Ct(ttag):match('${1}')
+--)
+--print("--------------------------------------------------------------")
+
+--print("------------ single snippet test ------------------------------------")
+--print_table(lpeg.Ct(tsnippet):match(testsingle))
+--print("--------------------------------------------------------------")
+
+--print("------------ multi snippet test ------------------------------------")
+--print_table(lpeg.Ct(tsnippetsfile):match(testmulti))
+--print("--------------------------------------------------------------")
+
+print("------------ file with comments -------------------------------------")
+print_table(tsnippetsfile:match(testfile))
+print("--------------------------------------------------------------")
diff --git a/config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua b/config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua
new file mode 100644
index 0000000..79df900
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/testlpeg-ultisnips.lua
@@ -0,0 +1,230 @@
+local lpeg = require("lpeg")
+
+--------------------------------------------------------------------------------
+
+local tsep = lpeg.S(" ")
+local tws = tsep ^ 1
+local tnewline = lpeg.S("\n")
+local tlowcasedword = lpeg.R("az") ^ 1
+local tdigit = lpeg.locale()["digit"]
+-- local talphanum = lpeg.locale()['alnum']
+local tanyprintable = lpeg.locale()["print"]
+local tcontrol = lpeg.locale()["cntrl"]
+local function quoted(p)
+ return lpeg.S('"') * p * lpeg.S('"')
+end
+local function anythingbut(ch)
+ return (tanyprintable + tcontrol) - lpeg.S(ch)
+end
+
+local ttabtriggercomplex = quoted(tlowcasedword * lpeg.S("()[]?0123456789-") ^ 1)
+-- TODO This is just retarded
+local ttabtriggerweird = lpeg.S("!") * (lpeg.R("az") + lpeg.S("?()")) ^ 1 * lpeg.S("!")
+local ttabtriggerweird2 = lpeg.P("#!")
+local ttabtrigger = ttabtriggercomplex + ttabtriggerweird + ttabtriggerweird2 + tlowcasedword
+local tdescription = quoted(lpeg.Cg((tanyprintable - lpeg.S('"')) ^ 1, "description"))
+local toption = lpeg.R("az")
+
+local tstartsnippet = lpeg.P("snippet")
+ * tws
+ * lpeg.Cg(ttabtrigger, "tabtrigger")
+ * tws
+ * tdescription
+ * tws ^ 0
+ * lpeg.Cg(toption ^ 0, "options")
+local tendsnippet = lpeg.P("endsnippet")
+
+-- The content parsing needs cleanup, its really convoluted due to me learning
+-- lpeg while using it
+--tcontent = ((tanyprintable + tcontrol)^1 - tendsnippet) * tnewline
+local tcontent = ((lpeg.S(" \t") + tanyprintable) ^ 1 - tendsnippet) * tnewline
+local tsnippet = tstartsnippet * tnewline * ((tendsnippet * tnewline) + lpeg.Cg(tcontent ^ 1, "content"))
+
+local tcomment = lpeg.S("#") * tanyprintable ^ 0 * tnewline
+local tpriority = lpeg.P("priority") * tws * lpeg.Cg(lpeg.S("-") ^ 0 * tdigit ^ 1, "priority")
+
+-- TODO doesn't work
+local tsnippetsfile = (lpeg.Ct(tsnippet) + tpriority + tcomment + tnewline) ^ 1
+
+-- TODO does parse values correctly, but parsing out nested tags will
+-- require recursion at the callsite since I have no clue how to do it
+local ttag = {
+ "T",
+ Expr = lpeg.C((lpeg.V("T") + anythingbut("}")) ^ 1),
+ Tnum = lpeg.Cg(tdigit ^ 1, "tagnum"),
+ Ps = lpeg.Cg(lpeg.Cp(), "selstart"),
+ Pe = lpeg.Cg(lpeg.Cp(), "selend"),
+ Tc = lpeg.V("Ps")
+ * lpeg.P("${")
+ * lpeg.V("Tnum")
+ * lpeg.S(":")
+ * lpeg.Cg(lpeg.V("Expr"), "expr")
+ * lpeg.V("Pe")
+ * lpeg.S("}"),
+ Ts = lpeg.V("Ps") * lpeg.S("$") * lpeg.V("Pe") * lpeg.V("Tnum"),
+ T = lpeg.V("Tc") + lpeg.V("Ts"),
+}
+
+--------------------------------------------------------------------------------
+
+-- local testheader = [[
+-- snippet #! "#!/usr/bin/env lua" b
+-- ]]
+
+local testcontent = [[
+for ${1:idx},${2:val} in ipairs(${3:table_name}) do
+ $0
+end
+]]
+
+local testsnippet = [[
+snippet fori "ipair for foop" b
+for ${1:idx},${2:val} in ipairs(${3:table_name}) do
+ $0
+end
+endsnippet
+]]
+
+local luasnippetfile = [[
+priority -50
+
+#################################
+# Snippets for the Lua language #
+#################################
+snippet #! "#!/usr/bin/env lua" b
+#!/usr/bin/env lua
+$0
+endsnippet
+
+snippet !fun(ction)?! "New function" br
+local function ${1:new_function}(${2:args})
+ $0
+end
+endsnippet
+
+snippet forp "pair for loop" b
+for ${1:name},${2:val} in pairs(${3:table_name}) do
+ $0
+end
+endsnippet
+
+snippet fori "ipair for foop" b
+for ${1:idx},${2:val} in ipairs(${3:table_name}) do
+ $0
+end
+endsnippet
+
+snippet for "numeric for loop" b
+for ${1:i}=${2:first},${3:last}${4/^..*/(?0:,:)/}${4:step} do
+ $0
+end
+endsnippet
+
+snippet do "do block"
+do
+ $0
+end
+endsnippet
+
+snippet repeat "repeat loop" b
+repeat
+ $1
+until $0
+endsnippet
+
+snippet while "while loop" b
+while $1 do
+ $0
+end
+endsnippet
+
+snippet if "if statement" b
+if $1 then
+ $0
+end
+endsnippet
+
+snippet ife "if/else statement" b
+if $1 then
+ $2
+else
+ $0
+end
+endsnippet
+
+snippet eif "if/elseif statement" b
+if $1 then
+ $2
+elseif $3 then
+ $0
+end
+endsnippet
+
+snippet eife "if/elseif/else statement" b
+if $1 then
+ $2
+elseif $3 then
+ $4
+else
+ $0
+end
+endsnippet
+
+snippet pcall "pcall statement" b
+local ok, err = pcall(${1:your_function})
+if not ok then
+ handler(${2:ok, err})
+${3:else
+ success(${4:ok, err})
+}end
+endsnippet
+
+snippet local "local x = 1"
+local ${1:x} = ${0:1}
+endsnippet
+
+# vim:ft=snippets:
+]]
+
+--------------------------------------------------------------------------------
+-- Test
+
+local function print_table(tableau, tabwidth)
+ if tabwidth == nil then
+ tabwidth = 0
+ end
+
+ -- Iterate
+ for k, v in pairs(tableau) do
+ local tabs = ("\t"):rep(tabwidth)
+
+ print(tabs .. k .. ': "' .. tostring(v) .. '"')
+ if type(v) == "table" then
+ print_table(v, tabwidth + 1)
+ end
+ end
+end
+
+do
+ print("------------ snippet test ------------------------------------")
+ local p = lpeg.Ct(tsnippet)
+ local t = p:match(testsnippet)
+ print_table(t)
+ print("--------------------------------------------------------------")
+end
+
+do
+ print("------------ snippetfile test ------------------------------------")
+ local p = lpeg.Ct(tsnippetsfile)
+ local t = p:match(luasnippetfile)
+ print_table(t)
+ print("--------------------------------------------------------------")
+end
+
+do
+ print("------------ tags test -------------------------------------")
+ local p = lpeg.Ct((lpeg.Ct(ttag) + tanyprintable + tcontrol) ^ 1)
+ local t = p:match(testcontent)
+ print_table(t)
+ print("--------------------------------------------------------------")
+end
diff --git a/config/essentials/vis/vis-ultisnips/ultisnips-parser.lua b/config/essentials/vis/vis-ultisnips/ultisnips-parser.lua
new file mode 100644
index 0000000..a4240b8
--- /dev/null
+++ b/config/essentials/vis/vis-ultisnips/ultisnips-parser.lua
@@ -0,0 +1,211 @@
+--------------------------------------------------------------------------------
+-- Module table
+
+local M = {}
+
+local lpeg = require('lpeg')
+
+
+
+--------------------------------------------------------------------------------
+-- lpeg rules
+
+local tsep = lpeg.S' \t'
+local tws = tsep ^ 1
+local tnewline = lpeg.S'\n'
+local tlowcasedword = lpeg.R'az' ^ 1
+local tdigit = lpeg.locale()['digit']
+-- local talphanum = lpeg.locale()['alnum']
+local tanyprintable = lpeg.locale()['print']
+local tcontrol = lpeg.locale()['cntrl']
+local function surrounded(ch, p) return lpeg.S(ch) * p * lpeg.S(ch) end
+local function anythingbut(ch) return (tanyprintable + tcontrol) - lpeg.S(ch) end
+
+local ttabtriggercomplex = surrounded ('"',
+ tlowcasedword * lpeg.S'()[]?0123456789-'^1
+ )
+-- TODO This is just retarded
+-- Check the actual grammar and see what special starting chars are
+-- then relax the grammar a bit
+local ttabtriggerweird = surrounded('!',
+ (lpeg.R'az' + lpeg.S'?()') ^ 1
+ )
+local ttabtriggerweird2 = lpeg.P'#!'
+local ttabtriggerweird3 = surrounded('/',
+ (anythingbut'/') ^1
+ )
+local ttabtrigger = ttabtriggercomplex
+ + ttabtriggerweird
+ + ttabtriggerweird2
+ + ttabtriggerweird3
+ + (tlowcasedword + lpeg.S'.')
+local tdescription = surrounded ('"',
+ lpeg.Cg( (tanyprintable - lpeg.S'"')^1, 'description')
+ )
+local toption = lpeg.R'az'
+
+local tstartsnippet = lpeg.P'snippet'
+ * tws
+ * lpeg.Cg(ttabtrigger, 'tabtrigger')
+ * tws
+ * tdescription
+ * tws ^ 0
+ * lpeg.Cg(toption^0, 'options')
+local tendsnippet = lpeg.P'endsnippet'
+
+-- The content parsing needs cleanup, its really convoluted due to me learning
+-- lpeg while using it
+--tcontent = ((tanyprintable + tcontrol)^1 - tendsnippet) * tnewline
+local tcontent = ((lpeg.S' \t' + tanyprintable)^1 - tendsnippet)
+ * tnewline
+local tsnippet = tstartsnippet
+ * tnewline
+ * ((tendsnippet * tnewline) + lpeg.Cg(tcontent ^ 1, 'content'))
+
+-- local tcomment = lpeg.S'#'
+-- * tanyprintable^0
+-- * tnewline
+-- local tpriority = lpeg.P'priority'
+-- * tws
+-- * lpeg.Cg(lpeg.S('-')^0 * tdigit^1, 'priority')
+
+-- TODO doesn't work
+-- local tsnippetsfile = (lpeg.Ct(tsnippet) + tpriority + tcomment + tnewline) ^ 1
+
+
+-- TODO does parse values correctly, but parsing out nested tags will
+-- require recursion at the callsite since I have no clue how to do it
+local ttag = { 'T'
+ ; Expr = lpeg.C((lpeg.V'T' + ((tanyprintable + tcontrol) - lpeg.S'}'))^1)
+ , Tnum = lpeg.Cg(tdigit ^ 1, 'tagnum')
+ , Ps = lpeg.Cg(lpeg.Cp(), 'selstart')
+ , Pe = lpeg.Cg(lpeg.Cp(), 'selend')
+ , Tc = lpeg.V'Ps'
+ * lpeg.P'${'
+ * lpeg.V'Tnum'
+ * lpeg.S(':')
+ * lpeg.Cg(lpeg.V'Expr', 'expr')
+ * lpeg.V'Pe'
+ * lpeg.S'}'
+ , Ts = lpeg.V'Ps' * lpeg.S'$' * lpeg.V'Pe' * lpeg.V'Tnum'
+ , T = lpeg.V'Tc' + lpeg.V'Ts'
+ }
+
+
+
+--------------------------------------------------------------------------------
+-- Functions
+
+-- Parses the snippet's content to create a table we later use
+-- to corrently insert the text, the selections, and the default values
+local function create_content(str)
+ local content = {}
+ content.str = str
+ content.tags = {}
+
+ local p = vis.lpeg.Ct((lpeg.Ct(ttag) + tanyprintable + tcontrol) ^ 1)
+ local m = p:match(str)
+
+ local s = 1 -- We start from 1 to adjust position from $^0 to ^$0
+ for k,v in ipairs(m) do
+ content.tags[k] = v
+ -- TODO recurse over tag.expr to extract nested tags
+ -- Of course this will actually have to be used later on, depending
+ -- on whether the tag is added or not
+
+ -- We need to keep track of how much we remove, and readjust all
+ -- subsequent selection points
+ -- Note to self, I hate all this bookkeeping
+ local tagtext = string.sub(str, v.selstart, v.selend)
+ if v.expr ~= nil then
+ content.str = string.gsub(content.str, tagtext, v.expr)
+ content.tags[k].selstart = content.tags[k].selstart - s
+ content.tags[k].selend = content.tags[k].selstart + #v.expr
+ s = s + #'${' + #tostring(k) + #':' + 1
+ else
+ content.str = string.gsub(content.str, tagtext, '')
+ content.tags[k].selstart = content.tags[k].selstart - s
+ content.tags[k].selend = content.tags[k].selstart
+ s = s + #'$' + 1
+ end
+ end
+
+ return content
+end
+
+
+
+-- Takes a line starting with 'snippet' and a lines iterator, and creates
+-- a 'snippet' table to be used
+-- If it fails it returns nil, otherwise returns two values, a tabtrigger
+-- and a snippet
+local function create_snippet(start_line, linesit)
+ local snippetstr = start_line .. '\n'
+ -- Read content into list of lines until we hit `endsnippet`
+ for line in linesit do
+ local s, _ = string.find(line, 'endsnippet')
+ if s == 1 then
+ snippetstr = snippetstr .. 'endsnippet' .. '\n'
+ break
+ else
+ snippetstr = snippetstr .. line .. '\n'
+ end
+ end
+
+ local p = vis.lpeg.Ct(tsnippet)
+ local m = p:match(snippetstr)
+
+ if not m then
+ -- Enable this when debugging, otherwise it nukes whole app
+ vis:info('Failed to parse some snippets!')
+ -- vis:message('Failed to parse snippet: ' .. snippetstr)
+ return nil
+ else
+ local tabtrigger = m.tabtrigger
+ local snippet = {}
+ snippet.description = m.description
+ snippet.options = m.options
+ snippet.content = create_content(m.content)
+ return tabtrigger, snippet
+ end
+end
+
+
+
+-- Loads all snippets from passed '.snippets' file. Should probably be
+-- triggered when new file is loaded or when syntax is set/changed
+M.load_snippets = function(snippetfile)
+ local snippets = {}
+
+ local f = io.open(snippetfile, 'r')
+ if f then
+ io.input(f)
+ local linesit = io.lines()
+
+ for line in linesit do
+ -- TODO read whole file, then apply lpeg grammar that parses all
+ -- snippets out rather than being pedestrian about it like this
+ local s, _ = string.find(line, 'snippet')
+ -- Find lines that start with 'snippet' and enter
+ -- snippet reading loop
+ if s == 1 then
+ local tabtrigger, snippet = create_snippet(line, linesit)
+ if tabtrigger then
+ snippets[tabtrigger] = snippet
+ end
+ end
+ end
+
+ io.close(f)
+ return snippets, true
+ else
+ return snippets, false
+ end
+end
+
+
+
+--------------------------------------------------------------------------------
+-- End module
+
+return M \ No newline at end of file
diff --git a/config/essentials/vis/visrc.lua b/config/essentials/vis/visrc.lua
index 60162bc..7847784 100644
--- a/config/essentials/vis/visrc.lua
+++ b/config/essentials/vis/visrc.lua
@@ -1,25 +1,45 @@
------------------------------------
---- LIBRARIES
+--- REQUIRES
------------------------------------
require("vis")
-- plugins
require("build")
+-- use Trash directory instead, remove set_dir function
require("backup")
require("cursors")
require("title")
require("commentary")
require("complete-line")
+-- removed formatting because already fulfilled by format.lua
+require("vis-go")
+-- set height to 40%
+require("fzf-open")
+require("vis-ultisnips")
+-- TODO: doesn't work when using with 'e|b'
+-- require("yank-highlight")
+
+-- save position before formatting, use vis:redraw
local format = require("format")
+-- set height to 40%
+local fzfmru = require("fzf-mru")
+fzfmru.fzfmru_path = 'grep "^' .. os.getenv("PWD") .. '" | fzf'
+
+
-- todo:
-- c-scope
-- c-tags
+-- ...
+-- vis-goto, favor open-file-under-cursor
+-- ...
+-- ultisnips
+-- ...
+-- vis-yank-highlight
------------------------------------
--- VARIABLES
------------------------------------
-
local m = vis.modes
------------------------------------
@@ -56,13 +76,16 @@ vis:command_register("Q", function()
vis:command("qa!")
end, "Quit all")
vis:command_register("delws", function()
- vis:command("x/[ \t]+$|^[ \t]+$/d")
+ vis:command(",x/[ \t]+$|^[ \t]+$/d")
end, "Remove trailing whitespace")
-------------------------------------
--- MAPPINGS
-------------------------------------
+vis:map(m.NORMAL, "<C-p>", function() vis:command("fzf") end, "Open file with fzf")
+
+
vis:map(m.NORMAL, " r", function()
wrap_restore(vis.command, vis, "e $vis_filepath")
end, "Reload active file")
@@ -107,8 +130,4 @@ vis.events.subscribe(vis.events.WIN_OPEN, function(win) -- luacheck: no unused a
"Print variable"
)
end
-
- vis:command_register("pipe", function()
- vis:pipe(win.file, nil, "sed 's/.*/- &/'")
- end, "pipe test")
end)
diff --git a/config/essentials/vis/yank-highlight.lua b/config/essentials/vis/yank-highlight.lua
new file mode 100644
index 0000000..37a9578
--- /dev/null
+++ b/config/essentials/vis/yank-highlight.lua
@@ -0,0 +1,37 @@
+require("vis")
+
+local M = {
+ style = "reverse", -- Style used for highlighting
+ duration = 0.2, -- [s] Time to remain highlighted (10 ms precision)
+}
+
+vis.events.subscribe(vis.events.INIT, function()
+ local yank = vis:action_register("highlighted-yank", function()
+ vis.win:style_define(vis.win.STYLE_SELECTION, M.style)
+ vis:redraw()
+ local tstamp = os.clock()
+ while os.clock() - tstamp < M.duration do end
+ vis.win:style_define(vis.win.STYLE_SELECTION, vis.lexers.STYLE_SELECTION)
+ vis:redraw()
+ vis:feedkeys("<vis-operator-yank>")
+ end, "Yank operator with highlighting")
+ vis:map(vis.modes.OPERATOR_PENDING, "y", yank)
+ vis:map(vis.modes.VISUAL, "y", yank)
+ vis:map(vis.modes.VISUAL_LINE, "y", yank)
+
+ vis:map(vis.modes.NORMAL, "y", function(keys)
+ local sel_end_chrs = "$%^{}()wp"
+ if #keys < 1 or sel_end_chrs:find(keys:sub(-1), 1, true) == nil then
+ if keys:find("<Escape>") then
+ return #keys
+ end
+ return -1
+ end
+ vis:feedkeys("<vis-mode-visual-charwise>")
+ vis:feedkeys(keys)
+ vis:feedkeys("y<Escape>")
+ return #keys
+ end)
+end)
+
+return M