戻る
6570c11
Neovimの設定をlispで書く
Emacsの利点として設定をLispで書ける点が挙げられるが
Neovimでも設定ファイルをLispで記述することが出来る。
Luaへコンパイル可能な言語には有名どころだと
MoonScript
や
Haxe
があるが、
Fennel
というLisp方言もある。
最新版の
0.8.1
のリリースも2021年2月と更新も盛んなようだ。
基本的にはLexical scopeを持つシンプルなLispだが、
Luaとの互換性を重視して設計されているようで手で書いたLuaと近い形にコンパイルされるのを利点としている。
Lispなので強力なマクロ機能が使えるのが素のLuaに対する利点と言える。
このFennelを使ってNeovimの設定を書けるプラグインとして
Aniseed
がある。
余談だがAniseedはアニスの果実の意味でフェンネルと同じ香り(アネトール)がする。
このプラグインは
$XDG_HOME_CONFIG/nvim/fnl/*
を
$XDG_HOME_CONFIG/nvim/lua/*
のコンフィグへとコンパイルする機能と
Fennelを使ってプラグインを書くための機能の2種類の機能があり、
またNeovimのapiのうち
lsp
と
treesitter
を除いたものへの薄いラッパー、
いくつかのユーティリティ関数も提供されている。
ユーティリティ関数については
:help aniseed
に全て書かれているがラッパーAPIの詳細は
nvim.lua
に準拠しているため
ここのドキュメントを参照する必要がある。
また当然ながらブートストラップのためのLuaは書く必要がある。
私はパッケージマネージャに
packer
を使っているため
packer.nvim
と
aniseed
をインストールする以下のスクリプトを
init.lua
としている。
function exists(file)
local ok, err, code = os.rename(file, file)
if not ok then
if code == 13 then
return true
end
end
return ok, err
end
local install_path = vim.fn.stdpath('data')..'/site/pack/packer/opt/'
if not exists(install_path..'packer.nvim') then
vim.cmd('!git clone https://github.com/wbthomason/packer.nvim '..install_path..'packer.nvim')
end
vim.cmd 'packadd packer.nvim'
if not exists(install_path..'aniseed') then
vim.cmd('!git clone https://github.com/Olical/aniseed '..install_path..'aniseed')
end
vim.cmd 'packadd aniseed'
vim.api.nvim_set_var('aniseed#env', true)
配列も連想配列(Luaでは配列と連想配列は同じ扱いだが)もLuaでは
{}
を使って書くが、
Fennelでは配列は
[]
、連想配列は
{}
を使って書く。
Fennelのatom(
:abc
のように書く)を使えばLuaの
{a = 42, b = "alpha"}
は
{:a 42 :b "alpha"}
と書ける。
また
each
を使うには素の配列ではダメで、
pairs
または
ipairs
を使う必要がある。
モジュールの宣言時に必要なパッケージを
require
出来る(Luaのパッケージも直接
require
出来る)が、
パッケージマネージャの設定より先にパッケージの
require
を書くとブートストラップが出来なくなるので
その場合は個別に
def
と
require
を使ってパッケージを読み込むべき。
fnl/init.fnl
、
fnl/cfg/completion.fnl
、
fnl/cfg/statusline.fnl
の順に載せる。
(module nvim-packages
{require {a aniseed.core
s aniseed.string
completion_cfg cfg.completion
statusline_cfg cfg.statusline
nvim aniseed.nvim
packer packer}})
(packer.startup (lambda []
(do
(each [_ pkg (pairs completion_cfg.packages)]
(use pkg))
(each [_ pkg (pairs statusline_cfg.packages)]
(use pkg))
(use "bakpakin/fennel.vim")
(use { 1 "Olical/aniseed" :opt true } )
(use { 1 "wbthomason/packer.nvim" :opt true } )
(use "lambdalisue/fern.vim")
(use "lambdalisue/nerdfont.vim")
(use "lambdalisue/fern-renderer-nerdfont.vim")
(use "lambdalisue/fern-git-status.vim")
(use "lambdalisue/fern-mapping-git.vim")
(use "lambdalisue/fern-hijack.vim")
(use "namachan10777/nvim-highlite-otynium")
(use { 1 "nvim-lua/plenary.nvim" :ft "lua" })
(use { 1 "tjdevries/manillua.nvim" :ft "lua" })
(use { 1 "euclidianAce/BetterLua.vim" :ft "lua" })
(use { 1 "pest-parser/pest.vim" :ft "pest" })
(use { 1 "ElmCast/elm-vim" :ft "elm"})
(use { 1 "prettier/vim-prettier" :ft ["typescript" "typescriptreact" "javascript"]})
(use { 1 "jalvesaq/Nvim-R" :ft "R" })
(use { 1 "qnighy/satysfi.vim" :ft "satysfi" })
(use { 1 "cespare/vim-toml" :ft "toml" })
(use { 1 "qnighy/lalrpop.vim" :ft "lalrpop" })
(use { 1 "namachan10777/tml.vim" :ft "tml" })
(use { 1 "ron-rs/ron.vim" :ft "ron" })
(use "t9md/vim-quickhl")
(use "nvim-treesitter/nvim-treesitter")
(use "nvim-treesitter/completion-treesitter"))))
(def treesitter (require "nvim-treesitter.configs"))
(completion_cfg.configure)
(statusline_cfg.configure)
(fn colorscheme [name]
(nvim.ex.colorscheme name))
(fn list [...]
[...])
(fn set_indent [confs]
(do
(nvim.ex.augroup :FileTypeIndent)
(nvim.ex.autocmd_)
(each [_ conf (pairs confs)]
(nvim.ex.autocmd "FileType"
(s.join "," conf.ft)
"setlocal"
(.. "tabstop=" conf.w)
(.. "shiftwidth=" conf.w)
(if conf.expand :expandtab :noexpandtab)))
(nvim.ex.augroup :END)))
(do
(nvim.ex.augroup :SaveEditPos)
(nvim.ex.autocmd_)
(nvim.ex.autocmd :BufReadPost "*" "if line(\"'\\\"\") > 1 && line(\"'\\\"\") <= line(\"$\") | exe \"normal! g`\\\"\" | endif")
(nvim.ex.augroup :END))
(set_indent (list
{:ft (list :typescript :typescriptreact :javascript)
:w 2
:expand true}
{:ft (list :python :haskell) :w 4 :expand true}
{:ft (list :yaml) :w 2 :expand true}
{:ft (list :plaintex :satysfi :tml) :w 2 :expand true}))
(nvim.set_keymap "n" "r" "diwi" { :noremap true })
(nvim.set_keymap "n" "j" "gj" { :noremap true })
(nvim.set_keymap "n" "k" "gk" { :noremap true })
(nvim.set_keymap "t" "<C-j>" "<C-\\><C-n>" { :noremap true })
(nvim.set_var "fern#renderer" "nerdfont")
(nvim.set_keymap "n" "<space>f" ":Fern . -drawer<CR>" { :noremap true })
(nvim.set_keymap "x" "<space>f" ":Fern . -drawer<CR>" { :noremap true })
(nvim.set_keymap "n" "<Space>m" "<Plug>(quickhl-manual-this)" { :noremap false })
(nvim.set_keymap "x" "<Space>m" "<Plug>(quickhl-manual-this)" { :noremap false })
(nvim.set_keymap "n" "<Space>M" "<Plug>(quickhl-manual-reset)" { :noremap false })
(nvim.set_keymap "x" "<Space>M" "<Plug>(quickhl-manual-reset)" { :noremap false })
(set nvim.bo.undofile true)
(set nvim.wo.foldmethod "marker")
(set nvim.o.undolevels 1024)
(set nvim.o.undoreload 8192)
(set nvim.o.swapfile false)
(set nvim.o.backup false)
(set nvim.o.writebackup false)
(set nvim.bo.tabstop 4)
(set nvim.bo.shiftwidth 4)
(set nvim.bo.expandtab false)
(set nvim.o.termguicolors true)
(set nvim.wo.number true)
(set nvim.wo.relativenumber true)
(set nvim.o.cmdheight 2)
(set nvim.o.hls true)
(set nvim.wo.list true)
(set nvim.o.listchars "tab:»-,trail:-,eol:↲,extends:»,precedes:«,nbsp:%")
(set nvim.o.hidden true)
(set nvim.o.updatetime 300)
(colorscheme "otynium")
(treesitter.setup {:ensure_installed "maintained"
:highlight {:enable true
:disable (list)}
:indent {:enable true}})
(module cfg.completion
{require {a aniseed.core
s aniseed.string
lsp vim.lsp
nvim aniseed.nvim}})
(def packages ["neovim/nvim-lspconfig"
"nvim-lua/completion-nvim"
"steelsojka/completion-buffers"
"nvim-lua/lsp-status.nvim"])
(fn attach_completion []
(do
(nvim.ex.augroup :AttachCompletion)
(nvim.ex.autocmd_)
(nvim.ex.autocmd :BufEnter "*" "lua require'completion'.on_attach()")))
(defn configure []
(let [lsp_status (require "lsp-status")
lspconfig (require "lspconfig")]
(do
(lsp_status.register_progress)
(lspconfig.pyright.setup {:on_attach lsp_status.on_attach
:capabilities lsp_status.capabilities})
(lspconfig.ocamllsp.setup {:on_attach lsp_status.on_attach
:capabilities lsp_status.capabilities})
(lspconfig.rust_analyzer.setup {:on_attach lsp_status.on_attach
:capabilities lsp_status.capabilities})
(lspconfig.texlab.setup {:on_attach lsp_status.on_attach
:capabilities lsp_status.capabilities})
(lspconfig.clangd.setup {:on_attach lsp_status.on_attach
:capabilities lsp_status.capabilities
:handlers (lsp_status.extensions.clangd.setup)})
(attach_completion)
(set nvim.g.completion_chain_complete_list
{:default [{:complete_items ["buffers"]}
{:mode [ "<c-p>"]}
{:mode [ "<c-n>"]}]
:python [{:complete_items ["lsp"]}
{:mode [ "<c-p>"]}
{:mode [ "<c-n>"]}]
:ocaml [{:complete_items ["lsp"]}
{:mode [ "<c-p>"]}
{:mode [ "<c-n>"]}]
:plaintex [{:complete_items ["lsp"]}
{:mode [ "<c-p>"]}
{:mode [ "<c-n>"]}]
:rust [{:complete_items ["lsp"]}
{:mode [ "<c-p>"]}
{:mode [ "<c-n>"]}]
:c [{:complete_items ["lsp"]}
{:mode [ "<c-p>"]}
{:mode [ "<c-n>"]}]
:cpp [{:complete_items ["lsp"]}
{:mode [ "<c-p>"]}
{:mode [ "<c-n>"]}]})
(nvim.ex.inoremap "<expr>" "<Tab>" "pumvisible() ? \"\\<C-n>\" : \"\\<Tab>\"")
(nvim.ex.inoremap "<expr>" "<S-Tab>" "pumvisible() ? \"\\<C-n>\" : \"\\<S-Tab>\"")
(set nvim.o.completeopt "menuone,noinsert,noselect")
(set nvim.o.shortmess (.. nvim.o.shortmess "c")))))
(module cfg.statusline
{require {a aniseed.core
s aniseed.string
lsp vim.lsp
nvim aniseed.nvim}})
(def packages [{1 "glepnir/galaxyline.nvim"
:branch "main"
:requires {1 "kyazdani42/nvim-web-devicons" :opt true}}])
(fn buffer_not_empty []
(~= (nvim.fn.empty (nvim.fn.expand "%:t")) 1))
(fn checkwidth []
(> (nvim.fn.winwidth 0) 80))
(fn lspStatus []
(let [lsp_status (require "lsp-status")]
(if (> (length (vim.lsp.buf_get_clients)) 0)
(lsp_status.status)
"no")))
(def aliases {"n" "NORMAL" "i" "INSERT" "c" "COMMAND" "V" "VISUAL" "^V" "VISUAL"})
(defn configure []
(let
[gl (require "galaxyline")
gls gl.section
colors {:bg "#282c34"
:yellow "#fabd2f"
:cyan "#008080"
:darkblue "#081633"
:green "#afd700"
:orange "#FF8800"
:purple "#5d4d7a"
:magenta "#d16d9e"
:grey "#c0c0c0"
:blue "#0087d7"
:red "#ec5f67"
}]
(do
(set gl.short_line_list ["LuaTree" "vista" "dbui"])
(set gls.left [{:FirstElement {:provider (lambda [] " ")
:highlight [colors.blue colors.yellow]}}
{:ViMode {:provider (lambda [] (. aliases (nvim.fn.mode)))
:separator ""
:separator_highlight [colors.yellow
(lambda []
(if (not (buffer_not_empty)) colors.purple colors.darkblue))]
:highlight [colors.magenta colors.yellow "bold"]}}
{:FileIcon {:provider "FileIcon"
:condition buffer_not_empty
:highlight [(lambda [] (require "galaxyline.provider_fileinfo").get_file_icon_color) colors.darkblue]}}
{:FileName {:provider ["FileIcon" "FileSize"]
:condition buffer_not_empty
:separator ""
:separator_highlight [colors.purple colors.darkblue]
:highlight [colors.magenta colors.darkblue]}}
{:GitIcon {:provider (lambda [] " ")
:condition buffer_not_empty
:highlight [colors.orange colors.purple]}}
{:GitBranch {:provider "GitBranch"
:condition buffer_not_empty
:highlight [colors.grey colors.purple]}}
{:DiffAdd {:provider "DiffAdd"
:icon (lambda [] " ")
:condition checkwidth
:highlight [colors.green colors.purple]}}
{:DiffModified {:provider "DiffModified"
:icon (lambda [] " ")
:condition checkwidth
:highlight [colors.green colors.purple]}}
{:DiffRemove {:provider "DiffRemove"
:icon (lambda [] " ")
:condition checkwidth
:highlight [colors.green colors.purple]}}
{:LeftEnd {:provider (lambda [] "")
:separator ""
:separator_highlight [colors.purple colors.bg]
:highlight [colors.purple colors.purple]}}
{:DiagonosticError {:provider "DiagnosticError"
:separator " "
:highlight [colors.red colors.bg]}}
{:Space {:provider (lambda [] " ")}}
{:DiagnosticWarn {:provider "DiagnosticWarn"
:separator " "
:highlight [colors.blue colors.bg]}}
{:LspStatus {:provider lspStatus}}])
(set gls.right [{:FileFormat {:provider "FileFormat"
:separator ""
:separator_highlight [colors.bg colors.purple]
:highlight [colors.grey colors.purple]}}
{:LineInfo {:provider "LineColumn"
:separator " | "
:separator_highlight [colors.darkblue colors.purple]
:highlight [colors.grey colors.purple]}}
{:LinePercent {:provider "LinePercent"
:separator ""
:separator_highlight [colors.darkblue colors.purple]
:highlight [colors.grey colors.darkblue]}}
{:ScrollBar {:provider "ScrollBar"
:highlight [colors.yellow colors.purple]}}])
(set gls.short_line_left [{:FileTypeName {:provider "FileTypeName"
:separator ""
:separator_highlight [colors.purple colors.bg]
:highlight [colors.grey colors.purple]}}
{:BufferIcon {:provider "BufferIcon"
:separator ""
:separator_highlight [colors.purple colors.bg]
:highlight [colors.grey colors.purple]}}])
)))