From 1f2531ec3ac2c306e61a98e974b6db2c6099f2cc Mon Sep 17 00:00:00 2001 From: Vincent Tsang Date: Sat, 9 May 2015 22:38:16 +0800 Subject: [PATCH 1/4] Speed up sortChildren() by using sorting token This improves the sorting functions from 12 seconds to 0.66 seconds for ~4000 objects --- autoload/nerdtree.vim | 12 ++++++++++++ lib/nerdtree/tree_dir_node.vim | 19 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/autoload/nerdtree.vim b/autoload/nerdtree.vim index 22283aa..cf044fd 100644 --- a/autoload/nerdtree.vim +++ b/autoload/nerdtree.vim @@ -34,6 +34,18 @@ function! nerdtree#compareNodes(n1, n2) return a:n1.path.compareTo(a:n2.path) endfunction +"FUNCTION: nerdtree#compareNodesBySortingToken(n1, n2) {{{2 +function! nerdtree#compareNodesBySortingToken(n1, n2) + return a:n1.path.compareTo(a:n2.path) + if a:n1.sorting_token < a:n2.sorting_token + return -1 + elseif a:n1.sorting_token > a:n2.sorting_token + return 1 + else + return 0 + endif +endfunction + " FUNCTION: nerdtree#deprecated(func, [msg]) {{{2 " Issue a deprecation warning for a:func. If a second arg is given, use this " as the deprecation message diff --git a/lib/nerdtree/tree_dir_node.vim b/lib/nerdtree/tree_dir_node.vim index a24c270..9a7f45a 100644 --- a/lib/nerdtree/tree_dir_node.vim +++ b/lib/nerdtree/tree_dir_node.vim @@ -504,7 +504,24 @@ endfunction "directory priority. " function! s:TreeDirNode.sortChildren() - let CompareFunc = function("nerdtree#compareNodes") + let CompareFunc = function("nerdtree#compareNodesBySortingToken") + " To optimize sorting, let's generate the sorting token for comparison + + " calculate how large number is needed to represent " order index + let digit = ceil(log10(len(g:NERDTreeSortOrder))) + let format = "%0" . float2nr(digit) . "d" " e.g. '%04d' + + for child in self.children + let path = child.path.getLastPathComponent(1) + if !g:NERDTreeSortHiddenFirst + let path = substitute(path, '^[._]', '', '') + endif + if !g:NERDTreeCaseSensitiveSort + let path = tolower(path) + endif + let child.sorting_token = printf(format, child.path.getSortOrderIndex()) . path + endfor + call sort(self.children, CompareFunc) endfunction From 57d5bd773101a86c7983b5b0755cd3720ea8be0c Mon Sep 17 00:00:00 2001 From: Vincent Tsang Date: Sat, 9 May 2015 22:38:16 +0800 Subject: [PATCH 2/4] Speed up sortChildren() by using sorting token This improves the sorting functions from 12 seconds to 0.66 seconds for ~4000 objects --- autoload/nerdtree.vim | 11 +++++++++++ lib/nerdtree/tree_dir_node.vim | 19 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/autoload/nerdtree.vim b/autoload/nerdtree.vim index 22283aa..0a7e4c7 100644 --- a/autoload/nerdtree.vim +++ b/autoload/nerdtree.vim @@ -34,6 +34,17 @@ function! nerdtree#compareNodes(n1, n2) return a:n1.path.compareTo(a:n2.path) endfunction +"FUNCTION: nerdtree#compareNodesBySortingToken(n1, n2) {{{2 +function! nerdtree#compareNodesBySortingToken(n1, n2) + if a:n1.sorting_token < a:n2.sorting_token + return -1 + elseif a:n1.sorting_token > a:n2.sorting_token + return 1 + else + return 0 + endif +endfunction + " FUNCTION: nerdtree#deprecated(func, [msg]) {{{2 " Issue a deprecation warning for a:func. If a second arg is given, use this " as the deprecation message diff --git a/lib/nerdtree/tree_dir_node.vim b/lib/nerdtree/tree_dir_node.vim index a24c270..9a7f45a 100644 --- a/lib/nerdtree/tree_dir_node.vim +++ b/lib/nerdtree/tree_dir_node.vim @@ -504,7 +504,24 @@ endfunction "directory priority. " function! s:TreeDirNode.sortChildren() - let CompareFunc = function("nerdtree#compareNodes") + let CompareFunc = function("nerdtree#compareNodesBySortingToken") + " To optimize sorting, let's generate the sorting token for comparison + + " calculate how large number is needed to represent " order index + let digit = ceil(log10(len(g:NERDTreeSortOrder))) + let format = "%0" . float2nr(digit) . "d" " e.g. '%04d' + + for child in self.children + let path = child.path.getLastPathComponent(1) + if !g:NERDTreeSortHiddenFirst + let path = substitute(path, '^[._]', '', '') + endif + if !g:NERDTreeCaseSensitiveSort + let path = tolower(path) + endif + let child.sorting_token = printf(format, child.path.getSortOrderIndex()) . path + endfor + call sort(self.children, CompareFunc) endfunction From 80e184df5615b9f4181abec289437b7fc07b8b5d Mon Sep 17 00:00:00 2001 From: Vincent Tsang Date: Mon, 11 May 2015 11:56:08 +0800 Subject: [PATCH 3/4] Refactor code to use getSortKey() and replace regular expression with simple string comparison in tree_dir_node.vim --- autoload/nerdtree.vim | 8 ++++---- lib/nerdtree/path.vim | 21 ++++++++++++++++++++ lib/nerdtree/tree_dir_node.vim | 35 ++++++++++++++-------------------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/autoload/nerdtree.vim b/autoload/nerdtree.vim index 0a7e4c7..d16cd66 100644 --- a/autoload/nerdtree.vim +++ b/autoload/nerdtree.vim @@ -34,11 +34,11 @@ function! nerdtree#compareNodes(n1, n2) return a:n1.path.compareTo(a:n2.path) endfunction -"FUNCTION: nerdtree#compareNodesBySortingToken(n1, n2) {{{2 -function! nerdtree#compareNodesBySortingToken(n1, n2) - if a:n1.sorting_token < a:n2.sorting_token +"FUNCTION: nerdtree#compareNodesBySortKey(n1, n2) {{{2 +function! nerdtree#compareNodesBySortKey(n1, n2) + if a:n1.path.getSortKey() < a:n2.path.getSortKey() return -1 - elseif a:n1.sorting_token > a:n2.sorting_token + elseif a:n1.path.getSortKey() > a:n2.path.getSortKey() return 1 else return 0 diff --git a/lib/nerdtree/path.vim b/lib/nerdtree/path.vim index 48793eb..4553418 100644 --- a/lib/nerdtree/path.vim +++ b/lib/nerdtree/path.vim @@ -1,6 +1,9 @@ "we need to use this number many times for sorting... so we calculate it only "once here let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') +" used in formating sortKey, e.g. '%04d' +let s:format = "%0" . float2nr(ceil(log10(len(g:NERDTreeSortOrder)))) . "d" + "CLASS: Path "============================================================ @@ -361,6 +364,24 @@ function! s:Path.getSortOrderIndex() return s:NERDTreeSortStarIndex endfunction +"FUNCTION: Path.getSortKey() {{{1 +"returns a string used in compare function for sorting +function! s:Path.getSortKey() + if !exists("self.sortKey") + let path = self.getLastPathComponent(1) + if !g:NERDTreeSortHiddenFirst + let path = substitute(path, '^[._]', '', '') + endif + if !g:NERDTreeCaseSensitiveSort + let path = tolower(path) + endif + let self.sortKey = printf(s:format, self.getSortOrderIndex()) . path + endif + + return self.sortKey +endfunction + + "FUNCTION: Path.isUnixHiddenFile() {{{1 "check for unix hidden files function! s:Path.isUnixHiddenFile() diff --git a/lib/nerdtree/tree_dir_node.vim b/lib/nerdtree/tree_dir_node.vim index 9a7f45a..4d8fd40 100644 --- a/lib/nerdtree/tree_dir_node.vim +++ b/lib/nerdtree/tree_dir_node.vim @@ -246,8 +246,13 @@ function! s:TreeDirNode._initChildren(silent) "filter out the .. and . directories "Note: we must match .. AND ../ cos sometimes the globpath returns "../ for path with strange chars (eg $) - if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' - +" if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' +" + " 20150511 + " Regular expression is too expensive. Use simply string comparison + " instead + if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." && + \ i[len(i)-2:1] != "." && i[len(i)-1] != "." "put the next file in a new node and attach it try let path = g:NERDTreePath.New(i) @@ -405,8 +410,13 @@ function! s:TreeDirNode.refresh() "filter out the .. and . directories "Note: we must match .. AND ../ cos sometimes the globpath returns "../ for path with strange chars (eg $) - if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + "if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + " 20150511 + " Regular expression is too expensive. Use simply string comparison + " instead + if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." && + \ i[len(i)-2:1] != "." && i[len(i)-1] != "." try "create a new path and see if it exists in this nodes children let path = g:NERDTreePath.New(i) @@ -504,24 +514,7 @@ endfunction "directory priority. " function! s:TreeDirNode.sortChildren() - let CompareFunc = function("nerdtree#compareNodesBySortingToken") - " To optimize sorting, let's generate the sorting token for comparison - - " calculate how large number is needed to represent " order index - let digit = ceil(log10(len(g:NERDTreeSortOrder))) - let format = "%0" . float2nr(digit) . "d" " e.g. '%04d' - - for child in self.children - let path = child.path.getLastPathComponent(1) - if !g:NERDTreeSortHiddenFirst - let path = substitute(path, '^[._]', '', '') - endif - if !g:NERDTreeCaseSensitiveSort - let path = tolower(path) - endif - let child.sorting_token = printf(format, child.path.getSortOrderIndex()) . path - endfor - + let CompareFunc = function("nerdtree#compareNodesBySortKey") call sort(self.children, CompareFunc) endfunction From 10261d60a05c3a2237a2b5e47df9235d52430e57 Mon Sep 17 00:00:00 2001 From: Vincent Tsang Date: Mon, 11 May 2015 11:59:10 +0800 Subject: [PATCH 4/4] Updated the comment --- lib/nerdtree/tree_dir_node.vim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/nerdtree/tree_dir_node.vim b/lib/nerdtree/tree_dir_node.vim index 4d8fd40..765982d 100644 --- a/lib/nerdtree/tree_dir_node.vim +++ b/lib/nerdtree/tree_dir_node.vim @@ -248,7 +248,6 @@ function! s:TreeDirNode._initChildren(silent) "../ for path with strange chars (eg $) " if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' " - " 20150511 " Regular expression is too expensive. Use simply string comparison " instead if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." && @@ -412,7 +411,6 @@ function! s:TreeDirNode.refresh() "../ for path with strange chars (eg $) "if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' - " 20150511 " Regular expression is too expensive. Use simply string comparison " instead if i[len(i)-3:2] != ".." && i[len(i)-2:2] != ".." &&