Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/udayvir-singh/hibiscus.nvim
:hibiscus: Flavored Fennel Macros for Neovim
https://github.com/udayvir-singh/hibiscus.nvim
Last synced: about 2 months ago
JSON representation
:hibiscus: Flavored Fennel Macros for Neovim
- Host: GitHub
- URL: https://github.com/udayvir-singh/hibiscus.nvim
- Owner: udayvir-singh
- License: mit
- Created: 2022-03-31T06:54:07.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2024-06-21T05:29:17.000Z (3 months ago)
- Last Synced: 2024-06-21T23:14:17.082Z (3 months ago)
- Language: Fennel
- Homepage:
- Size: 99.6 KB
- Stars: 101
- Watchers: 2
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-neovim - udayvir-singh/hibiscus.nvim - Flavored :hibiscus: Fennel macro library. (Fennel / Quickfix)
README
# Hibiscus.nvim
> :hibiscus: Highly opinionated macros to elegantly write your neovim config.
Companion library for [tangerine](https://github.com/udayvir-singh/tangerine.nvim),
but it can also be used standalone.![Neovim version](https://img.shields.io/badge/For_Neovim-0.8-dab?style=for-the-badge&logo=neovim&logoColor=dab)
## 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](https://github.com/folke/lazy.nvim) plugin manager,
> you should create `/init.lua` instead.```lua
-- ~/.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 pathif 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
endif 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}
endvim.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:
```fennel
; 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.
Packer
```fennel
(local packer (require :packer))(packer.startup (lambda [use]
(use :udayvir-singh/hibiscus.nvim)))
```Using [hibiscus](https://github.com/udayvir-singh/hibiscus.nvim) macros:
```fennel
(require-macros :hibiscus.packer)(packer-setup {}) ; bootstraps packer
(packer
(use! :udayvir-singh/hibiscus.nvim))
```Paq
```fennel
(local paq (require :paq))(paq [
:udayvir-singh/hibiscus.nvim
])
```Lazy
```fennel
(local lazy (require :lazy))(lazy.setup [
:udayvir-singh/hibiscus.nvim
])
```# Packer Macros
```fennel
(require-macros :hibiscus.packer)
```#### packer-setup!
(packer-setup! {opts?})
Bootstraps packer and calls packer.init function with {opts?}.
#### packer!
(packer! {...})
Wrapper around packer.startup function, automatically adds packer to plugin list and syncs it.
#### use!
(use! {name} {...opts})
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:
```fennel
(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
```fennel
(require-macros :hibiscus.vim)
; or
(import-macros {: augroup!} :hibiscus.vim)
```## keymaps
#### map!
(map! {args} {lhs} {rhs} {desc?})
Defines vim keymap for the given modes from {lhs} to {rhs}.
##### Arguments:
{args} can contain the following values:
```fennel
; modes | options |
[ nivcx :remap :verbose :buffer :nowait :expr :unique :script ]
```- `verbose`: opposite to `silent`
- `remap`: opposite to `noremap`##### Examples:
```fennel
;; -------------------- ;;
;; VIMSCRIPT ;;
;; -------------------- ;;
(map! [n :buffer] :R "echo &rtp")
(map! [n :remap] :P "(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!
(augroup! {name} {cmds})
Defines autocmd group of {name} with {cmds} containing [args pattern cmd] chunks.
##### Arguments:
{args} can contain the following values:
```fennel
[ :nested :once :desc BufRead Filetype ...etc ]
```##### Examples:
```fennel
;; -------------------- ;;
;; 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!
(command! {args} {lhs} {rhs})
Defines user command {lhs} to {rhs}.
##### Arguments:
{args} can contain the same opts as `nvim_create_user_command`:
```fennel
[
:buffer
:bar
:bang
:register
:range (or )
:addr
:count
:nargs
:complete (or )
]
```##### Examples:
```fennel
;; -------------------- ;;
;; VIMSCRIPT ;;
;; -------------------- ;;
(command! [:range "%"] :Strip ",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!
(exec! {...})
Translates commands written in fennel to `vim.cmd` calls.
##### Example:
```fennel
(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:
```lua
vim.cmd("hi! link TSInclude Special")
vim.cmd("hi! DiagnosticVirtualTextError guibg=NONE")
vim.cmd("echo resolve(expand('~/path'))")
vim.cmd("echo '" .. variable .. "'")
```## misc
#### concat!
(concat! {sep} {...})
Smartly concats all values in {...} with {sep} at compile time.
Useful for breaking down large strings without any overhead.##### Example:
```fennel
(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}.
```fennel
(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}.
```fennel
(setlocal! filetype "md")
(setlocal! number)
```#### setglobal!
Works like command `:setglobal`, sets global vim option {name} without changing the local value.
```fennel
(setglobal! wrap)
```#### set+
Appends {val} to string-style option {name}.
```fennel
(set+ wildignore "*.foo")
```#### set^
Prepends {val} to string-style option {name}.
```fennel
(set^ wildignore ["*.foo" "*.baz"])
```#### rem!
Removes {val} from string-style option {name}.
```fennel
(rem! wildignore "*.baz")
```#### color!
Sets vim colorscheme to {name}.
```fennel
(color! :desert)
```## variables
#### g!
Sets global variable {name} to {val}.
```fennel
(g! mapleader " ")
```#### b!
Sets buffer scoped variable {name} to {val}.
```fennel
(b! gretting "Hello World!")
```# Core Macros
```fennel
(require-macros :hibiscus.core)
; or
(import-macros {: fstring} :hibiscus.core)
```## OOP
## class!
(class! {name} {...})
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:
```fennel
;; -------------------- ;;
;; 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! next []
"returns next item from stream."
(++ state.cursor)
(assert (<= state.cursor state.len)
"stack-stream: attempt to call next() on empty stream.")
(. self.stack state.cursor)));; -------------------- ;;
;; DEMO ;;
;; -------------------- ;;
(local st (stack:new [:a :b])) ; new method should be called to create a instance
(st:push :c)
(print (tostring st)) ; => "a b c"(local stream (stack-stream:new st))
(print (stream:next)) ; => "a"
(print (stream:next)) ; => "b"
```#### method!
(method! {name} {args} {...})
Defines a method within the scope of class.
The `self` variable is accessible from the scope of every method.
##### Example:
```fennel
(class! foo
(method! init [] {}) ; required for all classes(method! hello []
(print "hello world!")))
```#### metamethod!
(metamethod! {name} {args} {...})
Defines a metamethod within the scope of class.
The `self` variable is accessible from the scope of every metamethod.
See lua docs for list of valid metamethods.
##### Example:
```fennel
(class! foo
(method! init [] {}) ; required for all classes(metamethod! __tostring []
"example_string"))
```#### instanceof?
(instanceof? {val} {class})
Checks if {val} is an instance of {class}.
##### Example:
```fennel
(class! foo
(method! init [] {}))(local x (foo:new))
(instanceof? x foo) ; => true
(instanceof? {} foo) ; => false
```## general
#### dump!
(dump! {...})
Pretty prints {...} into human readable form.
#### or=
(or= {x} {...})
Checks if {x} is equal to any one of {...}.
#### fstring!
(fstring! {str})
Wrapper around string.format, works like javascript's template literates.
- `${...}` is parsed as variable
- `$(...)` is parsed as fennel code##### Examples:
```fennel
(local name "foo")
(fstring! "hello ${name}")(fstring! "${name}: two + four is $(+ 2 4).")
```#### enum!
(enum! {name} ...)
Defines enumerated values for names.
##### Example:
```fennel
(enum! A B C) ; A=1, B=2, C=3
```#### time!
(time! {label} ...)
Prints execution time of {...} in milliseconds.
##### Example:
```fennel
(time! :add
(+ 1 2)) ; add: [XXX]ms
```## checking values
```fennel
(nil? {x})
```> checks if value of {x} is nil.
```fennel
(empty? {x})
```> checks if {x} :: [string or table] is empty.
```fennel
(boolean? {x})
```> checks if {x} is of boolean type.
```fennel
(string? {x})
```> checks if {x} is of string type.
```fennel
(number? {x})
```> checks if {x} is of number type.
```fennel
(odd? {int})
```> checks if {int} is of odd parity.
```fennel
(even? {int})
```> checks if {int} is of even parity.
```fennel
(fn? {x})
```> checks if {x} is of function type.
```fennel
(table? {x})
```> checks if {x} is of table type.
```fennel
(seq? {tbl})
```> checks if {tbl} is valid list / array.
## number
```fennel
(inc! {int})
```> increments {int} by 1 and returns its value.
```fennel
(++ {variable})
```> increments {variable} by 1 and returns its value.
```fennel
(dec! {int})
```> decrements {int} by 1 and returns its value.
```fennel
(-- {variable})
```> decrements {variable} by 1 and returns its value.
## string
```fennel
(append! {variable} {str})
```> appends {str} to {variable}.
```fennel
(tappend! {tbl} {key} {str})
```> appends {str} to {key} of table {tbl}.
```fennel
(prepend! {variable} {str})
```> prepends {str} to {variable}.
```fennel
(tprepend! {tbl} {key} {str})
```> prepends {str} to {key} of table {tbl}.
```fennel
(split! {str} {sep})
```> splits {str} into a list at each {sep}.
## table
```fennel
(tmap! {tbl} {handler})
```> maps values in {tbl} with {handler}.
>
> {handler} takes in (val, key, tbl) as arguments and returns a new value.```fennel
(filter! {list} {handler})
```> filters values in {list} with {handler}.
>
> {handler} takes in (val) and returns a boolean.```fennel
(merge-list! {list1} {list2})
```> merges all values of {list1} and {list2} together, and returns a new list.
```fennel
(merge-tbl! {tbl1} {tbl2})
```> merges {tbl2} onto {tbl1}, and returns a new table.
```fennel
(merge! {tbl1} {tbl2})
```> merges {tbl1} and {tbl2}, correctly appending lists.
```fennel
(vmerge! {variable} {tbl})
```> merges values of {tbl} onto {variable}.
# End Credits
- [aniseed](https://github.com/Olical/aniseed): for introducing me to fennel
- [zest](https://github.com/tsbohc/zest.nvim): for inspiring `hibiscus.vim` macros