summaryrefslogtreecommitdiff
path: root/nvim
diff options
context:
space:
mode:
authorEkaitz Zarraga <ekaitz@elenq.tech>2024-01-26 23:25:26 +0100
committerEkaitz Zarraga <ekaitz@elenq.tech>2024-01-27 00:24:05 +0100
commitcf1ec23a2d2e501aca8dc0a7090fa9566c8ecab5 (patch)
treece4bf271332fb90a7192da5ca7d92260deabf5ca /nvim
parente5019733ebeb244df4dd92248a433c754e49dd9b (diff)
nvim: Start with pro parediting
- nvim-paredit: not configured yet - scheme extension in alpha status done by myself <3 - parinfer: try it, if I don't like it just remove it later - parparpar: to use them together
Diffstat (limited to 'nvim')
-rw-r--r--nvim/nvim/init.lua11
-rw-r--r--nvim/nvim/lua/nvim-paredit-scheme.lua159
-rw-r--r--nvim/nvim/lua/parens.lua135
3 files changed, 301 insertions, 4 deletions
diff --git a/nvim/nvim/init.lua b/nvim/nvim/init.lua
index 7bdec4a..b166134 100644
--- a/nvim/nvim/init.lua
+++ b/nvim/nvim/init.lua
@@ -5,7 +5,9 @@ vim.cmd.filetype("off")
local Plug = vim.fn['plug#']
vim.fn["plug#begin"]()
Plug("nvim-treesitter/nvim-treesitter")
- Plug("kovisoft/paredit")
+ Plug("julienvincent/nvim-paredit") -- Keeps parens balanced
+ Plug("gpanders/nvim-parinfer") -- Parinfer helps with formatting
+ Plug("dundalek/parpar.nvim") -- Parinfer and Paredit work together
Plug("sgur/vim-editorconfig")
Plug("dracula/vim")
Plug("othree/html5.vim")
@@ -116,7 +118,7 @@ vim.opt.formatoptions="jcroql"
require'nvim-treesitter.configs'.setup {
-- A list of parser names, or "all"
ensure_installed = { "c", "cpp", "lua", "python", "scheme", "javascript",
- "fennel", "zig" },
+ "fennel", "zig", "clojure" },
-- Install parsers synchronously (only applied to `ensure_installed`)
sync_install = false,
@@ -150,5 +152,6 @@ if vim.fn.executable("rg") then
vim.opt.grepformat="%f:%l:%c:%m,%f:%l:%m"
end
--- Mappings
-require("mappings")
+-- Extras
+require'mappings'
+require'parens'
diff --git a/nvim/nvim/lua/nvim-paredit-scheme.lua b/nvim/nvim/lua/nvim-paredit-scheme.lua
new file mode 100644
index 0000000..f8de6c2
--- /dev/null
+++ b/nvim/nvim/lua/nvim-paredit-scheme.lua
@@ -0,0 +1,159 @@
+local traversal = require("nvim-paredit.utils.traversal")
+-- local common = require("nvim-paredit.utils.common")
+
+-- THIS IS A REFERENCE, UNUSED
+local nodes = {
+ "comment",
+ "block_comment", -- for example, #| something |#
+ "directive", -- for example, #!r6rs
+ "boolean",
+ "character",
+ "string",
+ "escape_sequence", -- escape sequence in string, for example, \n in "abc\n"
+ "number",
+ "symbol", -- identifier
+ "keyword", -- #:identifier
+ "list", -- things surrounded by () or [] or {}
+ "quote", -- '
+ "quasiquote", -- `
+ "syntax", -- #'
+ "quasisyntax", --`
+ "unquote", -- ,
+ "unquote_splicing", -- ,@
+ "unsyntax", -- #,
+ "unsyntax_splicing", -- #,@
+ "vector",
+ "byte_vector",
+ }
+
+local forms = {
+ comment = {2, 0}, -- for srfi 62, #;
+ block_comment = {2, 2}, -- for example, #| something |#
+ string = {1, 1},
+ list = {1, 1}, -- things surrounded by () or [] or {}
+ vector = {2, 1}, -- #(...)
+ byte_vector = {5, 1}, -- #vu8(...)
+ vector = {2, 1},
+ }
+
+
+local function find_next_parent_form(current_node)
+ if forms[current_node:type()] then
+ return current_node
+ end
+
+ local parent = current_node:parent()
+ if parent then
+ return find_next_parent_form(parent)
+ end
+
+ return current_node
+end
+
+local function find_parent_comment(node)
+ if node:type() == "comment" then
+ return node
+ end
+ local parent = node:parent()
+
+ if parent then
+ return find_parent_comment(parent)
+ else
+ return nil
+ end
+end
+
+local M = {}
+
+-- Should return the 'root' of the given Treesitter node. For example:
+-- The node at cursor in the below example is `()` or 'list_lit':
+-- '(|)
+-- But the node root is `'()` or 'quoting_lit'
+M.get_node_root = function(node)
+ local search_point = node
+ if M.node_is_form(node) then
+ search_point = node:parent()
+ end
+
+ local root = find_next_parent_form(search_point)
+ return traversal.find_root_element_relative_to(root, node)
+end
+-- This is the inverse of `get_node_root` for forms and should find the inner
+-- node for which the forms elements are direct children.
+--
+-- For example given the node `'()` or 'quoting_lit', this function should
+-- return `()` or 'list_lit'.
+M.unwrap_form = function(node)
+ if forms[node:type()] then
+ return node
+ end
+ local child = node:named_child(0)
+ if child then
+ return M.unwrap_form(child)
+ end
+end
+-- Accepts a Treesitter node and should return true or false depending on
+-- whether the given node can be considered a 'form'
+M.node_is_form = function(node)
+ if M.unwrap_form(node) then
+ return true
+ else
+ return false
+ end
+end
+ -- Accepts a Treesitter node and should return true or false depending on
+ -- whether the given node can be considered a 'comment'
+M.node_is_comment = function(node)
+ return (find_parent_comment(node)
+ or node:type() == "comment"
+ or node:type() == "block_comment")
+end
+ -- Accepts a Treesitter node representing a form and should return the
+ -- 'edges' of the node. This includes the node text and the range covered by
+ -- the node
+M.get_form_edges = function(node)
+ local node_range = { node:range() }
+
+ local form = M.unwrap_form(node)
+ local form_range = { form:range() }
+
+ -- Get the size of the form boundaries
+ local size = forms[node:type()]
+ if not size then
+ -- default to {1, 1}
+ size = {1, 1}
+ end
+ -- If it's an inline comment don't do anything
+ if node:type() == "comment"
+ and vim.api.nvim_buf_get_text(0, form_range[1], form_range[2],
+ form_range[3], form_range[4], {})[1]:sub(1,1) == ";"
+ then
+ return {}
+ end
+
+ local left_range = { node_range[1], node_range[2] }
+ left_range[3] = form_range[1]
+ left_range[4] = form_range[2] + size[1]
+
+ local right_range = { form:range() }
+ right_range[1] = right_range[3]
+ right_range[2] = right_range[4] - size[2]
+
+ local left_text = vim.api.nvim_buf_get_text(0, left_range[1], left_range[2],
+ left_range[3], left_range[4], {})
+ local right_text = vim.api.nvim_buf_get_text(0, right_range[1],
+ right_range[2], right_range[3], right_range[4], {})
+
+ return {
+ left = {
+ text = left_text[1],
+ range = left_range,
+ },
+ right = {
+ text = right_text[1],
+ range = right_range,
+ },
+ }
+end
+
+return M
diff --git a/nvim/nvim/lua/parens.lua b/nvim/nvim/lua/parens.lua
new file mode 100644
index 0000000..d60a35c
--- /dev/null
+++ b/nvim/nvim/lua/parens.lua
@@ -0,0 +1,135 @@
+local paredit = require "nvim-paredit"
+local parpar = require "parpar"
+
+vim.g.localleader=","
+parpar.setup {
+ paredit = {
+ extensions = {
+ scheme = require "nvim-paredit-scheme"
+ },
+ -- should plugin use default keybindings? (default = true)
+ use_default_keys = true,
+ -- sometimes user wants to restrict plugin to certain file types only
+ -- defaults to all supported file types including custom lang
+ -- extensions (see next section)
+ filetypes = { "scheme", "clojure", "guix", "fennel", "lisp", "guile" },
+
+ -- This controls where the cursor is placed when performing slurp/barf operations
+ --
+ -- - "remain" - It will never change the cursor position, keeping it in the same place
+ -- - "follow" - It will always place the cursor on the form edge that was moved
+ -- - "auto" - A combination of remain and follow, it will try keep the cursor in the original position
+ -- unless doing so would result in the cursor no longer being within the original form. In
+ -- this case it will place the cursor on the moved edge
+ cursor_behaviour = "auto", -- remain, follow, auto
+
+ indent = {
+ -- This controls how nvim-paredit handles indentation when performing operations which
+ -- should change the indentation of the form (such as when slurping or barfing).
+ --
+ -- When set to true then it will attempt to fix the indentation of nodes operated on.
+ enabled = false,
+ -- A function that will be called after a slurp/barf if you want to provide a custom indentation
+ -- implementation.
+ indentor = require("nvim-paredit.indentation.native").indentor,
+ },
+
+ -- list of default keybindings
+ keys = {
+ ["<localleader>S"] = { paredit.unwrap.unwrap_form_under_cursor, "Splice sexp" },
+ [">)"] = { paredit.api.slurp_forwards, "Slurp forwards" },
+ [">("] = { paredit.api.barf_backwards, "Barf backwards" },
+
+ ["<)"] = { paredit.api.barf_forwards, "Barf forwards" },
+ ["<("] = { paredit.api.slurp_backwards, "Slurp backwards" },
+
+ [">e"] = { paredit.api.drag_element_forwards, "Drag element right" },
+ ["<e"] = { paredit.api.drag_element_backwards, "Drag element left" },
+
+ [">f"] = { paredit.api.drag_form_forwards, "Drag form right" },
+ ["<f"] = { paredit.api.drag_form_backwards, "Drag form left" },
+
+ ["<localleader>o"] = { paredit.api.raise_form, "Raise form" },
+ ["<localleader>O"] = { paredit.api.raise_element, "Raise element" },
+
+ ["E"] = {
+ paredit.api.move_to_next_element_tail,
+ "Jump to next element tail",
+ -- by default all keybindings are dot repeatable
+ repeatable = false,
+ mode = { "n", "x", "o", "v" },
+ },
+ ["W"] = {
+ paredit.api.move_to_next_element_head,
+ "Jump to next element head",
+ repeatable = false,
+ mode = { "n", "x", "o", "v" },
+ },
+
+ ["B"] = {
+ paredit.api.move_to_prev_element_head,
+ "Jump to previous element head",
+ repeatable = false,
+ mode = { "n", "x", "o", "v" },
+ },
+ ["gE"] = {
+ paredit.api.move_to_prev_element_tail,
+ "Jump to previous element tail",
+ repeatable = false,
+ mode = { "n", "x", "o", "v" },
+ },
+
+ ["("] = {
+ paredit.api.move_to_parent_form_start,
+ "Jump to parent form's head",
+ repeatable = false,
+ mode = { "n", "x", "v" },
+ },
+ [")"] = {
+ paredit.api.move_to_parent_form_end,
+ "Jump to parent form's tail",
+ repeatable = false,
+ mode = { "n", "x", "v" },
+ },
+
+ -- These are text object selection keybindings which can used with
+ -- standard `d, y, c`, `v`
+ ["af"] = {
+ paredit.api.select_around_form,
+ "Around form",
+ repeatable = false,
+ mode = { "o", "v" }
+ },
+ ["if"] = {
+ paredit.api.select_in_form,
+ "In form",
+ repeatable = false,
+ mode = { "o", "v" }
+ },
+ ["aF"] = {
+ paredit.api.select_around_top_level_form,
+ "Around top level form",
+ repeatable = false,
+ mode = { "o", "v" }
+ },
+ ["iF"] = {
+ paredit.api.select_in_top_level_form,
+ "In top level form",
+ repeatable = false,
+ mode = { "o", "v" }
+ },
+ ["ae"] = {
+ paredit.api.select_element,
+ "Around element",
+ repeatable = false,
+ mode = { "o", "v" },
+ },
+ ["ie"] = {
+ paredit.api.select_element,
+ "Element",
+ repeatable = false,
+ mode = { "o", "v" },
+ },
+ }
+ }
+}