فهرست سریع فصل‌ها
پیشرفتهفصل 15 از 20⏱ حدود 14 دقیقه

🌙آموزش init.lua و ساخت پلاگین Yazi

نوشتن پلاگین شخصی، Status و Header، DDS و رویدادها.

اینجا دیگه واقعاً وارد اتاق موتور می‌شیم. init.lua فایلیه که موقع بالا اومدن یازی اجرا می‌شه و می‌تونی توش رابط کاربری رو عوض کنی، پلاگین بنویسی و به رویدادها گوش بدی.

اولین قدم: اضافه کردن اطلاعات به نوار وضعیت

~/.config/yazi/init.lua
lua

-- نمایش مالک و گروه فایل در سمت راست نوار وضعیت
Status:children_add(function()
	local h = cx.active.current.hovered
	if not h or ya.target_family() ~= "unix" then
		return ""
	end
	return ui.Line {
		ui.Span(ya.user_name(h.cha.uid) or tostring(h.cha.uid)):fg("magenta"),
		":",
		ui.Span(ya.group_name(h.cha.gid) or tostring(h.cha.gid)):fg("magenta"),
		" ",
	}
end, 500, Status.RIGHT)

-- نمایش مقصد لینک نمادین در سمت چپ
Status:children_add(function(self)
	local h = self._current.hovered
	if h and h.link_to then
		return " -> " .. tostring(h.link_to)
	end
	return ""
end, 3300, Status.LEFT)

عدد وسط «اولویت» ــه: هرچی کوچیک‌تر، نزدیک‌تر به لبه. Status.LEFT و Status.RIGHT هم که معلومه.

هدر شخصی‌سازی‌شده

init.lua
lua

-- نمایش user@hostname در هدر — مخصوصاً وقتی SSH زدی به چند سرور مفیده
Header:children_add(function()
	if ya.target_family() ~= "unix" then return "" end
	return ui.Span((ya.user_name() or "?") .. "@" .. (ya.host_name() or "?") .. ":"):fg("blue")
end, 500, Header.LEFT)

Linemode سفارشی: حجم + تاریخ با هم

init.lua
lua

function Linemode:size_and_mtime()
	local time = math.floor(self._file.cha.mtime or 0)
	if time == 0 then
		time = ""
	elseif os.date("%Y", time) == os.date("%Y") then
		time = os.date("%b %d %H:%M", time)
	else
		time = os.date("%b %d  %Y", time)
	end
	local size = self._file:size()
	return string.format("%s %s", size and ya.readable_size(size) or "-", time)
end
yazi.toml
toml

[mgr]
linemode = "size_and_mtime"

نوشتن اولین پلاگین واقعی

بیا یه پلاگین بنویسیم که یه تب جدید می‌سازه و مستقیم می‌ره داخل پوشه‌ای که مکان‌نما روشه:

~/.config/yazi/plugins/smart-tab.yazi/main.lua
lua

--- @sync entry
return {
	entry = function()
		local h = cx.active.current.hovered
		ya.emit("tab_create", h and h.cha.is_dir and { h.url } or { current = true })
	end,
}
keymap.toml
toml

[[mgr.prepend_keymap]]
on   = [ "t", "t" ]
run  = "plugin smart-tab"
desc = "تب جدید در پوشه‌ی زیر مکان‌نما"
  • --- @sync entry یعنی این پلاگین همگام اجرا می‌شه و به وضعیت زنده‌ی برنامه (cx) دسترسی داره.
  • ya.emit یه دستور داخلی یازی رو صدا می‌زنه — دقیقاً همون دستورهایی که توی keymap می‌نویسی.
  • cx.active.current.hovered فایل زیر مکان‌نمای تب فعاله.

پرسیدن از کاربر

~/.config/yazi/plugins/quick-mkdir.yazi/main.lua
lua

local get_cwd = ya.sync(function() return cx.active.current.cwd end)

