Skip to content

Commit

Permalink
Feature: collapse directories (#65)
Browse files Browse the repository at this point in the history
When enabled/toggled, directories that only contain another directory will be displayed like `a/b/c/`, allowing you to navigate more quickly down the filesystem

---------

Co-authored-by: Simon McLean <simonmclean@192.168.1.116>
Co-authored-by: simonmclean <simonmclean@users.noreply.github.com>
Co-authored-by: Simon McLean <simonmclean@192.168.1.129>
  • Loading branch information
4 people committed Sep 21, 2024
1 parent 94f3089 commit cb87a21
Show file tree
Hide file tree
Showing 16 changed files with 306 additions and 164 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,13 @@ require 'triptych'.setup {
paste = 'p',
quit = 'q',
toggle_hidden = '<leader>.',
toggle_collapse_dirs = 'z',
},
extension_mappings = {},
options = {
dirs_first = true,
show_hidden = false,
collapse_dirs = true,
line_numbers = {
enabled = true,
relative = false,
Expand Down
2 changes: 2 additions & 0 deletions doc/triptych.nvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,13 @@ bindings.
paste = 'p',
quit = 'q',
toggle_hidden = '<leader>.',
toggle_collapse_dirs = 'z',
},
extension_mappings = {},
options = {
dirs_first = true,
show_hidden = false,
collapse_dirs = true,
line_numbers = {
enabled = true,
relative = false,
Expand Down
22 changes: 16 additions & 6 deletions lua/triptych/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,13 @@ function Actions.new(State, refresh_view)

---@return nil
M.toggle_hidden = function()
if State.show_hidden then
State.show_hidden = false
else
State.show_hidden = true
end
State.show_hidden = not State.show_hidden
refresh_view()
end

---@return nil
M.toggle_collapse_dirs = function()
State.collapse_dirs = not State.collapse_dirs
refresh_view()
end

Expand All @@ -396,7 +398,15 @@ function Actions.new(State, refresh_view)
local target = view.get_target_under_cursor(State)
if target then
if target.is_dir then
view.set_primary_and_parent_window_targets(State, target.path)
local target_path
if State.collapse_dirs and target.collapse_path then
target_path = target.collapse_path
else
target_path = target.path
end
if target_path then
view.set_primary_and_parent_window_targets(State, target_path)
end
else
edit_file(target.path, 'in-place')
end
Expand Down
89 changes: 89 additions & 0 deletions lua/triptych/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,93 @@ local function config_warn(config_prop_name)
end
end

---@class TriptychConfig
---@field debug boolean
---@field mappings TriptychConfigMappings
---@field extension_mappings { [string]: ExtensionMapping }
---@field options TriptychConfigOptions
---@field git_signs TriptychConfigGitSigns
---@field diagnostic_signs TriptychConfigDiagnostic

---@class TriptychConfigMappings
---@field show_help KeyMapping
---@field jump_to_cwd KeyMapping
---@field nav_left KeyMapping
---@field nav_right KeyMapping
---@field open_vsplit KeyMapping
---@field open_hsplit KeyMapping
---@field open_tab KeyMapping
---@field cd KeyMapping
---@field delete KeyMapping
---@field add KeyMapping
---@field copy KeyMapping
---@field rename KeyMapping
---@field cut KeyMapping
---@field paste KeyMapping
---@field quit KeyMapping
---@field toggle_hidden KeyMapping
---@field toggle_collapse_dirs KeyMapping

---@class ExtensionMapping
---@field mode string
---@field fn fun(contents?: PathDetails, refresh_fn: fun(): nil): nil

---@class TriptychConfigOptions
---@field dirs_first boolean
---@field collapse_dirs boolean
---@field show_hidden boolean
---@field line_numbers TriptychConfigLineNumbers
---@field file_icons TriptychConfigFileIcons
---@field responsive_column_widths { [string]: number[] }
---@field highlights TriptychConfigHighlights
---@field syntax_highlighting TriptychConfigSyntaxHighlighting
---@field backdrop number
---@field border string | table
---@field max_height number
---@field max_width number
---@field margin_x number
---@field margin_y number

---@class TriptychConfigHighlights
---@field file_names string
---@field directory_names string

---@class TriptychConfigSyntaxHighlighting
---@field enabled boolean
---@field debounce_ms number

---@class TriptychConfigLineNumbers
---@field enabled boolean
---@field relative boolean

---@class TriptychConfigFileIcons
---@field enabled boolean
---@field directory_icon string
---@field fallback_file_icon string

---@class TriptychConfigGitSigns
---@field enabled boolean
---@field signs TriptychConfigGitSignsSigns

---@class TriptychConfigGitSignsSigns
---@field add string | TriptychConfigGitSignDefineOptions
---@field modify string | TriptychConfigGitSignDefineOptions
---@field rename string | TriptychConfigGitSignDefineOptions
---@field untracked string | TriptychConfigGitSignDefineOptions

---@class TriptychConfigGitSignDefineOptions
---@field icon? string
---@field linehl? string
---@field numhl? string
---@field text? string
---@field texthl? string
---@field culhl? string

---@class TriptychConfigDiagnostic
---@field enabled boolean

---@alias KeyMapping (string | string[])

---@return TriptychConfig
local function default_config()
return {
Expand All @@ -28,10 +115,12 @@ local function default_config()
paste = 'p',
quit = 'q',
toggle_hidden = '<leader>.',
toggle_collapse_dirs = 'z',
},
extension_mappings = {},
options = {
dirs_first = true,
collapse_dirs = true,
show_hidden = false,
line_numbers = {
enabled = true,
Expand Down
9 changes: 8 additions & 1 deletion lua/triptych/event_handlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local log = require 'triptych.logger'
local float = require 'triptych.float'
local autocmds = require 'triptych.autocmds'
local view = require 'triptych.view'
local fs = require 'triptych.fs'

local M = {}

Expand All @@ -16,7 +17,13 @@ function M.handle_cursor_moved(State)
local line_number = vim.api.nvim_win_get_cursor(0)[1]
State.path_to_line_map[current_dir] = line_number
if target then
view.set_child_window_target(State, target)
local final_target
if State.collapse_dirs and target.is_dir and target.collapse_path then
final_target = fs.read_path(target.collapse_path, true)
else
final_target = target
end
view.set_child_window_target(State, final_target)
end
end

Expand Down
59 changes: 44 additions & 15 deletions lua/triptych/fs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,37 @@ M.read_file_async = plenary_async.wrap(function(file_path, callback)
end)
end, 2)

---Keep recursively reading into sub-directories, so long as each sub-directory contains only a single directory and no files
---@param path string
---@param display_name string
---@return string - full path
---@return string - display name
local function read_collapsed_dirs(path, display_name)
local handle, _ = vim.loop.fs_scandir(path)
if not handle then
return path, display_name
end

local first_node_name, first_node_type = vim.loop.fs_scandir_next(handle)

-- Empty dir, or node is not a directory
if not first_node_name or first_node_type ~= 'directory' then
return path, display_name
end

local second_node_name, _ = vim.loop.fs_scandir_next(handle)

-- Directory contains more than 1 node
if second_node_name then
return path, display_name
end

return read_collapsed_dirs(path .. '/' .. first_node_name, display_name .. first_node_name .. '/')
end

---@param _path string
---@param show_hidden boolean
---@param callback fun(path_details: PathDetails): nil
function M.get_path_details(_path, show_hidden, callback)
---@param include_collapsed boolean whether to drill recursively into collapsed dirs
function M.read_path(_path, include_collapsed)
local path = vim.fs.normalize(_path)

local tree = {
Expand All @@ -56,8 +83,7 @@ function M.get_path_details(_path, show_hidden, callback)
local handle, _ = vim.loop.fs_scandir(path)
if not handle then
-- On error fallback to cwd
M.get_path_details(vim.fn.getcwd(), show_hidden, callback)
return
return M.read_path(vim.fn.getcwd())
end

while true do
Expand All @@ -66,24 +92,27 @@ function M.get_path_details(_path, show_hidden, callback)
break
end
local entry_path = path .. '/' .. name
table.insert(tree.children, {
display_name = u.eval(function()
if type == 'directory' then
return name .. '/'
end
return name
end),
local is_dir = type == 'directory'
local display_name = is_dir and (name .. '/') or name
local entry = {
display_name = display_name,
path = entry_path,
dirname = path,
is_dir = type == 'directory',
is_dir = is_dir,
filetype = u.eval(function()
if type == 'directory' then
return
end
return M.get_filetype_from_path(entry_path)
end),
children = {},
})
}
if is_dir and include_collapsed then
local collapsed_path, collapsed_display_name = read_collapsed_dirs(entry_path, display_name)
entry.collapse_path = collapsed_path
entry.collapse_display_name = collapsed_display_name
end
table.insert(tree.children, entry)
end

if vim.g.triptych_config.options.dirs_first then
Expand All @@ -98,7 +127,7 @@ function M.get_path_details(_path, show_hidden, callback)
end)
end

callback(tree)
return tree
end

return M
1 change: 1 addition & 0 deletions lua/triptych/mappings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function Mappings.new(State, actions, refresh_fn)
map('n', mappings.paste, actions.paste)
map('n', mappings.show_help, actions.help)
map('n', mappings.toggle_hidden, actions.toggle_hidden)
map('n', mappings.toggle_collapse_dirs, actions.toggle_collapse_dirs)
map('n', mappings.quit, function()
vim.g.triptych_close() -- TODO: Move to actions
end)
Expand Down
16 changes: 16 additions & 0 deletions lua/triptych/state.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
local u = require 'triptych.utils'

---@class TriptychState
---@field new fun(config: TriptychConfig, opening_win: integer): TriptychState
---@field list_add fun(self: TriptychState, list_type: 'cut' | 'copy', item: PathDetails): nil
---@field list_remove fun(self: TriptychState, list_type: 'cut' | 'copy', item: PathDetails): nil
---@field list_remove_all fun(self: TriptychState, list_type: 'cut' | 'copy'): nil
---@field list_toggle fun(self: TriptychState, list_type: 'cut' | 'copy', item: PathDetails): nil
---@field list_contains fun(self: TriptychState, list_type: 'cut' | 'copy', item: PathDetails): nil
---@field windows ViewState
---@field cut_list PathDetails[]
---@field copy_list PathDetails[]
---@field path_to_line_map { [string]: integer }
---@field opening_win integer
---@field show_hidden boolean
---@field collapse_dirs boolean
---@field has_initial_cursor_pos_been_set boolean
local TriptychState = {}

---@return TriptychState
Expand All @@ -8,6 +23,7 @@ function TriptychState.new(config, opening_win)
setmetatable(instance, { __index = TriptychState })

instance.show_hidden = config.options.show_hidden
instance.collapse_dirs = config.options.collapse_dirs
instance.windows = {
parent = {
path = '',
Expand Down
Loading

0 comments on commit cb87a21

Please sign in to comment.