Compare commits

...

44 Commits
0.0.5 ... main

Author SHA1 Message Date
LeMarsu a4cc5d9b9c feat: can declare extra lua packages 2024-06-18 01:12:08 +02:00
LeMarsu b5a3526f8a chore: bump version 2024-06-10 01:14:35 +02:00
LeMarsu 23c9863c97 feat: add option init config object to generate `init.lua` 2024-06-10 01:08:56 +02:00
LeMarsu b6630684fb feat!: `init.lua` configuration is now a `mkNeovimPkg`'s option
BREAKING CHANGE: The init configuration has moved out of runtime
configuration. It is now in the mkNeovimPkg confuguration.
2024-06-10 01:08:50 +02:00
LeMarsu 815a099805 feat: runtime is now optional
as it should be according to docs...
2024-06-10 00:36:56 +02:00
LeMarsu 3d20bc0ade chore: add alejandra to nix shell 2024-06-09 04:01:18 +02:00
LeMarsu 182c7cd83d chore: bump version 2024-06-09 02:02:47 +02:00
LeMarsu af9565fa95 feat: introduce mkPluginsFromInputs function
This permit creation of plugin before declaration of dependencies. The
biggest benefit is using those on-the-fly plugins in dependencies.
2024-06-09 00:00:56 +02:00
LeMarsu 6c499b1441 fix: plugins with init are now loaded as they should be 2024-06-08 23:57:29 +02:00
LeMarsu cbd08e5258 chore: move back to flake-utils 2024-06-08 20:03:23 +02:00
LeMarsu b36722bfe6 chore: remove sourcesWith fn, using lib.fileset 2024-06-07 20:22:01 +02:00
LeMarsu 61381e2ba0 fix: init/config are loaded to on-the-fly build plugins 2024-06-07 16:20:46 +02:00
LeMarsu da637930bc feat: add describe subcommand 2024-06-05 02:47:46 +02:00
LeMarsu c20336ee60 refactor: filters are now fully dynamic 2024-06-05 02:02:57 +02:00
LeMarsu f50f314c98 feat: Sloth command has now completion 2024-06-05 01:54:41 +02:00
LeMarsu 459eadfae4 chore: bump version 2024-06-04 03:37:08 +02:00
LeMarsu ada07e10d6 chore: switch from nixpkgs `23.11` to `unstable` 2024-06-04 03:35:08 +02:00
LeMarsu f52525abd1 feat: can load lazy plugins on keymaps 2024-06-04 03:26:27 +02:00
LeMarsu 70484e221f feat: can load lazy plugins on events 2024-06-04 03:26:24 +02:00
LeMarsu eb11cfbe1a fix: Sloth list was broken since refactoring 2024-06-04 00:48:37 +02:00
LeMarsu 3d35555ef7 fix: move files instead of copying them
There was left over files in sloth-flake in the store.
2024-06-04 00:47:37 +02:00
LeMarsu cf036bd26c chore: bump version 2024-06-03 03:43:06 +02:00
LeMarsu 2eaecf17a0 fix: init function is called before plugin is loaded 2024-06-03 03:18:44 +02:00
LeMarsu 3732144c33 refactor: deps are now loaded via a FSM 2024-06-03 02:59:42 +02:00
LeMarsu a2bc77f229 refactor: deps provides accessors via metatables 2024-06-03 02:59:42 +02:00
LeMarsu 29e8841a3d refactor: split Sloth subcommands in their own files 2024-06-03 02:59:42 +02:00
LeMarsu ab361c86b4 refactor: extract Sloth command code in its own module 2024-06-03 02:59:42 +02:00
LeMarsu 3204b5a39d refactor: extract all dep logic in Dep object 2024-06-03 02:59:29 +02:00
LeMarsu 9cb43cfd1f flake.lock: Update
Flake lock file updates:

• Updated input 'nil':
    'github:oxalica/nil/2f3ed6348bbf1440fcd1ab0411271497a0fbbfa4' (2024-05-01)
  → 'github:oxalica/nil/ab3ddb8f063774cf7e22eb610f5ecfdb77309f3c' (2024-05-30)
• Updated input 'nil/nixpkgs':
    'github:nixos/nixpkgs/cf8cc1201be8bc71b7cbbbdaf349b22f4f99c7ae' (2024-04-28)
  → 'github:nixos/nixpkgs/ac82a513e55582291805d6f09d35b6d8b60637a1' (2024-05-29)
• Updated input 'nil/rust-overlay':
    'github:oxalica/rust-overlay/9ca720fdcf7865385ae3b93ecdf65f1a64cb475e' (2024-05-01)
  → 'github:oxalica/rust-overlay/095702e63a40e86f339d11864da9dc965b70a01e' (2024-05-30)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/9d29cd266cebf80234c98dd0b87256b6be0af44e' (2024-05-25)
  → 'github:nixos/nixpkgs/25cf937a30bf0801447f6bf544fc7486c6309234' (2024-05-29)
2024-05-31 18:19:05 +02:00
LeMarsu a396afc2c4 feat: add `vimdiffAlias` and `nvimdiffAlias` mkNeovimPkg options 2024-05-31 02:56:27 +02:00
LeMarsu 359462b075 feat: add `viAlias` and `vimAlias` mkNeovimPkg options 2024-05-31 02:44:08 +02:00
LeMarsu 2903d288e2 feat: add `version` Sloth subcommand 2024-05-30 23:44:34 +02:00
LeMarsu d9ba9c8232 doc: fix url in the import example 2024-05-30 03:55:41 +02:00
LeMarsu bf963e67ab chore: bump version 2024-05-30 02:58:39 +02:00
LeMarsu b323cd8396 chore: add CHANGELOG with `git-cliff` 2024-05-30 02:57:35 +02:00
LeMarsu 75bca38fb1 feat: add `Sloth load` subcommand
The command allows you to load plugins
2024-05-30 02:55:11 +02:00
LeMarsu edab526dd0 feat: introduce new Sloth command with list subcommand
Only have a "list" subcommand for now.
The list can be filtered with "all", "loaded", "notloaded"
2024-05-30 02:55:11 +02:00
LeMarsu 3864d3b9b9 fix: prevent `setup` function to be called twice 2024-05-30 02:55:11 +02:00
LeMarsu 805b41ed58 feat: can load lazy plugins on FileType autocommand 2024-05-30 02:55:11 +02:00
LeMarsu cece8f6464 feat: loading plugins respect dependencies option 2024-05-30 02:55:11 +02:00
LeMarsu b087119333 refactor: plugin normalization 2024-05-30 02:55:11 +02:00
LeMarsu 81d82e05a2 feat: can load lazy plugins via placeholder `cmd`s 2024-05-30 02:55:11 +02:00
LeMarsu 5291529e6f feat: can load lazy plugins 2024-05-30 02:55:06 +02:00
LeMarsu 067dec167d chore: delete dead code 2024-05-29 00:20:17 +02:00
23 changed files with 1401 additions and 359 deletions

146
CHANGELOG.md Normal file
View File

