From ac92bfd911aef1a5851fd4bd952cddd6468176ca Mon Sep 17 00:00:00 2001 From: kyazdani42 Date: Wed, 19 Feb 2020 13:52:33 +0100 Subject: [PATCH] Faster git parsing - fix a bug when removing nodes from huge dir - only one `system` call for git status - add relative paths to nodes - parse git status from relative paths --- README.md | 13 +++++++------ lua/lib/format.lua | 1 + lua/lib/git.lua | 27 ++++++++++++++++++++------- lua/lib/state.lua | 18 ++++++++++-------- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index bc2b36ca..324d40e7 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,16 @@ - [x] Git integration ## TODO -- [ ] refresh tree (for git) on file save +- [ ] refresh tree (for git) on file save and update git status when needed - [ ] find a good way to display git info - [ ] better parsing of the git porcelain results +- [ ] handle permissions properly (TODO: display error on Read access denied) +- [ ] buffer / window should not disappear when only the tree is opened +- [ ] buffer / window should always stay on the left and never change size (open a file with only the tree open to reproduce this bug) + +- [ ] handle symbolic links - [ ] quickly find file in the directory structure - [ ] update tree automatically on window change -- [ ] handle permissions properly (TODO: display error on Read access denied) -- [ ] buffer / window should always stay on the left and never change size (open a file with only the tree open to reproduce this bug) -- [ ] buffer / window should not disappear when only the tree is opened - -- [ ] handle symbolic links +- [ ] mouse integration diff --git a/lua/lib/format.lua b/lua/lib/format.lua index 9d283a2c..3b9a219b 100644 --- a/lua/lib/format.lua +++ b/lua/lib/format.lua @@ -84,6 +84,7 @@ end local HIGHLIGHT_GROUPS = { ['^.*%.md$'] = 'MarkdownFile'; ['^LICENSE$'] = 'LicenseFile'; + ['^%.?vimrc$'] = 'VimFile'; ['^.*%.vim$'] = 'VimFile'; ['^.*%.c$'] = 'CFile'; ['^.*%.cpp$'] = 'CFile'; diff --git a/lua/lib/git.lua b/lua/lib/git.lua index 8ff166ef..b7e031c3 100644 --- a/lua/lib/git.lua +++ b/lua/lib/git.lua @@ -5,16 +5,28 @@ local function is_git_repo() return string.match(is_git, 'fatal') == nil end -local GIT_CMD = 'git status --porcelain=v1 ' +local IS_GIT_REPO = is_git_repo() -local function is_folder_dirty(path) - local ret = system(GIT_CMD..path) - return ret ~= nil and ret ~= '' +local function set_git_status() + if IS_GIT_REPO == false then return '' end + return system('git status --porcelain=v1') +end + +local GIT_STATUS = set_git_status() + +local function refresh_git() + IS_GIT_REPO = is_git_repo() + GIT_STATUS = set_git_status() +end + +local function is_folder_dirty(relpath) + return string.match(GIT_STATUS, relpath) ~= nil end local function create_git_checker(pattern) - return function(path) - local ret = system(GIT_CMD..path) + return function(relpath) + local ret = string.match(GIT_STATUS, '^.*' .. relpath) + if ret == nil then return false end return string.match(ret, pattern) ~= nil end end @@ -25,7 +37,7 @@ local is_unmerged = create_git_checker('^ ?UU') local is_untracked = create_git_checker('^%?%?') local function get_git_attr(path, is_dir) - if is_git_repo() == false then return '' end + if IS_GIT_REPO == false then return '' end if is_dir then if is_folder_dirty(path) == true then return 'Dirty' end else @@ -41,4 +53,5 @@ end return { get_git_attr = get_git_attr; + refresh_git = refresh_git; } diff --git a/lua/lib/state.lua b/lua/lib/state.lua index 19ca8507..b951c3dd 100644 --- a/lua/lib/state.lua +++ b/lua/lib/state.lua @@ -39,22 +39,24 @@ local function sort_dirs(dirs) return sorted_tree end -local function create_nodes(path, depth, dirs) +local function create_nodes(path, relpath, depth, dirs) local tree = {} if not string.find(path, '^.*/$') then path = path .. '/' end + if not string.find(relpath, '^.*/$') and depth > 0 then relpath = relpath .. '/' end for i, name in pairs(dirs) do - local full_path = path..name - local dir = is_dir(full_path) + local dir = is_dir(path..name) + local rel_path = relpath ..name tree[i] = { path = path, + relpath = rel_path, name = name, depth = depth, dir = dir, open = false, icon = true, - git = get_git_attr(full_path, dir) + git = get_git_attr(rel_path, dir) } end @@ -63,7 +65,7 @@ end local function init_tree() local ROOT_PATH = get_root_path() - Tree = create_nodes(ROOT_PATH, 0, list_dirs()) + Tree = create_nodes(ROOT_PATH, '', 0, list_dirs()) if ROOT_PATH ~= '/' then table.insert(Tree, 1, { path = ROOT_PATH, @@ -94,7 +96,7 @@ local function refresh_tree() if node.path .. node.name == path then node.open = true local dirs = list_dirs(path) - for j, n in pairs(create_nodes(path, node.depth + 1, dirs)) do + for j, n in pairs(create_nodes(path, node.relpath, node.depth + 1, dirs)) do table.insert(Tree, i + j, n) end end @@ -111,13 +113,13 @@ local function open_dir(tree_index) local next_index = tree_index + 1; local next_node = Tree[next_index] - while next_node ~= nil and next_node.depth ~= node.depth do + while next_node ~= nil and next_node.depth > node.depth do table.remove(Tree, next_index) next_node = Tree[next_index] end else local dirlist = list_dirs(node.path .. node.name) - local child_dirs = create_nodes(node.path .. node.name .. '/', node.depth + 1, dirlist) + local child_dirs = create_nodes(node.path .. node.name .. '/', node.relpath, node.depth + 1, dirlist) for i, n in pairs(child_dirs) do table.insert(Tree, tree_index + i, n)