SkillAgentSearch skills...

Hibiscus.nvim

:hibiscus: Flavored Fennel Macros for Neovim

Install / Use

/learn @udayvir-singh/Hibiscus.nvim
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

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 -->

Neovim version

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.lua to bootstrap hibiscus:

NOTE: if you are using lazy plugin manager, you should create /init.lua instead.

-- ~/.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.

<details> <summary><b>Packer</b></summary><br>
(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 around config, loads string or list of module names.
  • depends -- wrapper around requires, 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 to silent
  • remap: opposite to noremap
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
View on GitHub
GitHub Stars106
CategoryDevelopment
Updated3mo ago
Forks5

Languages

Fennel

Security Score

92/100

Audited on Dec 10, 2025

No findings