diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
index 71b6d26..9df74dc 100644
--- a/.github/workflows/documentation.yml
+++ b/.github/workflows/documentation.yml
@@ -1,11 +1,12 @@
+name: documentation
+
on:
push:
branches:
- main
-name: documentation
jobs:
- api_documentation:
+ documentation:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
@@ -20,10 +21,7 @@ jobs:
run: |
nvim --version
make api_documentation
- user_documentation:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
+
- name: Create User Documentation
uses: kdheepak/panvimdoc@main
with:
@@ -31,29 +29,11 @@ jobs:
version: "Neovim >= 0.8.0"
demojify: true
treesitter: true
- tags:
- runs-on: ubuntu-latest
- needs: [api_documentation, user_documentation]
- steps:
- - name: Setup Neovim
- uses: rhysd/action-setup-vim@v1
- with:
- neovim: true
- version: stable
-
- - name: Checkout plugin-template
- uses: actions/checkout@v4
- with:
- repository: ColinKennedy/nvim-best-practices-plugin-template
- path: neovim_plugin
- name: Generate Tags
run: |
- # nvim -c 'helptags doc' -c 'quit'
- # push:
- runs-on: ubuntu-latest
- needs: [tags]
- steps:
+ nvim -c 'helptags doc' -c 'quit'
+
- name: Push Changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml
index 97d19fb..7f7c52b 100644
--- a/.github/workflows/luacheck.yml
+++ b/.github/workflows/luacheck.yml
@@ -1,7 +1,7 @@
----
-on: [pull_request]
name: luacheck
+on: [pull_request]
+
jobs:
luacheck:
name: Luacheck
diff --git a/.github/workflows/news.yml b/.github/workflows/news.yml
index 1803852..9ce9e0b 100644
--- a/.github/workflows/news.yml
+++ b/.github/workflows/news.yml
@@ -1,10 +1,12 @@
# Reference: https://github.com/neovim/neovim/blob/9762c5e3406cab8152d8dd161c0178965d841676/.github/workflows/news.yml
name: "news.txt"
+
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
branches:
- main
+
jobs:
check:
runs-on: ubuntu-latest
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5acb227..661073f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,9 +1,11 @@
# Reference: https://github.com/ellisonleao/nvim-plugin-template/blob/922c0d5249076416c5d84e7c0504f1154225a7ab/.github/workflows/release.yml
name: release
+
on:
push:
tags:
- 'v*'
+
jobs:
luarocks-upload:
runs-on: ubuntu-22.04
diff --git a/.github/workflows/stylua.yml b/.github/workflows/stylua.yml
index 1d80d78..8fdba55 100644
--- a/.github/workflows/stylua.yml
+++ b/.github/workflows/stylua.yml
@@ -1,7 +1,10 @@
----
-on: [pull_request]
name: stylua
+on:
+ pull_request:
+ branches:
+ - main
+
jobs:
stylua:
name: stylua
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..71a2b27
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,45 @@
+name: test
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened, ready_for_review]
+ branches:
+ - main
+
+jobs:
+ test:
+ strategy:
+ matrix:
+ os: [ubuntu-latest, macos-latest]
+ neovim: [v0.10.0, stable, nightly]
+
+ runs-on: ${{ matrix.os }}
+ name: "OS: ${{ matrix.os }} - Neovim: ${{ matrix.neovim }}"
+
+ steps:
+ - uses: actions/checkout@master
+
+ - uses: leafo/gh-actions-lua@v10
+ with:
+ # Neovim is compiled with LuaJIT so we might as well match. But it
+ # doesn't look like we can match it exactly.
+ #
+ # Reference:
+ # https://github.com/leafo/gh-actions-lua/issues/49#issuecomment-2295071198
+ #
+ luaVersion: "luajit-openresty"
+
+ - uses: leafo/gh-actions-luarocks@v4
+
+ - uses: rhysd/action-setup-vim@v1
+ with:
+ neovim: true
+ version: ${{ matrix.neovim }}
+
+ - name: build
+ run: |
+ luarocks test plugin-template-scm-1.rockspec --prepare
+
+ - name: test
+ run: |
+ luarocks test --test-type busted
diff --git a/README.md b/README.md
index 7d269ac..39ade90 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,16 @@
-# 🚧 Under Construction 🚧
-
-This repository doesn't have all GitHub CI actions working yet but is available
-as an early preview. We will update docs/news.txt once it's ready.
-
-Add https://github.com/ColinKennedy/nvim-best-practices-plugin-template/commits/main/doc/news.txt.atom
-to your RSS feed so you don't miss it!
-
# A Neovim Plugin Template
-![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ColinKennedy/nvim-best-practices-plugin-template/test.yml?branch=main&style=for-the-badge)
-![Lua](https://img.shields.io/badge/Made%20with%20Lua-blueviolet.svg?style=for-the-badge&logo=lua)
+| | |
+|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Build Status | [![Unittests](https://img.shields.io/github/actions/workflow/status/ColinKennedy/nvim-best-practices-plugin-template/test.yml?branch=fix_todo_notes_005&style=for-the-badge&label=Unittests)](https://github.com/ColinKennedy/nvim-best-practices-plugin-template/actions/workflows/test.yml) [![Documentation](https://img.shields.io/github/actions/workflow/status/ColinKennedy/nvim-best-practices-plugin-template/documentation.yml?branch=fix_todo_notes_005&style=for-the-badge&label=Documentation)](https://github.com/ColinKennedy/nvim-best-practices-plugin-template/actions/workflows/documentation.yml) [![Luacheck](https://img.shields.io/github/actions/workflow/status/ColinKennedy/nvim-best-practices-plugin-template/luacheck.yml?branch=fix_todo_notes_005&style=for-the-badge&label=Luacheck)](https://github.com/ColinKennedy/nvim-best-practices-plugin-template/actions/workflows/luacheck.yml) [![Stylua](https://img.shields.io/github/actions/workflow/status/ColinKennedy/nvim-best-practices-plugin-template/stylua.yml?branch=fix_todo_notes_005&style=for-the-badge&label=Stylua)](https://github.com/ColinKennedy/nvim-best-practices-plugin-template/actions/workflows/stylua.yml) \| |
+| License | ![License-MIT](https://img.shields.io/badge/License-MIT-blue?style=for-the-badge) |
-A template repository for Neovim plugins.
+A template repository used to create Neovim plugins.
# Features
- Follows [nvim-best-practices](https://github.com/nvim-neorocks/nvim-best-practices)
-- Fast start-up (the plugin is super defer-loaded. < 1 ms guarantee)
+- Fast start-up (~1 ms)
- Auto-release to [luarocks](https://luarocks.org)
- Automated user documentation (using [panvimdoc](https://github.com/kdheepak/panvimdoc))
- Automated API documentation (using [mini.doc](https://github.com/echasnovski/mini.doc))
@@ -29,6 +23,9 @@ A template repository for Neovim plugins.
- [RSS feed support](tracking-updates)
- Built-in logging to stdout / files
- Unittests use the full power of native [busted](https://olivinelabs.com/busted)
+- Automated testing matrix supports 6 Neovim/OS combinations
+ - neovim: `[v0.10.0, stable, nightly]`
+ - os: `[ubuntu-latest, macos-latest]`
- 100% Lua
- Uses [Semantic Versioning](https://semver.org)
- Integrations
diff --git a/TODO.md b/TODO.md
deleted file mode 100644
index 02ed077..0000000
--- a/TODO.md
+++ /dev/null
@@ -1,32 +0,0 @@
-## Round 2
-- Document the old manual parser way
-- Fix the main commit history (force push master)
-
-
-## Round 3
-- Make sure the CI works
- - llscheck
-
-- Add badges to the README.md
- - RSS
- - Stylua
- - etc
- - Passing workflow badges
- - Static badges
-
-Consider more badges
-https://github.com/azratul/live-share.nvim?tab=readme-ov-file
-
-
-## Round 4
-- Do a round of finishing TODO notes
-
-
-## Extra Features
-- Check files for syntax errors using tree-sitter parsers (via Neovim)?
-
-
-## Last Round
-- Make sure PR linters work (release (post-merge) should also work)
-
-- Make sure to increment the version to v1.0.0
diff --git a/doc/news.txt b/doc/news.txt
index 90f6cd8..9c3d8a5 100644
--- a/doc/news.txt
+++ b/doc/news.txt
@@ -1,59 +1,18 @@
*plugin-template-news.txt*
-Notable changes since PluginTemplate 0.1
+Notable changes since PluginTemplate 1.0
===============================================================================
NEW FEATURES *plugin-template-new-features*
-GENERAL
-
-- 100% Lua
-- LuaCATS annotations and type-hints, everywhere
-- No external dependencies
-
-CI
-
-- Github actions for:
- - PR reviews - Reminds users to update `doc/news.txt`
- - `StyLua`
- - `llscheck`
- - `luacheck`
- - `luarocks`
- - `panvimdoc`
-- RSS feed support
-
-CLI
-
-- Added nargs support to `cmdparse` and other features
-
-START UP
-
-- Fast start-up (the plugin is defer-loaded)
-- Follows nvim-best-practices
-
-COMMANDS
-
-- Built-in Vim commands with auto-completion
-
-TESTS
-
-- Unittests use the full power of native busted
-
-TOOLS
-
-Integrates with
-
-- lualine.nvim
-- telescope.nvim
-- `:checkhealth`
+We're live!
===============================================================================
BREAKING CHANGES *plugin-template-new-breaking*
-CLI
+n/a
-- Replaced the old raw-lua-table-based API with a class-based API.
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/doc/plugin-template.txt b/doc/plugin-template.txt
index a8cc91b..aa402a3 100644
--- a/doc/plugin-template.txt
+++ b/doc/plugin-template.txt
@@ -45,7 +45,7 @@ A template repository for Neovim plugins.
- Follows nvim-best-practices
- Fast start-up (the plugin is super defer-loaded. < 1 ms guarantee)
- Auto-release to luarocks
-- Automated User documentation (using panvimdoc )
+- Automated user documentation (using panvimdoc )
- Automated API documentation (using mini.doc )
- Vimtags generation
- Built-in Vim commands
@@ -53,7 +53,7 @@ A template repository for Neovim plugins.
- Auto-completes your commands at any cursor position
- No external dependencies
- LuaCATS annotations and type-hints, everywhere
-- RSS feed support
+- RSS feed support
- Built-in logging to stdout / files
- Unittests use the full power of native busted
- 100% Lua
diff --git a/lua/plugin_template/_cli/cli_subcommand.lua b/lua/plugin_template/_cli/cli_subcommand.lua
index c484c6a..9038cab 100644
--- a/lua/plugin_template/_cli/cli_subcommand.lua
+++ b/lua/plugin_template/_cli/cli_subcommand.lua
@@ -3,8 +3,6 @@
---@module 'plugin_template._cli.cli_subcommand'
---
-local help_message = require("plugin_template._cli.cmdparse.help_message")
-
local M = {}
---@class argparse.SubcommandRunnerOptions
@@ -261,17 +259,15 @@ end
---
function M.make_parser_completer(parser_creator)
local function runner(_, all_text, _)
+ local configuration = require("plugin_template._core.configuration")
+ configuration.initialize_data_if_needed()
+
local parser = parser_creator()
local column = vim.fn.getcmdpos()
return parser:get_completion(all_text, column)
end
- -- NOTE: Initialize only once
- local configuration = require("plugin_template._core.configuration")
-
- configuration.initialize_data_if_needed()
-
return runner
end
@@ -285,6 +281,7 @@ function M.make_subcommand_completer(prefix, subcommands)
local function runner(latest_text, all_text, _)
local configuration = require("plugin_template._core.configuration")
configuration.initialize_data_if_needed()
+
local completion = _get_subcommand_completion(all_text, prefix, subcommands)
if completion then
@@ -381,6 +378,11 @@ function M.make_subcommand_triager(subcommands)
---@param opts argparse.SubcommandRunnerOptions The parsed user options.
---
local function runner(opts)
+ local configuration = require("plugin_template._core.configuration")
+ configuration.initialize_data_if_needed()
+
+ local help_message = require("plugin_template._cli.cmdparse.help_message")
+
local success, result = pcall(function()
_runner(opts)
end)
@@ -398,11 +400,6 @@ function M.make_subcommand_triager(subcommands)
end
end
- -- NOTE: Initialize only once
- local configuration = require("plugin_template._core.configuration")
-
- configuration.initialize_data_if_needed()
-
return runner
end
diff --git a/lua/plugin_template/_core/tabler.lua b/lua/plugin_template/_core/tabler.lua
index ecba861..50a52cb 100644
--- a/lua/plugin_template/_core/tabler.lua
+++ b/lua/plugin_template/_core/tabler.lua
@@ -38,13 +38,24 @@ end
---
function M.get_value(data, items)
local current = data
+ local found = {}
+ local count = #items
- for _, item in ipairs(items) do
+ for index = 1, count do
+ local item = items[index]
current = current[item]
if current == nil then
return nil
end
+
+ table.insert(found, item)
+
+ local type_ = type(current)
+
+ if index < count and type_ ~= "table" then
+ error(string.format("%s: expected table, got %s", vim.fn.join(found, "."), type_), 0)
+ end
end
return current
diff --git a/lua/plugin_template/_vendors/vlog.lua b/lua/plugin_template/_vendors/vlog.lua
index b5533bb..1ce8794 100644
--- a/lua/plugin_template/_vendors/vlog.lua
+++ b/lua/plugin_template/_vendors/vlog.lua
@@ -33,6 +33,9 @@ local default_config = {
{ name = "fatal", hl = "ErrorMsg" },
},
+ -- Define this path to redirect the log file to wherever you need it to go
+ outfile = nil,
+
-- Can limit the number of decimals displayed for floats
float_precision = 0.01,
}
@@ -64,8 +67,8 @@ log.new = function(config, standalone)
obj._is_logging_to_file_enabled = config.use_file
- obj._outfile =
- vim.fs.joinpath(vim.api.nvim_call_function("stdpath", { "data" }), string.format("%s.log", config.plugin))
+ obj._outfile = config.outfile
+ or vim.fs.joinpath(vim.api.nvim_call_function("stdpath", { "data" }), string.format("%s.log", config.plugin))
local levels = {}
for i, v in ipairs(config.modes) do
diff --git a/lua/plugin_template/health.lua b/lua/plugin_template/health.lua
index 666266e..3e88454 100644
--- a/lua/plugin_template/health.lua
+++ b/lua/plugin_template/health.lua
@@ -55,6 +55,45 @@ local function _is_hex_color(text)
return text:match("^#%x%x%x%x%x%x$") ~= nil
end
+--- Add issues to `array` if there are errors.
+---
+--- Todo:
+--- Once Neovim 0.10 is dropped, use the new function signature
+--- for vim.validate to make this function cleaner.
+---
+---@param array string[]
+--- All of the cumulated errors, if any.
+---@param name string
+--- The key to check for.
+---@param value_creator fun(): any
+--- A function that generates the value.
+---@param expected string | fun(value: any): boolean
+--- If `value_creator()` does not match `expected`, this error message is
+--- shown to the user.
+---@param message (string | boolean)?
+--- If it's a string, it's the error message when
+--- `value_creator()` does not match `expected`. When it's
+--- `true`, it means it's okay for `value_creator()` not to match `expected`.
+---
+local function _append_validated(array, name, value_creator, expected, message)
+ local success, value = pcall(value_creator)
+
+ if not success then
+ table.insert(array, value)
+
+ return
+ end
+
+ local validated
+ success, validated = pcall(vim.validate, {
+ [name] = { value, expected, message },
+ })
+
+ if not success then
+ table.insert(array, validated)
+ end
+end
+
--- Check if `data` is a boolean under `key`.
---
---@param key string The configuration value that we are checking.
@@ -84,54 +123,46 @@ local function _get_boolean_issue(key, data)
return message
end
---- Check all "commands" values for issues.
+--- Check all "cmdparse" values for issues.
---
---@param data plugin_template.Configuration All of the user's fallback settings.
---@return string[] # All found issues, if any.
---
-local function _get_command_issues(data)
+local function _get_cmdparse_issues(data)
local output = {}
- local success, message = pcall(
- vim.validate,
- "commands.goodnight_moon.read.phrase",
- tabler.get_value(data, { "commands", "goodnight_moon", "read", "phrase" }),
- "string"
- )
+ _append_validated(output, "cmdparse.auto_complete.display.help_flag", function()
+ return tabler.get_value(data, { "cmdparse", "auto_complete", "display", "help_flag" })
+ end, "boolean", true)
- if not success then
- table.insert(output, message)
- end
+ return output
+end
- success, message = pcall(vim.validate, {
- ["commands.hello_world.say.repeat"] = {
- tabler.get_value(data, { "commands", "hello_world", "say", "repeat" }),
- function(value)
- return type(value) == "number" and value > 0
- end,
- "a number (value must be 1-or-more)",
- },
- })
+--- Check all "commands" values for issues.
+---
+---@param data plugin_template.Configuration All of the user's fallback settings.
+---@return string[] # All found issues, if any.
+---
+local function _get_command_issues(data)
+ local output = {}
- if not success then
- table.insert(output, message)
- end
+ _append_validated(output, "commands.goodnight_moon.read.phrase", function()
+ return tabler.get_value(data, { "commands", "goodnight_moon", "read", "phrase" })
+ end, "string")
- success, message = pcall(vim.validate, {
- ["commands.hello_world.say.style"] = {
- tabler.get_value(data, { "commands", "hello_world", "say", "style" }),
- function(value)
- local choices = vim.tbl_keys(say_constant.Keyword.style)
+ _append_validated(output, "commands.hello_world.say.repeat", function()
+ return tabler.get_value(data, { "commands", "hello_world", "say", "repeat" })
+ end, function(value)
+ return type(value) == "number" and value > 0
+ end, "a number (value must be 1-or-more)")
- return vim.tbl_contains(choices, value)
- end,
- '"lowercase" or "uppercase"',
- },
- })
+ _append_validated(output, "commands.hello_world.say.style", function()
+ return tabler.get_value(data, { "commands", "hello_world", "say", "style" })
+ end, function(value)
+ local choices = vim.tbl_keys(say_constant.Keyword.style)
- if not success then
- table.insert(output, message)
- end
+ return vim.tbl_contains(choices, value)
+ end, '"lowercase" or "uppercase"')
return output
end
@@ -147,93 +178,73 @@ end
---@return string[] # All found issues, if any.
---
local function _get_lualine_command_issues(command, data)
- local success, message = pcall(vim.validate, {
- [string.format("tools.lualine.%s", command)] = {
- data,
- function(value)
- if type(value) ~= "table" then
- return false
- end
-
- return true
- end,
- 'a table. e.g. { text="some text here" }',
- },
- })
-
- if not success then
- return { message }
- end
-
local output = {}
- success, message = pcall(vim.validate, {
- [string.format("tools.lualine.%s.text", command)] = {
- tabler.get_value(data, { "text" }),
- function(value)
- if type(value) ~= "string" then
- return false
- end
+ _append_validated(output, string.format("tools.lualine.%s", command), function()
+ return data
+ end, function(value)
+ if type(value) ~= "table" then
+ return false
+ end
- return true
- end,
- 'a string. e.g. "some text here"',
- },
- })
+ return true
+ end, 'a table. e.g. { text="some text here" }')
- if not success then
- table.insert(output, message)
+ if not vim.tbl_isempty(output) then
+ return output
end
- success, message = pcall(vim.validate, {
- [string.format("tools.lualine.%s.color", command)] = {
- tabler.get_value(data, { "color" }),
- function(value)
- if value == nil then
- -- NOTE: It's okay for this value to be undefined because
- -- we define a fallback for the user.
- --
- return true
- end
+ _append_validated(output, string.format("tools.lualine.%s.text", command), function()
+ return tabler.get_value(data, { "text" })
+ end, function(value)
+ if type(value) ~= "string" then
+ return false
+ end
- local type_ = type(value)
+ return true
+ end, 'a string. e.g. "some text here"')
- if type_ == "string" then
- -- NOTE: We assume that there is a linkable highlight group
- -- with the name of `value` already or one that will exist.
- --
- return true
- end
+ _append_validated(output, string.format("tools.lualine.%s.color", command), function()
+ return tabler.get_value(data, { "color" })
+ end, function(value)
+ if value == nil then
+ -- NOTE: It's okay for this value to be undefined because
+ -- we define a fallback for the user.
+ --
+ return true
+ end
- if type_ == "table" then
- if value.bg ~= nil and not _is_hex_color(value.bg) then
- return false
- end
+ local type_ = type(value)
- if value.fg ~= nil and not _is_hex_color(value.fg) then
- return false
- end
+ if type_ == "string" then
+ -- NOTE: We assume that there is a linkable highlight group
+ -- with the name of `value` already or one that will exist.
+ --
+ return true
+ end
- if value.gui ~= nil and type(value.gui) ~= "string" then
- return false
- end
+ if type_ == "table" then
+ if value.bg ~= nil and not _is_hex_color(value.bg) then
+ return false
+ end
- if _has_extra_color_keys(value) then
- return false
- end
+ if value.fg ~= nil and not _is_hex_color(value.fg) then
+ return false
+ end
- return true
- end
+ if value.gui ~= nil and type(value.gui) ~= "string" then
+ return false
+ end
+ if _has_extra_color_keys(value) then
return false
- end,
- 'a table. e.g. {fg="#000000", bg="#FFFFFF", gui="effect"}',
- },
- })
+ end
- if not success then
- table.insert(output, message)
- end
+ return true
+ end
+
+ return false
+ end, 'a table. e.g. {fg="#000000", bg="#FFFFFF", gui="effect"}')
return output
end
@@ -248,27 +259,17 @@ local function _get_lualine_issues(data)
local lualine = tabler.get_value(data, { "tools", "lualine" })
- local success, message = pcall(vim.validate, {
- ["tools.lualine"] = {
- lualine,
- function(value)
- if type(value) ~= "table" then
- return false
- end
-
- return true
- end,
- "a table. e.g. { goodnight_moon = {...}, hello_world = {...} }",
- },
- })
+ _append_validated(output, "tools.lualine", function()
+ return lualine
+ end, function(value)
+ if type(value) ~= "table" then
+ return false
+ end
- if not success then
- table.insert(output, message)
+ return true
+ end, "a table. e.g. { goodnight_moon = {...}, hello_world = {...} }")
- return output
- end
-
- if not lualine or vim.tbl_isempty(lualine) then
+ if not vim.tbl_isempty(output) then
return output
end
@@ -292,49 +293,37 @@ end
---@return string[] # All of the found issues, if any.
---
local function _get_logging_issues(data)
- local success, message = pcall(vim.validate, {
- ["logging"] = {
- data,
- function(value)
- if type(value) ~= "table" then
- return false
- end
-
- return true
- end,
- 'a table. e.g. { level = "info", ... }',
- },
- })
+ local output = {}
- if not success then
- return { message }
- end
+ _append_validated(output, "logging", function()
+ return data
+ end, function(value)
+ if type(value) ~= "table" then
+ return false
+ end
- local output = {}
+ return true
+ end, 'a table. e.g. { level = "info", ... }')
- success, message = pcall(vim.validate, {
- ["logging.level"] = {
- data.level,
- function(value)
- if type(value) ~= "string" then
- return false
- end
+ if not vim.tbl_isempty(output) then
+ return output
+ end
- if not vim.tbl_contains({ "trace", "debug", "info", "warn", "error", "fatal" }, value) then
- return false
- end
+ _append_validated(output, "logging.level", function()
+ return data.level
+ end, function(value)
+ if type(value) ~= "string" then
+ return false
+ end
- return true
- end,
- 'an enum. e.g. "trace" | "debug" | "info" | "warn" | "error" | "fatal"',
- },
- })
+ if not vim.tbl_contains({ "trace", "debug", "info", "warn", "error", "fatal" }, value) then
+ return false
+ end
- if not success then
- table.insert(output, message)
- end
+ return true
+ end, 'an enum. e.g. "trace" | "debug" | "info" | "warn" | "error" | "fatal"')
- message = _get_boolean_issue("logging.use_console", data.use_console)
+ local message = _get_boolean_issue("logging.use_console", data.use_console)
if message ~= nil then
table.insert(output, message)
@@ -359,87 +348,57 @@ local function _get_telescope_issues(data)
local telescope = tabler.get_value(data, { "tools", "telescope" })
- if not telescope then
- return {}
- end
-
- local success, message = pcall(vim.validate, {
- ["tools.telescope"] = {
- telescope,
- function(value)
- if type(value) ~= "table" then
- return false
- end
-
- return true
- end,
- "a table. e.g. { goodnight_moon = {...}, hello_world = {...}}",
- },
- })
+ _append_validated(output, "tools.telescope", function()
+ return telescope
+ end, function(value)
+ if type(value) ~= "table" then
+ return false
+ end
- if not success then
- table.insert(output, message)
+ return true
+ end, "a table. e.g. { goodnight_moon = {...}, hello_world = {...}}")
+ if not vim.tbl_isempty(output) then
return output
end
- success, message = pcall(vim.validate, {
- ["tools.telescope.goodnight_moon"] = {
- telescope.goodnight_moon,
- function(value)
- if value == nil then
- return true
- end
-
- if type(value) ~= "table" then
- return false
- end
-
- for _, item in ipairs(value) do
- if not texter.is_string_list(item) then
- return false
- end
-
- if #item ~= 2 then
- return false
- end
- end
-
- return true
- end,
- 'a table. e.g. { {"Book", "Author"} }',
- },
- })
+ _append_validated(output, "tools.telescope.goodnight_moon", function()
+ return telescope.goodnight_moon
+ end, function(value)
+ if value == nil then
+ return true
+ end
- if not success then
- table.insert(output, message)
+ if type(value) ~= "table" then
+ return false
+ end
- return output
- end
+ for _, item in ipairs(value) do
+ if not texter.is_string_list(item) then
+ return false
+ end
- success, message = pcall(vim.validate, {
- ["tools.telescope.hello_world"] = {
- telescope.hello_world,
- function(value)
- if value == nil then
- return true
- end
+ if #item ~= 2 then
+ return false
+ end
+ end
- if type(value) ~= "table" then
- return false
- end
+ return true
+ end, 'a table. e.g. { {"Book", "Author"} }')
- return texter.is_string_list(value)
- end,
- 'a table. e.g. { "Hello", "Hi", ...} }',
- },
- })
+ _append_validated(output, "tools.telescope.hello_world", function()
+ return telescope.hello_world
+ end, function(value)
+ if value == nil then
+ return true
+ end
- if not success then
- table.insert(output, message)
+ if type(value) ~= "table" then
+ return false
+ end
- return output
- end
+ return texter.is_string_list(value)
+ end, 'a table. e.g. { "Hello", "Hi", ...} }')
return output
end
@@ -455,6 +414,7 @@ function M.get_issues(data)
end
local output = {}
+ vim.list_extend(output, _get_cmdparse_issues(data))
vim.list_extend(output, _get_command_issues(data))
local logging = data.logging
diff --git a/spec/plugin_template/configuration_spec.lua b/spec/plugin_template/configuration_spec.lua
index e200f5c..f326ca5 100644
--- a/spec/plugin_template/configuration_spec.lua
+++ b/spec/plugin_template/configuration_spec.lua
@@ -86,11 +86,41 @@ end)
---@diagnostic disable: assign-type-mismatch
---@diagnostic disable: missing-fields
+describe("bad configuration - cmdparse", function()
+ it("happens with a bad type for #cmdparse.auto_complete.display.help_flag", function()
+ _assert_bad({
+ cmdparse = { auto_complete = { display = { help_flag = "aaa" } } },
+ }, { "cmdparse.auto_complete.display.help_flag: expected boolean, got string" })
+
+ _assert_bad({
+ cmdparse = { auto_complete = { display = 123 } },
+ }, { "cmdparse.auto_complete.display: expected table, got number" })
+
+ _assert_bad({ cmdparse = { auto_complete = "bnb" } }, { "cmdparse.auto_complete: expected table, got string" })
+
+ _assert_bad({ cmdparse = 123 }, { "cmdparse: expected table, got number" })
+ end)
+
+ it("works with an #empty configuration", function()
+ _assert_good({
+ cmdparse = { auto_complete = { display = { help_flag = true } } },
+ })
+
+ _assert_good({
+ cmdparse = { auto_complete = { display = { help_flag = false } } },
+ })
+
+ _assert_good({
+ cmdparse = { auto_complete = { display = { help_flag = nil } } },
+ })
+ end)
+end)
+
describe("bad configuration - commands", function()
it("happens with a bad type for #commands.goodnight_moon.phrase", function()
_assert_bad(
{ commands = { goodnight_moon = { read = { phrase = 10 } } } },
- { "commands.goodnight_moon.read.phrase: expected string, got number (10)" }
+ { "commands.goodnight_moon.read.phrase: expected string, got number" }
)
end)
@@ -144,11 +174,11 @@ describe("bad configuration - logging", function()
end)
it("happens with a bad value for #logging.use_console", function()
- _assert_bad({ logging = { use_console = "asdf" } }, { "logging.use_console: expected a boolean, got asdf" })
+ _assert_bad({ logging = { use_console = "aaa" } }, { "logging.use_console: expected a boolean, got aaa" })
end)
it("happens with a bad value for #logging.use_file", function()
- _assert_bad({ logging = { use_file = "asdf" } }, { "logging.use_file: expected a boolean, got asdf" })
+ _assert_bad({ logging = { use_file = "aaa" } }, { "logging.use_file: expected a boolean, got aaa" })
end)
end)
---@diagnostic enable: assign-type-mismatch
@@ -171,11 +201,11 @@ describe("health.check", function()
health.check({
commands = {
goodnight_moon = { read = { phrase = 123 } },
- hello_world = { say = { ["repeat"] = "asdf", style = 789 } },
+ hello_world = { say = { ["repeat"] = "aaa", style = 789 } },
},
logging = {
level = false,
- use_console = "asdf",
+ use_console = "aaa",
use_file = "fdas",
},
tools = {
@@ -190,11 +220,11 @@ describe("health.check", function()
local issues = tabler.get_slice(found, 1, #found - 1)
assert.same({
- "commands.goodnight_moon.read.phrase: expected string, got number (123)",
- "commands.hello_world.say.repeat: expected a number (value must be 1-or-more), got asdf",
+ "commands.goodnight_moon.read.phrase: expected string, got number",
+ "commands.hello_world.say.repeat: expected a number (value must be 1-or-more), got aaa",
'commands.hello_world.say.style: expected "lowercase" or "uppercase", got 789',
'logging.level: expected an enum. e.g. "trace" | "debug" | "info" | "warn" | "error" | "fatal", got false',
- "logging.use_console: expected a boolean, got asdf",
+ "logging.use_console: expected a boolean, got aaa",
"logging.use_file: expected a boolean, got fdas",
'tools.lualine.goodnight_moon: expected a table. e.g. { text="some text here" }, got false',
}, issues)
diff --git a/spec/plugin_template/plugin_template_spec.lua b/spec/plugin_template/plugin_template_spec.lua
index 8305e28..598d3a8 100644
--- a/spec/plugin_template/plugin_template_spec.lua
+++ b/spec/plugin_template/plugin_template_spec.lua
@@ -7,8 +7,13 @@
---@module 'plugin_template.plugin_template_spec'
---
+local configuration = require("plugin_template._core.configuration")
local copy_logs_runner = require("plugin_template._commands.copy_logs.runner")
local plugin_template = require("plugin_template")
+local vlog = require("plugin_template._vendors.vlog")
+
+---@class plugin_template.Configuration
+local _CONFIGURATION_DATA
---@type string[]
local _DATA = {}
@@ -35,6 +40,7 @@ local function _initialize_copy_log()
_DATA = { path }
end
+ _CONFIGURATION_DATA = vim.deepcopy(configuration.DATA)
copy_logs_runner._read_file = _save_path
end
@@ -54,6 +60,7 @@ end
local function _reset_copy_log()
copy_logs_runner._read_file = _ORIGINAL_COPY_LOGS_READ_FILE
+ configuration.DATA = _CONFIGURATION_DATA
_DATA = {}
end
@@ -117,7 +124,7 @@ describe("copy logs API", function()
after_each(_reset_copy_log)
it("runs with an explicit file path", function()
- local path = vim.fn.tempname() .. "copy_logs_test.txt"
+ local path = vim.fn.tempname() .. "copy_logs_test.log"
_make_fake_log(path)
plugin_template.run_copy_logs(path)
@@ -127,11 +134,14 @@ describe("copy logs API", function()
end)
it("runs with default arguments", function()
+ local expected = vim.fn.tempname() .. "copy_logs_default_test.log"
+ configuration.DATA.logging.outfile = expected
+ vlog.new(configuration.DATA.logging or {}, true)
+ _make_fake_log(expected)
+
plugin_template.run_copy_logs()
_wait_for_result()
- local expected = vim.fs.joinpath(vim.fn.expand("~"), ".local", "share", "nvim", "plugin_template.log")
-
assert.same({ expected }, _DATA)
end)
end)
@@ -141,7 +151,7 @@ describe("copy logs command", function()
after_each(_reset_copy_log)
it("runs with an explicit file path", function()
- local path = vim.fn.tempname() .. "copy_logs_test.txt"
+ local path = vim.fn.tempname() .. "copy_logs_test.log"
_make_fake_log(path)
vim.cmd(string.format('PluginTemplate copy-logs "%s"', path))
@@ -151,10 +161,14 @@ describe("copy logs command", function()
end)
it("runs with default arguments", function()
+ local expected = vim.fn.tempname() .. "copy_logs_default_test.log"
+ configuration.DATA.logging.outfile = expected
+ vlog.new(configuration.DATA.logging or {}, true)
+ _make_fake_log(expected)
+
vim.cmd([[PluginTemplate copy-logs]])
- _wait_for_result()
- local expected = vim.fs.joinpath(vim.fn.expand("~"), ".local", "share", "nvim", "plugin_template.log")
+ _wait_for_result()
assert.same({ expected }, _DATA)
end)