Hibiscus.nvim
:hibiscus: Flavored Fennel Macros for Neovim
Install / Use
/learn @udayvir-singh/Hibiscus.nvimREADME
Hibiscus.nvim
:hibiscus: Highly opinionated macros to elegantly write your neovim config.
Companion library for tangerine, but it can also be used standalone.
<!-- ignore-line -->Rational
- :candy: Syntactic eye candy over hellscape of lua api
- :tanabata_tree: Provides missing features in both fennel and nvim api
Installation
- Create file
plugin/0-tangerine.luato bootstrap hibiscus:
NOTE: if you are using lazy plugin manager, you should create
/init.luainstead.
-- ~/.config/nvim/plugin/0-tangerine.lua or ~/.config/nvim/init.lua
-- pick your plugin manager
local pack = "tangerine" or "packer" or "paq" or "lazy"
local function bootstrap(url, ref)
local name = url:gsub(".*/", "")
local path
if pack == "lazy" then
path = vim.fn.stdpath("data") .. "/lazy/" .. name
vim.opt.rtp:prepend(path)
else
path = vim.fn.stdpath("data") .. "/site/pack/".. pack .. "/start/" .. name
end
if vim.fn.isdirectory(path) == 0 then
print(name .. ": installing in data dir...")
vim.fn.system {"git", "clone", url, path}
if ref then
vim.fn.system {"git", "-C", path, "checkout", ref}
end
vim.cmd "redraw"
print(name .. ": finished installing")
end
end
-- for stable version [recommended]
bootstrap("https://github.com/udayvir-singh/hibiscus.nvim", "v1.7")
-- for git head
bootstrap("https://github.com/udayvir-singh/hibiscus.nvim")
- Require a macro library at top of your fennel modules:
; require all macros
(require-macros :hibiscus.core)
(require-macros :hibiscus.vim)
; require specific macros [you can also rename them]
(import-macros {:fstring! f!} :hibiscus.core)
(import-macros {: map!} :hibiscus.vim)
:tada: Now start using these macros in your config
Package Management
Only use a package manager if you haven't used ref option in bootstrap function.
(local packer (require :packer))
(packer.startup (lambda [use]
(use :udayvir-singh/hibiscus.nvim)))
Using hibiscus macros:
(require-macros :hibiscus.packer)
(packer-setup {}) ; bootstraps packer
(packer
(use! :udayvir-singh/hibiscus.nvim))
</details>
<details>
<summary><b>Paq</b></summary><br>
(local paq (require :paq))
(paq [
:udayvir-singh/hibiscus.nvim
])
</details>
<details>
<summary><b>Lazy</b></summary><br>
(local lazy (require :lazy))
(lazy.setup [
:udayvir-singh/hibiscus.nvim
])
</details>
Packer Macros
(require-macros :hibiscus.packer)
packer-setup!
<pre lang="fennel"><code>(packer-setup! {opts?}) </pre></code>Bootstraps packer and calls packer.init function with {opts?}.
packer!
<pre lang="fennel"><code>(packer! {...}) </pre></code>Wrapper around packer.startup function, automatically adds packer to plugin list and syncs it.
use!
<pre lang="fennel"><code>(use! {name} {...opts}) </pre></code>Much more lisp friendly wrapper over packer.use function.
Extra Options:
require-- wrapper aroundconfig, loads string or list of module names.depends-- wrapper aroundrequires, configures plugin dependencies with lisp friendly syntax.
Examples:
(packer!
(use! :udayvir-singh/hibiscus.nvim)
(use! :plugin-foo
:require ["path.mod1" "path.mod2"]) ; automatically requires these modules
(use! :plugin-baz
:depends [ ; define dependencies in same syntax as use!
"example1"
["example2" :after "hibiscus.nvim" :require "xyz"]
]))
Neovim Macros
(require-macros :hibiscus.vim)
; or
(import-macros {: augroup!} :hibiscus.vim)
keymaps
map!
<pre lang="fennel"><code>(map! {args} {lhs} {rhs} {desc?}) </pre></code>Defines vim keymap for the given modes from {lhs} to {rhs}.
Arguments:
{args} can contain the following values:
; modes | options |
[ nivcx :remap :verbose :buffer :nowait :expr :unique :script ]
verbose: opposite tosilentremap: opposite tonoremap
Examples:
;; -------------------- ;;
;; VIMSCRIPT ;;
;; -------------------- ;;
(map! [n :buffer] :R "echo &rtp")
(map! [n :remap] :P "<Plug>(some-function)")
;; -------------------- ;;
;; FENNEL ;;
;; -------------------- ;;
(map! [nv :expr] :j
`(if (> vim.v.count 0) "j" "gj"))
(local greet #(print "Hello World!"))
(map! [n] :gH `greet ; optionally quote to explicitly indicate a function
"greets the world!")
autocmds
augroup!
<pre lang="fennel"><code>(augroup! {name} {cmds}) </pre></code>Defines autocmd group of {name} with {cmds} containing [args pattern cmd] chunks.
Arguments:
{args} can contain the following values:
[ :nested :once :desc <desc> BufRead Filetype ...etc ]
Examples:
;; -------------------- ;;
;; VIMSCRIPT ;;
;; -------------------- ;;
(augroup! :spell
[[FileType] [markdown gitcommit] "setlocal spell"])
(augroup! :MkView
[[BufWinLeave
BufLeave
BufWritePost
BufHidden
QuitPre :nested] ?* "silent! mkview!"]
[[BufWinEnter] ?* "silent! loadview"])
(augroup! :buffer-local
[[Event] `(buffer 0) "echo 'hello'"])
;; -------------------- ;;
;; FENNEL ;;
;; -------------------- ;;
(augroup! :highlight-yank
[[TextYankPost :desc "highlights yanked region."]
* #(vim.highlight.on_yank {:timeout 80})])
(local greet #(print "Hello World!"))
(augroup! :greet
[[BufRead] *.sh `(print :HOLLA)]
[[BufRead] * `hello] ; remember to quote functions to indicate they are callbacks
commands
command!
<pre lang="fennel"><code>(command! {args} {lhs} {rhs}) </pre></code>Defines user command {lhs} to {rhs}.
Arguments:
{args} can contain the same opts as nvim_create_user_command:
[
:buffer <number>
:bar <boolean>
:bang <boolean>
:register <boolean>
:range (or <boolean> <string>)
:addr <string>
:count <string>
:nargs <string>
:complete (or <string> <function>)
]
Examples:
;; -------------------- ;;
;; VIMSCRIPT ;;
;; -------------------- ;;
(command! [:range "%"] :Strip "<line1>,<line2>s: \\+$::e")
;; -------------------- ;;
;; FENNEL ;;
;; -------------------- ;;
(fn greet [opts]
(print :hello opts.args))
(command! [:nargs 1 :complete #["world"]] :Greet `greet) ; quoting is optional in command! macro
(command! [:buffer 0 :bang true] :Lhs #(print $.bang))
vimscript
exec!
<pre lang="fennel"><code>(exec! {...}) </pre></code>Translates commands written in fennel to vim.cmd calls.
Example:
(exec!
; setting highlights
[hi! link TSInclude Special]
[hi! DiagnosticVirtualTextError guibg=NONE]
; calling vimscript functions
[echo (resolve (expand "~/path"))]
; injecting commands by quoting [dangerous]
[echo `(.. "'" variable "'")])
Lua output:
vim.cmd("hi! link TSInclude Special")
vim.cmd("hi! DiagnosticVirtualTextError guibg=NONE")
vim.cmd("echo resolve(expand('~/path'))")
vim.cmd("echo '" .. variable .. "'")
misc
concat!
<pre lang="fennel"><code>(concat! {sep} {...}) </pre></code>Smartly concats all values in {...} with {sep} at compile time. Useful for breaking down large strings without any overhead.
Example:
(concat! "\n"
"first line"
"second line"
"third line") ; => "first line\nsecond line\nthird line"
vim options
set!
Works like command :set, sets vim option {name}.
(set! tabstop 4)
(set! nobackup)
(set! wrap!)
(each [_ opt (ipairs ["number" "rnu"])]
(set! opt true))
setlocal!
Works like command :setlocal, sets local vim option {name}.
(setlocal! filetype "md")
(setlocal! number)
setglobal!
Works like command :setglobal, sets global vim option {name} without changing the local value.
(setglobal! wrap)
set+
Appends {val} to string-style option {name}.
(set+ wildignore "*.foo")
set^
Prepends {val} to string-style option {name}.
(set^ wildignore ["*.foo" "*.baz"])
rem!
Removes {val} from string-style option {name}.
(rem! wildignore "*.baz")
color!
Sets vim colorscheme to {name}.
(color! :desert)
variables
g!
Sets global variable {name} to {val}.
(g! mapleader " ")
b!
Sets buffer scoped variable {name} to {val}.
(b! gretting "Hello World!")
Core Macros
(require-macros :hibiscus.core)
; or
(import-macros {: fstring} :hibiscus.core)
OOP
class!
<pre lang="fennel"><code>(class! {name} {...}) </pre></code>Defines a new class (object-oriented programming) with {name}.
An init method must be present in all classes and it should return the base table for class.
To create a instance of class, call new method on {name}.
Examples:
;; -------------------- ;;
;; DEFINING CLASSES ;;
;; -------------------- ;;
(class! stack
(method! init [list] list) ; arguments of new method are passed here
(method! push [val]
"inserts {val} into the stack."
(table.insert self val)) ; self variable is accessible from all methods
(metamethod! __tostring []
"converts stack into a string."
(table.concat self " ")))
(class! stack-stream
(local state {:cursor 0})
(method! init [stack]
(set state.len (# stack)) ; private state
{: stack}) ; public state
(method! n
