local mp = require 'mp' local msg = require 'mp.msg' local utils = require 'mp.utils' local o = require 'modules.options' local g = require 'modules.globals' local ass = require 'modules.ass' local scanning = require 'modules.navigation.scanning' local fb_utils = require 'modules.utils' local cursor = require 'modules.navigation.cursor' ---@class directory_movement local directory_movement = {} local NavType = scanning.NavType ---Appends an item to the directory stack, wiping any ---directories further ahead than the current position. ---@param dir string local function directory_stack_append(dir) -- don't clear the stack if we're re-entering the same directory if g.directory_stack.stack[g.directory_stack.position + 1] == dir then g.directory_stack.position = g.directory_stack.position + 1 return end local j = #g.directory_stack.stack while g.directory_stack.position < j do g.directory_stack.stack[j] = nil j = j - 1 end table.insert(g.directory_stack.stack, dir) g.directory_stack.position = g.directory_stack.position + 1 end ---@param dir string local function directory_stack_prepend(dir) table.insert(g.directory_stack.stack, 1, dir) g.directory_stack.position = 1 end ---Clears directories from the history ---@param from? number All entries >= this index are cleared. ---@return string[] function directory_movement.clear_history(from) ---@type string[] local cleared = {} from = from or 1 for i = g.history.size, from, -1 do table.insert(cleared, g.history.list[i]) g.history.list[i] = nil g.history.size = g.history.size - 1 if g.history.position >= i then g.history.position = g.history.position - 1 end end return cleared end ---Append a directory to the history ---If we have navigated backward in the history, ---then clear any history beyond the current point. ---@param directory string function directory_movement.append_history(directory) if g.history.list[g.history.position] == directory then msg.debug('reloading same directory - history unchanged:', directory) return end msg.debug('appending to history:', directory) if g.history.position < g.history.size then directory_movement.clear_history(g.history.position + 1) end table.insert(g.history.list, directory) g.history.size = g.history.size + 1 g.history.position = g.history.position + 1 if g.history.size > o.history_size then table.remove(g.history.list, 1) g.history.size = g.history.size - 1 end end ---@param filepath string function directory_movement.set_current_file(filepath) --if we're in idle mode then we want to open the working directory if filepath == nil then g.current_file.directory = fb_utils.fix_path( mp.get_property("working-directory", ""), true) g.current_file.name = nil g.current_file.path = nil g.current_file.original_path = nil return end local absolute_path = fb_utils.absolute_path(filepath) local resolved_path = fb_utils.resolve_directory_mapping(absolute_path) g.current_file.directory, g.current_file.name = utils.split_path(resolved_path) g.current_file.original_path = absolute_path g.current_file.path = resolved_path if o.cursor_follows_playing_item then cursor.select_playing_item() end ass.update_ass() end --the base function for moving to a directory ---@param directory string ---@param nav_type? NavigationType ---@param store_history? boolean default `true` ---@param parse_properties? ParseProperties ---@return thread function directory_movement.goto_directory(directory, nav_type, store_history, parse_properties) local current = g.state.list[g.state.selected] g.state.directory = directory if g.state.directory_label then if nav_type == NavType.DOWN then g.state.directory_label = g.state.directory_label..(current.label or current.name) elseif nav_type == NavType.UP then g.state.directory_label = string.match(g.state.directory_label, "^(.-/+)[^/]+/*$") end end if o.history_size > 0 and store_history == nil or store_history then directory_movement.append_history(directory) end return scanning.rescan(nav_type or NavType.GOTO, nil, parse_properties) end ---Move the browser to a particular point in the browser history. ---The history is a linear list of visited directories from oldest to newest. ---If the user changes directories while the current history position is not the head of the list, ---any later directories get cleared and the new directory becomes the new head. ---@param pos number The history index to move to. Clamped to [1,history_length] ---@return number|false # The index actually moved to after clamping. Returns -1 if the index was invalid (can occur if history is empty or disabled) function directory_movement.goto_history(pos) if type(pos) ~= "number" then return false end if pos < 1 then pos = 1 elseif pos > g.history.size then pos = g.history.size end if not g.history.list[pos] then return false end g.history.position = pos directory_movement.goto_directory(g.history.list[pos]) return pos end --loads the root list function directory_movement.goto_root() msg.verbose('jumping to root') return directory_movement.goto_directory("") end --switches to the directory of the currently playing file function directory_movement.goto_current_dir() msg.verbose('jumping to current directory') return directory_movement.goto_directory(g.current_file.directory) end --moves up a directory function directory_movement.up_dir() if g.state.directory == '' then return end local cached_parent_dir = g.directory_stack.stack[g.directory_stack.position - 1] if cached_parent_dir then g.directory_stack.position = g.directory_stack.position - 1 return directory_movement.goto_directory(cached_parent_dir, NavType.UP) end local parent_dir = g.state.directory:match("^(.-/+)[^/]+/*$") or "" if o.skip_protocol_schemes and parent_dir:find("^(%a[%w+-.]*)://$") then return directory_movement.goto_root() end directory_stack_prepend(parent_dir) return directory_movement.goto_directory(parent_dir, NavType.UP) end --moves down a directory function directory_movement.down_dir() local current = g.state.list[g.state.selected] if not current or not fb_utils.parseable_item(current) then return end local directory, redirected = fb_utils.get_new_directory(current, g.state.directory) directory_stack_append(directory) return directory_movement.goto_directory(directory, redirected and NavType.REDIRECT or NavType.DOWN) end --moves backwards through the directory history function directory_movement.back_history() msg.debug('moving backwards in history to', g.history.list[g.history.position-1]) if g.history.position == 1 then return end directory_movement.goto_history(g.history.position - 1) end --moves forward through the history function directory_movement.forwards_history() msg.debug('moving forwards in history to', g.history.list[g.history.position+1]) if g.history.position == g.history.size then return end directory_movement.goto_history(g.history.position + 1) end return directory_movement