init
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-----------------------------------------List Formatting------------------------------------------------
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
|
||||
local g = require 'modules.globals'
|
||||
local o = require 'modules.options'
|
||||
local fb_utils = require 'modules.utils'
|
||||
|
||||
local state = g.state
|
||||
local style = g.style
|
||||
local ass = g.ass
|
||||
|
||||
--- https://www.unicode.org/reports/tr9/#Explicit_Directional_Isolates
|
||||
local ISOLATE_DIRECTION_START = '\226\129\168' -- U+2068 FIRST STRONG ISOLATE
|
||||
local ISOLATE_DIRECTION_END = '\226\129\169' -- U+2069 POP DIRECTIONAL ISOLATE
|
||||
|
||||
local function draw()
|
||||
ass:update()
|
||||
end
|
||||
|
||||
local function remove()
|
||||
ass:remove()
|
||||
end
|
||||
|
||||
---@type string[]
|
||||
local string_buffer = {}
|
||||
|
||||
---appends the entered text to the overlay
|
||||
---@param ... string
|
||||
local function append(...)
|
||||
for i = 1, select("#", ...) do
|
||||
table.insert(string_buffer, select(i, ...) or '' )
|
||||
end
|
||||
end
|
||||
|
||||
--appends a newline character to the osd
|
||||
local function newline()
|
||||
table.insert(string_buffer, '\\N')
|
||||
end
|
||||
|
||||
local function flush_buffer()
|
||||
ass.data = table.concat(string_buffer, '')
|
||||
string_buffer = {}
|
||||
end
|
||||
|
||||
---detects whether or not to highlight the given entry as being played
|
||||
---@param v Item
|
||||
---@return boolean
|
||||
local function highlight_entry(v)
|
||||
if g.current_file.path == nil then return false end
|
||||
local full_path = fb_utils.get_full_path(v)
|
||||
local alt_path = v.name and g.state.directory..v.name or nil
|
||||
|
||||
if fb_utils.parseable_item(v) then
|
||||
return (
|
||||
string.find(g.current_file.directory, full_path, 1, true)
|
||||
or (alt_path and string.find(g.current_file.directory, alt_path, 1, true))
|
||||
) ~= nil
|
||||
else
|
||||
return g.current_file.path == full_path
|
||||
or (alt_path and g.current_file.path == alt_path)
|
||||
end
|
||||
end
|
||||
|
||||
---Escapes unwanted unicode control characters that may affect the rest of the display.
|
||||
---Currently this only isolates unicode directional overrides.
|
||||
---Based on: https://github.com/mpv-player/mpv/pull/17606
|
||||
---@param str string
|
||||
---@return string
|
||||
local function unicode_escape(str)
|
||||
return ISOLATE_DIRECTION_START..str..ISOLATE_DIRECTION_END
|
||||
end
|
||||
|
||||
---escape ass values and replace newlines
|
||||
---@param str string
|
||||
---@param style_reset string?
|
||||
---@return string
|
||||
local function ass_escape(str, style_reset)
|
||||
return fb_utils.ass_escape(str, style_reset and style.warning..'␊'..style_reset or true)
|
||||
end
|
||||
|
||||
local header_overrides = {['^'] = style.header}
|
||||
|
||||
---@return number start
|
||||
---@return number finish
|
||||
---@return boolean is_overflowing
|
||||
local function calculate_view_window()
|
||||
---@type number
|
||||
local start = 1
|
||||
---@type number
|
||||
local finish = start+o.num_entries-1
|
||||
|
||||
--handling cursor positioning
|
||||
local mid = math.ceil(o.num_entries/2)+1
|
||||
if state.selected+mid > finish then
|
||||
---@type number
|
||||
local offset = state.selected - finish + mid
|
||||
|
||||
--if we've overshot the end of the list then undo some of the offset
|
||||
if finish + offset > #state.list then
|
||||
offset = offset - ((finish+offset) - #state.list)
|
||||
end
|
||||
|
||||
start = start + offset
|
||||
finish = finish + offset
|
||||
end
|
||||
|
||||
--making sure that we don't overstep the boundaries
|
||||
if start < 1 then start = 1 end
|
||||
local overflow = finish < #state.list
|
||||
--this is necessary when the number of items in the dir is less than the max
|
||||
if not overflow then finish = #state.list end
|
||||
|
||||
return start, finish, overflow
|
||||
end
|
||||
|
||||
---@param i number index
|
||||
---@return string
|
||||
local function calculate_item_style(i)
|
||||
local is_playing_file = highlight_entry(state.list[i])
|
||||
|
||||
--sets the selection colour scheme
|
||||
local multiselected = state.selection[i]
|
||||
|
||||
--sets the colour for the item
|
||||
local item_style = style.body
|
||||
|
||||
if multiselected then item_style = item_style..style.multiselect
|
||||
elseif i == state.selected then item_style = item_style..style.selected end
|
||||
|
||||
if is_playing_file then item_style = item_style..(multiselected and style.playing_selected or style.playing) end
|
||||
|
||||
return item_style
|
||||
end
|
||||
|
||||
local function draw_header()
|
||||
append(style.header)
|
||||
append(fb_utils.substitute_codes(o.format_string_header, header_overrides, nil, nil, function(str, code)
|
||||
if code == '^' then return str end
|
||||
return ass_escape(str, style.header)
|
||||
end))
|
||||
newline()
|
||||
end
|
||||
|
||||
---@param wrapper_overrides ReplacerTable
|
||||
local function draw_top_wrapper(wrapper_overrides)
|
||||
--adding a header to show there are items above in the list
|
||||
append(style.footer_header)
|
||||
append(fb_utils.substitute_codes(o.format_string_topwrapper, wrapper_overrides, nil, nil, function(str)
|
||||
return ass_escape(str)
|
||||
end))
|
||||
newline()
|
||||
end
|
||||
|
||||
---@param wrapper_overrides ReplacerTable
|
||||
local function draw_bottom_wrapper(wrapper_overrides)
|
||||
append(style.footer_header)
|
||||
append(fb_utils.substitute_codes(o.format_string_bottomwrapper, wrapper_overrides, nil, nil, function(str)
|
||||
return ass_escape(str)
|
||||
end))
|
||||
end
|
||||
|
||||
---@param i number index
|
||||
---@param cursor string
|
||||
local function draw_cursor(i, cursor)
|
||||
--handles custom styles for different entries
|
||||
if i == state.selected or i == state.multiselect_start then
|
||||
if not (i == state.selected) then append(style.selection_marker) end
|
||||
|
||||
if not state.multiselect_start then append(style.cursor)
|
||||
else
|
||||
if state.selection[state.multiselect_start] then append(style.cursor_select)
|
||||
else append(style.cursor_deselect) end
|
||||
end
|
||||
else
|
||||
append(g.style.indent)
|
||||
end
|
||||
append(cursor, '\\h', style.body)
|
||||
end
|
||||
|
||||
--refreshes the ass text using the contents of the list
|
||||
local function update_ass()
|
||||
if state.hidden then state.flag_update = true ; return end
|
||||
|
||||
append(style.global)
|
||||
draw_header()
|
||||
|
||||
if #state.list < 1 then
|
||||
append(state.empty_text)
|
||||
flush_buffer()
|
||||
draw()
|
||||
return
|
||||
end
|
||||
|
||||
local start, finish, overflow = calculate_view_window()
|
||||
|
||||
-- these are the number values to place into the wrappers
|
||||
local wrapper_overrides = {['<'] = tostring(start-1), ['>'] = tostring(#state.list-finish)}
|
||||
if o.format_string_topwrapper ~= '' and start > 1 then
|
||||
draw_top_wrapper(wrapper_overrides)
|
||||
end
|
||||
|
||||
for i=start, finish do
|
||||
local v = state.list[i]
|
||||
append(style.body)
|
||||
if g.ALIGN_X ~= 'right' then draw_cursor(i, o.cursor_icon) end
|
||||
|
||||
local item_style = calculate_item_style(i)
|
||||
append(item_style)
|
||||
|
||||
--sets the folder icon
|
||||
if v.type == 'dir' then
|
||||
append(style.folder, o.folder_icon, "\\h", style.body)
|
||||
append(item_style)
|
||||
end
|
||||
|
||||
--adds the actual name of the item
|
||||
append(v.ass or ass_escape( unicode_escape(v.label or v.name) , item_style), '\\h')
|
||||
if g.ALIGN_X == 'right' then draw_cursor(i, o.cursor_icon_flipped) end
|
||||
newline()
|
||||
end
|
||||
|
||||
if o.format_string_bottomwrapper ~= '' and overflow then
|
||||
draw_bottom_wrapper(wrapper_overrides)
|
||||
end
|
||||
|
||||
flush_buffer()
|
||||
draw()
|
||||
end
|
||||
|
||||
---@class ass
|
||||
return {
|
||||
update_ass = update_ass,
|
||||
highlight_entry = highlight_entry,
|
||||
draw = draw,
|
||||
remove = remove,
|
||||
}
|
||||
Reference in New Issue
Block a user