Skip to content

Refactor AstroNvim Clojure pack

Thoughts for the week

Pull requests this week

Total commits this week: 37

Submitted a pull request to refactor the AstroNvim Community Clojure language pack which I contributed in June 2023.

  • add nvim-treesitter-sexp plugin
  • add example of disabling / configuring parinfer plugin
  • add ts-comment.nvim to support ;; and ; comment characters
  • remove autocmd from conjure plugin (no longer needed)
  • remove most of the opinionated conjure configuration overrides, although still hiding the repl log buffer (HUD) by default as its nicer as a separate tab. Maybe if I can have it open by default as a tab, then I could live with having the HUD open on REPL startup (a nice way to check things are working)

Still sleepy from travel to the company off-site last week and the cycle ride on Saturday. Although I did manage some work in the garden on Sunday.

Neovimλ︎

Refactor AstroNvim Community Clojure language pack with the help of the Astrocommunity team. All plugins have their own Astrocommunity plugin configuration separately and the Clojure pack composes those plugins, making the configuration far simpler.

Updates to Conjure mean that the diagnostics no longer require an autocmd to disable them (currently in dev)

Added Clojure comment patterns to the ts-comment.nvim plugin. That plugin now supports the ;; style comment syntax that is traditionally used for line comments, as well as the ; comment that is defined by the Clojure style guide as a post line comment

AstroNvim Community Clojure pack auto commands - no longer requred

This was the previous configuration for Conjure in the Clojure pack

  {
    "Olical/conjure",
    -- load plugin on filetypes
    filetype = { "clojure" },
    dependencies = {
      "AstroNvim/astrocore",
      opts = {
        autocmds = {                   -- (1)!
          conjure_log_disable_lsp = {
            {
              event = "BufNewFile",
              pattern = { "conjure-log-*" },
              callback = function() vim.diagnostic.disable(0) end,
              desc = "Conjure Log disable LSP diagnostics",
            },
            {
              event = "FileType",
              pattern = { "clojure" },
              callback = function() vim.bo.commentstring = ";; %s" end,
              desc = "Lisp style line comment",
            },
          },
        },
        options = {
          g = {                        -- (2)!
            ["conjure#log#hud#width"] = 1,
            ["conjure#log#hud#enabled"] = false, -- show log by default?
            ["conjure#log#hud#anchor"] = "SE",
            ["conjure#log#botright"] = true,
            ["conjure#extract#context_header_lines"] = 100,
            ["conjure#eval#comment_prefix"] = ";; ",
            ["conjure#client#clojure#nrepl#connection#auto_repl#enabled"] = false,
            ["conjure#client#clojure#nrepl#connection#auto_repl#hidden"] = true,
            ["conjure#client#clojure#nrepl#connection#auto_repl#cmd"] = nil,
            ["conjure#client#clojure#nrepl#eval#auto_require"] = false,
            ["conjure#client#clojure#nrepl#test#runner"] = "kaocha",
          },
        },
      },
    },
  },
  1. autocmd config is no longer required, ts-comment.nvim is used instead
  2. global options overrides are to be reduced, with an example in Clojure pack readme showing how to override them
Treesitter Structured Editing with nvim-treesitter-sexp

