From 119ba1178ab3c5c36d69ec2e6cc07f29abf2ac83 Mon Sep 17 00:00:00 2001
From: "th.obaland@gmail.com"
Date: Fri, 28 Jul 2023 15:39:28 +0900
Subject: [PATCH] refactor: internal structure of view.
---
lua/vfiler/view.lua | 161 ++++++++++++++++++++++++--------------------
1 file changed, 89 insertions(+), 72 deletions(-)
diff --git a/lua/vfiler/view.lua b/lua/vfiler/view.lua
index 2b01185..d110357 100644
--- a/lua/vfiler/view.lua
+++ b/lua/vfiler/view.lua
@@ -13,6 +13,63 @@ function LnumIndex.new(level, prev_sibling, next_sibling)
}, LnumIndex)
end
+local ItemContainer = {}
+ItemContainer.__index = ItemContainer
+
+function ItemContainer.new(options)
+ return setmetatable({
+ list = {},
+ table = {},
+ lnum_indexes = {},
+ _show_hidden_files = options.show_hidden_files,
+ _gitstatus = options.gitstatus,
+ _sort_compare = options.sort_compare,
+ }, ItemContainer)
+end
+
+function ItemContainer:insert(item, lnum_index)
+ table.insert(self.list, item)
+ table.insert(self.lnum_indexes, lnum_index)
+ self.table[item.path] = {
+ index = #self.list,
+ item = item,
+ }
+end
+
+function ItemContainer:insert_recursively(item)
+ -- Override gitstatus of items
+ item.gitstatus = self._gitstatus[item.path]
+
+ local children = item.children
+ if not children then
+ return
+ end
+
+ table.sort(children, self._sort_compare)
+ local prev_sibling
+ for i, child in ipairs(children) do
+ local hidden = child.name:sub(1, 1) == '.'
+ if self._show_hidden_files or not hidden then
+ local index = LnumIndex.new(child.level, prev_sibling)
+ self:insert(child, index)
+ prev_sibling = #self.list
+
+ -- recursive
+ self:insert_recursively(child)
+ if i ~= #children then
+ index.next_sibling = prev_sibling + (#self.list - prev_sibling) + 1
+ end
+ end
+ end
+end
+
+function ItemContainer:length()
+ if not self.list then
+ return 0
+ end
+ return #self.list
+end
+
local function new_window(layout)
local window
if layout == 'floating' then
@@ -45,7 +102,7 @@ local function create_columns(columns)
end
return {
list = list,
- tbl = tbl,
+ table = tbl,
}
end
@@ -106,7 +163,6 @@ View.__index = View
function View.new(options)
local self = setmetatable({
_buffer = nil,
- _gitstatus = nil,
_window = nil,
_winconfig = {},
_winoptions = {
@@ -145,20 +201,16 @@ end
---@param context table
function View:draw(context)
-- flatten hierarchical items into a list
- self._items = {}
- self._lnum_indexes = {}
+ local options = context.options
+ self._items = ItemContainer.new({
+ show_hidden_files = options.show_hidden_files,
+ gitstatus = context.gitstatus,
+ sort_compare = sort.get(options.sort),
+ })
if self._header then
- table.insert(self._items, context.root)
- table.insert(self._lnum_indexes, LnumIndex.new(context.root.level))
+ self._items:insert(context.root, LnumIndex.new(context.root.level))
end
-
- local options = context.options
- self._gitstatus = context.gitstatus
- self:_flatten_items(
- context.root,
- sort.get(options.sort),
- options.show_hidden_files
- )
+ self._items:insert_recursively(context.root)
self:redraw()
end
@@ -169,32 +221,31 @@ function View:get_item(lnum)
return nil
end
lnum = lnum or vim.fn.line('.')
- return self._items[lnum]
+ return self._items.list[lnum]
end
--- Checked to see if it has the specified column.
---@param name string
function View:has_column(name)
- return self._columns.tbl[name] ~= nil
+ return self._columns.table[name] ~= nil
end
--- Find the index of the item in the view buffer for the specified path
---@param path string
function View:indexof(path)
- for i, item in ipairs(self._items) do
- if item.path == path then
- return i
- end
+ local item = self._items.table[path]
+ if not item then
+ return 0
end
- return 0
+ return item.index
end
--- Get the index of the first sibling item
function View:indexof_first_sibling(lnum)
- local level = self._lnum_indexes[lnum].level
+ local level = self._items.lnum_indexes[lnum].level
local top_lnum = self:top_lnum()
for i = lnum - 1, top_lnum, -1 do
- local index = self._lnum_indexes[i]
+ local index = self._items.lnum_indexes[i]
if index.level == level and not index.prev_sibling then
return i
end
@@ -204,20 +255,19 @@ end
--- Get the index of the last sibling item
function View:indexof_last_sibling(lnum)
- local level = self._lnum_indexes[lnum].level
- local lines = #self._items
- for i = lnum + 1, #self._lnum_indexes do
- local index = self._lnum_indexes[i]
+ local level = self._items.lnum_indexes[lnum].level
+ for i = lnum + 1, self._items:length() do
+ local index = self._items.lnum_indexes[i]
if index.level == level and not index.next_sibling then
return i
end
end
- return lines
+ return self._items:length()
end
--- Get the index of the next sibling item
function View:indexof_next_sibling(lnum)
- local next = self._lnum_indexes[lnum].next_sibling
+ local next = self._items.lnum_indexes[lnum].next_sibling
if next then
return next
end
@@ -226,7 +276,7 @@ end
--- Get the index of the previous sibiling item
function View:indexof_prev_sibling(lnum)
- local prev = self._lnum_indexes[lnum].prev_sibling
+ local prev = self._items.lnum_indexes[lnum].prev_sibling
if prev then
return prev
end
@@ -245,10 +295,7 @@ end
--- Get the number of line in the view buffer
function View:num_lines()
- if not self._items then
- return 0
- end
- return #self._items
+ return self._items:length()
end
--- Open the view buffer for the current window
@@ -318,10 +365,10 @@ function View:redraw()
-- create text lines
local lines = vim.list({})
if self._header then
- table.insert(lines, self:_to_header(self._items[1]))
+ table.insert(lines, self:_to_header(self._items.list[1]))
end
- for i = self:top_lnum(), #self._items do
- table.insert(lines, self:_to_line(self._items[i]))
+ for i = self:top_lnum(), self._items:length() do
+ table.insert(lines, self:_to_line(self._items.list[i]))
end
-- set buffer lines
@@ -394,7 +441,7 @@ end
--- Get the currently selected items
function View:selected_items()
local selected = {}
- for _, item in ipairs(self._items) do
+ for _, item in ipairs(self._items.list) do
if item.selected then
table.insert(selected, item)
end
@@ -424,7 +471,7 @@ function View:walk_items()
return nil
end
local function _walk_items()
- for _, item in ipairs(self._items) do
+ for _, item in ipairs(self._items.list) do
coroutine.yield(item)
end
end
@@ -453,7 +500,7 @@ function View:_apply_syntaxes()
local syn_commands = {}
local hi_commands = {}
- for _, column in pairs(self._columns.tbl) do
+ for _, column in pairs(self._columns.table) do
local syntaxes = column:syntaxes()
if syntaxes then
core.list.extend(syn_commands, syntaxes)
@@ -505,7 +552,7 @@ function View:_create_column_props(width)
-- calculate later
table.insert(variable_columns, { index = i, object = column })
else
- cwidth = column:get_width(self._items, rest_width, winid)
+ cwidth = column:get_width(self._items.list, rest_width, winid)
end
table.insert(props, { width = cwidth })
rest_width = rest_width - cwidth
@@ -516,7 +563,7 @@ function View:_create_column_props(width)
local width_by_columns = math.floor(rest_width / #variable_columns)
for _, column in ipairs(variable_columns) do
props[column.index].width =
- column.object:get_width(self._items, width_by_columns, winid)
+ column.object:get_width(self._items.list, width_by_columns, winid)
end
end
@@ -529,36 +576,6 @@ function View:_create_column_props(width)
return props
end
-function View:_flatten_items(item, sort_compare, show_hidden_files)
- -- Override gitstatus of items
- item.gitstatus = self._gitstatus[item.path]
-
- local children = item.children
- if not children then
- return
- end
-
- table.sort(children, sort_compare)
- local prev_sibling
- for i, child in ipairs(children) do
- local hidden = child.name:sub(1, 1) == '.'
- if show_hidden_files or not hidden then
- local index = LnumIndex.new(child.level, prev_sibling)
-
- table.insert(self._items, child)
- table.insert(self._lnum_indexes, index)
- prev_sibling = #self._items
-
- -- recursive flattening
- self:_flatten_items(child, sort_compare, show_hidden_files)
-
- if i ~= #children then
- index.next_sibling = prev_sibling + (#self._items - prev_sibling) + 1
- end
- end
- end
-end
-
function View:_resize()
local config = self._win_config
self._window:resize(config.width, config.height)