From cf1ec23a2d2e501aca8dc0a7090fa9566c8ecab5 Mon Sep 17 00:00:00 2001 From: Ekaitz Zarraga Date: Fri, 26 Jan 2024 23:25:26 +0100 Subject: 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 --- nvim/nvim/init.lua | 11 ++- nvim/nvim/lua/nvim-paredit-scheme.lua | 159 ++++++++++++++++++++++++++++++++++ nvim/nvim/lua/parens.lua | 135 +++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 nvim/nvim/lua/nvim-paredit-scheme.lua create mode 100644 nvim/nvim/lua/parens.lua (limited to 'nvim') 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 = { + ["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" }, + ["f"] = { paredit.api.drag_form_forwards, "Drag form right" }, + ["o"] = { paredit.api.raise_form, "Raise form" }, + ["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" }, + }, + } + } +} -- cgit v1.2.3