A full example of nvim-treesitter-sexp configuration for AstroNvim

  -- Treesitter structural editing
  -- - package provides normal mode key mappings
  -- - practicalli config adds which-key mappings
  {
    "PaterJason/nvim-treesitter-sexp",
    filetype = { "clojure" },
    dependencies = {
      "AstroNvim/astrocore",
      opts = {
        -- configuration & keymaps overrides:
        -- https://github.com/PaterJason/nvim-treesitter-sexp#configuration
        -- enabled = false,
        --     -- Set to false to disable individual keymaps
        -- set_cursor = true,
        -- keymaps = {        -- (1)!
        -- Default key bindings - set to false to disable
        --   commands = {
        --     swap_prev_elem = "<e",
            swap_prev_elem = false,
        --     swap_next_elem = ">e",
        --     swap_prev_form = "<f",
        --     swap_next_form = ">f",
        --     promote_elem = "<LocalLeader>O",
        --     promote_form = "<LocalLeader>o",
        --     splice = "<LocalLeader>@",
        --     slurp_left = "<(",
        --     slurp_right = ">)",
        --     barf_left = ">(",
        --     barf_right = "<)",
        --     insert_head = "<I",
        --     insert_tail = ">I",
        --   },
        --   motions = {
        --     form_start = "(",
        --     form_end = ")",
        --     prev_elem = "[e",
        --     next_elem = "]e",
        --     prev_elem_end = "[E",
        --     next_elem_end = "]E",
        --     prev_top_level = "[[",
        --     next_top_level = "]]",
        --   },
        --   textobjects = {
        --     inner_elem = "ie",
        --     outer_elem = "ae",
        --     inner_form = "if",
        --     outer_form = "af",
        --     inner_top_level = "iF",
        --     outer_top_level = "aF",
        --   },
        -- },
        options = {
          g = {},
        },
        mappings = {       -- (2)!
          n = {
            -- Additional Which-key key mappings for nvim-treesitter-sexp
            ["<leader>k"] = { name = "Structural Editing" },
            ["<leader>kE"] = { "<cmd>TSSexp swap_prev_elem<cr>", desc = "Swap Previous Element" },
            ["<leader>ke"] = { "<cmd>TSSexp swap_next_elem<cr>", desc = "Swap Previous Element" },
            ["<leader>kF"] = { "<cmd>TSSexp swap_prev_form<cr>", desc = "Swap Previous Form" },
            ["<leader>kf"] = { "<cmd>TSSexp swap_next_form<cr>", desc = "Swap Previous Form" },
            ["<leader>kk"] = { "<cmd>TSSexp promote_elem<cr>", desc = "Promote Element" },
            ["<leader>kr"] = { "<cmd>TSSexp promote_form<cr>", desc = "Promote Form" },
            ["<leader>k@"] = { "<cmd>TSSexp splice<cr>", desc = "Splice" },
            ["<leader>kS"] = { "<cmd>TSSexp slurp_left<cr>", desc = "Slurp Left" },
            ["<leader>ks"] = { "<cmd>TSSexp slurp_right<cr>", desc = "Slurp Right" },
            ["<leader>kB"] = { "<cmd>TSSexp barf_left<cr>", desc = "Barf Left" },
            ["<leader>kb"] = { "<cmd>TSSexp barf_right<cr>", desc = "Barf Right" },
            ["<leader>kI"] = { "<cmd>TSSexp barf_right<cr>", desc = "Insert Head" },
            ["<leader>ki"] = { "<cmd>TSSexp barf_right<cr>", desc = "Insert Tail" },
          },
          t = {
            -- terminal? mode key bindings
          },
          v = {
            -- visual mode key bindings
          },
        },
      },
    },
  },
  1. Default keymaps can be disabled by setting the value to false
  2. Designed keymaps for discoverability along the lines of Spacemacs Lisp Mode SPC k, although deemed superfluous as the default keymaps from the plugin felt more appropriate for Neovim
Refactor of AstroCommunity Clojure language pack
-- ------------------------------------------
-- Clojure language pack
--
-- clojure-lsp server via mason
-- treesitter clojure parser
-- ts-comment.nvim with `;;` and `;` support
-- structured editing with parinfer and treesitter-sexp plugins
-- REPL connected editor with Conjure plugin (log hidden by default)
-- ------------------------------------------
return {
  -- Clojure Language Server
  {
    "williamboman/mason-lspconfig.nvim",
    optional = true,
    opts = function(_, opts)
      opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { "clojure_lsp" })
    end,
  },
  {
    "WhoIsSethDaniel/mason-tool-installer.nvim",
    optional = true,
    opts = function(_, opts)
      opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { "clojure-lsp" })
    end,
  },
  -- Clojure parser
  {
    "nvim-treesitter/nvim-treesitter",
    optional = true,
    opts = function(_, opts)
      if opts.ensure_installed ~= "all" then
        opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { "clojure" })
      end
    end,
  },

  -- Comment support `;;` and `;` (requires nvim 0.10.0)
  -- first disable potential plugin clashes
  { "numToStr/Comment.nvim", enabled = false },
  { "JoosepAlviste/nvim-ts-context-commentstring", enabled = false },
  -- Add ts-comment.nvim with Clojure comment strings
  {
    "folke/ts-comments.nvim",
    filetype = { "clojure" },
    opts = {
      lang = {
        clojure = { ";; %s", "; %s" },  --(1)!
      },
    },
    event = "VeryLazy",
    enabled = vim.fn.has "nvim-0.10.0" == 1,
  },

  -- Parinfer parens management for Clojure
  {
    "gpanders/nvim-parinfer",
    filetype = { "clojure" },
    dependencies = {
      "AstroNvim/astrocore",
      opts = {
        options = { g = {
          parinfer_force_balance = true,
          parinfer_comment_chars = ";;",
        } },
      },
    },
  },

  -- Treesitter structural editing
  -- package provides normal mode key mappings
  {
    "PaterJason/nvim-treesitter-sexp",
    filetype = { "clojure" },
    dependencies = {
      "AstroNvim/astrocore",
      opts = {
        -- configuration & keymaps overrides:
        -- https://github.com/PaterJason/nvim-treesitter-sexp#configuration
      },
    },
  },

  -- Conjure plugin for Clojure REPL
  {
    "Olical/conjure",
    -- load plugin on filetypes
    filetype = { "clojure" },
    dependencies = {
      "AstroNvim/astrocore",
      opts = {
        options = {
          g = {
            ["conjure#log#hud#enabled"] = false, -- show REPL log by default?
            ["conjure#extract#context_header_lines"] = 100, -- lines to examine for ns form
            ["conjure#eval#comment_prefix"] = ";; ",
          },
        },
      },
    },
  },
}
  1. ts-comment.nvim clojure pattern was merged into the project by pull request #19 so this configuration is now redundant

Thank you.

🌐 Practical.li Website

Practical.li GitHub Org practicalli-johnny profile

@practicalli@clj.social @practical_li