Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Case Sensitive Move Operation #1375

Merged
merged 12 commits into from
Oct 22, 2023
38 changes: 36 additions & 2 deletions autoload/nerdtree.vim
Original file line number Diff line number Diff line change
Expand Up @@ -198,16 +198,42 @@ function! nerdtree#postSourceActions() abort
runtime! nerdtree_plugin/**/*.vim
endfunction

"FUNCTION: nerdtree#runningWindows(dir) {{{2
"FUNCTION: nerdtree#runningWindows() {{{2
function! nerdtree#runningWindows() abort
return has('win16') || has('win32') || has('win64')
endfunction

"FUNCTION: nerdtree#runningCygwin(dir) {{{2
"FUNCTION: nerdtree#runningCygwin() {{{2
function! nerdtree#runningCygwin() abort
return has('win32unix')
endfunction

"FUNCTION: nerdtree#runningMac() {{{2
function! nerdtree#runningMac() abort
return has('gui_mac') || has('gui_macvim') || has('mac') || has('osx')
endfunction

" FUNCTION: nerdtree#osDefaultCaseSensitiveFS() {{{2
function! nerdtree#osDefaultCaseSensitiveFS() abort
return s:osDefaultCaseSensitiveFS
endfunction

" FUNCTION: nerdtree#caseSensitiveFS() {{{2
function! nerdtree#caseSensitiveFS() abort
return g:NERDTreeCaseSensitiveFS == 1 ||
\((g:NERDTreeCaseSensitiveFS == 2 || g:NERDTreeCaseSensitiveFS == 3) &&
\nerdtree#osDefaultCaseSensitiveFS())
endfunction

"FUNCTION: nerdtree#pathEquals(lhs, rhs) {{{2
function! nerdtree#pathEquals(lhs, rhs) abort
if nerdtree#caseSensitiveFS()
return a:lhs ==# a:rhs
else
return a:lhs ==? a:rhs
endif
endfunction

" SECTION: View Functions {{{1
"============================================================

Expand Down Expand Up @@ -246,4 +272,12 @@ function! nerdtree#renderView() abort
call b:NERDTree.render()
endfunction

if nerdtree#runningWindows()
let s:osDefaultCaseSensitiveFS = 0
elseif nerdtree#runningMac()
let s:osDefaultCaseSensitiveFS = 0
else
let s:osDefaultCaseSensitiveFS = 1
endif

" vim: set sw=4 sts=4 et fdm=marker:
23 changes: 23 additions & 0 deletions doc/NERDTree.txt
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,9 @@ the NERDTree. These settings should be set in your vimrc, using `:let`.

|NERDTreeAutoCenterThreshold| Controls the sensitivity of autocentering.

|NERDTreeCaseSensitiveFS| Tells the NERDTree whether or not it is
running in on a case sensitive file system.

|NERDTreeCaseSensitiveSort| Tells the NERDTree whether to be case
sensitive or not when sorting nodes.

Expand Down Expand Up @@ -808,6 +811,26 @@ Default: 3
This setting controls the "sensitivity" of the NERDTree auto centering. See
|NERDTreeAutoCenter| for details.

------------------------------------------------------------------------------
*NERDTreeCaseSensitiveFS*
Values: 0, 1, 2 or 3.
Default: 2.

If set to 0, the NERDTree will interact with the file system without case
sensitivity.

If set to 1, the NERDTree will interact with the file system in a case-sensitive
manner.

If set to 2, the NERDTree assumes its case sensitivity from the OS it is
running on. It Will default to case-insensitive on Windows and macOS
machines and case-sensitive on everything else. Since it's not a foolproof
way of detection, NERDTree won't proceed with any write actions when
the destination is ambiguous.

Setting it to 3 will perform just like 2, but without suppressing write
actions.

------------------------------------------------------------------------------
*NERDTreeCaseSensitiveSort*
Values: 0 or 1.
Expand Down
6 changes: 1 addition & 5 deletions lib/nerdtree/path.vim
Original file line number Diff line number Diff line change
Expand Up @@ -554,11 +554,7 @@ endfunction
" Args:
" path: the other path obj to compare this with
function! s:Path.equals(path)
if nerdtree#runningWindows()
return self.str() ==? a:path.str()
else
return self.str() ==# a:path.str()
endif
return nerdtree#pathEquals(self.str(), a:path.str())
endfunction

" FUNCTION: Path.New(pathStr) {{{1
Expand Down
55 changes: 46 additions & 9 deletions nerdtree_plugin/fs_menu.vim
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callbac
call NERDTreeAddMenuItem({'text': '(m)ove the current node', 'shortcut': 'm', 'callback': 'NERDTreeMoveNode'})
call NERDTreeAddMenuItem({'text': '(d)elete the current node', 'shortcut': 'd', 'callback': 'NERDTreeDeleteNode'})

if has('gui_mac') || has('gui_macvim') || has('mac')
if nerdtree#runningMac()
call NERDTreeAddMenuItem({'text': '(r)eveal in Finder the current node', 'shortcut': 'r', 'callback': 'NERDTreeRevealInFinder'})
call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFile'})
call NERDTreeAddMenuItem({'text': '(q)uicklook the current node', 'shortcut': 'q', 'callback': 'NERDTreeQuickLook'})
Expand Down Expand Up @@ -149,18 +149,38 @@ function! s:renameBuffer(bufNum, newNodeName, isDirectory)
let quotedFileName = fnameescape(a:newNodeName)
let editStr = g:NERDTreePath.New(a:newNodeName).str({'format': 'Edit'})
endif
" 1. ensure that a new buffer is loaded
call nerdtree#exec('badd ' . quotedFileName, 0)
" 2. ensure that all windows which display the just deleted filename
" display a buffer for a new filename.
let s:originalTabNumber = tabpagenr()
let s:originalWindowNumber = winnr()
call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . a:bufNum . " | exec ':e! " . editStr . "' | endif", 0)
let l:tempBufferName = 'NERDTreeRenameTempBuffer'

