diff --git a/repl-driven-development/conjure/index.html b/repl-driven-development/conjure/index.html index a3c21a21..b3cfd2fc 100644 --- a/repl-driven-development/conjure/index.html +++ b/repl-driven-development/conjure/index.html @@ -2688,7 +2688,7 @@

Evaluation - paste contents of the register into buffer. The result of every evaluation is stored in a Neovim register as well as the log.

REPL logλ︎

The Conjure REPL log shows the results of every evaluation for the current session.

-

,lt opens log in a new tab page (tab), ,ls in horizontal split, ,ls in vertical tab

+

,lt opens log in a new tab page (tab), ,ls in horizontal split, ,lv in vertical tab

,lq - close log window / tab page

,lr - soft REPL reset, leave window open

,lR - hard REPL reset, close window & delete buffer

@@ -2719,7 +2719,7 @@

Rich commentsThe vim-jack-in plugin enables Neovim to call out to Clojure tools or Leiningen to start a REPL and connect to it once its started.

A full screen REPL log is displayed. , l q to close the log window and return to the Clojure file. -, l v to create a vertical split between code and REPL log, , l h for a horizontal split.

+, l v to create a vertical split between code and REPL log, , l s for a horizontal split.


diff --git a/search/search_index.json b/search/search_index.json index 9e51328e..c837b2fe 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Neovim for Clojure development","text":"

coding at the speed of thought

Neovim is incredibly fast and efficient, so thoughts flow from brain to editor without unnecessary delay.

Touch typing is fast, Neovim and multi-modal editing makes it even faster.

Neovim is a highly extensible and powerful editor, supporting multi-modal editing and Vim-style sequential key bindings. Highly responsive and low resource use makes Neovim ideal for development on any computer or mobile device, e.g. tablet, smartphone.

Neovim has a diverse set of plugins and Practicalli curated configurations use these plugins to provide a rich set of features for Clojure development and wider engineering tasks.

Practicalli Neovim provides install & user guide focused on a simple, powerful and satisfying REPL Driven workflow for Clojure.

"},{"location":"#quick-start","title":"Quick Start","text":"

Install Clojure, Neovim and choose a community configuration

"},{"location":"#external-reverences","title":"External reverences","text":"

Getting started with Neovim and Conjure

Neovim user guide

This Week In Neovim - community update

Conjure install guide Conjuring Clojure in Vim

"},{"location":"#navigate-the-book","title":"Navigate the book","text":"

Use the mouse or built-in key bindings to navigate the pages of the book

Use the search box to quickly find a specific topic

"},{"location":"#sponsor-my-work","title":"Sponsor my work","text":"

All sponsorship recieved is used to maintain and further develop the Practicalli series of books and videos, although most of the work is still done with my own time and cost.

Thank you to Cognitect, Nubank and a wide range of other sponsors from the Clojure community for your continued support

"},{"location":"#creative-commons-license","title":"Creative commons license","text":"This work is licensed under a Creative Commons Attribution 4.0 ShareAlike License (including images & style sheets)."},{"location":"api-tools/","title":"API Tools","text":"

Astrocommunity proivdes plugins to support working with APIs and the JSON format

Included in Practicalli Astronvim Config

Practicalli Astronvim Config includes nvim-jqx and rest.nvim plugins

"},{"location":"api-tools/#inspect-json","title":"Inspect JSON","text":"

Browse and preview json files in neovim.

:JqxList prettify JSON and start the inspector

JqxQuery to run complex jq commands

jq binary required

jq binary should be available on the command line as nvim-jqx runs jq queries internally

nvim-jqx

"},{"location":"api-tools/#call-apis","title":"Call APIs","text":"

Space r r to run an http request under the cursor from within an *.http file.

A fast Neovim http client written in Lua, providing a curl wrapper.

"},{"location":"api-tools/#http-file","title":"http file","text":"

Open a file with an *.http extension

Write a call to an API, e.g. a call to a local server health care endpoint

Call locally running API

health-check.http
GET http://localhost:8080/system-admin/status\n

A new window opens with the result of the API call

Result of API call with rest.nvim
GET http://localhost:8080/system-admin/status\nCommand :curl -sSL --compressed -X 'GET' --data-raw '' 'http://localhost:8080/system-admin/status'\n#+END\nHTTP/1.1 200 OK\nContent-Type: application/json; charset=utf-8\nContent-Length: 66\nServer: http-kit\nDate: Mon, 10 Jul 2023 16:21:33 GMT\n\n#+RESPONSE\n{\"application\":\"practicalli hole-in-one Service\",\"status\":\"Alive\"}\n#+END\n

The Content-Type can be explicitly set, especially useful when not using JSON

API call returning EDN data

GET http://localhost:8080/api/v1/scoreboard\naccept: application/edn\n

rest.nvim test examples

rest.nvim

"},{"location":"assets/images/social/","title":"Social Cards","text":"

Social Cards are visual previews of the website that are included when sending links via social media platforms.

Material for MkDocs is configured to generate beautiful social cards automatically, using the colors, fonts and logos defined in mkdocs.yml

Generated images are stored in this directory.

"},{"location":"configuration/","title":"Neovim Configuration","text":"

Practicalli Neovim covers the following configurations.

"},{"location":"configuration/#multiple-configurations","title":"Multiple Configurations","text":"

Install multiple configurations, e.g. AstroNvim, lazyvim, Nvchad, etc. in the $HOME/.config directory using unique directory names.

Set NVIM_APPNAME to specific the configuration to use when running nvim.

NVIM_APPNAME=astronvim nvim\n

NVIM_APPNAME variable should be set to the directory name containing the configuration, relative to the .config directory.

The configuration directory name is used to hold share, state and cache files for that specific configuration.

Create shell aliases for each configuration. Optionalliy, define a terminal UI selection to choose a configuration.

Shell AliasesTerminal UI Selector

Create a Shell alias for each configuration that will be used, to avoid setting the NVIM_APPNAME variable each time.

Define Shell Aliases to run each configuration

alias astro=\"NVIM_APPNAME=astronvim nvim\"\nalias lazyvim=\"NVIM_APPNAME=lazyvim nvim\"\nalias practicalli-redux=\"NVIM_APPNAME=neovim-config-redux nvim\"\n

Create an nvim configuration selector script, with items listing the directory name of each configuration

Z Shell nvim-selector script

.local/bin/nvim-selector
function nvim-selector() {\n  items=(\"astronvim\" \"neovim-config-redux\" \"lazyvim\")\n  config=$(printf \"%s\\n\" \"${items[@]}\" | fzf --prompt=\"\ue62b Neovim Config \uf63d \" --height=~50% --layout=reverse --border --exit-0)\n  if [[ -z $config ]]; then\n    echo \"Nothing selected\"\n    return 0\n  elif [[ $config == \"default\" ]]; then\n    config=\"\"\n  fi\n  NVIM_APPNAME=$config nvim $@\n}\n
"},{"location":"configuration/astronvim/","title":"AstroNvim","text":"

AstroNvim is a community configuration with an engaging UI, using Lazy for plugin management (Neovim packages) and Mason for package management (LSP, DAP, format and lint tools)

Practicalli AstroNvim Config is a user configuration that extends AstroNvim and imports packages from the AstroNvim Community.

"},{"location":"configuration/astronvim/#prerequisits","title":"Prerequisits","text":"

AstroNvim requires node.js

AstroNvim uses Mason to install LSP servers, format and lint tools. Many LSP servers require node.js to install and function.

Node.js install - Practicalli Engineering Playbook

Kitty Terminal with Nerd Fonts

Kitty Terminal - Practicalli Engineering Playbook provides examples of using Nerd Fonts or Nerd Font symbols with the Kitty terminal.

"},{"location":"configuration/astronvim/#clone-astronvim","title":"Clone AstroNvim","text":"

Clone AstroNvim repository to $HOME/.config/astronvim/

git clone --depth 1 https://github.com/AstroNvim/AstroNvim ~/.config/astronvim\n

$HOME/.config/nvim can be used instead if only ever using one configuration for Neovim.

"},{"location":"configuration/astronvim/#clone-astronvim-user-config","title":"Clone AstroNvim user config","text":"

AstroNvim provides a template repository to create a user configuration. The template includes AstroNvim Community configuration to make it easier to extend the feature of AstroNvim.

Practicalli AstroNvim Config is a clone of the AstroNvim user config with additional configuration to support Clojure development.

Practicalli AstroNvim ConfigAstroNvim User Config

Clone the Practicalli AstroNvim config which provides a user configuration with Clojure support

git clone http://github.com/practicalli/astronvim-config $HOME/.config/astronvim/lua/user\n

Or clone to a separate directory and create a symbolic link

git clone http://github.com/practicalli/astronvim-config $HOME/.config/astronvim-config && \\\nln -s $HOME/.config/astronvim-config/ $HOME/.config/astronvim/lua/user\n

Create your own user configuration using the AstroNvim user configuration template repository.

Create a repository from the AstroNvim/user_example repository template

Clone the newly created repository into the existing AstroNvim configuration, in a user directory

git clone git@github.com/<github-account>/<new-repository> $HOME/.config/astronvim/lua/user\n

"},{"location":"configuration/astronvim/#configure-shell-alias","title":"Configure shell alias","text":"

Create a shell alias that sets NVIM_APPNAME to the location of the AstroNvim community config

Add alias to .bashrc for Bash shell or .zshenv for Zsh

alias astro=\"NVIM_APPNAME=astronvim nvim\"\n

Configure shell alias

"},{"location":"configuration/astronvim/#post-install","title":"Post install","text":"

Open a terminal and use the astro alias to run Neovim.

astro\n

NVIM_APPNAME=astronvim nvim to run Neovim with astronvim without setting a shell alias.

Neovim will open and display the Lazy plugin manager UI, showing the progress of plugin installation. This should only happen on the first run.

Unattended post install

Plugins can be installed without running the Neovim editor UI

nvim --headless -c 'autocmd User LazyDone quitall'\n
"},{"location":"configuration/astronvim/#check-health","title":"Check Health","text":"

Run the Neovim :checkhealth command to report on the general Neovim install and supporting tools

"},{"location":"configuration/astronvim/#add-lsp-dap-lint-and-format-tools","title":"Add LSP DAP Lint and Format tools","text":"

SPC p m to launch Mason which manages LSP servers, linters, filters ...

"},{"location":"configuration/astronvim/#configure-format-rules","title":"Configure format rules","text":"

The configuration files for each lint and format tool should be used by Neovim.

Setting a different location for these files has proved challenging. plugin/null-ls.lua has a section to override its builtin configuration for each lint and format tool, however, in tests Practicalli was unable to succeffuly set a different location.

"},{"location":"configuration/astronvim/config-design/","title":"\ud83d\udce6 Practicalli AstroNvim Config Design","text":"

A guide to the AstroNvim Config user configuration created by Practicalli to support Clojure development.

AstroCommunity used where possible

Plugins and configuration is added vial AstroCommunity were possible, to minimise the code size and maintenance of the configuration

"},{"location":"configuration/astronvim/config-design/#user-config-overview","title":"User Config overview","text":"

core.lua is for tuning plugins shipped with astronvim config

plugins/ for additional plugins organised logically. All .lua files are read from this directory

"},{"location":"configuration/astronvim/config-design/#clojure-support","title":"Clojure support","text":"

The AstroCommunity provides a Clojure language pack that adds Conjure and nvim-parinfer, along with clojure Treesitter parser and clojure-lsp support.

AstroCommunity PackManually add plugins

Edit the plugins/community.lua file and import the Clojure pack. The \"AstroNvim/astrocommunity\", repository is already added to to the file.

-- Packs\n-- Treesitter: clojure , Lsp: clojure-lsp, Lint/format:\n{ import = \"astrocommunity.pack.clojure\" },\n
Override AstroCommunity Pack

Create a plugins/clojure.lua file and add the AstroCommunity repository, Clojure pack and additional configuration to your own preferences

Clojure configuration with user configration overrides

return {\n  \"AstroNvim/astrocommunity\",\n  { import = \"astrocommunity.pack.clojure\" },\n  {\n    \"Olical/conjure\",\n    -- load plugin on filetypes\n    ft = { \"clojure\", \"fennel\" },\n    config = function()\n      -- HUD\n      -- Example: Set to `\"SE\"` and HUD width to `1.0` for full width HUD at bottom of screen\n      vim.g[\"conjure#log#hud#width\"] = 1 -- Width of HUD as percentage of the editor width, 0.0 and 1.0.\n      vim.g[\"conjure#log#hud#enabled\"] = false -- Display HUD\n      vim.g[\"conjure#log#hud#anchor\"] = \"SE\" -- Preferred corner position for the HUD\n      vim.g[\"conjure#log#botright\"] = true -- Open log at bottom or far right of editor\n      -- REPL\n      vim.g[\"conjure#extract#context_header_lines\"] = 100 -- Number of lines to check for `ns` form\n      vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#enabled\"] = false -- ;; Start \"auto-repl\" process, eg. babashka\n      vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#hidden\"] = true -- ;; Hide auto-repl buffer when triggered\n      vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#cmd\"] = nil -- ;; Command to start the auto-repl\n      -- ;; Automatically require namespace of new buffer or current buffer after connection\n      vim.g[\"conjure#client#clojure#nrepl#eval#auto_require\"] = false\n      -- Reloading code\n      -- Function to call on refresh (reloading) the log, namespace-qualified name of a zero-arity\n      -- vim.g[\"conjure#client#clojure#nrepl#refresh#after\"] = nil\n      -- The namespace-qualified name of a zero-arity function to call before reloading.\n      -- vim.g[\"conjure#client#clojure#nrepl#refresh#before\"] = nil\n      -- List of directories to scan. If no directories given, defaults to all directories on the classpath.\n      -- vim.g[\"conjure#client#clojure#nrepl#refresh#dirs\"] = nil\n      -- Testing\n      -- ;; Test runner called from the test key mappings\n      vim.g[\"conjure#client#clojure#nrepl#test#runner\"] = \"kaocha\"\n      -- Print raw test evaluation result, suppressing prefix for stdout lines `; (out)`\n      -- vim.g[\"conjure#client#clojure#nrepl#test#raw_out\"] = nil\n      -- Override string appended to the end of the test runner calls\n      -- vim.g[\"conjure#client#clojure#nrepl#test#call_suffix\"] = nil\n    end\n  },\n  {\n    \"gpanders/nvim-parinfer\",\n    ft = lisp_dialects,\n    config = function()\n      vim.g.parinfer_force_balance = true\n      vim.g.parinfer_comment_chars = \";;\"\n    end,\n  },\n}\n

Add Conjure and parinfer plugin that will load when Clojure or Fennel file is opened.

Clojure Packages in AstroNvim user configuration

```lua title=\".config/astronvim-config/plugins/clojure.lua\"\n-- Lazy Package manager configuration\nreturn {\n  {\n    \"Olical/conjure\",\n    -- load plugin on filetypes\n    ft = { \"clojure\", \"fennel\" },\n  },\n\n  {\n    \"gpanders/nvim-parinfer\",\n    ft = { \"clojure\", \"fennel\" },\n    config = function()\n      vim.g.parinfer_force_balance = true\n      vim.g.parinfer_comment_chars = \";;\"\n    end,\n  },\n}\n```\n

Improve syntax highlighting by installing the Clojure parser for Treesitter.

Treesitter Parser for clojure in AstroNvim user configuration

.config/astronvim-config/plugins/treesitter.lua
return {\n  \"nvim-treesitter/nvim-treesitter\",\n  opts = function(_, opts)\n    -- add more things to the ensure_installed table protecting against community packs modifying it\n    opts.ensure_installed = require(\"astronvim.utils\").list_insert_unique(opts.ensure_installed, {\n      -- \"lua\"\n    \"clojure\"\n    })\n  end,\n}\n

Install Treesitter Clojure Parser manually

:TSInstall clojure in Neovim will install the parser. A parser not included in the opts.ensure_installed configuration must be updated manually each time treesitter plugin is updated

"},{"location":"configuration/astronvim/config-design/#clojure-mappings","title":"Clojure Mappings","text":"

Conjure mappings are defined respective to a <localleader> value. Define a local leader in the AstroNvim user configuration, e.g. , and all Conjure mappings become available.

AstroNvim 3.17.0 has localleader

AstroNvim 3.17.0 release sets localleader to , so a separate setting is not required in the user configuration (unless a different localleader is preferred)

Set localleader in user config

options.lua in the user configuration provides a consistent way to set Neovim options.

.config/astronvim-config/options.lua
-- set vim options here (vim.<first_key>.<second_key> = value)\nreturn {\n  opt = {\n    -- set to true or false etc.\n    relativenumber = true, -- sets vim.opt.relativenumber\n    number = true,         -- sets vim.opt.number\n    spell = false,         -- sets vim.opt.spell\n    signcolumn = \"auto\",   -- sets vim.opt.signcolumn to auto\n    wrap = false,          -- sets vim.opt.wrap\n  },\n  g = {\n    mapleader = \" \",                 -- sets vim.g.mapleader\n    maplocalleader = \",\",            -- Set local leader key binding (supports Conjure key bindings)\n    autoformat_enabled = true,       -- enable or disable auto formatting at start (lsp.formatting.format_on_save must be enabled)\n    cmp_enabled = true,              -- enable completion at start\n    autopairs_enabled = true,        -- enable autopairs at start\n    diagnostics_mode = 3,            -- set the visibility of diagnostics in the UI (0=off, 1=only show in status line, 2=virtual text off, 3=all on)\n    icons_enabled = true,            -- disable icons in the UI (disable if no nerd font is available, requires :PackerSync after changing)\n    ui_notifications_enabled = true, -- disable notifications when toggling UI elements\n    VM_leader = \"gm\"                 -- Visual Multi Leader (multiple cursors)\n  },\n}\n
"},{"location":"configuration/astronvim/config-design/#clojure-lsp","title":"Clojure LSP","text":"

Clojure LSP support is enabled via the AstroCommunity Clojure pack.

clojure_lsp can be added using Mason UI, SPC p m or in the plugins/mason.lua file

Manual user config of clojure lsp server
-- customize mason plugins\nreturn {\n  -- use mason-lspconfig to configure LSP installations\n  {\n    \"williamboman/mason-lspconfig.nvim\",\n    -- overrides `require(\"mason-lspconfig\").setup(...)`\n    opts = function(_, opts)\n      -- add more things to the ensure_installed table protecting against community packs modifying it\n      opts.ensure_installed = require(\"astronvim.utils\").list_insert_unique(opts.ensure_installed, {\n        -- \"clojure_lsp\",  -- provide by Clojure pack\n        \"marksman\", -- Markdown structure (also in markdown pack)\n        \"yamlls\",\n      })\n    end,\n  },\n}\n
"},{"location":"configuration/astronvim/config-design/#snippets","title":"Snippets","text":"

The AstroNvim user example includes a commented LuaSnip configuration

.config/astronvim-config/plugins/core.lua
  -- {\n  --   \"L3MON4D3/LuaSnip\",\n  --   config = function(plugin, opts)\n  --     require \"plugins.configs.luasnip\" (plugin, opts)  -- include the default astronvim config that calls the setup call\n  --     -- add more custom luasnip configuration such as filetype extend or custom snippets\n  --     local luasnip = require \"luasnip\"\n  --     luasnip.filetype_extend(\"javascript\", { \"javascriptreact\" })\n  --   end,\n  -- },\n

AstroNvim includes a Recipe for custom snippets

return {\n  plugins = {\n    {\n      \"L3MON4D3/LuaSnip\",\n      config = function(plugin, opts)\n        require \"plugins.configs.luasnip\"(plugin, opts) -- include the default astronvim config that calls the setup call\n        require(\"luasnip.loaders.from_vscode\").lazy_load { paths = { \"./lua/user/snippets\" } } -- load snippets paths\n      end,\n    },\n  },\n}\n

Practicalli AstroNvim Config combines the two examples to get

AstroNvim config with custom VS Code style snippets

.config/astronvim-config/plugins/core.lua
{\n  \"L3MON4D3/LuaSnip\",\n  config = function(plugin, opts)\n    require \"plugins.configs.luasnip\" (plugin, opts) -- include the default astronvim config that calls the setup call\n    -- add more custom luasnip configuration such as filetype extend or custom snippets\n    require(\"luasnip.loaders.from_vscode\").lazy_load { paths = { \"./lua/user/snippets\" } } -- load snippets paths\n    local luasnip = require \"luasnip\"\n    luasnip.filetype_extend(\"javascript\", { \"javascriptreact\" })\nend,\n},\n
"},{"location":"configuration/astronvim/config-design/#astronvim-community-packages","title":"AstroNvim Community packages","text":"

AstroNvim Community provides a large number of packages currated by the community.

Visit the AstroNvim Community repository on GitHub and browse the packages available.

import each package of interest to the plugins/community.lua file in the AstroNvim user configuration.

AstroNvim Community Packages in AstroNvim user configuration

.config/astronvim-config/plugins/community.lua
return {\n  -- Add the community repository of plugin specifications\n  \"AstroNvim/astrocommunity\",\n  -- Import each plugin from the Astro Community as required\n  { import = \"astrocommunity.editing-support.todo-comments\" },\n  { import = \"astrocommunity.git.neogit\" },\n  { import = \"astrocommunity.git.octo\" },\n  { import = \"astrocommunity.git.openingh\" },\n}\n

AstroCommunity packs set up support for each language

Language packs enabled in Practicalli AstroNvim Config

.config/astronvim-config/plugin/community.lua
  -- Packs\n  -- Treesitter: dockerfile , Lsp: dockerls & docker_compose_language_service, Lint/format: hadolint\n  { import = \"astrocommunity.pack.docker\" },\n  -- Treesitter: json & jsonc, Lsp: jsonls, Lint/format: stylua\n  { import = \"astrocommunity.pack.json\" },\n  -- Treesitter: lua, Lsp: lua_ls, Lint/format: stylua\n  { import = \"astrocommunity.pack.lua\" },\n  -- Treesitter: markdown & markdown_inline, Lsp: marksman, Lint/format: prettierd\n  -- Pack disabled as prettierd too agressive with format\n  -- { import = \"astrocommunity.pack.markdown\" },\n  -- Treesitter: markdown & markdown_inline, Lsp: marksman, Lint/format: prettierd\n  { import = \"astrocommunity.pack.yaml\" },\n
"},{"location":"configuration/astronvim/config-design/#themes","title":"Themes","text":"

Themes are a collection of one or more colorschemes to affect the apperance of text, icons, highlights, etc.

Themes supporting vim.opt.background can change between dark and light colorscheme (SPC u b UI > background in AstroNvim)

SPC f t selector shows themes colorschemes, as long as the themes are configured to disable lazy loading

The default astrodark theme is set via the colorscheme option in init.lua

Everforest provides a good dark and light theme and supports the background option to toggle between each colorscheme.

Practicalli AstroNvim Config - default theme

colorscheme = \"everforest\",\n

AstroCommunity themes

Practicalli AstroNvim Config themes

return {\n{\n\"AstroNvim/astrotheme\", -- default AstroNvim theme\nlazy = false,\n},\n  -- Add the community repository of plugin specifications\n  \"AstroNvim/astrocommunity\",\n  { import = \"astrocommunity.colorscheme.everforest\" },\n  {\n    \"sainnhe/everforest\",\n    lazy = false,\n  },\n  { import = \"astrocommunity.colorscheme.nightfox-nvim\" },\n  {\n    \"EdenEast/nightfox.nvim\",\n    lazy = false,\n  },\n  { import = \"astrocommunity.colorscheme.kanagawa-nvim\" },\n  {\n    \"rebelot/kanagawa.nvim\",\n    lazy = false,\n  },\n  { import = \"astrocommunity.colorscheme.github-nvim-theme\" }, -- no background support\n  {\n    \"projekt0n/github-nvim-theme\",\n    lazy = false,\n  },\n
"},{"location":"configuration/astronvim/config-design/#configure-lazy-plugins","title":"Configure Lazy plugins","text":"

Lazy.nvim Plugin specification

"},{"location":"configuration/astronvim/config-design/#config-format-and-lint-tools","title":"Config Format and Lint tools","text":"

Disable format on save when tools provide unexpected results

SPC u f toggles if the respective format tool should run for the current buffer. SPC u F for all buffers of the current kind.

init.lua lsp section can enable or disable format on save for specific file types.

Mason is responsible for installing lint and format tools

null-ls is responsible for running each tool and provides default configuration for code_actions, completion, diagnostics, formatting and hover.

null-ls built-in configuration

Override config file unconsistent

The configuration file defined by -config-path does not always seem to be used when running astronvim. Quit and start Neovim again seems to use the configuration file.

Override null-ls builtin configuration

Specify configuration files to use that override the null-ls builtin configuration

return {\n  \"jose-elias-alvarez/null-ls.nvim\",\n  opts = function(_, config)\n    -- config variable is the default configuration table for the setup function call\n    local null_ls = require \"null-ls\"\n    config.sources = {\n      null_ls.builtins.formatting.markdownlint.with {\n        -- pass arguments to modify/override the null-ls builtin configuration\n        extra_args = { \n          \"--config-path\", \n          vim.fn.expand(\"~/.config/astro-config/tool-config/markdownlint.yaml\") },\n      },\n    }\n    return config -- return final config table\n  end,\n}\n

vim.fn.expand() reports luacheck error accessing undefined variable but seems to work regardless

General configuration for LSP Servers .config/astronvim-config/init.lua
  lsp = {\n    -- customize lsp formatting options\n    formatting = {\n      -- control auto formatting on save\n      format_on_save = {\n        enabled = true,     -- format on save globally\n        allow_filetypes = { -- format on save for specified filetypes only\n          -- \"go\",\n        },\n        ignore_filetypes = { -- turn off format on save for specified filetypes\n          -- \"python\",\n        },\n      },\n      disabled = { -- switch off formatting capabilities for the listed language servers\n        -- turn off lua_ls formatting capability if you want to use StyLua to format your lua code\n        -- \"lua_ls\",\n        \"markdownlint\",\n      },\n      timeout_ms = 1000, -- default format timeout\n      -- filter = function(client) -- fully override the default formatting function\n      --   return true\n      -- end\n    },\n    -- enable servers that you already have installed without mason\n    servers = {\n      -- \"pyright\"\n    },\n  },\n
"},{"location":"configuration/astronvim/config-design/#override-key-binding","title":"Override Key binding","text":"

AstroNvim uses Lazy package manager to set keys for packages.

Astrocommunity configuration defines a keys table that is used by Lazy.

In the user configuration, return a function that sets key bindings to overide the keys table provided by astrocommunity

Override Key bindings for vim highlighter .config/astronvim-config/plugins/community.lua
{\n    \"vim-highlighter\",\n    keys = function() \n        return {\n            { \"<leader>nn\", \"<cmd>Hi><CR>\", desc = \"Next Recently Set Highlight\" },\n            { \"<leader>ng\", \"<cmd>Hi<<CR>\", desc = \"Previous Recently Set Highlight\" },\n            { \"<leader>n[\", \"<cmd>Hi{<CR>\", desc = \"Next Nearest Highlight\" },\n            { \"<leader>n]\", \"<cmd>Hi}<CR>\", desc = \"Previous Nearest Highlight\" },\n        }\n    end,\n}\n
"},{"location":"configuration/astronvim/config-design/#plugin-key-binding","title":"Plugin Key binding","text":"

Add key binding if a plugin is available wrapped in an if statement, when defining keys in a different place to adding the plugin, e.g whichkey mappings.lua

if is_available \"plugin-name\" then\n  ,,,\nelse\n
"},{"location":"configuration/practicalli/","title":"Neovim Config Redux","text":"

practicalli/neovim-config-redux

practicalli/neovim-config-redux is a Fennel based configuraion with a wide range of plugins and telescope extensions.

Clone practicalli/neovim-config-redux or create a fork if intending to customise that configuration

Multiple Neovim ConfigsSingle Neovim Configs
git clone https://github.com/practicalli/neovim-config-redux.git ~/.config/neovim-config-redux\n
git clone https://github.com/practicalli/neovim-config-redux.git ~/.config/nvim\n
"},{"location":"configuration/practicalli/#screenshots","title":"Screenshots","text":"

Dashboard using the startup plugin

Mnemonic menu with which-key

Telescope buffer selection

Neogit Git client with diffview panel

"},{"location":"configuration/practicalli/config-design/","title":"Config Design","text":"

The overall design of the Practicalli Neovim Config Redux

"},{"location":"configuration/practicalli/config-design/#initlua","title":"init.lua","text":""},{"location":"configuration/practicalli/config-design/#fnlconfiginitfnl","title":"fnl/config/init.fnl","text":""},{"location":"configuration/practicalli/config-design/#fnlconfigpluginfnl","title":"fnl/config/plugin.fnl","text":"

Define plugins to add functionality to Neovim.

use is a private function that searches the plugin configuration map for the keyword :mod and loads the associated namespace (namespace defined with a keyword with the same name)

e.g. in the telescope plugin configuration :mod has a value of :telescope which will load the file fnl/config/plugin/telescope.fnl

  :nvim-telescope/telescope.nvim\n  {:requires [:nvim-lua/popup.nvim\n              :nvim-lua/plenary.nvim]\n   :mod :telescope}\n

Packer downloads the nvim-telescope/telescope.nvim plugin and all the plugins in :requires section and search for the namespace telescope in file located in the following path fnl/config/plugin/telescope

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginconjurefnl","title":"fnl/config/plugin/conjure.fnl","text":"

The majority of default configuration settings are used for Conjure, with the exception of a few commonly used key bindings from Emacs CIDER & Spacemacs. The Heads Up Display (HUD) is also configured to be less intrusive, relying on mostly on inline results.

Include the conjure and aniseed namespaces

(module config.plugin.conjure\n  {autoload {nvim aniseed.nvim}})\n

Configure keybindings to be closer to Spacemacs

;; Set e register for evaluation result\n(set nvim.g.conjure#eval#result_register :e)\n\n;; Evaluate root form (top level form) under the cursor\n;; Default: `\"er\"`\n(set nvim.g.conjure#mapping#eval_root_form \"ef\")\n\n;; Evaluate root form under the cursor & insert result as comment\n;; Default: `\"ecr\"`\n(set nvim.g.conjure#mapping#eval_comment_root_form \"e;\")\n\n;; Evaluate file loaded from disk\n;; Default: `\"ef\"`\n(set nvim.g.conjure#mapping#eval_file \"el\")\n

Configure the HUD to be less intrusive.

;; Width of HUD as percentage of the editor width\n;; A float between 0.0 and 1.0.\n;; Default: `0.42`\n(set nvim.g.conjure#log#hud#width 1)\n\n;; Display HUD\n;; Default: `true`\n(set nvim.g.conjure#log#hud#enabled false)\n\n;; Preferred corner position for the HUD, over-ridden by HUD cursor detection\n;; Example: Set to `\"SE\"` and HUD width to `1.0` for full width HUD at bottom of screen\n;; Default: `\"NE\"`\n(set nvim.g.conjure#log#hud#anchor \"SE\")\n\n;; Open log at bottom or far right of editor, using full width or height\n;; Default: `false`\n(set nvim.g.conjure#log#botright true)\n

Practicalli encourages header comments at the start of each file to describe the purpose of the namespace, so the Clojure ns lookup is extended

;; Number of lines to check for `ns` form, used for setting evaluation context\n;; `b:conjure#context` to override a specific buffer that isn't finding the context\n;; Default: `24`\n(set nvim.g.conjure#extract#context_header_lines 100)\n

Disable the auto-repl as practicalli prefers manage repl connections themselves

;; Start \"auto-repl\" process, eg. babashka\n;; when Conjure unable to find candidate REPL process via to an existing nREPL connection\n;; Default: `true`\n(set nvim.g.conjure#client#clojure#nrepl#connection#auto_repl#enabled false)\n\n;; Hide auto-repl buffer when triggered, to avoid the need to interact with that buffer\n;; Default: `false`\n(set nvim.g.conjure#client#clojure#nrepl#connection#auto_repl#hidden true)\n\n;; Command to start the auto-repl\n;; Default: `\"bb nrepl-server localhost:8794\"`\n(set nvim.g.conjure#client#clojure#nrepl#connection#auto_repl#cmd nil)\n\n;; Print raw evaluation result, suppressing prefix for stdout lines `; (out)`\n;; Default: `false`\n(set nvim.g.conjure#client#clojure#nrepl#eval#raw_out true)\n\n;; Automatically require namespace of new buffer or current buffer after connection\n;; Ensures buffers are loaded, required code to compile and (re)loadable.\n;; Default: `true`\n(set nvim.g.conjure#client#clojure#nrepl#eval#auto_require false)\n

Use lambdaisland/kaocha as the test runner rather, which has a fail fast feature which can be more effective when adding or changing functionality

;; Test runner called from the test key mappings\n;; Default: `\"clojure\"`\n(set nvim.g.conjure#client#clojure#nrepl#test#runner \"kaocha\")\n\n;; Print raw test evaluation result, suppressing prefix for stdout lines `; (out)`\n;; Default: `true`\n(set nvim.g.conjure#client#clojure#nrepl#test#raw_out true)\n
"},{"location":"configuration/practicalli/config-design/#fnlconfigplugintelescopefnl","title":"fnl/config/plugin/telescope.fnl","text":"

Settings like ignore node_modules and everything in .gitignore to be listed in the file finder.

Defines a ripgrep command to set parameters for searching files

Add --hidden to see all dotfiles (regardless of .gitignore patterns)

Keymaps:

"},{"location":"configuration/practicalli/config-design/#fnlconfigplugintreesitterfnl","title":"fnl/config/plugin/treesitter.fnl","text":"

Defines which language parsers and modules to use.

(treesitter.setup\n  {:ensure_installed [\"clojure\" \"fennel\" \"markdown\"]\n   :sync_install true\n   :highlight {:enable true}\n   :indent    {:enable true}})\n
"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginlspconfigfnl","title":"fnl/config/plugin/lspconfig.fnl","text":"

Language Server Protocol for static analysis of code, to provide common formatting, linting and refactoring tooling across all programming languages.

Define which symbols to show for lsp diagnostics

(defn define-signs\n  [prefix]\n  (let [error (.. prefix \"SignError\")\n        warn  (.. prefix \"SignWarn\")\n        info  (.. prefix \"SignInfo\")\n        hint  (.. prefix \"SignHint\")]\n  (vim.fn.sign_define error {:text \"\uf057\" :texthl error})\n  (vim.fn.sign_define warn  {:text \"\uf071\" :texthl warn})\n  (vim.fn.sign_define info  {:text \"\uf05a\" :texthl info})\n  (vim.fn.sign_define hint  {:text \"\uf059\" :texthl hint})))\n
"},{"location":"configuration/practicalli/config-design/#fnlconfigplugincmpfnl","title":"fnl/config/plugin/cmp.fnl","text":"

Configure sources to show in the autocomple menu (i.e. conjure, lsp, buffer) and key bindings to navigate the autocomplete popup menu.

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginthemefnl","title":"fnl/config/plugin/theme.fnl","text":"

Add the Neovim GitHub theme which gives 3 dark and 3 light themes to choose from. Individual colors and styles can be configured to change specific parts of the theme.

The light theme is used by default, with a custom softer background colour that is slightly red-shifted.

Options are specified in the theme.setup function, where the option names are keywords and the values are strings, boolean or hash-map of more option keywords and values.

(theme.setup {:theme_style \"light\"\n              :colors {:bg \"#f8f2e6\"}\n              :comment_style \"italic\"})\n

The colors (Hex values) for each theme are in the github-nvim-theme/lua/github-theme/palette with the overal theme definition in github-nvim-theme/lua/github-theme/theme.lua

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginsexpfnl","title":"fnl/config/plugin/sexp.fnl","text":"

Settings for vim-sexp like enabling it for another lisp languages like Fennel and Jannet

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginlualinefnl","title":"fnl/config/plugin/lualine.fnl","text":"

Configure the status line (lualine) that shows at the bottom of Neovim, defining colors and elements that appear on that line.

The Neovim GitHub theme includes definitions to set the look of the status line.

"},{"location":"configuration/practicalli/packer/","title":"Package Manager","text":"

Packer is a use-package inspired package management for Neovim.

Packer is used as the package manager in this guide as it is built on native Neovim packages and supports Luarocks dependencies, use the :help packages command in Neovim for more details.

Packer is written in Lua and is installed via the init.lua configuration file, although Practicalli Neovim configuration uses Fennel to configure each package added by Packer.

"},{"location":"configuration/practicalli/packer/#install","title":"Install","text":"

init.lua is the entry point to the configuration and is the only part that is written in Lua language.

The configuration bootstraps the Packer package manager and installs the Aniseed compiler required to process the fennel configuration.

Aniseed compiles and loads fnl/config/init.fnl and all the required namespaces in that file.

Packer will process the use form in fnl/config/plugin.fnl and install all the packages defined in that form, along with any package specific configuration defined in that package {:mod :namespace-name} file.

local execute = vim.api.nvim_command\nlocal fn = vim.fn\n\nlocal pack_path = fn.stdpath(\"data\") .. \"/site/pack\"\nlocal fmt = string.format\n\nfunction ensure (user, repo)\n  -- Ensures a given github.com/USER/REPO is cloned in the pack/packer/start directory.\n  local install_path = fmt(\"%s/packer/start/%s\", pack_path, repo, repo)\n  if fn.empty(fn.glob(install_path)) > 0 then\n    execute(fmt(\"!git clone https://github.com/%s/%s %s\", user, repo, install_path))\n    execute(fmt(\"packadd %s\", repo))\n  end\nend\n\n-- Bootstrap essential plugins required for installing and loading the rest.\nensure(\"wbthomason\", \"packer.nvim\")\nensure(\"Olical\", \"aniseed\")\n\n-- Enable Aniseed's automatic compilation and loading of Fennel source code.\nvim.g[\"aniseed#env\"] = {\n  module = \"config.init\",\n  compile = true\n}\n
"},{"location":"configuration/practicalli/packer/#packages","title":"Packages","text":"

Neovim packages add extra functionality to Neovim, e.g. conjure package provides an excellent Clojure REPL experience (and supports several other languages too).

See the packages section for details of the packages used and a breakdown of their configuration.

"},{"location":"configuration/practicalli/packages/","title":"Add Neovim Packages","text":"

Evolving Packages in Practicalli config

Check the practicalli/neovim-config-reduct configuration. Many packages have been added to the configuration and fnl/config/package.fnl is the most up to date list of packages currently used.

List of packages and their purpose

Package Description conjure Clojure REPL Driven Development (and other language REPLs) sexp Structured Editing newpaper theme Clean and simple UI & colour scheme, aimed at readably lualine Fast and configurable statusline nvim-treesitter Parse code highly efficiently, client for LSP servers telescope Completion tool, e.g. select files, buffers tabs, packages, etc nvim-tree Visual file manager - open, create, delete, etc. files & directories neogit Magit style visual Git client Octo Git Issues and Pull Requests gitsigns Show diff changes in buffer gutter and status line

Any specific package configuration & key bindings (on sub page if significant content)

"},{"location":"configuration/practicalli/packages/#package-selection-criteria","title":"Package selection criteria","text":"

Packages are more likely to be adopted if:

"},{"location":"configuration/practicalli/packages/#package-updates","title":"Package Updates","text":"

This Week In Neovim - community update

"},{"location":"configuration/practicalli/packages/lualine/","title":"Lualine - modeline theme","text":"

nvim-lualine/lualine.nvim is a fast and configurable statusline for neovim

Example status line: evil_lualine

"},{"location":"configuration/practicalli/packages/lualine/#lualine-configuration-in-fennel","title":"Lualine configuration in Fennel","text":"

nvim/fnl/config/plugin/lualine.fnl

(module config.plugin.lualine\n  {autoload {core aniseed.core\n             lualine lualine\n             lsp config.plugin.lspconfig}})\n\n(defn lsp_connection []\n  (if (vim.tbl_isempty (vim.lsp.buf_get_clients 0)) \"\uf096\" \"\uf0c8\"))\n\n(def github-lua-theme\n  (core.assoc\n    (require :lualine.themes.auto)\n    :inactive {:a {:bg \"#19181e\" :fg \"#a4a3a6\"}\n               :b {:bg \"#19181e\" :fg \"#a4a3a6\"}\n               :c {:bg \"#19181e\" :fg \"#a4a3a6\"}}\n    :normal {:a {:bg \"#131217\" :fg \"#24292e\"}\n             :b {:bg \"#131217\" :fg \"#3b8eea\"}\n             :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :command {:a {:bg \"#131217\" :fg \"#24292e\"}\n              :b {:bg \"#131217\" :fg \"#ccbed8\"}\n              :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :visual {:a {:bg \"#131217\" :fg \"#24292e\"}\n             :b {:bg \"#131217\" :fg \"#ced4b1\"}\n             :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :replace {:a {:bg \"#131217\" :fg \"#24292e\"}\n              :b {:bg \"#131217\" :fg \"#d1b6bd\"}\n              :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :insert {:a {:bg \"#131217\" :fg \"#24292e\"}\n             :b {:bg \"#131217\" :fg \"#a8d1c9\"}\n             :c {:bg \"#19181e\" :fg \"#d1d5da\"}}))\n\n(lualine.setup\n  {:options {:theme github-lua-theme\n             :icons_enabled true\n             :section_separators [\"\" \"\"]\n             :component_separators [\"\uf44a\" \"\uf438\"]}\n   :sections {:lualine_a []\n              :lualine_b [[:mode {:upper true}]]\n              :lualine_c [[\"FugitiveHead\"]\n                          [:filename {:filestatus true\n                                      :path 1}]]\n              :lualine_x [[:diagnostics {:sections [:error\n                                                    :warn\n                                                    :info\n                                                    :hint]\n                                         :sources [:nvim_lsp]}]\n                          [lsp_connection]\n                          :location\n                          :filetype]\n              :lualine_y [:encoding]\n              :lualine_z []}\n   :inactive_sections {:lualine_a []\n                       :lualine_b []\n                       :lualine_c [[:filename {:filestatus true\n                                               :path 1}]]\n                       :lualine_x []\n                       :lualine_y []\n                       :lualine_z []}})\n
"},{"location":"configuration/practicalli/packages/nvim-treesitter/","title":"Nvim Treesitter","text":"

Treesitter provides language specific parsing, highlight and indent features and so is a fundamental plugin to use with Neovim.

clojure, fennel, markdown and org parsers are automatically installed in the practicalli/neovim-config-redux configuration.

"},{"location":"configuration/practicalli/packages/nvim-treesitter/#nvim-treesitter-configuration","title":"nvim-treesitter configuration","text":"

clojure, fennel, markdown and org parsers are automatically installed if not already available.

:sync_install true automatically updates the parsers when the nvim-treesitter plugin is updated. Treesitter and its parsers are actively developed, so its important to ensure parsers are kept up to date. This is the equivalent of manually running :TSUpdateSync.

Parser highlight and indent modules are enabled by default

In fnl/config/plugin/treesitter.fnl

(module config.plugin.treesitter\n  {autoload {treesitter nvim-treesitter.configs}})\n\n(treesitter.setup\n  {:ensure_installed [\"clojure\" \"fennel\" \"markdown\" \"org\"]\n   :sync_install true\n   :highlight {:enable true}\n   :indent    {:enable true}})\n
"},{"location":"configuration/practicalli/packages/nvim-treesitter/#manually-install-parsers","title":"Manually Install Parsers","text":"

nvim-treesitter provides the TSInstall command to generate a parser for a specific language, assuming that language is supported.

A compiler (gcc, clang, etc) should be installed in the operating system on which nvim is running

:TSInstall {language}\n

TAB completion lists the available language parsers, TAB and S-TAB to navigate the auto-completion popup.

"},{"location":"install/","title":"Install Overview","text":"

Practicalli Neovim provides a feature rich configuration for Neovim and all the tools required for effective Clojure development (and other Lisp dialects too).

Neovim 0.9.x latest stable release

Content and configuration in this book has been tested against Neovim 0.9.x over the summer of 2023

"},{"location":"install/#install-summary","title":"Install summary","text":"

If you are familiar with most of the tools required, then the quick start list below provides an ultra-terse version on how to get started with Neovim and Clojure development.

"},{"location":"install/#next-steps","title":"Next Steps","text":"

Learn how to use Neovim and how to use Conjure for REPL driven development

"},{"location":"install/clojure/","title":"Install Clojure","text":"

A rich Clojure REPL workflow is provided by the Conjure package, which works with Clojure CLI and Leiningen projects, assuming the respective tool is installed.

Clojure LSP is highly recommended and packages to use an installed clojure-lsp tool are in the practicalli/neovim-config-redux configuration

"},{"location":"install/clojure/#clojure-cli","title":"Clojure CLI","text":"

Practicalli Clojure install guide

Clojure CLI provides a way to run Clojure code, packaged Clojure (jar) and run a Clojure REPL.

Practicalli Clojure install guide details prerequisites, Clojure install options and supporting tools for an enhanced developer workflow.

Visit the Clojure Getting Started guide for the Clojure CLI or to check the latest release version.

Practicalli Clojure CLI Config provides a wide range of community tools that extend the features of Clojure CLI, creating a rich development environment for use across all projects.

Aliases are required for many examples

Without Practicalli Clojure CLI Config many commands provided in this book are not available unless similar alias definitions are added to a either a project or user level deps.edn configuration.

"},{"location":"install/clojure/#language-server-protocol","title":"Language Server Protocol","text":"

Neovim Treesitter surfaces information from Language Server Protocol (LSP) servers to assist with development and refactor of Clojure code.

Clojure LSP installation guide shows how to install the Clojure LSP binary for the relevant operating system.

Once installed, run clojure-lsp -v in a terminal to ensure the command is working.

practicalli/clojure-lsp-config

practicalli/clojure-lsp-config provides a complete configuration for clojure-lsp (config.edn), including a wide range of snippets and less restrictive formatting rules (cljfmt.edn)

clj-kondo provides static analysis of source code files, providing subtle warnings as Clojure code is written to help the developer follow idioms and avoid syntatic errors.

Clojure LSP includes clj-kondo to provide an implementation of the Language Server Protocol for the Clojure Language.

Clojure LSP installation guide Treesitter Fennel Configuration

"},{"location":"install/clojure/#leiningen","title":"Leiningen","text":"

Many existing Clojure projects use Leiningen build automation tool (although many new projects use Clojure CLI as well or instead of Leiningen).

The code is the same regardless of tooling choice. The overall workflow is the same, although Clojure CLI may provide more workflow options.

Follow the install instructions at Leiningen.org if required.

"},{"location":"install/neovim/","title":"Install Neovim","text":"

Neovim releases

Neovim 8 is the minimum version for this configuration and Neovim 0.9.0 is currently being tested.

Follow the install Neovim guide for the specific operating system.

"},{"location":"install/neovim/#suppoting-tools","title":"Suppoting Tools","text":"

Neovim uses several external tools for searching for files, search file contents and using the operating system clipbaord.

AstroNvim requires node.js

AstroNvim uses Mason to install LSP servers, format and lint tools. Many LSP servers require node.js to install and function.

Node.js install - Practicalli Engineering Playbook

Debian / Ubuntu

Install the following packages to support Neovim

sudo apt install find-fd xclip luarocks\n

Add set clipboard+=unnamedplus to the Neovim configuration to use the Linux clipboard tool

Wayland requires wl-clipboard

Install the wl-clipboard package to use the Wayland desktop clipboard with Neovim

sudo apt install wl-clipboard\n

"},{"location":"install/neovim/#install-neovim_1","title":"Install Neovim","text":"Linux AppImageUbuntu/DebianBuild from Source

Download the AppImage from the Neovim Release page and place the file on the executable path, e.g. $HOME/.local/bin

Make the AppImage executable

chmod u+x nvim.appimage\n

Run neovim from the AppImage

nvim.appimage\n

Create a symbolic link called nvim to the nvim.appimage

ln -s $HOME/.local/bin/nvim.appimage $HOME/.local/bin/nvim\n

Download the Linux AppImage from the Neovim Releases page

Or build Neovim from source and generate a .deb file from the build.

Linux version only packaged as AppImage from Neovim 0.9 onward

Neovim Build Prerequisites for each operating system

Ubuntu/Debian Packages

Install packages to support building Neovim

sudo apt-get install ninja-build gettext cmake unzip curl\n

Clone the Neovim GitHub repository

git clone --origin neovim https://github.com/neovim/neovim.git\n
Change into the cloned directory and change to the stable release to build version 0.9.0

git checkout stable\n

Build a release

make CMAKE_BUILD_TYPE=Release                                                                                                              \u2500\u256f\n

Once the nvim release has been built, create a debian package for use with Ubuntu and Debian systems

cpack -G DEB\n
"},{"location":"install/neovim/#post-install-checks","title":"Post Install checks","text":"

Ensure supporting tools and binaries are available in the operating system by running the Neovim Heath Check.

nvim in a terminal to run NeoVim and check the installation is working without error.

:checkhealth to run a check supporting tools are available to NeoVim.

A report is generated and shown in NeoVim

j / k to scroll through the checkhealth report

Review the warnings and install tooling that is required for languages that will be used.

Ignore Provider Warnings

It is safe to ignore language provider warnings.

Language Providers can be disabled in the Neovim configuration to remove the warnings from :checkhealth report. Examples of disabling language provders are in the practicalli/neovim-config-redux configuration, covered in the Neovim Config install step

"},{"location":"introduction/community-projects/","title":"Community Configuration Projects","text":"

Practicalli Neovim book covers the following configurations:

"},{"location":"introduction/community-projects/#practicalli-neovim-config-redux","title":"Practicalli Neovim Config Redux","text":"

Practicalli Neovim Config Redux

"},{"location":"introduction/community-projects/#astronvim-and-practicalli-astronvim-config","title":"AstroNvim and Practicalli AstroNvim Config","text":"

AstroNvim and Practicalli AstroNvim Config organised configuration with a polished UI

"},{"location":"introduction/community-projects/#alternative-configurations","title":"Alternative configurations","text":"

Practicalli Neovim does not cover the following Community configurations.

Long term project: Fennel config with AstroNvim-like UI experience

A very long term goal for Practicalli is to create a Neovim configuration written predominatly in Fennel, providing a rich user experience on par with the very polished experience of AstroNvim.

Lazy and Mason should be used to manage packages and tools (LSP & DAP servers, lint & format tools).

Which-key should provide a mnemonic menu system similar to the Spacemacs experience.

"},{"location":"introduction/contributing/","title":"Contributing to Practicalli","text":"

Practicalli books are written in markdown and use MkDocs to generate the published website via a GitHub workflow. MkDocs can also run a local server using the make docs target from the Makefile

By submitting content ideas and corrections you are agreeing they can be used in this book under the Creative Commons Attribution ShareAlike 4.0 International license. Attribution will be detailed via GitHub contributors.

All content and interaction with any persons or systems must be done so with respect and within the Practicalli Code of Conduct.

"},{"location":"introduction/contributing/#book-status","title":"Book status","text":""},{"location":"introduction/contributing/#submit-and-issue-or-idea","title":"Submit and issue or idea","text":"

If something doesnt seem quite right or something is missing from the book, please raise an issue via the GitHub repository explaining in as much detail as you can.

Raising an issue before creating a pull request will save you and the maintainer time.

"},{"location":"introduction/contributing/#considering-a-pull-request","title":"Considering a Pull request?","text":"

Before investing any time in a pull request, please raise an issue explaining the situation. This can save you and the maintainer time and avoid rejected pull requests.

Please keep pull requests small and focused, as they are much quicker to review and easier to accept. Ideally PR's should be for a specific page or at most a section.

A PR with a list of changes across different sections will not be merged, it will be reviewed eventually though.

"},{"location":"introduction/contributing/#thank-you-to-everyone-that-has-contributed","title":"Thank you to everyone that has contributed","text":"

A huge thank you to Rich Hickey and the team at Cognitect for creating and continually guiding the Clojure language. Special thank you to Alex Miller who has provided excellent advice on working with Clojure and the CLI tooling.

The Clojure community has been highly supportive of everyone using Clojure and I'd like to thank everyone for the feedback and contributions. I would also like to thank everyone that has joined in with the London Clojurins community, ClojureBridgeLondon, Clojurians Slack community, Clojurians Zulip community and Clojureverse community.

Thank you to everyone who sponsors the Practicalli websites and videos and for the Clojurists Together sponsorship, it helps me continue the work at a much faster pace.

Special thanks to Bruce Durling for getting me into Cloure in the first place.

"},{"location":"introduction/features/","title":"Neovim features","text":"

A clean UI provides for a distraction free development experience, with only the essential information presented in the Neovim statusline or inline with the code

"},{"location":"introduction/features/#conjure","title":"Conjure","text":"

Conjure An interactive environment for evaluating code, e.g. a Clojure REPL. Conjure automatically connects to an nREPL process running in the current project.

Evaluate Clojure code as its developed for an instant feedback workflow.

Run unit tests with Kaocha test runner (Cognitect Labs and ClojureScript runners also available)

Fireplace has been a long-standing plugin for Vim to support Clojure REPL connection.

"},{"location":"introduction/features/#lazy-plugin-manager","title":"Lazy Plugin manager","text":"

Lazy.nvim manages neovim plugins with a rich UI that provides an enjoyable user experience. Plugins are automatically installed during startup and lists the status of each plugins.

Plugins are automatic cached & bytecode compiled and can be lazy loaded to streamline startup time and resource usage based on events, commands, filetypes, and key mappings. Efficient plugin downlaods using partial blobless clones of plugin repositories, i.e. --filter=blob:none

Lazy.nvim

"},{"location":"introduction/features/#treesitter","title":"Treesitter","text":"

Neovim provides highly effective syntax highlighting of source code due to Treesitter.

Tree-sitter parses files opened in Neovim and builds a concrete syntax tree that any Neovim plugin can use to efficiently provide feedback. Treesitter uses incremental parsing to efficiently update the syntax tree as a file is edited.

Treesitter

"},{"location":"introduction/features/#language-server-protocol","title":"Language Server Protocol","text":"

Neovim includes an LSP client which uses the information recieved from a language specific LSP server in real-time to provide a range of services:

LSP feedback is often presented in the buffer, file browser and status line of Neovim.

LSP Server implementation is not universal

LSP is a relatively new specification and many server implmentations are still evolving or are yet to be created.

Lint tools tend to be more prevelent and may be required in concert with or in the absence of an LSP server.

LSP related Plugins "},{"location":"introduction/features/#lint-and-format-tools","title":"Lint and format tools:","text":"

Linters check code for common problems and provide hints on how to correct any detected issues.

Format tools suppor code to conforming to a specified coding style, typically these run when save-file is run.

null-ls provides extensive builtin configuration for programming languages and configuration formats. null-ls also passes lint and format tool information to the Neovim LSP client, extending the range of language support.

"},{"location":"introduction/features/#selection-narrowing","title":"Selection Narrowing","text":"

telescope.nvim is a highly extendable fuzzy finder over lists with community driven pickers, sorters and previewers.

Navigate and narrow lists of files, packages, environment variables, ports, colour schemes (themes) and any other list of items effectively.

Telescope File browser popup also explores the file system and in Normal mode can be used to create files and directories

The telescope list narrows matches as characters are typed

"},{"location":"introduction/features/#version-control","title":"Version Control","text":"

Gitsigns hightlights buffer changes in the gutter

Lualine shows number of Git changes in status line

Diffview to review all changes for any git revision

Neogit provides a rich git client to add, stash, commit, push & pull changes.

Octo provides a GitHub specific client to manage issues and pull requests, using GitHub CLI authentication.

LazyGit UI

"},{"location":"introduction/features/#file-browser","title":"File Browser","text":"

neo-tree provides a visual file system explorer that can also create and delete files and directories

"},{"location":"introduction/features/#todo-comments","title":"TODO Comments","text":"

Highlight tasks, fixes, notes and dragons comments, including icons in the gutter. Use Telescope to navigate TODO comments in the current project.

"},{"location":"introduction/features/#status-line","title":"Status Line","text":"

LSP feedback

"},{"location":"introduction/features/#markdown","title":"Markdown","text":""},{"location":"introduction/fennel/","title":"Fennel","text":"

Lua is the defacto language for Neovim plugin development and configuration.

Fennel can be used to write Neovim packages and configuration, using nfnl to generate the equivalent Lua code that Neovim runs.

Although Neovim fully supports Vimscript, Practicalli encourages Fennel or Lua, as Vimscript is a niche language with quite complex syntax.

"},{"location":"introduction/fennel/#overview","title":"Overview","text":"

Fennel is a programming language that brings together the speed, simplicity, and reach of Lua with the flexibility of a lisp syntax and macro system.

Anywhere you can run Lua code, you can run Fennel code.

Translate Lua to Fennel

See Fennel is an online antifennel tool to convert Lua to Fennel or Fennel to Lua.

practicalli/neovim-config-redux configuration provides helper functions to minimise the translation required.

"},{"location":"introduction/fennel/#fennel-packages","title":"Fennel Packages","text":"

The Conjure package which provides the Clojure REPL (and much more) is written in Fennel.

"},{"location":"introduction/fennel/#nfnl","title":"nfnl","text":"

nfnl generates Lua code from Fennel code. Neovim runs the generated Lua code.

nfnl loads only when working in directories containing a .nfnl.fnl configuration file, so has zero overhead when not working with fennel.

*.fnl files are automatically compiled to *.lua when changes are saved, showing any compilation errors to provide an effective feedback loop.

nfnl standard library

nfnl plugin example

"},{"location":"introduction/fennel/#development-tooling","title":"Development tooling","text":"

Neovim support

See Fennel is an online antifennel tool to convert between Lua and Fennel.

Guide to plugin development with fennel

Emacs support:

"},{"location":"introduction/fennel/#playing-games","title":"Playing Games","text":"

TIC-80 is a simulated computer environment to to write code, design art, compose music and retro style game games.

L\u00d6VE is a framework for making games with the Lua programming language, allows import from external resources and can use any resolution or memory resources required.

TIC-80 and L\u00d6VE provide cross-platform support across Windows, Mac and Linux systems. TIC-80 games can also be played in the browser.

"},{"location":"introduction/repl-workflow/","title":"REPL Driven Development","text":"

Always be REPL'ing

Coding without a REPL feels limiting. The REPL provides fast feedback from code as its crafted, testing assumptions and design choices every step of the journey to a solution - John Stevenson, Practical.li

Clojure is a powerful, fun and highly productive language for developing applications and services. The clear language design is supported by a powerful development environment known as the REPL (read, evaluate, print, loop). The REPL gives you instant feedback on what your code does and enables you to test either a single expression or run the whole application (including tests).

REPL driven development is the foundation of working with Clojure effectively

An effective Clojure workflow begins by running a REPL process. Clojure expressions are written and evaluated immediately to provide instant feedback. The REPL feedback helps test the assumptions that are driving the design choices.

Design decisions and valuable data from REPL experiments can be codified as specifications and unit tests

Practicalli REPL Reloaded Workflow

The principles of REPL driven development are implemented in practice using the Practicalli REPL Reloaded Workflow and supporting tooling. This workflow uses Portal to inspect all evaluation results and log events, hot-load libraries into the running REPL process and reloads namespaces to support major refactor changes.

"},{"location":"introduction/repl-workflow/#evaluating-source-code","title":"Evaluating source code","text":"

A REPL connected editor is the primary tool for evaluating Clojure code from source code files, displaying the results inline.

Source code is automatically evaluated in its respective namespace, removing the need to change namespaces in the REPL with (in-ns) or use fully qualified names to call functions.

Evaluate Clojure in Neovim with Conjure

, e b evaluates the code in the current buffer

Evaluate Clojure in a Terminal UI REPL

Entering expressions at the REPL prompt evaluates the expression immediately, returning the result directly underneath

"},{"location":"introduction/repl-workflow/#rich-comment-blocks-living-documentation","title":"Rich Comment blocks - living documentation","text":"

The (comment ,,,) function wraps code that is only run directly by the developer using a Clojure aware editor.

Expressions in rich comment blocks can represent how to use the functions that make up the namespace API. For example, starting/restarting the system, updating the database, etc. Expressions provide examples of calling functions with typical arguments and make a project more accessible and easier to work with.

Clojure Rich Comment to manage a service

(ns practicalli.gameboard.service)\n\n(defn app-server-start [port] ,,,)\n(defn app-server-start [] ,,,)\n(defn app-server-restart [] ,,,)\n\n(defn -main\n  \"Start the service using system components\"\n  [& options] ,,,)\n\n(comment\n  (-main)\n  (app-server-start 8888)\n  (app-server-stop)\n  (app-server-restart 8888)\n\n  (System/getenv \"PORT\")\n  (def environment (System/getenv))\n  (def system-properties (System/getProperties))\n  ) ; End of rich comment block\n

Rich comment blocks are very useful for rapidly iterating over different design decisions by including the same function but with different implementations. Hide clj-kondo linter warnings for redefined vars (def, defn) when using this approach.

;; Rich comment block with redefined vars ignored\n#_{:clj-kondo/ignore [:redefined-var]}\n(comment\n  (defn value-added-tax []\n    ;; algorithm design - first idea)\n\n  (defn value-added-tax []\n    ;; algorithm design - second idea)\n\n  ) ;; End of rich comment block\n

The \"Rich\" in the name is an honourary mention to Rich Hickey, the author and benevolent dictator of Clojure design.

"},{"location":"introduction/repl-workflow/#design-journal","title":"Design Journal","text":"

A journal of design decisions makes the code easier to understand and maintain. Code examples of design decisions and alternative design discussions are captured, reducing the time spent revisiting those discussions.

Journals simplify the developer on-boarding processes as the journey through design decisions are already documented.

A Design Journal is usually created in a separate namespace, although it may start as a rich comment at the bottom of a namespace.

A journal should cover the following aspects

The design journal can be used to create meaningful documentation for the project very easily and should prevent time spent on repeating the same conversations.

Example design journal

Design journal for TicTacToe game using Reagent, ClojureScript and Scalable Vector Graphics

"},{"location":"introduction/repl-workflow/#viewing-data-structures","title":"Viewing data structures","text":"

Pretty print shows the structure of results from function calls in a human-friendly form, making it easier for a developer to parse and more likely to notice incorrect results.

Tools to view and navigate code

"},{"location":"introduction/repl-workflow/#code-style-and-idiomatic-clojure","title":"Code Style and idiomatic Clojure","text":"

Clojure aware editors should automatically apply formatting that follows the Clojure Style guide.

Live linting with clj-kondo suggests common idioms and highlights a wide range of syntax errors as code is written, minimizing bugs and therefore speeding up the development process.

Clojure LSP is build on top of clj-kondo

Clojure LSP uses clj-kondo static analysis to provide a standard set of development tools (format, refactor, auto-complete, syntax highlighting, syntax & idiom warnings, code navigation, etc).

Clojure LSP can be used with any Clojure aware editor that provides an LSP client, e.g. Spacemacs, Doom Emacs, Neovim, VSCode.

Clojure Style Guide

The Clojure Style guide provides examples of common formatting approaches, although the development team should decide which of these to adopt. Emacs clojure-mode will automatically format code and so will Clojure LSP (via cljfmt). These tools are configurable and should be tailored to the teams standard.

"},{"location":"introduction/repl-workflow/#data-and-function-specifications","title":"Data and Function specifications","text":"

Clojure spec is used to define a contract on incoming and outgoing data, to ensure it is of the correct form.

As data structures are identified in REPL experiments, create data specification to validate the keys and value types of that data.

;; ---------------------------------------------------\n;; Address specifications\n(spec/def ::house-number string?)\n(spec/def ::street string?)\n(spec/def ::postal-code string?)\n(spec/def ::city string?)\n(spec/def ::country string?)\n(spec/def ::additional string?)\n\n(spec/def ::address   ; Composite data specification\n  (spec/keys\n   :req-un [::street ::postal-code ::city ::country]\n   :opt-un [::house-number ::additional]))\n;; ---------------------------------------------------\n

As the public API is designed, specifications for each functions arguments are added to validate the correct data is used when calling those functions.

Generative testing provides a far greater scope of test values used incorporated into unit tests. Data uses clojure.spec to randomly generate data for testing on each test run.

"},{"location":"introduction/repl-workflow/#test-driven-development-and-repl-driven-development","title":"Test Driven Development and REPL Driven Development","text":"

Test Driven Development (TDD) and REPL Driven Development (RDD) complement each other as they both encourage incremental changes and continuous feedback.

Test Driven Development fits well with Hammock Time, as good design comes from deep thought

Unit tests should support the public API of each namespace in a project to help prevent regressions in the code. Its far more efficient in terms of thinking time to define unit tests as the design starts to stabilize than as an after thought.

clojure.test library is part of the Clojure standard library that provides a simple way to start writing unit tests.

Clojure spec can also be used for generative testing, providing far greater scope in values used when running unit tests. Specifications can be defined for values and functions.

Clojure has a number of test runners available. Kaocha is a test runner that will run unit tests and function specification checks.

Automate local test runner

Use kaocha test runner in watch mode to run tests and specification check automatically (when changes are saved)

clojure -X:test/watch\n

"},{"location":"introduction/repl-workflow/#continuous-integration-and-deployment","title":"Continuous Integration and Deployment","text":"

Add a continuous integration service to run tests and builds code on every shared commit. Spin up testable review deployments when commits pushed to a pull request branch, before pushing commits to the main deployment branch, creating an effective pipeline to gain further feedback.

"},{"location":"introduction/repl-workflow/#live-coding-with-data-stuart-halloway","title":"Live Coding with Data - Stuart Halloway","text":"

There are few novel features of programming languages, but each combination has different properties. The combination of dynamic, hosted, functional and extended Lisp in Clojure gives developers the tools for making effective programs. The ways in which Clojure's unique combination of features can yield a highly effective development process.

Over more than a decade we have developed an effective approach to writing code in Clojure whose power comes from composing many of its key features. As different as Clojure programs are from e.g. Java programs, so to can and should be the development experience. You are not in Kansas anymore!

This talk presents a demonstration of the leverage you can get when writing programs in Clojure, with examples, based on my experiences as a core developer of Clojure and Datomic.

"},{"location":"introduction/writing-tips/","title":"Writing tips for MkDocs","text":"

Making the docs more engaging using the mkdocs-material theme reference guide

Configuring Colors

Material for MkDocs - Changing the colors lists the primary and accent colors available.

HSL Color Picker for codes to modify the theme style, overriding colors in docs/assets/stylesheets/extra.css

"},{"location":"introduction/writing-tips/#hypertext-links","title":"Hypertext links","text":"

Links open in the same browser window/tab by default.

Add {target=_blank} to the end of a link to configure opening in a new tab

[link text](url){target=_blank}\n
"},{"location":"introduction/writing-tips/#buttons","title":"Buttons","text":"

Convert any link into a button by adding {.md-button} class names to end of the markdown for a link, which uses .md-button-primary by default. Include target=_blank for buttons with links to external sites.

[link text](http://practical.li/blog){.md-button target=_blank}\n

Or specify a different class

[link text](http://practical.li/blog){.md-button .md-button-primary}\n

Add an icon to the button

Practicalli Issues Practicalli Blog

[:fontawesome-brands-github: Practicalli Issues](http://practical.li/blog){ .md-button .md-button-primary }\n[:octicons-heart-fill-24: Practicalli Blog](http://practical.li/blog){ .md-button .md-button-primary }\n

Search all supported icons

"},{"location":"introduction/writing-tips/#youtube-video","title":"YouTube video","text":"

Use an iframe element to include a YouTube video, wrapping in a paragraph tag with center alignment to place the video in a centered horizontal position

<p style=\"text-align:center\">\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/rQ802kSaip4\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n</p>\n

mkdocs material does not have direct support for adding a YouTube video via markdown.

"},{"location":"introduction/writing-tips/#admonitions","title":"Admonitions","text":"

Supported admonition types

Note

Use !!! followed by NOTE

Adding a title

Use !!! followed by NOTE and a \"title in double quotes\"

Shh, no title bar just the text... Use !!! followed by NOTE and a \"\" empty double quotes

Abstract

Use !!! followed by ABSTRACT

Info

Use !!! followed by INFO

Tip

Use !!! followed by TIP

Success

Use !!! followed by SUCCESS

Question

Use !!! followed by QUESTION

Warning

Use !!! followed by WARNING

Failure

Use !!! followed by FAILURE

Danger

Use !!! followed by DANGER

Bug

Use !!! followed by BUG

Example

Use !!! followed by EXAMPLE

Quote

Use !!! followed by QUOTE

"},{"location":"introduction/writing-tips/#collapsing-admonitions","title":"Collapsing admonitions","text":"Note

Collapse those admonitions using ??? instead of !!!

Replace with a title

Use ??? followed by NOTE and a \"title in double quotes\"

Expanded by default

Use ???+, note the + character, followed by NOTE and a \"title in double quotes\"

"},{"location":"introduction/writing-tips/#inline-blocks","title":"Inline blocks","text":"

Inline blocks of text to make a very specific callout within text

Info

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Adding something to then end of text is probably my favourite

Info

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

"},{"location":"introduction/writing-tips/#code-blocks","title":"Code blocks","text":"

Code blocks include a copy icon automatically

Syntax highlighting in code blocks

(defn my-function  ; Write a simple function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map inc [1 2 3]))\n

Give the code block a title using title=\"\" after the backtics and language name

src/practicalli/gameboard.clj
(defn my-function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map inc [1 2 3]))\n

We all like line numbers, especially when you can set the starting line

src/practicalli/gameboard.clj
(defn my-function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map inc [1 2 3]))\n

Add linenums=42 to start line numbers from 42 onward

clojure linenums=\"42\" title=\"src/practicalli/gameboard.clj\"\n
"},{"location":"introduction/writing-tips/#annotations","title":"Annotations","text":"

Annotations in a code block help to highlight important aspects. Use the comment character for the language followed by a space and a number in brackets

For example, in a shell code block, use # (1) where 1 is the number of the annotation

Use a number after the code block to add the text for the annotation, e.g. 1.. Ensure there is a space between the code block and the annotation text.

ls -la $HOME/Downloads  # (1)\n
  1. I'm a code annotation! I can contain code, formatted text, images, ... basically anything that can be written in Markdown.

Code blocks with annotation, add ! after the annotation number to suppress the # character

(defn helper-function\n  \"Doc-string with description of function purpose\" ; (1)!\n  [data]\n  (merge {:fish 1} data)\n  )\n
  1. Always include a doc-string in every function to describe the purpose of that function, identifying why it was added and what its value is.

GitHub action example with multiple annotations

name: ci # (1)!\non:\n  push:\n    branches:\n      - master # (2)!\n      - main\npermissions:\n  contents: write\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.x\n      - run: pip install mkdocs-material # (3)!\n      - run: mkdocs gh-deploy --force\n
  1. You can change the name to your liking.

  2. At some point, GitHub renamed master to main. If your default branch is named master, you can safely remove main, vice versa.

  3. This is the place to install further [MkDocs plugins] or Markdown extensions with pip to be used during the build:

    pip install \\\n  mkdocs-material \\\n  mkdocs-awesome-pages-plugin \\\n  ...\n
"},{"location":"introduction/writing-tips/#highlight-lines-in-code-blocks","title":"Highlight lines in code blocks","text":"

Add highlight line meta data to a code block after the opening backticks and code block language.

hl_lines=\"2\" highlights line 2 in the codeblock

hl_lines=\"2 3 4\" highlights line 2, 3 and 4 in the codeblock

(defn my-function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map\n   inc\n   [1 2 3]))\n
"},{"location":"introduction/writing-tips/#embed-external-files","title":"Embed external files","text":"

--8<-- in a code block inserts code from a source code file or other text file

Specify a local file from the root of the book project (the directory containing mkdocs.yml)

Scheduled Version Check GitHub Workflow from source code file scheduled version check
---\n# ------------------------------------------\n# Scheduled check of versions\n# - use as non-urgent report on versions\n# - Uses POSIX Cron syntax\n#   - Minute [0,59]\n#   - Hour [0,23]\n#   - Day of the month [1,31]\n#   - Month of the year [1,12]\n#   - Day of the week ([0,6] with 0=Sunday)\n#\n# Using liquidz/anta to check:\n# - GitHub workflows\n# - deps.edn\n# ------------------------------------------\n\nname: \"Scheduled Version Check\"\non:\n  schedule:\n    # - cron: \"0 4 * * *\" # at 04:04:04 ever day\n    # - cron: \"0 4 * * 5\" # at 04:04:04 ever Friday\n    - cron: \"0 4 1 * *\" # at 04:04:04 on first day of month\n  workflow_dispatch: # Run manually via GitHub Actions Workflow page\n\njobs:\n  scheduled-version-check:\n    name: \"Scheduled Version Check\"\n    runs-on: ubuntu-latest\n    steps:\n      - run: echo \"\ud83d\ude80 Job automatically triggered by ${{ github.event_name }}\"\n      - run: echo \"\ud83d\udc27 Job running on ${{ runner.os }} server\"\n      - run: echo \"\ud83d\udc19 Using ${{ github.ref }} branch from ${{ github.repository }} repository\"\n\n      - name: \"Checkout code\"\n        uses: actions/checkout@v4\n      - run: echo \"\ud83d\udc19 ${{ github.repository }} repository was cloned to the runner.\"\n\n      - name: \"Antq Check versions\"\n        uses: liquidz/antq-action@main\n        with:\n          excludes: \"\"\n          skips: \"boot clojure-cli pom shadow-cljs leiningen\"\n\n      # Summary\n      - run: echo \"\ud83c\udfa8 library versions checked with liquidz/antq\"\n      - run: echo \"\ud83c\udf4f Job status is ${{ job.status }}.\"\n
Practicalli Project Templates Emacs project configuration - .dir-locals.el
((clojure-mode . ((cider-preferred-build-tool . clojure-cli)\n                  (cider-clojure-cli-aliases . \":test/env:dev/reloaded\"))))\n

Code example reuse

Use an embedded local or external file (URL) when the same content is required in more than one place in the book.

An effective way of sharing code and configuration mutliple times in a book or across multiple books.

"},{"location":"introduction/writing-tips/#content-tabs","title":"Content tabs","text":"

Create in page tabs that can also be

Setting up a project

Clojure CLILeiningen
clojure -T:project/new :template app :name practicalli/gameboard\n
lein new app practicalli/gameboard\n

Or nest the content tabs in an admonition

Run a terminal REPL

Clojure CLILeiningen
clojure -T:repl/rebel\n
lein repl\n
"},{"location":"introduction/writing-tips/#diagrams","title":"Diagrams","text":"

Neat flow diagrams

Diagrams - Material for MkDocs

graph LR\n  A[Start] --> B{Error?};\n  B -->|Yes| C[Hmm...];\n  C --> D[Debug];\n  D --> B;\n  B ---->|No| E[Yay!];

UML Sequence Diagrams

sequenceDiagram\n  Alice->>John: Hello John, how are you?\n  loop Healthcheck\n      John->>John: Fight against hypochondria\n  end\n  Note right of John: Rational thoughts!\n  John-->>Alice: Great!\n  John->>Bob: How about you?\n  Bob-->>John: Jolly good!

state transition diagrams

stateDiagram-v2\n  state fork_state <<fork>>\n    [*] --> fork_state\n    fork_state --> State2\n    fork_state --> State3\n\n    state join_state <<join>>\n    State2 --> join_state\n    State3 --> join_state\n    join_state --> State4\n    State4 --> [*]

Class diagrams - not needed for Clojure

Entity relationship diagrams are handy though

erDiagram\n  CUSTOMER ||--o{ ORDER : places\n  ORDER ||--|{ LINE-ITEM : contains\n  LINE-ITEM {\n    customer-name string\n    unit-price int\n  }\n  CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
"},{"location":"introduction/writing-tips/#keyboard-keys","title":"Keyboard keys","text":"

Represent key bindings with Keyboard keys. Each number and alphabet character has their own key.

Punctionation keys use their name

For key sequences, place a space between each keyboard character

For key combinations, use join they key identifies with a +

MkDocs keyboard keys reference

"},{"location":"introduction/writing-tips/#images","title":"Images","text":"

Markdown images can be appended with material tags to set the size of the image, whether to appear on light or dark theme and support lazy image loading in browsers

SizeLazy LoadingAlignTheme SpecificAll Image Attributes

{style=\"height:150px;width:150px\"} specifies the image size

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style=\"height:150px;width:150px\"}\n

{loading=lazy} specifies an image should lazily load in the browser

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png){loading=lazy}\n

{aligh=left} or {aligh=right} specifies the page alignment of an image.

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){align=right}\n![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){align=right}\n

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

![Kitty Logo](image/kitty-light.png#only-dark) or ![Kitty Logo](image/kitty-light.png#only-light) specifies the theme the image should be shown, allowing different versions of images to be shown based on the theme.

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style=\"height:150px;width:150px\"}\n![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){style=\"height:150px;width:150px\"}\n
Use the theme toggle in the top nav bar to see the icon change between light and dark.

Requires the color pallet toggle

Alight right, lazy load and set image to 150x150

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){align=right loading=lazy style=\"height:64px;width:64px\"}\n![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){align=right loading=lazy style=\"height:64px;width:64px\"}\n

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

"},{"location":"introduction/writing-tips/#lists","title":"Lists","text":"

Task lists

Task List example

- [x] Lorem ipsum dolor sit amet, consectetur adipiscing elit\n- [ ] Vestibulum convallis sit amet nisi a tincidunt\n    * [x] In hac habitasse platea dictumst\n    * [x] In scelerisque nibh non dolor mollis congue sed et metus\n    * [ ] Praesent sed risus massa\n- [ ] Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque\n
"},{"location":"introduction/writing-tips/#tooltips","title":"Tooltips","text":"

The humble tool tip

Hover me

with references

Hover me

Icon tool tip with a title

"},{"location":"introduction/writing-tips/#abreviations","title":"Abreviations","text":"

The HTML specification is maintained by the W3C.

[HTML]: Hyper Text Markup Language [W3C]: World Wide Web Consortium

"},{"location":"introduction/writing-tips/#magic-links","title":"Magic links","text":"

MagicLink can auto-link HTML, FTP, and email links. It can auto-convert repository links (GitHub, GitLab, and Bitbucket) and display them in a more concise, shorthand format.

Email Practicalli

Practicalli Neovim

"},{"location":"neovim-basics/","title":"Using Neovim","text":"

The fundamental controls of Neovim which apply across all editing tasks.

"},{"location":"neovim-basics/#fundamentals","title":"Fundamentals","text":"

File Buffer Window and Tab page Multi-modal Editing

"},{"location":"neovim-basics/#editing-tools","title":"Editing Tools","text":"

Multiple Cursors

"},{"location":"neovim-basics/#writing-tools","title":"Writing Tools","text":"

Snippets

"},{"location":"neovim-basics/#development-tools","title":"Development Tools","text":"

Comments Clojure Development Version Control

Format and Lint tools are installed via Mason

"},{"location":"neovim-basics/#spellcheck","title":"Spellcheck","text":"AstroNvim

SPC u s toggles spellcheck, marking misspelt words with a rew wavy underline

] s jumps to next misspelt word, [ s jumps to previous misspelt word,

z = shows numbered list of possible words, enter the number next to the work to replace the misspelt word.

z g to add the current word to the spell list, infroming spellcheck that this is a correct word.

"},{"location":"neovim-basics/comments/","title":"Comments","text":"

comment.nvim toggles a comment for lines, visual selections or for motions

gcc comment current line, 4gcc comment current line and next 4 lines

gc comment region or use with motion e.g. gcap comment paragraph,

gc in operator pending mode to target a comment TODO: what is operator pending mode

:7,17Commentary comment a range

:g/TODO/Commentary as part of a :global invocation

gcgc removes comments from a set of adjacent commented lines.

"},{"location":"neovim-basics/file-buffer-window-tab/","title":"Files Buffers Windows and Tabs","text":"

Files are text written to perminant storage, e.g. disk or usb drive and are names with an extension that represents the file type, e.g. .clj for clojure, .md for markdown, etc.

A Buffer hold the contents of a file or any other information from processes, e.g. the REPL evaluation log.

Windows are a view on a buffer and windows can swap which buffer they show. Multiple windows, also known as splits, can be present in a Neovim frame.

A tab page (or tab) can hold one or more windows and multiple tab pages can be shown on a tab-line.

"},{"location":"neovim-basics/file-buffer-window-tab/#files","title":"Files","text":"

Use Neo-tree.nvim to visually navigate and manage files using a tree view of the current project. Files and directories can be added, renamed, moved and deleted.

Use Telescope to select files, typing a name narrows the file list.

"},{"location":"neovim-basics/file-buffer-window-tab/#using-neo-tree","title":"Using Neo-tree","text":"AstronvimPracticalli Neovim Config Redux

Space e toggles neo-tree file browser

Space o toggles between buffer and neo-tree

Space f t t to open file explorer

Within Neo-tree:

h j k l to navigate the file tree hierachy

< and > to navigate between File, Bufs and Git sources tabs

? shows neotree help, listing key bindings

a adds a file, prompting for a name relative to the directory where a was pressed. The name can include new directories to be created. A name ending with ++forward-slash++ will create a directory rather than a file.

d deletes the current file or directory (including sub-directories), a conformation prompt is shown

r to rename a file or directory (use move to change the path)

m to move a file or directory, optionally renaming too

Neotree icons

"},{"location":"neovim-basics/file-buffer-window-tab/#telescope","title":"Telescope","text":"

Telescope provides a selector which will narrow the list of matches as a pattern is typed, providing a fast way to find an item in a list.

Telescope provides a preview of the selected file (only if there is sufficient space in the Neovim frame)

File lists are relative to the directory Neovim was opened from (or Path subsequently set in Neovim).

AstroNvimPracticalli Neovim Config Redux

SPC f f selector for files within the scope of the current directory path. SPC f F to also show hidden files from the current directory path.

SPC f a selector for AstroNvim user configuration files

SPC f p selector for previously opened files (oldfiles)

SPC f f to list files within the scope of the current directory path.

SPC f b provides a file browser to open files, navigate the file space and create new files and directories

"},{"location":"neovim-basics/file-buffer-window-tab/#save-file","title":"Save File","text":"

Files and directories are created in the path given, relative to the directory in which Neovim was opened.

A file must exist for Neovim to write to it. Neo-tree and Telescope can be used to create files and directories, as can a terminal and the command line integration (!)

AstronvimPracticalli Neovim Config ReduxNeovim

Space w will write all buffer changes to the associate file.

Space n creates a new buffer that can be written to a given file using :write path/to/filename

:write path/to/filename will write the current buffer to a new file.

SPC f b ESC C to create a new file or directory. The base path is shown in the command bar. Type the name of directories and file name as required. RTN to create or ESC to cancel. The newly created directories or file name appears n the Telescope list and scan be selected for opening.

Telescope Normal mode and help

ESC in Telescope to switch to Normal mode and use comannds, c for Create, r to rename.

? to show all the commands available in Telescope

:lcd to set the current local directory

:write path/to/filename will write the current buffer to a new file

:!mkdir path/to/directory will create a new directory

If a file is already opened, i.e. with :edit, there is some short-hand syntax to simplify the typing

:!mkdir -p %:h

-p option createst any parts of the path required to make the full path

% is the neovim name of the current file

:h for the current directory (the \u201chead\u201d of the path).

! is the NeoVim terminal shell command, e.g. :!mkdir -p path/to/new/directory creates a new directory and any intermediate path

"},{"location":"neovim-basics/file-buffer-window-tab/#swap-file","title":"Swap file","text":"

Neovim creates a swap file, .swp, containing the changes made in a buffer to minimise loss should there be an issue with the computer or Neovim. Changes are written to the swap file after 200 characters or after 4 seconds pause.

Swap file location

:swapname shows the full path to the swap file for the current buffer, e.g.

/home/practicalli/.local/state/astronvim/swap//%home%practicalli%projects%practicalli%books%neovim%docs%neovim-basics%files-buffers-windows.md.swp`\n

:preserve command will write all text from current buffer to the swap file.

:recover command overwrites the current buffer with the data from the swap file. :recover! command must be use if the buffer has newer changes than the swap file. Add a filename after the command to recover to a different file than that contained in the current buffer.

Opening a file checks if there is an associated swap file and prompts the user

:edit after the file is open also prompts if there is a swap file. Selecting (D)elete will delete the swap file without changing the current buffer

"},{"location":"neovim-basics/file-buffer-window-tab/#buffers","title":"Buffers","text":"AstroNvimPracticalli Neovim Config Redux

SPC f b selector for currently open buffers

SPC b b to select a buffer from the tab line, pressing the character that appears next to the buffer tab (case sensitive)

SPC b D to delete a buffer from the tab line, pressing the character that appears next to the buffer tab (case sensitive)

Open multiple buffers when starting Neovim by specifying multiple files to open

astro README.md deps.edn src/practicalli/playground.clj test/practicalli/playground.clj\n

SPC b b switch between buffers in the current window, using a Telescope popup that lists all current buffers (includes files, Conjure REPL Log, etc.).

SPC b n (:next) and SPC b n (:previous) to cycle through buffers in the current window

SPC TAB (C-^) opens the previous buffer, useful to toggle between two buffers in the same window

Use Telescope to switch between buffers

Open multiple buffers when starting Neovim by specifying multiple files to open

nvim README.md deps.edn src/practicalli/playground.clj test/practicalli/playground.clj\n
"},{"location":"neovim-basics/file-buffer-window-tab/#buffer-text-wrapping","title":"Buffer text wrapping","text":"

The test in a buffer is not wrapped by default. Set and unset soft text wrapping in a buffer

AstroNvimPracticalli Neovim Config ReduxNeovim

SPC u w toggles wrapping of text

line wrap not enabled in configuration by default.

fnl/config/init.fnl
(nvim.ex.set :nowrap)\n

:set wrap to set soft wrapping on current buffer

:set nowrap to show lines in full (scroll sideways to see lines longer than the window)

"},{"location":"neovim-basics/file-buffer-window-tab/#windows","title":"Windows","text":"

Windows can be active (contains the cursor), hidden (open but not shown) or inactive.

AstroNvimPracticalli Neovim Config ReduxNeovim

\\ creates an horizontal split

SPC q removes the current split

SPC h / SPC l to jump to left / right buffer, SPC j / SPC k to jump to buffer below / above

SPC b b to list current buffers and switch between them using telescope

C-w and hjkl to navigate windows is the classic Vim approach

C-w menu to manage Windows, also known as splits.

C-w with one of hjkl will move the cursor to the next window in that direction. Also works with arrow keys.

C-w w toggle between open windows

:q or C-w q closes the active window, closing Neovim if it is the last active window.

:wincmd can be used as an alternative to the Normal mode key bindings

Open file in a new window

:sp relative-or-full-filename-path\n

Resize windows

C-w -, +, < or > for vertical or horizontal size adjustment

"},{"location":"neovim-basics/file-buffer-window-tab/#tab-pages","title":"Tab pages","text":"

A Tab page can hold one or more tabs and are useful for grouping different types of files and information.

A Tab page holds one or more windows, each window is a view on a buffer, a buffer holds the contents of a file or any other information in the editor memory (repl log, etc).

A tab page can provide a logical grouping of windows, e.g. Clojure source code in one tab, tests in a second tab and REPL log in a third.

Neovim window commands may be constrained within the bounds of a tab page (without using the :tab modifier)

Tab pages are often referred to as tabs.

AstroNvim

g Tab jump to previously selected tab, commonly used to toggle between two tabs (Practicalli AstroNvim mapping)

g t jump to next tab page

g T jump to previous tab page

"},{"location":"neovim-basics/multi-modal-editing/","title":"Multi-modal Editing","text":"

TODO: Add multi-modal editing in Neovim guide

Practicalli Spacemacs has useful reference content on multi-modal editing (Evil mode).

Most of this content is the same in Neovim with a few exceptions

"},{"location":"neovim-basics/multi-modal-editing/#selecting-text","title":"Selecting text","text":"

vi) selects all the text within (), e.g. (http://oldwebsite.doh)

"},{"location":"neovim-basics/multi-modal-editing/#surround","title":"Surround","text":"

viw selects the current word, using j/k to modify the selection where required. o toggles which end of the selection is expanded/shrunk

s substitues the selection, type the characters to surround the selection.

p to pase the original text

"},{"location":"neovim-basics/multi-modal-editing/#nvim-surround","title":"nvim-surround","text":"

nvim-surround provides enhancments over the neovim surround command.

nvim-surround included in Practicalli AstroNvim Config

"},{"location":"neovim-basics/multi-modal-editing/#visual-mode","title":"Visual Mode","text":"

viw to select the current word (visual in word)

S on a visual selection to surround with next that character, e.g. S) to surround with parens.

Closing paren surrounds without spaces

), ], } surrounds the selected text without spaces between the text and the open and closing parens.

(, [, { surrounds the selected text with a space between the text and the open and closing parens.

"},{"location":"neovim-basics/multi-modal-editing/#normal-mode","title":"Normal mode","text":"

cs inside an existing pair of characters to change them to another pair of surrounding characters, e.g. cs(} to change (text) to {text}

ds inside a pair of surrounding characters to delete them, e.g. ds( to change (text) to text

ys you surround followed by motion and character, e.g. ysw) surrounds word with (parens)

yS to surround current line

ySS to surround current line, placing characters on new lines, e.g. ySS{ will change \"Olical/conjure\" to:

{\n    \"Olical/conjure\"\n}\n

The three \"core\" operations of add/delete/change can be done with the keymaps ys{motion}{char}, ds{char}, and cs{target}{replacement}, respectively. For the following examples, * will denote the cursor position:

Old text                    Command         New text\n----------------------------------------------------\nsurr*ound_words             ysiw)           (surround_words)\n*make strings               ys$\"            \"make strings\"\n[delete ar*ound me!]        ds]             delete around me!\nremove <b>HTML t*ags</b>    dst             remove HTML tags\n'change quot*es'            cs'\"            \"change quotes\"\n<b>or tag* types</b>        csth1<CR>       <h1>or tag types</h1>\ndelete(functi*on calls)     dsf             function calls\n

Neovim help provides details on using nvim-surround

:help nvim-surround.usage\n
"},{"location":"neovim-basics/multi-modal-editing/#web-links","title":"Web Links","text":"

g x on a URL to open in the default browser

"},{"location":"neovim-basics/multiple-cursors/","title":"Multiple cursors","text":"

Visual-Multi (VM) is a multiple selections/cursors plugin that uses modal editing and provide visual feedback when editing multiple lines simultaneously.

Mulitple cursors is generally useful when editing smilarly structured lines with diffferent content. Cursors are moved by column position or by using vim motions.

AstroNvimPracticalli Neovim Config Redux

Space g m opens the visual-multi menu

Using visual select is a simple way to edit multiple lines as the same time.

Space g m c on visually selected lines creates a cursor on each line.

Esc or f d to close multiple cursors.

\\ \\ c creates a cursor at the start of every visual selection line

\\ \\ \\ toggle cursor at position

"},{"location":"neovim-basics/multiple-cursors/#search-and-replace","title":"Search and Replace","text":"

Select a text pattern to search for and use multiple cursors to add a cursor each match, then change each selected occurance concurrently.

AstroNvimPracticalli Neovim Config Redux

Select the pattern with visual select

Space g m a on each matching text pattern in the buffer

c to change the original text and type the new pattern. All cursors will update concurrently.

Esc or f d to close multiple cursors.

\\ \\ a creates a cursor at the start of every visual selection line

\\ \\ \\ toggle cursor at position

c to change the original text and type the new pattern. All cursors will update concurrently.

Esc or f d to close multiple cursors.

"},{"location":"neovim-basics/multiple-cursors/#command-quick-reference","title":"Command quick reference","text":"

:help g:VM_maps for a reference of all mappings and instructions on how to change them

AstroNvim

SPC g m opens the Visual-Multi menu in normal mode

g m opens the Visual-Multi menu in visual mode

c to add a cursor to every line in the visually selected region

Practicalli Neovim Config Redux

\\ \\ is the leader for multiple cursors and will show the visual-multi menu in which-key.

These commands cover the large majority of use cases for multiple cursors.

Action Key Command Add Cursor at Position \\\\\\ vm-add-cursor Alignm VM cursors with cursor \\\\a vm-align Select All Words \\\\A vm-select-all Transposition \\\\t vm-transpose Toggle Mappings \\\\<Space> vm-mappings-toggle Find with Regex \\\\/ vm-regex-search Reselect Last \\\\gS vm-reselect-last

Once visual-multi has started the vm-mappings-buffer mappings are available:

Action Key Command Find Word <C-n> vm-find-word Next/Previous/Skip n / N / q vm-find-next Remove Region Q vm-remove-region Add Cursors Down/Up <C-Down> / <C-Up> vm-add-cursors Select Right/Left <S-Right>, <S-Left> vm-shift-select Slash motion g/ vm-slash Select Operator s vm-select-operator Find Operator m vm-find-operator

NOTE: C-n conflicts with the Termux binding for naming a session

"},{"location":"neovim-basics/multiple-cursors/#searching","title":"Searching","text":"

g/ to search for a match to add when visual-multi is active, rather than the usual / vim search.

n and N can't be used to repeat the search, as they are used to get the next visual-multi match.

"},{"location":"neovim-basics/multiple-cursors/#find-with-regex","title":"Find with Regex","text":"

\\ \\ / followed by a regex pattern will create a selection with that pattern.

n and N finds the next occurrence of the regex pattern

"},{"location":"neovim-basics/multiple-cursors/#smart-case-change","title":"Smart case change","text":"

gc In extend-mode will use smartcase to change a selection

"},{"location":"neovim-basics/multiple-cursors/#filter-regions","title":"Filter regions","text":"

\\ \\ f filter out (remove) regions based on pattern or expression.

C-x to cycle filtering method:

"},{"location":"neovim-basics/multiple-cursors/#transform-regions-with-expression","title":"Transform regions with expression","text":"

\\ \\ e to transform a region with a vim expression, run on each region

Placeholders can be used in the expression

Examples: - %f * 0.5 divide text of all regions by 2 - %t .\" \". %i .\" / \". %n append index / total to text of each region - %i%2 ? %t : toupper(%t) uppercase all odd regions (1,3,5...) - %i%3-2 ? %t : '' delete every third region

"},{"location":"neovim-basics/multiple-cursors/#vm-motions","title":"VM Motions","text":"

visual-multi supports vim motions although they behave differently as their result is dependent on the mode:

Unless multiline-mode is enabled motions are restricted to the current line and cannot cross line boundaries

Some object-motions and various-motions require multiline-mode and aliased to avoid conflict with VM mappings:

vim VM~ Description / g/ to next match (for all regions) ( ( [count] sentences backward ) ) [count] sentences forward { { [count] paragraphs backward } } [count] paragraphs forward [( g( go to [count] previous unmatched '(' [{ g{ go to [count] previous unmatched '{' ]) g) go to [count] next unmatched ')' ]} g} go to [count] next unmatched '}'"},{"location":"neovim-basics/multiple-cursors/#vm-operators","title":"vm-operators","text":"

Visual-Multi supports several operators by default:

Visual-Multi uses its own registers that are lists of strings. One element for each region that is yanked/deleted.

There is also built-in support for:

`:help g:VM_user_operators to disccover how to doefine other operators

"},{"location":"neovim-basics/multiple-cursors/#vm-multiline-mode","title":"vm-multiline-mode","text":"

In normal and insert mode, cursors and selections are kept within their own line. Cursors are blocked from moving off the current line to the next line.

M enables multiline-mode that allows cuursors to move onto another line.

Multiline mode must be enabled for an object motions, or they will fail. See |vm-motions|.

"},{"location":"neovim-basics/multiple-cursors/#alignment","title":"Alignment","text":"

\\\\a aligns by setting the minimum column to the highest of all regions \\\\< aligns by character, or [count] characters \\\\> aligns by regex pattern

In extend-mode selections are collapsed to cursors first, although will work regardless.

"},{"location":"neovim-basics/multiple-cursors/#replace-pattern-in-regions","title":"Replace pattern in regions","text":"

R to replace with a pattern and then the replacement text

substitution will take place in all selected regions, leaving unselected text untouched.

Only working in |extend-mode|. When |R| is pressed in |cursor-mode|, it will start |vm-replace-mode| instead.

"},{"location":"neovim-basics/multiple-cursors/#subtract-pattern-from-regions","title":"Subtract pattern from regions","text":"

\\\\s subtract the entered pattern from regions, splitting them. Only working in |extend-mode|.

"},{"location":"neovim-basics/multiple-cursors/#transposition","title":"Transposition","text":"

\\ \\ t swaps the contents of selections, cycling them if there are more than two.

If there is an equal number of selections in each line, swapping takes place within the same line only. Only in |extend-mode|.

"},{"location":"neovim-basics/multiple-cursors/#duplication","title":"Duplication","text":"

\\ \\ d duplicates in place the contents of the selections, reselecting the original ones. Only in extend-mode.

"},{"location":"neovim-basics/multiple-cursors/#shift-selections","title":"Shift Selections","text":"

and move the selections right or left, preserving the surroundings."},{"location":"neovim-basics/multiple-cursors/#case-conversion","title":"Case conversion","text":"

\\\\C runs on inner words in cursor mode

"},{"location":"neovim-basics/multiple-cursors/#modes","title":"Modes","text":"

cursor-mode and extend-mode are two Visual-Multi modes, roughly corresponding to normal-mode and visual-mode

TAB switches between cursor-mode and extended-mode

"},{"location":"neovim-basics/multiple-cursors/#vm-cursor-mode","title":"VM Cursor Mode","text":"

cursor-mode commands expect a motion, e.g. c should be followed by a text object to be changed.

Key Description operators see vm-operators motions see vm-motions | set column for all cursors (to current column or [count]) r replace single character R enter vm-replace-mode ~ change case of single character & repeat last substitution <C-A> increase numbers <C-X> decrease numbers g<C-A> progressively increase numbers (v_g_CTRL-A) g<C-X> progressively decrease numbers (v_g_CTRL-X)

You can enter |insert-mode| with i, I, a, A, and only from cursor mode also with o and O.

Also see vm-motions for supported motions in VM (some with differences).

"},{"location":"neovim-basics/multiple-cursors/#vm-extend-mode","title":"VM Extend Mode","text":"

extend-mode is like having multiple visual selections. motions extend the slections and change / yank / delete commands don't wait for a motion, just like in visual mode.

Even the key o works as in visual mode, inverting the anchor of the selections.

Some commands are specific to |extend-mode|, such as:

Some commands enforce cursor-mode when run from extend-mode:

Others can use a different mapping:

"},{"location":"neovim-basics/notifications/","title":"Notifications","text":"Notifications only in AstroNvim, not the Practicalli Neovim configuration

Space f n lists the history of notifications for the current sesion

Enter to open the highlighted item in the list in its own popup

Notification popups show information, warnings and errors.

"},{"location":"neovim-basics/notifications/#configure-notifications","title":"Configure notifications","text":"

Notifications are controlled by nvim-notify

Practicalli astronvim-config overrides several default values in plugins/core.lua

Practicalli Configuration for notifications

plugins/core.lua
  -- Configure notify popups\n  {\n    \"rcarriga/nvim-notify\",\n    opts = {\n      top_down = false,\n      timeout = 1000,\n      -- log level - 3 hide file write messages - default 5\n      level = 3,\n      -- background_color = \"#000000\",\n    },\n  },\n

Noice uses nvim-notify configuration

Noice replaces the UI for messages, command line and popup menus, although uses the configuration of nvim-notify for position and popup timing.

"},{"location":"neovim-basics/plugin-manager/","title":"Plugin Manager","text":"

Neovim community provides a wide range of plugins to greatly extend the features of Neovim

There is a wide range of plugin managers too, including a built-in plugin manager in Neovim.

Lazy plugin manager recommeded

Practicalli recommends Lazy plugin manager as it feels much easier to use and has a more engaing and understandable user interface

Neovim evolving

Neovim and its plugins are evolving quite rapidly, so it is recommended to update plugins if there are issue or when a newer version of Neovim has been installed

Plugin issue are not that common and typically fixed quite quickly by the community

AstroNvimPracticalli Neovim Config Redux

Lazy plugin manager

SPC P u to update packages to their latest versions (:PackerUpdate). Details of updated changes will be shown at the end of the update.

r in the package update screen gives the option to revert an update if something has gone wrong (although this seem to be a rare issue).

When packages are all at the latest available version, Packer update reports packages already up to date.

Packer downloads packages and documentation from the Internet, so a connection is required

"},{"location":"neovim-basics/plugin-manager/#package-list-and-documentation","title":"Package List and documentation","text":"AstroNvimPracticalli Neovim Config Redux

Lazy plugin manager

SPC P l to list the current packages added to the configuration

Selecting a package will display the website documentation for the package (although this may be in HTML so not the cleanest way to read the docs).

"},{"location":"neovim-basics/plugin-manager/#adding-packages","title":"Adding packages","text":"AstroNvimPracticalli Neovim Config Redux

Lazy plugin manager

Add package names as keywords in the use expression in fnl/config/plugin.fnl file.

:requires to add a package that is a dependency for the package being added

:mod defines the namespace that contains the package configuration, typically a setup function with options. The namespace matches the file name under fnl/config/plugin

SPC P i to install packages that have been added to fnl/config/plugin.fnl

q to quit once all packages are up to date

"},{"location":"neovim-basics/search-replace/","title":"Search and Replace","text":"

:substitute or :s vim command will highlight the matches for a text pattern and substitute for a new pattern

Built-in help for the command

:help :substitute\n
Multiple cursors can also be used for multiple substitutions

multiple cursors created on each occurance can be used to search and replace a pattern

Subsitute the first matching patterns in the current line

:s/current-pattern/new-pattern\n

Subsitute all the matching patterns in the current line, g representing all occurances in a line

:s/current-pattern/new-pattern/g\n

Use % to specify the current buffer as the scope to change all matches

:%s/current-pattern/new-pattern/g\n
"},{"location":"neovim-basics/snippets/","title":"Snippets","text":"

LuaSnip can use several different sources for snippets

LuaSnip Configuration

Practicalli Neovim Config Redux includes the LuaSnip package which also adds friendly-snippets and cmp_luasnip.

  ; snippets\n  :L3MON4D3/LuaSnip \n  {:requires [:rafamadriz/friendly-snippets\n              :saadparwaiz1/cmp_luasnip]\n   :mod :lua-snip}\n
Configure LSP snippet locations
{\n  \"name\": \"practicalli-snippets\",\n  \"engines\": {\n    \"vscode\": \"^1.11.0\"\n  },\n  \"contributes\": {\n    \"snippets\": [\n      {\n        \"language\": [\n          \"markdown\",\n          \"global\",\n          \"all\"\n        ],\n        \"comment\": \"snippets accross several languages\",\n        \"path\": \"./global.json\"\n      },\n      {\n        \"language\": \n          \"markdown\",\n        \"path\": \"./markdown.json\"\n      }\n    ]\n  }\n}\n

"},{"location":"neovim-basics/snippets/#snippet-definitions","title":"Snippet Definitions","text":"

snippets directory contains snippet definitions, with a JSON file for each language, e.g. markdown.json

Practicalli Neovim Config Redux contains several groups of snippet definitions

Restart Neovim to load new defintions

Snippets added to VSCode JSON snippets are only loaded when Neovim starts, so newly added snippets will only be available after Neovim is restarted.

"},{"location":"neovim-basics/terminal/","title":"Terminal","text":"

akinsho/toggleterm.nvim plugin provides a terminal session within Neovim, using a float, split or tab.

AstroNvim

SPC t for the Terminal sub-menu

SPC t f opens a terminal in a floating window, useful for one-off commands

SPC t h opens a terminal in a horizontal split, useful for a process that prints valuable feedback, e.g. a test runner in watch mode

SPC t t opens a terminal in a tab, useful for background processes that do not need attendtion

"},{"location":"neovim-basics/zen-mode/","title":"Focus Modes","text":"

Focus on the code or text being created, without distractions

zZ toggles Zen mode

SPC z a ataraxis focus mode

SPC z f focus current buffer

SPC z n narrow to current buffer

SPC z n remove status bar and window decorations

v SPC z n narrow to selection

"},{"location":"neovim-basics/zen-mode/#zen-mode","title":"Zen Mode","text":"

Zen Mode distraction-free coding for Neovim

Available via the Astrocommunity repository.

Zen Mode configuration for AstroNvim

.config/astronvim-config/plugins/community.lua
  { import = \"astrocommunity.editing-support.zen-mode-nvim\" },\n  {\n    \"folke/zen-mode.nvim\",\n    opts = {\n      -- override default configuration\n      -- https://github.com/folke/zen-mode.nvim#%EF%B8%8F-configuration\n      plugins = {\n        options = {\n          enabled = true,\n        },\n        kitty = {\n          enabled = true,\n          font = \"+4\", -- font size increment\n        },\n      },\n    },\n  },\n

kitty configuration enables Zen Mode to resize kitty fonts.

"},{"location":"neovim-basics/zen-mode/#true-zen","title":"True Zen","text":"

true-zen.nvim clean and elegant distraction-free writing for NeoVim

True Zen Mode configuration for AstroNvim

  {\n    \"Pocco81/true-zen.nvim\",\n    lazy = false,\n    opts = {\n      integrations = {\n        kitty = {\n          -- increment font size in Kitty.\n          enabled = true,\n          font = \"+4\",\n        },\n      },\n    },\n  },\n

See kitty configuration to enable Zen Mode to resize kitty fonts.

"},{"location":"neovim-basics/zen-mode/#kitty-configuration","title":"Kitty configuration","text":"

Add allow_remote_control socket-only and listen_on unix:/tmp/kitty to the kitty config

Kitty support for Zen Mode

.config/kitty/kitty.config
# ---------------------------------------------------------\n#  Neovim zen-mode-nvim\n#  - change the font size on kitty when in zen mode\nallow_remote_control socket-only\nlisten_on unix:/tmp/kitty\n# ---------------------------------------------------------\n
"},{"location":"reference/lua-language/","title":"Lua","text":"

Lua is the default language for Neovim configuration.

"},{"location":"reference/lua-language/#learning-lua","title":"Learning Lua","text":"

Neovim Lua introduction

Lua.org - Programming in Lua (first edition)

Codecademy - learn lua course

"},{"location":"reference/lua-language/#reference","title":"Reference","text":"

Lua.org 5.4 Reference Manual

"},{"location":"reference/neovim/","title":"Neovim Reference","text":""},{"location":"reference/neovim/language-providers/","title":"Language Providers","text":"

Neovim delegates some features to language providers.

:checkhealth command in Neovim shows if the binaries and tools required by each provider are available in the operating system.

Resolve the issue with providers that generate a warning in the checkhealth report, following the ADVICE steps provided.

"},{"location":"reference/neovim/language-providers/#disable-language-providers","title":"Disable Language Providers","text":"

If a language is not used with Neovim, then its provider can be disabled. Details on how to disable a provider are included at the end of the ADVICE in the report section for that provider.

Disable language providers in the init.lua configuration file

init.lua
-- Disable Language providers\nvim.g.loaded_node_provider = 0       --- (1)!\nvim.g.loaded_perl_provider = 0\nvim.g.loaded_python3_provider = 0\nvim.g.loaded_ruby_provider = 0\n
  1. Example configuration to disable providers is provided in the practicalli/neovim-config-redux configuration

Ignore Language Provider warnings

If the programming language is not used, there are no issues with using Neovim if the warnings are simply ignored

"},{"location":"reference/neovim/standard-path/","title":"Neovim Standard Path","text":"

View the standard paths used by Neovim using the help menu

:help standard-path\n

Output of command

Standard Paths                  *standard-path*\n\nNvim stores configuration, data, and logs in standard locations. Plugins are\nstrongly encouraged to follow this pattern also. Use |stdpath()| to get the\npaths.\n\n                        *base-directories* *xdg*\nThe \"base\" (root) directories conform to the XDG Base Directory Specification.\nhttps://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\nThe $XDG_CONFIG_HOME, $XDG_DATA_HOME, $XDG_RUNTIME_DIR, and $XDG_STATE_HOME\nenvironment variables are used if defined, else default values (listed below)\nare used.\n\nCONFIG DIRECTORY (DEFAULT) ~\n                  *$XDG_CONFIG_HOME*            Nvim: stdpath(\"config\")\n    Unix:         ~/.config                   ~/.config/nvim\n    Windows:      ~/AppData/Local             ~/AppData/Local/nvim\n\nDATA DIRECTORY (DEFAULT) ~\n                  *$XDG_DATA_HOME*              Nvim: stdpath(\"data\")\n    Unix:         ~/.local/share              ~/.local/share/nvim\n    Windows:      ~/AppData/Local             ~/AppData/Local/nvim-data\n\nRUN DIRECTORY (DEFAULT) ~\n                  *$XDG_RUNTIME_DIR*            Nvim: stdpath(\"run\")\n    Unix:         /tmp/nvim.user/xxx          /tmp/nvim.user/xxx\n    Windows:      $TMP/nvim.user/xxx          $TMP/nvim.user/xxx\n\nSTATE DIRECTORY (DEFAULT) ~\n                  *$XDG_STATE_HOME*             Nvim: stdpath(\"state\")\n    Unix:         ~/.local/state              ~/.local/state/nvim\n    Windows:      ~/AppData/Local             ~/AppData/Local/nvim-data\n\nNote: Throughout the user manual these defaults are used as placeholders, e.g.\n\"~/.config\" is understood to mean \"$XDG_CONFIG_HOME or ~/.config\".\n\nLOG FILE                    *$NVIM_LOG_FILE* *E5430*\nBesides 'debug' and 'verbose', Nvim keeps a general log file for internal\ndebugging, plugins and RPC clients. >\n    :echo $NVIM_LOG_FILE\nBy default, the file is located at stdpath('log')/log unless that path\nis inaccessible or if $NVIM_LOG_FILE was set before |startup|.\n
"},{"location":"reference/vim-style/","title":"Reference: Learn Vim-style Editing","text":"

Learning vim-style multi-modal editing takes time and practice. Most importantly this approach can be learned in stages, as insert mode is the same editing experience as using most other editors.

Start with the multi-modal concept and the basics of navigation. Then adopt more normal and visual mode actions, including motions

"},{"location":"reference/vim-style/#getting-started","title":"Getting started","text":"

:Tutor runs the intteractive tutorial built into neovim (:help tutor also runs the tutor)

vim adventures isa simple online game to teach you the fundamentals of vim-style editing.

"},{"location":"reference/vim-style/#navigation-and-searching","title":"Navigation and searching","text":""},{"location":"reference/vim-style/#text-wrangling","title":"Text wrangling","text":""},{"location":"reference/vim-style/#clojure-editing","title":"Clojure Editing","text":"

traversing expressions structural editing

"},{"location":"reference/vim-style/case/","title":"Modifying text case","text":"

Convert Characters and regioins to upper or lower case text.

"},{"location":"reference/vim-style/case/#toggle-case-with-visual-select","title":"Toggle case with visual select","text":"

v to visually select a character or use the vim motion keys to select a region

U to uppercase current character or selected region

u to lowercase current character or selected region

~ to toggle the case of the text in the selected region

. will repeat the previous selection size and case toggle

"},{"location":"reference/vim-style/case/#toggle-case-menu","title":"Toggle case menu","text":"

Toggle the current character using vim motion keys, without needing to select a region.

g ~ opens the toggle case menu

TODO: Add screenshot of g ~ toggle case menu

g ~ ~ uppercase current line (also works for RET and maybe other none-menu characters, but not SPC)

"},{"location":"reference/vim-style/case/#cheatsheet","title":"Cheatsheet","text":""},{"location":"reference/vim-style/g-menu/","title":"Evil G menu","text":"

g` in normal mode opens a menu of convenient utilities. Practicalli uses this menu to comment existing lines, jumping to top or bottom of the buffer and changing text case.

"},{"location":"reference/vim-style/g-menu/#comment-lines-and-regions","title":"Comment lines and regions","text":"

g c c will comment the current line using the buffer major mode comment character(s). A prompt will ask if no comment character is set for the major mode.

g c with a selected region will comment all lines with the major mode comment character(s)

"},{"location":"reference/vim-style/g-menu/#jumping-around","title":"Jumping around","text":"

g g jumps to the top of the buffer, g G to the bottom of the buffer

g d to jump to the source code of a function definition, g D to open that in a different window.

g f to jump to file name under cursor (if file exists).

"},{"location":"reference/vim-style/g-menu/#changing-text-case","title":"Changing text case","text":"

g u to change the current character or selection to lowercase, g U for uppercase.

Toggle case with ~

~ will toggle the case of the current character or selected region.

"},{"location":"reference/vim-style/key-binding-reference/","title":"Evil Keybinding Reference","text":"

An alphabetically ordered reference of Vim-style key bindings.

"},{"location":"reference/vim-style/key-binding-reference/#normal-mode-keybindings","title":"Normal mode keybindings","text":"

Keybindings available in Evil normal mode and the resultant state they leave you in.

Keybinding Description State @ execute keyboard macro (defined by q) Normal ' jump to mark (defined by m) Normal a append text after cursor Insert a append text after cursor Insert A append text to end of sentence Insert b move cursor back to start of previous word Normal B move cursor back to start of last word Normal c change (use with modifier) Insert C change rest of sentence Insert d delete (use with modifier) Normal D delete rest of sentence Normal e end of word Normal E end of word (seems same as above) Normal f find character forward (type character) Normal F find character backward (type character) Normal fd Escape (press almost together) Normal g go menu Normal G Jump to end of buffer Normal h move cursor left Normal H move cursor to top of buffer Normal i insert text Insert I insert text at start of sentence Insert j Move cursor down a line Normal J Join next line to end of current Normal k Move cursor up a line Normal K spacemacs/evil-smart-doc-lookup Normal l Move cursor right Normal L Move cursor to bottom of buffer Normal m Create marker (next character is marker name) Normal M Jump to middle of buffer Normal n Next search occurrence Normal N Previous search occurrence Normal o New line below Insert O New line above Insert p Paste (after / below cursor) Insert P Paste (before / above cursor) Insert q Record keyboard macro attached to given character Normal Q undefined Normal r Replace character under cursor Normal R Replace character state Replace s Substitute character Insert S Substitute current line Insert t Find character forward - cursor before character Normal T Find character backward - cursor after character Normal u Undo last change (C-R to redo) Normal U Undefined Normal v Visual select Visual V Visual select sentence Visual w Jump cursor to start of next word Normal W Jump cursor to start of next word Normal x Delete character under cursor Normal X Delete character backwards Normal y y Yank (copy) line Normal Y Yank (copy) line Normal z Menu - code folding / keyboard macros Normal"},{"location":"reference/vim-style/motions/","title":"Motions","text":"

Todo

Moving the cursor around by context rather than individual characters

"},{"location":"reference/vim-style/moving-around/","title":"Moving around the cursor","text":"

Scrolling is quite inefficient in most editors and moving (jumping) the curor around is far more effective.

Using the h j k l as a common part of navigation provides consistency and keeps fingers on the most convienient part of the keyboard.

"},{"location":"reference/vim-style/moving-around/#moving-by-charater","title":"Moving by charater","text":"

h j k l keys move the cursor once character or can be used with numbers to move further.

"},{"location":"reference/vim-style/moving-around/#moving-with-numbers","title":"Moving with numbers","text":"

: followed by a number then one of h j k l keys will move the cursor that number in the director of the key.

3j will move 3 lines down the buffer (or to the end of the fuffer if there are fewer lines remaining)

Using Relative line numbers showws how far each line is from the current line. The practicalli/neovim-config sets :relativenames true in fnl/config/init.fnl.

42l moves 42 charaters to the right

moving by motions avoids the need to count characters

"},{"location":"reference/vim-style/moving-around/#moving-around-the-buffer","title":"Moving around the buffer","text":"

g g to jump to the top of the current buffer

G to jump to the bottom of the buffer

z z moves the current line and cursor to the middle of the window

z t moves the current line and cursor to the top of the window

z t moves the current line and cursor to the bottom of the window (or as far as the buffer will move in the window)

"},{"location":"reference/vim-style/narrowing/","title":"Narrowing","text":"

Narrowing to a region enables vim commands to be applied to a specific part of the current buffer, rather than the whole buffer.

Common examples include - replacing local variables within a specific function (avoiding affecting other function definitions)

"},{"location":"reference/vim-style/narrowing/#nrrwrgn-plugin","title":"NrrwRgn plugin","text":"

[NrrwRgn plugin] is inspired by the Narrowing feature of Emacs and means to focus on a selected region while making the rest inaccessible.

SPC n r opens a select region in a new split window. The original buffer is protected from changes.

:w to write changes in the narrowed window to the original buffer

"},{"location":"reference/vim-style/narrowing/#commands","title":"Commands","text":"

:NR - Open the selected region in a new narrowed window :NW - Open the current visual window in a new narrowed window :WR - (In the narrowed window) write the changes back to the original buffer. :NRV - Open the narrowed window for the region that was last visually selected. :NUD - (In a unified diff) open the selected diff in 2 Narrowed windows :NRP - Mark a region for a Multi narrowed window :NRM - Create a new Multi narrowed window (after :NRP) - experimental! :NRS - Enable Syncing the buffer content back (default on) :NRN - Disable Syncing the buffer content back :NRL - Reselect the last selected region and open it again in a narrowed window

Appending ! to most commands opens the narrowed part in the current window instead of a new window.

:WR! closes the narrowed window in addition to writing to the original buffer.

"},{"location":"reference/vim-style/narrowing/#documentation","title":"Documentation","text":"

:help NarrowRegion to view the documetation on the NrrwRgn plug use

"},{"location":"reference/vim-style/narrowing/#attention","title":"Attention","text":"

:NRM is described as experimental by the project readme.

"},{"location":"reference/vim-style/speaking-vim/","title":"Learning to speak Vim","text":"

Neovim is easier to learn and gain much more benefit from if you learn to speak commands as sentences.

First learn some verbs:

Then use those verbs with some modifiers

Then learn the text objects you can apply verbs and modifiers too

"},{"location":"reference/vim-style/speaking-vim/#examples-of-speaking-vim","title":"Examples of speaking Vim","text":"

Practice speaking evil with these examples

Keybinding Description c i s change inside current sentence (change the whole sentence) c i \" change inside double quotes c f ) change from cursor to next ) character c s ' \" change by the surrounding single quotes with double quotes c t X change till the character X (not including X) c /foo change until the first search result of \u2018foo\u2019 d d delete current line D delete current line from cursor onward d i w delete inside the current word (delete word) v t SPC visual select till the next Space character v s ] visually select and surround with [] without spaces v s [ as above with [ ] with spaces between parens and content g v go to last visual selection (select last visual selection) v a p visually select around current paragraph v i w S \" visually select, insert around current word, and surround with quotes y y yank (copy) current line y w yank (copy) current word y @ a yank (copy) to mark a (m a creates a mark called a)"},{"location":"reference/vim-style/vim-quick-reference/","title":"Neovim Quick Reference","text":"

A reference of the most common keybindings available in Vim Normal mode. Spacemacs DOCUMENTATION key bindings section contains full details

. repeats the last keybinding sequence used in Vim Normal mode or a change made within a complete Vim Insert session.

"},{"location":"reference/vim-style/vim-quick-reference/#moving-around","title":"Moving around","text":"

In Normal mode you can keep your fingers resting on the main row of your keyboard to move around.

Key action j move cursor down one line k move cursor up one line l move cursor right one character h move cursor left one character

In menus such as helm you can move around using Ctrl and these keybindings. So C-j will move the cursor down one item in a menu.

"},{"location":"reference/vim-style/vim-quick-reference/#navigating-the-current-line","title":"Navigating the current line","text":"Key Action f to next character (you specify) t to just before the next character ; repeat f or t search w start of next word W start of next word, white space delimited e end of current word b start of previous word W end of next word, white space delimited * to next matching symbol name $ end of current line 0 start of current line ^ start of non-whitespace % jump to matching parens or next closed paren"},{"location":"reference/vim-style/vim-quick-reference/#navigating-the-current-buffer","title":"Navigating the current buffer","text":"Key action gg start of buffer G end of buffer H move cursor to head of buffer M move cursor to middle of buffer L move cursor to bottom line of buffer C-u jump up half a page C-d jump down half a page } move cursor forward by paragraph or block { move cursor backward by paragraph or block ma mark a line in a file with marker \"a\" `a after moving around, go back to the exact position of marker \"a\" 'a after moving around, go back to line of marker \"a\" :marks view all the marks '' go to the last place you were [{ jump back to the \"{\" at the beginning of the current code block C-o jump back to previous cursor location (evil-jump-backwards) C-i Go to newer position in jump list (opposite of C-o) : 4 go to line 4"},{"location":"reference/vim-style/vim-quick-reference/#text-editing","title":"Text Editing","text":"

The following commands put you into the Evil Insert state

Key Action i insert state at cursor I insert state at start of line a append - insert state after cursor A append - insert state at end of line o new line after cursor O new line before cursor"},{"location":"reference/vim-style/vim-quick-reference/#return-to-normal-state","title":"Return to Normal state","text":"

Regularly switch back to normal state should become common practice. As soon as you finish typing some new text, it should become second nature to go back to normal state.

ESC or press fd keys in extremely quick succession.

fd shortcut for Esc

Using f d together is low risk as if you dont get it right it will either add the characters or try find the next d character (as f moves to the next character). Keep trying this key combination as once in normal state you can use u to undo any f d characters inserted.

"},{"location":"reference/vim-style/vim-quick-reference/#copy-cut-paste-undo-redo","title":"Copy, cut, paste, undo, redo","text":"

v in Vim normal mode changes to Visual select mode. Use the navigation keys or any other movement keys to select text to copy or cut.

Key Action y copy (yank) selection and add to kill ring x delete character at point and add to kill ring X delete character before point and add to kill ring p paste (put) u undo Ctrl-r redo

Undo tips

Undo will revert the last action in normal mode or all the changes you made in insert state

"},{"location":"reference/vim-style/vim-quick-reference/#replace-and-changing-text","title":"Replace and changing text","text":"Key Action r replace the character under cursor R replace multiple characters until ESC cw change word from cursor to end 4 c w change 4 words v (select) c change region v (select) d delete region v i w c change current word v i d delete current word d w delete from cursor to end of word C change from cursor to end of line D , d $ delete from cursor to end of line"},{"location":"reference/vim-style/vim-quick-reference/#delete-commands","title":"Delete commands","text":"Key Action de delete to end of word, not including space dw delete to end of word, including space d$ delete to end of line dd delete the current line 4 d w delete 4 words 4 d $ delete 4 lines to end dt delete to a character (not including character) dab delete a whole block / expression dib delete contents of a block / expression cab change all the block / expression cib change inner block contents / expression yab yank all block / expression yib yank inner block contents / expression"},{"location":"reference/vim-style/vim-quick-reference/#repeat-commands","title":"Repeat commands","text":"Key Action . repeat last command again <number> <cmd> repeat command a number of times

The . keybinding will repeat the last command in normal mode or the last text edit in insert mode.

Type a number before a command and that command will run that number of times.

Inserting a comment border

Use the number repeat to create a border of 42 ; characters.

Type 42 to repeat the command 42 times

Press i for insert mode

Press ; as the character to repeat insert

Press ESC or fd to leave insert mode and insert all 42 ; characters

"},{"location":"reference/vim-style/vim-quick-reference/#transposing-swap","title":"Transposing / swap","text":"Key Description x p transpose the current character with the next character"},{"location":"reference/vim-style/vim-quick-reference/#comments-works-for-all-major-modes","title":"Comments - works for all major modes","text":"

g c c to comment out the current line

g c to comment out the currently selected region

To comment multiple lines you can use the repeat command style, especially useful if you are using relative line numbers.

g c 3 j will comment the current line and the following two lines below. Comment in reverse using g c 3 k.

In Visual state, v, select the lines you wish to comment and use g c to comment all the marked lines. Partially marked lines are not commented.

"},{"location":"reference/vim-style/vim-quick-reference/#managing-files","title":"Managing Files","text":"

Files in practicalli/neovim-config can be managed with Telescope plugin, although the neovim commands can also be used

SPC p t toggles a visual file explorer on as a leftmost window, providing a further way to navigate files and directories.

Key Description SPC f f find existing file (from current local root of neovim) SPC f / copy file - save current buffer with a new file name SPC f b browse files - Esc to run commands SPC f b Esc r change file name of current buffer

Telescope file browser opens in Insert mode to allow typing filenames, to narrow the results in the Telescope popup.

"},{"location":"reference/vim-style/vim-quick-reference/#telescope-browser-commands","title":"Telescope browser commands","text":"

SPC f b opens telescope browser which allows commands to be run over the current file or directory.

Esc swiches the Telescope popup to normal mode, allowing commands to be used

TAB selects files and directories, allowing for commands (i.e. rename) to be done in batch mode (acting on all selected files / directories)

"},{"location":"reference/vim-style/vim-quick-reference/#working-with-buffers","title":"Working with Buffers","text":"

To work with files in Neovim they are loaded into a Buffer.

Buffers are displayed in a window and you can change the window to show any of the current buffers.

SPC b displays the buffer menu and the most common commands include:

Key Command Description SPC b b :Telescope buffers List current buffers SPC b d :bdelete Kill current buffer SPC b n :bnext Switch to next buffer SPC b p :bprevious Switch to previous buffer SPC b a :ball Switch to previous buffer"},{"location":"reference/vim-style/vim-quick-reference/#quit-or-restart-emacs","title":"Quit or Restart Emacs","text":"

I recommend using the Spacemacs menu from normal mode to quit / restart Spacemacs.

Key Action SPC q a Quit Neovim (blocked if unsaved change in buffers) SPC q q Quit buffer (blocked if unsaved change in buffers) SPS q Q Force quit of Neovim"},{"location":"reference/vim-style/vim-quick-reference/#external-commands","title":"External commands","text":"

run external commands using :! followed by a command. For example:

:!ls - run the ls command

"},{"location":"reference/vim-style/vim-tips-for-developers/","title":"Vim editing for Clojure developers","text":"

Vim keybindings that drive Vim editing tools that are common for developers

"},{"location":"reference/vim-style/vim-tips-for-developers/#comments-and-commenting-code","title":"Comments and Commenting code","text":""},{"location":"reference/vim-style/vim-tips-for-developers/#simulated-structural-editing-with-surround","title":"Simulated structural editing with surround","text":"Keybinding Description v s ] surround with [characters] without spaces v s [ surround with [ characters ] without spaces c s ( [ change surrounding from ( to [ c i ( change in ( c a ( change \u201caround\u201d ( % jump forwards to next paren, further % toggles between open and close parens. x p transpose characters (cut current, paste after)"},{"location":"reference/vim-style/vim-tips-for-developers/#moving-around-quickly","title":"Moving around quickly","text":"

f to jump forward to a given character on the current line. F to jump backwards.

zt, zz, and zb to pull the current line to the top/middle/bottom of the screen.

[number] G jump to line number or :22 to jump to line 22

:7j to jump 7 lines down

gf jump to file name under the cursor - try this in the summary.md file

"},{"location":"reference/vim-style/vim-tips-for-developers/#selection-find-and-replace","title":"Selection, find and replace","text":"

viw to visual-select in (within) the current word

"},{"location":"reference/vim-style/vim-tips-for-developers/#source-code-and-configuration-files","title":"Source code and configuration files","text":"

g Dopen definition in another window

= (code-aware indenting) operator. Nice with the ap (a paragraph) text object.

C-] Jump to definition of keyword under the cursor

"},{"location":"reference/vim-style/vim-tips-for-developers/#code-folding","title":"code folding","text":"

zc and zo are useful to close and open folds, which can be a nice way of focusing on certain pieces of code.

"},{"location":"reference/vim-style/vim-tips-for-developers/#transposing-characters-and-sections","title":"Transposing characters and sections","text":"

x p simple transpose of the current and next character

M-t transpose words before and after cursor position

{, } motions jump to next and previous empty lines. This motion makes it simple to rearrange paragraphs

{ d } will kill the paragraph (or multiple paragraphs)

{ will jump to the start of the previous paragraph

p pastes the killed paragraph before the current paragraph

> and < (indent and dedent) operators, useful with the aforementioned }/{ motions.

/ ## multi-replace with iedit and narrowing /

"},{"location":"reference/vim-style/visual-select/","title":"Visual Select","text":"

Select characters, words, lines and regions with visual select. The background changes color to visually indicate which text is selected

v enters visual select mode and can be with objects such as word w and locations such as end of line $.

o to expand from left side of selection and O to expand from the right side of a selection, using the hjkl navigation keys

"},{"location":"reference/vim-style/visual-select/#visual-line-selection","title":"Visual Line selection","text":"

V to select by lines, using j and k.

"},{"location":"reference/vim-style/z-menu/","title":"Evil Z menu","text":"

z in normal mode opens a menu of convenient utilities

"},{"location":"reference/vim-style/z-menu/#folding-code-comments-and-other-content","title":"Folding code, comments and other content","text":"

Code folding is very useful for hiding different levels of detail, for example you could hide everything but the function names in a namespace, showing just the API for that namespace.

Comments and documentation can be folded to help you focus on a specific part of the content.

Key Description z a toggle fold of code, comment, section, etc. z A toggle all folds z c close fold z f create fold z M close all folds z o open fold z O open fold recursive (capital o) z r fewer folds z R open all folds z x update folds

See narrowing for a focused approach to editing.

"},{"location":"reference/vim-style/z-menu/#scrolling","title":"Scrolling","text":"

Jump the current line to the center, top or bottom of the buffer.

Key Description z b scroll the current line to bottom of buffer z t scroll the current line to top of buffer z z scroll the current line to center of buffer"},{"location":"reference/vim-style/z-menu/#spelling","title":"Spelling","text":"

z = with the cursor on a word shows a list of possible spelling and similar words.

Select a word using its number in tye list to repace the word under the cursor, or q to quit the spelling list.

Key Description z = spelling suggestions z g add word to spelling list z w mark word as misspelled"},{"location":"repl-driven-development/","title":"REPL Driven Development with Clojure","text":"

Conjure provides the REPL driven development workflow for Clojure (and many other fun languages) and includes a built-in tutorial.

Practicalli Clojure CLI Config

Practicalli Clojure CLI config contains aliases used extensively through the Clojure sections of this book

Practicalli Neovim config replaces some key bindings

practicalli/neovim-config-redux replaces several key bindings to make them consistent with other Clojure editors

"},{"location":"repl-driven-development/#references","title":"References","text":""},{"location":"repl-driven-development/conjure/","title":"Conjure","text":"

Conjure is the Clojure REPL client for Neovim. Code in source code buffers can be evaluated and show the results in-line, providing instant feedback on the behaviour of the code as it develops.

Conjure School interative tutorial

:ConjureSchool runs an interactive tutorial in Neovim, walking through the essential Conjure commands and key bindings. Use the commands provided to move through the guide or j / k to scroll through the guide content.

"},{"location":"repl-driven-development/conjure/#start-repl","title":"Start REPL","text":"

Start a REPL on the command line in the root of a Clojure project. The REPL should also start an nREPL server for Conjure to connect too.

Conjure will detect an nREPL server (via .nrepl-port file) when a Clojure file is opended (.clj .edn .cljs .cljc) and connect to the REPL process via that nREPL server.

Practicalli Clojure CLI ConfigManual Alias definition

Practicalli Clojure CLI config contains aliases to start a REPL process that also start an nREPL server.

Use repl make task for projects created by Practicalli Project templates

make repl\n

Or use the Clojure CLI command with the :repl/rebel alias directly

clojure -M:repl/rebel\n
Simplify the command line

Add a Makefile to define common tasks to simplify and add consistency to working with Clojure across projects or shell script to simplify the commands used to call clojure to run common tasks

repl:  ## Run Clojure REPL with rich terminal UI (Rebel Readline)\n    $(info --------- Run Rebel REPL ---------)\n    clojure -M:env/dev:env/test:repl/rebel\n\n\nrepl-reloaded:  ## Run Clojure REPL with hotload, reload and rich terminal UI (Rebel Readline)\n    $(info --------- Run Rebel REPL ---------)\n    clojure -M:env/dev:env/test:lib/reloaded:repl/rebel\n

A Makefile can also include supporting commands, such as lint and format tools.

# Run MegaLinter with custom configuration\nlint:\n    $(info --------- MegaLinter Runner ---------)\n    mega-linter-runner --flavor java --env 'MEGALINTER_CONFIG=.github/linters/mega-linter.yml'\n

practicalli/dotfiles/Makefile contains tasks for Clojure development, including running a REPL, preparing dependencies, building an uberjar, lint & format Clojure and configuration files.

Docker related tasks to build, run and compose common images and containers are also included.

Add aliases to the user configuration for Clojure, e.g. XDG_HOME_CONFIG/clojure/deps.edn or HOME/.clojure/deps.edn

  ;; Interactive client REPL with nREPL server for Clojure Editor support\n  :repl/basic\n  {:extra-deps {nrepl/nrepl       {:mvn/version \"1.0.0\"}\n                cider/cider-nrepl {:mvn/version \"0.40.0\"}}\n   :main-opts  [\"--main\" \"nrepl.cmdline\"\n                \"--middleware\" \"[cider.nrepl/cider-middleware]\"\n                \"--interactive\"]}\n\n  ;; Headless REPL with nREPL server for Clojure Editor support\n  :repl/headless\n  {:extra-deps {nrepl/nrepl       {:mvn/version \"1.0.0\"}\n                cider/cider-nrepl {:mvn/version \"0.40.0\"}}\n   :main-opts  [\"--main\" \"nrepl.cmdline\"\n                \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}\n

clojure -M:repl/basic starts a REPL with nREPL with a minimal REPL UI

clojure -M:repl/headless starts a REPL with nREPL server but without a REPL prompt (to prevent accidental interaction via the command line)

Practicalli Clojure CLI Config aliases

Practicalli Clojure CLI config defines aliases for a wide range of community tools and libraries that extend the features of Clojure CLI

"},{"location":"repl-driven-development/conjure/#evaluation","title":"Evaluation","text":"

Clojure REPL workflow encourages code expressions to be evaluated as the are written, providing instant feedback to ensure expected results are returned (or learn the kind of results a function returns).

Results of evaluating an expression are shown in-line. Open the REPL log to see larger results and a complete REPL history for the current session.

,eb - evaluate current buffer - used after first starting the REPL to load in a whole namespace and any required namespaces. Use to ensure all changes have been evaluated in the REPL (except those within a (comment ) form or otherwise commented)

,er - evaluate top-level expression (root), ignoring a surrounding (comment ) form to support the rich comments approach

,ee - evaluate expression (from start of current form) - especially useful for nested forms

,ei - interrupt evaluation (stop long running evaluations) - stop a long running evaluation

,ew - evaluate word (symbol) - inspect value of form - i.e. for def names

,e! - replace form with its result - helps understand a more complex function by replacing code with a specific value

,emf - evaluate marked form - mark forms regularly re-evaluted with mf (or any character with m) to avoid jumping to that form each time . A capital letter to mark form in a different namespace and evaluate from the current buffer.

\"cp - paste contents of the register into buffer. The result of every evaluation is stored in a Neovim register as well as the log.

"},{"location":"repl-driven-development/conjure/#repl-log","title":"REPL log","text":"

The Conjure REPL log shows the results of every evaluation for the current session.

,lt opens log in a new tab page (tab), ,ls in horizontal split, ,ls in vertical tab

,lq - close log window / tab page

,lr - soft REPL reset, leave window open

,lR - hard REPL reset, close window & delete buffer

Inline evaluation over HUD log popup

Practicalli Neovim configurations hide the HUD log popup that is otherwise shown when Conjure connects to the REPL process, i.e. vim.g[\"conjure#log#hud#enabled\"] = false

In-line evaluation results are the main feedback approach used by Practicalli when evaluating code.

Practicalli recommends using the REPL log when larger results are returned

Portal data inspector can be sent evaluation history and provides rich visualisation and navigation tools to explore that history in detail.

"},{"location":"repl-driven-development/conjure/#rich-comments","title":"Rich comments","text":"

Rich comments are a useful way to contain experimental expressions, or expresisons only evaluated directly by a person developing the code (e.g. starting / stoping services, testing api calls, etc.)

Expressions in rich comments are not included when evaluating the buffer or when expressions are evaluated via a namespace require.

,er to evaluate the top level form within the rich comment, without evaluating the comment expression itself.

Start REPL from Neovim

Practicalli Configurations require the vim-jack-in plugin to be added before this approach will work.

Start Neovim with a Clojure file, e.g. nvim src/practialli/playground.clj or run nvim and open a Clojure file, e.g. *.clj, *.cljc, *.cljs or .edn.

Neovim switches to a terminal state, use C-\\ C-n to leave the terminal state. Use :N or :previous to switch back to the source code buffer

, c f to connect to the REPL from Conjure, or simply open a Clojure file. Automated connection will be added in a future version on Conjure.

The vim-jack-in plugin enables Neovim to call out to Clojure tools or Leiningen to start a REPL and connect to it once its started.

A full screen REPL log is displayed. , l q to close the log window and return to the Clojure file. , l v to create a vertical split between code and REPL log, , l h for a horizontal split.

"},{"location":"repl-driven-development/refactor-tools/","title":"Refactor tools","text":"

Neovim and common plugins provide many text oriented tools useful for refactoring code.

Clojure LSP server and Neovim LSP client support use static analysis of the project source code to allow provide common code refactor tools.

"},{"location":"repl-driven-development/refactor-tools/#language-server-protocol-lsp","title":"Language Server Protocol (LSP)","text":"

Using clojure-lsp server and Neovim Treesitter as an LSP client, code is statically analysed to provide auto-completion data, advanced editing actions such as refactor, live formatting, etc.

Function help

SPC l h or K displays help for the function under the cursor

Repeat the key binding to move the cursor to the documentation popup window and use j k to scroll the documentation

"},{"location":"repl-driven-development/refactor-tools/#key-maps","title":"Key maps","text":"Practicalli AstroNvim ConfigPracticalli Neovim Config Redux "},{"location":"repl-driven-development/refactor-tools/#limitations-to-investigate","title":"Limitations to investigate","text":""},{"location":"repl-driven-development/structural-editing/","title":"Structural Editing","text":"

Structural editing seeks to ensure that parenthesis (parens) and other pairs of characters remain balanced, i.e. an open paren is not removed without removing the closing paren.

AstroNvim Community Clojure Pack includes parinfer

nvim-parinfer plugin is included in the AstroNvim Community Clojure pack

  { import = \"astrocommunity.pack.clojure\" },\n
"},{"location":"repl-driven-development/structural-editing/#parinfer","title":"Parinfer","text":"

Parinfer works very well with vim-style modal editing.

The author of the code focuses on aligning code and parinfer takes care of balancing the parens.

To include new lines of code within an expression, create a new line o and indent.

Parinfer will move the preceeding closing paren(s) to the new line, enclosing the new code in the overall expression.

Parinfer website

"},{"location":"repl-driven-development/testing/","title":"Unit tests and test runners","text":"

Run unit tests from within Neovim, showing a summary of test results or a full test report (especially if there are failures)

Or run and external test runner via a terminal session, optionally using watch mode to re-run tests on every saved change.

Practicalli sets Kaocha test runner as default

practicalli/neovim-config-redux sets Kaocha as the default test runner

Kaocha test runner set in Astrocommunity Clojure language pack

Astrocommunity Clojure language pack
{\n  \"Olical/conjure\",\n  -- load plugin on filetypes\n  ft = { \"clojure\" },\n  init = function()\n    vim.g[\"conjure#log#hud#width\"] = 1\n    vim.g[\"conjure#log#hud#enabled\"] = false\n    vim.g[\"conjure#log#hud#anchor\"] = \"SE\"\n    vim.g[\"conjure#log#botright\"] = true\n    vim.g[\"conjure#extract#context_header_lines\"] = 100\n    vim.g[\"conjure#eval#comment_prefix\"] = \";; \"\n    vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#enabled\"] = false\n    vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#hidden\"] = true\n    vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#cmd\"] = nil\n    vim.g[\"conjure#client#clojure#nrepl#eval#auto_require\"] = false\n    vim.g[\"conjure#client#clojure#nrepl#test#runner\"] = \"kaocha\"\n\n    vim.api.nvim_create_autocmd(\"BufNewFile\", {\n      group = vim.api.nvim_create_augroup(\"conjure_log_disable_lsp\", { clear = true }),\n      pattern = { \"conjure-log-*\" },\n      callback = function() vim.diagnostic.disable(0) end,\n      desc = \"Conjure Log disable LSP diagnostics\",\n    })\n
"},{"location":"repl-driven-development/testing/#include-test-path","title":"Include test path","text":"

Ensure the test directory is included in the classpath when starting a REPL. Use a project or user level alias which defines an :extra-paths key with the [\"test\"] path

clojure -M:test/env:repl/reloaded\n
"},{"location":"repl-driven-development/testing/#conjure-test-runners","title":"Conjure Test runners","text":"

, t n to run the tests for the current namespace

, t a to run all tests in the project

"},{"location":"repl-driven-development/testing/#external-test-runner","title":"External test runner","text":"

Open a terminal in Neovim or a separate terminal session to run start a test runner in watch mode. Tests run automatically when the code changes are saved

Practicalli Clojure CLI Config

Practicalli Clojure CLI config contains aliases for test runner tools

Projects created with Practicalli Project Templates include a test and test-watch task to run Kaocha test runner

Run all tests, stoping on first failing test

make test\n

Watch for changes and run all tests, stoping on first failing test

make test-watch\n

The make tasks call Clojure CLI with the appropriate alias, e.g. clojure -X:test/run and clojure -X:test/watch

"},{"location":"repl-driven-development/testing/#test-selectors","title":"Test Selectors","text":"

Use Test selectors to run a sub-set of tests based on selector meta data added to deftest code

(deftest ^:infrastructure function-name-test\n  (testing \"\"\n    (is ,,,))\n\n(deftest ^:persistence function-name-test\n  (testing \"\"\n    (is ,,,))\n
Kaocha test runnerCognitect Labs Test Runner

Kaocha test runner can focus or skip on a sub-set of unit tests using test id, metadata, namespaces or a specific deftest.

Specifying test :id in the tests.edn configuration file allows different test suites to be run, e.g. :unit for unit tests, :spec for specification tests

Focus and skip works with a single test run or with a continuous watcher.

Skip all tests with :persistence metadata

clojure -X:test/watch :skip-meta :persistence\n

Focus on a specific test namespace

clojure -X:test/watch :focus '[\"practicalli.gameboard.api.scoreboard-test\"]\n

Focus on a specific unit test (deftest)

clojure -X:test/watch :focus '[\"practicalli.gameboard.api.scoreboard-test/total-score-test\"]\n

Refine the tests that are watched

Start the watcher with focused or skiped tests by name or meta data (test selectors)

Cognitect Labs Test Runner can include or exclude a sub-set of tests, identified by metadata on the var (deftest)

Cognitect Labs Test Runner - inclusions & exclusions

"},{"location":"termux/","title":"NeoVim on Termux","text":"

A smart phone or tablet and an external keyboard can make an excellent ultra-portable development environment, especially when travelling with limited space or restricted weight constraints.

Termux can be installed using the F-Droid marketplace, as with installing any other Android app.

Do not install Termux App from the Google Play store

The Termux App in Google Play store is significantly out of date and will not work properly and probably not at all

"},{"location":"termux/#keyboard","title":"Keyboard","text":"

Atreus from Keyboardio is an excellent travel keyboard and was used to write most of the Practicalli Neovim configuration and Neovim book (especially during delays at airports)

Model 100 from Keyboardio is used by Practicalli at the office

"},{"location":"termux/#running-termux","title":"Running Termux","text":"

Run Termux from the app launcher added as an android app by the F-Droid install.

A help menu will show the basic command needed to work with packages.

Software keys for Termux specific controls are shown. Keys can be toggled with the Volume Up + q key combination.

Termux may not display in fullscreen when Android productivity mode, usually activated on tablets when physical keyboard or mouse is attached. Disabling productivity mode in the Android settings is recommended.

"},{"location":"termux/clojure-development/","title":"Clojure development environment","text":"

A comprehensive development environment for Clojure, supporting a REPL workflow and static analysis of code via Clojure Language Server Protocol.

"},{"location":"termux/clojure-development/#java-host-platform","title":"Java host platform","text":"

Install OpenJDK to host the Clojure REPL process and run packaged Clojure applications.

Java 17 Long Term Support version is recommended as it is very stable, receives security updates and has the latest highly tested performance improvements.

pkg install openjdk-17\n
"},{"location":"termux/clojure-development/#install-clojure","title":"Install Clojure","text":"

Clone practicalli/clojure-deps-edn to add a wide range of community tools to the Clojure CLI

git clone git@github.com:practicalli/clojure-deps-edn.git ~/.config/clojure\n

Use the Linux install with a prefix path pointing to Termux equivalent of /usr/local. Find the path using echo $PATH and remove bin from the end. Without the prefix Clojure will not install correctly

curl -O https://download.clojure.org/install/linux-install-1.11.1.1149.sh\n\nchmod +x linux-install-1.11.1.1149.sh\n\n./linux-install-1.11.1.1149.sh --prefix /data/data/com.termux/files/usr/\n

clojure binary is installed in the existing bin, lib and share directories in /data/..../usr/, placing that binary on the system execution path.

Test by running a REPL session, for example with Rebel Readline

clojure -M:repl/rebel\n

optionally install rlwrap package if using the basic repl terminal UI

"},{"location":"termux/clojure-development/#install-clojure-lsp","title":"Install Clojure LSP","text":"

Visit clojure-lsp GitHub releases page and download the clojure-lsp file

If the practicalli/clojure-lsp-config repository was cloned, move or link the clojure-lsp directory to ~/.config/clojure-lsp

"},{"location":"termux/custom-shell/","title":"Customise shell","text":"

Customising the shell is optional, although gives an enhanced experience.

Zsh provides the richest command line experience, providing many advanced features over bash. Oh My Zsh is a community configuration that provides a simple way to configure Zsh features and also supports powerline10k terminal theme, providing context specific information and a more engaging visual experience.

Oh My Zsh community configuration enhances the Zsh experience. Practicalli normally uses Prezto community configuration, unfortunately this did not work well on Termux.

"},{"location":"termux/custom-shell/#install-zsh","title":"Install Zsh","text":"

Install the zsh package using the Termux package manager

pkg install zsh\n

Start zsh, which will show a % character as the prompt

zsh\n

Set the shell to run zsh by default

chsh -s zsh\n
"},{"location":"termux/custom-shell/#install-oh-my-zsh","title":"Install Oh My Zsh","text":"

Install Oh My Zsh via curl (or wget if preferred) in the .oh-my-zsh/ directory

sh -c \"$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\"\n
"},{"location":"termux/custom-shell/#install-powerline10k","title":"Install Powerline10k","text":"

Powerline10k is a visually appealing prompt with a setup script to visually choose the presentation of the prompt.

git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k\n

Edit ~/.zshrc and set the theme to ZSH_THEME=\"powerlevel10k/powerlevel10k\"

nano ~/.zshrc\n

Save the changes exit termux.

Next time zsh is run, powerline10k setup script will run. If Meslo is not set as the terminal font, the setup script offers to install the font. Installing the font will restart Termux (without prompting for a restart).

The powerline10k setup script provides a wizard to configure each part of the prompt.

p10k configure command will manually run the powerline10k setup script.

Prezto Zsh community configuration

NOTE: previous attempts to use Prezto proved to have issues

Clone prezto and its sub-modules into XDG_CONFIG_HOME/zsh which is typically ~/.config/zsh

git clone --recursive https://github.com/sorin-ionescu/prezto.git \"${ZDOTDIR:-${XDG_CONFIG_HOME:-$HOME/.config}/zsh}/.zprezto\"\n

Set the location of the Zsh configuration home with $ZDOTDIR, relative to the XDG locations

export ZDOTDIR=\"${ZDOTDIR:=$XDG_CONFIG_HOME/zsh}\"\n

Create a new Zsh configuration by copying/linking the Zsh configuration files provided:

setopt EXTENDED_GLOB\nfor rcfile in \"${ZDOTDIR:-$HOME}\"/.zprezto/runcoms/^README.md(.N); do\n  ln -s \"$rcfile\" \"${ZDOTDIR:-$HOME}/.${rcfile:t}\"\ndone\n

Practicalli Zsh configuration

Clone practicalli/dotfiles and replace the symbolic links in $XDG_CONFIG_HOME/zsh with links to the respective Zsh configuration files in the cloned repository (or copy the files if you prefer)

Copy or create a symbolic like for the .p10k configuration or skip this to create your own configuration when next startingzsh.

Edit $XDG_CONFIG_HOME/.config/zsh/.zshenv and add the following lines to enable zsh to find the prezto configuration

export XDG_CONFIG_HOME=\"${XDG_CONFIG_HOME:=$HOME/.config}\"\nexport ZDOTDIR=\"${ZDOTDIR:=$XDG_CONFIG_HOME/zsh}\"\n

Create a symbolic link from $HOME/.zshenv to $XDG_CONFIG_HOME/.config/zsh/.zshenv (or to the .zshenv file from practicalli/dotfiles)

ln -s $XDG_CONFIG_HOME/.config/zsh/.zshenv $HOME/.zshenv\n

Check the configuration is working by loading the .zshenv configuration

source \"$ZDOTDIR/.zshenv\"\n

Using Oh My Bash

If preferring Bash, then ohmybash provides a nice command line experience, showing completions clearer, nice themes that provide information.

"},{"location":"termux/fdroid-install/","title":"Install Termux via the F-Droid App","text":"

Visit the FDroid app website and download F-Droid, which saves an F-Droid.apk file. Android may display a security prompt stating the browser does not have permissions to install software. The popup should include a configure link that opens the Android settings to allow the browser to install software.

F-Droid should now be installed and its icon added to the Android system alongside all other Android apps.

Open the F-Droid App and allow it to update its repositories, to ensure the latest list of apps are shown.

Search for the Termux application, clicking on the Termux name if more details are required.

Select the Install button.

When installing apps from F-Droid for the first time, a security prompt is show as F-Droid is an unknown source.

Select Settings to open the Android settings and enable Allow from this source for the F-Droid app.

A Termux App launcher will be added to the Android screen. Consider adding the Termux icon to the commonly used icons bar.

"},{"location":"termux/fdroid-install/#termux-styling","title":"Termux Styling","text":"

Styling is a Termux plugin that provides a visually richer experience. Styling contains beautiful color schemes and powerline-reaqdy fonts to customise the appearance of the terminal

Install the package via F-Droid

The styling menu is accessed via a long press on the Termux app screen, showing a More > Style option on the usual cut/copy/paste popup menu. Practicalli recommends FiraCode fonts.

"},{"location":"termux/git/","title":"Git version control","text":"

A Git client is used to version control projects and to clone projects and configuration from GitHub/GitLab. Practicalli maintains several editor configurations in shared repositories on GitHub

"},{"location":"termux/git/#install-a-git-client-and-github-cli","title":"Install a git client and GitHub CLI","text":"
pkg install git gh\n

Clone the practicalli/dotfiles repository

git clone https://github.com/practicalli/dotfiles projects/dotfiles\n

Move or symbolically link the top-level directories to ~/.config, e.g. for the Git configuration:

ln -s projects/dotfiles/git ~/.config/git\n

Edit the .config/git/config and update the core.user, core.name and github or gitlab identities

"},{"location":"termux/git/#create-ssh-key-for-remote-repository-access","title":"Create SSH Key for remote repository access","text":"

Install the openssh package which contains the ssh-keygen command to generate a new public/private key combinations for use with GitHub SSH repository URLs

pkg install openssh\n

Generate a key using the email address of the GitHub or GitLab account

ssh-keygen -t rsa -C name@domain.tld\n

RET to confirm storing the keys in the default location.

Usually a passphrase is recommended, however, termux does not seem to save a keyring to save the key passphrase using ssh-add. So the passphrase must be entered each time the key is used, unless a blank passphrase is used.

Vist your GitHub account settings and create a new SSH key

Use cat ~/.ssh/id_rsa.pub to show the public key contents. Press the screen to select and copy the public key to the clipboard.

Paste the public key into the GitHub new key form.

"},{"location":"termux/git/#optional-create-a-developer-token","title":"[optional] Create a developer token","text":"

A developer token (or ssh key) is required to access GitHub {and far more secure over password}

Should the android device become lost or compromised, the developer token can be deleted to protect the repositories from any malicious access. The developer token should be limited to the minimal access. The developer token does not give access to the GitHub or GitLab account.

HTTPS URLs should be used with a developer token. git@git.com URLs are for SSH keys only.

Visit GitHub / GitLab settings for your account

Create a new developer token specifically for Termux

Add a descriptive name for the token, based on the device Termuxc is runniung on, e.g. Termux Pixel2XL

Check the public_repo and status repo scopes

Generate button creates a new token.

Copy the token using the copy icon.

Edit the .config/git/config file and add a github section with the GitHub account name and token

[github]\n    name = practicalli\n    token = ghp_************************************\n

Consider using GitHub CLI to cache the developer token rather than write the token to the Git configuration file for greater security.

"},{"location":"termux/neovim/","title":"Install neovim","text":"

Neovim version 8 availabe as current package

pkg install neovim\n
"},{"location":"termux/neovim/#neovim-treesitter","title":"Neovim treesitter","text":"

Treesitter provides excellent language syntax parsing and highlighting and is a very attractive feature of the recent neovim releases. Treesitter is a major attraction, bringing in a new audience for Neovim.

The nvim-treesitter package is included in the practicalli/neovim-config-redux configuration.

"},{"location":"termux/neovim/#c-compiler","title":"C Compiler","text":"

Install C compiler for neovim-treesitter, to compile a parser for each specific programming language.

pkg install clang\n

gcc is not packaged for Termux, although there are guides to install gcc if preferred. clang has proved to be capable of creating the parsers used in the Practicalli configuration.

"},{"location":"termux/neovim/#searching-files","title":"Searching files","text":"

Telescope and other packages that involve searching for files recommend using ripgrep, a highly optomised tool for finding files on the operating system.

pkg install ripgrep\n
"},{"location":"termux/neovim/#optional-nodejs","title":"[optional] nodejs","text":"

Optional. Only if node.js is required as a Neovim provider and JavaScript or ClojureScript development is to be done.

pkg install nodejs\n
"},{"location":"termux/setup/","title":"Termux Setup","text":"

Launch Termux via its application icon. A black terminal screen will appear with a bash shell prompt.

"},{"location":"termux/setup/#update-packages","title":"Update packages","text":"

Check for new packages and update them all

pkg upgrade -y\n

If you wish to first check the packages that will be updated, use pkg --list-upgradable

Select a specific region to minimise the number of mirrors checked during package upgrades, especially useful if on a limited data plan.

termux-change-repo\n

At time of writing, the Termux package on F-Droid was around 6 months old so there will be a number of packages that should be updated before any further installation steps are undertaken.

"},{"location":"termux/setup/#configure-freedesktoporg-xdg-locations","title":"Configure Freedesktop.org XDG locations","text":"

Edit the ~/.profile file, adding export directives to set the XDG locations:

nano ~/.profile\n
XDG locations
# Common Free desktop.org locations\nexport XDG_CONFIG_HOME=$HOME/.config\nexport XDG_DATA_HOME=$HOME/.local/share\nexport XDG_STATE_HOME=$HOME/.local/state\nexport XDG_CACHE_HOME=$HOME/.cache\n\n# Set XDG location of Emacs Spacemacs configuration\nexport SPACEMACSDIR=\"$XDG_CONFIG_HOME/spacemacs\"\n

Load the environment variables into the shell, or exit Termux and restart.

Load .profile into shell
source ~/.profile\n

nano editor installed by default

nano editor is used to edit the commands as the package is installed by default in termux. vim, neovim, emacs or any other Linux command line editor can be used if the package is first installed. Termux will list packages to install when trying to run a command that is from a package not yet installed.

"},{"location":"termux/setup/#tools-to-download-binaries-and-configuration","title":"Tools to download binaries and configuration","text":"

Many tools can be installed via the pkg tool, although specific Clojure tools and configuration require additional tools:

pkg install curl wget git openssh\n

Configure a Git Identify and SSH key to before committing and pushing changes, or cloning repositories using the SSH protocol. practicalli/dotfiles contains example configuration, ignore patterns and commit template for using Git.

"},{"location":"termux/setup/#optional-configure-termux-settings","title":"[Optional] Configure Termux Settings","text":"

Edit ~/.termux/termux.properties to configure the default settings for termux.

nano ~/.termux/termux.properties\n

Load termux.properties if values are changed (restarting Termux is not enough to load setting changes)

termux-reload-settings\n

The defaults are suitable for the majority of uses, although you may wish to consider:

If swiping from left edge of the screen is already taken, set key bindings for creating a new termux session, naming a session and switching between sessions. Alternatively, use byobu to create and switch between its tabs for multiple terminal sessions.

"},{"location":"termux/setup/#set-color-scheme-and-font","title":"Set Color Scheme and Font","text":"

The Termux:Styling plug provides menus for selecting terminal color scheme and font to use

Press and hold on the Termux screen to show the context menu and select the Style menu. On smaller screens select More > Style

If Termux:Styling plugin was not installed, a prompt will display asking if the plugin should be installed

A menu appears with Choose Color and Choose Font

Select Choose Color to select from the available list of colour schemes, e.g. Gruvbox Dark or Gruvbox Light

~/.termux/colors.properties file is added when selecting a colour scheme, defining Hex colors from the theme selected.

Select Choose Font to select from the available fonts, e.g. FiraCode or Ubuntu

~/.termux/font.ttf font file is added when selecting a font.

Termux:Styling uses NerdFonts for icons

All fonts installed via Termux:Styling have been patched with NerdFonts, providing several thousand icons to use within the terminal prompt and Neovim itself (e.g. VimDevIcons).

"},{"location":"termux/using-termux/","title":"Using Termux","text":"

Start Termux app and a terminal prompt is shown, along with the standard Android software keyboard. An extended keyboard is provided with common key bindings for the command line interface (Tab, Esc, Ctrl, arrow keys, etc.).

"},{"location":"termux/using-termux/#keyboards","title":"Keyboards","text":"

Termux provides an extended keyboard with key combinations not possible with the Android software keyboard, i.e Ctrl-c, arrow keys, etc. TAB is especially useful for driving command and filename completion.

Volume Up + q toggles the extended keyboard, so more screen is available when using a hardware keyboard.

Connect a hardware keyboard for the best experience, e.g the Keyboard.io atreus is an excellent and highly portable mechanical keyboard. The software keyboard is automatically switched off when a hardware keyboard is connected, although the extended keyboard is still displayed by default.

"},{"location":"termux/using-termux/#adjusting-font-size","title":"Adjusting Font size","text":"

Pinch the screen inwards to zoom out making the text font smaller.

Pinch the screen outwards to zoom in making the text font larger.

"},{"location":"termux/using-termux/#termux-menus","title":"Termux menus","text":"

Termux has three menus: A context menu, navigation drawer and Termux section of the Android notification.

The context menu is shown by a long press anywhere on the terminal screen:

The navigation drawer is shown by swiping inwards from the left of the screen

If gesture navigation is enabled in Android, hold the edge of the screen briefly before swiping to bring up the navigation drawer

The Android notification menu contains a Termux section. Press the Termux section to show the current terminal session or expand the Termux section to exiting all running terminal sessions or aquire a wake lock to avoid Termux entering sleep mode. A wake lock allows server and other background processes to run reliably and to continue to receive notifications

"},{"location":"termux/using-termux/#package-management","title":"Package management","text":"

Termux provides a Linux command line experience, providing a wide range of Unix tools and development environments. Termux uses a Debian based system and packages are easily installed

pkg is an alias for apt, the advance package tool, although there seems little benefit to using pkg if familiar with apt (they are both 3 characters)

"},{"location":"termux/using-termux/#byobu-terminal-tab-manager","title":"Byobu terminal tab manager","text":"

Byobu is an alternative to Termux provides a single terminal prompt. Byobu provides multiple shell prompts, allowing individual Clojure tools and editors to be run from the Termux prompt simultaneously. Practicalli uses byobu to run Neovim, a Clojure REPL and unit test watcher in separate byobu tabs with the ability to add further tabs for other command line tools.

pkg install byobu\n

byobu-enable command will configure the current shell to run byobu on startup. Test this is working by typing exit in Termux and start Termux app again. byobu-disable stops this behaviour and byobu will need to be run manually after starting Termux.

Run the byobu-enable command again if zsh is configured after this step or if adding any other shell to Termux.

"},{"location":"version-control/","title":"Version Control","text":"

There are several ways to interact with Git version control, although Practicalli recommends Neogit interactive git client and Octo to manage GitHub issues and pull requests

"},{"location":"version-control/#init-local-repository","title":"Init local repository","text":"AstroNvim

Space t f opens floating terminal window in the current project directory root (or which ever directory Neovim was started from).

Initialise a local git repository in the current directory.

git init .\n

"},{"location":"version-control/#stage-in-buffer","title":"Stage in buffer","text":"AstroNvimPracticalli Neovim Config Redux

The current hunk or the whole buffer can be staged from the buffer using Git Signs, saving a trip to the Git Status buffer.

Space g H stages the current hunk

Space g S stages the current buffer

Not supported.

"},{"location":"version-control/#git-status","title":"Git Status","text":"AstroNvimPracticalli Neovim Config Redux

SPC g g opens lazygit status, for minimal UI

Space g s Space g n ++\"t\" opens neogit in a new tab for Magit style experience

SPC g s opens Git Status tab, by running :Neogit

"},{"location":"version-control/#github-integration","title":"GitHub integration","text":"

Interact with the remote GitHub repository using Octo

List issues from a specific repository

:Octo issue list practicalli/neovim\n

Create a pull request on a specific repository

:Octo pr create practicalli/neovim\n
"},{"location":"version-control/diff/","title":"Diff","text":"

Compare differences between different files or between a file and its versions.

:diffsplit filename Neovim command opens a split containing the selected filename, showing a diff comparision to the currently opened file

file path completion helps select the correct file for comparison

"},{"location":"version-control/diff/#git-diff","title":"Git Diff","text":"

DiffView compares working space and staged changes side by side, or a diff for git merge conflicts.

++SPC++ g d or d in neogit status buffer (SPC g s) will open diffview in a new tab

q to return to neogit status buffer

AstroNvimPracticalli Neovim Config

Ctrl h / j / k / l to navigate between open splits

SPC b toggles the sidebar buffer

SPC w l and SPC w h to move cursor between diff buffer and sidebar buffer

"},{"location":"version-control/lazygit/","title":"Lazygit version control","text":"Command Line or AstroNvim configuration

Lazygit interface not provided by Practicalli Neovim Config Redux

"},{"location":"version-control/lazygit/#requirements","title":"Requirements","text":"

Install lazygit command line tool

"},{"location":"version-control/lazygit/#open-lazygit","title":"Open Lazygit","text":"AstroNvimCommand Line

SPC g g to open git status with lazygit in a popup window

Change to the root directory of the git managed project.

Run the lazygit rich terminal UI

lazygit\n
"},{"location":"version-control/lazygit/#use-lazygit","title":"Use Lazygit","text":"

SPC to stage files or directories in the files section of the UI

c for a simple commit message prompt in the lazygit UI

C to create a commit message within the

Define Editor for Git Commit Messages

Set core.editor in the user Git configuration (i.e. .config/git/config) to the name of the editor to use for commit messages, e.g. nvim, emacsclient) shell title= git config --global core.editor = nvim Alternatively, use the VISUAL or EDITOR environment variable to the choice of editor

"},{"location":"version-control/neogit/","title":"Neogit - interactive client for Git","text":"

Neogit is an interactive git client that provides the core features of version control with Git. Neogit emulates many of the features found in magit.

SPC g s to open :Neogit status buffer

TAB toggles expansion of sections, files and hunks

d provide a side-by-side view of changes

q to quit Neogit and return to the previous tab

Neovim is configured to use the magit style key bindings in practicalli/neovim-config-redux

"},{"location":"version-control/neogit/#branching","title":"Branching","text":"

b opens the branch menu,

"},{"location":"version-control/neogit/#staging-changes","title":"Staging changes","text":"

s to stage change under cursor, either file or hunk. S to stage all changes

u to unstage change under cursor, U to unstage all changes

v to select lines to stage within a hunk using s or unstage with u

"},{"location":"version-control/neogit/#commit","title":"Commit","text":"

c for the commit menu

c for a new commit, a to amend the latest commit, w to reword a commit message, e to add staged changes to existing commit

A new commit or amend commit qill open a new window to write a commit message (using a git commit message template if defined)

:wq to save a commit message and initiate the commit.

:q! to cancel the commit from the commit message buffer.

"},{"location":"version-control/neogit/#stashing-changes","title":"Stashing changes","text":"

Z to open the stash menu

z to stash the working copy and staged files (index)

i to only stash the staged files (index)

"},{"location":"version-control/neogit/#remote-changes","title":"Remote changes","text":"

F to open the pull menu, p to pull changes (fetch and merge) from the remote repository, u t pull from the upstream repository, or e to specify the remote and branch names.

P to open the push menu to open, -u to push to the current remote

Confused when remote is not origin

Use e option to push to elsewhere when the remote name is not set to origin. The e option will prompt for a remote name and branch.

"},{"location":"version-control/neogit/#commit-history","title":"Commit history","text":"

L l to view git commit history log

RET on a log entry shows the commit details in a new window (split)

q to close the commit details window

"},{"location":"version-control/neogit/#modify-git-commit-history","title":"Modify Git commit history","text":"

r opens the rebase menu

"},{"location":"version-control/octo/","title":"Octo - GitHub issues and PRs","text":"

List, create and edit issues and pull requests from Neovim with Octo package.

Octo connects to GitHub via the GitHub CLI, using a developer token for authentication

Neogit provides a Magit style client, creating commits, pull & push changes with remote repositories.

"},{"location":"version-control/octo/#github-interaction","title":"GitHub interaction","text":"

GitHub CLI

Work with GitHub issues and Pull Requests from the comfort of Neovim.

GitHub CLI to authentication to a GitHub account. Successful login creates a local developer token that is used by Octo to communicate with GitHub.

gh auth login\n
"},{"location":"version-control/octo/#octo-commands","title":"Octo commands","text":"

Command line form: Octo <object> <action> [arguments] - Object, Action and Arguments commands

List issues from current project (optionally add a specific repository)

:Octo issue list practicalli/neovim\n

The account/repository-name is required if Octo cannot find the repository

Create a pull requests from current project

:Octo pr create\n

Add a comment to the current topic (issue/pr)

:Octo comment add\n

:Octo gist list\n

Octo.nvim configuration options

Octo.nvim configuration options

"},{"location":"version-control/open-in-github/","title":"Open In GitHub","text":"

Open a file under local version control in the GitHub web UI (browser window).

Neovim

:OpenInGHFile

:OpenInGHRepo

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Neovim for Clojure development","text":"

coding at the speed of thought

Neovim is incredibly fast and efficient, so thoughts flow from brain to editor without unnecessary delay.

Touch typing is fast, Neovim and multi-modal editing makes it even faster.

Neovim is a highly extensible and powerful editor, supporting multi-modal editing and Vim-style sequential key bindings. Highly responsive and low resource use makes Neovim ideal for development on any computer or mobile device, e.g. tablet, smartphone.

Neovim has a diverse set of plugins and Practicalli curated configurations use these plugins to provide a rich set of features for Clojure development and wider engineering tasks.

Practicalli Neovim provides install & user guide focused on a simple, powerful and satisfying REPL Driven workflow for Clojure.

"},{"location":"#quick-start","title":"Quick Start","text":"

Install Clojure, Neovim and choose a community configuration

"},{"location":"#external-reverences","title":"External reverences","text":"

Getting started with Neovim and Conjure

Neovim user guide

This Week In Neovim - community update

Conjure install guide Conjuring Clojure in Vim

"},{"location":"#navigate-the-book","title":"Navigate the book","text":"

Use the mouse or built-in key bindings to navigate the pages of the book

Use the search box to quickly find a specific topic

"},{"location":"#sponsor-my-work","title":"Sponsor my work","text":"

All sponsorship recieved is used to maintain and further develop the Practicalli series of books and videos, although most of the work is still done with my own time and cost.

Thank you to Cognitect, Nubank and a wide range of other sponsors from the Clojure community for your continued support

"},{"location":"#creative-commons-license","title":"Creative commons license","text":"This work is licensed under a Creative Commons Attribution 4.0 ShareAlike License (including images & style sheets)."},{"location":"api-tools/","title":"API Tools","text":"

Astrocommunity proivdes plugins to support working with APIs and the JSON format

Included in Practicalli Astronvim Config

Practicalli Astronvim Config includes nvim-jqx and rest.nvim plugins

"},{"location":"api-tools/#inspect-json","title":"Inspect JSON","text":"

Browse and preview json files in neovim.

:JqxList prettify JSON and start the inspector

JqxQuery to run complex jq commands

jq binary required

jq binary should be available on the command line as nvim-jqx runs jq queries internally

nvim-jqx

"},{"location":"api-tools/#call-apis","title":"Call APIs","text":"

Space r r to run an http request under the cursor from within an *.http file.

A fast Neovim http client written in Lua, providing a curl wrapper.

"},{"location":"api-tools/#http-file","title":"http file","text":"

Open a file with an *.http extension

Write a call to an API, e.g. a call to a local server health care endpoint

Call locally running API

health-check.http
GET http://localhost:8080/system-admin/status\n

A new window opens with the result of the API call

Result of API call with rest.nvim
GET http://localhost:8080/system-admin/status\nCommand :curl -sSL --compressed -X 'GET' --data-raw '' 'http://localhost:8080/system-admin/status'\n#+END\nHTTP/1.1 200 OK\nContent-Type: application/json; charset=utf-8\nContent-Length: 66\nServer: http-kit\nDate: Mon, 10 Jul 2023 16:21:33 GMT\n\n#+RESPONSE\n{\"application\":\"practicalli hole-in-one Service\",\"status\":\"Alive\"}\n#+END\n

The Content-Type can be explicitly set, especially useful when not using JSON

API call returning EDN data

GET http://localhost:8080/api/v1/scoreboard\naccept: application/edn\n

rest.nvim test examples

rest.nvim

"},{"location":"assets/images/social/","title":"Social Cards","text":"

Social Cards are visual previews of the website that are included when sending links via social media platforms.

Material for MkDocs is configured to generate beautiful social cards automatically, using the colors, fonts and logos defined in mkdocs.yml

Generated images are stored in this directory.

"},{"location":"configuration/","title":"Neovim Configuration","text":"

Practicalli Neovim covers the following configurations.

"},{"location":"configuration/#multiple-configurations","title":"Multiple Configurations","text":"

Install multiple configurations, e.g. AstroNvim, lazyvim, Nvchad, etc. in the $HOME/.config directory using unique directory names.

Set NVIM_APPNAME to specific the configuration to use when running nvim.

NVIM_APPNAME=astronvim nvim\n

NVIM_APPNAME variable should be set to the directory name containing the configuration, relative to the .config directory.

The configuration directory name is used to hold share, state and cache files for that specific configuration.

Create shell aliases for each configuration. Optionalliy, define a terminal UI selection to choose a configuration.

Shell AliasesTerminal UI Selector

Create a Shell alias for each configuration that will be used, to avoid setting the NVIM_APPNAME variable each time.

Define Shell Aliases to run each configuration

alias astro=\"NVIM_APPNAME=astronvim nvim\"\nalias lazyvim=\"NVIM_APPNAME=lazyvim nvim\"\nalias practicalli-redux=\"NVIM_APPNAME=neovim-config-redux nvim\"\n

Create an nvim configuration selector script, with items listing the directory name of each configuration

Z Shell nvim-selector script

.local/bin/nvim-selector
function nvim-selector() {\n  items=(\"astronvim\" \"neovim-config-redux\" \"lazyvim\")\n  config=$(printf \"%s\\n\" \"${items[@]}\" | fzf --prompt=\"\ue62b Neovim Config \uf63d \" --height=~50% --layout=reverse --border --exit-0)\n  if [[ -z $config ]]; then\n    echo \"Nothing selected\"\n    return 0\n  elif [[ $config == \"default\" ]]; then\n    config=\"\"\n  fi\n  NVIM_APPNAME=$config nvim $@\n}\n
"},{"location":"configuration/astronvim/","title":"AstroNvim","text":"

AstroNvim is a community configuration with an engaging UI, using Lazy for plugin management (Neovim packages) and Mason for package management (LSP, DAP, format and lint tools)

Practicalli AstroNvim Config is a user configuration that extends AstroNvim and imports packages from the AstroNvim Community.

"},{"location":"configuration/astronvim/#prerequisits","title":"Prerequisits","text":"

AstroNvim requires node.js

AstroNvim uses Mason to install LSP servers, format and lint tools. Many LSP servers require node.js to install and function.

Node.js install - Practicalli Engineering Playbook

Kitty Terminal with Nerd Fonts

Kitty Terminal - Practicalli Engineering Playbook provides examples of using Nerd Fonts or Nerd Font symbols with the Kitty terminal.

"},{"location":"configuration/astronvim/#clone-astronvim","title":"Clone AstroNvim","text":"

Clone AstroNvim repository to $HOME/.config/astronvim/

git clone --depth 1 https://github.com/AstroNvim/AstroNvim ~/.config/astronvim\n

$HOME/.config/nvim can be used instead if only ever using one configuration for Neovim.

"},{"location":"configuration/astronvim/#clone-astronvim-user-config","title":"Clone AstroNvim user config","text":"

AstroNvim provides a template repository to create a user configuration. The template includes AstroNvim Community configuration to make it easier to extend the feature of AstroNvim.

Practicalli AstroNvim Config is a clone of the AstroNvim user config with additional configuration to support Clojure development.

Practicalli AstroNvim ConfigAstroNvim User Config

Clone the Practicalli AstroNvim config which provides a user configuration with Clojure support

git clone http://github.com/practicalli/astronvim-config $HOME/.config/astronvim/lua/user\n

Or clone to a separate directory and create a symbolic link

git clone http://github.com/practicalli/astronvim-config $HOME/.config/astronvim-config && \\\nln -s $HOME/.config/astronvim-config/ $HOME/.config/astronvim/lua/user\n

Create your own user configuration using the AstroNvim user configuration template repository.

Create a repository from the AstroNvim/user_example repository template

Clone the newly created repository into the existing AstroNvim configuration, in a user directory

git clone git@github.com/<github-account>/<new-repository> $HOME/.config/astronvim/lua/user\n

"},{"location":"configuration/astronvim/#configure-shell-alias","title":"Configure shell alias","text":"

Create a shell alias that sets NVIM_APPNAME to the location of the AstroNvim community config

Add alias to .bashrc for Bash shell or .zshenv for Zsh

alias astro=\"NVIM_APPNAME=astronvim nvim\"\n

Configure shell alias

"},{"location":"configuration/astronvim/#post-install","title":"Post install","text":"

Open a terminal and use the astro alias to run Neovim.

astro\n

NVIM_APPNAME=astronvim nvim to run Neovim with astronvim without setting a shell alias.

Neovim will open and display the Lazy plugin manager UI, showing the progress of plugin installation. This should only happen on the first run.

Unattended post install

Plugins can be installed without running the Neovim editor UI

nvim --headless -c 'autocmd User LazyDone quitall'\n
"},{"location":"configuration/astronvim/#check-health","title":"Check Health","text":"

Run the Neovim :checkhealth command to report on the general Neovim install and supporting tools

"},{"location":"configuration/astronvim/#add-lsp-dap-lint-and-format-tools","title":"Add LSP DAP Lint and Format tools","text":"

SPC p m to launch Mason which manages LSP servers, linters, filters ...

"},{"location":"configuration/astronvim/#configure-format-rules","title":"Configure format rules","text":"

The configuration files for each lint and format tool should be used by Neovim.

Setting a different location for these files has proved challenging. plugin/null-ls.lua has a section to override its builtin configuration for each lint and format tool, however, in tests Practicalli was unable to succeffuly set a different location.

"},{"location":"configuration/astronvim/config-design/","title":"\ud83d\udce6 Practicalli AstroNvim Config Design","text":"

A guide to the AstroNvim Config user configuration created by Practicalli to support Clojure development.

AstroCommunity used where possible

Plugins and configuration is added vial AstroCommunity were possible, to minimise the code size and maintenance of the configuration

"},{"location":"configuration/astronvim/config-design/#user-config-overview","title":"User Config overview","text":"

core.lua is for tuning plugins shipped with astronvim config

plugins/ for additional plugins organised logically. All .lua files are read from this directory

"},{"location":"configuration/astronvim/config-design/#clojure-support","title":"Clojure support","text":"

The AstroCommunity provides a Clojure language pack that adds Conjure and nvim-parinfer, along with clojure Treesitter parser and clojure-lsp support.

AstroCommunity PackManually add plugins

Edit the plugins/community.lua file and import the Clojure pack. The \"AstroNvim/astrocommunity\", repository is already added to to the file.

-- Packs\n-- Treesitter: clojure , Lsp: clojure-lsp, Lint/format:\n{ import = \"astrocommunity.pack.clojure\" },\n
Override AstroCommunity Pack

Create a plugins/clojure.lua file and add the AstroCommunity repository, Clojure pack and additional configuration to your own preferences

Clojure configuration with user configration overrides

return {\n  \"AstroNvim/astrocommunity\",\n  { import = \"astrocommunity.pack.clojure\" },\n  {\n    \"Olical/conjure\",\n    -- load plugin on filetypes\n    ft = { \"clojure\", \"fennel\" },\n    config = function()\n      -- HUD\n      -- Example: Set to `\"SE\"` and HUD width to `1.0` for full width HUD at bottom of screen\n      vim.g[\"conjure#log#hud#width\"] = 1 -- Width of HUD as percentage of the editor width, 0.0 and 1.0.\n      vim.g[\"conjure#log#hud#enabled\"] = false -- Display HUD\n      vim.g[\"conjure#log#hud#anchor\"] = \"SE\" -- Preferred corner position for the HUD\n      vim.g[\"conjure#log#botright\"] = true -- Open log at bottom or far right of editor\n      -- REPL\n      vim.g[\"conjure#extract#context_header_lines\"] = 100 -- Number of lines to check for `ns` form\n      vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#enabled\"] = false -- ;; Start \"auto-repl\" process, eg. babashka\n      vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#hidden\"] = true -- ;; Hide auto-repl buffer when triggered\n      vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#cmd\"] = nil -- ;; Command to start the auto-repl\n      -- ;; Automatically require namespace of new buffer or current buffer after connection\n      vim.g[\"conjure#client#clojure#nrepl#eval#auto_require\"] = false\n      -- Reloading code\n      -- Function to call on refresh (reloading) the log, namespace-qualified name of a zero-arity\n      -- vim.g[\"conjure#client#clojure#nrepl#refresh#after\"] = nil\n      -- The namespace-qualified name of a zero-arity function to call before reloading.\n      -- vim.g[\"conjure#client#clojure#nrepl#refresh#before\"] = nil\n      -- List of directories to scan. If no directories given, defaults to all directories on the classpath.\n      -- vim.g[\"conjure#client#clojure#nrepl#refresh#dirs\"] = nil\n      -- Testing\n      -- ;; Test runner called from the test key mappings\n      vim.g[\"conjure#client#clojure#nrepl#test#runner\"] = \"kaocha\"\n      -- Print raw test evaluation result, suppressing prefix for stdout lines `; (out)`\n      -- vim.g[\"conjure#client#clojure#nrepl#test#raw_out\"] = nil\n      -- Override string appended to the end of the test runner calls\n      -- vim.g[\"conjure#client#clojure#nrepl#test#call_suffix\"] = nil\n    end\n  },\n  {\n    \"gpanders/nvim-parinfer\",\n    ft = lisp_dialects,\n    config = function()\n      vim.g.parinfer_force_balance = true\n      vim.g.parinfer_comment_chars = \";;\"\n    end,\n  },\n}\n

Add Conjure and parinfer plugin that will load when Clojure or Fennel file is opened.

Clojure Packages in AstroNvim user configuration

```lua title=\".config/astronvim-config/plugins/clojure.lua\"\n-- Lazy Package manager configuration\nreturn {\n  {\n    \"Olical/conjure\",\n    -- load plugin on filetypes\n    ft = { \"clojure\", \"fennel\" },\n  },\n\n  {\n    \"gpanders/nvim-parinfer\",\n    ft = { \"clojure\", \"fennel\" },\n    config = function()\n      vim.g.parinfer_force_balance = true\n      vim.g.parinfer_comment_chars = \";;\"\n    end,\n  },\n}\n```\n

Improve syntax highlighting by installing the Clojure parser for Treesitter.

Treesitter Parser for clojure in AstroNvim user configuration

.config/astronvim-config/plugins/treesitter.lua
return {\n  \"nvim-treesitter/nvim-treesitter\",\n  opts = function(_, opts)\n    -- add more things to the ensure_installed table protecting against community packs modifying it\n    opts.ensure_installed = require(\"astronvim.utils\").list_insert_unique(opts.ensure_installed, {\n      -- \"lua\"\n    \"clojure\"\n    })\n  end,\n}\n

Install Treesitter Clojure Parser manually

:TSInstall clojure in Neovim will install the parser. A parser not included in the opts.ensure_installed configuration must be updated manually each time treesitter plugin is updated

"},{"location":"configuration/astronvim/config-design/#clojure-mappings","title":"Clojure Mappings","text":"

Conjure mappings are defined respective to a <localleader> value. Define a local leader in the AstroNvim user configuration, e.g. , and all Conjure mappings become available.

AstroNvim 3.17.0 has localleader

AstroNvim 3.17.0 release sets localleader to , so a separate setting is not required in the user configuration (unless a different localleader is preferred)

Set localleader in user config

options.lua in the user configuration provides a consistent way to set Neovim options.

.config/astronvim-config/options.lua
-- set vim options here (vim.<first_key>.<second_key> = value)\nreturn {\n  opt = {\n    -- set to true or false etc.\n    relativenumber = true, -- sets vim.opt.relativenumber\n    number = true,         -- sets vim.opt.number\n    spell = false,         -- sets vim.opt.spell\n    signcolumn = \"auto\",   -- sets vim.opt.signcolumn to auto\n    wrap = false,          -- sets vim.opt.wrap\n  },\n  g = {\n    mapleader = \" \",                 -- sets vim.g.mapleader\n    maplocalleader = \",\",            -- Set local leader key binding (supports Conjure key bindings)\n    autoformat_enabled = true,       -- enable or disable auto formatting at start (lsp.formatting.format_on_save must be enabled)\n    cmp_enabled = true,              -- enable completion at start\n    autopairs_enabled = true,        -- enable autopairs at start\n    diagnostics_mode = 3,            -- set the visibility of diagnostics in the UI (0=off, 1=only show in status line, 2=virtual text off, 3=all on)\n    icons_enabled = true,            -- disable icons in the UI (disable if no nerd font is available, requires :PackerSync after changing)\n    ui_notifications_enabled = true, -- disable notifications when toggling UI elements\n    VM_leader = \"gm\"                 -- Visual Multi Leader (multiple cursors)\n  },\n}\n
"},{"location":"configuration/astronvim/config-design/#clojure-lsp","title":"Clojure LSP","text":"

Clojure LSP support is enabled via the AstroCommunity Clojure pack.

clojure_lsp can be added using Mason UI, SPC p m or in the plugins/mason.lua file

Manual user config of clojure lsp server
-- customize mason plugins\nreturn {\n  -- use mason-lspconfig to configure LSP installations\n  {\n    \"williamboman/mason-lspconfig.nvim\",\n    -- overrides `require(\"mason-lspconfig\").setup(...)`\n    opts = function(_, opts)\n      -- add more things to the ensure_installed table protecting against community packs modifying it\n      opts.ensure_installed = require(\"astronvim.utils\").list_insert_unique(opts.ensure_installed, {\n        -- \"clojure_lsp\",  -- provide by Clojure pack\n        \"marksman\", -- Markdown structure (also in markdown pack)\n        \"yamlls\",\n      })\n    end,\n  },\n}\n
"},{"location":"configuration/astronvim/config-design/#snippets","title":"Snippets","text":"

The AstroNvim user example includes a commented LuaSnip configuration

.config/astronvim-config/plugins/core.lua
  -- {\n  --   \"L3MON4D3/LuaSnip\",\n  --   config = function(plugin, opts)\n  --     require \"plugins.configs.luasnip\" (plugin, opts)  -- include the default astronvim config that calls the setup call\n  --     -- add more custom luasnip configuration such as filetype extend or custom snippets\n  --     local luasnip = require \"luasnip\"\n  --     luasnip.filetype_extend(\"javascript\", { \"javascriptreact\" })\n  --   end,\n  -- },\n

AstroNvim includes a Recipe for custom snippets

return {\n  plugins = {\n    {\n      \"L3MON4D3/LuaSnip\",\n      config = function(plugin, opts)\n        require \"plugins.configs.luasnip\"(plugin, opts) -- include the default astronvim config that calls the setup call\n        require(\"luasnip.loaders.from_vscode\").lazy_load { paths = { \"./lua/user/snippets\" } } -- load snippets paths\n      end,\n    },\n  },\n}\n

Practicalli AstroNvim Config combines the two examples to get

AstroNvim config with custom VS Code style snippets

.config/astronvim-config/plugins/core.lua
{\n  \"L3MON4D3/LuaSnip\",\n  config = function(plugin, opts)\n    require \"plugins.configs.luasnip\" (plugin, opts) -- include the default astronvim config that calls the setup call\n    -- add more custom luasnip configuration such as filetype extend or custom snippets\n    require(\"luasnip.loaders.from_vscode\").lazy_load { paths = { \"./lua/user/snippets\" } } -- load snippets paths\n    local luasnip = require \"luasnip\"\n    luasnip.filetype_extend(\"javascript\", { \"javascriptreact\" })\nend,\n},\n
"},{"location":"configuration/astronvim/config-design/#astronvim-community-packages","title":"AstroNvim Community packages","text":"

AstroNvim Community provides a large number of packages currated by the community.

Visit the AstroNvim Community repository on GitHub and browse the packages available.

import each package of interest to the plugins/community.lua file in the AstroNvim user configuration.

AstroNvim Community Packages in AstroNvim user configuration

.config/astronvim-config/plugins/community.lua
return {\n  -- Add the community repository of plugin specifications\n  \"AstroNvim/astrocommunity\",\n  -- Import each plugin from the Astro Community as required\n  { import = \"astrocommunity.editing-support.todo-comments\" },\n  { import = \"astrocommunity.git.neogit\" },\n  { import = \"astrocommunity.git.octo\" },\n  { import = \"astrocommunity.git.openingh\" },\n}\n

AstroCommunity packs set up support for each language

Language packs enabled in Practicalli AstroNvim Config

.config/astronvim-config/plugin/community.lua
  -- Packs\n  -- Treesitter: dockerfile , Lsp: dockerls & docker_compose_language_service, Lint/format: hadolint\n  { import = \"astrocommunity.pack.docker\" },\n  -- Treesitter: json & jsonc, Lsp: jsonls, Lint/format: stylua\n  { import = \"astrocommunity.pack.json\" },\n  -- Treesitter: lua, Lsp: lua_ls, Lint/format: stylua\n  { import = \"astrocommunity.pack.lua\" },\n  -- Treesitter: markdown & markdown_inline, Lsp: marksman, Lint/format: prettierd\n  -- Pack disabled as prettierd too agressive with format\n  -- { import = \"astrocommunity.pack.markdown\" },\n  -- Treesitter: markdown & markdown_inline, Lsp: marksman, Lint/format: prettierd\n  { import = \"astrocommunity.pack.yaml\" },\n
"},{"location":"configuration/astronvim/config-design/#themes","title":"Themes","text":"

Themes are a collection of one or more colorschemes to affect the apperance of text, icons, highlights, etc.

Themes supporting vim.opt.background can change between dark and light colorscheme (SPC u b UI > background in AstroNvim)

SPC f t selector shows themes colorschemes, as long as the themes are configured to disable lazy loading

The default astrodark theme is set via the colorscheme option in init.lua

Everforest provides a good dark and light theme and supports the background option to toggle between each colorscheme.

Practicalli AstroNvim Config - default theme

colorscheme = \"everforest\",\n

AstroCommunity themes

Practicalli AstroNvim Config themes

return {\n{\n\"AstroNvim/astrotheme\", -- default AstroNvim theme\nlazy = false,\n},\n  -- Add the community repository of plugin specifications\n  \"AstroNvim/astrocommunity\",\n  { import = \"astrocommunity.colorscheme.everforest\" },\n  {\n    \"sainnhe/everforest\",\n    lazy = false,\n  },\n  { import = \"astrocommunity.colorscheme.nightfox-nvim\" },\n  {\n    \"EdenEast/nightfox.nvim\",\n    lazy = false,\n  },\n  { import = \"astrocommunity.colorscheme.kanagawa-nvim\" },\n  {\n    \"rebelot/kanagawa.nvim\",\n    lazy = false,\n  },\n  { import = \"astrocommunity.colorscheme.github-nvim-theme\" }, -- no background support\n  {\n    \"projekt0n/github-nvim-theme\",\n    lazy = false,\n  },\n
"},{"location":"configuration/astronvim/config-design/#configure-lazy-plugins","title":"Configure Lazy plugins","text":"

Lazy.nvim Plugin specification

"},{"location":"configuration/astronvim/config-design/#config-format-and-lint-tools","title":"Config Format and Lint tools","text":"

Disable format on save when tools provide unexpected results

SPC u f toggles if the respective format tool should run for the current buffer. SPC u F for all buffers of the current kind.

init.lua lsp section can enable or disable format on save for specific file types.

Mason is responsible for installing lint and format tools

null-ls is responsible for running each tool and provides default configuration for code_actions, completion, diagnostics, formatting and hover.

null-ls built-in configuration

Override config file unconsistent

The configuration file defined by -config-path does not always seem to be used when running astronvim. Quit and start Neovim again seems to use the configuration file.

Override null-ls builtin configuration

Specify configuration files to use that override the null-ls builtin configuration

return {\n  \"jose-elias-alvarez/null-ls.nvim\",\n  opts = function(_, config)\n    -- config variable is the default configuration table for the setup function call\n    local null_ls = require \"null-ls\"\n    config.sources = {\n      null_ls.builtins.formatting.markdownlint.with {\n        -- pass arguments to modify/override the null-ls builtin configuration\n        extra_args = { \n          \"--config-path\", \n          vim.fn.expand(\"~/.config/astro-config/tool-config/markdownlint.yaml\") },\n      },\n    }\n    return config -- return final config table\n  end,\n}\n

vim.fn.expand() reports luacheck error accessing undefined variable but seems to work regardless

General configuration for LSP Servers .config/astronvim-config/init.lua
  lsp = {\n    -- customize lsp formatting options\n    formatting = {\n      -- control auto formatting on save\n      format_on_save = {\n        enabled = true,     -- format on save globally\n        allow_filetypes = { -- format on save for specified filetypes only\n          -- \"go\",\n        },\n        ignore_filetypes = { -- turn off format on save for specified filetypes\n          -- \"python\",\n        },\n      },\n      disabled = { -- switch off formatting capabilities for the listed language servers\n        -- turn off lua_ls formatting capability if you want to use StyLua to format your lua code\n        -- \"lua_ls\",\n        \"markdownlint\",\n      },\n      timeout_ms = 1000, -- default format timeout\n      -- filter = function(client) -- fully override the default formatting function\n      --   return true\n      -- end\n    },\n    -- enable servers that you already have installed without mason\n    servers = {\n      -- \"pyright\"\n    },\n  },\n
"},{"location":"configuration/astronvim/config-design/#override-key-binding","title":"Override Key binding","text":"

AstroNvim uses Lazy package manager to set keys for packages.

Astrocommunity configuration defines a keys table that is used by Lazy.

In the user configuration, return a function that sets key bindings to overide the keys table provided by astrocommunity

Override Key bindings for vim highlighter .config/astronvim-config/plugins/community.lua
{\n    \"vim-highlighter\",\n    keys = function() \n        return {\n            { \"<leader>nn\", \"<cmd>Hi><CR>\", desc = \"Next Recently Set Highlight\" },\n            { \"<leader>ng\", \"<cmd>Hi<<CR>\", desc = \"Previous Recently Set Highlight\" },\n            { \"<leader>n[\", \"<cmd>Hi{<CR>\", desc = \"Next Nearest Highlight\" },\n            { \"<leader>n]\", \"<cmd>Hi}<CR>\", desc = \"Previous Nearest Highlight\" },\n        }\n    end,\n}\n
"},{"location":"configuration/astronvim/config-design/#plugin-key-binding","title":"Plugin Key binding","text":"

Add key binding if a plugin is available wrapped in an if statement, when defining keys in a different place to adding the plugin, e.g whichkey mappings.lua

if is_available \"plugin-name\" then\n  ,,,\nelse\n
"},{"location":"configuration/practicalli/","title":"Neovim Config Redux","text":"

practicalli/neovim-config-redux

practicalli/neovim-config-redux is a Fennel based configuraion with a wide range of plugins and telescope extensions.

Clone practicalli/neovim-config-redux or create a fork if intending to customise that configuration

Multiple Neovim ConfigsSingle Neovim Configs
git clone https://github.com/practicalli/neovim-config-redux.git ~/.config/neovim-config-redux\n
git clone https://github.com/practicalli/neovim-config-redux.git ~/.config/nvim\n
"},{"location":"configuration/practicalli/#screenshots","title":"Screenshots","text":"

Dashboard using the startup plugin

Mnemonic menu with which-key

Telescope buffer selection

Neogit Git client with diffview panel

"},{"location":"configuration/practicalli/config-design/","title":"Config Design","text":"

The overall design of the Practicalli Neovim Config Redux

"},{"location":"configuration/practicalli/config-design/#initlua","title":"init.lua","text":""},{"location":"configuration/practicalli/config-design/#fnlconfiginitfnl","title":"fnl/config/init.fnl","text":""},{"location":"configuration/practicalli/config-design/#fnlconfigpluginfnl","title":"fnl/config/plugin.fnl","text":"

Define plugins to add functionality to Neovim.

use is a private function that searches the plugin configuration map for the keyword :mod and loads the associated namespace (namespace defined with a keyword with the same name)

e.g. in the telescope plugin configuration :mod has a value of :telescope which will load the file fnl/config/plugin/telescope.fnl

  :nvim-telescope/telescope.nvim\n  {:requires [:nvim-lua/popup.nvim\n              :nvim-lua/plenary.nvim]\n   :mod :telescope}\n

Packer downloads the nvim-telescope/telescope.nvim plugin and all the plugins in :requires section and search for the namespace telescope in file located in the following path fnl/config/plugin/telescope

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginconjurefnl","title":"fnl/config/plugin/conjure.fnl","text":"

The majority of default configuration settings are used for Conjure, with the exception of a few commonly used key bindings from Emacs CIDER & Spacemacs. The Heads Up Display (HUD) is also configured to be less intrusive, relying on mostly on inline results.

Include the conjure and aniseed namespaces

(module config.plugin.conjure\n  {autoload {nvim aniseed.nvim}})\n

Configure keybindings to be closer to Spacemacs

;; Set e register for evaluation result\n(set nvim.g.conjure#eval#result_register :e)\n\n;; Evaluate root form (top level form) under the cursor\n;; Default: `\"er\"`\n(set nvim.g.conjure#mapping#eval_root_form \"ef\")\n\n;; Evaluate root form under the cursor & insert result as comment\n;; Default: `\"ecr\"`\n(set nvim.g.conjure#mapping#eval_comment_root_form \"e;\")\n\n;; Evaluate file loaded from disk\n;; Default: `\"ef\"`\n(set nvim.g.conjure#mapping#eval_file \"el\")\n

Configure the HUD to be less intrusive.

;; Width of HUD as percentage of the editor width\n;; A float between 0.0 and 1.0.\n;; Default: `0.42`\n(set nvim.g.conjure#log#hud#width 1)\n\n;; Display HUD\n;; Default: `true`\n(set nvim.g.conjure#log#hud#enabled false)\n\n;; Preferred corner position for the HUD, over-ridden by HUD cursor detection\n;; Example: Set to `\"SE\"` and HUD width to `1.0` for full width HUD at bottom of screen\n;; Default: `\"NE\"`\n(set nvim.g.conjure#log#hud#anchor \"SE\")\n\n;; Open log at bottom or far right of editor, using full width or height\n;; Default: `false`\n(set nvim.g.conjure#log#botright true)\n

Practicalli encourages header comments at the start of each file to describe the purpose of the namespace, so the Clojure ns lookup is extended

;; Number of lines to check for `ns` form, used for setting evaluation context\n;; `b:conjure#context` to override a specific buffer that isn't finding the context\n;; Default: `24`\n(set nvim.g.conjure#extract#context_header_lines 100)\n

Disable the auto-repl as practicalli prefers manage repl connections themselves

;; Start \"auto-repl\" process, eg. babashka\n;; when Conjure unable to find candidate REPL process via to an existing nREPL connection\n;; Default: `true`\n(set nvim.g.conjure#client#clojure#nrepl#connection#auto_repl#enabled false)\n\n;; Hide auto-repl buffer when triggered, to avoid the need to interact with that buffer\n;; Default: `false`\n(set nvim.g.conjure#client#clojure#nrepl#connection#auto_repl#hidden true)\n\n;; Command to start the auto-repl\n;; Default: `\"bb nrepl-server localhost:8794\"`\n(set nvim.g.conjure#client#clojure#nrepl#connection#auto_repl#cmd nil)\n\n;; Print raw evaluation result, suppressing prefix for stdout lines `; (out)`\n;; Default: `false`\n(set nvim.g.conjure#client#clojure#nrepl#eval#raw_out true)\n\n;; Automatically require namespace of new buffer or current buffer after connection\n;; Ensures buffers are loaded, required code to compile and (re)loadable.\n;; Default: `true`\n(set nvim.g.conjure#client#clojure#nrepl#eval#auto_require false)\n

Use lambdaisland/kaocha as the test runner rather, which has a fail fast feature which can be more effective when adding or changing functionality

;; Test runner called from the test key mappings\n;; Default: `\"clojure\"`\n(set nvim.g.conjure#client#clojure#nrepl#test#runner \"kaocha\")\n\n;; Print raw test evaluation result, suppressing prefix for stdout lines `; (out)`\n;; Default: `true`\n(set nvim.g.conjure#client#clojure#nrepl#test#raw_out true)\n
"},{"location":"configuration/practicalli/config-design/#fnlconfigplugintelescopefnl","title":"fnl/config/plugin/telescope.fnl","text":"

Settings like ignore node_modules and everything in .gitignore to be listed in the file finder.

Defines a ripgrep command to set parameters for searching files

Add --hidden to see all dotfiles (regardless of .gitignore patterns)

Keymaps:

"},{"location":"configuration/practicalli/config-design/#fnlconfigplugintreesitterfnl","title":"fnl/config/plugin/treesitter.fnl","text":"

Defines which language parsers and modules to use.

(treesitter.setup\n  {:ensure_installed [\"clojure\" \"fennel\" \"markdown\"]\n   :sync_install true\n   :highlight {:enable true}\n   :indent    {:enable true}})\n
"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginlspconfigfnl","title":"fnl/config/plugin/lspconfig.fnl","text":"

Language Server Protocol for static analysis of code, to provide common formatting, linting and refactoring tooling across all programming languages.

Define which symbols to show for lsp diagnostics

(defn define-signs\n  [prefix]\n  (let [error (.. prefix \"SignError\")\n        warn  (.. prefix \"SignWarn\")\n        info  (.. prefix \"SignInfo\")\n        hint  (.. prefix \"SignHint\")]\n  (vim.fn.sign_define error {:text \"\uf057\" :texthl error})\n  (vim.fn.sign_define warn  {:text \"\uf071\" :texthl warn})\n  (vim.fn.sign_define info  {:text \"\uf05a\" :texthl info})\n  (vim.fn.sign_define hint  {:text \"\uf059\" :texthl hint})))\n
"},{"location":"configuration/practicalli/config-design/#fnlconfigplugincmpfnl","title":"fnl/config/plugin/cmp.fnl","text":"

Configure sources to show in the autocomple menu (i.e. conjure, lsp, buffer) and key bindings to navigate the autocomplete popup menu.

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginthemefnl","title":"fnl/config/plugin/theme.fnl","text":"

Add the Neovim GitHub theme which gives 3 dark and 3 light themes to choose from. Individual colors and styles can be configured to change specific parts of the theme.

The light theme is used by default, with a custom softer background colour that is slightly red-shifted.

Options are specified in the theme.setup function, where the option names are keywords and the values are strings, boolean or hash-map of more option keywords and values.

(theme.setup {:theme_style \"light\"\n              :colors {:bg \"#f8f2e6\"}\n              :comment_style \"italic\"})\n

The colors (Hex values) for each theme are in the github-nvim-theme/lua/github-theme/palette with the overal theme definition in github-nvim-theme/lua/github-theme/theme.lua

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginsexpfnl","title":"fnl/config/plugin/sexp.fnl","text":"

Settings for vim-sexp like enabling it for another lisp languages like Fennel and Jannet

"},{"location":"configuration/practicalli/config-design/#fnlconfigpluginlualinefnl","title":"fnl/config/plugin/lualine.fnl","text":"

Configure the status line (lualine) that shows at the bottom of Neovim, defining colors and elements that appear on that line.

The Neovim GitHub theme includes definitions to set the look of the status line.

"},{"location":"configuration/practicalli/packer/","title":"Package Manager","text":"

Packer is a use-package inspired package management for Neovim.

Packer is used as the package manager in this guide as it is built on native Neovim packages and supports Luarocks dependencies, use the :help packages command in Neovim for more details.

Packer is written in Lua and is installed via the init.lua configuration file, although Practicalli Neovim configuration uses Fennel to configure each package added by Packer.

"},{"location":"configuration/practicalli/packer/#install","title":"Install","text":"

init.lua is the entry point to the configuration and is the only part that is written in Lua language.

The configuration bootstraps the Packer package manager and installs the Aniseed compiler required to process the fennel configuration.

Aniseed compiles and loads fnl/config/init.fnl and all the required namespaces in that file.

Packer will process the use form in fnl/config/plugin.fnl and install all the packages defined in that form, along with any package specific configuration defined in that package {:mod :namespace-name} file.

local execute = vim.api.nvim_command\nlocal fn = vim.fn\n\nlocal pack_path = fn.stdpath(\"data\") .. \"/site/pack\"\nlocal fmt = string.format\n\nfunction ensure (user, repo)\n  -- Ensures a given github.com/USER/REPO is cloned in the pack/packer/start directory.\n  local install_path = fmt(\"%s/packer/start/%s\", pack_path, repo, repo)\n  if fn.empty(fn.glob(install_path)) > 0 then\n    execute(fmt(\"!git clone https://github.com/%s/%s %s\", user, repo, install_path))\n    execute(fmt(\"packadd %s\", repo))\n  end\nend\n\n-- Bootstrap essential plugins required for installing and loading the rest.\nensure(\"wbthomason\", \"packer.nvim\")\nensure(\"Olical\", \"aniseed\")\n\n-- Enable Aniseed's automatic compilation and loading of Fennel source code.\nvim.g[\"aniseed#env\"] = {\n  module = \"config.init\",\n  compile = true\n}\n
"},{"location":"configuration/practicalli/packer/#packages","title":"Packages","text":"

Neovim packages add extra functionality to Neovim, e.g. conjure package provides an excellent Clojure REPL experience (and supports several other languages too).

See the packages section for details of the packages used and a breakdown of their configuration.

"},{"location":"configuration/practicalli/packages/","title":"Add Neovim Packages","text":"

Evolving Packages in Practicalli config

Check the practicalli/neovim-config-reduct configuration. Many packages have been added to the configuration and fnl/config/package.fnl is the most up to date list of packages currently used.

List of packages and their purpose

Package Description conjure Clojure REPL Driven Development (and other language REPLs) sexp Structured Editing newpaper theme Clean and simple UI & colour scheme, aimed at readably lualine Fast and configurable statusline nvim-treesitter Parse code highly efficiently, client for LSP servers telescope Completion tool, e.g. select files, buffers tabs, packages, etc nvim-tree Visual file manager - open, create, delete, etc. files & directories neogit Magit style visual Git client Octo Git Issues and Pull Requests gitsigns Show diff changes in buffer gutter and status line

Any specific package configuration & key bindings (on sub page if significant content)

"},{"location":"configuration/practicalli/packages/#package-selection-criteria","title":"Package selection criteria","text":"

Packages are more likely to be adopted if:

"},{"location":"configuration/practicalli/packages/#package-updates","title":"Package Updates","text":"

This Week In Neovim - community update

"},{"location":"configuration/practicalli/packages/lualine/","title":"Lualine - modeline theme","text":"

nvim-lualine/lualine.nvim is a fast and configurable statusline for neovim

Example status line: evil_lualine

"},{"location":"configuration/practicalli/packages/lualine/#lualine-configuration-in-fennel","title":"Lualine configuration in Fennel","text":"

nvim/fnl/config/plugin/lualine.fnl

(module config.plugin.lualine\n  {autoload {core aniseed.core\n             lualine lualine\n             lsp config.plugin.lspconfig}})\n\n(defn lsp_connection []\n  (if (vim.tbl_isempty (vim.lsp.buf_get_clients 0)) \"\uf096\" \"\uf0c8\"))\n\n(def github-lua-theme\n  (core.assoc\n    (require :lualine.themes.auto)\n    :inactive {:a {:bg \"#19181e\" :fg \"#a4a3a6\"}\n               :b {:bg \"#19181e\" :fg \"#a4a3a6\"}\n               :c {:bg \"#19181e\" :fg \"#a4a3a6\"}}\n    :normal {:a {:bg \"#131217\" :fg \"#24292e\"}\n             :b {:bg \"#131217\" :fg \"#3b8eea\"}\n             :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :command {:a {:bg \"#131217\" :fg \"#24292e\"}\n              :b {:bg \"#131217\" :fg \"#ccbed8\"}\n              :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :visual {:a {:bg \"#131217\" :fg \"#24292e\"}\n             :b {:bg \"#131217\" :fg \"#ced4b1\"}\n             :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :replace {:a {:bg \"#131217\" :fg \"#24292e\"}\n              :b {:bg \"#131217\" :fg \"#d1b6bd\"}\n              :c {:bg \"#19181e\" :fg \"#d1d5da\"}}\n    :insert {:a {:bg \"#131217\" :fg \"#24292e\"}\n             :b {:bg \"#131217\" :fg \"#a8d1c9\"}\n             :c {:bg \"#19181e\" :fg \"#d1d5da\"}}))\n\n(lualine.setup\n  {:options {:theme github-lua-theme\n             :icons_enabled true\n             :section_separators [\"\" \"\"]\n             :component_separators [\"\uf44a\" \"\uf438\"]}\n   :sections {:lualine_a []\n              :lualine_b [[:mode {:upper true}]]\n              :lualine_c [[\"FugitiveHead\"]\n                          [:filename {:filestatus true\n                                      :path 1}]]\n              :lualine_x [[:diagnostics {:sections [:error\n                                                    :warn\n                                                    :info\n                                                    :hint]\n                                         :sources [:nvim_lsp]}]\n                          [lsp_connection]\n                          :location\n                          :filetype]\n              :lualine_y [:encoding]\n              :lualine_z []}\n   :inactive_sections {:lualine_a []\n                       :lualine_b []\n                       :lualine_c [[:filename {:filestatus true\n                                               :path 1}]]\n                       :lualine_x []\n                       :lualine_y []\n                       :lualine_z []}})\n
"},{"location":"configuration/practicalli/packages/nvim-treesitter/","title":"Nvim Treesitter","text":"

Treesitter provides language specific parsing, highlight and indent features and so is a fundamental plugin to use with Neovim.

clojure, fennel, markdown and org parsers are automatically installed in the practicalli/neovim-config-redux configuration.

"},{"location":"configuration/practicalli/packages/nvim-treesitter/#nvim-treesitter-configuration","title":"nvim-treesitter configuration","text":"

clojure, fennel, markdown and org parsers are automatically installed if not already available.

:sync_install true automatically updates the parsers when the nvim-treesitter plugin is updated. Treesitter and its parsers are actively developed, so its important to ensure parsers are kept up to date. This is the equivalent of manually running :TSUpdateSync.

Parser highlight and indent modules are enabled by default

In fnl/config/plugin/treesitter.fnl

(module config.plugin.treesitter\n  {autoload {treesitter nvim-treesitter.configs}})\n\n(treesitter.setup\n  {:ensure_installed [\"clojure\" \"fennel\" \"markdown\" \"org\"]\n   :sync_install true\n   :highlight {:enable true}\n   :indent    {:enable true}})\n
"},{"location":"configuration/practicalli/packages/nvim-treesitter/#manually-install-parsers","title":"Manually Install Parsers","text":"

nvim-treesitter provides the TSInstall command to generate a parser for a specific language, assuming that language is supported.

A compiler (gcc, clang, etc) should be installed in the operating system on which nvim is running

:TSInstall {language}\n

TAB completion lists the available language parsers, TAB and S-TAB to navigate the auto-completion popup.

"},{"location":"install/","title":"Install Overview","text":"

Practicalli Neovim provides a feature rich configuration for Neovim and all the tools required for effective Clojure development (and other Lisp dialects too).

Neovim 0.9.x latest stable release

Content and configuration in this book has been tested against Neovim 0.9.x over the summer of 2023

"},{"location":"install/#install-summary","title":"Install summary","text":"

If you are familiar with most of the tools required, then the quick start list below provides an ultra-terse version on how to get started with Neovim and Clojure development.

"},{"location":"install/#next-steps","title":"Next Steps","text":"

Learn how to use Neovim and how to use Conjure for REPL driven development

"},{"location":"install/clojure/","title":"Install Clojure","text":"

A rich Clojure REPL workflow is provided by the Conjure package, which works with Clojure CLI and Leiningen projects, assuming the respective tool is installed.

Clojure LSP is highly recommended and packages to use an installed clojure-lsp tool are in the practicalli/neovim-config-redux configuration

"},{"location":"install/clojure/#clojure-cli","title":"Clojure CLI","text":"

Practicalli Clojure install guide

Clojure CLI provides a way to run Clojure code, packaged Clojure (jar) and run a Clojure REPL.

Practicalli Clojure install guide details prerequisites, Clojure install options and supporting tools for an enhanced developer workflow.

Visit the Clojure Getting Started guide for the Clojure CLI or to check the latest release version.

Practicalli Clojure CLI Config provides a wide range of community tools that extend the features of Clojure CLI, creating a rich development environment for use across all projects.

Aliases are required for many examples

Without Practicalli Clojure CLI Config many commands provided in this book are not available unless similar alias definitions are added to a either a project or user level deps.edn configuration.

"},{"location":"install/clojure/#language-server-protocol","title":"Language Server Protocol","text":"

Neovim Treesitter surfaces information from Language Server Protocol (LSP) servers to assist with development and refactor of Clojure code.

Clojure LSP installation guide shows how to install the Clojure LSP binary for the relevant operating system.

Once installed, run clojure-lsp -v in a terminal to ensure the command is working.

practicalli/clojure-lsp-config

practicalli/clojure-lsp-config provides a complete configuration for clojure-lsp (config.edn), including a wide range of snippets and less restrictive formatting rules (cljfmt.edn)

clj-kondo provides static analysis of source code files, providing subtle warnings as Clojure code is written to help the developer follow idioms and avoid syntatic errors.

Clojure LSP includes clj-kondo to provide an implementation of the Language Server Protocol for the Clojure Language.

Clojure LSP installation guide Treesitter Fennel Configuration

"},{"location":"install/clojure/#leiningen","title":"Leiningen","text":"

Many existing Clojure projects use Leiningen build automation tool (although many new projects use Clojure CLI as well or instead of Leiningen).

The code is the same regardless of tooling choice. The overall workflow is the same, although Clojure CLI may provide more workflow options.

Follow the install instructions at Leiningen.org if required.

"},{"location":"install/neovim/","title":"Install Neovim","text":"

Neovim releases

Neovim 8 is the minimum version for this configuration and Neovim 0.9.0 is currently being tested.

Follow the install Neovim guide for the specific operating system.

"},{"location":"install/neovim/#suppoting-tools","title":"Suppoting Tools","text":"

Neovim uses several external tools for searching for files, search file contents and using the operating system clipbaord.

AstroNvim requires node.js

AstroNvim uses Mason to install LSP servers, format and lint tools. Many LSP servers require node.js to install and function.

Node.js install - Practicalli Engineering Playbook

Debian / Ubuntu

Install the following packages to support Neovim

sudo apt install find-fd xclip luarocks\n

Add set clipboard+=unnamedplus to the Neovim configuration to use the Linux clipboard tool

Wayland requires wl-clipboard

Install the wl-clipboard package to use the Wayland desktop clipboard with Neovim

sudo apt install wl-clipboard\n

"},{"location":"install/neovim/#install-neovim_1","title":"Install Neovim","text":"Linux AppImageUbuntu/DebianBuild from Source

Download the AppImage from the Neovim Release page and place the file on the executable path, e.g. $HOME/.local/bin

Make the AppImage executable

chmod u+x nvim.appimage\n

Run neovim from the AppImage

nvim.appimage\n

Create a symbolic link called nvim to the nvim.appimage

ln -s $HOME/.local/bin/nvim.appimage $HOME/.local/bin/nvim\n

Download the Linux AppImage from the Neovim Releases page

Or build Neovim from source and generate a .deb file from the build.

Linux version only packaged as AppImage from Neovim 0.9 onward

Neovim Build Prerequisites for each operating system

Ubuntu/Debian Packages

Install packages to support building Neovim

sudo apt-get install ninja-build gettext cmake unzip curl\n

Clone the Neovim GitHub repository

git clone --origin neovim https://github.com/neovim/neovim.git\n
Change into the cloned directory and change to the stable release to build version 0.9.0

git checkout stable\n

Build a release

make CMAKE_BUILD_TYPE=Release                                                                                                              \u2500\u256f\n

Once the nvim release has been built, create a debian package for use with Ubuntu and Debian systems

cpack -G DEB\n
"},{"location":"install/neovim/#post-install-checks","title":"Post Install checks","text":"

Ensure supporting tools and binaries are available in the operating system by running the Neovim Heath Check.

nvim in a terminal to run NeoVim and check the installation is working without error.

:checkhealth to run a check supporting tools are available to NeoVim.

A report is generated and shown in NeoVim

j / k to scroll through the checkhealth report

Review the warnings and install tooling that is required for languages that will be used.

Ignore Provider Warnings

It is safe to ignore language provider warnings.

Language Providers can be disabled in the Neovim configuration to remove the warnings from :checkhealth report. Examples of disabling language provders are in the practicalli/neovim-config-redux configuration, covered in the Neovim Config install step

"},{"location":"introduction/community-projects/","title":"Community Configuration Projects","text":"

Practicalli Neovim book covers the following configurations:

"},{"location":"introduction/community-projects/#practicalli-neovim-config-redux","title":"Practicalli Neovim Config Redux","text":"

Practicalli Neovim Config Redux

"},{"location":"introduction/community-projects/#astronvim-and-practicalli-astronvim-config","title":"AstroNvim and Practicalli AstroNvim Config","text":"

AstroNvim and Practicalli AstroNvim Config organised configuration with a polished UI

"},{"location":"introduction/community-projects/#alternative-configurations","title":"Alternative configurations","text":"

Practicalli Neovim does not cover the following Community configurations.

Long term project: Fennel config with AstroNvim-like UI experience

A very long term goal for Practicalli is to create a Neovim configuration written predominatly in Fennel, providing a rich user experience on par with the very polished experience of AstroNvim.

Lazy and Mason should be used to manage packages and tools (LSP & DAP servers, lint & format tools).

Which-key should provide a mnemonic menu system similar to the Spacemacs experience.

"},{"location":"introduction/contributing/","title":"Contributing to Practicalli","text":"

Practicalli books are written in markdown and use MkDocs to generate the published website via a GitHub workflow. MkDocs can also run a local server using the make docs target from the Makefile

By submitting content ideas and corrections you are agreeing they can be used in this book under the Creative Commons Attribution ShareAlike 4.0 International license. Attribution will be detailed via GitHub contributors.

All content and interaction with any persons or systems must be done so with respect and within the Practicalli Code of Conduct.

"},{"location":"introduction/contributing/#book-status","title":"Book status","text":""},{"location":"introduction/contributing/#submit-and-issue-or-idea","title":"Submit and issue or idea","text":"

If something doesnt seem quite right or something is missing from the book, please raise an issue via the GitHub repository explaining in as much detail as you can.

Raising an issue before creating a pull request will save you and the maintainer time.

"},{"location":"introduction/contributing/#considering-a-pull-request","title":"Considering a Pull request?","text":"

Before investing any time in a pull request, please raise an issue explaining the situation. This can save you and the maintainer time and avoid rejected pull requests.

Please keep pull requests small and focused, as they are much quicker to review and easier to accept. Ideally PR's should be for a specific page or at most a section.

A PR with a list of changes across different sections will not be merged, it will be reviewed eventually though.

"},{"location":"introduction/contributing/#thank-you-to-everyone-that-has-contributed","title":"Thank you to everyone that has contributed","text":"

A huge thank you to Rich Hickey and the team at Cognitect for creating and continually guiding the Clojure language. Special thank you to Alex Miller who has provided excellent advice on working with Clojure and the CLI tooling.

The Clojure community has been highly supportive of everyone using Clojure and I'd like to thank everyone for the feedback and contributions. I would also like to thank everyone that has joined in with the London Clojurins community, ClojureBridgeLondon, Clojurians Slack community, Clojurians Zulip community and Clojureverse community.

Thank you to everyone who sponsors the Practicalli websites and videos and for the Clojurists Together sponsorship, it helps me continue the work at a much faster pace.

Special thanks to Bruce Durling for getting me into Cloure in the first place.

"},{"location":"introduction/features/","title":"Neovim features","text":"

A clean UI provides for a distraction free development experience, with only the essential information presented in the Neovim statusline or inline with the code

"},{"location":"introduction/features/#conjure","title":"Conjure","text":"

Conjure An interactive environment for evaluating code, e.g. a Clojure REPL. Conjure automatically connects to an nREPL process running in the current project.

Evaluate Clojure code as its developed for an instant feedback workflow.

Run unit tests with Kaocha test runner (Cognitect Labs and ClojureScript runners also available)

Fireplace has been a long-standing plugin for Vim to support Clojure REPL connection.

"},{"location":"introduction/features/#lazy-plugin-manager","title":"Lazy Plugin manager","text":"

Lazy.nvim manages neovim plugins with a rich UI that provides an enjoyable user experience. Plugins are automatically installed during startup and lists the status of each plugins.

Plugins are automatic cached & bytecode compiled and can be lazy loaded to streamline startup time and resource usage based on events, commands, filetypes, and key mappings. Efficient plugin downlaods using partial blobless clones of plugin repositories, i.e. --filter=blob:none

Lazy.nvim

"},{"location":"introduction/features/#treesitter","title":"Treesitter","text":"

Neovim provides highly effective syntax highlighting of source code due to Treesitter.

Tree-sitter parses files opened in Neovim and builds a concrete syntax tree that any Neovim plugin can use to efficiently provide feedback. Treesitter uses incremental parsing to efficiently update the syntax tree as a file is edited.

Treesitter

"},{"location":"introduction/features/#language-server-protocol","title":"Language Server Protocol","text":"

Neovim includes an LSP client which uses the information recieved from a language specific LSP server in real-time to provide a range of services:

LSP feedback is often presented in the buffer, file browser and status line of Neovim.

LSP Server implementation is not universal

LSP is a relatively new specification and many server implmentations are still evolving or are yet to be created.

Lint tools tend to be more prevelent and may be required in concert with or in the absence of an LSP server.

LSP related Plugins "},{"location":"introduction/features/#lint-and-format-tools","title":"Lint and format tools:","text":"

Linters check code for common problems and provide hints on how to correct any detected issues.

Format tools suppor code to conforming to a specified coding style, typically these run when save-file is run.

null-ls provides extensive builtin configuration for programming languages and configuration formats. null-ls also passes lint and format tool information to the Neovim LSP client, extending the range of language support.

"},{"location":"introduction/features/#selection-narrowing","title":"Selection Narrowing","text":"

telescope.nvim is a highly extendable fuzzy finder over lists with community driven pickers, sorters and previewers.

Navigate and narrow lists of files, packages, environment variables, ports, colour schemes (themes) and any other list of items effectively.

Telescope File browser popup also explores the file system and in Normal mode can be used to create files and directories

The telescope list narrows matches as characters are typed

"},{"location":"introduction/features/#version-control","title":"Version Control","text":"

Gitsigns hightlights buffer changes in the gutter

Lualine shows number of Git changes in status line

Diffview to review all changes for any git revision

Neogit provides a rich git client to add, stash, commit, push & pull changes.

Octo provides a GitHub specific client to manage issues and pull requests, using GitHub CLI authentication.

LazyGit UI

"},{"location":"introduction/features/#file-browser","title":"File Browser","text":"

neo-tree provides a visual file system explorer that can also create and delete files and directories

"},{"location":"introduction/features/#todo-comments","title":"TODO Comments","text":"

Highlight tasks, fixes, notes and dragons comments, including icons in the gutter. Use Telescope to navigate TODO comments in the current project.

"},{"location":"introduction/features/#status-line","title":"Status Line","text":"

LSP feedback

"},{"location":"introduction/features/#markdown","title":"Markdown","text":""},{"location":"introduction/fennel/","title":"Fennel","text":"

Lua is the defacto language for Neovim plugin development and configuration.

Fennel can be used to write Neovim packages and configuration, using nfnl to generate the equivalent Lua code that Neovim runs.

Although Neovim fully supports Vimscript, Practicalli encourages Fennel or Lua, as Vimscript is a niche language with quite complex syntax.

"},{"location":"introduction/fennel/#overview","title":"Overview","text":"

Fennel is a programming language that brings together the speed, simplicity, and reach of Lua with the flexibility of a lisp syntax and macro system.

Anywhere you can run Lua code, you can run Fennel code.

Translate Lua to Fennel

See Fennel is an online antifennel tool to convert Lua to Fennel or Fennel to Lua.

practicalli/neovim-config-redux configuration provides helper functions to minimise the translation required.

"},{"location":"introduction/fennel/#fennel-packages","title":"Fennel Packages","text":"

The Conjure package which provides the Clojure REPL (and much more) is written in Fennel.

"},{"location":"introduction/fennel/#nfnl","title":"nfnl","text":"

nfnl generates Lua code from Fennel code. Neovim runs the generated Lua code.

nfnl loads only when working in directories containing a .nfnl.fnl configuration file, so has zero overhead when not working with fennel.

*.fnl files are automatically compiled to *.lua when changes are saved, showing any compilation errors to provide an effective feedback loop.

nfnl standard library

nfnl plugin example

"},{"location":"introduction/fennel/#development-tooling","title":"Development tooling","text":"

Neovim support

See Fennel is an online antifennel tool to convert between Lua and Fennel.

Guide to plugin development with fennel

Emacs support:

"},{"location":"introduction/fennel/#playing-games","title":"Playing Games","text":"

TIC-80 is a simulated computer environment to to write code, design art, compose music and retro style game games.

L\u00d6VE is a framework for making games with the Lua programming language, allows import from external resources and can use any resolution or memory resources required.

TIC-80 and L\u00d6VE provide cross-platform support across Windows, Mac and Linux systems. TIC-80 games can also be played in the browser.

"},{"location":"introduction/repl-workflow/","title":"REPL Driven Development","text":"

Always be REPL'ing

Coding without a REPL feels limiting. The REPL provides fast feedback from code as its crafted, testing assumptions and design choices every step of the journey to a solution - John Stevenson, Practical.li

Clojure is a powerful, fun and highly productive language for developing applications and services. The clear language design is supported by a powerful development environment known as the REPL (read, evaluate, print, loop). The REPL gives you instant feedback on what your code does and enables you to test either a single expression or run the whole application (including tests).

REPL driven development is the foundation of working with Clojure effectively

An effective Clojure workflow begins by running a REPL process. Clojure expressions are written and evaluated immediately to provide instant feedback. The REPL feedback helps test the assumptions that are driving the design choices.

Design decisions and valuable data from REPL experiments can be codified as specifications and unit tests

Practicalli REPL Reloaded Workflow

The principles of REPL driven development are implemented in practice using the Practicalli REPL Reloaded Workflow and supporting tooling. This workflow uses Portal to inspect all evaluation results and log events, hot-load libraries into the running REPL process and reloads namespaces to support major refactor changes.

"},{"location":"introduction/repl-workflow/#evaluating-source-code","title":"Evaluating source code","text":"

A REPL connected editor is the primary tool for evaluating Clojure code from source code files, displaying the results inline.

Source code is automatically evaluated in its respective namespace, removing the need to change namespaces in the REPL with (in-ns) or use fully qualified names to call functions.

Evaluate Clojure in Neovim with Conjure

, e b evaluates the code in the current buffer

Evaluate Clojure in a Terminal UI REPL

Entering expressions at the REPL prompt evaluates the expression immediately, returning the result directly underneath

"},{"location":"introduction/repl-workflow/#rich-comment-blocks-living-documentation","title":"Rich Comment blocks - living documentation","text":"

The (comment ,,,) function wraps code that is only run directly by the developer using a Clojure aware editor.

Expressions in rich comment blocks can represent how to use the functions that make up the namespace API. For example, starting/restarting the system, updating the database, etc. Expressions provide examples of calling functions with typical arguments and make a project more accessible and easier to work with.

Clojure Rich Comment to manage a service

(ns practicalli.gameboard.service)\n\n(defn app-server-start [port] ,,,)\n(defn app-server-start [] ,,,)\n(defn app-server-restart [] ,,,)\n\n(defn -main\n  \"Start the service using system components\"\n  [& options] ,,,)\n\n(comment\n  (-main)\n  (app-server-start 8888)\n  (app-server-stop)\n  (app-server-restart 8888)\n\n  (System/getenv \"PORT\")\n  (def environment (System/getenv))\n  (def system-properties (System/getProperties))\n  ) ; End of rich comment block\n

Rich comment blocks are very useful for rapidly iterating over different design decisions by including the same function but with different implementations. Hide clj-kondo linter warnings for redefined vars (def, defn) when using this approach.

;; Rich comment block with redefined vars ignored\n#_{:clj-kondo/ignore [:redefined-var]}\n(comment\n  (defn value-added-tax []\n    ;; algorithm design - first idea)\n\n  (defn value-added-tax []\n    ;; algorithm design - second idea)\n\n  ) ;; End of rich comment block\n

The \"Rich\" in the name is an honourary mention to Rich Hickey, the author and benevolent dictator of Clojure design.

"},{"location":"introduction/repl-workflow/#design-journal","title":"Design Journal","text":"

A journal of design decisions makes the code easier to understand and maintain. Code examples of design decisions and alternative design discussions are captured, reducing the time spent revisiting those discussions.

Journals simplify the developer on-boarding processes as the journey through design decisions are already documented.

A Design Journal is usually created in a separate namespace, although it may start as a rich comment at the bottom of a namespace.

A journal should cover the following aspects

The design journal can be used to create meaningful documentation for the project very easily and should prevent time spent on repeating the same conversations.

Example design journal

Design journal for TicTacToe game using Reagent, ClojureScript and Scalable Vector Graphics

"},{"location":"introduction/repl-workflow/#viewing-data-structures","title":"Viewing data structures","text":"

Pretty print shows the structure of results from function calls in a human-friendly form, making it easier for a developer to parse and more likely to notice incorrect results.

Tools to view and navigate code

"},{"location":"introduction/repl-workflow/#code-style-and-idiomatic-clojure","title":"Code Style and idiomatic Clojure","text":"

Clojure aware editors should automatically apply formatting that follows the Clojure Style guide.

Live linting with clj-kondo suggests common idioms and highlights a wide range of syntax errors as code is written, minimizing bugs and therefore speeding up the development process.

Clojure LSP is build on top of clj-kondo

Clojure LSP uses clj-kondo static analysis to provide a standard set of development tools (format, refactor, auto-complete, syntax highlighting, syntax & idiom warnings, code navigation, etc).

Clojure LSP can be used with any Clojure aware editor that provides an LSP client, e.g. Spacemacs, Doom Emacs, Neovim, VSCode.

Clojure Style Guide

The Clojure Style guide provides examples of common formatting approaches, although the development team should decide which of these to adopt. Emacs clojure-mode will automatically format code and so will Clojure LSP (via cljfmt). These tools are configurable and should be tailored to the teams standard.

"},{"location":"introduction/repl-workflow/#data-and-function-specifications","title":"Data and Function specifications","text":"

Clojure spec is used to define a contract on incoming and outgoing data, to ensure it is of the correct form.

As data structures are identified in REPL experiments, create data specification to validate the keys and value types of that data.

;; ---------------------------------------------------\n;; Address specifications\n(spec/def ::house-number string?)\n(spec/def ::street string?)\n(spec/def ::postal-code string?)\n(spec/def ::city string?)\n(spec/def ::country string?)\n(spec/def ::additional string?)\n\n(spec/def ::address   ; Composite data specification\n  (spec/keys\n   :req-un [::street ::postal-code ::city ::country]\n   :opt-un [::house-number ::additional]))\n;; ---------------------------------------------------\n

As the public API is designed, specifications for each functions arguments are added to validate the correct data is used when calling those functions.

Generative testing provides a far greater scope of test values used incorporated into unit tests. Data uses clojure.spec to randomly generate data for testing on each test run.

"},{"location":"introduction/repl-workflow/#test-driven-development-and-repl-driven-development","title":"Test Driven Development and REPL Driven Development","text":"

Test Driven Development (TDD) and REPL Driven Development (RDD) complement each other as they both encourage incremental changes and continuous feedback.

Test Driven Development fits well with Hammock Time, as good design comes from deep thought

Unit tests should support the public API of each namespace in a project to help prevent regressions in the code. Its far more efficient in terms of thinking time to define unit tests as the design starts to stabilize than as an after thought.

clojure.test library is part of the Clojure standard library that provides a simple way to start writing unit tests.

Clojure spec can also be used for generative testing, providing far greater scope in values used when running unit tests. Specifications can be defined for values and functions.

Clojure has a number of test runners available. Kaocha is a test runner that will run unit tests and function specification checks.

Automate local test runner

Use kaocha test runner in watch mode to run tests and specification check automatically (when changes are saved)

clojure -X:test/watch\n

"},{"location":"introduction/repl-workflow/#continuous-integration-and-deployment","title":"Continuous Integration and Deployment","text":"

Add a continuous integration service to run tests and builds code on every shared commit. Spin up testable review deployments when commits pushed to a pull request branch, before pushing commits to the main deployment branch, creating an effective pipeline to gain further feedback.

"},{"location":"introduction/repl-workflow/#live-coding-with-data-stuart-halloway","title":"Live Coding with Data - Stuart Halloway","text":"

There are few novel features of programming languages, but each combination has different properties. The combination of dynamic, hosted, functional and extended Lisp in Clojure gives developers the tools for making effective programs. The ways in which Clojure's unique combination of features can yield a highly effective development process.

Over more than a decade we have developed an effective approach to writing code in Clojure whose power comes from composing many of its key features. As different as Clojure programs are from e.g. Java programs, so to can and should be the development experience. You are not in Kansas anymore!

This talk presents a demonstration of the leverage you can get when writing programs in Clojure, with examples, based on my experiences as a core developer of Clojure and Datomic.

"},{"location":"introduction/writing-tips/","title":"Writing tips for MkDocs","text":"

Making the docs more engaging using the mkdocs-material theme reference guide

Configuring Colors

Material for MkDocs - Changing the colors lists the primary and accent colors available.

HSL Color Picker for codes to modify the theme style, overriding colors in docs/assets/stylesheets/extra.css

"},{"location":"introduction/writing-tips/#hypertext-links","title":"Hypertext links","text":"

Links open in the same browser window/tab by default.

Add {target=_blank} to the end of a link to configure opening in a new tab

[link text](url){target=_blank}\n
"},{"location":"introduction/writing-tips/#buttons","title":"Buttons","text":"

Convert any link into a button by adding {.md-button} class names to end of the markdown for a link, which uses .md-button-primary by default. Include target=_blank for buttons with links to external sites.

[link text](http://practical.li/blog){.md-button target=_blank}\n

Or specify a different class

[link text](http://practical.li/blog){.md-button .md-button-primary}\n

Add an icon to the button

Practicalli Issues Practicalli Blog

[:fontawesome-brands-github: Practicalli Issues](http://practical.li/blog){ .md-button .md-button-primary }\n[:octicons-heart-fill-24: Practicalli Blog](http://practical.li/blog){ .md-button .md-button-primary }\n

Search all supported icons

"},{"location":"introduction/writing-tips/#youtube-video","title":"YouTube video","text":"

Use an iframe element to include a YouTube video, wrapping in a paragraph tag with center alignment to place the video in a centered horizontal position

<p style=\"text-align:center\">\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/rQ802kSaip4\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n</p>\n

mkdocs material does not have direct support for adding a YouTube video via markdown.

"},{"location":"introduction/writing-tips/#admonitions","title":"Admonitions","text":"

Supported admonition types

Note

Use !!! followed by NOTE

Adding a title

Use !!! followed by NOTE and a \"title in double quotes\"

Shh, no title bar just the text... Use !!! followed by NOTE and a \"\" empty double quotes

Abstract

Use !!! followed by ABSTRACT

Info

Use !!! followed by INFO

Tip

Use !!! followed by TIP

Success

Use !!! followed by SUCCESS

Question

Use !!! followed by QUESTION

Warning

Use !!! followed by WARNING

Failure

Use !!! followed by FAILURE

Danger

Use !!! followed by DANGER

Bug

Use !!! followed by BUG

Example

Use !!! followed by EXAMPLE

Quote

Use !!! followed by QUOTE

"},{"location":"introduction/writing-tips/#collapsing-admonitions","title":"Collapsing admonitions","text":"Note

Collapse those admonitions using ??? instead of !!!

Replace with a title

Use ??? followed by NOTE and a \"title in double quotes\"

Expanded by default

Use ???+, note the + character, followed by NOTE and a \"title in double quotes\"

"},{"location":"introduction/writing-tips/#inline-blocks","title":"Inline blocks","text":"

Inline blocks of text to make a very specific callout within text

Info

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Adding something to then end of text is probably my favourite

Info

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

"},{"location":"introduction/writing-tips/#code-blocks","title":"Code blocks","text":"

Code blocks include a copy icon automatically

Syntax highlighting in code blocks

(defn my-function  ; Write a simple function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map inc [1 2 3]))\n

Give the code block a title using title=\"\" after the backtics and language name

src/practicalli/gameboard.clj
(defn my-function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map inc [1 2 3]))\n

We all like line numbers, especially when you can set the starting line

src/practicalli/gameboard.clj
(defn my-function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map inc [1 2 3]))\n

Add linenums=42 to start line numbers from 42 onward

clojure linenums=\"42\" title=\"src/practicalli/gameboard.clj\"\n
"},{"location":"introduction/writing-tips/#annotations","title":"Annotations","text":"

Annotations in a code block help to highlight important aspects. Use the comment character for the language followed by a space and a number in brackets

For example, in a shell code block, use # (1) where 1 is the number of the annotation

Use a number after the code block to add the text for the annotation, e.g. 1.. Ensure there is a space between the code block and the annotation text.

ls -la $HOME/Downloads  # (1)\n
  1. I'm a code annotation! I can contain code, formatted text, images, ... basically anything that can be written in Markdown.

Code blocks with annotation, add ! after the annotation number to suppress the # character

(defn helper-function\n  \"Doc-string with description of function purpose\" ; (1)!\n  [data]\n  (merge {:fish 1} data)\n  )\n
  1. Always include a doc-string in every function to describe the purpose of that function, identifying why it was added and what its value is.

GitHub action example with multiple annotations

name: ci # (1)!\non:\n  push:\n    branches:\n      - master # (2)!\n      - main\npermissions:\n  contents: write\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v4\n        with:\n          python-version: 3.x\n      - run: pip install mkdocs-material # (3)!\n      - run: mkdocs gh-deploy --force\n
  1. You can change the name to your liking.

  2. At some point, GitHub renamed master to main. If your default branch is named master, you can safely remove main, vice versa.

  3. This is the place to install further [MkDocs plugins] or Markdown extensions with pip to be used during the build:

    pip install \\\n  mkdocs-material \\\n  mkdocs-awesome-pages-plugin \\\n  ...\n
"},{"location":"introduction/writing-tips/#highlight-lines-in-code-blocks","title":"Highlight lines in code blocks","text":"

Add highlight line meta data to a code block after the opening backticks and code block language.

hl_lines=\"2\" highlights line 2 in the codeblock

hl_lines=\"2 3 4\" highlights line 2, 3 and 4 in the codeblock

(defn my-function\n  \"With a lovely doc-string\"\n  [arguments]\n  (map\n   inc\n   [1 2 3]))\n
"},{"location":"introduction/writing-tips/#embed-external-files","title":"Embed external files","text":"

--8<-- in a code block inserts code from a source code file or other text file

Specify a local file from the root of the book project (the directory containing mkdocs.yml)

Scheduled Version Check GitHub Workflow from source code file scheduled version check
---\n# ------------------------------------------\n# Scheduled check of versions\n# - use as non-urgent report on versions\n# - Uses POSIX Cron syntax\n#   - Minute [0,59]\n#   - Hour [0,23]\n#   - Day of the month [1,31]\n#   - Month of the year [1,12]\n#   - Day of the week ([0,6] with 0=Sunday)\n#\n# Using liquidz/anta to check:\n# - GitHub workflows\n# - deps.edn\n# ------------------------------------------\n\nname: \"Scheduled Version Check\"\non:\n  schedule:\n    # - cron: \"0 4 * * *\" # at 04:04:04 ever day\n    # - cron: \"0 4 * * 5\" # at 04:04:04 ever Friday\n    - cron: \"0 4 1 * *\" # at 04:04:04 on first day of month\n  workflow_dispatch: # Run manually via GitHub Actions Workflow page\n\njobs:\n  scheduled-version-check:\n    name: \"Scheduled Version Check\"\n    runs-on: ubuntu-latest\n    steps:\n      - run: echo \"\ud83d\ude80 Job automatically triggered by ${{ github.event_name }}\"\n      - run: echo \"\ud83d\udc27 Job running on ${{ runner.os }} server\"\n      - run: echo \"\ud83d\udc19 Using ${{ github.ref }} branch from ${{ github.repository }} repository\"\n\n      - name: \"Checkout code\"\n        uses: actions/checkout@v4\n      - run: echo \"\ud83d\udc19 ${{ github.repository }} repository was cloned to the runner.\"\n\n      - name: \"Antq Check versions\"\n        uses: liquidz/antq-action@main\n        with:\n          excludes: \"\"\n          skips: \"boot clojure-cli pom shadow-cljs leiningen\"\n\n      # Summary\n      - run: echo \"\ud83c\udfa8 library versions checked with liquidz/antq\"\n      - run: echo \"\ud83c\udf4f Job status is ${{ job.status }}.\"\n
Practicalli Project Templates Emacs project configuration - .dir-locals.el
((clojure-mode . ((cider-preferred-build-tool . clojure-cli)\n                  (cider-clojure-cli-aliases . \":test/env:dev/reloaded\"))))\n

Code example reuse

Use an embedded local or external file (URL) when the same content is required in more than one place in the book.

An effective way of sharing code and configuration mutliple times in a book or across multiple books.

"},{"location":"introduction/writing-tips/#content-tabs","title":"Content tabs","text":"

Create in page tabs that can also be

Setting up a project

Clojure CLILeiningen
clojure -T:project/new :template app :name practicalli/gameboard\n
lein new app practicalli/gameboard\n

Or nest the content tabs in an admonition

Run a terminal REPL

Clojure CLILeiningen
clojure -T:repl/rebel\n
lein repl\n
"},{"location":"introduction/writing-tips/#diagrams","title":"Diagrams","text":"

Neat flow diagrams

Diagrams - Material for MkDocs

graph LR\n  A[Start] --> B{Error?};\n  B -->|Yes| C[Hmm...];\n  C --> D[Debug];\n  D --> B;\n  B ---->|No| E[Yay!];

UML Sequence Diagrams

sequenceDiagram\n  Alice->>John: Hello John, how are you?\n  loop Healthcheck\n      John->>John: Fight against hypochondria\n  end\n  Note right of John: Rational thoughts!\n  John-->>Alice: Great!\n  John->>Bob: How about you?\n  Bob-->>John: Jolly good!

state transition diagrams

stateDiagram-v2\n  state fork_state <<fork>>\n    [*] --> fork_state\n    fork_state --> State2\n    fork_state --> State3\n\n    state join_state <<join>>\n    State2 --> join_state\n    State3 --> join_state\n    join_state --> State4\n    State4 --> [*]

Class diagrams - not needed for Clojure

Entity relationship diagrams are handy though

erDiagram\n  CUSTOMER ||--o{ ORDER : places\n  ORDER ||--|{ LINE-ITEM : contains\n  LINE-ITEM {\n    customer-name string\n    unit-price int\n  }\n  CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
"},{"location":"introduction/writing-tips/#keyboard-keys","title":"Keyboard keys","text":"

Represent key bindings with Keyboard keys. Each number and alphabet character has their own key.

Punctionation keys use their name

For key sequences, place a space between each keyboard character

For key combinations, use join they key identifies with a +

MkDocs keyboard keys reference

"},{"location":"introduction/writing-tips/#images","title":"Images","text":"

Markdown images can be appended with material tags to set the size of the image, whether to appear on light or dark theme and support lazy image loading in browsers

SizeLazy LoadingAlignTheme SpecificAll Image Attributes

{style=\"height:150px;width:150px\"} specifies the image size

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style=\"height:150px;width:150px\"}\n

{loading=lazy} specifies an image should lazily load in the browser

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png){loading=lazy}\n

{aligh=left} or {aligh=right} specifies the page alignment of an image.

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){align=right}\n![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){align=right}\n

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

![Kitty Logo](image/kitty-light.png#only-dark) or ![Kitty Logo](image/kitty-light.png#only-light) specifies the theme the image should be shown, allowing different versions of images to be shown based on the theme.

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style=\"height:150px;width:150px\"}\n![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){style=\"height:150px;width:150px\"}\n
Use the theme toggle in the top nav bar to see the icon change between light and dark.

Requires the color pallet toggle

Alight right, lazy load and set image to 150x150

![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){align=right loading=lazy style=\"height:64px;width:64px\"}\n![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){align=right loading=lazy style=\"height:64px;width:64px\"}\n

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

"},{"location":"introduction/writing-tips/#lists","title":"Lists","text":"

Task lists

Task List example

- [x] Lorem ipsum dolor sit amet, consectetur adipiscing elit\n- [ ] Vestibulum convallis sit amet nisi a tincidunt\n    * [x] In hac habitasse platea dictumst\n    * [x] In scelerisque nibh non dolor mollis congue sed et metus\n    * [ ] Praesent sed risus massa\n- [ ] Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque\n
"},{"location":"introduction/writing-tips/#tooltips","title":"Tooltips","text":"

The humble tool tip

Hover me

with references

Hover me

Icon tool tip with a title

"},{"location":"introduction/writing-tips/#abreviations","title":"Abreviations","text":"

The HTML specification is maintained by the W3C.

[HTML]: Hyper Text Markup Language [W3C]: World Wide Web Consortium

"},{"location":"introduction/writing-tips/#magic-links","title":"Magic links","text":"

MagicLink can auto-link HTML, FTP, and email links. It can auto-convert repository links (GitHub, GitLab, and Bitbucket) and display them in a more concise, shorthand format.

Email Practicalli

Practicalli Neovim

"},{"location":"neovim-basics/","title":"Using Neovim","text":"

The fundamental controls of Neovim which apply across all editing tasks.

"},{"location":"neovim-basics/#fundamentals","title":"Fundamentals","text":"

File Buffer Window and Tab page Multi-modal Editing

"},{"location":"neovim-basics/#editing-tools","title":"Editing Tools","text":"

Multiple Cursors

"},{"location":"neovim-basics/#writing-tools","title":"Writing Tools","text":"

Snippets

"},{"location":"neovim-basics/#development-tools","title":"Development Tools","text":"

Comments Clojure Development Version Control

Format and Lint tools are installed via Mason

"},{"location":"neovim-basics/#spellcheck","title":"Spellcheck","text":"AstroNvim

SPC u s toggles spellcheck, marking misspelt words with a rew wavy underline

] s jumps to next misspelt word, [ s jumps to previous misspelt word,

z = shows numbered list of possible words, enter the number next to the work to replace the misspelt word.

z g to add the current word to the spell list, infroming spellcheck that this is a correct word.

"},{"location":"neovim-basics/comments/","title":"Comments","text":"

comment.nvim toggles a comment for lines, visual selections or for motions

gcc comment current line, 4gcc comment current line and next 4 lines

gc comment region or use with motion e.g. gcap comment paragraph,

gc in operator pending mode to target a comment TODO: what is operator pending mode

:7,17Commentary comment a range

:g/TODO/Commentary as part of a :global invocation

gcgc removes comments from a set of adjacent commented lines.

"},{"location":"neovim-basics/file-buffer-window-tab/","title":"Files Buffers Windows and Tabs","text":"

Files are text written to perminant storage, e.g. disk or usb drive and are names with an extension that represents the file type, e.g. .clj for clojure, .md for markdown, etc.

A Buffer hold the contents of a file or any other information from processes, e.g. the REPL evaluation log.

Windows are a view on a buffer and windows can swap which buffer they show. Multiple windows, also known as splits, can be present in a Neovim frame.

A tab page (or tab) can hold one or more windows and multiple tab pages can be shown on a tab-line.

"},{"location":"neovim-basics/file-buffer-window-tab/#files","title":"Files","text":"

Use Neo-tree.nvim to visually navigate and manage files using a tree view of the current project. Files and directories can be added, renamed, moved and deleted.

Use Telescope to select files, typing a name narrows the file list.

"},{"location":"neovim-basics/file-buffer-window-tab/#using-neo-tree","title":"Using Neo-tree","text":"AstronvimPracticalli Neovim Config Redux

Space e toggles neo-tree file browser

Space o toggles between buffer and neo-tree

Space f t t to open file explorer

Within Neo-tree:

h j k l to navigate the file tree hierachy

< and > to navigate between File, Bufs and Git sources tabs

? shows neotree help, listing key bindings

a adds a file, prompting for a name relative to the directory where a was pressed. The name can include new directories to be created. A name ending with ++forward-slash++ will create a directory rather than a file.

d deletes the current file or directory (including sub-directories), a conformation prompt is shown

r to rename a file or directory (use move to change the path)

m to move a file or directory, optionally renaming too

Neotree icons

"},{"location":"neovim-basics/file-buffer-window-tab/#telescope","title":"Telescope","text":"

Telescope provides a selector which will narrow the list of matches as a pattern is typed, providing a fast way to find an item in a list.

Telescope provides a preview of the selected file (only if there is sufficient space in the Neovim frame)

File lists are relative to the directory Neovim was opened from (or Path subsequently set in Neovim).

AstroNvimPracticalli Neovim Config Redux

SPC f f selector for files within the scope of the current directory path. SPC f F to also show hidden files from the current directory path.

SPC f a selector for AstroNvim user configuration files

SPC f p selector for previously opened files (oldfiles)

SPC f f to list files within the scope of the current directory path.

SPC f b provides a file browser to open files, navigate the file space and create new files and directories

"},{"location":"neovim-basics/file-buffer-window-tab/#save-file","title":"Save File","text":"

Files and directories are created in the path given, relative to the directory in which Neovim was opened.

A file must exist for Neovim to write to it. Neo-tree and Telescope can be used to create files and directories, as can a terminal and the command line integration (!)

AstronvimPracticalli Neovim Config ReduxNeovim

Space w will write all buffer changes to the associate file.

Space n creates a new buffer that can be written to a given file using :write path/to/filename

:write path/to/filename will write the current buffer to a new file.

SPC f b ESC C to create a new file or directory. The base path is shown in the command bar. Type the name of directories and file name as required. RTN to create or ESC to cancel. The newly created directories or file name appears n the Telescope list and scan be selected for opening.

Telescope Normal mode and help

ESC in Telescope to switch to Normal mode and use comannds, c for Create, r to rename.

? to show all the commands available in Telescope

:lcd to set the current local directory

:write path/to/filename will write the current buffer to a new file

:!mkdir path/to/directory will create a new directory

If a file is already opened, i.e. with :edit, there is some short-hand syntax to simplify the typing

:!mkdir -p %:h

-p option createst any parts of the path required to make the full path

% is the neovim name of the current file

:h for the current directory (the \u201chead\u201d of the path).

! is the NeoVim terminal shell command, e.g. :!mkdir -p path/to/new/directory creates a new directory and any intermediate path

"},{"location":"neovim-basics/file-buffer-window-tab/#swap-file","title":"Swap file","text":"

Neovim creates a swap file, .swp, containing the changes made in a buffer to minimise loss should there be an issue with the computer or Neovim. Changes are written to the swap file after 200 characters or after 4 seconds pause.

Swap file location

:swapname shows the full path to the swap file for the current buffer, e.g.

/home/practicalli/.local/state/astronvim/swap//%home%practicalli%projects%practicalli%books%neovim%docs%neovim-basics%files-buffers-windows.md.swp`\n

:preserve command will write all text from current buffer to the swap file.

:recover command overwrites the current buffer with the data from the swap file. :recover! command must be use if the buffer has newer changes than the swap file. Add a filename after the command to recover to a different file than that contained in the current buffer.

Opening a file checks if there is an associated swap file and prompts the user

:edit after the file is open also prompts if there is a swap file. Selecting (D)elete will delete the swap file without changing the current buffer

"},{"location":"neovim-basics/file-buffer-window-tab/#buffers","title":"Buffers","text":"AstroNvimPracticalli Neovim Config Redux

SPC f b selector for currently open buffers

SPC b b to select a buffer from the tab line, pressing the character that appears next to the buffer tab (case sensitive)

SPC b D to delete a buffer from the tab line, pressing the character that appears next to the buffer tab (case sensitive)

Open multiple buffers when starting Neovim by specifying multiple files to open

astro README.md deps.edn src/practicalli/playground.clj test/practicalli/playground.clj\n

SPC b b switch between buffers in the current window, using a Telescope popup that lists all current buffers (includes files, Conjure REPL Log, etc.).

SPC b n (:next) and SPC b n (:previous) to cycle through buffers in the current window

SPC TAB (C-^) opens the previous buffer, useful to toggle between two buffers in the same window

Use Telescope to switch between buffers

Open multiple buffers when starting Neovim by specifying multiple files to open

nvim README.md deps.edn src/practicalli/playground.clj test/practicalli/playground.clj\n
"},{"location":"neovim-basics/file-buffer-window-tab/#buffer-text-wrapping","title":"Buffer text wrapping","text":"

The test in a buffer is not wrapped by default. Set and unset soft text wrapping in a buffer

AstroNvimPracticalli Neovim Config ReduxNeovim

SPC u w toggles wrapping of text

line wrap not enabled in configuration by default.

fnl/config/init.fnl
(nvim.ex.set :nowrap)\n

:set wrap to set soft wrapping on current buffer

:set nowrap to show lines in full (scroll sideways to see lines longer than the window)

"},{"location":"neovim-basics/file-buffer-window-tab/#windows","title":"Windows","text":"

Windows can be active (contains the cursor), hidden (open but not shown) or inactive.

AstroNvimPracticalli Neovim Config ReduxNeovim

\\ creates an horizontal split

SPC q removes the current split

SPC h / SPC l to jump to left / right buffer, SPC j / SPC k to jump to buffer below / above

SPC b b to list current buffers and switch between them using telescope

C-w and hjkl to navigate windows is the classic Vim approach

C-w menu to manage Windows, also known as splits.

C-w with one of hjkl will move the cursor to the next window in that direction. Also works with arrow keys.

C-w w toggle between open windows

:q or C-w q closes the active window, closing Neovim if it is the last active window.

:wincmd can be used as an alternative to the Normal mode key bindings

Open file in a new window

:sp relative-or-full-filename-path\n

Resize windows

C-w -, +, < or > for vertical or horizontal size adjustment

"},{"location":"neovim-basics/file-buffer-window-tab/#tab-pages","title":"Tab pages","text":"

A Tab page can hold one or more tabs and are useful for grouping different types of files and information.

A Tab page holds one or more windows, each window is a view on a buffer, a buffer holds the contents of a file or any other information in the editor memory (repl log, etc).

A tab page can provide a logical grouping of windows, e.g. Clojure source code in one tab, tests in a second tab and REPL log in a third.

Neovim window commands may be constrained within the bounds of a tab page (without using the :tab modifier)

Tab pages are often referred to as tabs.

AstroNvim

g Tab jump to previously selected tab, commonly used to toggle between two tabs (Practicalli AstroNvim mapping)

g t jump to next tab page

g T jump to previous tab page

"},{"location":"neovim-basics/multi-modal-editing/","title":"Multi-modal Editing","text":"

TODO: Add multi-modal editing in Neovim guide

Practicalli Spacemacs has useful reference content on multi-modal editing (Evil mode).

Most of this content is the same in Neovim with a few exceptions

"},{"location":"neovim-basics/multi-modal-editing/#selecting-text","title":"Selecting text","text":"

vi) selects all the text within (), e.g. (http://oldwebsite.doh)

"},{"location":"neovim-basics/multi-modal-editing/#surround","title":"Surround","text":"

viw selects the current word, using j/k to modify the selection where required. o toggles which end of the selection is expanded/shrunk

s substitues the selection, type the characters to surround the selection.

p to pase the original text

"},{"location":"neovim-basics/multi-modal-editing/#nvim-surround","title":"nvim-surround","text":"

nvim-surround provides enhancments over the neovim surround command.

nvim-surround included in Practicalli AstroNvim Config

"},{"location":"neovim-basics/multi-modal-editing/#visual-mode","title":"Visual Mode","text":"

viw to select the current word (visual in word)

S on a visual selection to surround with next that character, e.g. S) to surround with parens.

Closing paren surrounds without spaces

), ], } surrounds the selected text without spaces between the text and the open and closing parens.

(, [, { surrounds the selected text with a space between the text and the open and closing parens.

"},{"location":"neovim-basics/multi-modal-editing/#normal-mode","title":"Normal mode","text":"

cs inside an existing pair of characters to change them to another pair of surrounding characters, e.g. cs(} to change (text) to {text}

ds inside a pair of surrounding characters to delete them, e.g. ds( to change (text) to text

ys you surround followed by motion and character, e.g. ysw) surrounds word with (parens)

yS to surround current line

ySS to surround current line, placing characters on new lines, e.g. ySS{ will change \"Olical/conjure\" to:

{\n    \"Olical/conjure\"\n}\n

The three \"core\" operations of add/delete/change can be done with the keymaps ys{motion}{char}, ds{char}, and cs{target}{replacement}, respectively. For the following examples, * will denote the cursor position:

Old text                    Command         New text\n----------------------------------------------------\nsurr*ound_words             ysiw)           (surround_words)\n*make strings               ys$\"            \"make strings\"\n[delete ar*ound me!]        ds]             delete around me!\nremove <b>HTML t*ags</b>    dst             remove HTML tags\n'change quot*es'            cs'\"            \"change quotes\"\n<b>or tag* types</b>        csth1<CR>       <h1>or tag types</h1>\ndelete(functi*on calls)     dsf             function calls\n

Neovim help provides details on using nvim-surround

:help nvim-surround.usage\n
"},{"location":"neovim-basics/multi-modal-editing/#web-links","title":"Web Links","text":"

g x on a URL to open in the default browser

"},{"location":"neovim-basics/multiple-cursors/","title":"Multiple cursors","text":"

Visual-Multi (VM) is a multiple selections/cursors plugin that uses modal editing and provide visual feedback when editing multiple lines simultaneously.

Mulitple cursors is generally useful when editing smilarly structured lines with diffferent content. Cursors are moved by column position or by using vim motions.

AstroNvimPracticalli Neovim Config Redux

Space g m opens the visual-multi menu

Using visual select is a simple way to edit multiple lines as the same time.

Space g m c on visually selected lines creates a cursor on each line.

Esc or f d to close multiple cursors.

\\ \\ c creates a cursor at the start of every visual selection line

\\ \\ \\ toggle cursor at position

"},{"location":"neovim-basics/multiple-cursors/#search-and-replace","title":"Search and Replace","text":"

Select a text pattern to search for and use multiple cursors to add a cursor each match, then change each selected occurance concurrently.

AstroNvimPracticalli Neovim Config Redux

Select the pattern with visual select

Space g m a on each matching text pattern in the buffer

c to change the original text and type the new pattern. All cursors will update concurrently.

Esc or f d to close multiple cursors.

\\ \\ a creates a cursor at the start of every visual selection line

\\ \\ \\ toggle cursor at position

c to change the original text and type the new pattern. All cursors will update concurrently.

Esc or f d to close multiple cursors.

"},{"location":"neovim-basics/multiple-cursors/#command-quick-reference","title":"Command quick reference","text":"

:help g:VM_maps for a reference of all mappings and instructions on how to change them

AstroNvim

SPC g m opens the Visual-Multi menu in normal mode

g m opens the Visual-Multi menu in visual mode

c to add a cursor to every line in the visually selected region

Practicalli Neovim Config Redux

\\ \\ is the leader for multiple cursors and will show the visual-multi menu in which-key.

These commands cover the large majority of use cases for multiple cursors.

Action Key Command Add Cursor at Position \\\\\\ vm-add-cursor Alignm VM cursors with cursor \\\\a vm-align Select All Words \\\\A vm-select-all Transposition \\\\t vm-transpose Toggle Mappings \\\\<Space> vm-mappings-toggle Find with Regex \\\\/ vm-regex-search Reselect Last \\\\gS vm-reselect-last

Once visual-multi has started the vm-mappings-buffer mappings are available:

Action Key Command Find Word <C-n> vm-find-word Next/Previous/Skip n / N / q vm-find-next Remove Region Q vm-remove-region Add Cursors Down/Up <C-Down> / <C-Up> vm-add-cursors Select Right/Left <S-Right>, <S-Left> vm-shift-select Slash motion g/ vm-slash Select Operator s vm-select-operator Find Operator m vm-find-operator

NOTE: C-n conflicts with the Termux binding for naming a session

"},{"location":"neovim-basics/multiple-cursors/#searching","title":"Searching","text":"

g/ to search for a match to add when visual-multi is active, rather than the usual / vim search.

n and N can't be used to repeat the search, as they are used to get the next visual-multi match.

"},{"location":"neovim-basics/multiple-cursors/#find-with-regex","title":"Find with Regex","text":"

\\ \\ / followed by a regex pattern will create a selection with that pattern.

n and N finds the next occurrence of the regex pattern

"},{"location":"neovim-basics/multiple-cursors/#smart-case-change","title":"Smart case change","text":"

gc In extend-mode will use smartcase to change a selection

"},{"location":"neovim-basics/multiple-cursors/#filter-regions","title":"Filter regions","text":"

\\ \\ f filter out (remove) regions based on pattern or expression.

C-x to cycle filtering method:

"},{"location":"neovim-basics/multiple-cursors/#transform-regions-with-expression","title":"Transform regions with expression","text":"

\\ \\ e to transform a region with a vim expression, run on each region

Placeholders can be used in the expression

Examples: - %f * 0.5 divide text of all regions by 2 - %t .\" \". %i .\" / \". %n append index / total to text of each region - %i%2 ? %t : toupper(%t) uppercase all odd regions (1,3,5...) - %i%3-2 ? %t : '' delete every third region

"},{"location":"neovim-basics/multiple-cursors/#vm-motions","title":"VM Motions","text":"

visual-multi supports vim motions although they behave differently as their result is dependent on the mode:

Unless multiline-mode is enabled motions are restricted to the current line and cannot cross line boundaries

Some object-motions and various-motions require multiline-mode and aliased to avoid conflict with VM mappings:

vim VM~ Description / g/ to next match (for all regions) ( ( [count] sentences backward ) ) [count] sentences forward { { [count] paragraphs backward } } [count] paragraphs forward [( g( go to [count] previous unmatched '(' [{ g{ go to [count] previous unmatched '{' ]) g) go to [count] next unmatched ')' ]} g} go to [count] next unmatched '}'"},{"location":"neovim-basics/multiple-cursors/#vm-operators","title":"vm-operators","text":"

Visual-Multi supports several operators by default:

Visual-Multi uses its own registers that are lists of strings. One element for each region that is yanked/deleted.

There is also built-in support for:

`:help g:VM_user_operators to disccover how to doefine other operators

"},{"location":"neovim-basics/multiple-cursors/#vm-multiline-mode","title":"vm-multiline-mode","text":"

In normal and insert mode, cursors and selections are kept within their own line. Cursors are blocked from moving off the current line to the next line.

M enables multiline-mode that allows cuursors to move onto another line.

Multiline mode must be enabled for an object motions, or they will fail. See |vm-motions|.

"},{"location":"neovim-basics/multiple-cursors/#alignment","title":"Alignment","text":"

\\\\a aligns by setting the minimum column to the highest of all regions \\\\< aligns by character, or [count] characters \\\\> aligns by regex pattern

In extend-mode selections are collapsed to cursors first, although will work regardless.

"},{"location":"neovim-basics/multiple-cursors/#replace-pattern-in-regions","title":"Replace pattern in regions","text":"

R to replace with a pattern and then the replacement text

substitution will take place in all selected regions, leaving unselected text untouched.

Only working in |extend-mode|. When |R| is pressed in |cursor-mode|, it will start |vm-replace-mode| instead.

"},{"location":"neovim-basics/multiple-cursors/#subtract-pattern-from-regions","title":"Subtract pattern from regions","text":"

\\\\s subtract the entered pattern from regions, splitting them. Only working in |extend-mode|.

"},{"location":"neovim-basics/multiple-cursors/#transposition","title":"Transposition","text":"

\\ \\ t swaps the contents of selections, cycling them if there are more than two.

If there is an equal number of selections in each line, swapping takes place within the same line only. Only in |extend-mode|.

"},{"location":"neovim-basics/multiple-cursors/#duplication","title":"Duplication","text":"

\\ \\ d duplicates in place the contents of the selections, reselecting the original ones. Only in extend-mode.

"},{"location":"neovim-basics/multiple-cursors/#shift-selections","title":"Shift Selections","text":"

and move the selections right or left, preserving the surroundings."},{"location":"neovim-basics/multiple-cursors/#case-conversion","title":"Case conversion","text":"

\\\\C runs on inner words in cursor mode

"},{"location":"neovim-basics/multiple-cursors/#modes","title":"Modes","text":"

cursor-mode and extend-mode are two Visual-Multi modes, roughly corresponding to normal-mode and visual-mode

TAB switches between cursor-mode and extended-mode

"},{"location":"neovim-basics/multiple-cursors/#vm-cursor-mode","title":"VM Cursor Mode","text":"

cursor-mode commands expect a motion, e.g. c should be followed by a text object to be changed.

Key Description operators see vm-operators motions see vm-motions | set column for all cursors (to current column or [count]) r replace single character R enter vm-replace-mode ~ change case of single character & repeat last substitution <C-A> increase numbers <C-X> decrease numbers g<C-A> progressively increase numbers (v_g_CTRL-A) g<C-X> progressively decrease numbers (v_g_CTRL-X)

You can enter |insert-mode| with i, I, a, A, and only from cursor mode also with o and O.

Also see vm-motions for supported motions in VM (some with differences).

"},{"location":"neovim-basics/multiple-cursors/#vm-extend-mode","title":"VM Extend Mode","text":"

extend-mode is like having multiple visual selections. motions extend the slections and change / yank / delete commands don't wait for a motion, just like in visual mode.

Even the key o works as in visual mode, inverting the anchor of the selections.

Some commands are specific to |extend-mode|, such as:

Some commands enforce cursor-mode when run from extend-mode:

Others can use a different mapping:

"},{"location":"neovim-basics/notifications/","title":"Notifications","text":"Notifications only in AstroNvim, not the Practicalli Neovim configuration

Space f n lists the history of notifications for the current sesion

Enter to open the highlighted item in the list in its own popup

Notification popups show information, warnings and errors.

"},{"location":"neovim-basics/notifications/#configure-notifications","title":"Configure notifications","text":"

Notifications are controlled by nvim-notify

Practicalli astronvim-config overrides several default values in plugins/core.lua

Practicalli Configuration for notifications

plugins/core.lua
  -- Configure notify popups\n  {\n    \"rcarriga/nvim-notify\",\n    opts = {\n      top_down = false,\n      timeout = 1000,\n      -- log level - 3 hide file write messages - default 5\n      level = 3,\n      -- background_color = \"#000000\",\n    },\n  },\n

Noice uses nvim-notify configuration

Noice replaces the UI for messages, command line and popup menus, although uses the configuration of nvim-notify for position and popup timing.

"},{"location":"neovim-basics/plugin-manager/","title":"Plugin Manager","text":"

Neovim community provides a wide range of plugins to greatly extend the features of Neovim

There is a wide range of plugin managers too, including a built-in plugin manager in Neovim.

Lazy plugin manager recommeded

Practicalli recommends Lazy plugin manager as it feels much easier to use and has a more engaing and understandable user interface

Neovim evolving

Neovim and its plugins are evolving quite rapidly, so it is recommended to update plugins if there are issue or when a newer version of Neovim has been installed

Plugin issue are not that common and typically fixed quite quickly by the community

AstroNvimPracticalli Neovim Config Redux

Lazy plugin manager

SPC P u to update packages to their latest versions (:PackerUpdate). Details of updated changes will be shown at the end of the update.

r in the package update screen gives the option to revert an update if something has gone wrong (although this seem to be a rare issue).

When packages are all at the latest available version, Packer update reports packages already up to date.

Packer downloads packages and documentation from the Internet, so a connection is required

"},{"location":"neovim-basics/plugin-manager/#package-list-and-documentation","title":"Package List and documentation","text":"AstroNvimPracticalli Neovim Config Redux

Lazy plugin manager

SPC P l to list the current packages added to the configuration

Selecting a package will display the website documentation for the package (although this may be in HTML so not the cleanest way to read the docs).

"},{"location":"neovim-basics/plugin-manager/#adding-packages","title":"Adding packages","text":"AstroNvimPracticalli Neovim Config Redux

Lazy plugin manager

Add package names as keywords in the use expression in fnl/config/plugin.fnl file.

:requires to add a package that is a dependency for the package being added

:mod defines the namespace that contains the package configuration, typically a setup function with options. The namespace matches the file name under fnl/config/plugin

SPC P i to install packages that have been added to fnl/config/plugin.fnl

q to quit once all packages are up to date

"},{"location":"neovim-basics/search-replace/","title":"Search and Replace","text":"

:substitute or :s vim command will highlight the matches for a text pattern and substitute for a new pattern

Built-in help for the command

:help :substitute\n
Multiple cursors can also be used for multiple substitutions

multiple cursors created on each occurance can be used to search and replace a pattern

Subsitute the first matching patterns in the current line

:s/current-pattern/new-pattern\n

Subsitute all the matching patterns in the current line, g representing all occurances in a line

:s/current-pattern/new-pattern/g\n

Use % to specify the current buffer as the scope to change all matches

:%s/current-pattern/new-pattern/g\n
"},{"location":"neovim-basics/snippets/","title":"Snippets","text":"

LuaSnip can use several different sources for snippets

LuaSnip Configuration

Practicalli Neovim Config Redux includes the LuaSnip package which also adds friendly-snippets and cmp_luasnip.

  ; snippets\n  :L3MON4D3/LuaSnip \n  {:requires [:rafamadriz/friendly-snippets\n              :saadparwaiz1/cmp_luasnip]\n   :mod :lua-snip}\n
Configure LSP snippet locations
{\n  \"name\": \"practicalli-snippets\",\n  \"engines\": {\n    \"vscode\": \"^1.11.0\"\n  },\n  \"contributes\": {\n    \"snippets\": [\n      {\n        \"language\": [\n          \"markdown\",\n          \"global\",\n          \"all\"\n        ],\n        \"comment\": \"snippets accross several languages\",\n        \"path\": \"./global.json\"\n      },\n      {\n        \"language\": \n          \"markdown\",\n        \"path\": \"./markdown.json\"\n      }\n    ]\n  }\n}\n

"},{"location":"neovim-basics/snippets/#snippet-definitions","title":"Snippet Definitions","text":"

snippets directory contains snippet definitions, with a JSON file for each language, e.g. markdown.json

Practicalli Neovim Config Redux contains several groups of snippet definitions

Restart Neovim to load new defintions

Snippets added to VSCode JSON snippets are only loaded when Neovim starts, so newly added snippets will only be available after Neovim is restarted.

"},{"location":"neovim-basics/terminal/","title":"Terminal","text":"

akinsho/toggleterm.nvim plugin provides a terminal session within Neovim, using a float, split or tab.

AstroNvim

SPC t for the Terminal sub-menu

SPC t f opens a terminal in a floating window, useful for one-off commands

SPC t h opens a terminal in a horizontal split, useful for a process that prints valuable feedback, e.g. a test runner in watch mode

SPC t t opens a terminal in a tab, useful for background processes that do not need attendtion

"},{"location":"neovim-basics/zen-mode/","title":"Focus Modes","text":"

Focus on the code or text being created, without distractions

zZ toggles Zen mode

SPC z a ataraxis focus mode

SPC z f focus current buffer

SPC z n narrow to current buffer

SPC z n remove status bar and window decorations

v SPC z n narrow to selection

"},{"location":"neovim-basics/zen-mode/#zen-mode","title":"Zen Mode","text":"

Zen Mode distraction-free coding for Neovim

Available via the Astrocommunity repository.

Zen Mode configuration for AstroNvim

.config/astronvim-config/plugins/community.lua
  { import = \"astrocommunity.editing-support.zen-mode-nvim\" },\n  {\n    \"folke/zen-mode.nvim\",\n    opts = {\n      -- override default configuration\n      -- https://github.com/folke/zen-mode.nvim#%EF%B8%8F-configuration\n      plugins = {\n        options = {\n          enabled = true,\n        },\n        kitty = {\n          enabled = true,\n          font = \"+4\", -- font size increment\n        },\n      },\n    },\n  },\n

kitty configuration enables Zen Mode to resize kitty fonts.

"},{"location":"neovim-basics/zen-mode/#true-zen","title":"True Zen","text":"

true-zen.nvim clean and elegant distraction-free writing for NeoVim

True Zen Mode configuration for AstroNvim

  {\n    \"Pocco81/true-zen.nvim\",\n    lazy = false,\n    opts = {\n      integrations = {\n        kitty = {\n          -- increment font size in Kitty.\n          enabled = true,\n          font = \"+4\",\n        },\n      },\n    },\n  },\n

See kitty configuration to enable Zen Mode to resize kitty fonts.

"},{"location":"neovim-basics/zen-mode/#kitty-configuration","title":"Kitty configuration","text":"

Add allow_remote_control socket-only and listen_on unix:/tmp/kitty to the kitty config

Kitty support for Zen Mode

.config/kitty/kitty.config
# ---------------------------------------------------------\n#  Neovim zen-mode-nvim\n#  - change the font size on kitty when in zen mode\nallow_remote_control socket-only\nlisten_on unix:/tmp/kitty\n# ---------------------------------------------------------\n
"},{"location":"reference/lua-language/","title":"Lua","text":"

Lua is the default language for Neovim configuration.

"},{"location":"reference/lua-language/#learning-lua","title":"Learning Lua","text":"

Neovim Lua introduction

Lua.org - Programming in Lua (first edition)

Codecademy - learn lua course

"},{"location":"reference/lua-language/#reference","title":"Reference","text":"

Lua.org 5.4 Reference Manual

"},{"location":"reference/neovim/","title":"Neovim Reference","text":""},{"location":"reference/neovim/language-providers/","title":"Language Providers","text":"

Neovim delegates some features to language providers.

:checkhealth command in Neovim shows if the binaries and tools required by each provider are available in the operating system.

Resolve the issue with providers that generate a warning in the checkhealth report, following the ADVICE steps provided.

"},{"location":"reference/neovim/language-providers/#disable-language-providers","title":"Disable Language Providers","text":"

If a language is not used with Neovim, then its provider can be disabled. Details on how to disable a provider are included at the end of the ADVICE in the report section for that provider.

Disable language providers in the init.lua configuration file

init.lua
-- Disable Language providers\nvim.g.loaded_node_provider = 0       --- (1)!\nvim.g.loaded_perl_provider = 0\nvim.g.loaded_python3_provider = 0\nvim.g.loaded_ruby_provider = 0\n
  1. Example configuration to disable providers is provided in the practicalli/neovim-config-redux configuration

Ignore Language Provider warnings

If the programming language is not used, there are no issues with using Neovim if the warnings are simply ignored

"},{"location":"reference/neovim/standard-path/","title":"Neovim Standard Path","text":"

View the standard paths used by Neovim using the help menu

:help standard-path\n

Output of command

Standard Paths                  *standard-path*\n\nNvim stores configuration, data, and logs in standard locations. Plugins are\nstrongly encouraged to follow this pattern also. Use |stdpath()| to get the\npaths.\n\n                        *base-directories* *xdg*\nThe \"base\" (root) directories conform to the XDG Base Directory Specification.\nhttps://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\nThe $XDG_CONFIG_HOME, $XDG_DATA_HOME, $XDG_RUNTIME_DIR, and $XDG_STATE_HOME\nenvironment variables are used if defined, else default values (listed below)\nare used.\n\nCONFIG DIRECTORY (DEFAULT) ~\n                  *$XDG_CONFIG_HOME*            Nvim: stdpath(\"config\")\n    Unix:         ~/.config                   ~/.config/nvim\n    Windows:      ~/AppData/Local             ~/AppData/Local/nvim\n\nDATA DIRECTORY (DEFAULT) ~\n                  *$XDG_DATA_HOME*              Nvim: stdpath(\"data\")\n    Unix:         ~/.local/share              ~/.local/share/nvim\n    Windows:      ~/AppData/Local             ~/AppData/Local/nvim-data\n\nRUN DIRECTORY (DEFAULT) ~\n                  *$XDG_RUNTIME_DIR*            Nvim: stdpath(\"run\")\n    Unix:         /tmp/nvim.user/xxx          /tmp/nvim.user/xxx\n    Windows:      $TMP/nvim.user/xxx          $TMP/nvim.user/xxx\n\nSTATE DIRECTORY (DEFAULT) ~\n                  *$XDG_STATE_HOME*             Nvim: stdpath(\"state\")\n    Unix:         ~/.local/state              ~/.local/state/nvim\n    Windows:      ~/AppData/Local             ~/AppData/Local/nvim-data\n\nNote: Throughout the user manual these defaults are used as placeholders, e.g.\n\"~/.config\" is understood to mean \"$XDG_CONFIG_HOME or ~/.config\".\n\nLOG FILE                    *$NVIM_LOG_FILE* *E5430*\nBesides 'debug' and 'verbose', Nvim keeps a general log file for internal\ndebugging, plugins and RPC clients. >\n    :echo $NVIM_LOG_FILE\nBy default, the file is located at stdpath('log')/log unless that path\nis inaccessible or if $NVIM_LOG_FILE was set before |startup|.\n
"},{"location":"reference/vim-style/","title":"Reference: Learn Vim-style Editing","text":"

Learning vim-style multi-modal editing takes time and practice. Most importantly this approach can be learned in stages, as insert mode is the same editing experience as using most other editors.

Start with the multi-modal concept and the basics of navigation. Then adopt more normal and visual mode actions, including motions

"},{"location":"reference/vim-style/#getting-started","title":"Getting started","text":"

:Tutor runs the intteractive tutorial built into neovim (:help tutor also runs the tutor)

vim adventures isa simple online game to teach you the fundamentals of vim-style editing.

"},{"location":"reference/vim-style/#navigation-and-searching","title":"Navigation and searching","text":""},{"location":"reference/vim-style/#text-wrangling","title":"Text wrangling","text":""},{"location":"reference/vim-style/#clojure-editing","title":"Clojure Editing","text":"

traversing expressions structural editing

"},{"location":"reference/vim-style/case/","title":"Modifying text case","text":"

Convert Characters and regioins to upper or lower case text.

"},{"location":"reference/vim-style/case/#toggle-case-with-visual-select","title":"Toggle case with visual select","text":"

v to visually select a character or use the vim motion keys to select a region

U to uppercase current character or selected region

u to lowercase current character or selected region

~ to toggle the case of the text in the selected region

. will repeat the previous selection size and case toggle

"},{"location":"reference/vim-style/case/#toggle-case-menu","title":"Toggle case menu","text":"

Toggle the current character using vim motion keys, without needing to select a region.

g ~ opens the toggle case menu

TODO: Add screenshot of g ~ toggle case menu

g ~ ~ uppercase current line (also works for RET and maybe other none-menu characters, but not SPC)

"},{"location":"reference/vim-style/case/#cheatsheet","title":"Cheatsheet","text":""},{"location":"reference/vim-style/g-menu/","title":"Evil G menu","text":"

g` in normal mode opens a menu of convenient utilities. Practicalli uses this menu to comment existing lines, jumping to top or bottom of the buffer and changing text case.

"},{"location":"reference/vim-style/g-menu/#comment-lines-and-regions","title":"Comment lines and regions","text":"

g c c will comment the current line using the buffer major mode comment character(s). A prompt will ask if no comment character is set for the major mode.

g c with a selected region will comment all lines with the major mode comment character(s)

"},{"location":"reference/vim-style/g-menu/#jumping-around","title":"Jumping around","text":"

g g jumps to the top of the buffer, g G to the bottom of the buffer

g d to jump to the source code of a function definition, g D to open that in a different window.

g f to jump to file name under cursor (if file exists).

"},{"location":"reference/vim-style/g-menu/#changing-text-case","title":"Changing text case","text":"

g u to change the current character or selection to lowercase, g U for uppercase.

Toggle case with ~

~ will toggle the case of the current character or selected region.

"},{"location":"reference/vim-style/key-binding-reference/","title":"Evil Keybinding Reference","text":"

An alphabetically ordered reference of Vim-style key bindings.

"},{"location":"reference/vim-style/key-binding-reference/#normal-mode-keybindings","title":"Normal mode keybindings","text":"

Keybindings available in Evil normal mode and the resultant state they leave you in.

Keybinding Description State @ execute keyboard macro (defined by q) Normal ' jump to mark (defined by m) Normal a append text after cursor Insert a append text after cursor Insert A append text to end of sentence Insert b move cursor back to start of previous word Normal B move cursor back to start of last word Normal c change (use with modifier) Insert C change rest of sentence Insert d delete (use with modifier) Normal D delete rest of sentence Normal e end of word Normal E end of word (seems same as above) Normal f find character forward (type character) Normal F find character backward (type character) Normal fd Escape (press almost together) Normal g go menu Normal G Jump to end of buffer Normal h move cursor left Normal H move cursor to top of buffer Normal i insert text Insert I insert text at start of sentence Insert j Move cursor down a line Normal J Join next line to end of current Normal k Move cursor up a line Normal K spacemacs/evil-smart-doc-lookup Normal l Move cursor right Normal L Move cursor to bottom of buffer Normal m Create marker (next character is marker name) Normal M Jump to middle of buffer Normal n Next search occurrence Normal N Previous search occurrence Normal o New line below Insert O New line above Insert p Paste (after / below cursor) Insert P Paste (before / above cursor) Insert q Record keyboard macro attached to given character Normal Q undefined Normal r Replace character under cursor Normal R Replace character state Replace s Substitute character Insert S Substitute current line Insert t Find character forward - cursor before character Normal T Find character backward - cursor after character Normal u Undo last change (C-R to redo) Normal U Undefined Normal v Visual select Visual V Visual select sentence Visual w Jump cursor to start of next word Normal W Jump cursor to start of next word Normal x Delete character under cursor Normal X Delete character backwards Normal y y Yank (copy) line Normal Y Yank (copy) line Normal z Menu - code folding / keyboard macros Normal"},{"location":"reference/vim-style/motions/","title":"Motions","text":"

Todo

Moving the cursor around by context rather than individual characters

"},{"location":"reference/vim-style/moving-around/","title":"Moving around the cursor","text":"

Scrolling is quite inefficient in most editors and moving (jumping) the curor around is far more effective.

Using the h j k l as a common part of navigation provides consistency and keeps fingers on the most convienient part of the keyboard.

"},{"location":"reference/vim-style/moving-around/#moving-by-charater","title":"Moving by charater","text":"

h j k l keys move the cursor once character or can be used with numbers to move further.

"},{"location":"reference/vim-style/moving-around/#moving-with-numbers","title":"Moving with numbers","text":"

: followed by a number then one of h j k l keys will move the cursor that number in the director of the key.

3j will move 3 lines down the buffer (or to the end of the fuffer if there are fewer lines remaining)

Using Relative line numbers showws how far each line is from the current line. The practicalli/neovim-config sets :relativenames true in fnl/config/init.fnl.

42l moves 42 charaters to the right

moving by motions avoids the need to count characters

"},{"location":"reference/vim-style/moving-around/#moving-around-the-buffer","title":"Moving around the buffer","text":"

g g to jump to the top of the current buffer

G to jump to the bottom of the buffer

z z moves the current line and cursor to the middle of the window

z t moves the current line and cursor to the top of the window

z t moves the current line and cursor to the bottom of the window (or as far as the buffer will move in the window)

"},{"location":"reference/vim-style/narrowing/","title":"Narrowing","text":"

Narrowing to a region enables vim commands to be applied to a specific part of the current buffer, rather than the whole buffer.

Common examples include - replacing local variables within a specific function (avoiding affecting other function definitions)

"},{"location":"reference/vim-style/narrowing/#nrrwrgn-plugin","title":"NrrwRgn plugin","text":"

[NrrwRgn plugin] is inspired by the Narrowing feature of Emacs and means to focus on a selected region while making the rest inaccessible.

SPC n r opens a select region in a new split window. The original buffer is protected from changes.

:w to write changes in the narrowed window to the original buffer

"},{"location":"reference/vim-style/narrowing/#commands","title":"Commands","text":"

:NR - Open the selected region in a new narrowed window :NW - Open the current visual window in a new narrowed window :WR - (In the narrowed window) write the changes back to the original buffer. :NRV - Open the narrowed window for the region that was last visually selected. :NUD - (In a unified diff) open the selected diff in 2 Narrowed windows :NRP - Mark a region for a Multi narrowed window :NRM - Create a new Multi narrowed window (after :NRP) - experimental! :NRS - Enable Syncing the buffer content back (default on) :NRN - Disable Syncing the buffer content back :NRL - Reselect the last selected region and open it again in a narrowed window

Appending ! to most commands opens the narrowed part in the current window instead of a new window.

:WR! closes the narrowed window in addition to writing to the original buffer.

"},{"location":"reference/vim-style/narrowing/#documentation","title":"Documentation","text":"

:help NarrowRegion to view the documetation on the NrrwRgn plug use

"},{"location":"reference/vim-style/narrowing/#attention","title":"Attention","text":"

:NRM is described as experimental by the project readme.

"},{"location":"reference/vim-style/speaking-vim/","title":"Learning to speak Vim","text":"

Neovim is easier to learn and gain much more benefit from if you learn to speak commands as sentences.

First learn some verbs:

Then use those verbs with some modifiers

Then learn the text objects you can apply verbs and modifiers too

"},{"location":"reference/vim-style/speaking-vim/#examples-of-speaking-vim","title":"Examples of speaking Vim","text":"

Practice speaking evil with these examples

Keybinding Description c i s change inside current sentence (change the whole sentence) c i \" change inside double quotes c f ) change from cursor to next ) character c s ' \" change by the surrounding single quotes with double quotes c t X change till the character X (not including X) c /foo change until the first search result of \u2018foo\u2019 d d delete current line D delete current line from cursor onward d i w delete inside the current word (delete word) v t SPC visual select till the next Space character v s ] visually select and surround with [] without spaces v s [ as above with [ ] with spaces between parens and content g v go to last visual selection (select last visual selection) v a p visually select around current paragraph v i w S \" visually select, insert around current word, and surround with quotes y y yank (copy) current line y w yank (copy) current word y @ a yank (copy) to mark a (m a creates a mark called a)"},{"location":"reference/vim-style/vim-quick-reference/","title":"Neovim Quick Reference","text":"

A reference of the most common keybindings available in Vim Normal mode. Spacemacs DOCUMENTATION key bindings section contains full details

. repeats the last keybinding sequence used in Vim Normal mode or a change made within a complete Vim Insert session.

"},{"location":"reference/vim-style/vim-quick-reference/#moving-around","title":"Moving around","text":"

In Normal mode you can keep your fingers resting on the main row of your keyboard to move around.

Key action j move cursor down one line k move cursor up one line l move cursor right one character h move cursor left one character

In menus such as helm you can move around using Ctrl and these keybindings. So C-j will move the cursor down one item in a menu.

"},{"location":"reference/vim-style/vim-quick-reference/#navigating-the-current-line","title":"Navigating the current line","text":"Key Action f to next character (you specify) t to just before the next character ; repeat f or t search w start of next word W start of next word, white space delimited e end of current word b start of previous word W end of next word, white space delimited * to next matching symbol name $ end of current line 0 start of current line ^ start of non-whitespace % jump to matching parens or next closed paren"},{"location":"reference/vim-style/vim-quick-reference/#navigating-the-current-buffer","title":"Navigating the current buffer","text":"Key action gg start of buffer G end of buffer H move cursor to head of buffer M move cursor to middle of buffer L move cursor to bottom line of buffer C-u jump up half a page C-d jump down half a page } move cursor forward by paragraph or block { move cursor backward by paragraph or block ma mark a line in a file with marker \"a\" `a after moving around, go back to the exact position of marker \"a\" 'a after moving around, go back to line of marker \"a\" :marks view all the marks '' go to the last place you were [{ jump back to the \"{\" at the beginning of the current code block C-o jump back to previous cursor location (evil-jump-backwards) C-i Go to newer position in jump list (opposite of C-o) : 4 go to line 4"},{"location":"reference/vim-style/vim-quick-reference/#text-editing","title":"Text Editing","text":"

The following commands put you into the Evil Insert state

Key Action i insert state at cursor I insert state at start of line a append - insert state after cursor A append - insert state at end of line o new line after cursor O new line before cursor"},{"location":"reference/vim-style/vim-quick-reference/#return-to-normal-state","title":"Return to Normal state","text":"

Regularly switch back to normal state should become common practice. As soon as you finish typing some new text, it should become second nature to go back to normal state.

ESC or press fd keys in extremely quick succession.

fd shortcut for Esc

Using f d together is low risk as if you dont get it right it will either add the characters or try find the next d character (as f moves to the next character). Keep trying this key combination as once in normal state you can use u to undo any f d characters inserted.

"},{"location":"reference/vim-style/vim-quick-reference/#copy-cut-paste-undo-redo","title":"Copy, cut, paste, undo, redo","text":"

v in Vim normal mode changes to Visual select mode. Use the navigation keys or any other movement keys to select text to copy or cut.

Key Action y copy (yank) selection and add to kill ring x delete character at point and add to kill ring X delete character before point and add to kill ring p paste (put) u undo Ctrl-r redo

Undo tips

Undo will revert the last action in normal mode or all the changes you made in insert state

"},{"location":"reference/vim-style/vim-quick-reference/#replace-and-changing-text","title":"Replace and changing text","text":"Key Action r replace the character under cursor R replace multiple characters until ESC cw change word from cursor to end 4 c w change 4 words v (select) c change region v (select) d delete region v i w c change current word v i d delete current word d w delete from cursor to end of word C change from cursor to end of line D , d $ delete from cursor to end of line"},{"location":"reference/vim-style/vim-quick-reference/#delete-commands","title":"Delete commands","text":"Key Action de delete to end of word, not including space dw delete to end of word, including space d$ delete to end of line dd delete the current line 4 d w delete 4 words 4 d $ delete 4 lines to end dt delete to a character (not including character) dab delete a whole block / expression dib delete contents of a block / expression cab change all the block / expression cib change inner block contents / expression yab yank all block / expression yib yank inner block contents / expression"},{"location":"reference/vim-style/vim-quick-reference/#repeat-commands","title":"Repeat commands","text":"Key Action . repeat last command again <number> <cmd> repeat command a number of times

The . keybinding will repeat the last command in normal mode or the last text edit in insert mode.

Type a number before a command and that command will run that number of times.

Inserting a comment border

Use the number repeat to create a border of 42 ; characters.

Type 42 to repeat the command 42 times

Press i for insert mode

Press ; as the character to repeat insert

Press ESC or fd to leave insert mode and insert all 42 ; characters

"},{"location":"reference/vim-style/vim-quick-reference/#transposing-swap","title":"Transposing / swap","text":"Key Description x p transpose the current character with the next character"},{"location":"reference/vim-style/vim-quick-reference/#comments-works-for-all-major-modes","title":"Comments - works for all major modes","text":"

g c c to comment out the current line

g c to comment out the currently selected region

To comment multiple lines you can use the repeat command style, especially useful if you are using relative line numbers.

g c 3 j will comment the current line and the following two lines below. Comment in reverse using g c 3 k.

In Visual state, v, select the lines you wish to comment and use g c to comment all the marked lines. Partially marked lines are not commented.

"},{"location":"reference/vim-style/vim-quick-reference/#managing-files","title":"Managing Files","text":"

Files in practicalli/neovim-config can be managed with Telescope plugin, although the neovim commands can also be used

SPC p t toggles a visual file explorer on as a leftmost window, providing a further way to navigate files and directories.

Key Description SPC f f find existing file (from current local root of neovim) SPC f / copy file - save current buffer with a new file name SPC f b browse files - Esc to run commands SPC f b Esc r change file name of current buffer

Telescope file browser opens in Insert mode to allow typing filenames, to narrow the results in the Telescope popup.

"},{"location":"reference/vim-style/vim-quick-reference/#telescope-browser-commands","title":"Telescope browser commands","text":"

SPC f b opens telescope browser which allows commands to be run over the current file or directory.

Esc swiches the Telescope popup to normal mode, allowing commands to be used

TAB selects files and directories, allowing for commands (i.e. rename) to be done in batch mode (acting on all selected files / directories)

"},{"location":"reference/vim-style/vim-quick-reference/#working-with-buffers","title":"Working with Buffers","text":"

To work with files in Neovim they are loaded into a Buffer.

Buffers are displayed in a window and you can change the window to show any of the current buffers.

SPC b displays the buffer menu and the most common commands include:

Key Command Description SPC b b :Telescope buffers List current buffers SPC b d :bdelete Kill current buffer SPC b n :bnext Switch to next buffer SPC b p :bprevious Switch to previous buffer SPC b a :ball Switch to previous buffer"},{"location":"reference/vim-style/vim-quick-reference/#quit-or-restart-emacs","title":"Quit or Restart Emacs","text":"

I recommend using the Spacemacs menu from normal mode to quit / restart Spacemacs.

Key Action SPC q a Quit Neovim (blocked if unsaved change in buffers) SPC q q Quit buffer (blocked if unsaved change in buffers) SPS q Q Force quit of Neovim"},{"location":"reference/vim-style/vim-quick-reference/#external-commands","title":"External commands","text":"

run external commands using :! followed by a command. For example:

:!ls - run the ls command

"},{"location":"reference/vim-style/vim-tips-for-developers/","title":"Vim editing for Clojure developers","text":"

Vim keybindings that drive Vim editing tools that are common for developers

"},{"location":"reference/vim-style/vim-tips-for-developers/#comments-and-commenting-code","title":"Comments and Commenting code","text":""},{"location":"reference/vim-style/vim-tips-for-developers/#simulated-structural-editing-with-surround","title":"Simulated structural editing with surround","text":"Keybinding Description v s ] surround with [characters] without spaces v s [ surround with [ characters ] without spaces c s ( [ change surrounding from ( to [ c i ( change in ( c a ( change \u201caround\u201d ( % jump forwards to next paren, further % toggles between open and close parens. x p transpose characters (cut current, paste after)"},{"location":"reference/vim-style/vim-tips-for-developers/#moving-around-quickly","title":"Moving around quickly","text":"

f to jump forward to a given character on the current line. F to jump backwards.

zt, zz, and zb to pull the current line to the top/middle/bottom of the screen.

[number] G jump to line number or :22 to jump to line 22

:7j to jump 7 lines down

gf jump to file name under the cursor - try this in the summary.md file

"},{"location":"reference/vim-style/vim-tips-for-developers/#selection-find-and-replace","title":"Selection, find and replace","text":"

viw to visual-select in (within) the current word

"},{"location":"reference/vim-style/vim-tips-for-developers/#source-code-and-configuration-files","title":"Source code and configuration files","text":"

g Dopen definition in another window

= (code-aware indenting) operator. Nice with the ap (a paragraph) text object.

C-] Jump to definition of keyword under the cursor

"},{"location":"reference/vim-style/vim-tips-for-developers/#code-folding","title":"code folding","text":"

zc and zo are useful to close and open folds, which can be a nice way of focusing on certain pieces of code.

"},{"location":"reference/vim-style/vim-tips-for-developers/#transposing-characters-and-sections","title":"Transposing characters and sections","text":"

x p simple transpose of the current and next character

M-t transpose words before and after cursor position

{, } motions jump to next and previous empty lines. This motion makes it simple to rearrange paragraphs

{ d } will kill the paragraph (or multiple paragraphs)

{ will jump to the start of the previous paragraph

p pastes the killed paragraph before the current paragraph

> and < (indent and dedent) operators, useful with the aforementioned }/{ motions.

/ ## multi-replace with iedit and narrowing /

"},{"location":"reference/vim-style/visual-select/","title":"Visual Select","text":"

Select characters, words, lines and regions with visual select. The background changes color to visually indicate which text is selected

v enters visual select mode and can be with objects such as word w and locations such as end of line $.

o to expand from left side of selection and O to expand from the right side of a selection, using the hjkl navigation keys

"},{"location":"reference/vim-style/visual-select/#visual-line-selection","title":"Visual Line selection","text":"

V to select by lines, using j and k.

"},{"location":"reference/vim-style/z-menu/","title":"Evil Z menu","text":"

z in normal mode opens a menu of convenient utilities

"},{"location":"reference/vim-style/z-menu/#folding-code-comments-and-other-content","title":"Folding code, comments and other content","text":"

Code folding is very useful for hiding different levels of detail, for example you could hide everything but the function names in a namespace, showing just the API for that namespace.

Comments and documentation can be folded to help you focus on a specific part of the content.

Key Description z a toggle fold of code, comment, section, etc. z A toggle all folds z c close fold z f create fold z M close all folds z o open fold z O open fold recursive (capital o) z r fewer folds z R open all folds z x update folds

See narrowing for a focused approach to editing.

"},{"location":"reference/vim-style/z-menu/#scrolling","title":"Scrolling","text":"

Jump the current line to the center, top or bottom of the buffer.

Key Description z b scroll the current line to bottom of buffer z t scroll the current line to top of buffer z z scroll the current line to center of buffer"},{"location":"reference/vim-style/z-menu/#spelling","title":"Spelling","text":"

z = with the cursor on a word shows a list of possible spelling and similar words.

Select a word using its number in tye list to repace the word under the cursor, or q to quit the spelling list.

Key Description z = spelling suggestions z g add word to spelling list z w mark word as misspelled"},{"location":"repl-driven-development/","title":"REPL Driven Development with Clojure","text":"

Conjure provides the REPL driven development workflow for Clojure (and many other fun languages) and includes a built-in tutorial.

Practicalli Clojure CLI Config

Practicalli Clojure CLI config contains aliases used extensively through the Clojure sections of this book

Practicalli Neovim config replaces some key bindings

practicalli/neovim-config-redux replaces several key bindings to make them consistent with other Clojure editors

"},{"location":"repl-driven-development/#references","title":"References","text":""},{"location":"repl-driven-development/conjure/","title":"Conjure","text":"

Conjure is the Clojure REPL client for Neovim. Code in source code buffers can be evaluated and show the results in-line, providing instant feedback on the behaviour of the code as it develops.

Conjure School interative tutorial

:ConjureSchool runs an interactive tutorial in Neovim, walking through the essential Conjure commands and key bindings. Use the commands provided to move through the guide or j / k to scroll through the guide content.

"},{"location":"repl-driven-development/conjure/#start-repl","title":"Start REPL","text":"

Start a REPL on the command line in the root of a Clojure project. The REPL should also start an nREPL server for Conjure to connect too.

Conjure will detect an nREPL server (via .nrepl-port file) when a Clojure file is opended (.clj .edn .cljs .cljc) and connect to the REPL process via that nREPL server.

Practicalli Clojure CLI ConfigManual Alias definition

Practicalli Clojure CLI config contains aliases to start a REPL process that also start an nREPL server.

Use repl make task for projects created by Practicalli Project templates

make repl\n

Or use the Clojure CLI command with the :repl/rebel alias directly

clojure -M:repl/rebel\n
Simplify the command line

Add a Makefile to define common tasks to simplify and add consistency to working with Clojure across projects or shell script to simplify the commands used to call clojure to run common tasks

repl:  ## Run Clojure REPL with rich terminal UI (Rebel Readline)\n    $(info --------- Run Rebel REPL ---------)\n    clojure -M:env/dev:env/test:repl/rebel\n\n\nrepl-reloaded:  ## Run Clojure REPL with hotload, reload and rich terminal UI (Rebel Readline)\n    $(info --------- Run Rebel REPL ---------)\n    clojure -M:env/dev:env/test:lib/reloaded:repl/rebel\n

A Makefile can also include supporting commands, such as lint and format tools.

# Run MegaLinter with custom configuration\nlint:\n    $(info --------- MegaLinter Runner ---------)\n    mega-linter-runner --flavor java --env 'MEGALINTER_CONFIG=.github/linters/mega-linter.yml'\n

practicalli/dotfiles/Makefile contains tasks for Clojure development, including running a REPL, preparing dependencies, building an uberjar, lint & format Clojure and configuration files.

Docker related tasks to build, run and compose common images and containers are also included.

Add aliases to the user configuration for Clojure, e.g. XDG_HOME_CONFIG/clojure/deps.edn or HOME/.clojure/deps.edn

  ;; Interactive client REPL with nREPL server for Clojure Editor support\n  :repl/basic\n  {:extra-deps {nrepl/nrepl       {:mvn/version \"1.0.0\"}\n                cider/cider-nrepl {:mvn/version \"0.40.0\"}}\n   :main-opts  [\"--main\" \"nrepl.cmdline\"\n                \"--middleware\" \"[cider.nrepl/cider-middleware]\"\n                \"--interactive\"]}\n\n  ;; Headless REPL with nREPL server for Clojure Editor support\n  :repl/headless\n  {:extra-deps {nrepl/nrepl       {:mvn/version \"1.0.0\"}\n                cider/cider-nrepl {:mvn/version \"0.40.0\"}}\n   :main-opts  [\"--main\" \"nrepl.cmdline\"\n                \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}\n

clojure -M:repl/basic starts a REPL with nREPL with a minimal REPL UI

clojure -M:repl/headless starts a REPL with nREPL server but without a REPL prompt (to prevent accidental interaction via the command line)

Practicalli Clojure CLI Config aliases

Practicalli Clojure CLI config defines aliases for a wide range of community tools and libraries that extend the features of Clojure CLI

"},{"location":"repl-driven-development/conjure/#evaluation","title":"Evaluation","text":"

Clojure REPL workflow encourages code expressions to be evaluated as the are written, providing instant feedback to ensure expected results are returned (or learn the kind of results a function returns).

Results of evaluating an expression are shown in-line. Open the REPL log to see larger results and a complete REPL history for the current session.

,eb - evaluate current buffer - used after first starting the REPL to load in a whole namespace and any required namespaces. Use to ensure all changes have been evaluated in the REPL (except those within a (comment ) form or otherwise commented)

,er - evaluate top-level expression (root), ignoring a surrounding (comment ) form to support the rich comments approach

,ee - evaluate expression (from start of current form) - especially useful for nested forms

,ei - interrupt evaluation (stop long running evaluations) - stop a long running evaluation

,ew - evaluate word (symbol) - inspect value of form - i.e. for def names

,e! - replace form with its result - helps understand a more complex function by replacing code with a specific value

,emf - evaluate marked form - mark forms regularly re-evaluted with mf (or any character with m) to avoid jumping to that form each time . A capital letter to mark form in a different namespace and evaluate from the current buffer.

\"cp - paste contents of the register into buffer. The result of every evaluation is stored in a Neovim register as well as the log.

"},{"location":"repl-driven-development/conjure/#repl-log","title":"REPL log","text":"

The Conjure REPL log shows the results of every evaluation for the current session.

,lt opens log in a new tab page (tab), ,ls in horizontal split, ,lv in vertical tab

,lq - close log window / tab page

,lr - soft REPL reset, leave window open

,lR - hard REPL reset, close window & delete buffer

Inline evaluation over HUD log popup

Practicalli Neovim configurations hide the HUD log popup that is otherwise shown when Conjure connects to the REPL process, i.e. vim.g[\"conjure#log#hud#enabled\"] = false

In-line evaluation results are the main feedback approach used by Practicalli when evaluating code.

Practicalli recommends using the REPL log when larger results are returned

Portal data inspector can be sent evaluation history and provides rich visualisation and navigation tools to explore that history in detail.

"},{"location":"repl-driven-development/conjure/#rich-comments","title":"Rich comments","text":"

Rich comments are a useful way to contain experimental expressions, or expresisons only evaluated directly by a person developing the code (e.g. starting / stoping services, testing api calls, etc.)

Expressions in rich comments are not included when evaluating the buffer or when expressions are evaluated via a namespace require.

,er to evaluate the top level form within the rich comment, without evaluating the comment expression itself.

Start REPL from Neovim

Practicalli Configurations require the vim-jack-in plugin to be added before this approach will work.

Start Neovim with a Clojure file, e.g. nvim src/practialli/playground.clj or run nvim and open a Clojure file, e.g. *.clj, *.cljc, *.cljs or .edn.

Neovim switches to a terminal state, use C-\\ C-n to leave the terminal state. Use :N or :previous to switch back to the source code buffer

, c f to connect to the REPL from Conjure, or simply open a Clojure file. Automated connection will be added in a future version on Conjure.

The vim-jack-in plugin enables Neovim to call out to Clojure tools or Leiningen to start a REPL and connect to it once its started.

A full screen REPL log is displayed. , l q to close the log window and return to the Clojure file. , l v to create a vertical split between code and REPL log, , l s for a horizontal split.

"},{"location":"repl-driven-development/refactor-tools/","title":"Refactor tools","text":"

Neovim and common plugins provide many text oriented tools useful for refactoring code.

Clojure LSP server and Neovim LSP client support use static analysis of the project source code to allow provide common code refactor tools.

"},{"location":"repl-driven-development/refactor-tools/#language-server-protocol-lsp","title":"Language Server Protocol (LSP)","text":"

Using clojure-lsp server and Neovim Treesitter as an LSP client, code is statically analysed to provide auto-completion data, advanced editing actions such as refactor, live formatting, etc.

Function help

SPC l h or K displays help for the function under the cursor

Repeat the key binding to move the cursor to the documentation popup window and use j k to scroll the documentation

"},{"location":"repl-driven-development/refactor-tools/#key-maps","title":"Key maps","text":"Practicalli AstroNvim ConfigPracticalli Neovim Config Redux "},{"location":"repl-driven-development/refactor-tools/#limitations-to-investigate","title":"Limitations to investigate","text":""},{"location":"repl-driven-development/structural-editing/","title":"Structural Editing","text":"

Structural editing seeks to ensure that parenthesis (parens) and other pairs of characters remain balanced, i.e. an open paren is not removed without removing the closing paren.

AstroNvim Community Clojure Pack includes parinfer

nvim-parinfer plugin is included in the AstroNvim Community Clojure pack

  { import = \"astrocommunity.pack.clojure\" },\n
"},{"location":"repl-driven-development/structural-editing/#parinfer","title":"Parinfer","text":"

Parinfer works very well with vim-style modal editing.

The author of the code focuses on aligning code and parinfer takes care of balancing the parens.

To include new lines of code within an expression, create a new line o and indent.

Parinfer will move the preceeding closing paren(s) to the new line, enclosing the new code in the overall expression.

Parinfer website

"},{"location":"repl-driven-development/testing/","title":"Unit tests and test runners","text":"

Run unit tests from within Neovim, showing a summary of test results or a full test report (especially if there are failures)

Or run and external test runner via a terminal session, optionally using watch mode to re-run tests on every saved change.

Practicalli sets Kaocha test runner as default

practicalli/neovim-config-redux sets Kaocha as the default test runner

Kaocha test runner set in Astrocommunity Clojure language pack

Astrocommunity Clojure language pack
{\n  \"Olical/conjure\",\n  -- load plugin on filetypes\n  ft = { \"clojure\" },\n  init = function()\n    vim.g[\"conjure#log#hud#width\"] = 1\n    vim.g[\"conjure#log#hud#enabled\"] = false\n    vim.g[\"conjure#log#hud#anchor\"] = \"SE\"\n    vim.g[\"conjure#log#botright\"] = true\n    vim.g[\"conjure#extract#context_header_lines\"] = 100\n    vim.g[\"conjure#eval#comment_prefix\"] = \";; \"\n    vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#enabled\"] = false\n    vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#hidden\"] = true\n    vim.g[\"conjure#client#clojure#nrepl#connection#auto_repl#cmd\"] = nil\n    vim.g[\"conjure#client#clojure#nrepl#eval#auto_require\"] = false\n    vim.g[\"conjure#client#clojure#nrepl#test#runner\"] = \"kaocha\"\n\n    vim.api.nvim_create_autocmd(\"BufNewFile\", {\n      group = vim.api.nvim_create_augroup(\"conjure_log_disable_lsp\", { clear = true }),\n      pattern = { \"conjure-log-*\" },\n      callback = function() vim.diagnostic.disable(0) end,\n      desc = \"Conjure Log disable LSP diagnostics\",\n    })\n
"},{"location":"repl-driven-development/testing/#include-test-path","title":"Include test path","text":"

Ensure the test directory is included in the classpath when starting a REPL. Use a project or user level alias which defines an :extra-paths key with the [\"test\"] path

clojure -M:test/env:repl/reloaded\n
"},{"location":"repl-driven-development/testing/#conjure-test-runners","title":"Conjure Test runners","text":"

, t n to run the tests for the current namespace

, t a to run all tests in the project

"},{"location":"repl-driven-development/testing/#external-test-runner","title":"External test runner","text":"

Open a terminal in Neovim or a separate terminal session to run start a test runner in watch mode. Tests run automatically when the code changes are saved

Practicalli Clojure CLI Config

Practicalli Clojure CLI config contains aliases for test runner tools

Projects created with Practicalli Project Templates include a test and test-watch task to run Kaocha test runner

Run all tests, stoping on first failing test

make test\n

Watch for changes and run all tests, stoping on first failing test

make test-watch\n

The make tasks call Clojure CLI with the appropriate alias, e.g. clojure -X:test/run and clojure -X:test/watch

"},{"location":"repl-driven-development/testing/#test-selectors","title":"Test Selectors","text":"

Use Test selectors to run a sub-set of tests based on selector meta data added to deftest code

(deftest ^:infrastructure function-name-test\n  (testing \"\"\n    (is ,,,))\n\n(deftest ^:persistence function-name-test\n  (testing \"\"\n    (is ,,,))\n
Kaocha test runnerCognitect Labs Test Runner

Kaocha test runner can focus or skip on a sub-set of unit tests using test id, metadata, namespaces or a specific deftest.

Specifying test :id in the tests.edn configuration file allows different test suites to be run, e.g. :unit for unit tests, :spec for specification tests

Focus and skip works with a single test run or with a continuous watcher.

Skip all tests with :persistence metadata

clojure -X:test/watch :skip-meta :persistence\n

Focus on a specific test namespace

clojure -X:test/watch :focus '[\"practicalli.gameboard.api.scoreboard-test\"]\n

Focus on a specific unit test (deftest)

clojure -X:test/watch :focus '[\"practicalli.gameboard.api.scoreboard-test/total-score-test\"]\n

Refine the tests that are watched

Start the watcher with focused or skiped tests by name or meta data (test selectors)

Cognitect Labs Test Runner can include or exclude a sub-set of tests, identified by metadata on the var (deftest)

Cognitect Labs Test Runner - inclusions & exclusions

"},{"location":"termux/","title":"NeoVim on Termux","text":"

A smart phone or tablet and an external keyboard can make an excellent ultra-portable development environment, especially when travelling with limited space or restricted weight constraints.

Termux can be installed using the F-Droid marketplace, as with installing any other Android app.

Do not install Termux App from the Google Play store

The Termux App in Google Play store is significantly out of date and will not work properly and probably not at all

"},{"location":"termux/#keyboard","title":"Keyboard","text":"

Atreus from Keyboardio is an excellent travel keyboard and was used to write most of the Practicalli Neovim configuration and Neovim book (especially during delays at airports)

Model 100 from Keyboardio is used by Practicalli at the office

"},{"location":"termux/#running-termux","title":"Running Termux","text":"

Run Termux from the app launcher added as an android app by the F-Droid install.

A help menu will show the basic command needed to work with packages.

Software keys for Termux specific controls are shown. Keys can be toggled with the Volume Up + q key combination.

Termux may not display in fullscreen when Android productivity mode, usually activated on tablets when physical keyboard or mouse is attached. Disabling productivity mode in the Android settings is recommended.

"},{"location":"termux/clojure-development/","title":"Clojure development environment","text":"

A comprehensive development environment for Clojure, supporting a REPL workflow and static analysis of code via Clojure Language Server Protocol.

"},{"location":"termux/clojure-development/#java-host-platform","title":"Java host platform","text":"

Install OpenJDK to host the Clojure REPL process and run packaged Clojure applications.

Java 17 Long Term Support version is recommended as it is very stable, receives security updates and has the latest highly tested performance improvements.

pkg install openjdk-17\n
"},{"location":"termux/clojure-development/#install-clojure","title":"Install Clojure","text":"

Clone practicalli/clojure-deps-edn to add a wide range of community tools to the Clojure CLI

git clone git@github.com:practicalli/clojure-deps-edn.git ~/.config/clojure\n

Use the Linux install with a prefix path pointing to Termux equivalent of /usr/local. Find the path using echo $PATH and remove bin from the end. Without the prefix Clojure will not install correctly

curl -O https://download.clojure.org/install/linux-install-1.11.1.1149.sh\n\nchmod +x linux-install-1.11.1.1149.sh\n\n./linux-install-1.11.1.1149.sh --prefix /data/data/com.termux/files/usr/\n

clojure binary is installed in the existing bin, lib and share directories in /data/..../usr/, placing that binary on the system execution path.

Test by running a REPL session, for example with Rebel Readline

clojure -M:repl/rebel\n

optionally install rlwrap package if using the basic repl terminal UI

"},{"location":"termux/clojure-development/#install-clojure-lsp","title":"Install Clojure LSP","text":"

Visit clojure-lsp GitHub releases page and download the clojure-lsp file

If the practicalli/clojure-lsp-config repository was cloned, move or link the clojure-lsp directory to ~/.config/clojure-lsp

"},{"location":"termux/custom-shell/","title":"Customise shell","text":"

Customising the shell is optional, although gives an enhanced experience.

Zsh provides the richest command line experience, providing many advanced features over bash. Oh My Zsh is a community configuration that provides a simple way to configure Zsh features and also supports powerline10k terminal theme, providing context specific information and a more engaging visual experience.

Oh My Zsh community configuration enhances the Zsh experience. Practicalli normally uses Prezto community configuration, unfortunately this did not work well on Termux.

"},{"location":"termux/custom-shell/#install-zsh","title":"Install Zsh","text":"

Install the zsh package using the Termux package manager

pkg install zsh\n

Start zsh, which will show a % character as the prompt

zsh\n

Set the shell to run zsh by default

chsh -s zsh\n
"},{"location":"termux/custom-shell/#install-oh-my-zsh","title":"Install Oh My Zsh","text":"

Install Oh My Zsh via curl (or wget if preferred) in the .oh-my-zsh/ directory

sh -c \"$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\"\n
"},{"location":"termux/custom-shell/#install-powerline10k","title":"Install Powerline10k","text":"

Powerline10k is a visually appealing prompt with a setup script to visually choose the presentation of the prompt.

git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k\n

Edit ~/.zshrc and set the theme to ZSH_THEME=\"powerlevel10k/powerlevel10k\"

nano ~/.zshrc\n

Save the changes exit termux.

Next time zsh is run, powerline10k setup script will run. If Meslo is not set as the terminal font, the setup script offers to install the font. Installing the font will restart Termux (without prompting for a restart).

The powerline10k setup script provides a wizard to configure each part of the prompt.

p10k configure command will manually run the powerline10k setup script.

Prezto Zsh community configuration

NOTE: previous attempts to use Prezto proved to have issues

Clone prezto and its sub-modules into XDG_CONFIG_HOME/zsh which is typically ~/.config/zsh

git clone --recursive https://github.com/sorin-ionescu/prezto.git \"${ZDOTDIR:-${XDG_CONFIG_HOME:-$HOME/.config}/zsh}/.zprezto\"\n

Set the location of the Zsh configuration home with $ZDOTDIR, relative to the XDG locations

export ZDOTDIR=\"${ZDOTDIR:=$XDG_CONFIG_HOME/zsh}\"\n

Create a new Zsh configuration by copying/linking the Zsh configuration files provided:

setopt EXTENDED_GLOB\nfor rcfile in \"${ZDOTDIR:-$HOME}\"/.zprezto/runcoms/^README.md(.N); do\n  ln -s \"$rcfile\" \"${ZDOTDIR:-$HOME}/.${rcfile:t}\"\ndone\n

Practicalli Zsh configuration

Clone practicalli/dotfiles and replace the symbolic links in $XDG_CONFIG_HOME/zsh with links to the respective Zsh configuration files in the cloned repository (or copy the files if you prefer)

Copy or create a symbolic like for the .p10k configuration or skip this to create your own configuration when next startingzsh.

Edit $XDG_CONFIG_HOME/.config/zsh/.zshenv and add the following lines to enable zsh to find the prezto configuration

export XDG_CONFIG_HOME=\"${XDG_CONFIG_HOME:=$HOME/.config}\"\nexport ZDOTDIR=\"${ZDOTDIR:=$XDG_CONFIG_HOME/zsh}\"\n

Create a symbolic link from $HOME/.zshenv to $XDG_CONFIG_HOME/.config/zsh/.zshenv (or to the .zshenv file from practicalli/dotfiles)

ln -s $XDG_CONFIG_HOME/.config/zsh/.zshenv $HOME/.zshenv\n

Check the configuration is working by loading the .zshenv configuration

source \"$ZDOTDIR/.zshenv\"\n

Using Oh My Bash

If preferring Bash, then ohmybash provides a nice command line experience, showing completions clearer, nice themes that provide information.

"},{"location":"termux/fdroid-install/","title":"Install Termux via the F-Droid App","text":"

Visit the FDroid app website and download F-Droid, which saves an F-Droid.apk file. Android may display a security prompt stating the browser does not have permissions to install software. The popup should include a configure link that opens the Android settings to allow the browser to install software.

F-Droid should now be installed and its icon added to the Android system alongside all other Android apps.

Open the F-Droid App and allow it to update its repositories, to ensure the latest list of apps are shown.

Search for the Termux application, clicking on the Termux name if more details are required.

Select the Install button.

When installing apps from F-Droid for the first time, a security prompt is show as F-Droid is an unknown source.

Select Settings to open the Android settings and enable Allow from this source for the F-Droid app.

A Termux App launcher will be added to the Android screen. Consider adding the Termux icon to the commonly used icons bar.

"},{"location":"termux/fdroid-install/#termux-styling","title":"Termux Styling","text":"

Styling is a Termux plugin that provides a visually richer experience. Styling contains beautiful color schemes and powerline-reaqdy fonts to customise the appearance of the terminal

Install the package via F-Droid

The styling menu is accessed via a long press on the Termux app screen, showing a More > Style option on the usual cut/copy/paste popup menu. Practicalli recommends FiraCode fonts.

"},{"location":"termux/git/","title":"Git version control","text":"

A Git client is used to version control projects and to clone projects and configuration from GitHub/GitLab. Practicalli maintains several editor configurations in shared repositories on GitHub

"},{"location":"termux/git/#install-a-git-client-and-github-cli","title":"Install a git client and GitHub CLI","text":"
pkg install git gh\n

Clone the practicalli/dotfiles repository

git clone https://github.com/practicalli/dotfiles projects/dotfiles\n

Move or symbolically link the top-level directories to ~/.config, e.g. for the Git configuration:

ln -s projects/dotfiles/git ~/.config/git\n

Edit the .config/git/config and update the core.user, core.name and github or gitlab identities

"},{"location":"termux/git/#create-ssh-key-for-remote-repository-access","title":"Create SSH Key for remote repository access","text":"

Install the openssh package which contains the ssh-keygen command to generate a new public/private key combinations for use with GitHub SSH repository URLs

pkg install openssh\n

Generate a key using the email address of the GitHub or GitLab account

ssh-keygen -t rsa -C name@domain.tld\n

RET to confirm storing the keys in the default location.

Usually a passphrase is recommended, however, termux does not seem to save a keyring to save the key passphrase using ssh-add. So the passphrase must be entered each time the key is used, unless a blank passphrase is used.

Vist your GitHub account settings and create a new SSH key

Use cat ~/.ssh/id_rsa.pub to show the public key contents. Press the screen to select and copy the public key to the clipboard.

Paste the public key into the GitHub new key form.

"},{"location":"termux/git/#optional-create-a-developer-token","title":"[optional] Create a developer token","text":"

A developer token (or ssh key) is required to access GitHub {and far more secure over password}

Should the android device become lost or compromised, the developer token can be deleted to protect the repositories from any malicious access. The developer token should be limited to the minimal access. The developer token does not give access to the GitHub or GitLab account.

HTTPS URLs should be used with a developer token. git@git.com URLs are for SSH keys only.

Visit GitHub / GitLab settings for your account

Create a new developer token specifically for Termux

Add a descriptive name for the token, based on the device Termuxc is runniung on, e.g. Termux Pixel2XL

Check the public_repo and status repo scopes

Generate button creates a new token.

Copy the token using the copy icon.

Edit the .config/git/config file and add a github section with the GitHub account name and token

[github]\n    name = practicalli\n    token = ghp_************************************\n

Consider using GitHub CLI to cache the developer token rather than write the token to the Git configuration file for greater security.

"},{"location":"termux/neovim/","title":"Install neovim","text":"

Neovim version 8 availabe as current package

pkg install neovim\n
"},{"location":"termux/neovim/#neovim-treesitter","title":"Neovim treesitter","text":"

Treesitter provides excellent language syntax parsing and highlighting and is a very attractive feature of the recent neovim releases. Treesitter is a major attraction, bringing in a new audience for Neovim.

The nvim-treesitter package is included in the practicalli/neovim-config-redux configuration.

"},{"location":"termux/neovim/#c-compiler","title":"C Compiler","text":"

Install C compiler for neovim-treesitter, to compile a parser for each specific programming language.

pkg install clang\n

gcc is not packaged for Termux, although there are guides to install gcc if preferred. clang has proved to be capable of creating the parsers used in the Practicalli configuration.

"},{"location":"termux/neovim/#searching-files","title":"Searching files","text":"

Telescope and other packages that involve searching for files recommend using ripgrep, a highly optomised tool for finding files on the operating system.

pkg install ripgrep\n
"},{"location":"termux/neovim/#optional-nodejs","title":"[optional] nodejs","text":"

Optional. Only if node.js is required as a Neovim provider and JavaScript or ClojureScript development is to be done.

pkg install nodejs\n
"},{"location":"termux/setup/","title":"Termux Setup","text":"

Launch Termux via its application icon. A black terminal screen will appear with a bash shell prompt.

"},{"location":"termux/setup/#update-packages","title":"Update packages","text":"

Check for new packages and update them all

pkg upgrade -y\n

If you wish to first check the packages that will be updated, use pkg --list-upgradable

Select a specific region to minimise the number of mirrors checked during package upgrades, especially useful if on a limited data plan.

termux-change-repo\n

At time of writing, the Termux package on F-Droid was around 6 months old so there will be a number of packages that should be updated before any further installation steps are undertaken.

"},{"location":"termux/setup/#configure-freedesktoporg-xdg-locations","title":"Configure Freedesktop.org XDG locations","text":"

Edit the ~/.profile file, adding export directives to set the XDG locations:

nano ~/.profile\n
XDG locations
# Common Free desktop.org locations\nexport XDG_CONFIG_HOME=$HOME/.config\nexport XDG_DATA_HOME=$HOME/.local/share\nexport XDG_STATE_HOME=$HOME/.local/state\nexport XDG_CACHE_HOME=$HOME/.cache\n\n# Set XDG location of Emacs Spacemacs configuration\nexport SPACEMACSDIR=\"$XDG_CONFIG_HOME/spacemacs\"\n

Load the environment variables into the shell, or exit Termux and restart.

Load .profile into shell
source ~/.profile\n

nano editor installed by default

nano editor is used to edit the commands as the package is installed by default in termux. vim, neovim, emacs or any other Linux command line editor can be used if the package is first installed. Termux will list packages to install when trying to run a command that is from a package not yet installed.

"},{"location":"termux/setup/#tools-to-download-binaries-and-configuration","title":"Tools to download binaries and configuration","text":"

Many tools can be installed via the pkg tool, although specific Clojure tools and configuration require additional tools:

pkg install curl wget git openssh\n

Configure a Git Identify and SSH key to before committing and pushing changes, or cloning repositories using the SSH protocol. practicalli/dotfiles contains example configuration, ignore patterns and commit template for using Git.

"},{"location":"termux/setup/#optional-configure-termux-settings","title":"[Optional] Configure Termux Settings","text":"

Edit ~/.termux/termux.properties to configure the default settings for termux.

nano ~/.termux/termux.properties\n

Load termux.properties if values are changed (restarting Termux is not enough to load setting changes)

termux-reload-settings\n

The defaults are suitable for the majority of uses, although you may wish to consider:

If swiping from left edge of the screen is already taken, set key bindings for creating a new termux session, naming a session and switching between sessions. Alternatively, use byobu to create and switch between its tabs for multiple terminal sessions.

"},{"location":"termux/setup/#set-color-scheme-and-font","title":"Set Color Scheme and Font","text":"

The Termux:Styling plug provides menus for selecting terminal color scheme and font to use

Press and hold on the Termux screen to show the context menu and select the Style menu. On smaller screens select More > Style

If Termux:Styling plugin was not installed, a prompt will display asking if the plugin should be installed

A menu appears with Choose Color and Choose Font

Select Choose Color to select from the available list of colour schemes, e.g. Gruvbox Dark or Gruvbox Light

~/.termux/colors.properties file is added when selecting a colour scheme, defining Hex colors from the theme selected.

Select Choose Font to select from the available fonts, e.g. FiraCode or Ubuntu

~/.termux/font.ttf font file is added when selecting a font.

Termux:Styling uses NerdFonts for icons

All fonts installed via Termux:Styling have been patched with NerdFonts, providing several thousand icons to use within the terminal prompt and Neovim itself (e.g. VimDevIcons).

"},{"location":"termux/using-termux/","title":"Using Termux","text":"

Start Termux app and a terminal prompt is shown, along with the standard Android software keyboard. An extended keyboard is provided with common key bindings for the command line interface (Tab, Esc, Ctrl, arrow keys, etc.).

"},{"location":"termux/using-termux/#keyboards","title":"Keyboards","text":"

Termux provides an extended keyboard with key combinations not possible with the Android software keyboard, i.e Ctrl-c, arrow keys, etc. TAB is especially useful for driving command and filename completion.

Volume Up + q toggles the extended keyboard, so more screen is available when using a hardware keyboard.

Connect a hardware keyboard for the best experience, e.g the Keyboard.io atreus is an excellent and highly portable mechanical keyboard. The software keyboard is automatically switched off when a hardware keyboard is connected, although the extended keyboard is still displayed by default.

"},{"location":"termux/using-termux/#adjusting-font-size","title":"Adjusting Font size","text":"

Pinch the screen inwards to zoom out making the text font smaller.

Pinch the screen outwards to zoom in making the text font larger.

"},{"location":"termux/using-termux/#termux-menus","title":"Termux menus","text":"

Termux has three menus: A context menu, navigation drawer and Termux section of the Android notification.

The context menu is shown by a long press anywhere on the terminal screen:

The navigation drawer is shown by swiping inwards from the left of the screen

If gesture navigation is enabled in Android, hold the edge of the screen briefly before swiping to bring up the navigation drawer

The Android notification menu contains a Termux section. Press the Termux section to show the current terminal session or expand the Termux section to exiting all running terminal sessions or aquire a wake lock to avoid Termux entering sleep mode. A wake lock allows server and other background processes to run reliably and to continue to receive notifications

"},{"location":"termux/using-termux/#package-management","title":"Package management","text":"

Termux provides a Linux command line experience, providing a wide range of Unix tools and development environments. Termux uses a Debian based system and packages are easily installed

pkg is an alias for apt, the advance package tool, although there seems little benefit to using pkg if familiar with apt (they are both 3 characters)

"},{"location":"termux/using-termux/#byobu-terminal-tab-manager","title":"Byobu terminal tab manager","text":"

Byobu is an alternative to Termux provides a single terminal prompt. Byobu provides multiple shell prompts, allowing individual Clojure tools and editors to be run from the Termux prompt simultaneously. Practicalli uses byobu to run Neovim, a Clojure REPL and unit test watcher in separate byobu tabs with the ability to add further tabs for other command line tools.

pkg install byobu\n

byobu-enable command will configure the current shell to run byobu on startup. Test this is working by typing exit in Termux and start Termux app again. byobu-disable stops this behaviour and byobu will need to be run manually after starting Termux.

Run the byobu-enable command again if zsh is configured after this step or if adding any other shell to Termux.

"},{"location":"version-control/","title":"Version Control","text":"

There are several ways to interact with Git version control, although Practicalli recommends Neogit interactive git client and Octo to manage GitHub issues and pull requests

"},{"location":"version-control/#init-local-repository","title":"Init local repository","text":"AstroNvim

Space t f opens floating terminal window in the current project directory root (or which ever directory Neovim was started from).

Initialise a local git repository in the current directory.

git init .\n

"},{"location":"version-control/#stage-in-buffer","title":"Stage in buffer","text":"AstroNvimPracticalli Neovim Config Redux

The current hunk or the whole buffer can be staged from the buffer using Git Signs, saving a trip to the Git Status buffer.

Space g H stages the current hunk

Space g S stages the current buffer

Not supported.

"},{"location":"version-control/#git-status","title":"Git Status","text":"AstroNvimPracticalli Neovim Config Redux

SPC g g opens lazygit status, for minimal UI

Space g s Space g n ++\"t\" opens neogit in a new tab for Magit style experience

SPC g s opens Git Status tab, by running :Neogit

"},{"location":"version-control/#github-integration","title":"GitHub integration","text":"

Interact with the remote GitHub repository using Octo

List issues from a specific repository

:Octo issue list practicalli/neovim\n

Create a pull request on a specific repository

:Octo pr create practicalli/neovim\n
"},{"location":"version-control/diff/","title":"Diff","text":"

Compare differences between different files or between a file and its versions.

:diffsplit filename Neovim command opens a split containing the selected filename, showing a diff comparision to the currently opened file

file path completion helps select the correct file for comparison

"},{"location":"version-control/diff/#git-diff","title":"Git Diff","text":"

DiffView compares working space and staged changes side by side, or a diff for git merge conflicts.

++SPC++ g d or d in neogit status buffer (SPC g s) will open diffview in a new tab

q to return to neogit status buffer

AstroNvimPracticalli Neovim Config

Ctrl h / j / k / l to navigate between open splits

SPC b toggles the sidebar buffer

SPC w l and SPC w h to move cursor between diff buffer and sidebar buffer

"},{"location":"version-control/lazygit/","title":"Lazygit version control","text":"Command Line or AstroNvim configuration

Lazygit interface not provided by Practicalli Neovim Config Redux

"},{"location":"version-control/lazygit/#requirements","title":"Requirements","text":"

Install lazygit command line tool

"},{"location":"version-control/lazygit/#open-lazygit","title":"Open Lazygit","text":"AstroNvimCommand Line

SPC g g to open git status with lazygit in a popup window

Change to the root directory of the git managed project.

Run the lazygit rich terminal UI

lazygit\n
"},{"location":"version-control/lazygit/#use-lazygit","title":"Use Lazygit","text":"

SPC to stage files or directories in the files section of the UI

c for a simple commit message prompt in the lazygit UI

C to create a commit message within the

Define Editor for Git Commit Messages

Set core.editor in the user Git configuration (i.e. .config/git/config) to the name of the editor to use for commit messages, e.g. nvim, emacsclient) shell title= git config --global core.editor = nvim Alternatively, use the VISUAL or EDITOR environment variable to the choice of editor

"},{"location":"version-control/neogit/","title":"Neogit - interactive client for Git","text":"

Neogit is an interactive git client that provides the core features of version control with Git. Neogit emulates many of the features found in magit.

SPC g s to open :Neogit status buffer

TAB toggles expansion of sections, files and hunks

d provide a side-by-side view of changes

q to quit Neogit and return to the previous tab

Neovim is configured to use the magit style key bindings in practicalli/neovim-config-redux

"},{"location":"version-control/neogit/#branching","title":"Branching","text":"

b opens the branch menu,

"},{"location":"version-control/neogit/#staging-changes","title":"Staging changes","text":"

s to stage change under cursor, either file or hunk. S to stage all changes

u to unstage change under cursor, U to unstage all changes

v to select lines to stage within a hunk using s or unstage with u

"},{"location":"version-control/neogit/#commit","title":"Commit","text":"

c for the commit menu

c for a new commit, a to amend the latest commit, w to reword a commit message, e to add staged changes to existing commit

A new commit or amend commit qill open a new window to write a commit message (using a git commit message template if defined)

:wq to save a commit message and initiate the commit.

:q! to cancel the commit from the commit message buffer.

"},{"location":"version-control/neogit/#stashing-changes","title":"Stashing changes","text":"

Z to open the stash menu

z to stash the working copy and staged files (index)

i to only stash the staged files (index)

"},{"location":"version-control/neogit/#remote-changes","title":"Remote changes","text":"

F to open the pull menu, p to pull changes (fetch and merge) from the remote repository, u t pull from the upstream repository, or e to specify the remote and branch names.

P to open the push menu to open, -u to push to the current remote

Confused when remote is not origin

Use e option to push to elsewhere when the remote name is not set to origin. The e option will prompt for a remote name and branch.

"},{"location":"version-control/neogit/#commit-history","title":"Commit history","text":"

L l to view git commit history log

RET on a log entry shows the commit details in a new window (split)

q to close the commit details window

"},{"location":"version-control/neogit/#modify-git-commit-history","title":"Modify Git commit history","text":"

r opens the rebase menu

"},{"location":"version-control/octo/","title":"Octo - GitHub issues and PRs","text":"

List, create and edit issues and pull requests from Neovim with Octo package.

Octo connects to GitHub via the GitHub CLI, using a developer token for authentication

Neogit provides a Magit style client, creating commits, pull & push changes with remote repositories.

"},{"location":"version-control/octo/#github-interaction","title":"GitHub interaction","text":"

GitHub CLI

Work with GitHub issues and Pull Requests from the comfort of Neovim.

GitHub CLI to authentication to a GitHub account. Successful login creates a local developer token that is used by Octo to communicate with GitHub.

gh auth login\n
"},{"location":"version-control/octo/#octo-commands","title":"Octo commands","text":"

Command line form: Octo <object> <action> [arguments] - Object, Action and Arguments commands

List issues from current project (optionally add a specific repository)

:Octo issue list practicalli/neovim\n

The account/repository-name is required if Octo cannot find the repository

Create a pull requests from current project

:Octo pr create\n

Add a comment to the current topic (issue/pr)

:Octo comment add\n

:Octo gist list\n

Octo.nvim configuration options

Octo.nvim configuration options

"},{"location":"version-control/open-in-github/","title":"Open In GitHub","text":"

Open a file under local version control in the GitHub web UI (browser window).

Neovim

:OpenInGHFile

:OpenInGHRepo

"}]} \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index e5b0ab9d..1bffee47 100644 Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