Skip to content

Latest commit

 

History

History
437 lines (348 loc) · 21.6 KB

README.md

File metadata and controls

437 lines (348 loc) · 21.6 KB

Jnvim

Table Of Contents

  1. About
    1. Requirements
    2. Structure
    3. Plugins
  2. User API
    1. user_api.types
    2. user_api.util
    3. user_api.opts
    4. user_api.check
    5. user_api.maps
      1. user_api.maps.kmap.desc
      2. user_api.maps.wk
    6. user_api.highlight

About

This is a Nvim configuration, configured in a modular, obsessively documented, portable and platform-independent way. Typed documentation is included.

This configuration uses lazy.nvim as the default plugin manager. Please read the Plugins section to get an understanding of how this works.

This configuration has its core entirely dependant on the user_api module, which provides a customized API which includes module checking, type checking, highlighting functions, options setting, keymap functions, annotations, and more. For more info make sure to check the User API section.

Requirements

This config relies on essential plugins that improve the readability and understanding of how it works. For these to work, the following executables must be installed and in your $PATH:

Structure

/lua
├── config/  <== Folder containing all Lua plugin configurations
│   ├── keymaps.lua  <== Setup default, non-plugin keymaps here
│   ├── lazy.lua  <== Plugin Installation. `plugin._spec` entry points are called here
│   └── util.lua  <== Utilities used in the file above (env checks, etc.)
├── plugin/  <==  Plugins are configured in this directory
│   ├── _spec/  <== Plugin categories are stored here in files serving as categories. `config.lazy` calls this  directory
│   │   ├── essentials.lua  <== Essential plugins. TREAT THIS ONE WITH CARE
│   │   ├── colorschemes.lua  <== Colorscheme plugins
│   │   ├── completion.lua  <== Completion plugins
│   │   ├── editing.lua  <== Editing enhancement plugins
│   │   ├── lsp.lua  <== LSP-related plugins
│   │   ├── neorg.lua  <== Neorg-related plugins
│   │   ├── syntax.lua  <== Syntax plugins
│   │   ├── telescope.lua  <== Telescope-related plugins
│   │   ├── treesitter.lua  <== Treesitter plugins
│   │   ├── ui.lua  <== UI-enhancement plugins
│   │   ├── utils.lua  <== Utilitary plugins
│   │   └── vcs.lua  <== Version Control plugins
│   ├── plugin1/  <== Arbitrary plugin #1
│   │   └── init.lua  <== Entry points + setup
│   ├── plugin2/  <== Arbitrary plugin #2
│   │   ├── init.lua  <== Entry points + setup
│   │   └── submoule.lua  <== Arbitrary submodule
│   └── ...  <==  More plugin configs...
├── user_api/  <== User API module
│   ├── init.lua  <== API entry points
│   ├── check/  <== Checker Functions
│   │   ├── init.lua  <== Entry points are defined here
│   │   ├── exists.lua  <== Existance checkers
│   │   └── value.lua  <== Value checkers
│   ├── commands.lua  <== User-defined commands
│   ├── distro/  <== OS Utilities
│   │   ├── init.lua  <== Entry points are defined here
│   │   └── archlinux.lua  <== Arch Linux utilities
│   ├── highlight.lua  <== Highlight Functions
│   ├── maps/  <== Mapping Utilities
│   │   ├── init.lua  <== Entry points are defined here
│   │   ├── kmap.lua  <== `vim.keymap.set` utilities
│   │   └── wk.lua  <== `which_key` utilities (regardless if installed or not)
│   ├── opts/  <== Vim Option Utilities
│   │   ├── init.lua  <== Entry points are defined here
│   │   ├── all_opts.lua  <== Internal checking utility [DO NOT TOUCH]
│   │   └── config.lua  <== Default options set here
│   ├── update.lua  <== Update utilities
│   ├── util/  <== Misc Utils
│   │   ├── init.lua  <== Entry points are defined here
│   │   ├── autocmd.lua  <== Autocommand utilities
│   │   ├── notify.lua  <== Notification utilities
│   │   └── string.lua  <== String operators/pre-defined lists
│   └── types/  <== Lua Type Annotations and Documentation
│       ├── init.lua  <== Entry points are defined here
│       ├── user/  <== User API Documentation
│       │   ├── init.lua  <== Entry points are defined here
│       │   ├── autocmd.lua  <== Autocommand annotations
│       │   ├── check.lua  <== `check` module annotations
│       │   ├── commands.lua  <== `commands` module annotations
│       │   ├── highlight.lua  <== `highlight` module annotations
│       │   ├── maps.lua  <== `maps` module annotations
│       │   ├── opts.lua  <== `opts` module annotations
│       │   ├── update.lua  <== `update` module annotations (WIP)
│       │   └── util.lua  <== `util` module annotations
└───────└── ...  <== Other annotations

Plugins

There's a lot of plugins included. The plugins are installed based on the files in the lua/plugin/_spec directory. You can create your own category file or expand from the existant files in said directory. Just make sure to read the lazy.nvim documentation for more info on how to install plugins.

