old
1-- Auto-Layout Yazi Plugin
2-- From https://github.com/josephschmitt/auto-layout.yazi
3-- Automatically adjusts the number of Yazi panes based on terminal width.
4-- Attempts to use Yazi's configured ratios via `rt.mgr.ratio`.
5-- Falls back to fixed internal ratios if `rt.mgr.ratio` is unavailable.
6--
7-- Usage in init.lua:
8-- require("auto-layout").setup({
9-- breakpoint_large = 110, -- Width threshold for 3 panes (default: 100)
10-- breakpoint_medium = 60, -- Width threshold for 2 panes (default: 50)
11-- })
12-- If setup is not called, default breakpoints are used.
13
14-- --- Debug Flag ---
15-- Set to true to enable logging to the file specified below.
16local DEBUG_MODE = false
17
18-- --- Logging Setup ---
19local log_file_path = "/tmp/yazi-autolayout-debug.log"
20local log_enabled = DEBUG_MODE
21local function write_log(level, message) if not log_enabled then return end local success, file_or_err = pcall(io.open, log_file_path, "a") if success and file_or_err then local file = file_or_err local timestamp = os.date("%Y-%m-%d %H:%M:%S") local write_success, write_err = pcall(function() file:write(string.format("[%s] [%s] %s\n", timestamp, level, message)) file:flush() file:close() end) if not write_success then io.stderr:write(string.format("[auto-layout] LOG WRITE ERROR: %s\n", tostring(write_err))) end else io.stderr:write(string.format("[auto-layout] LOG FILE ERROR: Could not open %s - %s\n", log_file_path, tostring(file_or_err))) end end
22local function log_info(message) write_log("INFO", message) end
23local function log_warn(message) write_log("WARN", message) end
24local function log_error(message) write_log("ERROR", message) end
25if DEBUG_MODE then local success, file_or_err = pcall(io.open, log_file_path, "w"); if success and file_or_err then file_or_err:close() end end
26-- --- End Logging Setup ---
27
28
29-- --- Configuration ---
30local plugin_config = {
31 breakpoint_large = 100,
32 breakpoint_medium = 50,
33}
34-- Define fallback ratios in case Yazi's runtime ratios are unavailable.
35local fallback_ratios = { parent = 2, current = 3, preview = 4, all = 9 }
36-- --- End Configuration ---
37
38
39-- --- Plugin Module ---
40local M = {}
41
42local original_layout = nil
43local layout_overridden = false
44
45-- Get layout ratios, trying the modern 'rt.mgr.ratio' first.
46local function get_layout_ratios()
47 local using_fallback = true -- Assume fallback needed initially
48 local ratios = fallback_ratios -- Default to fallback
49
50 log_info("Attempting to get ratios from rt.mgr.ratio...")
51 -- Check the modern Yazi runtime object path
52 if rt and rt.mgr and rt.mgr.ratio and
53 rt.mgr.ratio.parent and rt.mgr.ratio.current and
54 rt.mgr.ratio.preview and rt.mgr.ratio.all then
55 log_info(" -> Success: Found ratios in rt.mgr.ratio.")
56 ratios = rt.mgr.ratio
57 using_fallback = false
58 else
59 -- Log the specific reason for failure if possible
60 if not rt then log_warn(" -> Failed: 'rt' object not available.")
61 elseif not rt.mgr then log_warn(" -> Failed: 'rt.mgr' not available.")
62 elseif not rt.mgr.ratio then log_warn(" -> Failed: 'rt.mgr.ratio' not available.")
63 else log_warn(" -> Failed: One or more required ratios (parent, current, preview, all) missing in rt.mgr.ratio.") end
64 log_warn(" -> Using fallback ratios.")
65 end
66 return ratios, using_fallback
67end
68
69-- The layout override function
70local function auto_layout_override(self)
71 log_info("--- Tab:layout Start ---")
72
73 if not self._area or not self._area.w then
74 log_error("ERROR - self._area or self._area.w is nil!")
75 if original_layout then original_layout(self) end
76 return
77 end
78 if not ui or not ui.Layout or not ui.Constraint then
79 log_error("ERROR - 'ui' object or components not available!")
80 if original_layout then original_layout(self) end
81 return
82 end
83
84 local w = self._area.w
85 -- Get ratios using the function that tries 'rt.mgr.ratio' first
86 local ratios, using_fallback = get_layout_ratios()
87
88 log_info(string.format("Width=%d, Ratios: p=%d, c=%d, pv=%d, all=%d%s",
89 w, ratios.parent, ratios.current, ratios.preview, ratios.all,
90 using_fallback and " (FALLBACK)" or " (FROM rt.mgr.ratio)"))
91
92 local success, result = pcall(function()
93 local constraints = nil
94 local layout_type = ""
95 if w > plugin_config.breakpoint_large then
96 layout_type = "3-column"
97 constraints = {
98 ui.Constraint.Ratio(ratios.parent, ratios.all),
99 ui.Constraint.Ratio(ratios.current, ratios.all),
100 ui.Constraint.Ratio(ratios.preview, ratios.all),
101 }
102 elseif w > plugin_config.breakpoint_medium then
103 layout_type = "2-column"
104 constraints = {
105 ui.Constraint.Ratio(0, ratios.all),
106 ui.Constraint.Ratio(ratios.current + ratios.parent, ratios.all),
107 ui.Constraint.Ratio(ratios.preview + ratios.parent, ratios.all),
108 }
109 else
110 layout_type = "1-column"
111 constraints = {
112 ui.Constraint.Ratio(0, ratios.all),
113 ui.Constraint.Ratio(ratios.all, ratios.all),
114 ui.Constraint.Ratio(0, ratios.all),
115 }
116 end
117
118 log_info(string.format("Applying %s layout.", layout_type))
119 self._chunks = ui.Layout() :direction(ui.Layout.HORIZONTAL) :constraints(constraints) :split(self._area)
120 if not self._chunks then error("Layout split returned nil chunks") end
121 end)
122
123 if not success or not self._chunks then
124 log_error(string.format("ERROR - Layout failed (success=%s): %s. Falling back.", tostring(success), tostring(result or "chunks nil")))
125 if original_layout then original_layout(self) end
126 else
127 log_info("Layout split successful.")
128 end
129 log_info("--- Tab:layout End ---")
130end
131
132-- Setup function
133function M.setup(user_config)
134 if DEBUG_MODE and not layout_overridden then
135 print(string.format("[auto-layout] DEBUG MODE ENABLED. Logging to: %s", log_file_path))
136 end
137 log_info("--- Plugin Setup Start ---")
138
139 if type(user_config) == "table" then
140 log_info("Applying user config:")
141 for k, v in pairs(user_config) do
142 if plugin_config[k] ~= nil then
143 log_info(string.format(" Setting plugin_config[%s] = %s", k, tostring(v)))
144 plugin_config[k] = v
145 else
146 log_warn(string.format("WARN - Ignoring unknown config key: %s", k))
147 end
148 end
149 else
150 log_info("No user config provided or invalid type.")
151 end
152 log_info(string.format("Final plugin config - large: %d, medium: %d", plugin_config.breakpoint_large, plugin_config.breakpoint_medium))
153
154 if layout_overridden then
155 log_warn("WARN - Tab:layout already overridden. Skipping.")
156 return
157 end
158
159 log_info("Attempting to override Tab:layout...")
160 if not Tab then
161 log_error("ERROR - Cannot override layout: Global 'Tab' is not available!")
162 return
163 end
164
165 if not original_layout then
166 log_info("Storing original Tab.layout function.")
167 original_layout = Tab.layout
168 if not original_layout then
169 log_warn("WARN - Original Tab.layout is nil! Fallback may not work.")
170 original_layout = function() log_error("ERROR - Executing dummy original_layout (original was nil).") end
171 end
172 end
173
174 log_info("Assigning auto_layout_override to Tab.layout.")
175 Tab.layout = auto_layout_override
176 layout_overridden = true
177 log_info("Tab:layout override complete.")
178 log_info("--- Plugin Setup End ---")
179end
180
181return M