diff --git a/.config/yazi/init.lua b/.config/yazi/init.lua new file mode 100644 index 0000000..40ea142 --- /dev/null +++ b/.config/yazi/init.lua @@ -0,0 +1,103 @@ +Manager = { + area = ui.Rect.default, +} + +function Manager:layout(area) + self.area = area + + return ui.Layout() + :direction(ui.Layout.HORIZONTAL) + :constraints({ + ui.Constraint.Ratio(MANAGER.ratio.parent, MANAGER.ratio.all), + ui.Constraint.Ratio(MANAGER.ratio.current, MANAGER.ratio.all), + ui.Constraint.Ratio(MANAGER.ratio.preview, MANAGER.ratio.all), + }) + :split(area) +end + +function Manager:render(area) + local chunks = self:layout(area) + + local bar = function(c, x, y) + x, y = math.max(0, x), math.max(0, y) + return ui.Bar(ui.Rect { x = x, y = y, w = ya.clamp(0, area.w - x, 1), h = math.min(1, area.h) }, ui.Bar.TOP) + :symbol(c) + end + + return ya.flat { + -- Borders + ui.Border(area, ui.Border.ALL):type(ui.Border.ROUNDED), + ui.Bar(chunks[1], ui.Bar.RIGHT), + ui.Bar(chunks[3], ui.Bar.LEFT), + + bar("┬", chunks[1].right - 1, chunks[1].y), + bar("┴", chunks[1].right - 1, chunks[1].bottom - 1), + bar("┬", chunks[2].right, chunks[2].y), + bar("┴", chunks[2].right, chunks[1].bottom - 1), + + -- Parent + Parent:render(chunks[1]:padding(ui.Padding.xy(1))), + -- Current + Current:render(chunks[2]:padding(ui.Padding.y(1))), + -- Preview + Preview:render(chunks[3]:padding(ui.Padding.xy(1))), + } +end + +function Header:host() + if ya.target_family() ~= "unix" then + return ui.Line {} + end + return ui.Span(ya.user_name() .. "@" .. ya.host_name() .. ":"):fg("blue") +end + +function Header:render(area) + local chunks = self:layout(area) + + local left = ui.Line { self:host(), self:cwd() } + local right = ui.Line { self:tabs() } + return { + ui.Paragraph(chunks[1], { left }), + ui.Paragraph(chunks[2], { right }):align(ui.Paragraph.RIGHT), + } +end + +function Status:owner() + local h = cx.active.current.hovered + if h == nil or ya.target_family() ~= "unix" then + return ui.Line {} + end + + return ui.Line { + ui.Span(ya.user_name(h.cha.uid) or tostring(h.cha.uid)):fg("magenta"), + ui.Span(":"), + ui.Span(ya.group_name(h.cha.gid) or tostring(h.cha.gid)):fg("magenta"), + ui.Span(" "), + } +end + +function Status:mtime() + local h = cx.active.current.hovered + if h == nil or ya.target_family() ~= "unix" then + return ui.Line {} + end + + -- fix unix timestamp format + return ui.Line { + ui.Span(h.cha.modified):fg("magenta"), + ui.Span(" ") + } +end + +function Status:render(area) + self.area = area + + local left = ui.Line { self:mode(), self:size(), self:name() } + --local right = ui.Line { self:mtime(), self:owner(), self:percentage(), self:position() } + local right = ui.Line { self:owner(), self:percentage(), self:position() } + return { + ui.Paragraph(area, { left }), + ui.Paragraph(area, { right }):align(ui.Paragraph.RIGHT), + table.unpack(Progress:render(area, right:width())), + } +end \ No newline at end of file diff --git a/.config/yazi/keymap.toml b/.config/yazi/keymap.toml new file mode 100644 index 0000000..6e6de70 --- /dev/null +++ b/.config/yazi/keymap.toml @@ -0,0 +1,14 @@ +[[input.prepend_keymap]] +on = [ "" ] +exec = "close" +desc = "Cancel input" + +[[manager.prepend_keymap]] +on = [ "l" ] +exec = "plugin --sync smart-enter" +desc = "Enter the child directory, or open the file" + +[[manager.prepend_keymap]] +on = [ "" ] +exec = "plugin --sync smart-enter" +desc = "Enter the child directory, or open the file" \ No newline at end of file diff --git a/.config/yazi/plugins/7z.yazi/init.lua b/.config/yazi/plugins/7z.yazi/init.lua new file mode 100644 index 0000000..128bdc4 --- /dev/null +++ b/.config/yazi/plugins/7z.yazi/init.lua @@ -0,0 +1,63 @@ +local M = {} + +function M:peek() + local child = Command("7z") + :args({ + "l", + tostring(self.file.url), + }) + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() + + if not child then + return self:fallback_to_builtin() + end + + local limit = self.area.h + local i, lines = 0, "" + repeat + local next, event = child:read_line() + if event == 1 then + return self:fallback_to_builtin() + elseif event ~= 0 then + break + end + + i = i + 1 + if i > self.skip then + lines = lines .. next + end + until i >= self.skip + limit + + child:start_kill() + if self.skip > 0 and i < self.skip + limit then + ya.manager_emit( + "peek", + { tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" } + ) + else + lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size)) + ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) }) + end +end + +function M:seek(units) + local h = cx.active.current.hovered + if h and h.url == self.file.url then + local step = math.floor(units * self.area.h / 10) + ya.manager_emit("peek", { + tostring(math.max(0, cx.active.preview.skip + step)), + only_if = tostring(self.file.url), + }) + end +end + +function M:fallback_to_builtin() + local _, bound = ya.preview_code(self) + if bound then + ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" }) + end +end + +return M \ No newline at end of file diff --git a/.config/yazi/plugins/glow.yazi/init.lua b/.config/yazi/plugins/glow.yazi/init.lua new file mode 100644 index 0000000..d55e9de --- /dev/null +++ b/.config/yazi/plugins/glow.yazi/init.lua @@ -0,0 +1,66 @@ +local M = {} + +function M:peek() + local child = Command("glow") + :args({ + "--style", + "dark", + "--width", + tostring(self.area.w), + tostring(self.file.url), + }) + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() + + if not child then + return self:fallback_to_builtin() + end + + local limit = self.area.h + local i, lines = 0, "" + repeat + local next, event = child:read_line() + if event == 1 then + return self:fallback_to_builtin() + elseif event ~= 0 then + break + end + + i = i + 1 + if i > self.skip then + lines = lines .. next + end + until i >= self.skip + limit + + child:start_kill() + if self.skip > 0 and i < self.skip + limit then + ya.manager_emit( + "peek", + { tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" } + ) + else + lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size)) + ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) }) + end +end + +function M:seek(units) + local h = cx.active.current.hovered + if h and h.url == self.file.url then + local step = math.floor(units * self.area.h / 10) + ya.manager_emit("peek", { + tostring(math.max(0, cx.active.preview.skip + step)), + only_if = tostring(self.file.url), + }) + end +end + +function M:fallback_to_builtin() + local _, bound = ya.preview_code(self) + if bound then + ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" }) + end +end + +return M \ No newline at end of file diff --git a/.config/yazi/plugins/hexyl.yazi/init.lua b/.config/yazi/plugins/hexyl.yazi/init.lua new file mode 100644 index 0000000..939aca7 --- /dev/null +++ b/.config/yazi/plugins/hexyl.yazi/init.lua @@ -0,0 +1,57 @@ +local M = {} + +function M:peek() + local child = Command("hexyl") + :args({ + "--border", + "none", + "-n", + "4092", + "--terminal-width", + tostring(self.area.w), + tostring(self.file.url), + }) + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() + + local limit = self.area.h + local i, lines = 0, "" + repeat + local next, event = child:read_line() + if event == 1 then + ya.err(tostring(event)) + elseif event ~= 0 then + break + end + + i = i + 1 + if i > self.skip then + lines = lines .. next + end + until i >= self.skip + limit + + child:start_kill() + if self.skip > 0 and i < self.skip + limit then + ya.manager_emit( + "peek", + { tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" } + ) + else + lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size)) + ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) }) + end +end + +function M:seek(units) + local h = cx.active.current.hovered + if h and h.url == self.file.url then + local step = math.floor(units * self.area.h / 10) + ya.manager_emit("peek", { + tostring(math.max(0, cx.active.preview.skip + step)), + only_if = tostring(self.file.url), + }) + end +end + +return M diff --git a/.config/yazi/plugins/imdl.yazi/init.lua b/.config/yazi/plugins/imdl.yazi/init.lua new file mode 100644 index 0000000..c81a64c --- /dev/null +++ b/.config/yazi/plugins/imdl.yazi/init.lua @@ -0,0 +1,64 @@ +local M = {} + +function M:peek() + local child = Command("imdl") + :args({ + "torrent", + "show", + tostring(self.file.url), + }) + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() + + if not child then + return self:fallback_to_builtin() + end + + local limit = self.area.h + local i, lines = 0, "" + repeat + local next, event = child:read_line() + if event == 1 then + return self:fallback_to_builtin() + elseif event ~= 0 then + break + end + + i = i + 1 + if i > self.skip then + lines = lines .. next + end + until i >= self.skip + limit + + child:start_kill() + if self.skip > 0 and i < self.skip + limit then + ya.manager_emit( + "peek", + { tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" } + ) + else + lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size)) + ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) }) + end +end + +function M:seek(units) + local h = cx.active.current.hovered + if h and h.url == self.file.url then + local step = math.floor(units * self.area.h / 10) + ya.manager_emit("peek", { + tostring(math.max(0, cx.active.preview.skip + step)), + only_if = tostring(self.file.url), + }) + end +end + +function M:fallback_to_builtin() + local _, bound = ya.preview_code(self) + if bound then + ya.manager_emit("peek", { tostring(bound), only_if = tostring(self.file.url), upper_bound = "" }) + end +end + +return M \ No newline at end of file diff --git a/.config/yazi/plugins/smart-enter.yazi/init.lua b/.config/yazi/plugins/smart-enter.yazi/init.lua new file mode 100644 index 0000000..ee7b607 --- /dev/null +++ b/.config/yazi/plugins/smart-enter.yazi/init.lua @@ -0,0 +1,6 @@ +return { + entry = function() + local h = cx.active.current.hovered + ya.manager_emit(h and h.cha.is_dir and "enter" or "open", {}) + end, +} \ No newline at end of file diff --git a/.config/yazi/theme.toml b/.config/yazi/theme.toml new file mode 100644 index 0000000..90c2722 --- /dev/null +++ b/.config/yazi/theme.toml @@ -0,0 +1,307 @@ +[manager] +cwd = { fg = "cyan" } + +# Hovered +hovered = { fg = "black", bg = "lightblue" } +preview_hovered = { underline = true } + +# Find +find_keyword = { fg = "yellow", italic = true } +find_position = { fg = "magenta", bg = "reset", italic = true } + +# Marker +marker_selected = { fg = "lightgreen", bg = "lightgreen" } +marker_copied = { fg = "lightyellow", bg = "lightyellow" } +marker_cut = { fg = "lightred", bg = "lightred" } + +# Tab +tab_active = { fg = "black", bg = "lightblue" } +tab_inactive = { fg = "white", bg = "darkgray" } +tab_width = 1 + +# Border +border_symbol = "│" +border_style = { fg = "gray" } + +# Highlighting +syntect_theme = "" + +# : }}} + + +# : Status {{{ + +[status] +separator_open = "" +separator_close = "" +separator_style = { fg = "darkgray", bg = "darkgray" } + +# Mode +mode_normal = { fg = "black", bg = "lightblue", bold = true } +mode_select = { fg = "black", bg = "lightgreen", bold = true } +mode_unset = { fg = "black", bg = "lightmagenta", bold = true } + +# Progress +progress_label = { bold = true } +progress_normal = { fg = "blue", bg = "black" } +progress_error = { fg = "red", bg = "black" } + +# Permissions +permissions_t = { fg = "lightgreen" } +permissions_r = { fg = "lightyellow" } +permissions_w = { fg = "lightred" } +permissions_x = { fg = "lightcyan" } +permissions_s = { fg = "darkgray" } + +# : }}} + + +# : Select {{{ + +[select] +border = { fg = "blue" } +active = { fg = "magenta" } +inactive = {} + +# : }}} + + +# : Input {{{ + +[input] +border = { fg = "blue" } +title = {} +value = {} +selected = { reversed = true } + +# : }}} + + +# : Completion {{{ + +[completion] +border = { fg = "blue" } +active = { bg = "darkgray" } +inactive = {} + +# Icons +icon_file = "" +icon_folder = "" +icon_command = "" + +# : }}} + + +# : Tasks {{{ + +[tasks] +border = { fg = "blue" } +title = {} +hovered = { underline = true } + +# : }}} + + +# : Which {{{ + +[which] +cols = 3 +mask = { bg = "black" } +cand = { fg = "lightcyan" } +rest = { fg = "darkgray" } +desc = { fg = "magenta" } +separator = "  " +separator_style = { fg = "darkgray" } + +# : }}} + + +# : Help {{{ + +[help] +on = { fg = "magenta" } +exec = { fg = "cyan" } +desc = { fg = "gray" } +hovered = { bg = "darkgray", bold = true } +footer = { fg = "black", bg = "white" } + +# : }}} + + +# : File-specific styles {{{ + +[filetype] + +rules = [ + # Images + { mime = "image/*", fg = "cyan" }, + + # Videos + { mime = "video/*", fg = "yellow" }, + { mime = "audio/*", fg = "yellow" }, + + # Archives + { mime = "application/zip", fg = "magenta" }, + { mime = "application/gzip", fg = "magenta" }, + { mime = "application/x-tar", fg = "magenta" }, + { mime = "application/x-bzip", fg = "magenta" }, + { mime = "application/x-bzip2", fg = "magenta" }, + { mime = "application/x-7z-compressed", fg = "magenta" }, + { mime = "application/x-rar", fg = "magenta" }, + { mime = "application/xz", fg = "magenta" }, + + # Documents + { mime = "application/doc", fg = "green" }, + { mime = "application/pdf", fg = "green" }, + { mime = "application/rtf", fg = "green" }, + { mime = "application/vnd.*", fg = "green" }, + + # Fallback + # { name = "*", fg = "white" }, + { name = "*/", fg = "blue" } +] + +[icon] + +rules = [ + # Programming + { name = "*.c" , text = "" }, + { name = "*.cpp" , text = "" }, + { name = "*.css" , text = "" }, + { name = "*.fish" , text = "" }, + { name = "*.go" , text = "" }, + { name = "*.h" , text = "" }, + { name = "*.hpp" , text = "" }, + { name = "*.html" , text = "" }, + { name = "*.java" , text = "" }, + { name = "*.js" , text = "" }, + { name = "*.jsx" , text = "" }, + { name = "*.lua" , text = "" }, + { name = "*.nix" , text = "" }, + { name = "*.php" , text = "" }, + { name = "*.py" , text = "" }, + { name = "*.rb" , text = "" }, + { name = "*.rs" , text = "" }, + { name = "*.scss" , text = "" }, + { name = "*.sh" , text = "" }, + { name = "*.swift", text = "" }, + { name = "*.ts" , text = "" }, + { name = "*.tsx" , text = "" }, + { name = "*.vim" , text = "" }, + { name = "*.vue" , text = "󰡄" }, + + # Text + { name = "*.conf", text = "" }, + { name = "*.ini" , text = "" }, + { name = "*.json", text = "" }, + { name = "*.md" , text = "" }, + { name = "*.toml", text = "" }, + { name = "*.txt", text = "" }, + { name = "*.yaml", text = "" }, + { name = "*.yml" , text = "" }, + + # Archives + { name = "*.7z" , text = "" }, + { name = "*.bz2", text = "" }, + { name = "*.gz" , text = "" }, + { name = "*.rar", text = "" }, + { name = "*.tar", text = "" }, + { name = "*.xz" , text = "" }, + { name = "*.zip", text = "" }, + + # Images + { name = "*.HEIC", text = "" }, + { name = "*.avif", text = "" }, + { name = "*.bmp" , text = "" }, + { name = "*.gif" , text = "" }, + { name = "*.ico" , text = "" }, + { name = "*.jpeg", text = "" }, + { name = "*.jpg" , text = "" }, + { name = "*.png" , text = "" }, + { name = "*.svg" , text = "" }, + { name = "*.webp", text = "" }, + + # Movies + { name = "*.avi" , text = "" }, + { name = "*.mkv" , text = "" }, + { name = "*.mov" , text = "" }, + { name = "*.mp4" , text = "" }, + { name = "*.webm", text = "" }, + + # Audio + { name = "*.aac" , text = "" }, + { name = "*.flac", text = "" }, + { name = "*.m4a" , text = "" }, + { name = "*.mp3" , text = "" }, + { name = "*.ogg" , text = "" }, + { name = "*.wav" , text = "" }, + + # Documents + { name = "*.csv" , text = "" }, + { name = "*.doc" , text = "" }, + { name = "*.doct", text = "" }, + { name = "*.docx", text = "" }, + { name = "*.dot" , text = "" }, + { name = "*.ods" , text = "" }, + { name = "*.ots" , text = "" }, + { name = "*.pdf" , text = "" }, + { name = "*.pom" , text = "" }, + { name = "*.pot" , text = "" }, + { name = "*.potx", text = "" }, + { name = "*.ppm" , text = "" }, + { name = "*.ppmx", text = "" }, + { name = "*.pps" , text = "" }, + { name = "*.ppsx", text = "" }, + { name = "*.ppt" , text = "" }, + { name = "*.pptx", text = "" }, + { name = "*.xlc" , text = "" }, + { name = "*.xlm" , text = "" }, + { name = "*.xls" , text = "" }, + { name = "*.xlsm", text = "" }, + { name = "*.xlsx", text = "" }, + { name = "*.xlt" , text = "" }, + + # Lockfiles + { name = "*.lock", text = "" }, + + # Misc + { name = "*.bin", text = "" }, + { name = "*.exe", text = "" }, + { name = "*.pkg", text = "" }, + + # Dotfiles + { name = ".DS_Store" , text = "" }, + { name = ".bashprofile" , text = "" }, + { name = ".bashrc" , text = "" }, + { name = ".gitattributes", text = "" }, + { name = ".gitignore" , text = "" }, + { name = ".gitmodules" , text = "" }, + { name = ".vimrc" , text = "" }, + { name = ".zprofile" , text = "" }, + { name = ".zshenv" , text = "" }, + { name = ".zshrc" , text = "" }, + + # Named files + { name = "COPYING" , text = "󰿃" }, + { name = "Containerfile", text = "󰡨" }, + { name = "Dockerfile" , text = "󰡨" }, + { name = "LICENSE" , text = "󰿃" }, + + # Directories + { name = ".config/" , text = "" }, + { name = ".git/" , text = "" }, + { name = "Desktop/" , text = "" }, + { name = "Development/", text = "" }, + { name = "Documents/" , text = "" }, + { name = "Downloads/" , text = "" }, + { name = "Library/" , text = "" }, + { name = "Movies/" , text = "" }, + { name = "Music/" , text = "" }, + { name = "Pictures/" , text = "" }, + { name = "Public/" , text = "" }, + { name = "Videos/" , text = "" }, + + # Default + { name = "*" , text = "" }, + { name = "*/", text = "" }, +] diff --git a/.config/yazi/yazi.toml b/.config/yazi/yazi.toml new file mode 100644 index 0000000..0b23632 --- /dev/null +++ b/.config/yazi/yazi.toml @@ -0,0 +1,120 @@ +[manager] +ratio = [1, 4, 3] +sort_by = "natural" +sort_sensitive=false + +#sort_dir_first=true +sort_dir_first=false + +#linemode="mtime" +linemode="size" + +show_hidden=false +show_symlink=true + +[opener] +edit = [ + { exec = '$EDITOR "$@"', block = true, desc="Edit", for = "unix" }, +] +open = [ + { exec = 'xdg-open "$@"', desc = "Open", for = "linux" }, + { exec = 'open "$@"', desc = "Open", for = "macos" }, + { exec = 'start "" "%1"', orphan = true, desc = "Open", for = "windows" } +] +extract = [ + { exec = '7z x "$1"', desc = "Extract here", for = "unix" }, +] +play = [ + { exec = 'mpv "$@"', orphan = true, desc = "Play", for = "unix" }, + { exec = 'mpv "%1"', orphan = true, desc = "Play", for = "windows" }, +] +info = [ + { exec = '''ffprobe -hide_banner "$1"; echo "Press enter to exit"; read''', block = true, desc = "Show ffprobe info", for = "unix" }, + { exec = '''ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$1"; echo "Press enter to exit"; read''', block = true, desc = "Show duration", for = "unix"} +] + +[open] +rules = [ + { name = "*/", use = [ "edit", "open" ] }, + + { mime = "text/*", use = [ "edit" ] }, + { mime = "image/*", use = [ "open" ] }, + { mime = "video/*", use = [ "play", "info" ] }, + { mime = "audio/*", use = [ "play", "info" ] }, + { mime = "inode/x-empty", use = [ "edit" ] }, + + { mime = "application/json", use = [ "edit" ] }, + { mime = "*/javascript", use = [ "edit" ] }, + + { mime = "application/zip", use = [ "extract" ] }, + { mime = "application/gzip", use = [ "extract" ] }, + { mime = "application/x-tar", use = [ "extract" ] }, + { mime = "application/x-bzip", use = [ "extract" ] }, + { mime = "application/x-bzip2", use = [ "extract" ] }, + { mime = "application/x-7z-compressed", use = [ "extract" ] }, + { mime = "application/x-rar", use = [ "extract" ] }, + { mime = "application/xz", use = [ "extract" ] }, + + { mime = "*", use = [ "open" ] }, +] + +[tasks] +micro_workers = 10 +macro_workers = 25 +bizarre_retry = 5 +image_alloc = 536870912 # 512MB +image_bound = [ 0, 0 ] +suppress_preload = false + +[plugin] +prepend_previewers = [ + { name = "*.md", exec = "glow" }, +] + +preloaders = [ + { name = "*", cond = "!mime", exec = "mime", multi = true, prio = "high" }, + # Image + { mime = "image/vnd.djvu", exec = "noop" }, + { mime = "image/*", exec = "image" }, + # Video + { mime = "video/*", exec = "video" }, + # PDF + { mime = "application/pdf", exec = "pdf" }, +] +previewers = [ + { name = "*/", exec = "folder", sync = true }, + # Code + { mime = "text/*", exec = "code" }, + { mime = "*/xml", exec = "code" }, + { mime = "*/javascript", exec = "code" }, + { mime = "*/x-wine-extension-ini", exec = "code" }, + # JSON + { mime = "application/json", exec = "json" }, + # Image + { mime = "image/vnd.djvu", exec = "noop" }, + { mime = "image/*", exec = "image" }, + # Video + { mime = "video/*", exec = "video" }, + # PDF + { mime = "application/pdf", exec = "pdf" }, + # Archive + { mime = "application/zip", exec = "7z" }, + { mime = "application/gzip", exec = "7z" }, + { mime = "application/x-tar", exec = "7z" }, + { mime = "application/x-bzip", exec = "7z" }, + { mime = "application/x-bzip2", exec = "7z" }, + { mime = "application/x-7z-compressed", exec = "7z" }, + { mime = "application/x-rar", exec = "7z" }, + { mime = "application/xz", exec = "7z" }, + { mime = "application/x-bittorrent;", exec = "imdl" }, + { name = "*.torrent", exec = "imdl" }, + + { mime = "application/octet-stream", exec = "hexyl" }, + # Fallback + { name = "*", exec = "file" }, +] + +[select] +open_title = "Open with:" +open_origin = "hovered" +open_offset = [ 0, 1, 50, 7 ]