{"id":13600390,"url":"https://github.com/julienvincent/nvim-paredit","last_synced_at":"2025-04-04T20:07:59.770Z","repository":{"id":173499634,"uuid":"650743148","full_name":"julienvincent/nvim-paredit","owner":"julienvincent","description":"A Paredit implementation for Neovim, built using Treesitter and written in Lua.","archived":false,"fork":false,"pushed_at":"2025-01-13T10:20:03.000Z","size":1258,"stargazers_count":200,"open_issues_count":7,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-28T19:07:40.261Z","etag":null,"topics":["clojure","lisp","lua","neovim","nvim","paredit","vim"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/julienvincent.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-07T17:59:11.000Z","updated_at":"2025-03-22T09:44:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"ccf364ca-ec95-4ee1-9844-fa9f95811185","html_url":"https://github.com/julienvincent/nvim-paredit","commit_stats":null,"previous_names":["julienvincent/nvim-paredit"],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienvincent%2Fnvim-paredit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienvincent%2Fnvim-paredit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienvincent%2Fnvim-paredit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienvincent%2Fnvim-paredit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/julienvincent","download_url":"https://codeload.github.com/julienvincent/nvim-paredit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247242671,"owners_count":20907133,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","lisp","lua","neovim","nvim","paredit","vim"],"created_at":"2024-08-01T18:00:38.101Z","updated_at":"2025-04-04T20:07:59.745Z","avatar_url":"https://github.com/julienvincent.png","language":"Lua","funding_links":[],"categories":["Lua","Editing support"],"sub_categories":["Parenthetical edit"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003envim-paredit\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cp\u003e\n    \u003cimg src=\"https://github.com/user-attachments/assets/4175e39c-42b4-48bd-81b6-ed7ef52bda30\" align=\"center\" alt=\"Logo\" /\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    A \u003ca href=\"https://paredit.org/\"\u003eParedit\u003c/a\u003e implementation for \u003ca href=\"https://github.com/neovim/neovim/\"\u003eNeovim\u003c/a\u003e, built using \u003ca href=\"https://github.com/tree-sitter/tree-sitter\"\u003eTreesitter\u003c/a\u003e and written in Lua.\n  \u003c/p\u003e\n\u003c/div\u003e\n\nThe goal of `nvim-paredit` is to provide a comparable s-expression editing experience in Neovim to that provided by\nEmacs. This is what is provided:\n\n- Treesitter based lisp structural editing, cursor motions and text object selections\n- Dot-repeatable keybindings\n- Language extensibility\n- Programmable API\n\n---\n\n![Demo](https://github.com/user-attachments/assets/634ae915-43d6-487b-9453-cf0257e38630)\n\n## Index\n\n- **[Installation](#installation)**\n- **[Configuration](#configuration)**\n- **[API Reference](./docs/api-reference.md)**\n- **[Recipes](./docs/recipes.md)**\n- **[Auto Indentation](#auto-indentation)**\n- **[Pairwise Dragging](#pairwise-dragging)**\n- **[Language Support](#language-support)**\n  - **[Language Queries Spec](./docs/language-queries.md)**\n- **[Prior Art](#prior-art)**\n\n## Installation\n\n### Using [folke/lazy.vim](https://github.com/folke/lazy.nvim)\n\n```lua\n{\n  \"julienvincent/nvim-paredit\",\n  config = function()\n    require(\"nvim-paredit\").setup()\n  end\n}\n```\n\n## Configuration\n\n```lua\nlocal paredit = require(\"nvim-paredit\")\nparedit.setup({\n  -- Change some keys\n  keys = {\n    [\"\u003clocalleader\u003eo\"] = false,\n    [\"\u003clocalleader\u003er\"] = { paredit.api.raise_form, \"Raise form\" },\n  },\n})\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ccode\u003e\u003cb\u003eDefault Configuration Values\u003c/b\u003e\u003c/code\u003e\u003c/summary\u003e\n\n```lua\nlocal paredit = require(\"nvim-paredit\")\nparedit.setup({\n  -- Should plugin use default keybindings? (default = true)\n  use_default_keys = true,\n  -- Sometimes user wants to restrict plugin to certain filetypes only or add support\n  -- for new filetypes.\n  --\n  -- Defaults to all supported filetypes.\n  filetypes = { \"clojure\", \"fennel\", \"scheme\", \"lisp\" },\n\n  -- This is some language specific configuration. Right now this is just used for\n  -- setting character lists that are considered whitespace.\n  languages = {\n    clojure = {\n      whitespace_chars = { \" \", \",\" },\n    },\n    fennel = {\n      whitespace_chars = { \" \", \",\" },\n    },\n  },\n\n  -- This controls where the cursor is placed when performing slurp/barf operations\n  --\n  -- - \"remain\" - It will never change the cursor position, keeping it in the same place\n  -- - \"follow\" - It will always place the cursor on the form edge that was moved\n  -- - \"auto\"   - A combination of remain and follow, it will try keep the cursor in the original position\n  --              unless doing so would result in the cursor no longer being within the original form. In\n  --              this case it will place the cursor on the moved edge\n  cursor_behaviour = \"auto\", -- remain, follow, auto\n\n  dragging = {\n    -- If set to `true` paredit will attempt to infer if an element being\n    -- dragged is part of a 'paired' form like as a map. If so then the element\n    -- will be dragged along with it's pair.\n    auto_drag_pairs = true,\n  },\n\n  indent = {\n    -- This controls how nvim-paredit handles indentation when performing operations which\n    -- should change the indentation of the form (such as when slurping or barfing).\n    --\n    -- When set to true then it will attempt to fix the indentation of nodes operated on.\n    enabled = false,\n    -- A function that will be called after a slurp/barf if you want to provide a custom indentation\n    -- implementation.\n    indentor = require(\"nvim-paredit.indentation.native\").indentor,\n  },\n\n  -- list of default keybindings\n  keys = {\n    [\"\u003clocalleader\u003e@\"] = { paredit.unwrap.unwrap_form_under_cursor, \"Splice sexp\" },\n    [\"\u003e)\"] = { paredit.api.slurp_forwards, \"Slurp forwards\" },\n    [\"\u003e(\"] = { paredit.api.barf_backwards, \"Barf backwards\" },\n\n    [\"\u003c)\"] = { paredit.api.barf_forwards, \"Barf forwards\" },\n    [\"\u003c(\"] = { paredit.api.slurp_backwards, \"Slurp backwards\" },\n\n    [\"\u003ee\"] = { paredit.api.drag_element_forwards, \"Drag element right\" },\n    [\"\u003ce\"] = { paredit.api.drag_element_backwards, \"Drag element left\" },\n\n    [\"\u003ep\"] = { paredit.api.drag_pair_forwards, \"Drag element pairs right\" },\n    [\"\u003cp\"] = { paredit.api.drag_pair_backwards, \"Drag element pairs left\" },\n\n    [\"\u003ef\"] = { paredit.api.drag_form_forwards, \"Drag form right\" },\n    [\"\u003cf\"] = { paredit.api.drag_form_backwards, \"Drag form left\" },\n\n    [\"\u003clocalleader\u003eo\"] = { paredit.api.raise_form, \"Raise form\" },\n    [\"\u003clocalleader\u003eO\"] = { paredit.api.raise_element, \"Raise element\" },\n\n    [\"E\"] = {\n      paredit.api.move_to_next_element_tail,\n      \"Jump to next element tail\",\n      -- by default all keybindings are dot repeatable\n      repeatable = false,\n      mode = { \"n\", \"x\", \"o\", \"v\" },\n    },\n    [\"W\"] = {\n      paredit.api.move_to_next_element_head,\n      \"Jump to next element head\",\n      repeatable = false,\n      mode = { \"n\", \"x\", \"o\", \"v\" },\n    },\n\n    [\"B\"] = {\n      paredit.api.move_to_prev_element_head,\n      \"Jump to previous element head\",\n      repeatable = false,\n      mode = { \"n\", \"x\", \"o\", \"v\" },\n    },\n    [\"gE\"] = {\n      paredit.api.move_to_prev_element_tail,\n      \"Jump to previous element tail\",\n      repeatable = false,\n      mode = { \"n\", \"x\", \"o\", \"v\" },\n    },\n\n    [\"(\"] = {\n      paredit.api.move_to_parent_form_start,\n      \"Jump to parent form's head\",\n      repeatable = false,\n      mode = { \"n\", \"x\", \"v\" },\n    },\n    [\")\"] = {\n      paredit.api.move_to_parent_form_end,\n      \"Jump to parent form's tail\",\n      repeatable = false,\n      mode = { \"n\", \"x\", \"v\" },\n    },\n\n    -- These are text object selection keybindings which can used with standard `d, y, c`, `v`\n    [\"af\"] = {\n      paredit.api.select_around_form,\n      \"Around form\",\n      repeatable = false,\n      mode = { \"o\", \"v\" },\n    },\n    [\"if\"] = {\n      paredit.api.select_in_form,\n      \"In form\",\n      repeatable = false,\n      mode = { \"o\", \"v\" },\n    },\n    [\"aF\"] = {\n      paredit.api.select_around_top_level_form,\n      \"Around top level form\",\n      repeatable = false,\n      mode = { \"o\", \"v\" },\n    },\n    [\"iF\"] = {\n      paredit.api.select_in_top_level_form,\n      \"In top level form\",\n      repeatable = false,\n      mode = { \"o\", \"v\" },\n    },\n    [\"ae\"] = {\n      paredit.api.select_element,\n      \"Around element\",\n      repeatable = false,\n      mode = { \"o\", \"v\" },\n    },\n    [\"ie\"] = {\n      paredit.api.select_element,\n      \"Element\",\n      repeatable = false,\n      mode = { \"o\", \"v\" },\n    },\n  },\n})\n```\n\n\u003c/details\u003e\n\n---\n\n## API Reference\n\nSee **[api-reference.md](./docs/api-reference.md)**\n\n## Auto Indentation\n\nNvim-paredit comes with built-in support for fixing form indentation when performing slurp and barf operations. By\ndefault, this behaviour is disabled and can be enabled by setting `indent.enabled = true` in the\n[configuration](#configuration)\n\nThe main goal of this implementation is to provide a visual aid to the user, allowing them to confirm they are operating\non the correct node and to know when to stop when performing recursive slurp/barf operations. This implementation is\nfast and does not result in any UI lag or jitter.\n\nThe goal is _not_ to be 100% correct. The implementation follows a simple set of rules which account for most scenarios\nbut not all. If a more correct implementation is needed then the native implementation can be replaced by setting the\nconfiguration property `intent.indentor`.\n\nFor example an implementation using `vim.lsp.buf.format` could be built if you don't mind sacrificing performance for\ncorrectness. See the **[lsp indentation recipe](./docs/recipes.md#lsp-indentation)** for an example of this.\n\n## Pairwise Dragging\n\nNvim-paredit has support for dragging elements pairwise. If an element being dragged is within a form that contains\npairs of elements (such as a Clojure `map`) then the element will be dragged along with its pair.\n\nFor example:\n\n```clojure\n{:a 1\n |:b 2}\n;; Drag backwards\n{|:b 2\n :a 1}\n```\n\nThis is enabled by default and can be disabled by setting `dragging.auto_drag_pairs = false` in the\n[configuration](#configuration).\n\nPairwise dragging works using treesitter queries to identify element pairs within some localized node. This means you\ncan very easily extend the paredit pairwise implementation by simply adding new treesitter queries to your nvim\nconfiguration.\n\nYou might want to extend if:\n\n1. You are a language extension author and want to add pairwise dragging support to your extension.\n2. You want to add support for some syntax not supported by nvim-paredit.\n\nThis is especially useful if you have your own Clojure macros that you want to enable pairwise dragging on.\n\nAll you need to do to extend is to add a new file called `queries/\u003clanguage\u003e/paredit/pairs.scm` in your nvim config\ndirectory. Make sure to include the `;; extends` directive to the file, or you will overwrite any pre-existing queries\ndefined by nvim-paredit or other language extensions.\n\nSee the **[custom macro pairwise dragging recipe](./docs/recipes.md#custom-macro-pairwise-dragging)** for an example of\nhow to add pairwise dragging support for new syntax\n\n## Language Support\n\nAs this is built using Treesitter it requires that you have the relevant Treesitter grammar installed for your language\nof choice. Additionally, `nvim-paredit` will need explicit support for the treesitter grammar used by your language as\nthe node names and metadata of nodes vary between languages.\n\nLanguage support is added by providing treesitter query files that specify specific captures nvim-paredit can use to\nunderstand the AST.\n\nRight now `nvim-paredit` has built-in support for:\n\n- `clojure`\n- `fennel` *\n- `scheme` *\n- `commonlisp` *\n\n\u003e [!NOTE]\n\u003e\n\u003e Items marked with `*` only have partial test coverage. Not all language syntax is guaranteed to work.\n\nTake a look at the [Language Queries Spec](./docs/language-queries.md) if you are wanting to add support for languages\nnot built-in to nvim-paredit, or you want to develop on the existing queries.\n\n## Prior Art\n\n#### [vim-sexp](https://github.com/guns/vim-sexp)\n\nHistorically this was the de-facto s-expression editing plugin. Supports a wider range of motions than nvim-paredit but\notherwise significantly less functionality.\n\nThe main reasons you might want to consider `nvim-paredit` instead are:\n\n- Easier configuration and an exposed Lua API\n- Control over how the cursor is moved during slurp/barf. (For example if you don't want the cursor to always be moved)\n- Recursive slurp/barf operations. If your cursor is in a nested form you can still slurp from the forms parent(s)\n- Automatic form/element indentations on slurp/barf\n- Pairwise element dragging\n- Subjectively better out-of-the-box keybindings\n\n#### [vim-sexp-mappings-for-regular-people](https://github.com/tpope/vim-sexp-mappings-for-regular-people)\n\nA companion to `vim-sexp` which configures `vim-sexp` with better mappings. The default mappings for `nvim-paredit` were\nderived from here.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulienvincent%2Fnvim-paredit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjulienvincent%2Fnvim-paredit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulienvincent%2Fnvim-paredit/lists"}