return {
	entry = function()
		local cwd = get_cwd()
		local value, event = ya.input {
			title = "اسم پوشه‌ی جدید:",
			pos = { "top-center", y = 3, w = 40 },
		}
		if event ~= 1 or not value or value == "" then return end
		if value == "." or value == ".." or value:find("/", 1, true) then
			return ya.notify { title = "نام نامعتبر", content = "فقط اسم یک پوشه رو بنویس.", timeout = 3, level = "warn" }
		end
		local ok, err = fs.create("dir", cwd:join(value))
		ya.notify {
			title = ok and "ساخته شد" or "ساخت ناموفق",
			content = ok and value or tostring(err),
			timeout = 3,
			level = ok and "info" or "error",
		}
	end,
}

این پلاگین ناهمگامه؛ ya.input و عملیات فایل نباید داخل تابع همگام اجرا بشن.ya.sync فقط مسیر فعلی رو میگیره. اسم پوشه مستقیم به API فایل داده میشه و وارد دستور شل نمیشه. برای اجرا، یه میان‌بر با run = "plugin quick-mkdir" تعریف کن.

توابع مفید تعاملی: ya.input (گرفتن متن)، ya.confirm (بله/خیر)، ya.notify (اعلان گوشه‌ی صفحه)، ya.which (منوی انتخاب کلید).

DDS — گوش دادن به رویدادها

یازی یه سیستم توزیع داده داره که می‌تونی به رویدادهاش مشترک بشی. مثلاً این پلاگین باعث می‌شه پوشه‌ی Downloads همیشه بر اساس تاریخ مرتب باشه و بقیه‌ی پوشه‌ها الفبایی:

~/.config/yazi/plugins/folder-rules.yazi/main.lua
lua

local function setup()
	ps.sub("ind-sort", function(opt)
		local cwd = cx.active.current.cwd
		if cwd:ends_with("Downloads") then
			opt.by, opt.reverse, opt.dir_first = "mtime", true, false
		else
			opt.by, opt.reverse, opt.dir_first = "natural", false, true
		end
		return opt
	end)
end
return { setup = setup }
init.lua
lua

require("folder-rules"):setup()

تأیید قبل از خروج وقتی چند تب بازه

~/.config/yazi/plugins/confirm-quit.yazi/main.lua
lua

local count = ya.sync(function() return #cx.tabs end)

local function entry()
	if count() < 2 then
		return ya.emit("quit", {})
	end
	local yes = ya.confirm {
		pos   = { "center", w = 62, h = 10 },
		title = "خروج؟",
		body  = ui.Text("چند تا تب باز داری. مطمئنی می‌خوای بری بیرون؟"):wrap(ui.Wrap.YES),
	}
	if yes then ya.emit("quit", {}) end
end

return { entry = entry }
keymap.toml
toml

[[mgr.prepend_keymap]]
on  = "q"
run = "plugin confirm-quit"

دیباگ کردن Lua

terminal
bash

# لاگ رو روشن کن
YAZI_LOG=debug yazi

# توی کد Lua:
#   ya.dbg("مقدار:", some_value)
#   ya.err("خطا رخ داد")

# خروجی رو ببین
tail -f ~/.local/state/yazi/yazi.log
🚀ya emit — کنترل یازی از بیرون
داخل شلی که از Yazi باز شده، YAZI_ID مشخصه و این دستورها همون نمونه رو کنترل میکنن:
terminal
bash

ya emit cd /var/log
ya emit reveal /etc/fstab
از یه ترمینال مستقل باید شناسه‌ی واقعی نمونه رو به ya emit-to بدی؛ پیام دلخواه DDS فقط وقتی کاری میکنه که پلاگینی مشترک اون رویداد شده باشه. همین قابلیت پشت خیلی از ترفندهای فصل بعده.

آموزش کار با Yazi برای توزیع‌های مختلف لینوکس کاربرد داره؛ مثال‌های نصب و تنظیم محیط با اولویت کاربری نوشته شدن که فدورا رو با تنظیمات پیش‌فرض نصب کرده. دستور نصب بسته‌ها و ابزارهای جانبی در توزیع‌های دیگه ممکنه متفاوت باشه.