ややこしい計算は電卓に頼りたくなるのだけど、これが案外、面倒くさいという話を学生さんと交しました。
-
まずは、電卓アプリを起動するのが面倒。そして
-
数式を入力するのに、仕事の文脈と行き来しながら何度か数値をコピペするのが面倒。おまけに、
-
計算結果をコピーして、どこかに貼るのが面倒。
計算した結果はほぼ確実にどこかにペーストするのだから、計算結果は勝手にコピーされるべきだ。
というわけで、仕事の中心にいるテキストエティタ (neovim
- vim
の進化版) に自分が望む電卓機能を追加したというお話しです。
最初に Python との連携機能を用いた実装
こちらは Vim script 2行でできました。
py3 from math import *
command! -nargs=* P let @* = py3eval("str(<args>)") | echo @*
その心は :P 2 + 3 + 5
とやれば、結果の 10 を表示し、これをクリップボードにコピーします。neovim の文書に "*p
でペーストできることはもちろん、ほかのアプリ (Word, Excel, ブラウザ、なんでもあれ) にもペーストできます。
また、この設定の1行目で math
モジュールをインポートしているので、:P sin(pi / 6)
のような math
モジュールに定義されている定数や関数も簡単に利用できます。
つぎに NeoVim に組込まれている Lua を用いた実装。
NeoVim 0.5.0 は Lua を内包し、最近、利用できるようになった NeoVim 0.7.0 で Lua から NeoVim の機能拡張がしやすくなりました。
数式の文法は Python でも Lua でもほとんど違いはないだろうと思ったので、NeoVim がもともと含んでいる Lua で実装した方が軽いかと思って作ってみました。(もっとも、Python API を利用するパッケージがほかにあるから、Lua で実装する意義はほとんどないけれど)
前の実装よりすこしややこしいけれど、こんな感じです。
vim.api.nvim_create_user_command('C', function (args)
vim.fn.setreg('*', tostring(load('return ' .. args.args)()))
print(vim.fn.getreg('*'))
end, { nargs='+' } )
load
関数は eval
っぽい役割を果し、引数に与えられた文字列を本体とする関数を構成してくれるので、その場で呼び出して計算結果 (result
) を得ています。C
コマンドとともに書いた数式が Lua の引数 (args.args
) に与えられるので、それを return
と連結して load
関数に与えると、数式を評価する関数が得られます。これをその場で呼び出す(load(...)()
)ことで計算しています。
vim のレジスタには文字列を収めるものらしいので、保存する前に文字列化しています。ちなみに、setreg
の第一引数に与えている *
はクリップボードに該当する vim のレジスタです。
よくわからなかった、Python での from math import *
相当のことを Lua で実現する方法です。Lua の math
モジュールで定義されている要素を走査して、大域モジュール (_G
) に追加すればよいことを StackOverflow で学びました。
function using(module, ...)
for k,v in pairs(module) do
if _G[k] then
io.stderr:write("use: skipping duplicate symbol ", k, "\n")
else
_G[k] = module[k]
end
end
end
using(math)
もうすこし簡単にできないものかなぁ。