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