Tangerine provides a painless way to add fennel to your config.
- π₯ BLAZING fast, compile times in milliseconds
- π 100% support for interactive evaluation
- π Control over when and how to compile
- π Natively loads
nvim/init.fnl
HOTPOT π²
- Abstracts too much away from the user.
- Hooks onto lua package searchers to compile [harder to debug].
ANISEED πΏ
- Excessively feature rich for use in dotfiles.
- Blindly compiles all files that it founds, resulting in slow load times.
- Create file
plugin/0-tangerine.lua
to bootstrap tangerine:
Important
If you are using Lazy plugin manager,
you should create init.lua
instead of plugin/0-tangerine.lua
. (see #20)
-- ~/.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/tangerine.nvim", "v2.8")
-- for git head
bootstrap("https://github.com/udayvir-singh/tangerine.nvim")
- Call tangerine
setup()
function, see config for valid options:
-- ~/.config/nvim/plugin/0-tangerine.lua
require "tangerine".setup {}
- Invoke
:FnlCompile
manually or add hooks in setup.
π Now start writing your config in ~/.config/nvim/init.fnl
.
πΊ Optionally you can also install hibiscus for macros.
Only use a package manager if you haven't used ref
option in bootstrap function.
Packer
(local packer (require :packer))
(packer.startup (lambda [use]
(use :udayvir-singh/tangerine.nvim)))
Using hibiscus macros:
(require-macros :hibiscus.packer)
(packer-setup {}) ; bootstraps packer
(packer
(use! :udayvir-singh/tangerine.nvim))
Paq
(local paq (require :paq))
(paq [
:udayvir-singh/tangerine.nvim
])
Lazy
(local lazy (require :lazy))
(lazy.setup [
:udayvir-singh/tangerine.nvim
])
Tangerine comes with sane defaults so that you can get going without having to add much to your config:
local nvim_dir = vim.fn.stdpath [[config]]
{
vimrc = nvim_dir .. "/init.fnl",
source = nvim_dir .. "/fnl",
target = nvim_dir .. "/lua",
rtpdirs = {},
custom = {
-- list of custom [source target] chunks, for example:
-- {"~/.config/awesome/fnl", "~/.config/awesome/lua"}
},
compiler = {
float = true, -- show output in floating window
clean = true, -- delete stale lua files
force = false, -- disable diffing (not recommended)
verbose = true, -- enable messages showing compiled files
globals = vim.tbl_keys(_G), -- list of alowed globals in fennel code
-- wrapper function that provides access to underlying fennel compiler
-- useful if you want to modify fennel API or want to provide your own fennel compiler
adviser = function (fennel)
-- for example, adding a custom macro path:
-- fennel["macro-path"] = fennel["macro-path"] .. ";/custom/path/?.fnl"
return fennel
end,
-- version of fennel to use, [ latest, 1-4-0, 1-3-1, 1-3-0, 1-2-1, 1-2-0, 1-1-0, 1-0-0, 0-10-0, 0-9-2 ]
version = "latest",
-- hooks for tangerine to compile on:
-- "onsave" run every time you save fennel file in {source} dir
-- "onload" run on VimEnter event
-- "oninit" run before sourcing init.fnl [recommended than onload]
hooks = {}
},
eval = {
float = true, -- show results in floating window
luafmt = function() -- function that returns formatter with flags for peeked lua
-- optionally install lua-format by running `$ luarocks install --local --server=https://luarocks.org/dev luaformatter`
return {"~/.luarocks/bin/lua-format", "--column-limit", "80"}
end,
diagnostic = {
virtual = true, -- show errors in virtual text
timeout = 10 -- how long should the error persist
}
},
keymaps = {
-- set them to <Nop> if you want to disable them
eval_buffer = "gE",
peek_buffer = "gL",
goto_output = "gO",
float = {
next = "<C-K>",
prev = "<C-J>",
kill = "<Esc>",
close = "<Enter>",
resizef = "<C-W>=",
resizeb = "<C-W>-"
}
},
highlight = {
float = "Normal",
success = "String",
errors = "DiagnosticError"
},
}
Here is config that I use in my dotfiles:
{
-- save fnl output in a separate dir, it gets automatically added to package.path
target = vim.fn.stdpath [[data]] .. "/tangerine",
-- compile files in &rtp
rtpdirs = {
"plugin",
"colors",
"$HOME/mydir" -- absolute paths are also supported
},
compiler = {
-- disable popup showing compiled files
verbose = false,
-- compile every time you change fennel files or on entering vim
hooks = {"onsave", "oninit"}
}
}
Compiles current active fennel buffer.
Diff compiles all indexed fennel files.
If bang! is present then forcefully compiles all source
files.
Deletes stale or orphaned lua files in target
dir.
If bang! is present then it deletes all compiled lua files.
Executes and Evalutate {expr} of fennel.
:Fnl (print "Hello World")
-> Hello World
:Fnl (values some_var)
-> :return [ 1 2 3 4 ]
Evaluates {file} of fennel and outputs the result.
:FnlFile path/source.fnl
:FnlFile % ;; not recommended
Evaluates all lines or [range] in current fennel buffer.
mapped to
gE
by default.
Peek lua output for [range] in current fennel buffer.
mapped to
gL
by default.
Open lua output of current fennel buffer in a new buffer.
mapped to
gO
by default.
Jump to [N]th next floating window created by tangerine..
mapped to
CTRL-K
in floats by default.
Jump to [N]th previous floating window created by tangerine.
mapped to
CTRL-J
in floats by default.
Increase or Decrease floating window height by [N] factor.
mapped to
CTRL-W =
to increase andCTRL-W -
decrease by default.
Closes current floating window under cursor.
mapped to
ENTER
in floats by default.
Closes all floating windows made by tangerine.
mapped to
ESC
in floats by default.
Q: How to make tangerine compile automatically when you open vim
A: add hooks in config:
require [[tangerine]].setup {
compiler = {
-- if you want to compile before loading init.fnl (recommended)
hooks = {"oninit"}
-- if you want to compile after VimEnter event has fired
hooks = {"onenter"}
}
}
Q: How to tuck away compiled output in a separate directory
A: change target in config:
require [[tangerine]].setup {
target = "/path/to/your/dir"
}
Q: How to make impatient work with tangerine
A: bootstrap and require impatient before calling tangerine:
bootstrap "https://github.com/lewis6991/impatient.nvim"
require [[impatient]]
require [[tangerine]].setup {...}
Q: How to use lua files interchangeably with fennel files
A: lua files can simply be stored in fnl
dir:
fnl
βββ options.lua
βββ autocmd.fnl
; require both as normal modules in your config
(require :options)
(require :autocmd)
Q: How to fix errors in macros while migrating from hotpot
A: make sure that macro files are suffixed with -macros.fnl
.
utils
βββ neovim-macros.fnl
βββ packer-macros.fnl
see #2 and #30 for more information
By default tangerine provides the following api:
:Fnl tangerine.api
-> :return {
:compile {
:all (function 0)
:buffer (function 1)
:custom (function 2)
:dir (function 3)
:file (function 4)
:rtp (function 5)
:string (function 6)
:vimrc (function 7)
}
:clean {
:rtp (function 8)
:target (function 9)
:orphaned (function 10)
}
:eval {
:buffer (function 11)
:file (function 12)
:peek (function 13)
:string (function 14)
}
:win {
:next (function 15)
:prev (function 16)
:close (function 17)
:killall (function 18)
:resize (function 19)
}
:goto_output (function 20)
:serialize (function 21)
}
(tangerine.api.compile.string {str} {opts?})
Compiles string {str} of fennel, returns string of lua.
{
:filename <string>
:globals <list>
}
(tangerine.api.compile.file {source} {target} {opts?})
Compiles fennel {source} and writes output to {target}.
{
:filename <string>
:globals <list>
}
(tangerine.api.compile.dir {source} {target} {opts?})
Diff compiles files in {source} dir and outputs to {target} dir.
{
:force <boolean>
:float <boolean>
:verbose <boolean>
:globals <list>
}
{opts.force} disables diffing if set to true
(tangerine.api.compile.dir
:path/fnl
:path/lua
{:force false :float true :verbose true})
(tangerine.api.compile.buffer {opts?})
Compiles the current active fennel buffer.
{
:float <boolean>
:verbose <boolean>
:filename <string>
:globals <list>
}
(tangerine.api.compile.vimrc {opts?})
Diff compiles config.vimrc
to config.target
dir.
{
:force <boolean>
:float <boolean>
:verbose <boolean>
:filename <string>
:globals <list>
}
{opts.force} disables diffing if set to true
(tangerine.api.compile.rtp {opts?})
Diff compiles fennel files in config.rtpdirs
or {opts.rtpdirs}.
{
:rtpdirs <list>
:force <boolean>
:float <boolean>
:verbose <boolean>
:globals <list>
}
{opts.force} disables diffing if set to true
(tangerine.api.compile.rtp {
:rtpdirs ["colors" "plugin" "$HOME/mydir"]
:force false
:float true
:verbose true })
(tangerine.api.compile.custom {opts?})
Diff compiles fennel files indexed in config.custom
or {opts.custom}.
{
:custom <list>
:force <boolean>
:float <boolean>
:verbose <boolean>
:globals <list>
}
{opts.force} disables diffing if set to true
(tangerine.api.compile.custom {
:custom [["~/path/fnl" "~/path/lua"]]
:force false
:float true
:verbose true })
(tangerine.api.compile.all {opts?})
Diff compiles all indexed fennel files in config
.
{
:force <boolean>
:float <boolean>
:verbose <boolean>
:globals <list>
:rtpdirs <list>
:custom <list>
}
{opts.force} disables diffing if set to true
Provides functions to clean stale / orphaned lua files in target dirs.
(tangerine.api.clean.target {source} {target} {opts?})
Deletes orphaned? {target} after comparing against {source}.
{
:force <boolean>
}
{opts.force} deletes {target} without comparing if set to true
(tangerine.api.clean.rtp {opts?})
Deletes all orphaned lua files in config.rtpdirs
or {opts.rtpdirs}.
{
:force <boolean>
:float <boolean>
:verbose <boolean>
:rtpdirs <list>
}
{opts.force} deletes all compiled files if set to true
(tangerine.api.clean.orphaned {opts?})
Deletes all orphaned lua files indexed inside target
dirs.
{
:force <boolean>
:float <boolean>
:verbose <boolean>
:rtpdirs <list>
}
{opts.force} deletes all compiled files if set to true
(tangerine.api.eval.string {str} {opts?})
Evaluates string {str} of fennel, pretty prints the output.
{
:float <boolean>
:virtual <boolean>
:filename <string>
:offset <number> ;; line offset for errors
}
(tangerine.api.eval.file {path} {opts?})
Evaluates {path} of fennel, pretty prints the output.
{
:float <boolean>
:virtual <boolean>
:filename <string>
}
(tangerine.api.eval.buffer {start} {end} {opts?})
Evaluates lines {start} to {end} in current fennel buffer.
{
:float <boolean>
:virtual <boolean>
:filename <string>
}
(tangerine.api.eval.peek {start} {end} {opts?})
Peek lua output for lines {start} to {end} inside a scratch buffer.
{
:float <boolean>
:virtual <boolean>
:filename <string>
}
(tangerine.api.goto_output)
Open lua source of current fennel buffer in a new buffer.
(tangerine.api.serialize {...})
Returns human-readable representation of {...}.
(tangerine.api.serialize example)
-> ":return [ 1 2 3 4 ]"
Provides functions to interact with floating windows created by tangerine.
(tangerine.api.win.next {steps?})
Switch to next floating window by 1 or N {steps?}.
(tangerine.api.win.prev {steps?})
Switch to previous floating window by 1 or N {steps?}.
(tangerine.api.win.resize {factor})
Changes height of current floating window by {factor} of N.
(tangerine.api.win.close)
Closes current floating window, switching to nearest neighbor afterwards.
(tangerine.api.win.killall)
Closes all floating windows created by tangerine.
(tangerine.fennel {version?})
Provides access to fennel compiler used by tangerine.
{version} can be one of [ "latest"
"1-4-0"
"1-3-1"
"1-3-0"
"1-2-1"
"1-2-0"
"1-1-0"
"1-0-0"
"0-10-0"
"0-9-2"
]
Program | Description |
---|---|
pandoc | generates vimdoc |
lua | runs included fennel |
make | runs build instructions |
watchexec | build on changes (optional) |
bash | runs shell scripts |
utils | coreutils findutils gawk curl |
only GNU utils work; 9base or busybox should not work
git clone https://github.com/udayvir-singh/tangerine.nvim
cd tangerine.nvim
make <git-hooks>
make <target>
see make help
or below for information on targets.
Target | Description |
---|---|
fnl |
compiles fennel files |
deps |
copy required deps in lua folder |
vimdoc |
runs panvimdoc to generate vimdocs |
fnldoc |
generates module level documentation |
build |
combines fnl deps vimdoc fnldoc |
watch-build |
watches source dir, runs :build on changes |
clean |
deletes build and install dir |
install |
install tangerine on this system |
runner |
compiles test runner library |
test |
runs unit tests, will erase nvim config |
To build tangerine run:
$ make clean build
# or
$ make watch-build
To install tangerine run:
$ make install
Target | Description |
---|---|
git-pull |
safely fetches git repo, prevents conflicts with local changes |
git-skip |
makes git ignore changes to build files |
git-unskip |
reverts git-skip , makes build files trackable |
$ make git-skip # first thing that you should be running
# makes changes to tangerine
$ ...
$ make clean build
# commit changes
$ git commit -a -m "<msg>"
# cleanly fetch from origin
$ make git-pull
Helpers to generate detailed summary about lines of code in source files:
$ make loc-{language}
fennel
/test
bash
markdown
makefile
yaml
$ make loc-fennel
$ make loc-bash
:: γγγ¨γγ¦η½ηΌγγγγθγγͺ ::