@ -0,0 +1,146 @@
# Changelog
All notable changes to this project will be documented in this file.
## [0.0.10] - 2024-06-09
### Features
- Runtime is now optional
- [**breaking**] `init.lua` configuration is now a `mkNeovimPkg`'s option
- Add option init config object to generate `init.lua`
### Miscellaneous Tasks
- Add alejandra to nix shell
## [0.0.9] - 2024-06-09
### Features
- Sloth command has now completion
- Add describe subcommand
- Introduce mkPluginsFromInputs function
### Bug Fixes
- Init/config are loaded to on-the-fly build plugins
- Plugins with init are now loaded as they should be
### Refactor
- Filters are now fully dynamic
### Miscellaneous Tasks
- Remove sourcesWith fn, using lib.fileset
- Move back to flake-utils
## [0.0.8] - 2024-06-04
### Features
- Can load lazy plugins on events
- Can load lazy plugins on keymaps
### Bug Fixes
- Move files instead of copying them
- Sloth list was broken since refactoring
### Miscellaneous Tasks
- Switch from nixpkgs `23.11` to `unstable`
## [0.0.7] - 2024-06-03
### Features
- Add `version` Sloth subcommand
- Add `viAlias` and `vimAlias` mkNeovimPkg options
- Add `vimdiffAlias` and `nvimdiffAlias` mkNeovimPkg options
### Bug Fixes
- Init function is called before plugin is loaded
### Documentation
- Fix url in the import example
### Refactor
- Extract all dep logic in Dep object
- Extract Sloth command code in its own module
- Split Sloth subcommands in their own files
- Deps provides accessors via metatables
- Deps are now loaded via a FSM
## [0.0.6] - 2024-05-30
### Features
- Can load lazy plugins
- Can load lazy plugins via placeholder `cmd`s
- Loading plugins respect dependencies option
- Can load lazy plugins on FileType autocommand
- Introduce new Sloth command with list subcommand
- Add `Sloth load` subcommand
### Bug Fixes
- Prevent `setup` function to be called twice
### Refactor
- Plugin normalization
### Miscellaneous Tasks
- Delete dead code
- Add CHANGELOG with `git-cliff`
## [0.0.5] - 2024-05-28
### Features
- Add real documentation
### Bug Fixes
- Give default init.lua if none provided
- Remove namePrefix and nameSuffix
### Miscellaneous Tasks
- Refactor lua generation
- Remove dead code
## [0.0.4] - 2024-05-28
### Features
- Generating plugins lua definition from nix
- Simplify lua api
## [0.0.3] - 2024-05-26
### Features
- Rename neofalke to sloth-flake.nvim
- Check inputs of functions with yants
## [0.0.2] - 2024-05-26
### Features
- Can give dependencies to new package
- Can build package with all config
- Remove neovim from nix-shell
- Neoflake and runtime plugin have their version
### Miscellaneous Tasks
- Release v0.0.2
<!-- generated by git-cliff -->

203
README.md
View File