" 1. swap deleted file buffer with a temporary one
" this step is needed to compensate for case insensitive filesystems

" 1.1. create an intermediate(temporary) buffer
call nerdtree#exec('badd ' . l:tempBufferName, 0)
let l:tempBufNum = bufnr(l:tempBufferName)
" 1.2. ensure that all windows which display the just deleted filename
" display the new temp buffer.
call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . a:bufNum . " | exec ':e! " . l:tempBufferName . "' | endif", 0)
" 1.3. We don't need the deleted file buffer anymore
try
call nerdtree#exec('confirm bwipeout ' . a:bufNum, 0)
catch
" This happens when answering Cancel if confirmation is needed. Do nothing.
endtry

" 2. swap temporary buffer with the new filename buffer
" 2.1. create the actual new file buffer
call nerdtree#exec('badd ' . quotedFileName, 0)

" 2.2. ensure that all windows which display the temporary buffer
" display a buffer for the new filename.
call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . l:tempBufNum . " | exec ':e! " . editStr . "' | endif", 0)
call nerdtree#exec('tabnext ' . s:originalTabNumber, 1)
call nerdtree#exec(s:originalWindowNumber . 'wincmd w', 1)
" 3. We don't need a previous buffer anymore
" 2.3. We don't need the temporary buffer anymore
try
call nerdtree#exec('confirm bwipeout ' . a:bufNum, 0)
call nerdtree#exec('confirm bwipeout ' . l:tempBufNum, 0)
catch
" This happens when answering Cancel if confirmation is needed. Do nothing.
endtry
Expand Down Expand Up @@ -206,7 +226,24 @@ function! NERDTreeMoveNode()
let prompt = s:inputPrompt('move')
let newNodePath = input(prompt, curNode.path.str(), 'file')
while filereadable(newNodePath)
call nerdtree#echoWarning('This destination already exists. Try again.')
" allow renames with different casing when g:NERDTreeCaseSensitiveFS
" is set to either 0 or 3 and the 2 paths are equal
if (g:NERDTreeCaseSensitiveFS == 0 || g:NERDTreeCaseSensitiveFS == 3) &&
\nerdtree#pathEquals(curNode.path.str(), newNodePath)
break
endif

call nerdtree#echoWarning('This destination already exists, Try again.')

" inform the user about the flag if we think it is a false positive
" when g:NERDTreeCaseSensitiveFS is set to 2
if g:NERDTreeCaseSensitiveFS == 2 &&
\!nerdtree#osDefaultCaseSensitiveFS() &&
\nerdtree#pathEquals(curNode.path.str(), newNodePath)
echon "\n(If it is a false positive please consider assigning NERDTreeCaseSensitiveFS's value)"
endif

" prompt the user again
let newNodePath = substitute(input(prompt, curNode.path.str(), 'file'), '\(^\s*\|\s*$\)', '', 'g')
endwhile

Expand Down
2 changes: 2 additions & 0 deletions plugin/NERD_tree.vim
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ set cpoptions&vim
"SECTION: Initialize variable calls and other random constants {{{2
let g:NERDTreeAutoCenter = get(g:, 'NERDTreeAutoCenter', 1)
let g:NERDTreeAutoCenterThreshold = get(g:, 'NERDTreeAutoCenterThreshold', 3)
let g:NERDTreeCaseSensitiveFS = get(g:, 'NERDTreeCaseSensitiveFS', 2)
let g:NERDTreeCaseSensitiveSort = get(g:, 'NERDTreeCaseSensitiveSort', 0)
let g:NERDTreeNaturalSort = get(g:, 'NERDTreeNaturalSort', 0)
let g:NERDTreeSortHiddenFirst = get(g:, 'NERDTreeSortHiddenFirst', 1)
Expand All @@ -53,6 +54,7 @@ let g:NERDTreeShowHidden = get(g:, 'NERDTreeShowHidden', 0
let g:NERDTreeShowLineNumbers = get(g:, 'NERDTreeShowLineNumbers', 0)
let g:NERDTreeSortDirs = get(g:, 'NERDTreeSortDirs', 1)


if !nerdtree#runningWindows() && !nerdtree#runningCygwin()
let g:NERDTreeDirArrowExpandable = get(g:, 'NERDTreeDirArrowExpandable', '▸')
let g:NERDTreeDirArrowCollapsible = get(g:, 'NERDTreeDirArrowCollapsible', '▾')
Expand Down