Some of the included plugins...


The user API

The user API can be found in lua/user_api. It provides a bunch of functionalities to give easier code structures and to simplify configuration. It's still at an experimental phase, but it works as-is.

user_api.types

This submodule includes type annotations and documentation. It can be found in user_api/types.

  • You can include it by using the following code snippet:
require('user_api.types.module_name')
-- Or by using the entry point (not recommended):
require('user_api').types.module_name

For API-specific documentation, you can find them in the submodule user_api/types/user:

require('user_api.types.user.module_name')
-- Or by using the entry point (not recommended):
require('user_api').types.user.module_name

Each directory serves as an entry point for its pertinent files, sourced by the init.lua file in it.

user_api.opts

This submodule can be found at here. The options are defined in a default table to be processed by the funtion opts.setup().

To call the options:

local Opts1 = require('user_api.opts')
Opts1:setup()
--- Or by using the entry point:
local Opts2 = require('user_api').opts
Opts2:setup()

The setup() function optionally accepts a dictionary-like table with your own vim options. It overwrites some of the default options as defined in opts.lua. MAKE SURE THEY CAN BE ACCEPTED BY vim.opt.

As an example:

local User = require('user_api')
local Opts = User.opts

Opts:setup({
    completeopt = { 'menu', 'menuone', 'noselect', 'noinsert', 'preview' },
    nu = false, -- `:set nonumber`

    -- These equate to `:set tabstop=4 softtabstop=4 shiftwidth=4 expandtab`
    -- In the cmdline
    ts = 4,
    sts = 4,
    sw = 4,
    et = true,

    wrap = false,
})

user_api.check

This is the most important utility for this config. It currently provides a table with two sub-tables. Both used for many conditional checks, aswell as module handling.

These are the following:

  • user_api.check.value Used for value checking, differentiation and conditional code, aswell as for optional parameters in functions. It can be found in user_api/check/value.lua.

    function description parameter types return type
    is_nil Checks whether the input values are nil
    (AKA whether they even exist).
    By default it checks for a single value,
    but can be told to check for multiple
    by setting the 2nd param as true.
    var: unknown|table, multiple: boolean (default: false) boolean
    is_str Checks whether the input values are of string type.
    By default it checks for a single value,
    but can be told to check for multiple
    by setting the 2nd param as true.
    Same as is_nil. boolean
    is_num Checks whether the input values are of number type.
    By default it checks for a single value,
    but can be told to check for multiple
    by setting the 2nd param as true.
    Same as is_nil. boolean
    is_bool Checks whether the input values are of boolean type.
    By default it checks for a single value,
    but can be told to check for multiple
    by setting the 2nd param as true.
    Same as is_nil. boolean
    is_fun Checks whether the input values are of function type.
    By default it checks for a single value,
    but can be told to check for multiple
    by setting the 2nd param as true.
    Same as is_nil. boolean
    is_tbl Checks whether the input values are of table type.
    By default it checks for a single value,
    but can be told to check for multiple
    by setting the 2nd param as true.
    Same as is_nil. boolean
    is_int Checks whether the input values are integers.
    By default it checks for a single value,
    but can be told to check for multiple
    by setting the 2nd param as true.
    Same as is_nil. boolean
    empty If input is a string, checks for an empty string.
    If input is number, checks for value 0.
    If input is table, checks for an empty table.
    If other type return true.
    v: string|number|table boolean
  • user_api.check.exists Used for data existance checks, conditional module loading and fallback operations. It can be found in user_api/check/exists.lua.

    function description parameter types return type
    module Checks whether a require(...) statement is valid, given the input string.
    If 2nd parameter is true, attempt to return said statement if the module can be found.
    mod: string, return_mod: boolean (default: false) boolean|unknown
    modules Checks whether multiple require(...) statements are valid, given the input strings.
    If 2nd parameter is false then check for each string, then stop and return false if one is not valid.
    If 2nd parameter is true, return a dictionary for each key as each input string,
    and a boolean as its respective value.
    mod: string[], need_all: boolean (default: false) boolean|table<string, boolean>
    vim_exists Checks whether a string or multiple strings are true statements using the Vimscript exists() function.
    If a string array is given, check each string and if any string is invalid, return false. Otherwise return true when finished.
    expr: string|string[] boolean
    vim_has Checks whether a string or multiple are true statements when using the Vimscript has() function.
    If a string array is given, check each string and if any string is invalid, return false. Otherwise return true when finished.
    expr: string|string[] boolean
    vim_isdir Checks whether the string is a directory. path: string boolean
    executable Checks whether one or multiple strings are executables found in $PATH.
    If a string array is given, check each string and if any string is invalid and the fallback parameter is a function then execute the fallback function.
    This function will return the result regardless of whether fallback has been set or not.
    exe: string|string[], fallback: fun() (default: nil) boolean

user_api.maps

This module provides keymapping utilities in a more complete, extensible and (hopefully) smarter way for the end user.

The maps.kmap module has the same function names for each mode:

  • maps.kmap.n(...): Same as :nmap
  • maps.kmap.i(...): Same as :imap
  • maps.kmap.v(...): Same as :vmap
  • maps.kmap.t(...): Same as :tmap
  • maps.kmap.o(...): Same as :omap
  • maps.kmap.x(...): Same as :xmap

user_api.maps.kmap.desc

There exists a kmap.desc() method that returns an option table with a description field and other fields corresponding to each parameter.

--- Returns a `vim.keymap.set.Opts` table
---@param msg: string Defaults to `'Unnamed Key'`
---@param silent? boolean Defaults to `true`
---@param bufnr? integer|nil Not included in output table unless explicitly set
---@param noremap? boolean Defaults to `true`
---@param nowait? boolean Defaults to `true`
---@param expr? boolean Defaults to `false`
---@return vim.keymap.set.Opts
require('user_api.maps.kmap').desc(msg, silent, bufnr, noremap, nowait, expr)

The function returns this table:

-- DO NOT COPY THIS DIRECTLY
{
    desc = 'Unnamed Key' or msg, -- First option is the default
    silent = true or false, -- First option is the default
    noremap = true or false, -- First option is the default
    nowait = true or false, -- First option is the default
    expr = false or true, -- First option is the default

    -- If buffer is passed as an argument:
    buffer = bufnr or 0,
}

user_api.maps.wk

The maps API also includes integration with which_key as user_api.maps.wk. It can be found found in user_api/maps.lua

This module creates mappings using custom-made functions that convert a specific type of mapping dictionary to a format compatible with which_key. To understand how this works refer to the aforementioned link to the which_key repository.

This module has the method wk.available(), which simply returns a boolean indicating whether which-key is installed and available to use. Use it, for example, to setup a fallback for setting keys, like in the following example:

local Kmap = require('user_api.maps.kmap')
local WK = require('user_api.maps.wk')

local my_keys = {
    --- Your maps go here...
}

if WK.available() then
    --- Use `WK`
else
    --- Use `Kmap`
end

If you try to use wk.register() despite not being available it'll return false and refuse to process your keymaps altogether.

If you want to convert a keymap table, you must first structure it as follows:

-- Using `vim.keymap.set()` (`User.maps.kmap`) as an example.

---@class KeyMapRhsOptsArr
---@field [1] User.Maps.Keymap.Rhs
---@field [2]? User.Maps.Keymap.Opts

---@alias KeyMapDict table<string, KeyMapRhsOptsArr> A dict with the key as lhs and the value as the class above

---@alias MapMode ('n'|'i'|'v'|'t'|'o'|'x') Vim Mode
---@alias MapModes MapMode[]

---@alias KeyMapModeDict table<MapMode, KeyMapDict>

-- Without modes
---@type KeyMapDict
local Keys1 = {
    ['lhs1'] = { 'rhs1', { desc = 'Keymap 1' } },
    ['lhs2'] = { function() print('this is rhs2') end, { desc = 'Keymap 1', noremap = true } }
}

-- With modes
---@type KeyMapModeDict
local Keys2 = {
    -- Normal Mode Keys
    n = {
        ['n_lhs1'] = { 'n_rhs1', { desc = 'Keymap 1' } },
        ['n_lhs2'] = { function() print('this is n_rhs2') end, { desc = 'Keymap 1', noremap = true } },
    },
    v = {
        ['v_lhs1'] = { 'v_rhs1', { desc = 'Keymap 1 (Visual Mode)' } },
    }
}

You can then pass this dictionary to user_api.maps.map_dict():

  • Example

    -- Following the code above...
    
    local map_dict = require('user_api.maps').map_dict
    
    -- NOTE: Third parameter is `false` because the `Keys1` table doesn't tell what mode to use
    map_dict(Keys1, 'wk.register', false, 'n')
    
    -- NOTE: Third parameter is `true` because the `Keys2` table tells us what modes to use,
    -- so fourth param can be `nil`
    map_dict(Keys2, 'wk.register', true, nil)
  • You can also process keymap groups the following way:

    ---@class RegPfx
    ---@field group string The map group name. Should look like `'+Group'`
    ---@field hidden? boolean Whether to show the map in `which-key`
    ---@field mode? MapModes @see user_api.types.user.maps
    
    ---@alias RegKeysNamed table<string, RegKeysNamed>
    
    ---@type RegKeysNamed
    local Names = {
        ['<leader>X'] = { group = '+Group X' },
        ['<leader>X1'] = { group = '+Subgroup X1' },
    
        ['<leader>t'] = { group = '+Group t' },
    }
    
    -- If `which_key` is available
    if require('user_api.maps.wk').available() then
        require('user_api.maps').map_dict(Names, 'wk.register', false, 'n')
    end

This API component is in early design so it will be simpler and more complete in the future.


user_api.highlight

This module provides utilities for setting highlights in an easier way. It can be found in user_api/highlight.lua.

A description will be pending until further notice, i.e. when the module is structured in a satisfactory manner.