@ -8,15 +8,20 @@ A [neovim] plugin and configuration management plugin, highly inspired by [lazy]
- [Features](#features) - [Features](#features)
- [SemVer](#semver) - [SemVer](#semver)
- [Installation](#installation) - [Installation](#installation)
- [Flake installation](#flake-installation) - [Flake installation](#flake-installation)
- [Usage](#usage) - [Usage](#usage)
- [Documentation](#documentation) - [Documentation](#documentation)
- [nix](#nix) - [nix](#nix)
- [`mkNeovimPkg`](#mkneovimpkg) - [`mkPluginsFromInputs`](#mkpluginsfrominputs)
- [neovim (lua)](#neovim-lua) - [`mkNeovimPkg`](#mkneovimpkg)
- [Using default `init.lua`](#using-default-initlua) - [neovim (lua)](#neovim-lua)
- [Using your own `init.lua`](#using-your-own-initlua) - [Using default `init.lua`](#using-default-initlua)
- [API](#api) - [Using your own `init.lua`](#using-your-own-initlua)
- [`:Sloth` command](#sloth-command)
- [`list` subcommand](#list-subcommand)
- [`load` subcommand](#load-subcommand)
- [`version` subcommand](#version-subcommand)
- [API](#api)
<!-- TOC --> <!-- TOC -->
@ -37,12 +42,13 @@ A [neovim] plugin and configuration management plugin, highly inspired by [lazy]
- [X] Generate nix package from local files - [X] Generate nix package from local files
- [X] Generate default `init.lua` - [X] Generate default `init.lua`
- [X] Accepts your own `init.lua` - [X] Accepts your own `init.lua`
- [ ] Lazy load your plugins - [X] Lazy load your plugins
- [ ] on command - [X] on command
- [ ] on filetype - [X] on filetype
- [ ] on event - [X] on event
- [ ] on keybinding - [X] on keybinding
- [ ] load plugins in order (via plugin `dependencies` property) - [X] load plugins in order (via plugin `dependencies` property)
- [X] Have a `:Sloth` command to load or query your plugins
- [ ] Generate spell files on build (maybe) - [ ] Generate spell files on build (maybe)
## SemVer ## SemVer
@ -75,7 +81,7 @@ inputs.sloth-flake.url = "github:lemarsu/sloth-flake.nvim";
You can give a specific version: You can give a specific version:
```nix ```nix
inputs.sloth-flake.url = "github:lemarsu/sloth-flake.nvim?ref=0.0.5"; inputs.sloth-flake.url = "github:lemarsu/sloth-flake.nvim?tag=0.0.5";
``` ```
## Usage ## Usage
@ -87,6 +93,8 @@ Once installed, you can call the `sloth-flake.lib.mkNeovimPkg` to build your neo
```nix ```nix
sloth-flake.lib.mkNeovimPkg { sloth-flake.lib.mkNeovimPkg {
inherit pkgs; inherit pkgs;
viAlias = true;
vimAlias = true;
runtime = { runtime = {
version = "0.1"; version = "0.1";
src = sloth-flake.lib.sourcesWith ./. [ src = sloth-flake.lib.sourcesWith ./. [
@ -115,30 +123,95 @@ sloth-flake.lib.mkNeovimPkg {
### nix ### nix
#### `mkPluginsFromInputs`
`mkPluginsFromInputs` is a helper function that converts flake inputs (starting by `"plugin-"` by default) into vimPlugins.
Example:
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
sloth-flake.url = "github:lemarsu/sloth-flake.nvim";
utils.url = "github:numtide/flake-utils";
plugin-base64 = {
url = "github:moevis/base64.nvim";
flake = false;
};
plugin-cellular-automaton = {
url = "github:eandrju/cellular-automaton.nvim";
flake = false;
};
};
outputs = {utils, sloth-flake, ...}@inputs: let
fu = utils.lib;
in fu.eachDefaultSystem (system: let
plugins = sloth-flake.lib.mkPluginsFromInputs {
inherit pkgs inputs;
};
in {
packages = rec {
default = neovim;
neovim = pkgs.callPackage ./package.nix {
# By adding `plugins` here, we can use `with plugins; base64 cellular-automaton`,
inherit plugins sloth-flake;
};
};
};
}
```
The function accepts the following attributes:
- `pkgs` **REQUIRED** the nixpkgs set.
- `inputs` **REQUIRED** the inputs from a flake.
- `predicate` **optional** predicate to filter input by name. By default, it's
filter inputs with `hasPrefix "plugin-"`.
- `nameMap` **optional** function to change the key of the input in the resulting
set. By default, the 7 first letters are removed, so to remove the "plugin-"
prefix.
- `buildVimPlugin` **optional** function used to build the plugin. Defaults to
`pkgs.vimUtils.buildVimPlugin`.
#### `mkNeovimPkg` #### `mkNeovimPkg`
`mkNeovimPkg` requires only the `pkgs` argument. `mkNeovimPkg` requires only the `pkgs` argument.
Here's a list of all accepted arguments Here's a list of all accepted arguments
| name | default | description | | name | default | description |
|-------------------------|-------------------------|----------------------------------------------------------| |-------------------------|-------------------------|---------------------------------------------------------------------|
| `pkgs` | N/A | The nixpkgs set. **REQUIRED** | | `pkgs` | N/A | The nixpkgs set. **REQUIRED** |
| `package` | `pkgs.neovim-unwrapped` | The unwrapped neovim package to use | | `package` | `pkgs.neovim-unwrapped` | The unwrapped neovim package to use |
| `runtime` | `{}` | Your Runtime configuration (see below) | | `init` | `null` | The `init.lua` of your config (string, path or init config object)¹ |
| `dependencies` | `[]` | A list of your dependencies (see below) | | `runtime` | `{}` | Your Runtime configuration (see below) |
| `dependenciesExtraArgs` | `{}` | Extra arguments to load your dependencies in other files | | `dependencies` | `[]` | A list of your dependencies (see below) |
| `dependenciesExtraArgs` | `{}` | Extra arguments to load your dependencies in other files |
| `extraLuaPackages` | `null` | Extra lua packages needed for the plugin |
| `viAlias` | `false` | Wether to create a `vi` alias to run neovim |
| `vimAlias` | `false` | Wether to create a `vim` alias to run neovim |
| `vimdiffAlias` | `false` | Wether to create a `vimdiff` alias to run neovim in diff mode |
| `nvimdiffAlias` | `false` | Wether to create a `nvimdiff` alias to run neovim in diff mode |
> ¹ If you give your own `init.lua` as string or path, you'll have to call `sloth-flake` lua plugin yourself. See more below.
The init configuration object accepts the following properties:
| name | default | description |
|------------|---------|----------------------------------------------------------------------------|
| `init` | `null` | Lua code call before plugins init. String or path. |
| `postInit` | `null` | Lua code call after plugins init and before plugin config. String or path. |
| `config` | `null` | Luas cod call after plugins config. String or path. |
The Runtime configuration object accepts the following properties: The Runtime configuration object accepts the following properties:
| name | default | description | | name | default | description |
|-----------|---------|--------------------------------| |-----------|---------|--------------------------------|
| `version` | `null` | The version of your runtime | | `version` | `null` | The version of your runtime |
| `init` | `null` | The `init.lua` of your config¹ |
| `src` | `null` | The content of your runtime | | `src` | `null` | The content of your runtime |
> ¹ If you give your own `init.lua`, you'll have to call `sloth-flake` lua plugin yourself. See more below.
The dependencies is a list of element of either: The dependencies is a list of element of either:
- path: the path of the file to load other dependencies - path: the path of the file to load other dependencies
- package: a nix package of a neovim/vim plugin - package: a nix package of a neovim/vim plugin
@ -146,24 +219,49 @@ The dependencies is a list of element of either:
The Plugin configuration object accepts the following properties: The Plugin configuration object accepts the following properties:
| name | default | description | | name | default | description |
|----------------|---------|-----------------------------------------------------------------| |--------------------|---------|----------------------------------------------------------------|
| `plugin` | N/A | The plugin to load² **REQUIRED** | | `plugin` | N/A | The plugin to load² **REQUIRED** |
| `init` | `null` | lua code (as string of path) to call before loading the plugin³ | | `init` | `null` | Lua code (as string of path) to call before loading the plugin |
| `config` | `null` | lua code (as string of path) to call after loading the plugin | | `config` | `null` | Lua code (as string of path) to call after loading the plugin |
| `dependencies` | [] | The plugin dependencies⁴ | | `dependencies` | `[]` | The plugin dependencies³ |
| `extraLuaPackages` | `null` | Extra lua packages needed for the plugin |
| `lazy` | `false` | Should the plugin be loaded lazily |
| `cmd` | `[]` | Command to put as place_holder to load the lazy plugin⁴ |
| `ft` | `[]` | Filetype to watch to load the lazy plugin⁴ |
| `events` | `[]` | Events to watch to load the lazy plugin⁴⁵ |
| `keymaps` | `[]` | Keymaps that when press will load the lazy plugin⁴⁶ |
> ² The plugin can be either a nix package or an object with only `name` and > ² The plugin can be either a nix package or an object with only `name` and
> `src` as properties. The latter will be used to create a nix package of your > `src` as properties. The latter will be used to create a nix package of your
> plugin on the fly. > plugin on the fly.
> ³ Not yet implemented. The function is called, but the plugin is already loaded. > ³ `nix` handles the installation of your plugin, therefore, this list is
> **NOT** to declare dependencies that the nix package of the plugin doesn't
> know. This will tell `sloth-flake` in what order your plugins should be
> loaded.
> ⁴ Not yet implemented. `nix` handles the installation of your plugin, > ⁴ Setting this property implicitly set `lazy` to `true`.
> therefore, this list is **NOT** to declare dependencies that the nix package
> of the plugin doesn't know. This will tell `sloth-flake` in what order your > ⁵ Events can be a string, an Event object or a list of either. You can
> plugins should be loaded... when `sloth-flake` will handle asynchronous > represent a simple event name and pattern with the following string format :
> loading... (Soon™). > "BufRead *.md".
> ⁶ Keymaps can be a string, an Keymap object or a list of either.
The Event configuration object accepts the following properties:
| name | default | description |
|-----------|---------|----------------------------------------------------------------|
| `name` | N/A | The name of the event as string or list of string **REQUIRED** |
| `pattern` | `null` | Pattern (as string or list of string) associated to the event |
The Keymap configuration object accepts the following properties:
| name | default | description |
|-----------|---------|----------------------------------------------------|
| `mode` | `"n"` | The mode of the keymap as string or list of string |
| `mapping` | N/A | The actual mapping **REQUIRED** |
### neovim (lua) ### neovim (lua)
@ -195,6 +293,39 @@ sloth_flake.setup {
-- From here, your plugins are loaded and their optional `config` function called -- From here, your plugins are loaded and their optional `config` function called
``` ```
#### `:Sloth` command
`sloth-flake` give a `Sloth` command that you can call to gather some
informations about or load your plugins.
Usage: `Sloth [command] [args...]`
If no arguments are given, the `Sloth` command will call the `list` subcommand.
##### `list` subcommand
Summary: List plugins.
Usage: `Sloth list [filter]`
- `filter`: filter the list of plugins.
- `all`: list all declared plugins. Same as if no filter is given.
- `loaded`: list only loaded plugins.
- `notloaded`: list only not loaded plugins.
##### `load` subcommand
Summary: Load lazy plugins.
Usage: `Sloth load <plugin> [plugin [...]]`
- `plugin`: a plugin to load
##### `version` subcommand
Summary: Return Sloth version
Usage: `Sloth version`
#### API #### API
The lua API is not really defined yet. This documentation will be completed then. The lua API is not really defined yet. This documentation will be completed then.

View File

@ -1 +1 @@
0.0.5 0.0.10

87
cliff.toml Normal file
View File

@ -0,0 +1,87 @@
# git-cliff ~ default configuration file
# https://git-cliff.org/docs/configuration
#
# Lines starting with "#" are comments.
# Configuration options are organized into tables and keys.
# See documentation for more information on available options.
[changelog]
# changelog header
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
# template for the changelog body
# https://keats.github.io/tera/docs/#introduction
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}\n
"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
<!-- generated by git-cliff -->
"""
# postprocessors
postprocessors = [
# { pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" }, # replace repository URL
]
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
# { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, # replace issue numbers
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "<!-- 1 -->Features" },
{ message = "^fix", group = "<!-- 2 -->Bug Fixes" },
{ message = "^doc", group = "<!-- 3 -->Documentation" },
{ message = "^perf", group = "<!-- 4 -->Performance" },
{ message = "^refactor", group = "<!-- 5 -->Refactor" },
{ message = "^style", group = "<!-- 6 -->Styling" },
{ message = "^test", group = "<!-- 7 -->Testing" },
{ message = "^chore\\(release\\): prepare for", skip = true },
{ message = "^chore\\(deps\\)", skip = true },
{ message = "^chore\\(pr\\)", skip = true },
{ message = "^chore\\(pull\\)", skip = true },
{ message = "^chore: bump version", skip = true },
{ message = "^chore|ci", group = "<!-- 8 -->Miscellaneous Tasks" },
{ message = "^flake\\.lock: Update", skip = true },
{ body = ".*security", group = "<!-- 9 -->Security" },
{ message = "^revert", group = "<!-- 10 -->Revert" },
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# filter out the commits that are not matched by commit parsers
filter_commits = false
# regex for matching git tags
tag_pattern = "[0-9].*"
breaking_always_bump_major = false
# regex for skipping tags
skip_tags = "v0.1.0-beta.1"
# regex for ignoring tags
ignore_tags = ""
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
# limit the number of commits included in the changelog.
# limit_commits = 42

View File

@ -63,24 +63,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flakeCompat": { "flakeCompat": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -104,11 +86,11 @@
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
}, },
"locked": { "locked": {
"lastModified": 1714571717, "lastModified": 1717086091,
"narHash": "sha256-o4tqlTzi9kcVub167kTGXgCac9jM3kW4+v9MH/ue4Hk=", "narHash": "sha256-GmsEQa4HZeMfec37LZnwG/Lt/XmqFLXsjv5QWojeNiM=",
"owner": "oxalica", "owner": "oxalica",
"repo": "nil", "repo": "nil",
"rev": "2f3ed6348bbf1440fcd1ab0411271497a0fbbfa4", "rev": "ab3ddb8f063774cf7e22eb610f5ecfdb77309f3c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -119,11 +101,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1714314149, "lastModified": 1716977081,
"narHash": "sha256-yNAevSKF4krRWacmLUsLK7D7PlfuY3zF0lYnGYNi9vQ=", "narHash": "sha256-pFe5jLeIPlKEln5n2h998d7cpzXFdbrBMRe3suz4K1o=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "cf8cc1201be8bc71b7cbbbdaf349b22f4f99c7ae", "rev": "ac82a513e55582291805d6f09d35b6d8b60637a1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -135,16 +117,16 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1716633019, "lastModified": 1717196966,
"narHash": "sha256-xim1b5/HZYbWaZKyI7cn9TJCM6ewNVZnesRr00mXeS4=", "narHash": "sha256-yZKhxVIKd2lsbOqYd5iDoUIwsRZFqE87smE2Vzf6Ck0=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9d29cd266cebf80234c98dd0b87256b6be0af44e", "rev": "57610d2f8f0937f39dbd72251e9614b1561942d8",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "nixos",
"ref": "nixos-23.11", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -202,11 +184,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1714529851, "lastModified": 1717035469,
"narHash": "sha256-YMKJW880f7LHXVRzu93xa6Ek+QLECIu0IRQbXbzZe38=", "narHash": "sha256-MzH+yjKULH3HCRj9QCTwBvqq4LZkR0ZqRE/QfGOGC2E=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "9ca720fdcf7865385ae3b93ecdf65f1a64cb475e", "rev": "095702e63a40e86f339d11864da9dc965b70a01e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -247,20 +229,19 @@
}, },
"utils": { "utils": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_2" "systems": "systems_2"
}, },
"locked": { "locked": {
"lastModified": 1696281284, "lastModified": 1710146030,
"narHash": "sha256-xcmtTmoiiAOSk4abifbtqVZk0iwBcqJfg47iUbkwhcE=", "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "gytis-ivaskevicius", "owner": "numtide",
"repo": "flake-utils-plus", "repo": "flake-utils",
"rev": "6cf1e312fb259693c4930d07ca3cbe1d07ef4a48", "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "gytis-ivaskevicius", "owner": "numtide",
"ref": "v1.4.0", "repo": "flake-utils",
"repo": "flake-utils-plus",
"type": "github" "type": "github"
} }
}, },

View File

@ -2,8 +2,8 @@
description = "My neovim configuration"; description = "My neovim configuration";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11"; nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
utils.url = "github:gytis-ivaskevicius/flake-utils-plus/v1.4.0"; utils.url = "github:numtide/flake-utils";
nil.url = "github:oxalica/nil"; nil.url = "github:oxalica/nil";
yants.url = "github:divnix/yants"; yants.url = "github:divnix/yants";
alejandra = { alejandra = {
@ -20,24 +20,25 @@
yants, yants,
... ...
} @ inputs: let } @ inputs: let
versionFile = builtins.replaceStrings ["\n"] [""] (builtins.readFile ./VERSION); inherit (builtins) readFile replaceStrings;
fu = utils.lib;
versionFile = replaceStrings ["\n"] [""] (readFile ./VERSION);
version =
if self.sourceInfo ? dirtyShortRev
then "${versionFile}-${self.sourceInfo.dirtyShortRev}"
else versionFile;
version = if self.sourceInfo ? dirtyShortRev forSystem = system: let
then "${versionFile}-${self.sourceInfo.dirtyShortRev}" pkgs = nixpkgs.legacyPackages.${system};
else versionFile; formatter = alejandra.defaultPackage.${system};
in inherit (inputs.nil.packages.${system}) nil;
utils.lib.mkFlake { in {
inherit self inputs; inherit formatter;
outputsBuilder = channel: let devShells.default = import ./shell.nix {
system = channel.nixpkgs.system; inherit pkgs nil formatter;
in {
formatter = alejandra.defaultPackage.${channel.nixpkgs.system};
devShells.default = import ./shell.nix {
pkgs = channel.nixpkgs;
inherit (inputs.nil.packages.${system}) nil;
};
}; };
lib = import ./lib {inherit version yants;};
}; };
in
(fu.eachDefaultSystem forSystem)
// {lib = import ./lib {inherit version yants;};};
} }

View File

@ -1,152 +0,0 @@
# Imported from home-manager. Couldn't find another way to access it
{
homeDirectory,
lib,
pkgs,
}: let
inherit
(lib)
hasPrefix
hm
literalExpression
mkDefault
mkIf
mkOption
removePrefix
types
;
in rec {
# Constructs a type suitable for a `home.file."specific/path"` like option. The
# target path may be either absolute or relative, in which case it
# is relative the `basePath` argument (which itself must be an
# absolute path).
#
# Arguments:
# - opt the name of the option, for self-references
# - basePathDesc docbook compatible description of the base path
# - basePath the file base path
fileTypeSubmodule = opt: basePathDesc: basePath:
types.submodule ({
name,
config,
...
}: {
options = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether this file should be generated. This option allows specific
files to be disabled.
'';
};
target = mkOption {
type = types.str;
apply = p: let
absPath =
if hasPrefix "/" p
then p
else "${basePath}/${p}";
in
removePrefix (homeDirectory + "/") absPath;
defaultText = literalExpression "name";
description = ''
Path to target file relative to ${basePathDesc}.
'';
};
text = mkOption {
default = null;
type = types.nullOr types.lines;
description = ''
Text of the file. If this option is null then
[](#opt-${opt}._name_.source)
must be set.
'';
};
source = mkOption {
type = types.path;
description = ''
Path of the source file or directory. If
[](#opt-${opt}._name_.text)
is non-null then this option will automatically point to a file
containing that text.
'';
};
executable = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Set the execute bit. If `null`, defaults to the mode
of the {var}`source` file or to `false`
for files created through the {var}`text` option.
'';
};
recursive = mkOption {
type = types.bool;
default = false;
description = ''
If the file source is a directory, then this option
determines whether the directory should be recursively
linked to the target location. This option has no effect
if the source is a file.
If `false` (the default) then the target
will be a symbolic link to the source directory. If
`true` then the target will be a
directory structure matching the source's but whose leafs
are symbolic links to the files of the source directory.
'';
};
onChange = mkOption {
type = types.lines;
default = "";
description = ''
Shell commands to run when file has changed between
generations. The script will be run
*after* the new files have been linked
into place.
Note, this code is always run when `recursive` is
enabled.
'';
};
force = mkOption {
type = types.bool;
default = false;
visible = false;
description = ''
Whether the target path should be unconditionally replaced
by the managed file source. Warning, this will silently
delete the target regardless of whether it is a file or
link.
'';
};
};
config = {
target = mkDefault name;
source = mkIf (config.text != null) (mkDefault (pkgs.writeTextFile {
inherit (config) text;
executable = config.executable == true; # can be null
name = hm.strings.storeFileName name;
}));
};
});
# Constructs a type suitable for a `home.file` like option. The
# target path may be either absolute or relative, in which case it
# is relative the `basePath` argument (which itself must be an
# absolute path).
#
# Arguments:
# - opt the name of the option, for self-references
# - basePathDesc docbook compatible description of the base path
# - basePath the file base path
fileTypeAttrSet = opt: basePathDesc: basePath:
types.attrsOf (fileTypeSubmodule opt basePathDesc basePath);
}

View File

@ -1,18 +1,9 @@
{version, yants}: let {
version,
yants,
}: let
types = import ./types.nix {inherit yants;}; types = import ./types.nix {inherit yants;};
in { in {
mkNeovimPkg = import ./mkNeovimPkg.nix {inherit version types;}; mkNeovimPkg = import ./mkNeovimPkg.nix {inherit version types;};
mkPluginsFromInputs = import ./mkPluginsFromInputs.nix;
sourcesWith = path: paths: let
samePath = a: let a' = builtins.toString a; in b: a' == builtins.toString b;
isRoot = samePath "/";
isInPath = path: subPath:
if isRoot subPath
then false
else (samePath path subPath) || (isInPath path (builtins.dirOf subPath));
filter = src: _type: builtins.any (includePath: isInPath includePath src) paths;
in
builtins.path {
inherit path filter;
};
} }

View File

@ -6,18 +6,29 @@
types, types,
... ...
}: let }: let
inherit (builtins) isPath foldl'; inherit (builtins) foldl' isPath isList isString mapAttrs match elemAt;
inherit (lib.attrsets) attrNames optionalAttrs; inherit (lib.attrsets) attrNames optionalAttrs;
inherit (lib.lists) concatMap; inherit (lib.lists) concatMap;
inherit (lib.strings) fileContents; inherit (lib.strings) fileContents splitString;
lua = callPackage ./lua.nix {}; lua = callPackage ./lua.nix {};
callPackage = lib.callPackageWith (pkgs // dependenciesExtraArgs); callPackage = lib.callPackageWith (pkgs // dependenciesExtraArgs);
hasMatch = pattern: str: isList (match pattern str);
wrapArray = value:
if isList value
then value
else [value];
defaultPlugin = { defaultPlugin = {
enabled = true; enabled = true;
init = null; init = null;
config = null; config = null;
dependencies = [];
lazy = false;
cmd = [];
ft = [];
events = [];
keymaps = [];
}; };
remotePluginToNeovimPlugin = p: remotePluginToNeovimPlugin = p:
@ -26,20 +37,64 @@
pname = name; pname = name;
}; };
defaultKeymap = {mode = "n";};
normalizeKeymap = keymap: let
value = (
if isString keymap
then {mapping = keymap;}
else keymap
);
in
mapAttrs (_: wrapArray) (defaultKeymap // value);
normalizeKeymaps = keymaps:
if isList keymaps
then map normalizeKeymap keymaps
else [(normalizeKeymap keymaps)];
normalizeEvent = event: let
value =
if ! isString event
then event
else if ! hasMatch ".* .*" event
then {name = event;}
else let
part = elemAt (splitString " " event);
in {
name = part 0;
pattern = part 1;
};
in
mapAttrs (_: wrapArray) value;
normalizeEvents = events:
if isList events
then map normalizeEvent events
else [(normalizeEvent events)];
withPluginDefaults = dep: defaultPlugin // dep; withPluginDefaults = dep: defaultPlugin // dep;
normalizePlugin = d: let normalizePlugin = d: let
dep = types.dependency d; dep = types.dependency d;
p = plugin =
if ! dep ? plugin if ! dep ? plugin
then {plugin = dep;} then {plugin = dep;}
else let else let
inherit (dep) plugin; inherit (dep) plugin;
in in
if attrNames plugin == ["name" "src"] if attrNames plugin == ["name" "src"]
then {plugin = remotePluginToNeovimPlugin plugin;} then dep // {plugin = remotePluginToNeovimPlugin plugin;}
else dep; else dep;
p = withPluginDefaults plugin;
in in
withPluginDefaults p; p
// rec {
hasCommands = p.cmd != [];
hasFileTypes = p.ft != [];
keymaps = normalizeKeymaps p.keymaps;
hasKeymaps = p.keymaps != [];
events = normalizeEvents p.events;
hasEvents = p.events != [];
lazy = p.lazy || hasCommands || hasFileTypes || hasEvents || hasKeymaps;
optional = lazy || p.init != null;
};
normalizeOrImportPlugin = dep: normalizeOrImportPlugin = dep:
if isPath dep if isPath dep
@ -67,25 +122,32 @@
vimUtils.buildVimPlugin { vimUtils.buildVimPlugin {
inherit version; inherit version;
pname = "sloth-flake"; pname = "sloth-flake";
src = ../lua/sloth-flake; src = with lib.fileset;
toSource {
root = ../.;
fileset = ../lua/sloth-flake;
};
buildPhase = '' buildPhase = ''
dir=lua/sloth-flake dir=lua/sloth-flake
mkdir -p $dir
mv init.lua $dir
cat <<'LUA' > $dir/deps.lua cat <<'LUA' > $dir/dependencies.lua
return ${pluginsLuaDef plugins} ${pluginsLuaDef plugins}
LUA
cat <<'LUA' > $dir/version.lua
${versionLua version}
LUA LUA
''; '';
}; };
versionLua = version: with lua; nix2lua (return (lambda (return version)));
textOrContent = content: textOrContent = content:
if isPath content if isPath content
then fileContents content then fileContents content
else content; else content;
pluginLuaDef = memo: plugin: let pluginLuaDef = memo: plugin: let
# plugin = builtins.removeAttrs plugin ["dependencies" "plugin"];
mkTypeFn = type: let mkTypeFn = type: let
content = textOrContent plugin.${type}; content = textOrContent plugin.${type};
in in
@ -96,24 +158,39 @@
if plugin ? pname if plugin ? pname
then plugin.pname then plugin.pname
else plugin.name; else plugin.name;
hasDeps = plugin ? dependencies && plugin.dependencies != [];
name = pluginName plugin.plugin; name = pluginName plugin.plugin;
in in
memo memo
// { // {
${name} = ${name} =
{name = pluginName plugin.plugin;} {
name = pluginName plugin.plugin;
dependencies = map pluginName plugin.dependencies;
}
// (mkTypeFn "init") // (mkTypeFn "init")
// (mkTypeFn "config") // (mkTypeFn "config")
// (optionalAttrs hasDeps { // (optionalAttrs plugin.lazy {
dependencies = map pluginName plugin.dependencies; lazy = true;
})
// (optionalAttrs plugin.hasCommands {
inherit (plugin) cmd;
})
// (optionalAttrs plugin.hasFileTypes {
inherit (plugin) ft;
})
// (optionalAttrs plugin.hasEvents {
inherit (plugin) events;
})
// (optionalAttrs plugin.hasKeymaps {
inherit (plugin) keymaps;
}); });
}; };
pluginsLuaDef = plugins: lua.nix2lua (foldl' pluginLuaDef {} plugins); pluginsLuaDef = plugins:
with lua; nix2lua (return (foldl' pluginLuaDef {} plugins));
in { in {
inherit normalizePlugin;
inherit normalizePlugins; inherit normalizePlugins;
inherit mkSlothFlakePlugin; inherit mkSlothFlakePlugin;
inherit mkRuntimePlugin; inherit mkRuntimePlugin;
inherit textOrContent; inherit textOrContent;
inherit pluginsLuaDef;
} }

View File

@ -1,5 +1,4 @@
{lib, ...}: let {...}: let
inherit (lib.strings) removeSuffix;
inherit (builtins) match isNull typeOf concatStringsSep attrNames concatMap; inherit (builtins) match isNull typeOf concatStringsSep attrNames concatMap;
commaJoin = concatStringsSep ", "; commaJoin = concatStringsSep ", ";

View File

@ -6,35 +6,110 @@
package ? pkgs.neovim-unwrapped, package ? pkgs.neovim-unwrapped,
dependencies ? [], dependencies ? [],
dependenciesExtraArgs ? {}, dependenciesExtraArgs ? {},
runtime ? {}, extraLuaPackages ? (_: []),
runtime ? null,
init ? null,
viAlias ? false,
vimAlias ? false,
vimdiffAlias ? false,
nvimdiffAlias ? false,
... ...
} @ config: let } @ config: let
inherit (builtins) map; inherit (builtins) isString isPath map;
inherit (pkgs) callPackage; inherit (pkgs) callPackage bash lib;
# inherit (lib.lists) concatMap filter foldl' map optional reverseList; inherit (lib.strings) optionalString;
# inherit (lib.attrsets) attrNames optionalAttrs; inherit (lib.lists) concatMap optional;
# inherit (lib.strings) concatStringsSep fileContents hasSuffix removePrefix removeSuffix replaceStrings; inherit (lib.trivial) flip;
# inherit (lib.debug) traceIf traceSeq traceVal traceValSeq traceValFn; inherit (lib.attrsets) optionalAttrs;
deps = callPackage ./deps.nix {inherit dependenciesExtraArgs types;}; deps = callPackage ./deps.nix {inherit dependenciesExtraArgs types;};
sloth-flake.plugin = deps.mkSlothFlakePlugin version plugins; normalizedPlugins = deps.normalizePlugins dependencies;
runtimePlugin.plugin = deps.mkRuntimePlugin runtime; sloth-flake = deps.mkSlothFlakePlugin version normalizedPlugins;
plugins = deps.normalizePlugins (dependencies ++ [runtimePlugin sloth-flake]); runtimePlugin = deps.mkRuntimePlugin runtime;
plugins =
normalizedPlugins
++ (
deps.normalizePlugins
([sloth-flake] ++ (optional (runtime != null) runtimePlugin))
);
extractPlugin = map (p: p.plugin); extractPlugin = p: {inherit (p) optional plugin;};
extractPlugins = map extractPlugin;
customRC = let extractLuaPackageFn = plugin:
rc = ({init ? ../lua/default_init.lua, ...}: init) runtime; optional (plugin ? extraLuaPackages) plugin.extraLuaPackages;
extractLuaPackagesFn = plugins: let
fnList = concatMap extractLuaPackageFn plugins;
concatPackages = ps: fn: fn ps;
in in
deps.textOrContent rc; ps: concatMap (concatPackages ps) fnList;
buildInit = {
init ? null,
postInit ? null,
config ? null,
}: let
initStr = optionalString (! isNull init) ''
(function()
${deps.textOrContent init}
end)();
'';
slothCall =
if isNull postInit
then "require('sloth-flake').setup {}"
else ''
require('sloth-flake').setup {
post_init = function()
${deps.textOrContent postInit}
end,
};
'';
configStr = optionalString (! isNull config) ''
(function()
${deps.textOrContent config}
end)()
'';
in ''
-- Generated by sloth-flake
${initStr}
${slothCall}
${configStr}
'';
customRC =
if isString init || isPath init
then deps.textOrContent init
else buildInit (optionalAttrs (! isNull init) init);
neovimConfig = neovimConfig =
pkgs.neovimUtils.makeNeovimConfig { pkgs.neovimUtils.makeNeovimConfig {
inherit customRC; inherit customRC;
plugins = extractPlugin plugins; plugins = extractPlugins plugins;
extraLuaPackages = ps:
(extractLuaPackagesFn plugins ps) ++ (extraLuaPackages ps);
} }
// {luaRcContent = customRC;}; // {luaRcContent = customRC;};
pkg = pkgs.wrapNeovimUnstable package (removeAttrs neovimConfig ["manifestRc" "neovimRcContent"]); params =
removeAttrs neovimConfig ["manifestRc" "neovimRcContent"]
// {inherit viAlias vimAlias;};
pkg = pkgs.wrapNeovimUnstable package params;
mkDiffAlias = name:
(flip optionalString) ''
cat <<SH > $out/bin/${name}
#!${bash}/bin/bash
exec $out/bin/nvim -d "\''${@}"
SH
chmod 555 $out/bin/${name}
'';
in in
builtins.seq (types.mkNeovimPkgOptions config) pkg builtins.seq (types.mkNeovimPkgOptions config) (pkg.overrideAttrs (final: super: {
postBuild =
super.postBuild
+ (mkDiffAlias "vimdiff" vimdiffAlias)
+ (mkDiffAlias "nvimdiff" nvimdiffAlias);
}))

View File

@ -0,0 +1,20 @@
{
pkgs,
inputs,
predicate ? pkgs.lib.strings.hasPrefix "plugin-",
nameMap ? builtins.substring 7 (-1),
buildVimPlugin ? pkgs.vimUtils.buildVimPlugin,
}: let
inherit (builtins) attrNames filter foldl' mapAttrs;
names = filter predicate (attrNames inputs);
mkPlugin = m: k: let
name = nameMap k;
pluginDef = {
inherit name;
src = inputs.${k};
};
in
m // {${name} = pluginDef;};
plugins = foldl' mkPlugin {} names;
in
mapAttrs (_: buildVimPlugin) plugins

View File

@ -1,17 +1,30 @@
{yants, ...}: rec { {yants, ...}: let
stringList = with yants; list string;
stringOrStringList = with yants; either string stringList;
stringOrStringListOr = type:
with yants;
option (eitherN [string type (list (either string type))]);
in rec {
# The runtime object # The runtime object
runtimeType = with yants; runtimeType = with yants;
struct "runtime" { struct "runtime" {
# The version of the runtime # The version of the runtime
version = option string; version = option string;
# The init configuration file
init = option (either path string);
# The content of the runtime directory # The content of the runtime directory
src = any; src = any;
}; };
neovimInitType = with yants;
struct "neovimInit" {
# Lua code to call before plugins loaded
init = option (either string path);
# Lua code called after init but before import
postInit = option (either string path);
# Lua code called after all plugins are loaded
config = option (either string path);
};
# As simple remote plugin definition # As simple remote plugin definition
basicPluginType = with yants; basicPluginType = with yants;
struct "basicPlugin" { struct "basicPlugin" {
@ -22,9 +35,24 @@
src = any; src = any;
}; };
eventType = with yants;
struct "event" {
# The name of the event
name = stringOrStringList;
# The pattern of the event
pattern = stringOrStringList;
};
keymapType = with yants;
struct "keymap" {
# The mode of the keymap
mode = option stringOrStringList;
# The mapping of the keymap
mapping = stringOrStringList;
};
# The plugin type of dependencies # The plugin type of dependencies
pluginType = with yants; pluginType = with yants;
# let stringList = list string in
struct "plugin" { struct "plugin" {
# Whether this plugin should be enabled. This option allows specific # Whether this plugin should be enabled. This option allows specific
# plugins to be disabled. # plugins to be disabled.
@ -44,20 +72,23 @@
# Ensure thoses plugins are loaded before the current one # Ensure thoses plugins are loaded before the current one
dependencies = option (list drv); dependencies = option (list drv);
# Ensure those packages are available
extraLuaPackages = option function;
# Should this plugin be load lazily ? # Should this plugin be load lazily ?
# lazy = option bool; lazy = option bool;
# List of events on which the plugin should be loaded # List of events on which the plugin should be loaded
# events = option stringList; events = option (stringOrStringListOr eventType);
# List of commands on which the plugin should be loaded # List of commands on which the plugin should be loaded
# commands = option stringList; cmd = option stringList;
# List of filetypes on which the plugin should be loaded # List of filetypes on which the plugin should be loaded
# filetypes = option stringList; ft = option stringList;
# List of keystrokes on which the plugin should be loaded # List of keystrokes on which the plugin should be loaded
# keys = option stringList; keymaps = option (stringOrStringListOr keymapType);
# Priority of the module. Influence the order of loading plugins. # Priority of the module. Influence the order of loading plugins.
# Highest values get loaded before. # Highest values get loaded before.
@ -77,13 +108,31 @@
# Default is pkgs.neovim-unwrapped # Default is pkgs.neovim-unwrapped
package = option drv; package = option drv;
# init.lua configuration
init = option (eitherN [string path neovimInitType]);
# An array of dependencies. # An array of dependencies.
dependencies = list dependency; dependencies = option (list dependency);
# Extra argument to pass to dependencies files # Extra argument to pass to dependencies files
dependenciesExtraArgs = attrs any; dependenciesExtraArgs = option (attrs any);
# Ensure those packages are available
extraLuaPackages = option function;
# Runtime configuration # Runtime configuration
runtime = runtimeType; runtime = option runtimeType;
# Create a vi alias
viAlias = option bool;
# Create a vim alias
vimAlias = option bool;
# Create a vimdiff alias to run neovim in diff mode
vimdiffAlias = option bool;
# Create a nvimdiff alias to run neovim in diff mode
nvimdiffAlias = option bool;
}; };
} }

View File

@ -0,0 +1,74 @@
local Dep = require 'sloth-flake.dep'
local utils = require 'sloth-flake.utils'
local function yesno(value)
return value and "Yes" or "No"
end
local function list(items)
if items == nil or #items == 0 then
return "None"
end
return vim.iter(items):join(', ')
end
local function describe(dep)
utils.info('Name: %s', dep.name)
utils.info('Is loaded: %s', yesno(dep.is_loaded))
utils.info('Is lazy: %s', yesno(dep.is_lazy))
utils.info('Has init: %s', yesno(dep.init))
utils.info('Has config: %s', yesno(dep.config))
utils.info('Dependencies: %s', list(dep.dependency_names))
utils.info('Filetypes: %s', list(dep.ft))
utils.info('Commands: %s', list(dep.cmd))
if dep.events == nil then
utils.info('Events: None')
else
utils.info('Events:')
for _, event in ipairs(dep.events) do
for _, name in ipairs(event.name) do
for _, pattern in ipairs(event.pattern) do
utils.info(' - %s %s', name, pattern)
end
end
end
end
if dep.keymaps == nil then
utils.info('Keymaps: None')
else
utils.info('Keymaps:')
for _, keymap in ipairs(dep.keymaps) do
for _, mode in ipairs(keymap.mode) do
for _, mapping in ipairs(keymap.mapping) do
utils.info(' - %s %s', mode, mapping)
end
end
end
end
end
return {
complete = function(line)
if line.arg_idx == 3 then
local prefix = line.args[line.arg_idx].arg
return vim.iter(Dep.all()):map(function(name)
return name
end):filter(function(name)
return vim.startswith(name, prefix)
end):totable()
end
end,
cmd = function(plugins)
if #plugins == 0 then
utils.error("You should at least give a plugin to describe!")
return
end
local plugin = plugins[1]
local dep = Dep.get(plugin)
if dep == nil then
return utils.error([[Unknown plugin "%s"]], plugin)
end
describe(dep)
end,
}

View File

@ -0,0 +1,87 @@
local Dep = require 'sloth-flake.dep'
local M = {}
local commands = {
list = require 'sloth-flake.command.list',
load = require 'sloth-flake.command.load',
version = require 'sloth-flake.command.version',
describe = require 'sloth-flake.command.describe',
}
local function parse_line(line, cursor_pos)
local raw_args = vim.split(line, ' +', { trimempty = true })
local parse_pos = 1
local args = vim.iter(raw_args):map(function(arg)
local start, stop = string.find(line, arg, parse_pos, { plain = true })
parse_pos = stop
return {
arg = arg,
start = start,
stop = stop,
}
end):totable()
parse_pos = 1
local arg_idx = 1
vim.iter(args):find(function(arg)
if cursor_pos < arg.start then
arg_idx = arg_idx - 1
return true
elseif cursor_pos <= arg.stop then
return true
end
arg_idx = arg_idx + 1
return false
end)
arg_idx = arg_idx < 1 and 1 or arg_idx
if arg_idx > #args then
args[#args + 1] = {
arg = "",
start = line:len(),
stop = line:len(),
}
end
return {
line = line,
args = args,
arg_idx = arg_idx,
pos = cursor_pos,
in_arg_pos = args[arg_idx] and cursor_pos - args[arg_idx].start + 1,
}
end
-- print(vim.inspect(parse_line('Sloth ', 6)))
local function sloth_cmd_complete(arg_lead, cmd_line, cursor_pos)
local parsed_line = parse_line(cmd_line, cursor_pos)
local arg = parsed_line.args[parsed_line.arg_idx]
if parsed_line.arg_idx == 2 then
return vim.iter(commands):map(function(name, command)
return vim.startswith(name, arg.arg) and name or nil
end):totable()
elseif parsed_line.arg_idx > 2 then
local cmd = parsed_line.args[2].arg
local command = commands[cmd]
return command and command.complete(parsed_line)
end
end
local function sloth_cmd(param)
local args = param.fargs
local cmd = args[1] or "list";
table.remove(args, 1)
local command = commands[cmd]
if command then
command.cmd(args)
else
vim.api.nvim_err_writeln(string.format([[No Sloth subcommand "%s"]], cmd))
end
end
function M.register()
vim.api.nvim_create_user_command('Sloth', sloth_cmd, {
nargs = '*',
complete = sloth_cmd_complete
})
end
return M

View File

@ -0,0 +1,55 @@
local Dep = require 'sloth-flake.dep'
local utils = require 'sloth-flake.utils'
local filters = {
all = {
filter = function(iter)
-- Nothing to do
return iter
end
},
loaded = {
filter = function(iter)
return iter:filter(function(dep)
return Dep.get(dep).is_loaded
end)
end
},
notloaded = {
filter = function(iter)
return iter:filter(function(dep)
return not Dep.get(dep).is_loaded
end)
end
},
}
return {
complete = function(line)
if line.arg_idx == 3 then
local prefix = line.args[3].arg
return vim.iter(vim.tbl_keys(filters)):filter(function(name)
return vim.startswith(name, prefix)
end):totable()
end
end,
cmd = function(args)
local filter_name = args[1] or "all"
local filter = filters[filter_name]
if not filter then
utils.error([[No Sloth list filter "%s".]], cmd)
utils.error("Filters are: %s", vim.iter(vim.tbl_keys(filters)):join(', '))
return
end
local deps = vim.iter(Dep.all()):map(function(_, dep)
return dep.name
end)
deps = filter.filter(deps):totable()
table.sort(deps)
for _, dep in ipairs(deps) do
print(string.format("- %s", dep))
end
end,
}

View File

@ -0,0 +1,32 @@
local Dep = require 'sloth-flake.dep'
local utils = require 'sloth-flake.utils'
return {
complete = function(line)
local previous_deps = vim.iter(line.args):enumerate():map(function(i, arg)
if i < 3 or i > line.arg_idx then return end
return arg.arg
end):totable()
local prefix = line.args[line.arg_idx].arg
return vim.iter(Dep.all()):filter(function(name, dep)
return vim.startswith(name, prefix) and not dep.is_loaded
and not vim.list_contains(previous_deps, name)
end):map(function(name)
return name
end):totable()
end,
cmd = function(plugins)
if #plugins == 0 then
utils.error("You should at least give a plugin to load!")
return
end
for _, plugin in ipairs(plugins) do
local dep = Dep.get(plugin)
if dep ~= nil then
dep:load()
end
end
end,
}

View File

@ -0,0 +1,7 @@
return {
complete = function() end,
cmd = function()
local version = require('sloth-flake.version')
print(string.format('Sloth v%s', version()))
end,
}

268
lua/sloth-flake/dep.lua Normal file
View File

@ -0,0 +1,268 @@
local raw_deps = require 'sloth-flake.dependencies'
local state_machine = require 'sloth-flake.state_machine'
local M = {}
local State = state_machine.build_states {
'NotLoaded',
'Shimed',
'Inited',
'Imported',
'Loaded',
}
function M.new(values)
local self = {
values = values,
}
self.sm = state_machine.build(State, {
enter = {
[State.Shimed] = function()
return self:_shim()
end,
[State.Inited] = function()
for _, dep in ipairs(self.dependencies) do
dep:init()
end
local init = self.values.init or function() end
init()
end,
[State.Imported] = function()
for _, dep in ipairs(self.dependencies) do
dep:import()
end
if self.is_lazy or self.values.init then
vim.cmd("packadd " .. self.name)
end
end,
[State.Loaded] = function()
for _, dep in ipairs(self.dependencies) do
dep:config()
end
local config = self.values.config or function() end
config()
end
},
exit = {
[State.Shimed] = function()
self:_unshim()
end,
},
events = {
shim = { from = State.NotLoaded, to = State.Shimed, },
init = { from = { State.NotLoaded, State.Shimed }, to = State.Inited, },
import = { from = State.Inited, to = State.Imported, },
config = { from = State.Imported, to = State.Loaded, },
},
})
return setmetatable(self, {
__index = function(self, k)
local fn = M[k]
if fn then
return fn
end
fn = M['get_' .. k]
if fn then
return fn(self)
end
end,
__newindex = function(self, k, v)
-- Ignore new values
end
})
end
function M:get_name()
return self.values.name
end
function M:get_dependencies()
local ret = {}
for _, name in ipairs(self.values.dependencies) do
local dep = M.get(name)
if dep ~= nil then
ret[#ret + 1] = dep
end
end
return ret
end
function M:get_dependency_names()
local ret = {}
for _, name in ipairs(self.values.dependencies) do
ret[#ret + 1] = name
end
return ret
end
function M:get_cmd()
return self.values.cmd
end
function M:get_ft()
return self.values.ft
end
function M:get_events()
return self.values.events
end
function M:get_keymaps()
return self.values.keymaps
end
function M:get_is_lazy()
return self.values.lazy or false
end
function M:get_state()
return self.sm.state
end
function M:get_is_imported()
return self.state >= State.Imported
end
function M:get_is_loaded()
return self.state >= State.Loaded
end
function M:get_has_events()
return self.ft or self.events
end
function M:get_augroup_name()
return "Sloth-plugin-" .. self.name
end
function M:shim()
return self.sm:shim()
end
function M:_shim()
if self.cmd then
for _, cmd in ipairs(self.cmd) do
vim.api.nvim_create_user_command(cmd, self:lazy_load_cmd(cmd), {
desc = "Sloth-flake placeholder for plugin " .. self.name,
nargs = '*',
bang = true,
})
end
end
if self.has_events then
local group_id = vim.api.nvim_create_augroup(self.augroup_name, {
clear = true,
})
if self.ft then
vim.api.nvim_create_autocmd('FileType', {
group = group_id,
pattern = self.ft,
callback = self:lazy_load_event('FileType')
})
end
if self.events then
for _, event in ipairs(self.events) do
vim.api.nvim_create_autocmd(event.name, {
group = group_id,
pattern = event.pattern,
callback = self:lazy_load_event(event.name)
})
end
end
end
if self.keymaps then
for _, keymap in ipairs(self.keymaps) do
for _, mapping in ipairs(keymap.mapping) do
vim.keymap.set(keymap.mode, mapping, self:lazy_load_mapping(mapping))
end
end
end
end
function M:_unshim()
if self.cmd then
for _, cmd in ipairs(self.cmd) do
vim.api.nvim_del_user_command(cmd)
end
end
if self.has_events then
vim.api.nvim_del_augroup_by_name(self.augroup_name)
end
if self.keymaps then
for _, keymap in ipairs(self.keymaps) do
for _, mapping in ipairs(keymap.mapping) do
vim.keymap.del(keymap.mode, mapping)
end
end
end
end
function M:init()
return self.sm:init()
end
function M:import()
self:init()
return self.sm:import()
end
function M:config()
self:init()
self:import()
return self.sm:config()
end
function M:load()
self:init()
self:import()
return self:config()
end
function M:lazy_load_cmd(cmd)
return function(param)
self:load()
local bang = param.bang and '!' or ''
vim.cmd(cmd .. bang .. ' ' .. param.args)
end
end
function M:lazy_load_event(name)
return function(param)
self:load()
vim.api.nvim_exec_autocmds(name, {
pattern = param.match,
})
end
end
function M:lazy_load_mapping(mapping)
return function(param)
self:load()
vim.cmd.normal(mapping)
end
end
local deps = {}
for k, v in pairs(raw_deps) do
deps[k] = M.new(v)
end
function M.get(name)
return deps[name]
end
function M.all()
return deps
end
return M

View File

@ -1,80 +1,76 @@
local deps = require 'sloth-flake.deps' local Dep = require 'sloth-flake.dep'
local command = require 'sloth-flake.command'
local priv = { local priv = {
is_loaded = {} setup_called = false,
} }
local M = {} local M = {}
function M.get(name) function M.get(name)
return deps[name] return Dep.get(name)
end end
function M.init_all() function M.init_non_lazy()
for k, v in pairs(deps) do for _, dep in ipairs(M.non_lazy_deps()) do
M.init(k) dep:init()
end end
end end
function M.config_all() function M.import_non_lazy()
for k, v in pairs(deps) do for _, dep in ipairs(M.non_lazy_deps()) do
M.config(k) dep:import()
end end
end end
function M.init(name) function M.config_non_lazy()
local dep = M.get(name) for _, dep in ipairs(M.non_lazy_deps()) do
if name == nil then dep:config()
-- TODO Report error ?
elseif dep.init ~= nil then
dep.init()
end end
end end
function M.load(name) function M.dep_names()
if name == nil then return M.dep_names_by(function() return true end):totable()
-- TODO Report error ?
elseif M.is_loaded(name) then
-- TODO Nothing todo
else
-- TODO Laod dynamic plugin
priv.is_loaded[name] = true
end
end end
function M.config(name) function M.dep_names_by(fn)
local dep = M.get(name) return M.deps_iter_by(fn):map(function(v) return v:name() end)
if name == nil then
-- TODO Report error ?
elseif dep.config ~= nil then
dep.config()
end
end end
function M.get_dep_names() function M.deps_iter_by(fn)
local ret = {} return vim.iter(Dep.all()):map(function(k, v) return v end):filter(fn)
for k, v in pairs(deps) do
ret[#ret + 1] = v.name
end
return ret
end end
function M.load_all() function M.non_lazy_deps()
for k, _v in pairs(deps) do return M.deps_iter_by(function(dep)
M.load(k) return not dep.is_lazy
end end):totable()
end end
function M.is_loaded(name) function M.lazy_deps()
return priv.is_loaded[name] or false return M.deps_iter_by(function(dep)
return dep.is_lazy
end):totable()
end end
function M.setup(config) function M.setup(config)
if priv.setup_called then
return
end
priv.setup_called = true
local post_init = config and config.post_init or function() end local post_init = config and config.post_init or function() end
M.init_all() M.init_non_lazy()
post_init() post_init()
M.load_all() M.import_non_lazy()
M.config_all() M.config_non_lazy()
local lazy_deps = M.lazy_deps()
for _, dep in ipairs(lazy_deps) do
dep:shim()
end
command.register()
end end
return M return M

View File

@ -0,0 +1,104 @@
local M = {}
local stateMeta
local function are_both_states(a, b)
return a.is_state and b.is_state
end
stateMeta = {
__tostring = function(v)
return v.name
end,
__le = function(self, other)
if not are_both_states(self, other) then
return false
end
return self.idx <= other.idx
end,
__lt = function(self, other)
if not are_both_states(self, other) then
return false
end
return self.idx < other.idx
end,
__index = function(self, name)
if name == 'is_state' then
return true
end
end
}
function M.build_states(defs)
local states = {}
for i, name in ipairs(defs) do
local state = setmetatable({ idx = i, name = name }, stateMeta)
states[i] = state
states[name] = state
end
return states
end
local SM = {}
local function empty_fn()
end
function SM:run_enter_state(state)
local enter_fn = self.defs.enter and self.defs.enter[state] or empty_fn
enter_fn(self.state)
end
function SM:run_exit_state(state)
local exit_fn = self.defs.exit and self.defs.exit[state] or empty_fn
exit_fn(self.state)
end
local function wrap_state_array(val)
return val.is_state and { val } or val
end
local function canonicalize_event(event)
return {
from = wrap_state_array(event.from),
to = event.to,
transition = event.transition or function() end,
}
end
function M.build(states, defs)
local machine = {
state = states[1],
defs = defs,
}
local prototype = {}
for name, infos in pairs(defs.events) do
local event = canonicalize_event(infos)
prototype[name] = function(self)
if not vim.list_contains(event.from, self.state) then
return false
end
local previous = self.state
self:run_exit_state(previous)
self.state = event.to
event.transition(previous, self.state)
self:run_enter_state(self.state)
return true
end
end
local ret = setmetatable(machine, { __index = vim.tbl_extend('error', SM, prototype)})
ret:run_enter_state(states[1])
return ret
end
local State = M.build_states {
'NotLoaded',
'Shimed',
'Inited',
'Imported',
'Loaded',
}
return M

11
lua/sloth-flake/utils.lua Normal file
View File

@ -0,0 +1,11 @@
local M = {}
function M.info(...)
print(string.format(...))
end
function M.error(...)
vim.api.nvim_err_writeln(string.format(...))
end
return M

View File

@ -1,11 +1,14 @@
{ {
pkgs, formatter,
nil, nil,
pkgs,
... ...
}: }:
with pkgs; with pkgs;
mkShell { mkShell {
buildInputs = [ buildInputs = [
formatter
git-cliff
nil nil
sumneko-lua-language-server sumneko-lua-language-server
]; ];