Files
nerdtree/lib/nerdtree/menu_controller.vim
Chris Patuzzo 84737f2ebe Add a NERDTreeMinimalMenu feature (#938)
* Extract the menu action prompts to a function

* Add a NERDTreeMinimalMenu configuration option

If this option is set, Vim’s command line displays
a single-line version of the menu:

Which action? (a*/m/d/r/o/q/c/l):

Pressing ‘a’ will call the ‘add child node’ menu
item as that is its shortcut.

The * denotes the position of the currently
selected menu item which can be changed with
NERDTreeMenuDown and Up in the usual way.

The user may wish to set these to <left>, <right>
or h, l if they prefer.

* Minimise the text once a menu item is chosen

If NERDTreeMinimalMenu is set, then echo a single
line prompt after the menu item is chosen. This
reduces noise for users who are already familiar
with how the menu works and prevents Vim scrolling
down to accommodate the menu text.

If the directory is non-empty we display
‘Delete directory?’ instead of ‘Delete?’ and the
user must still type ‘yes’ to confirm, rather than
just pressing ‘y’.

* Document the new NERDTreeMinimalMenu feature

* Tweak the format for the minimal menu prompt

As per @PhilRunninger’s suggestions:

- The menu now shows the ‘j/k/enter’ help text
- The first word of the selected item is shown*
- Use commas between menu items so that it’s
  visually distinct from the ‘j/k/enter’ text

* I tried displaying the full menuItem text, but
this can be quite long, e.g.

> (o)pen the current node with system editor

This causes the menu to jump around a lot. We
could add another minimal versions of these, but
I think the first word seems ok for now.
2019-02-24 18:01:12 -05:00

207 lines
5.9 KiB
VimL

"CLASS: MenuController
"============================================================
let s:MenuController = {}
let g:NERDTreeMenuController = s:MenuController
"FUNCTION: MenuController.New(menuItems) {{{1
"create a new menu controller that operates on the given menu items
function! s:MenuController.New(menuItems)
let newMenuController = copy(self)
if a:menuItems[0].isSeparator()
let newMenuController.menuItems = a:menuItems[1:-1]
else
let newMenuController.menuItems = a:menuItems
endif
return newMenuController
endfunction
" FUNCTION: s:MenuController.isMinimal() {{{1
function! s:MenuController.isMinimal()
return g:NERDTreeMinimalMenu
endfunction
" FUNCTION: MenuController.showMenu() {{{1
" Enter the main loop of the NERDTree menu, prompting the user to select
" a menu item.
function! s:MenuController.showMenu()
call self._saveOptions()
try
let self.selection = 0
let l:done = 0
while !l:done
redraw!
call self._echoPrompt()
let l:key = nr2char(getchar())
let l:done = self._handleKeypress(l:key)
endwhile
finally
call self._restoreOptions()
" Redraw when "Ctrl-C" or "Esc" is received.
if !l:done || self.selection == -1
redraw!
endif
endtry
if self.selection != -1
let l:m = self._current()
call l:m.execute()
endif
endfunction
"FUNCTION: MenuController._echoPrompt() {{{1
function! s:MenuController._echoPrompt()
let navHelp = "Use " . g:NERDTreeMenuDown . "/" . g:NERDTreeMenuUp . "/enter"
if self.isMinimal()
let selection = self.menuItems[self.selection].text
let shortcuts = map(copy(self.menuItems), "v:val['shortcut']")
let shortcuts[self.selection] = " " . split(selection)[0] . " "
echo "Menu: [" . join(shortcuts, ",") . "] (" . navHelp . " or shortcut): "
else
echo "NERDTree Menu. " . navHelp . " . or the shortcuts indicated"
echo "========================================================="
for i in range(0, len(self.menuItems)-1)
if self.selection == i
echo "> " . self.menuItems[i].text
else
echo " " . self.menuItems[i].text
endif
endfor
endif
endfunction
"FUNCTION: MenuController._current(key) {{{1
"get the MenuItem that is currently selected
function! s:MenuController._current()
return self.menuItems[self.selection]
endfunction
"FUNCTION: MenuController._handleKeypress(key) {{{1
"change the selection (if appropriate) and return 1 if the user has made
"their choice, 0 otherwise
function! s:MenuController._handleKeypress(key)
if a:key == g:NERDTreeMenuDown
call self._cursorDown()
elseif a:key == g:NERDTreeMenuUp
call self._cursorUp()
elseif a:key == nr2char(27) "escape
let self.selection = -1
return 1
elseif a:key == "\r" || a:key == "\n" "enter and ctrl-j
return 1
else
let index = self._nextIndexFor(a:key)
if index != -1
let self.selection = index
if len(self._allIndexesFor(a:key)) == 1
return 1
endif
endif
endif
return 0
endfunction
"FUNCTION: MenuController._allIndexesFor(shortcut) {{{1
"get indexes to all menu items with the given shortcut
function! s:MenuController._allIndexesFor(shortcut)
let toReturn = []
for i in range(0, len(self.menuItems)-1)
if self.menuItems[i].shortcut == a:shortcut
call add(toReturn, i)
endif
endfor
return toReturn
endfunction
"FUNCTION: MenuController._nextIndexFor(shortcut) {{{1
"get the index to the next menu item with the given shortcut, starts from the
"current cursor location and wraps around to the top again if need be
function! s:MenuController._nextIndexFor(shortcut)
for i in range(self.selection+1, len(self.menuItems)-1)
if self.menuItems[i].shortcut == a:shortcut
return i
endif
endfor
for i in range(0, self.selection)
if self.menuItems[i].shortcut == a:shortcut
return i
endif
endfor
return -1
endfunction
"FUNCTION: MenuController._setCmdheight() {{{1
"sets &cmdheight to whatever is needed to display the menu
function! s:MenuController._setCmdheight()
if self.isMinimal()
let &cmdheight = 1
else
let &cmdheight = len(self.menuItems) + 3
endif
endfunction
"FUNCTION: MenuController._saveOptions() {{{1
"set any vim options that are required to make the menu work (saving their old
"values)
function! s:MenuController._saveOptions()
let self._oldLazyredraw = &lazyredraw
let self._oldCmdheight = &cmdheight
set nolazyredraw
call self._setCmdheight()
endfunction
"FUNCTION: MenuController._restoreOptions() {{{1
"restore the options we saved in _saveOptions()
function! s:MenuController._restoreOptions()
let &cmdheight = self._oldCmdheight
let &lazyredraw = self._oldLazyredraw
endfunction
"FUNCTION: MenuController._cursorDown() {{{1
"move the cursor to the next menu item, skipping separators
function! s:MenuController._cursorDown()
let done = 0
while !done
if self.selection < len(self.menuItems)-1
let self.selection += 1
else
let self.selection = 0
endif
if !self._current().isSeparator()
let done = 1
endif
endwhile
endfunction
"FUNCTION: MenuController._cursorUp() {{{1
"move the cursor to the previous menu item, skipping separators
function! s:MenuController._cursorUp()
let done = 0
while !done
if self.selection > 0
let self.selection -= 1
else
let self.selection = len(self.menuItems)-1
endif
if !self._current().isSeparator()
let done = 1
endif
endwhile
endfunction
" vim: set sw=4 sts=4 et fdm=marker: