down.lua

Intro

down.lua is a simple ORM for Lua. It is designed to be simple to use and

Is it for you?

todo

Is it better than the alternatives?

todo

Other resources

About

Philosophy

Why?

I started down.lua primarily due to my conflicting captivation and frustration with existing solutions like org-mode and, more recently in the burgeoning Neovim ecosystem, neorg.

Comapare

To org-mode

To marksman

To neorg

Config

Setting up

Options

Commands

Autocommands

Keymaps

Basic Configuration

Advanced Configuration

Extending

Extending with plugins

inits

Extending keymaps

Extending with Autocommands

Modules

Example custom module

local down = require("down")

local mod, config, util = down.mod, down.config, down.util

local M = mod.create("user.example", {
  --- @brief submodules
  ---         child directories containing
  ---         modules to load in tandem, relative
  ---         to this (parent) module.
  --- "subexample",
  --- "pre_example",
  --- ...
})

M.setup = function()
  return {
    requires = {
      ---@brief required modules
      ---         modules from builtin or custom
      ---         modules that can be loaded in (same as
      ---         if calling `require 'module'`) as a dependency
      ---         for the module.
      --- "ui.popup",
      --- "edit.link",
      --- "integration.treesitter",
      --- ...
    },
    loaded = true,
  }
end

---@class (exact) example.Config
M.config = {
  --- @brief module config
  ---          the public facing config for this module that can be
  ---          set by the user from its default values here.
  --- ...
}

---@class example.Data
M.data = {
  --- @brief module data
  ---          the home of the module's internal data and methods
  ---          TODO: split up concerns
  --- ...
}

M.load = function()
  --- @brief module load
  ---          a set of functions to run whenever the
  ---          module is fist loaded upon startup.
  ---          TODO: maybe just merge in with setup()
  --- ...
end

return M

Module Introduction

Examples of user custom modules

Example of a barebones module

---@brief Let's go through the most boilerplate, simple example of a module you may use.
---@brief This module will have no real functionality,
local mod = require "down.mod"


---@brief Let's say you want to create a module for Jupyter notebooks to run in Neovim.
---@brief We'll start by just creating a barebones module, with no functionality, just to show you how.
---@brief We will name this module "jupyter".
---@type down.Mod
local J = mod.create("jupyter", {

  ---@brief This is where we would automatically call any submodules underneath "jupyter" to be called in
  ---@brief simultaneously as it is loaded. Since we do not have any such submodules, we will leave this empty.

})

--[[           1. Flow of functions:

      +-------+  load mod   +------------------+ +------+ +----------+
      | setup |>----------->| cmds, opts, maps |>| load |>| postload |
      +-------+  set data   +------------------+ +------+ +----------+

--]]

---@brief This is where the module will first be `setup`. As you can see above, this occurs before a module has
---@brief fully loaded its data it needs to function. It may, however, perform important functionality during
---@brief this step, such as specifying dependencies it will need, setting up configuration, defining variables,
---@brief or even defining commands and autocommands that will invoke its functionality.
---@brief It must only return a table generally containing a confirmation it has loaded, as well as its
---@brief dependencies, except on rare occasions.
---@return down.mod.Setup
function J.setup()
  ---@class down.mod.Setup
  return {
    loaded = true,
    ---@brief For a jupyter module, we will likely need several dependencies, perhaps too many to list
    ---@brief through in such an early stage. Taking a guess, however, and knowing we can always change,
    ---@brief we'll just choose a few which we will likely need regardless.
    requires = {
      "data",
      "workspace",
      "data.code",
      "ui.progress",
      "ui.status",
      "ui.notify",
      "ui.vtext"
    }
  }
end

---@brief This is where we will set up the module's data and any methods it will call.
---@class down.jupyter.Data
J.data = {

  ---@brief One such piece of data you may wish to store is the ongoing collection of cells, as well
  ---@brief as their contents and type in the Juypyter notebook. You may even wish to leverage the
  ---@brief down.lua `lsp.notebook` module to hook into the LSP for Jupyter notebooks.
  cells = {

  },

  ---@brief To keep track of the notebook currently being interacted with
  notebook = {

    path = nil,

    name = nil,

    kernel = "python3",

  }

}

---@brief Technically, we have now created a proper module that can be loaded into Neovim through down.lua.
---@brief However, we will be typically be best off at the beginning characterizing the module with any
---@brief setup, dependencies, configuration, commands, and even keymaps you believe it may one day need.

---@brief Each modue has a config table specified, which is where the user may set any configuration options
---@brief changing the behaviour of the module.

---@class down.jupyter.Config
---@field kernal string: The kernel to use for the Jupyter user interface. Default is `python3
J.config = {

  ---@brief The default directory you might want to specify for Jupyter notebooks to be stored in.
  ---@brief You may also wish to leverage the required "workspace" module to allow users to specify both
  ---@brief a specific workspace tey would like to associate with Jupyter notebooks, as well as a default
  ---@brief relative directory within that workspace.
  ---
  ---@brief Configuration details about created notebooks. While you are specifying default values here,
  ---@brief consider that a user will likely want to change several of the values.
  notebook = {

    default = "notebook.ipynb",

    dir = {

      workspace = "default",

      default = "notes",
    }

  },

  service = "jupyter",

  command = "jupyterlab",

  kernel = "python3",

  kernels = {
    "python3"
  }

}

---@brief There are many more aspects to a module that can and should be defined as you begin to flesh it out,
---@brief even before you begin to test any major functionality. These include defining commands, options,
---@brief mappings, not to mention learning the interdependencies between your module and other modules,
---@brief whether builtin or custom-made by the community.
---
---@brief Regardless, I hope this has provided a good starting point to help you to take the very first steps
---@brief in creating an awesome module to extend and bless the down.lua ecosystem. Good luck and godspeed!
return J

Example custom module

Note that the below example is out of date and needs to be updated. Thanks!

local down = require("down")

local mod, config, util = down.mod, down.config, down.util

local M = mod.create("user.example", {
  --- @brief submodules
  ---         child directories containing
  ---         modules to load in tandem, relative
  ---         to this (parent) module.
  --- "subexample",
  --- "pre_example",
  --- ...
})

M.setup = function()
  return {
    requires = {
      ---@brief required modules
      ---         modules from builtin or custom
      ---         modules that can be loaded in (same as
      ---         if calling `require 'module'`) as a dependency
      ---         for the module.
      --- "ui.popup",
      --- "edit.link",
      --- "integration.treesitter",
      --- ...
    },
    loaded = true,
  }
end

---@class (exact) example.Config
M.config = {
  --- @brief module config
  ---          the public facing config for this module that can be
  ---          set by the user from its default values here.
  --- ...
}

---@class example.Data
M.data = {
  --- @brief module data
  ---          the home of the module's internal data and methods
  ---          TODO: split up concerns
  --- ...
}

M.load = function()
  --- @brief module load
  ---          a set of functions to run whenever the
  ---          module is fist loaded upon startup.
  ---          TODO: maybe just merge in with setup()
  --- ...
end

return M

---@brief Let's go through the most boilerplate, simple example of a module you may use. ---@brief This module will have no real functionality, local mod = require "down.mod"

---@brief Let's say you want to create a module for Jupyter notebooks to run in Neovim. ---@brief We'll start by just creating a barebones module, with no functionality, just to show you how. ---@brief We will name this module "jupyter". ---@type down.Mod local J = mod.create("jupyter", {

---@brief This is where we would automatically call any submodules underneath "jupyter" to be called in ---@brief simultaneously as it is loaded. Since we do not have any such submodules, we will leave this empty.

})

--[[ 1. Flow of functions:

  +-------+  load mod   +------------------+ +------+ +----------+
  | setup |>----------->| cmds, opts, maps |>| load |>| postload |
  +-------+  set data   +------------------+ +------+ +----------+

--]]

---@brief This is where the module will first be setup. As you can see above, this occurs before a module has ---@brief fully loaded its data it needs to function. It may, however, perform important functionality during ---@brief this step, such as specifying dependencies it will need, setting up configuration, defining variables, ---@brief or even defining commands and autocommands that will invoke its functionality. ---@brief It must only return a table generally containing a confirmation it has loaded, as well as its ---@brief dependencies, except on rare occasions. ---@return down.mod.Setup function J.setup() ---@class down.mod.Setup return { loaded = true, ---@brief For a jupyter module, we will likely need several dependencies, perhaps too many to list ---@brief through in such an early stage. Taking a guess, however, and knowing we can always change, ---@brief we'll just choose a few which we will likely need regardless. requires = { "data", "workspace", "data.code", "ui.progress", "ui.status", "ui.notify", "ui.vtext" } } end

---@brief This is where we will set up the module's data and any methods it will call. ---@class down.jupyter.Data J.data = {

---@brief One such piece of data you may wish to store is the ongoing collection of cells, as well ---@brief as their contents and type in the Juypyter notebook. You may even wish to leverage the ---@brief down.lua lsp.notebook module to hook into the LSP for Jupyter notebooks. cells = {

},

---@brief To keep track of the notebook currently being interacted with notebook = {

path = nil,

name = nil,

kernel = "python3",

}

}

---@brief Technically, we have now created a proper module that can be loaded into Neovim through down.lua. ---@brief However, we will be typically be best off at the beginning characterizing the module with any ---@brief setup, dependencies, configuration, commands, and even keymaps you believe it may one day need.

---@brief Each modue has a config table specified, which is where the user may set any configuration options ---@brief changing the behaviour of the module.

---@class down.jupyter.Config ---@field kernal string: The kernel to use for the Jupyter user interface. Default is `python3 J.config = {

---@brief The default directory you might want to specify for Jupyter notebooks to be stored in. ---@brief You may also wish to leverage the required "workspace" module to allow users to specify both ---@brief a specific workspace tey would like to associate with Jupyter notebooks, as well as a default ---@brief relative directory within that workspace.

---@brief Configuration details about created notebooks. While you are specifying default values here, ---@brief consider that a user will likely want to change several of the values. notebook = {

default = "notebook.ipynb",

dir = {

  workspace = "default",

  default = "notes",
}

},

service = "jupyter",

command = "jupyterlab",

kernel = "python3",

kernels = { "python3" }

}

---@brief There are many more aspects to a module that can and should be defined as you begin to flesh it out, ---@brief even before you begin to test any major functionality. These include defining commands, options, ---@brief mappings, not to mention learning the interdependencies between your module and other modules, ---@brief whether builtin or custom-made by the community.

---@brief Regardless, I hope this has provided a good starting point to help you to take the very first steps ---@brief in creating an awesome module to extend and bless the down.lua ecosystem. Good luck and godspeed! return J

-- TODO: do-over

--- @brief First, import the module class for type suggestions and checking local mod = require "down.mod"

---@brief Your first module will likely be a root (parentless) module. --- Typically, a . separates the name in the module name only if --- it separates the parent module name (left) from the child (right). --- However, you may choose to quickly ---@type word.Mod local M = mod.create("user.mod", { --- @brief submodules --- child directories containing --- modules to load in tandem, relative --- to this (parent) module. --- "subexample", --- "pre_example", --- ... })

M.setup = function() return { requires = { ---@brief required modules --- modules from builtin or custom --- modules that can be loaded in (same as --- if calling require 'module') as a dependency --- for the module. --- "ui.popup", --- "edit.link", --- "integration.treesitter", --- ... }, loaded = true, } end

---@class (exact) example.Config M.config = { --- @brief module config --- the public facing config for this module that can be --- set by the user from its default values here. --- ... }

---@class example.Data M.data = { --- @brief module data --- the home of the module's internal data and methods --- TODO: split up concerns --- ... }

M.load = function() --- @brief module load --- a set of functions to run whenever the --- module is fist loaded upon startup. --- TODO: maybe just merge in with setup() --- ... end

return M

Module quickstart

The core builtin module directory

Accurate as of December 15, 2024

Here is the full guide to all the modules, which I intend to keep largely perminantely in this arrangement so far as I can muster, and so far as it provides a good experience for everyone.

I will also not be changing the names to any of the modules, switching them around willy-nilly, etc., and especially not changing the name of the project, which is down.lua, after its most recent overhaul.

This is a project in its extremely early days, so perhaps I may be laying this down too soon and without any real consequence, but I believe that the system, naming, etc. has congealed to the point where I can safely believe in the foundations it has laid.

[!Tip]

On a lighter note, working on this project for this long has been an incredible pleasure, and I hope I can impart some of the wonderful flights of fancy my mind would necessarily take when stumbling upon what I believed to be a great (at the moment, perhaps) idea. Building an extensible and dev-friendly environment like this, I hope this is something I can share!

The primary core modules are

Below, you will find a list of the primary root core modules builtin to down.lua. There are a few things beyond the obvious that should be stated first:

  1. While I have intended for all modules to be useful in their own right in a context not involving internal use, I do have to note that, like all things, there is a certain variance with regards how accessible a given builtin module is, as well as how much use it may serve to you. To that end, I have tried to begin scaffolding a per-module README.md that should (at some point) provide any others contributing or building on top of down.lua what they may and may not get out of the builtin modules here.

  2. The hierarchy of modules presented here is very important to understand, both with regards its structure and its purpose. This becomes especially important when considering the control flow of the setup process, both for the plugin as a whole and indeed to a lesser degree for the individual modules themselves. It can be easy to at first get lost in the weeds here, but I don't believe it is something that should hinder those exploring the codebase very long at all.

  3. As you can see, nearly allo of the builtin base modules have a number of submodules. A creator of a module which has another module (builtin or external) as its parent may, with the ability to affect the code of the parent, the ability to choose whether the module shouuld be loaded in whenever the parent is loaded in, or to be specified by the user (or through other means: e.g. through configurations, dependencies, and other module interdependencies).

idnamepurposesubmodulesstatus
1cmdprovides the core logic to allow other moduless and users to create their own custom commands.back, mod, rename, findgood! no changes anticipated at the moment besides a few possible refactors.
2dataprovides database and file-storage capabilities, through a variety of means and methods.clipboard, code, dirs, encrypt, export, log, media, metadata, mod, save, sync, tag, template, time, todoessential internally already, but will take time
3editprovides direct editing capabilities when interacting with files, and performs indirect analysis of files.conceal, cursor, find, fold, hl, indent, rk inline, link, parse, syntax, toc, todoessential internally already, but will take time
4lspprovides as much language-server-protocol-enabled functionality as possible without compromising rapidity.command, completion, declaration, definition, document, implementation, moniker, notebook, refactor, reference, type, window, workspacethe lsp development process, not a surprise, will be a rather laborous endeavour
5noteprovides a journaling environment where notes can be created and leveraged in various powerful ways....while more will always be added, the note functionality is fortunately well under way
5toolprovides interoperability with external tooling, enabling emergent possibilities.blink, cmp, coq, dcmp, fzf, lualine, pandoc, telescope, treesitter, troublewhie a few modules are well on their way, there are a few I'd like (blink, telescope, etc.)
5uiprovides internal ui functionality, and may be leveraged by users or devs withing to expand their own environment.calendar, chat, dashboard, icon, nav, popup, progress, prompt, render, sidebar, status, winui as a whole has not been an early priority, and it shows.
5workspaceprovides the core workspace or vault logic, keeping spaces compartmentalized appropriately....the workspace module has been without any issue thus far, although I would like to clean it up.
5configwithout configuration, will initalize a set of default modules most will use, but may be customized....Similarly, no problems with the ultra-simple config module, although I do wish to add meaningful options

Accurate as of December 15, 2024

The full overview of the builtin modules

Hierarchy included!

The hierarchy of modules

...

Further reading on modules

Customizing

Customizing themes

Customizing highlights

Export

Exporting with Pandoc

Exporting with Styling

Publishing

Publishing with Frameworks

Publishing a Blog

Publishing a Wiki

Publishing a Digital Garden

Plans

Short-term Plans

Plans for the Far Future

General Plans

Todos

Contributing

Contributing to Issues

Contributing to Discussions

Sponsorship

Tools

Neovim

Visual Studio Code

Vim

Mobile

Desktop

CLI

Emacs

Introduction to Contributing

Roadmap

down.lua Book Index

About

Roadmap

For next version

For future versions

For later future

Bugs