Microのプラグイン開発の例として、現在開いているファイルのパスをクリップボードに保存するという処理を書いてみます。
Microでのプラグイン開発はinit.luaに処理を記述するか?配布できる形にするか?の2つの形式がありますが、内容を簡略化する為にinit.luaに記述する方式を取ります。
環境
Micro:2.0.11
今回追加したい機能はコマンドモードで
> cp path
を実行した時は、現在開いているファイルのパスをクリップボードに保存し、
> cp dir
を実行した時は、現在開いているファイルが配置されているディレクトリをクリップボードに保存します。
クリップボードに関しては、コマンドライン上でのクリップボードの利用方法をご覧ください。
※今回の内容を読み進める前に、上記のリンク先の記事を参考にして、wl-copyとosc52のコマンドを使用できるようにしておきましょう。
先に今回作成したコードを載せておきます。
~/.config/micro/init.lua
local micro = import("micro")
local config = import("micro/config")
local shell = import("micro/shell")
function init()
config.MakeCommand("cp", cp, config.NoComplete)
end
-- コマンド実行時に引数を取得する
function extractCpMode(args)
local mode = "";
for i = 1, #args do
mode = args[i]
end
return mode
end
-- 使用しているディスプレイサーバを取得する (wayland|x11|tty)
function getDisplayServerType()
local srv, err = shell.RunCommand("sh -c 'echo $XDG_SESSION_TYPE'")
if err == nil and srv:len() > 0 then
local strings = import("strings")
srv = strings.TrimRight(srv, "\n")
if srv:len() > 0 then
return srv
end
end
return "tty"
end
function cp(bp, args)
local mode = extractCpMode(args)
local path = bp.Buf.AbsPath
if mode == "dir" then
local fp = import("filepath")
path = fp.Dir(path)
end
local srv = getDisplayServerType()
if srv == "wayland" then
cmd = "sh -c 'echo -n \""..path.."\" | wl-copy'"
elseif srv == "tty" then
cmd = "sh -c 'echo -n \""..path.."\" | osc52'"
else
cmd = "sh -c 'echo -n \""..path.."\" | xclip -selection clipboard'"
end
local output, err = shell.RunInteractiveShell(cmd, false, false)
if err == nil then
micro.InfoBar():Message("copied filepath.")
else
micro.InfoBar():Error(err)
end
end
コードの解説になります。
extractCpMode関数に関しては省略します。
function getDisplayServerType()
local srv, err = shell.RunCommand("sh -c 'echo $XDG_SESSION_TYPE'")
if err == nil and srv:len() > 0 then
local strings = import("strings")
srv = strings.TrimRight(srv, "\n")
if srv:len() > 0 then
return srv
end
end
return "tty"
end
ですが、シェルモードで
sh -c 'echo $XDG_SESSION_TYPE
を実行し、その値を返します。
何も値が返ってこなかった場合は tty を返すようにしています。
この関数で注意すべき内容は、シェルモードを
RunCommand(input string) (string, error)
を介してコマンドを実行しているのですが、実行結果には必ず改行コードが付いてしまいますので、Go言語の strings パッケージにあるTrimRightメソッドで改行コードを削除しています。
micro/runtime/help/plugins.md at master · zyedidia/micro
Luaのコード内でGo言語のパッケージを使用できるようにしているのは、GopherLuaとgopher-luarによって実現しています。
yuin/gopher-lua: GopherLua: VM and compiler for Lua in Go
layeh/gopher-luar: simplifies data passing to and from gopher-lua
使い方は
local strings = import("strings")
srv = strings.TrimRight(srv, "\n")
import関数でGo言語のパッケージを読み込み、Go言語の仕様と同様にドット区切りでメソッドを呼び出します。
strings package - strings#TrimRight - Go Packages
使用可能なメソッドはmicro/internal/lua/lua.go at master · zyedidia/microをご確認ください。
続いて見るべきコードは cp 関数内にあります
local path = bp.Buf.AbsPath
になります。
BufのAbsPathはbuffer package - github.com/zyedidia/micro/v2/internal/buffer#SharedBuffer - Go Packagesを参考にしました。
cp 関数内の下記の処理にも触れておきます。
local srv = getDisplayServerType() if srv == "wayland" then cmd = "sh -c 'echo -n \""..path.."\" | wl-copy'" elseif srv == "tty" then cmd = "sh -c 'echo -n \""..path.."\" | osc52'" else cmd = "sh -c 'echo -n \""..path.."\" | xclip -selection clipboard'" end local output, err = shell.RunInteractiveShell(cmd, false, false)
になります。
ディスプレイサーバに合わせて、クリップボードに文字列を保存するコマンドを生成してシェルモードで実行なのですが、今回は
RunInteractiveShell(input string, wait bool, getOutput bool) (string, error)
を利用しています。
何故、ディスプレイサーバの確認時と異なるメソッドを使用する必要があるのか?
これは、RunInteractiveShellの引数にあります wait と getOutput を使用したいからになります。
micro/runtime/help/plugins.md at master · zyedidia/micro
Microのシェルモードで wl-copy を実行すると、実行結果がない状態でエンターキーの入力待ちになります。
※ シェルモードで echo を実行すると待機にはなりますが、実行結果がある為、RunCommandでも問題ないようです。
入力待ち状態を回避するために、wait と getOutput のパラメータを false にしておく必要があります。
追記
tmuxを起動した状態で、Microを開いた時、
> cp path
をしても意図通りに動作しないことがあります。
tmuxの設定を変更する - ターミナルの内容を参考にして、tmux上でクリップボードを使用できるようにしておきましょう。
~/.tmux.conf
set -g set-clipboard on