Remove all direct vim bundles

This commit is contained in:
2024-10-08 18:16:51 +09:00
parent 847d7d3c59
commit 82d47276a7
177 changed files with 0 additions and 43281 deletions

View File

@@ -1,41 +0,0 @@
---
name: "Bug Report"
about: "nerdtree-git-plugin is misbehaving? Tell us about it."
labels: bug
---
<!-- Attention! Please Read!
Please fill out ALL the information below so that the issue can be fully
understood. Omitting information will delay the resolution of your issue. It
will be labeled "Needs More Info", and may be closed until there is enough
information.
Keep in mind that others may have the same question in the future. The better
your information, the more likely they'll be able to help themselves. -->
#### Self-Diagnosis
<!-- Check the boxes after creating the issue, or use [x]. -->
- [ ] I have searched the [issues](https://github.com/Xuyuanp/nerdtree-git-plugin/issues) for an answer to my question.
- [ ] I have reviewed the NERDTree documentation(README.md).
- [ ] I have searched the web for an answer to my question.
#### Environment (for bug reports)
- [ ] Operating System:
- [ ] vimrc settings
```vim
" all settings about nerdtree and other plugins
```
- Other NERDTree-dependent Plugins
- [ ] jistr/vim-nerdtree-tabs
- [ ] ryanoasis/vim-devicons
- [ ] tiagofumo/vim-nerdtree-syntax-highlight
- [ ] Others (specify):
- [ ] I've verified the issue occurs with only `nerdtree-git-plugin` installed.
- [ ] Copy-Paste `call gitstatus#doctor#Say()` outputs
#### Steps to Reproduce the Issue
1.
#### Current Result (Include screenshots where appropriate.)
#### Expected Result

View File

@@ -1,8 +0,0 @@
---
name: "Feature Request"
about: "What new feature are you requesting for nerdtree-git-plugin?"
labels: "feature request"
---
#### Description

View File

@@ -1,23 +0,0 @@
---
name: "General Question"
about: "Having trouble setting up nerdtree-git-plugin? Need clarification on a setting? Ask your question here."
labels: "general question"
---
<!-- Attention! Please Read!
Please fill out ALL the information below so that the issue can be fully
understood. Omitting information will delay the resolution of your issue. It
will be labeled "Needs More Info", and may be closed until there is enough
information.
Keep in mind that others may have the same question in the future. The better
your information, the more likely they'll be able to help themselves. -->
#### Self-Diagnosis
<!-- Check the boxes after creating the issue, or use [x]. -->
- [ ] I have searched the [issues](https://github.com/Xuyuanp/nerdtree-git-plugin/issues) for an answer to my question.
- [ ] I have reviewed the NERDTree documentation(README.md).
- [ ] I have searched the web for an answer to my question.
#### State Your Question

View File

@@ -1,3 +0,0 @@
### Description of Changes
Closes # <!-- Enter the issue number this PR addresses. If none, remove this line. -->

View File

@@ -1,17 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@@ -1,57 +0,0 @@
name: CI
on: [push, pull_request]
jobs:
vint:
name: Vint
strategy:
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run vint with reviewdog
uses: reviewdog/action-vint@v1.0.1
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-review
test:
name: Unit tests
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
neovim: [true, false]
version: [stable, nightly]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout themis.vim
uses: actions/checkout@v2
with:
repository: thinca/vim-themis
path: tmp/vim-themis
- name: Checkout nerdtree
uses: actions/checkout@v2
with:
repository: preservim/nerdtree
path: tmp/nerdtree
# Remove apt repos that are known to break from time to time
# See https://github.com/actions/virtual-environments/issues/323
- name: Remove broken apt repos [Ubuntu]
if: matrix.os == 'ubuntu-latest'
run: |
for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done
- name: Install Vim or Neovim
uses: rhysd/action-setup-vim@v1
id: vim
with:
neovim: ${{ matrix.neovim }}
version: ${{ matrix.version }}
- name: Run unit tests
env:
THEMIS_VIM: ${{ steps.vim.outputs.executable }}
THEMIS_PROFILE: profile.txt
run: |
echo $THEMIS_VIM
./tmp/vim-themis/bin/themis --runtimepath ./tmp/nerdtree --reporter spec tests/
# TODO: coverage

View File

@@ -1,14 +0,0 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-added-large-files
- id: mixed-line-ending
- repo: https://github.com/Vimjas/vint
rev: master
hooks:
- id: vint

View File

@@ -1,40 +0,0 @@
cmdargs:
# Checking more strictly
severity: style_problem
# Enable coloring
color: false
# Enable Neovim syntax
env:
neovim: true
policies:
ProhibitAutocmdWithNoGroup:
enabled: true
ProhibitCommandRelyOnUser:
enabled: true
ProhibitCommandWithUnintendedSideEffect:
enabled: true
ProhibitEncodingOptionAfterScriptEncoding:
enabled: true
ProhibitEqualTildeOperator:
enabled: true
ProhibitImplicitScopeBuiltinVariable:
enabled: true
ProhibitMissingScriptEncoding:
enabled: true
ProhibitNoAbortFunction:
enabled: true
ProhibitSetNoCompatible:
enabled: true
ProhibitUnnecessaryDoubleQuote:
enabled: true
ProhibitUnusedVariable:
enabled: true
ProhibitUsingUndeclaredVariable:
enabled: true
ProhibitAbbreviationOption:
enabled: true
ProhibitImplicitScopeVariable:
enabled: true

View File

@@ -1,14 +0,0 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@@ -1,104 +0,0 @@
nerdtree-git-plugin
===================
[![Github Action](https://img.shields.io/github/workflow/status/Xuyuanp/nerdtree-git-plugin/CI)](https://github.com/Xuyuanp/nerdtree-git-plugin/actions?query=workflow%3ACI)
[![License: WTFPL](https://img.shields.io/github/license/Xuyuanp/nerdtree-git-plugin)](http://www.wtfpl.net/about/)
[![GitHub contributors](https://img.shields.io/github/contributors/Xuyuanp/nerdtree-git-plugin)](https://github.com/Xuyuanp/nerdtree-git-plugin/graphs/contributors)
A plugin of [NERDTree](https://github.com/preservim/nerdtree) showing git status flags.
The original project [git-nerdtree](https://github.com/Xuyuanp/git-nerdtree) will not be maintained any longer.
![Imgur](http://i.imgur.com/jSCwGjU.gif?1)
## Installation
Use your favorite package manager. Here is the example of using [vim-plug](https://github.com/junegunn/vim-plug)
```vim script
Plug 'preservim/nerdtree' |
\ Plug 'Xuyuanp/nerdtree-git-plugin'
```
## FAQ
> Got error message like `Error detected while processing function
177[2]..178[22]..181[7]..144[9]..142[36]..238[4]..NERDTreeGitStatusRefreshListener[2]..NERDTreeGitStatusRefresh:
line 6:
E484: Can't open file /tmp/vZEZ6gM/1` while nerdtree opening in fish, how to resolve this problem?
This was because that vim couldn't execute `system` function in `fish`. Add `set shell=sh` in your vimrc.
This issue has been fixed.
> How to config custom symbols?
Use this variable to change symbols.
```vim
let g:NERDTreeGitStatusIndicatorMapCustom = {
\ 'Modified' :'✹',
\ 'Staged' :'✚',
\ 'Untracked' :'✭',
\ 'Renamed' :'➜',
\ 'Unmerged' :'═',
\ 'Deleted' :'✖',
\ 'Dirty' :'✗',
\ 'Ignored' :'☒',
\ 'Clean' :'✔︎',
\ 'Unknown' :'?',
\ }
```
There is a predefined map used *nerdfonts*, to enable it
```vim
let g:NERDTreeGitStatusUseNerdFonts = 1 " you should install nerdfonts by yourself. default: 0
```
> How to show `ignored` status?
```vim
let g:NERDTreeGitStatusShowIgnored = 1 " a heavy feature may cost much more time. default: 0
```
> How to cooperate with [vim-devicons](https://github.com/ryanoasis/vim-devicons)
```vim
Plug 'preservim/nerdtree' |
\ Plug 'Xuyuanp/nerdtree-git-plugin' |
\ Plug 'ryanoasis/vim-devicons'
```
Make sure they are in the right order.
> How to indicate every single `untracked` file under an `untracked` dir?
```vim
let g:NERDTreeGitStatusUntrackedFilesMode = 'all' " a heave feature too. default: normal
```
> How to set `git` executable file path?
```vim
let g:NERDTreeGitStatusGitBinPath = '/your/file/path' " defualt: git (auto find in path)
```
> How to show `Clean` indicator?
```vim
let g:NERDTreeGitStatusShowClean = 1 " default: 0
```
> How to hide the boring brackets(`[ ]`)?
```vim
let g:NERDTreeGitStatusConcealBrackets = 1 " default: 0
```
**NOTICE**: DO NOT enable this feature if you have also installed [vim-devicons](https://github.com/ryanoasis/vim-devicons).
## Credits
* [scrooloose](https://github.com/scrooloose): Open API for me.
* [git\_nerd](https://github.com/swerner/git_nerd): Where my idea comes from.
* [PickRelated](https://github.com/PickRelated): Add custom indicators & Review code.

View File

@@ -1,58 +0,0 @@
" ============================================================================
" File: autoload/gitstatus/job.vim
" Description: git status indicator syntax highlighting
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
if !get(g:, 'NERDTreeGitStatusEnable', 0)
finish
endif
function! s:getIndicator(status) abort
return gitstatus#getIndicator(a:status)
endfunction
if gitstatus#shouldConceal()
" Hide the backets
syntax match hideBracketsInNerdTreeL "\]" contained conceal containedin=NERDTreeFlags
syntax match hideBracketsInNerdTreeR "\[" contained conceal containedin=NERDTreeFlags
setlocal conceallevel=3
setlocal concealcursor=nvic
endif
function! s:highlightFromGroup(group) abort
let l:synid = synIDtrans(hlID(a:group))
let [l:ctermfg, l:guifg] = [synIDattr(l:synid, 'fg', 'cterm'), synIDattr(l:synid, 'fg', 'gui')]
return 'cterm=NONE ctermfg=' . l:ctermfg . ' ctermbg=NONE gui=NONE guifg=' . l:guifg . ' guibg=NONE'
endfunction
function! s:setHightlighting() abort
let l:synlist = [
\ ['Unmerged', 'Function'],
\ ['Modified', 'Special'],
\ ['Staged', 'Function'],
\ ['Renamed', 'Title'],
\ ['Unmerged', 'Label'],
\ ['Untracked', 'Comment'],
\ ['Dirty', 'Tag'],
\ ['Deleted', 'Operator'],
\ ['Ignored', 'SpecialKey'],
\ ['Clean', 'Method'],
\ ]
for [l:name, l:group] in l:synlist
let l:indicator = escape(s:getIndicator(l:name), '\#-*.$')
let l:synname = 'NERDTreeGitStatus' . l:name
execute 'silent! syntax match ' . l:synname . ' #\m\C\zs[' . l:indicator . ']\ze[^\]]*\]# containedin=NERDTreeFlags'
let l:hipat = get(get(g:, 'NERDTreeGitStatusHighlightingCustom', {}),
\ l:name,
\ s:highlightFromGroup(l:group))
execute 'silent! highlight ' . l:synname . ' ' . l:hipat
endfor
endfunction
silent! call s:setHightlighting()

View File

@@ -1,69 +0,0 @@
" ============================================================================
" File: autoload/gitstatus.vim
" Description: library for indicators
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
if exists('g:loaded_nerdtree_git_status_autoload')
finish
endif
let g:loaded_nerdtree_git_status_autoload = 1
function! gitstatus#isWin() abort
return has('win16') || has('win32') || has('win64')
endfunction
if get(g:, 'NERDTreeGitStatusUseNerdFonts', 0)
let s:indicatorMap = {
\ 'Modified' :nr2char(61545),
\ 'Staged' :nr2char(61543),
\ 'Untracked' :nr2char(61736),
\ 'Renamed' :nr2char(62804),
\ 'Unmerged' :nr2char(61556),
\ 'Deleted' :nr2char(63167),
\ 'Dirty' :nr2char(61453),
\ 'Ignored' :nr2char(61738),
\ 'Clean' :nr2char(61452),
\ 'Unknown' :nr2char(61832)
\ }
elseif &encoding ==? 'utf-8'
let s:indicatorMap = {
\ 'Modified' :nr2char(10041),
\ 'Staged' :nr2char(10010),
\ 'Untracked' :nr2char(10029),
\ 'Renamed' :nr2char(10140),
\ 'Unmerged' :nr2char(9552),
\ 'Deleted' :nr2char(10006),
\ 'Dirty' :nr2char(10007),
\ 'Ignored' :nr2char(33),
\ 'Clean' :nr2char(10004),
\ 'Unknown' :nr2char(120744)
\ }
else
let s:indicatorMap = {
\ 'Modified' :'*',
\ 'Staged' :'+',
\ 'Untracked' :'!',
\ 'Renamed' :'R',
\ 'Unmerged' :'=',
\ 'Deleted' :'D',
\ 'Dirty' :'X',
\ 'Ignored' :'?',
\ 'Clean' :'C',
\ 'Unknown' :'E'
\ }
endif
function! gitstatus#getIndicator(status) abort
return get(get(g:, 'NERDTreeGitStatusIndicatorMapCustom', {}),
\ a:status,
\ s:indicatorMap[a:status])
endfunction
function! gitstatus#shouldConceal() abort
return has('conceal') && g:NERDTreeGitStatusConcealBrackets
endfunction

View File

@@ -1,167 +0,0 @@
" ============================================================================
" File: autoload/gitstatus/doctor.vim
" Description: what does the doctor say?
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
let s:types = {
\ 'NUMBER': type(0),
\ 'STRING': type(''),
\ 'FUNCREF': type(function('tr')),
\ 'LIST': type([]),
\ 'DICT': type({}),
\ 'FLOAT': type(0.0),
\ 'BOOL': type(v:true),
\ 'NULL': type(v:null)
\ }
let s:type_formatters = {}
let s:type_formatters[s:types.NUMBER] = { nbr -> string(nbr) }
let s:type_formatters[s:types.STRING] = { str -> printf("'%s'", str) }
let s:type_formatters[s:types.FUNCREF] = { fn -> string(fn) }
let s:type_formatters[s:types.LIST] = { lst -> s:prettifyList(lst, ' \ ', 0, ' ') }
let s:type_formatters[s:types.DICT] = { dct -> s:prettifyDict(dct, ' \ ', 0, ' ') }
let s:type_formatters[s:types.FLOAT] = { flt -> string(flt) }
let s:type_formatters[s:types.BOOL] = { bol -> bol ? 'v:true' : 'v:false' }
let s:type_formatters[s:types.NULL] = { nul -> string(nul) }
function! s:get_git_version() abort
return split(system('git version'), "\n")[0]
endfunction
function! s:get_git_status_output(workdir) abort
return system(join(gitstatus#util#BuildGitStatusCommand(a:workdir, g:), ' '))
endfunction
function! s:prettifyDict(obj, prefix, level, indent) abort
let l:prefix = a:prefix . repeat(a:indent, a:level)
if empty(a:obj)
return '{}'
endif
let l:res = "{\n"
for [l:key, l:val] in items(a:obj)
let l:type = type(l:val)
if l:type is# s:types.DICT
let l:val = s:prettifyDict(l:val, a:prefix, a:level + 1, a:indent)
elseif l:type is# s:types.LIST
let l:val = s:prettifyList(l:val, a:prefix , a:level + 1, a:indent)
else
let l:val = s:prettify(l:val)
endif
let l:res .= l:prefix . a:indent . "'" . l:key . "': " . l:val . ",\n"
endfor
let l:res .= l:prefix . '}'
return l:res
endfunction
function! s:prettifyList(obj, prefix, level, indent) abort
let l:prefix = a:prefix . repeat(a:indent, a:level)
if empty(a:obj)
return '[]'
endif
let l:res = "[\n"
for l:val in a:obj
let l:type = type(l:val)
if l:type is# s:types.LIST
let l:val = s:prettifyList(l:val, a:prefix, a:level + 1, a:indent)
elseif l:type is# s:types.DICT
let l:val = s:prettifyDict(l:val, a:prefix, a:level + 1, a:indent)
else
let l:val = s:prettify(l:val)
endif
let l:res .= l:prefix . a:indent . l:val . ",\n"
endfor
let l:res .= l:prefix . ']'
return l:res
endfunction
function! s:prettify(obj) abort
let l:type = type(a:obj)
return call(s:type_formatters[l:type], [a:obj])
endfunction
function! s:loaded_vim_devicons() abort
return get(g:, 'loaded_webdevicons', 0) && get(g:, 'webdevicons_enable', 0) && get(g:, 'webdevicons_enable_nerdtree', 0)
endfunction
function! s:loaded_vim_nerdtree_syntax_highlight() abort
return exists('g:NERDTreeSyntaxEnabledExtensions')
endfunction
function! s:loaded_vim_nerdtree_tabs() abort
return exists('g:nerdtree_tabs_open_on_gui_startup')
endfunction
function! gitstatus#doctor#Say() abort
call g:NERDTree.MustBeOpen()
call g:NERDTree.CursorToTreeWin()
let l:line = repeat('=', 80)
echo has('nvim') ? 'Neovim:' : 'Vim:'
echo execute('version')
echo l:line
echo 'NERDTree:'
echo 'version: ' . nerdtree#version()
echo 'root: ' . b:NERDTree.root.path.str()
echo l:line
echo 'Git:'
echo 'version: ' . s:get_git_version()
let l:git_workdir = get(g:, 'NTGitWorkdir', '')
echo 'workdir: ' . l:git_workdir
if !empty(l:git_workdir)
echo 'status output:'
echo s:get_git_status_output(l:git_workdir)
endif
echo l:line
echo 'Options:'
for [l:key, l:val] in items(g:)
if l:key =~# 'NERDTreeGitStatus*'
echo '' . l:key . ' = ' . s:prettify(l:val)
endif
endfor
echo l:line
echo 'Others:'
echo 'vim-devicons: ' . (s:loaded_vim_devicons() ? 'yes' : 'no')
if s:loaded_vim_devicons()
for [l:key, l:val] in items(g:)
if l:key =~# 'WebDevIconsNerdTree*'
echo '' . l:key . ' = ' . s:prettify(l:val)
endif
endfor
endif
echo repeat('-', 40)
echo 'vim-nerdtree-syntax-highlight: ' . (s:loaded_vim_nerdtree_syntax_highlight() ? 'yes': 'no')
if s:loaded_vim_nerdtree_syntax_highlight()
for [l:key, l:val] in items(g:)
if l:key =~# 'NERDTreeSyntax*'
echo '' . l:key . ' = ' . s:prettify(l:val)
endif
endfor
endif
echo repeat('-', 40)
echo 'vim-nerdtree-tabs: ' . (s:loaded_vim_nerdtree_tabs() ? 'yes': 'no')
if s:loaded_vim_nerdtree_tabs()
for [l:key, l:val] in items(g:)
if l:key =~# 'nerdtree_tabs_*'
echo '' . l:key . ' = ' . s:prettify(l:val)
endif
endfor
endif
echo l:line
endfunction

View File

@@ -1,131 +0,0 @@
" ============================================================================
" File: autoload/gitstatus/job.vim
" Description: async-jobs
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
if exists('g:loaded_nerdtree_git_status_job')
finish
endif
let g:loaded_nerdtree_git_status_job = 1
" stolen from vim-plug
let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait'))
let s:vim8 = has('patch-8.0.0039') && exists('*job_start')
let s:Job = {
\ 'running': 0,
\ 'failed': 0,
\ 'chunks': [''],
\ 'err_chunks': [''],
\ }
" disabled ProhibitImplicitScopeVariable because we will use lots of `self`
" disabled ProhibitUnusedVariable because lambda
" vint: -ProhibitImplicitScopeVariable -ProhibitUnusedVariable
function! s:newJob(name, opts) abort
return extend(deepcopy(s:Job), {
\ 'name': a:name,
\ 'opts': a:opts
\ })
endfunction
function! s:Job.onStdoutCB(data) abort
let self.chunks[-1] .= a:data[0]
call extend(self.chunks, a:data[1:])
endfunction
function! s:Job.onStderrCB(data) abort
let self.failed = self.failed || !s:isEOF(a:data)
let self.err_chunks[-1] .= a:data[0]
call extend(self.err_chunks, a:data[1:])
endfunction
function! s:Job.onExitCB() abort
let self.running = 0
if self.failed
call self.onFailed()
else
call self.onSuccess()
endif
endfunction
function! s:Job.onFailed() abort
if has_key(self.opts, 'on_failed_cb')
call call(self.opts.on_failed_cb, [self])
endif
endfunction
function! s:Job.onSuccess() abort
if has_key(self.opts, 'on_success_cb')
call call(self.opts.on_success_cb, [self])
endif
endfunction
if s:nvim
function! s:Job.run(cmd) abort
let jid = jobstart(a:cmd, {
\ 'on_stdout': {_job_id, data, _event -> self.onStdoutCB(data)},
\ 'on_stderr': {_job_id, data, _event -> self.onStderrCB(data)},
\ 'on_exit': {_job_id, _data, _event -> self.onExitCB()},
\ })
let self.id = jid
let self.running = jid > 0
if jid <= 0
let self.failed = 1
let self.err_chunks = jid == 0 ?
\ ['invalid arguments'] :
\ ['command is not executable']
call self.onExitCB()
endif
endfunction
elseif s:vim8
function! s:Job.run(cmd) abort
let options = {
\ 'out_cb': { _ch, data -> self.onStdoutCB([data]) },
\ 'err_cb': { _ch, data -> self.onStderrCB([data]) },
\ 'close_cb': { _ch -> self.onExitCB() },
\ 'out_mode': 'nl',
\ 'err_mode': 'nl',
\ }
if has('patch-8.1.350')
let options['noblock'] = 1
endif
let jid = job_start(a:cmd, options)
if job_status(jid) ==# 'run'
let self.id = jid
let self.running = 1
else
let self.running = 0
let self.failed = 1
let self.err_chunks = ['failed to start job']
call self.onExitCB()
endif
endfunction
else
function! s:Job.run(cmd) abort
let output = substitute(system(join(a:cmd, ' ')), "\<C-A>", "\n", 'g')
let self.failed = v:shell_error isnot# 0
if self.failed
let self.err_chunks = [output]
else
let self.chunks = [output]
endif
call self.onExitCB()
endfunction
endif
" vint: +ProhibitImplicitScopeVariable +ProhibitUnusedVariable
function! s:isEOF(data) abort
return len(a:data) == 1 && a:data[0] is# ''
endfunction
function! gitstatus#job#Spawn(name, cmd, opts) abort
let l:job = s:newJob(a:name, a:opts)
call l:job.run(a:cmd)
return l:job
endfunction

View File

@@ -1,112 +0,0 @@
" ============================================================================
" File: autoload/gitstatus/listener.vim
" Description: nerdtree event listener
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
if exists('g:loaded_nerdtree_git_status_listener')
finish
endif
let g:loaded_nerdtree_git_status_listener = 1
let s:Listener = {
\ 'current': {},
\ 'next': {},
\ }
" disabled ProhibitImplicitScopeVariable because we will use lots of `self`
" vint: -ProhibitImplicitScopeVariable
function! s:Listener.OnInit(event) abort
call self.callback(a:event)
endfunction
function! s:Listener.OnRefresh(event) abort
call self.callback(a:event)
endfunction
function! s:Listener.OnRefreshFlags(event) abort
call self.callback(a:event)
endfunction
function! s:Listener.callback(event) abort
let l:path = a:event.subject
let l:indicator = self.getIndicatorByPath(l:path)
call l:path.flagSet.clearFlags('git')
if l:indicator !=# ''
if gitstatus#shouldConceal()
let l:indicator = printf(' %s ', l:indicator)
endif
call l:path.flagSet.addFlag('git', l:indicator)
endif
endfunction
function!s:Listener.getIndicatorByPath(path) abort
let l:pathStr = gitstatus#util#FormatPath(a:path)
let l:statusKey = get(self.current, l:pathStr, '')
if l:statusKey !=# ''
return gitstatus#getIndicator(l:statusKey)
endif
if self.getOption('ShowClean', 0)
return gitstatus#getIndicator('Clean')
endif
if self.getOption('ConcealBrackets', 0) && self.getOption('AlignIfConceal', 0)
return ' '
endif
return ''
endfunction
function! s:Listener.SetNext(cache) abort
let self.next = a:cache
endfunction
function! s:Listener.HasPath(path_str) abort
return has_key(self.current, a:path_str)
endfunction
function! s:Listener.changed() abort
return self.current !=# self.next
endfunction
function! s:Listener.update() abort
let self.current = self.next
endfunction
function! s:Listener.TryUpdateNERDTreeUI() abort
if !g:NERDTree.IsOpen()
return
endif
if !self.changed()
return
endif
call self.update()
let l:winnr = winnr()
let l:altwinnr = winnr('#')
try
call g:NERDTree.CursorToTreeWin()
call b:NERDTree.root.refreshFlags()
call NERDTreeRender()
finally
exec l:altwinnr . 'wincmd w'
exec l:winnr . 'wincmd w'
endtry
endfunction
function! s:Listener.getOption(name, default) abort
return get(self.opts, 'NERDTreeGitStatus' . a:name, a:default)
endfunction
" vint: +ProhibitImplicitScopeVariable
function! gitstatus#listener#New(opts) abort
return extend(deepcopy(s:Listener), {'opts': a:opts})
endfunction

View File

@@ -1,56 +0,0 @@
" ============================================================================
" File: autoload/gitstatus/job.vim
" Description: leveled-logger
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
if exists('g:loaded_nerdtree_git_status_log')
finish
endif
let g:loaded_nerdtree_git_status_log = 1
let s:debug = 0 | :lockvar s:debug
let s:info = 1 | :lockvar s:info
let s:warning = 2 | :lockvar s:warning
let s:error = 3 | :lockvar s:error
let s:Logger = {}
" vint: -ProhibitImplicitScopeVariable
function! s:Logger.output(level, msg) abort
if a:level < self.level
return
endif
echomsg '[nerdtree-git-status] ' . a:msg
endfunction
function! s:Logger.debug(msg) abort
echohl LineNr |
\ call self.output(s:debug, a:msg) |
\ echohl None
endfunction
function! s:Logger.info(msg) abort
call self.output(s:info, a:msg)
endfunction
function! s:Logger.warning(msg) abort
echohl WarningMsg |
\ call self.output(s:warning, a:msg) |
\ echohl None
endfunction
function! s:Logger.error(msg) abort
echohl ErrorMsg |
\ call self.output(s:error, a:msg) |
\ echohl None
endfunction
" vint: +ProhibitImplicitScopeVariable
function! gitstatus#log#NewLogger(level) abort
return extend(copy(s:Logger), {'level': a:level})
endfunction

View File

@@ -1,225 +0,0 @@
" ============================================================================
" File: autoload/git_status/util.vim
" Description: utils
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
if exists('g:loaded_nerdtree_git_status_util')
finish
endif
let g:loaded_nerdtree_git_status_util = 1
" FUNCTION: gitstatus#utilFormatPath
" This function is used to format nerdtree.Path.
" For Windows, returns in format 'C:/path/to/file'
"
" ARGS:
" path: nerdtree.Path
"
" RETURNS:
" absolute path
if gitstatus#isWin()
if exists('+shellslash')
function! gitstatus#util#FormatPath(path) abort
let l:sslbak = &shellslash
try
set shellslash
return a:path.str()
finally
let &shellslash = l:sslbak
endtry
endfunction
else
function! gitstatus#util#FormatPath(path) abort
let l:pathStr = a:path.str()
let l:pathStr = a:path.WinToUnixPath(l:pathStr)
let l:pathStr = a:path.drive . l:pathStr
return l:pathStr
endfunction
endif
else
function! gitstatus#util#FormatPath(path) abort
return a:path.str()
endfunction
endif
function! gitstatus#util#BuildGitWorkdirCommand(root, opts) abort
return [
\ get(a:opts, 'NERDTreeGitStatusGitBinPath', 'git'),
\ '-C', a:root,
\ 'rev-parse',
\ '--show-toplevel',
\ ]
endfunction
function! gitstatus#util#BuildGitStatusCommand(root, opts) abort
let l:cmd = [
\ get(a:opts, 'NERDTreeGitStatusGitBinPath', 'git'),
\ '-C', a:root,
\ 'status',
\ '--porcelain' . (get(a:opts, 'NERDTreeGitStatusPorcelainVersion', 2) ==# 2 ? '=v2' : ''),
\ '-z'
\ ]
if has_key(a:opts, 'NERDTreeGitStatusUntrackedFilesMode')
let l:cmd += ['--untracked-files=' . a:opts['NERDTreeGitStatusUntrackedFilesMode']]
endif
if get(a:opts, 'NERDTreeGitStatusShowIgnored', 0)
let l:cmd += ['--ignored=traditional']
endif
if has_key(a:opts, 'NERDTreeGitStatusIgnoreSubmodules')
let l:cmd += ['--ignore-submodules=' . a:opts['NERDTreeGitStatusIgnoreSubmodules']]
endif
return l:cmd
endfunction
function! gitstatus#util#ParseGitStatusLines(root, statusLines, opts) abort
let l:result = {}
let l:is_rename = 0
for l:line in a:statusLines
if l:is_rename
call gitstatus#util#UpdateParentDirsStatus(l:result, a:root, a:root . '/' . l:line, 'Dirty', a:opts)
let l:is_rename = 0
continue
endif
let [l:pathStr, l:statusKey] = gitstatus#util#ParseGitStatusLine(l:line, a:opts)
let l:pathStr = a:root . '/' . l:pathStr
if l:pathStr[-1:-1] is# '/'
let l:pathStr = l:pathStr[:-2]
endif
let l:is_rename = l:statusKey is# 'Renamed'
let l:result[l:pathStr] = l:statusKey
call gitstatus#util#UpdateParentDirsStatus(l:result, a:root, l:pathStr, l:statusKey, a:opts)
endfor
return l:result
endfunction
let s:unmerged_status = {
\ 'DD': 1,
\ 'AU': 1,
\ 'UD': 1,
\ 'UA': 1,
\ 'DU': 1,
\ 'AA': 1,
\ 'UU': 1,
\ }
" Function: s:getStatusKey() function {{{2
" This function is used to get git status key
"
" Args:
" x: index tree
" y: work tree
"
"Returns:
" status key
"
" man git-status
" X Y Meaning
" -------------------------------------------------
" [MD] not updated
" M [ MD] updated in index
" A [ MD] added to index
" D [ M] deleted from index
" R [ MD] renamed in index
" C [ MD] copied in index
" [MARC] index and work tree matches
" [ MARC] M work tree changed since index
" [ MARC] D deleted in work tree
" -------------------------------------------------
" D D unmerged, both deleted
" A U unmerged, added by us
" U D unmerged, deleted by them
" U A unmerged, added by them
" D U unmerged, deleted by us
" A A unmerged, both added
" U U unmerged, both modified
" -------------------------------------------------
" ? ? untracked
" ! ! ignored
" -------------------------------------------------
function! s:getStatusKey(x, y) abort
let l:xy = a:x . a:y
if get(s:unmerged_status, l:xy, 0)
return 'Unmerged'
elseif l:xy ==# '??'
return 'Untracked'
elseif l:xy ==# '!!'
return 'Ignored'
elseif a:y ==# 'M'
return 'Modified'
elseif a:y ==# 'D'
return 'Deleted'
elseif a:y =~# '[RC]'
return 'Renamed'
elseif a:x ==# 'D'
return 'Deleted'
elseif a:x =~# '[MA]'
return 'Staged'
elseif a:x =~# '[RC]'
return 'Renamed'
else
return 'Unknown'
endif
endfunction
function! gitstatus#util#ParseGitStatusLine(statusLine, opts) abort
if get(a:opts, 'NERDTreeGitStatusPorcelainVersion', 2) ==# 2
if a:statusLine[0] ==# '1'
let l:statusKey = s:getStatusKey(a:statusLine[2], a:statusLine[3])
let l:pathStr = a:statusLine[113:]
elseif a:statusLine[0] ==# '2'
let l:statusKey = 'Renamed'
let l:pathStr = a:statusLine[113:]
let l:pathStr = l:pathStr[stridx(l:pathStr, ' ')+1:]
elseif a:statusLine[0] ==# 'u'
let l:statusKey = 'Unmerged'
let l:pathStr = a:statusLine[161:]
elseif a:statusLine[0] ==# '?'
let l:statusKey = 'Untracked'
let l:pathStr = a:statusLine[2:]
elseif a:statusLine[0] ==# '!'
let l:statusKey = 'Ignored'
let l:pathStr = a:statusLine[2:]
else
throw '[nerdtree_git_status] unknown status: ' . a:statusLine
endif
return [l:pathStr, l:statusKey]
else
let l:pathStr = a:statusLine[3:]
let l:statusKey = s:getStatusKey(a:statusLine[0], a:statusLine[1])
return [l:pathStr, l:statusKey]
endif
endfunction
function! gitstatus#util#UpdateParentDirsStatus(cache, root, pathStr, statusKey, opts) abort
let l:dirtyPath = fnamemodify(a:pathStr, ':h')
let l:dir_dirty_only = get(a:opts, 'NERDTreeGitStatusDirDirtyOnly', 1)
while l:dirtyPath !=# a:root
let l:key = get(a:cache, l:dirtyPath, '')
if l:dir_dirty_only
if l:key ==# ''
let a:cache[l:dirtyPath] = 'Dirty'
else
return
endif
else
if l:key ==# ''
let a:cache[l:dirtyPath] = a:statusKey
elseif l:key ==# 'Dirty' || l:key ==# a:statusKey
return
else
let a:cache[l:dirtyPath] = 'Dirty'
endif
endif
let l:dirtyPath = fnamemodify(l:dirtyPath, ':h')
endwhile
endfunction

View File

@@ -1,343 +0,0 @@
" ============================================================================
" File: git_status.vim
" Description: plugin for NERD Tree that provides git status support
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
scriptencoding utf-8
if exists('g:loaded_nerdtree_git_status')
finish
endif
let g:loaded_nerdtree_git_status = 1
let s:is_win = gitstatus#isWin()
" stolen from nerdtree
"Function: s:initVariable() function {{{2
"This function is used to initialise a given variable to a given value. The
"variable is only initialised if it does not exist prior
"
"Args:
"var: the name of the var to be initialised
"value: the value to initialise var to
"
"Returns:
"1 if the var is set, 0 otherwise
function! s:initVariable(var, value) abort
if !exists(a:var)
exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", 'g') . "'"
return 1
endif
return 0
endfunction
let s:default_vals = {
\ 'g:NERDTreeGitStatusEnable': 1,
\ 'g:NERDTreeGitStatusUpdateOnWrite': 1,
\ 'g:NERDTreeGitStatusUpdateOnCursorHold': 1,
\ 'g:NERDTreeGitStatusShowIgnored': 0,
\ 'g:NERDTreeGitStatusUseNerdFonts': 0,
\ 'g:NERDTreeGitStatusDirDirtyOnly': 1,
\ 'g:NERDTreeGitStatusConcealBrackets': 0,
\ 'g:NERDTreeGitStatusAlignIfConceal': 1,
\ 'g:NERDTreeGitStatusShowClean': 0,
\ 'g:NERDTreeGitStatusLogLevel': 2,
\ 'g:NERDTreeGitStatusPorcelainVersion': 2,
\ 'g:NERDTreeGitStatusMapNextHunk': ']c',
\ 'g:NERDTreeGitStatusMapPrevHunk': '[c',
\ 'g:NERDTreeGitStatusUntrackedFilesMode': 'normal',
\ 'g:NERDTreeGitStatusGitBinPath': 'git',
\ }
for [s:var, s:value] in items(s:default_vals)
call s:initVariable(s:var, s:value)
endfor
let s:logger = gitstatus#log#NewLogger(g:NERDTreeGitStatusLogLevel)
function! s:deprecated(oldv, newv) abort
call s:logger.warning(printf("option '%s' is deprecated, please use '%s'", a:oldv, a:newv))
endfunction
function! s:migrateVariable(oldv, newv) abort
if exists(a:oldv)
call s:deprecated(a:oldv, a:newv)
exec 'let ' . a:newv . ' = ' . a:oldv
return 1
endif
return 0
endfunction
let s:need_migrate_vals = {
\ 'g:NERDTreeShowGitStatus': 'g:NERDTreeGitStatusEnable',
\ 'g:NERDTreeUpdateOnWrite': 'g:NERDTreeGitStatusUpdateOnWrite',
\ 'g:NERDTreeMapNextHunk': 'g:NERDTreeGitStatusMapNextHunk',
\ 'g:NERDTreeMapPrevHunk': 'g:NERDTreeGitStatusMapPrevHunk',
\ 'g:NERDTreeShowIgnoredStatus': 'g:NERDTreeGitStatusShowIgnored',
\ 'g:NERDTreeIndicatorMapCustom': 'g:NERDTreeGitStatusIndicatorMapCustom',
\ }
for [s:oldv, s:newv] in items(s:need_migrate_vals)
call s:migrateVariable(s:oldv, s:newv)
endfor
if !g:NERDTreeGitStatusEnable
finish
endif
if !executable(g:NERDTreeGitStatusGitBinPath)
call s:logger.error('git command not found')
finish
endif
" FUNCTION: path2str
" This function is used to format nerdtree.Path.
" For Windows, returns in format 'C:/path/to/file'
"
" ARGS:
" path: nerdtree.Path
"
" RETURNS:
" absolute path
function! s:path2str(path) abort
return gitstatus#util#FormatPath(a:path)
endfunction
" disable ProhibitUnusedVariable because these three functions used to callback
" vint: -ProhibitUnusedVariable
function! s:onGitWorkdirSuccessCB(job) abort
let g:NTGitWorkdir = split(join(a:job.chunks, ''), "\n")[0]
call s:logger.debug(printf("'%s' is in a git repo: '%s'", a:job.opts.cwd, g:NTGitWorkdir))
call s:enableLiveUpdate()
call s:refreshGitStatus('init', g:NTGitWorkdir)
endfunction
function! s:onGitWorkdirFailedCB(job) abort
let l:errormsg = join(a:job.err_chunks, '')
if l:errormsg =~# 'fatal: Not a git repository'
call s:logger.debug(printf("'%s' is not in a git repo", a:job.opts.cwd))
endif
call s:disableLiveUpdate()
unlet! g:NTGitWorkdir
endfunction
function! s:getGitWorkdir(ntRoot) abort
call gitstatus#job#Spawn('git-workdir',
\ s:buildGitWorkdirCommand(a:ntRoot),
\ {
\ 'on_success_cb': function('s:onGitWorkdirSuccessCB'),
\ 'on_failed_cb': function('s:onGitWorkdirFailedCB'),
\ 'cwd': a:ntRoot,
\ })
endfunction
" vint: +ProhibitUnusedVariable
function! s:buildGitWorkdirCommand(root) abort
return gitstatus#util#BuildGitWorkdirCommand(a:root, g:)
endfunction
function! s:buildGitStatusCommand(workdir) abort
return gitstatus#util#BuildGitStatusCommand(a:workdir, g:)
endfunction
function! s:refreshGitStatus(name, workdir) abort
let l:opts = {
\ 'on_failed_cb': function('s:onGitStatusFailedCB'),
\ 'on_success_cb': function('s:onGitStatusSuccessCB'),
\ 'cwd': a:workdir
\ }
let l:job = gitstatus#job#Spawn(a:name, s:buildGitStatusCommand(a:workdir), l:opts)
return l:job
endfunction
" vint: -ProhibitUnusedVariable
function! s:onGitStatusSuccessCB(job) abort
if !exists('g:NTGitWorkdir') || g:NTGitWorkdir !=# a:job.opts.cwd
call s:logger.debug(printf("git workdir has changed: '%s' -> '%s'", a:job.opts.cwd, get(g:, 'NTGitWorkdir', '')))
return
endif
let l:output = join(a:job.chunks, '')
let l:lines = split(l:output, "\n")
let l:cache = gitstatus#util#ParseGitStatusLines(a:job.opts.cwd, l:lines, g:)
call s:listener.SetNext(l:cache)
call s:listener.TryUpdateNERDTreeUI()
endfunction
function! s:onGitStatusFailedCB(job) abort
let l:errormsg = join(a:job.err_chunks, '')
if l:errormsg =~# "error: option `porcelain' takes no value"
call s:logger.error(printf("'git status' command failed, please upgrade your git binary('v2.11.0' or higher) or set option 'g:NERDTreeGitStatusPorcelainVersion' to 1 in vimrc"))
call s:disableLiveUpdate()
unlet! g:NTGitWorkdir
elseif l:errormsg =~# '^warning: could not open .* Permission denied'
call s:onGitStatusSuccessCB(a:job)
else
call s:logger.error(printf('job[%s] failed: %s', a:job.name, l:errormsg))
endif
endfunction
" FUNCTION: s:onCursorHold(fname) {{{2
function! s:onCursorHold(fname)
" Do not update when a special buffer is selected
if !empty(&l:buftype)
return
endif
let l:fname = s:is_win ?
\ substitute(a:fname, '\', '/', 'g') :
\ a:fname
if !exists('g:NTGitWorkdir') || !s:hasPrefix(l:fname, g:NTGitWorkdir)
return
endif
let l:job = s:refreshGitStatus('cursor-hold', g:NTGitWorkdir)
call s:logger.debug('run cursor-hold job: ' . l:job.id)
endfunction
" FUNCTION: s:onFileUpdate(fname) {{{2
function! s:onFileUpdate(fname)
let l:fname = s:is_win ?
\ substitute(a:fname, '\', '/', 'g') :
\ a:fname
if !exists('g:NTGitWorkdir') || !s:hasPrefix(l:fname, g:NTGitWorkdir)
return
endif
let l:job = s:refreshGitStatus('file-update', g:NTGitWorkdir)
call s:logger.debug('run file-update job: ' . l:job.id)
endfunction
" vint: +ProhibitUnusedVariable
function! s:hasPrefix(text, prefix) abort
return len(a:text) >= len(a:prefix) && a:text[:len(a:prefix)-1] ==# a:prefix
endfunction
function! s:setupNERDTreeListeners(listener) abort
call g:NERDTreePathNotifier.AddListener('init', a:listener.OnInit)
call g:NERDTreePathNotifier.AddListener('refresh', a:listener.OnRefresh)
call g:NERDTreePathNotifier.AddListener('refreshFlags', a:listener.OnRefreshFlags)
endfunction
" FUNCTION: s:findHunk(node, direction)
" Args:
" node: the current node
" direction: next(>0) or prev(<0)
"
" Returns:
" lineNum if the hunk found, -1 otherwise
function! s:findHunk(node, direction) abort
let l:ui = b:NERDTree.ui
let l:rootLn = l:ui.getRootLineNum()
let l:totalLn = line('$')
let l:currLn = l:ui.getLineNum(a:node)
let l:currLn = l:currLn <= l:rootLn ? l:rootLn+1 : l:currLn
let l:step = a:direction > 0 ? 1 : -1
let l:lines = a:direction > 0 ?
\ range(l:currLn+1, l:totalLn, l:step) + range(l:rootLn+1, l:currLn-1, l:step) :
\ range(l:currLn-1, l:rootLn+1, l:step) + range(l:totalLn, l:currLn+1, l:step)
for l:ln in l:lines
let l:path = s:path2str(l:ui.getPath(l:ln))
if s:listener.HasPath(l:path)
return l:ln
endif
endfor
return -1
endfunction
" vint: -ProhibitUnusedVariable
" FUNCTION: s:jumpToNextHunk(node) {{{2
function! s:jumpToNextHunk(node)
let l:ln = s:findHunk(a:node, 1)
if l:ln > 0
exec '' . l:ln
call s:logger.info('Jump to next hunk')
endif
endfunction
" FUNCTION: s:jumpToPrevHunk(node) {{{2
function! s:jumpToPrevHunk(node)
let l:ln = s:findHunk(a:node, -1)
if l:ln > 0
exec '' . l:ln
call s:logger.info('Jump to prev hunk')
endif
endfunction
" vint: +ProhibitUnusedVariable
" Function: s:SID() {{{2
function s:SID()
if !exists('s:sid')
let s:sid = matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endif
return s:sid
endfun
" FUNCTION: s:setupNERDTreeKeyMappings {{{2
function! s:setupNERDTreeKeyMappings()
let l:s = '<SNR>' . s:SID() . '_'
call NERDTreeAddKeyMap({
\ 'key': g:NERDTreeGitStatusMapNextHunk,
\ 'scope': 'Node',
\ 'callback': l:s.'jumpToNextHunk',
\ 'quickhelpText': 'Jump to next git hunk' })
call NERDTreeAddKeyMap({
\ 'key': g:NERDTreeGitStatusMapPrevHunk,
\ 'scope': 'Node',
\ 'callback': l:s.'jumpToPrevHunk',
\ 'quickhelpText': 'Jump to prev git hunk' })
endfunction
" I don't know why, but vint said they are unused.
" vint: -ProhibitUnusedVariable
function! s:onNERDTreeDirChanged(path) abort
call s:getGitWorkdir(a:path)
endfunction
function! s:onNERDTreeInit(path) abort
call s:getGitWorkdir(a:path)
endfunction
" vint: +ProhibitUnusedVariable
function! s:enableLiveUpdate() abort
augroup nerdtreegitplugin_liveupdate
autocmd!
if g:NERDTreeGitStatusUpdateOnWrite
autocmd BufWritePost * silent! call s:onFileUpdate(expand('%:p'))
endif
if g:NERDTreeGitStatusUpdateOnCursorHold
autocmd CursorHold * silent! call s:onCursorHold(expand('%:p'))
endif
" TODO: is it necessary to pass the buffer name?
autocmd User FugitiveChanged silent! call s:onFileUpdate(expand('%:p'))
autocmd BufEnter NERD_tree_* call s:onNERDTreeInit(s:path2str(b:NERDTree.root.path))
augroup end
endfunction
function! s:disableLiveUpdate() abort
augroup nerdtreegitplugin_liveupdate
autocmd!
augroup end
endfunction
augroup nerdtreegitplugin
autocmd!
autocmd User NERDTreeInit call s:onNERDTreeInit(s:path2str(b:NERDTree.root.path))
autocmd User NERDTreeNewRoot call s:onNERDTreeDirChanged(s:path2str(b:NERDTree.root.path))
augroup end
call s:setupNERDTreeKeyMappings()
let s:listener = gitstatus#listener#New(g:)
call s:setupNERDTreeListeners(s:listener)

View File

@@ -1,4 +0,0 @@
if exists('$THEMIS_PROFILE')
execute 'profile' 'start' $THEMIS_PROFILE
profile! file ./autoload/*
endif

View File

@@ -1,109 +0,0 @@
let s:suite = themis#suite('Test for nerdtree-git-plugin')
let s:assert = themis#helper('assert')
call themis#helper('command').with(s:)
function! s:suite.Initializing() abort
NERDTreeFocus
call s:assert.exists('g:NERDTree')
call s:assert.exists('g:loaded_nerdtree_git_status')
call g:NERDTree.CursorToTreeWin()
call s:assert.exists('b:NERDTree')
endfunction
function! s:suite.BuildGitWorkdirCommand() abort
let l:cmd = gitstatus#util#BuildGitWorkdirCommand('/workdir', {})
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'rev-parse', '--show-toplevel'])
let l:cmd = gitstatus#util#BuildGitWorkdirCommand('/workdir', {'NERDTreeGitStatusGitBinPath': '/path/to/git'})
call s:assert.equal(l:cmd, ['/path/to/git', '-C', '/workdir', 'rev-parse', '--show-toplevel'])
endfunction
function! s:suite.BuildGitStatusCommand() abort
let l:cmd = gitstatus#util#BuildGitStatusCommand('/workdir', {})
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'status', '--porcelain=v2', '-z'])
let l:cmd = gitstatus#util#BuildGitStatusCommand('/workdir', {
\ 'NERDTreeGitStatusPorcelainVersion': 1
\ })
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'status', '--porcelain', '-z'])
let l:cmd = gitstatus#util#BuildGitStatusCommand('/workdir', {
\ 'NERDTreeGitStatusUntrackedFilesMode': 'all'
\ })
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'status', '--porcelain=v2', '-z', '--untracked-files=all'])
let l:cmd = gitstatus#util#BuildGitStatusCommand('/workdir', {
\ 'NERDTreeGitStatusShowIgnored': 1
\ })
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'status', '--porcelain=v2', '-z', '--ignored=traditional'])
let l:cmd = gitstatus#util#BuildGitStatusCommand('/workdir', {
\ 'NERDTreeGitStatusShowIgnored': 0
\ })
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'status', '--porcelain=v2', '-z'])
let l:cmd = gitstatus#util#BuildGitStatusCommand('/workdir', {
\ 'NERDTreeGitStatusIgnoreSubmodules': 'dirty'
\ })
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'status', '--porcelain=v2', '-z', '--ignore-submodules=dirty'])
let l:cmd = gitstatus#util#BuildGitStatusCommand('/workdir', {
\ 'NERDTreeGitStatusPorcelainVersion': 1,
\ 'NERDTreeGitStatusUntrackedFilesMode': 'all',
\ 'NERDTreeGitStatusShowIgnored': 1,
\ 'NERDTreeGitStatusIgnoreSubmodules': 'dirty'
\ })
call s:assert.equal(l:cmd, ['git', '-C', '/workdir', 'status', '--porcelain', '-z',
\ '--untracked-files=all',
\ '--ignored=traditional',
\ '--ignore-submodules=dirty'])
endfunction
function! s:suite.Logger() abort
let l:logger = gitstatus#log#NewLogger(1) " info
let l:messages = execute('messages')
call l:logger.debug('debug')
call s:assert.equal(execute('messages'), l:messages)
call l:logger.error('error')
call s:assert.equal(execute('messages'), l:messages . "\n[nerdtree-git-status] error")
endfunction
function! s:suite.CustomIndicator() abort
let g:NERDTreeGitStatusIndicatorMapCustom = {'Untracked': '~'}
let l:staged = gitstatus#getIndicator('Staged')
call s:assert.equal(gitstatus#getIndicator('Staged'), l:staged)
call s:assert.equal(gitstatus#getIndicator('Untracked'), '~')
" Vim(return):E716: Key not present in Dictionary
Throws /E716/ gitstatus#getIndicator('no such status')
endfunction
function! s:suite.UpdateParentDirsStatus() abort
let l:opts = {'NERDTreeGitStatusDirDirtyOnly': 1}
let l:root = '/root'
let l:cache = {}
let l:pathStr = '/root/dir1/dir2/dir3'
let l:cache[l:pathStr] = 'Untracked'
call gitstatus#util#UpdateParentDirsStatus(l:cache, l:root, l:pathStr, 'Untracked', l:opts)
call s:assert.equal({'/root/dir1': 'Dirty', '/root/dir1/dir2': 'Dirty', '/root/dir1/dir2/dir3': 'Untracked'}, l:cache)
let l:pathStr = '/root/dir1/dir2/file0'
let l:cache[l:pathStr] = 'Staged'
call gitstatus#util#UpdateParentDirsStatus(l:cache, l:root, l:pathStr, 'Staged', l:opts)
call s:assert.equal({'/root/dir1': 'Dirty', '/root/dir1/dir2': 'Dirty', '/root/dir1/dir2/dir3': 'Untracked', '/root/dir1/dir2/file0': 'Staged'}, l:cache)
let l:opts = {'NERDTreeGitStatusDirDirtyOnly': 0}
let l:cache = {}
let l:pathStr = '/root/dir1/dir2/dir3'
let l:cache[l:pathStr] = 'Untracked'
call gitstatus#util#UpdateParentDirsStatus(l:cache, l:root, l:pathStr, 'Untracked', l:opts)
call s:assert.equal({'/root/dir1': 'Untracked', '/root/dir1/dir2': 'Untracked', '/root/dir1/dir2/dir3': 'Untracked'}, l:cache)
let l:cache['/root/dir1/file1'] = 'Staged'
call gitstatus#util#UpdateParentDirsStatus(l:cache, l:root, '/root/dir1/file1', 'Staged', l:opts)
call s:assert.equal({'/root/dir1': 'Dirty','/root/dir1/file1': 'Staged', '/root/dir1/dir2': 'Untracked', '/root/dir1/dir2/dir3': 'Untracked'}, l:cache)
endfunction

View File

@@ -1,46 +0,0 @@
---
name: "Bug Report"
about: "NERDTree is misbehaving? Tell us about it."
labels: bug
---
<!-- Attention! Please Read!
Please fill out ALL the information below so that the issue can be fully understood. Omitting
information will delay the resolution of your issue. It will be labeled "Needs More Info", and
may be closed until there is enough information.
Keep in mind that others may have the same question in the future. The better your information,
the more likely they'll be able to help themselves.
-->
#### Self-Diagnosis
Before creating an issue, take some time to search these resources for an answer. It's possible that someone else has already seen and solved your issue.
- [old NERDTree issues](https://github.com/preservim/nerdtree/issues?q=is%3Aissue)
- NERDTree documentation - `:h NERDTree`
- [NERDTree Wiki](https://github.com/preservim/nerdtree/wiki)
- Other resources: <https://stackoverflow.com>, <https://vi.stackexchange.com>, etc.
#### Environment
- Operating System:
- Vim/Neovim version `:version`:
- NERDTree version, found on first line of quickhelp `?`:
- Are you using any of these NERDTree-dependent plugins? <!-- Check the boxes after creating the issue. -->
- [ ] [Xuyuanp/nerdtree-git-plugin](https://github.com/Xuyuanp/nerdtree-git-plugin)
- [ ] [ryanoasis/vim-devicons](https://github.com/ryanoasis/vim-devicons)
- [ ] [tiagofumo/vim-nerdtree-syntax-highlight](https://github.com/tiagofumo/vim-nerdtree-syntax-highlight)
- [ ] [scrooloose/nerdtree-project-plugin](https://github.com/scrooloose/nerdtree-project-plugin)
- [ ] [PhilRunninger/nerdtree-buffer-ops](https://github.com/PhilRunninger/nerdtree-buffer-ops)
- [ ] [PhilRunninger/nerdtree-visual-selection](https://github.com/PhilRunninger/nerdtree-visual-selection)
- [ ] [jistr/vim-nerdtree-tabs](https://github.com/jistr/vim-nerdtree-tabs)
- [ ] Others (specify):
- Provide a minimal **.vimrc** file that will reproduce the issue.
```vim
```
#### Steps to Reproduce the Issue
1.
#### Current Behavior (Include screenshots where appropriate.)
#### Expected Result

View File

@@ -1,8 +0,0 @@
---
name: "Feature Request"
about: "What new feature are you requesting for NERDTree?"
labels: "feature request"
---
#### Description

View File

@@ -1,13 +0,0 @@
---
name: "General Question"
about: "Having trouble setting up NERDTree? Need clarification on a setting? Ask your question here."
labels: "general question"
---
Before creating an issue, take some time to search these resources. It's possible that someone else has already asked your question and gotten an answer.
- [old NERDTree issues](https://github.com/preservim/nerdtree/issues?q=is%3Aissue)
- NERDTree documentation - `:h NERDTree`
- [NERDTree Wiki](https://github.com/preservim/nerdtree/wiki)
- Other resource: <https://stackoverflow.com>, <https://vi.stackexchange.com>, etc.
#### State Your Question

View File

@@ -1,22 +0,0 @@
### Description of Changes
Closes # <!-- Enter the issue number this PR addresses. If none, remove this line. -->
---
### New Version Info
#### Author's Instructions
- [ ] Derive a new `MAJOR.MINOR.PATCH` version number. Increment the:
- `MAJOR` version when you make incompatible API changes
- `MINOR` version when you add functionality in a backwards-compatible manner
- `PATCH` version when you make backwards-compatible bug fixes
- [ ] Update [CHANGELOG.md](https://github.com/scrooloose/nerdtree/blob/master/CHANGELOG.md), following the established pattern.
#### Collaborator's Instructions
- [ ] Review [CHANGELOG.md](https://github.com/scrooloose/nerdtree/blob/master/CHANGELOG.md), suggesting a different version number if necessary.
- [ ] After merging, tag the commit using these (Mac-compatible) bash commands:
```bash
git checkout master
git pull
sed -n "$(grep -n -m2 '####' CHANGELOG.md | cut -f1 -d: | sed 'N;s/\n/,/')p" CHANGELOG.md | sed '$d'
git tag -a $(read -p "Tag Name: " tag;echo $tag) -m"$(git show --quiet --pretty=%s)";git push origin --tags
```

View File

@@ -1,15 +0,0 @@
name: Vint
on: [push, pull_request]
jobs:
vint:
strategy:
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Run vint with reviewdog
uses: reviewdog/action-vint@v1.0.1
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-review

View File

@@ -1,3 +0,0 @@
*~
*.swp
tags

View File

@@ -1,5 +0,0 @@
cmdargs:
severity: style_problem
color: true
env:
neovim: false

View File

@@ -1,307 +0,0 @@
# NERDTree Change Log
<!-- Introduce a new MAJOR or MINOR version with a 4-hash header.
PATCH versions are listed from newest to oldest under their respective MAJOR.MINOR
version in an unordered list. The format is:
- **.PATCH**: Pull Request Title (PR Author) [PR Number](Link to PR)
-->
#### 6.10
- **.16**: Fix documentation errors. (lifecrisis) [#1269](https://github.com/preservim/nerdtree/pull/1269)
- **.15**: Ensure backward compatible testing of types. (lifecrisis) [#1266](https://github.com/preservim/nerdtree/pull/1266)
- **.14**: Replace trim() with a version-compatible alternative. (PhilRunninger) [#1265](https://github.com/preservim/nerdtree/pull/1265)
- **.13**: Change highlighting of bookmarks in the tree. (PhilRunninger) [#1261](https://github.com/preservim/nerdtree/pull/1261)
- **.12**: Answer the question about accessing files over scp or ftp. (PhilRunninger) [#1259](https://github.com/preservim/nerdtree/pull/1259)
- **.11**: Trim filenames created via the fs_menu (elanorigby) [#1243](https://github.com/preservim/nerdtree/pull/1243)
- **.10**: Improve F.A.Q. Answers and Issue Templates (PhilRunninger) [#1249](https://github.com/preservim/nerdtree/pull/1249)
- **.9**: `go` on a bookmark directory will NERDTreeFind it. (PhilRunninger) [#1236](https://github.com/preservim/nerdtree/pull/1236)
- **.8**: Put `Callback` function variables in local scope. (PhilRunninger) [#1230](https://github.com/preservim/nerdtree/pull/1230)
- **.7**: Fix mouse-clicking a file to open it. (PhilRunninger) [#1225](https://github.com/preservim/nerdtree/pull/1225)
- **.6**: Restore the default behavior of the `<CR>` key. (PhilRunninger) [#1221](https://github.com/preservim/nerdtree/pull/1221)
- **.5**: Fix `{'keepopen':0}` in NERDTreeCustomOpenArgs (PhilRunninger) [#1217](https://github.com/preservim/nerdtree/pull/1217)
- **.4**: Removed directory separator from sort key (Daniel E) [#1219](https://github.com/preservim/nerdtree/pull/1219)
- **.3**: Add new FAQ and answer: How to prevent buffers replacing NERDTree. (PhilRunninger) [#1215](https://github.com/preservim/nerdtree/pull/1215)
- **.2**: New menu command: Run a system command in this directory. (PhilRunninger) [#1214](https://github.com/preservim/nerdtree/pull/1214)
- **.1**: Escape quotation marks so they can be used in key mappings. (PhilRunninger) [#1213](https://github.com/preservim/nerdtree/pull/1213)
- **.0**: Enable full path specifications for NERDTreeIgnore (PhilRunninger) [#1207](https://github.com/preservim/nerdtree/pull/1207)
#### 6.9
- **.12**: Respect NERDTreeCustomOpenArgs when opening bookmark (przepompownia) [#1200](https://github.com/preservim/nerdtree/pull/1200)
- **.11**: Revamp the README. (buncis, PhilRunninger) [#1192](https://github.com/preservim/nerdtree/pull/1192), [#1193](https://github.com/preservim/nerdtree/pull/1193)
- **.10**: Open a mirrored NERDTree with correct width (PhilRunninger) [#1177](https://github.com/preservim/nerdtree/pull/1177)
- **.9**: Updated Readme, removed typo (H3RSKO) [#1167](https://github.com/preservim/nerdtree/pull/1167)
- **.8**: Refactor sort comparison functions, removing redundancy (PhilRunninger) [#1166](https://github.com/preservim/nerdtree/pull/1166)
- **.7**: Fix argument of `exists()` function calls checking for autocommands. (PhilRunninger) [#1165](https://github.com/preservim/nerdtree/pull/1165)
- **.6**: Don't use silent when raising User events (PhilRunninger) [#1164](https://github.com/preservim/nerdtree/pull/1164)
- **.5**: Fix highlight for file node. (pirey) [#1157](https://github.com/preservim/nerdtree/pull/1157)
- **.4**: Make sure symbolic links' flags are highlighted correctly. (PhilRunninger) [#1156](https://github.com/preservim/nerdtree/pull/1156)
- **.3**: Fix new NERDTrees' width when previous one was in the only window. (PhilRunninger) [#1153](https://github.com/preservim/nerdtree/pull/1153)
- **.2**: Fix the scope of several key mappings (lifecrisis, PhilRunninger) [#1151](https://github.com/preservim/nerdtree/pull/1151)
- **.1**: Respect user's `&shellslash` setting in CopyNode and RemoveNode functions (PhilRunninger) [#1150](https://github.com/preservim/nerdtree/pull/1150)
- **.0**: Enable opening bookmarks in split windows. (PhilRunninger) [#1144](https://github.com/preservim/nerdtree/pull/1144)
#### 6.8
- **.0**: Allow concealed characters to show another character. (PhilRunninger) [#1138](https://github.com/preservim/nerdtree/pull/1138)
#### 6.7
- **.15**: Add curly braces to the list of characters to be escaped. (PhilRunninger) [#1128](https://github.com/preservim/nerdtree/pull/1128)
- **.14**: Use backward-compatible `nerdtree#and()` in one place that was missed. (PhilRunninger) [#1134](https://github.com/preservim/nerdtree/pull/1134)
- **.13**: `cmd.exe /c start "" <filename>` for windows default viewer support. (J. Altayó) [#1130](https://github.com/preservim/nerdtree/pull/1130)
- **.12**: Fixed a bug that caused the file-tree construction to slow down significantly. (Eugenij-W) [#1126](https://github.com/preservim/nerdtree/pull/1126)
- **.11**: Fix exception in NERDTreeFind (on windows OS and If the file is located in the root directory of the disk) (Eugenij-W) [#1122](https://github.com/preservim/nerdtree/pull/1122)
- **.10**: Do not consider the tree root to be "cascadable". (lifecrisis) [#1120](https://github.com/preservim/nerdtree/pull/1120)
- **.9**: Force `:NERDTreeFocus` to allow events to be fired when switching windows. (PhilRunninger) [#1118](https://github.com/preservim/nerdtree/pull/1118)
- **.8**: Fix example code for the `NERDTreeAddKeyMap()` function. (PhilRunninger) [#1116](https://github.com/preservim/nerdtree/pull/1116)
- **.7**: Put `'%'` argument in `bufname()` for backwards compatibility. (PhilRunninger) [#1105](https://github.com/preservim/nerdtree/pull/1105)
- **.6**: If a file's already open in the window, don't edit it again. (PhilRunninger) [#1103](https://github.com/preservim/nerdtree/pull/1103)
- **.5**: Prevent unneeded tree creation in `:NERDTreeToggle[VCS] <path>` (PhilRunninger) [#1101](https://github.com/preservim/nerdtree/pull/1101)
- **.4**: Add missing calls to the `shellescape()` function (lifecrisis) [#1099](https://github.com/preservim/nerdtree/pull/1099)
- **.3**: Fix vsplit to not open empty buffers when opening previously closed file (AwkwardKore) [#1098](https://github.com/preservim/nerdtree/pull/1098)
- **.2**: Fix infinity loop (on winvim) in FindParentVCSRoot (Eugenij-W) [#1095](https://github.com/preservim/nerdtree/pull/1095)
- **.1**: File Move: Escape existing directory name when looking for open files. (PhilRunninger) [#1094](https://github.com/preservim/nerdtree/pull/1094)
- **.0**: Open the parent directory when revealing a non-existent file with :NERDTreeFind (bouk) [#1090](https://github.com/preservim/nerdtree/pull/1090)
#### 6.6
- **.1**: [add] How to install using dein.vim (kazukazuinaina) [#1087](https://github.com/preservim/nerdtree/pull/1087)
- **.0**: Add the ability to turn off directory arrows (PhilRunninger) [#1085](https://github.com/preservim/nerdtree/pull/1085)
#### 6.5
- **.0**: `NERDTreeToggle <start-directory>` always sets NERDTree root. (PhilRunninger) [#1083](https://github.com/preservim/nerdtree/pull/1083)
#### 6.4
- **.6**: NERDTreeFind shows expected message if file doesn't exist e.g. with vim-startify (andys8). [#1081](https://github.com/preservim/nerdtree/pull/1081)
- **.5**: Ensure events are (or aren't) being ignored correctly. (PhilRunninger) [#1080](https://github.com/preservim/nerdtree/pull/1080)
- **.4**: Prevent overwriting existing files/dirs on node move. (PhilRunninger) [#1079](https://github.com/preservim/nerdtree/pull/1079)
- **.3**: Fix regex that finds keyword for minimal menu. (PhilRunninger) [#1075](https://github.com/preservim/nerdtree/pull/1075)
- **.2**: Lint vimscript, fix errors and warnings, add CI job to review PRs (Caleb Maclennan) [#1071](https://github.com/preservim/nerdtree/pull/1071)
- **.1**: Ensure backward compatibility. v:t_func is not available before Vim 8.0 (Phil Runninger)
- **.0**: Allow use of function references as callbacks (HiPhish) [#1067](https://github.com/preservim/nerdtree/pull/1067)
#### 6.3
- **.0**: Add new command that behaves like NERDTreeToggle but defaults to the root of a VCS repository. (willfindlay) [#1060](https://github.com/preservim/nerdtree/pull/1060)
#### 6.2
- **.1**: Menu option, 'copy path to clipboard' is aware of VIM clipboard option (jhzn) [#1056](https://github.com/preservim/nerdtree/pull/1056)
- **.0**: Support tab-specific CWDs (PhilRunninger) [#1032](https://github.com/preservim/nerdtree/pull/1032)
#### 6.1
- **.4**: Add VIM built-in package management to read me file. (pesarkhobeee) [#1049](https://github.com/preservim/nerdtree/pull/1049)
- **.3**: Save/Set screen state also on WinLeave and WinEnter. (PhilRunninger) [#1048](https://github.com/preservim/nerdtree/pull/1048)
- **.2**: Wrap saveScreenState's statements in a try-catch block. (PhilRunninger) [#1047](https://github.com/preservim/nerdtree/pull/1047)
- **.1**: Catch errors when trying to read CHANGELOG.md. (PhilRunninger) [#1045](https://github.com/preservim/nerdtree/pull/1045)
- **.0**: If file path doesn't exist, :NERDTreeFind its parent directory instead. (PhilRunninger) [#1043](https://github.com/preservim/nerdtree/pull/1043)
#### 6.0
- **.1**: Reintroduce necessary variable mistakenly removed. (PhilRunninger) [#1040](https://github.com/preservim/nerdtree/pull/1040)
- **.0**: Make the behavior of window splits consistent (dragonxlwang, PhilRunninger) [#1035](https://github.com/preservim/nerdtree/pull/1035)
#### 5.3
- **.3**: Fix (p)ath not displaying in the minimal menu (tuzz) [#1038](https://github.com/preservim/nerdtree/pull/1038)
- **.2**: Enable events when closing NerdTree window. (PhilRunninger) [#1037](https://github.com/preservim/nerdtree/pull/1037)
- **.1**: Fix the `e` key mapping to use netrw if desired (PhilRunninger) [#1031](https://github.com/preservim/nerdtree/pull/1031)
- **.0**: Add file extension and size to sorting capabilities (PhilRunninger) [#1029](https://github.com/preservim/nerdtree/pull/1029)
#### 5.2
- **.9**: Suppress events for intermediate window/tab/buffer changes (PhilRunninger) [#1026](https://github.com/preservim/nerdtree/pull/1026)
- **.8**: Revert [#1019](https://github.com/preservim/nerdtree/pull/1019) to fix nvim artifacts and flickering. (PhilRunninger) [#1021](https://github.com/preservim/nerdtree/pull/1021)
- **.7**: Use :mode only in neovim. MacVim still needs to use :redraw! (PhilRunninger) [#1019](https://github.com/preservim/nerdtree/pull/1019)
- **.6**: In CHANGELOG.md and PR template, make reference to PR a true HTML link. (PhilRunninger) [#1017](https://github.com/preservim/nerdtree/pull/1017)
- **.5**: Use `:mode` instead of `:redraw!` when updating menu. (PhilRunninger) [#1016](https://github.com/preservim/nerdtree/pull/1016)
- **.4**: When searching for root line num, stop at end of file. (PhilRunninger) [#1015](https://github.com/preservim/nerdtree/pull/1015)
- **.3**: Fix `<CR>` key map on the bookmark (lkebin) [#1014](https://github.com/preservim/nerdtree/pull/1014)
- **.2**: Make Enter work on the `.. ( up a dir )` line (PhilRunninger) [#1013](https://github.com/preservim/nerdtree/pull/1013)
- **.1**: Fix nerdtree#version() on Windows. (PhilRunninger)
- **.0**: Expand functionality of `<CR>` mapping. (PhilRunninger) [#1011](https://github.com/preservim/nerdtree/pull/1011)
#### 5.1
- **.3**: Remove @mentions from PR template and change log. They weren't working. (PhilRunninger) [#1009](https://github.com/preservim/nerdtree/pull/1009)
- **.2**: Fix NERDTree opening with the wrong size. (PhilRunninger) [#1008](https://github.com/preservim/nerdtree/pull/1008)
- **.1**: Update Changelog and create PR Template (PhilRunninger) [#1007](https://github.com/preservim/nerdtree/pull/1007)
- **.0**: Too many changes for one patch...
- Refresh a dir_node if the file wasn't found in it, and look once more. (PhilRunninger) [#1005](https://github.com/preservim/nerdtree/pull/1005)
- Add a "copy path to clipboard" menu option (PhilRunninger) [#1002](https://github.com/preservim/nerdtree/pull/1002)
- Enable root refresh on "vim ." a different way than [#999](https://github.com/preservim/nerdtree/pull/999). (PhilRunninger) [#1001](https://github.com/preservim/nerdtree/pull/1001)
- Fix refreshroot (PhilRunninger) [#999](https://github.com/preservim/nerdtree/pull/999)
- Change version check to look for 703 not 730 (vhalis) [#994](https://github.com/preservim/nerdtree/pull/994)
- Change minimum vim (PhilRunninger) [#991](https://github.com/preservim/nerdtree/pull/991)
- Allow multi-character DirArrows (PhilRunninger) [#985](https://github.com/preservim/nerdtree/pull/985)
- Remove redraw! while still clearing last message empty string. (PhilRunninger) [#979](https://github.com/preservim/nerdtree/pull/979)
- fix `_initChildren` function value set to numChildrenCached error (terryding77) [#969](https://github.com/preservim/nerdtree/pull/969)
- On Windows, do a case-insensitive comparison of paths. (PhilRunninger) [#967](https://github.com/preservim/nerdtree/pull/967)
- Remove the **Please wait... DONE** messages. (PhilRunninger) [#966](https://github.com/preservim/nerdtree/pull/966)
- Smarter delimiter default (PhilRunninger) [#963](https://github.com/preservim/nerdtree/pull/963)
- Update directory .vimdc readme example (spencerdcarlson) [#961](https://github.com/preservim/nerdtree/pull/961)
- Preview bookmarks (PhilRunninger) [#956](https://github.com/preservim/nerdtree/pull/956)
- Add new value to NERDTreeQuitOnOpen to close bookmark table (PhilRunninger) [#955](https://github.com/preservim/nerdtree/pull/955)
- Add an :EditBookmarks command to edit the bookmarks file (PhilRunninger) [#954](https://github.com/preservim/nerdtree/pull/954)
- Before copying, turn off &shellslash. Restore after copy is finished. (PhilRunninger) [#952](https://github.com/preservim/nerdtree/pull/952)
- Set a maximum window size when zooming. (PhilRunninger) [#950](https://github.com/preservim/nerdtree/pull/950)
- Confirm the wipeout of a unsaved buffer whose file has been renamed. (PhilRunninger) [#949](https://github.com/preservim/nerdtree/pull/949)
- Escape a backslash so it can be used in a key mapping. (PhilRunninger) [#948](https://github.com/preservim/nerdtree/pull/948)
- Add a NERDTreeMinimalMenu feature (tuzz) [#938](https://github.com/preservim/nerdtree/pull/938)
- fixed root path error for windows (zcodes) [#935](https://github.com/preservim/nerdtree/pull/935)
- Restore getDirChildren for use in nerdtree-project-plugin. (PhilRunninger) [#929](https://github.com/preservim/nerdtree/pull/929)
- Document NERDTreeNodeDelimiter [#912](https://github.com/preservim/nerdtree/pull/912) (PhilRunninger) [#926](https://github.com/preservim/nerdtree/pull/926)
- Allow modification of menu keybindings (Leandros) [#923](https://github.com/preservim/nerdtree/pull/923)
- Add two more disqualifications for isCascadable(). (PhilRunninger) [#914](https://github.com/preservim/nerdtree/pull/914)
- Allow highlighting more than one flag. (kristijanhusak) [#908](https://github.com/preservim/nerdtree/pull/908)
- Support sorting files and directories by modification time. (PhilRunninger) [#901](https://github.com/preservim/nerdtree/pull/901)
- Parse . and .. from path string with trailing slash. (PhilRunninger) [#899](https://github.com/preservim/nerdtree/pull/899)
- Force sort to recalculate the cached sortKey. (PhilRunninger) [#898](https://github.com/preservim/nerdtree/pull/898)
- Add NERDTreeRefreshRoot command (wgfm) [#897](https://github.com/preservim/nerdtree/pull/897)
- Call Resolve on the file's path when calling :NERDTreeFind. (PhilRunninger) [#896](https://github.com/preservim/nerdtree/pull/896)
- Catch all errors, not just NERDTree errors. (PhilRunninger) [#894](https://github.com/preservim/nerdtree/pull/894)
- Fix typo in help file (lvoisin) [#892](https://github.com/preservim/nerdtree/pull/892)
- Make NERDTreeCreator set the `'nolist'` option (lifecrisis) [#889](https://github.com/preservim/nerdtree/pull/889)
- Refresh buffers after `m`, `m` operation on a folder (PhilRunninger) [#888](https://github.com/preservim/nerdtree/pull/888)
- Use a better arg for FINDSTR when using the m,l command in Windows. (PhilRunninger) [#887](https://github.com/preservim/nerdtree/pull/887)
- Fix the <C-J>/<C-K> motions, which currently fail with cascades (lifecrisis) [#886](https://github.com/preservim/nerdtree/pull/886)
- Function "s:UI.getLineNum()" doesn't always work on cascades. (lifecrisis) [#882](https://github.com/preservim/nerdtree/pull/882)
- NERDTreeCWD: reset CWD if changed by NERDTreeFocus (PhilRunninger) [#878](https://github.com/preservim/nerdtree/pull/878)
- Use <count>tabnext instead of <count>gt to allow users to remap gt. (PhilRunninger) [#877](https://github.com/preservim/nerdtree/pull/877)
- Do a case sensitive comparison of new/existing buffers. (PhilRunninger) [#875](https://github.com/preservim/nerdtree/pull/875)
- Fix opening sub-directories that have commas in their name. (PhilRunninger) [#873](https://github.com/preservim/nerdtree/pull/873)
- Add new command to open NERDTree in the root of a VCS repository. (PhilRunninger) [#872](https://github.com/preservim/nerdtree/pull/872)
- Make sure the path to the bookmarks file exists before writing it. (PhilRunninger) [#871](https://github.com/preservim/nerdtree/pull/871)
- Unzoom NERDTree when opening a file (PhilRunninger) [#870](https://github.com/preservim/nerdtree/pull/870)
- Support unusual characters in file and directory names (PhilRunninger) [#868](https://github.com/preservim/nerdtree/pull/868)
- Reword renamed-buffer prompt to be more clear (aflock) [#867](https://github.com/preservim/nerdtree/pull/867)
- Default to placing cursor on root when closing bookmark table (lifecrisis) [#866](https://github.com/preservim/nerdtree/pull/866)
- Fix issues with sorting of nodes (PhilRunninger) [#856](https://github.com/preservim/nerdtree/pull/856)
- Better OSX detection (bubba-h57) [#853](https://github.com/preservim/nerdtree/pull/853)
- Bugfix - ensure keymaps dictionary exists before using it (mnussbaum) [#852](https://github.com/preservim/nerdtree/pull/852)
- Decrease startup-time by avoiding linear-time iteration over key mappings (mnussbaum) [#851](https://github.com/preservim/nerdtree/pull/851)
- Add code to sort mappings in quickhelp (lifecrisis) [#849](https://github.com/preservim/nerdtree/pull/849)
- Use ":clearjumps" in new NERDTree windows (lifecrisis) [#844](https://github.com/preservim/nerdtree/pull/844)
- Like m-c did before, create parent directories if needed on m-m. (PhilRunninger) [#840](https://github.com/preservim/nerdtree/pull/840)
- BUGFIX: Repair a problem with the `'u'` mapping. (lifecrisis) [#838](https://github.com/preservim/nerdtree/pull/838)
- Make the NERDTree buffer writable when rendering it. (PhilRunninger) [#837](https://github.com/preservim/nerdtree/pull/837)
- Code cleanup: Remove unsupported bookmark table mappings (lifecrisis) [#835](https://github.com/preservim/nerdtree/pull/835)
- Replace strcharpart() with substitute() for backward compatibility (bravestarr) [#834](https://github.com/preservim/nerdtree/pull/834)
- Fixed error `unknown function strcharpart` for older versions of Vim (hav4ik) [#833](https://github.com/preservim/nerdtree/pull/833)
- Clear output when NERDTree menu is aborted (lifecrisis) [#832](https://github.com/preservim/nerdtree/pull/832)
- Display a path with multi-byte characters correctly when it is truncated (bravestarr) [#830](https://github.com/preservim/nerdtree/pull/830)
- Support revealing file and executing file with xdg-open for Linux (ngnmhieu) [#824](https://github.com/preservim/nerdtree/pull/824)
- If node isn't open, count children on disk before deleting. (PhilRunninger) [#822](https://github.com/preservim/nerdtree/pull/822)
- Add new variable g:NERDTreeRemoveFileCmd (kutsan) [#816](https://github.com/preservim/nerdtree/pull/816)
- Use a better check for existence of the NERDTree buffer. (PhilRunninger) [#814](https://github.com/preservim/nerdtree/pull/814)
- Fix focussing previous buffer when closing NERDTree (mrubli) [#801](https://github.com/preservim/nerdtree/pull/801)
- Update the docs for "NERDTreeStatusline" (lifecrisis) [#796](https://github.com/preservim/nerdtree/pull/796)
- BUGFIX: Unstable behavior in the "getPath()" method (lifecrisis) [#795](https://github.com/preservim/nerdtree/pull/795)
- Revert the bugfix from pull request [#785](https://github.com/preservim/nerdtree/pull/785) (lifecrisis) [#794](https://github.com/preservim/nerdtree/pull/794)
- BUGFIX: Allow ":NERDTreeFind" to discover hidden files (lifecrisis) [#786](https://github.com/preservim/nerdtree/pull/786)
- BUGFIX: Allow ":NERDTreeFind" to reveal new files (lifecrisis) [#785](https://github.com/preservim/nerdtree/pull/785)
- Add modelines (lifecrisis) [#782](https://github.com/preservim/nerdtree/pull/782)
- Change the type of completion used by NERDTreeFind (lifecrisis) [#781](https://github.com/preservim/nerdtree/pull/781)
- change NERDTreeFind with args (zhenyangze) [#778](https://github.com/preservim/nerdtree/pull/778)
- Style Choice: Using confirm() when deleting a bookmark (lifecrisis) [#777](https://github.com/preservim/nerdtree/pull/777)
- remove useless substitute when `file =~# "/$"` (skyblueee) [#773](https://github.com/preservim/nerdtree/pull/773)
- remove useless removeLeadingSpaces in _stripMarkup (skyblueee) [#772](https://github.com/preservim/nerdtree/pull/772)
- Make the "o" mapping consistent with "x" (lifecrisis) [#769](https://github.com/preservim/nerdtree/pull/769)
- Fix a problem with the "x" handler (lifecrisis) [#768](https://github.com/preservim/nerdtree/pull/768)
- Clean up the handler for the "x" mapping (lifecrisis) [#767](https://github.com/preservim/nerdtree/pull/767)
- Revert change to tab opening method (lifecrisis) [#766](https://github.com/preservim/nerdtree/pull/766)
- BUGFIX: Add back support for "b:NERDTreeRoot" (lifecrisis) [#765](https://github.com/preservim/nerdtree/pull/765)
- Fix broken "t" and "T" mappings, tabs now open at end (lifecrisis) [#759](https://github.com/preservim/nerdtree/pull/759)
- Update doc with already existing mapping variables (asnr) [#699](https://github.com/preservim/nerdtree/pull/699)
- Fix the broken g:NERDTreeBookmarksSort setting (lifecrisis) [#696](https://github.com/preservim/nerdtree/pull/696)
- Correct NERDTreeIgnore pattern in doc (cntoplolicon) [#648](https://github.com/preservim/nerdtree/pull/648)
- Remove empty segments when splitting path (sooth-sayer) [#574](https://github.com/preservim/nerdtree/pull/574)
- Suppress autocmds less agressively (wincent) [#578](https://github.com/preservim/nerdtree/pull/578) [#691](https://github.com/preservim/nerdtree/pull/691)
- Add an Issues template to ask for more info initially.
- Fix markdown headers in readme (josephfrazier) [#676](https://github.com/preservim/nerdtree/pull/676)
- Don't touch `@o` and `@h` registers when rendering
- Fix bug with files and directories with dollar signs (alegen) [#649](https://github.com/preservim/nerdtree/pull/649)
- Reuse/reopen existing window trees where possible [#244](https://github.com/preservim/nerdtree/pull/244)
- Remove NERDTree.previousBuf()
- Change color of arrow (Leeiio) [#630](https://github.com/preservim/nerdtree/pull/630)
- Improved a tip in README.markdown (ggicci) [#628](https://github.com/preservim/nerdtree/pull/628)
- Shorten delete confimration of empty directory to `y` (mikeperri) [#530](https://github.com/preservim/nerdtree/pull/530)
- Fix API call to open directory tree in window (devm33) [#533](https://github.com/preservim/nerdtree/pull/533)
- Change default arrows on non-Windows platforms (gwilk) [#546](https://github.com/preservim/nerdtree/pull/546)
- Update to README - combine cd and git clone (zwhitchcox) [#584](https://github.com/preservim/nerdtree/pull/584)
- Update to README - Tip: start NERDTree when vim starts (therealplato) [#593](https://github.com/preservim/nerdtree/pull/593)
- Escape filename when moving an open buffer (zacharyvoase) [#595](https://github.com/preservim/nerdtree/pull/595)
- Fixed incorrect :helptags command in README (curran) [#619](https://github.com/preservim/nerdtree/pull/619)
- Fixed incomplete escaping of folder arrows (adityanatraj) [#548](https://github.com/preservim/nerdtree/pull/548)
- Added NERDTreeCascadeSingleChildDir option (juanibiapina) [#558](https://github.com/preservim/nerdtree/pull/558)
- Replace strchars() with backward compatible workaround.
- Add support for copy command in Windows (SkylerLipthay) [#231](https://github.com/preservim/nerdtree/pull/231)
- Fixed typo in README.markdown - :Helptags -> :helptags
- Rename "primary" and "secondary" trees to "tab" and "window" trees.
- Move a bunch of buffer level variables into the NERDTree and UI classes.
- Display cascading dirs on one line to save vertical/horizontal space (matt-gardner: brainstorming/testing)
- Remove the old style UI - Remove `NERDTreeDirArrows` option.
- On windows default to + and ~ for expand/collapse directory symbols.
- Lots more refactoring. Move a bunch of b: level vars into b:NERDTree and friends.
#### 5.0.0
- Refactor the code significantly:
* Break the classes out into their own files.
* Make the majority of the code OO - previously large parts were effectively a tangle of "global" methods.
- Add an API to assign flags to nodes. This allows VCS plugins like https://github.com/Xuyuanp/nerdtree-git-plugin to exist. Thanks to **Xuyuanp** for helping design/test/build said API.
- add `scope` argument to the key map API see :help NERDTreeAddKeyMap()
- add magic [[dir]] and [[file]] flags to NERDTreeIgnore
- add support for custom path filters. See :help NERDTreeAddPathFilter()
- add path listener API. See :help NERDTreePathListenerAPI.
- expand the fs menu functionality to list file properties (PhilRunninger, apbarrero, JESii)
- make bookmarks work with `~` home shortcuts (hiberabyss)
- show OSX specific fsmenu options in regular vim on mac (evindor)
- make dir arrow icons configurable (PickRelated)
- optimise node sorting performance when opening large dirs (vtsang)
- make the root note render prettier by truncating it at a path slash (gcmt)
- remove NERDChristmasTree option - its always christmas now
- add "cascade" open and closing for dirs containing only another single dir. See :help NERDTreeCascadeOpenSingleChildDir (pendulm)
- Many other fixes, doc updates and contributions from: **actionshrimp**, **agrussellknives**, **alvan**, **AndrewRadev**, **cperl82** (*many small fixes*), **devmanhinton**, **egalpin**, **franksort**, **gastropoda**, **handcraftedbits**, **kelaban**, **lucascaton**, **mixvin**, **pendulm**, **SchDen**, **shanesmith**, **staeff**, **stephenprater**, **toiffel**, **Twinside**, **WoLpH**, **xiaodili**, **zhangoose**
#### 4.2.0
- Add NERDTreeDirArrows option to make the UI use pretty arrow chars instead of the old +~| chars to define the tree structure (sickill)
- shift the syntax highlighting out into its own syntax file (gnap)
- add some mac specific options to the filesystem menu - for macvim only (andersonfreitas)
- Add NERDTreeMinimalUI option to remove some non functional parts of the nerdtree ui (camthompson)
- tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the new behaviour (benjamingeiger)
- if no name is given to :Bookmark, make it default to the name of the target file/dir (minyoung)
- use `file` completion when doing copying, create, and move operations (EvanDotPro)
- lots of misc bug fixes from: **AndrewRadev**, **Bogdanov**, **camthompson**, **kml**, **mathias**, **paddyoloughlin**, **scottstvnsn**, **sdewald**, **Vitaly**, **wycats**, me RAWR!
#### 4.1.0
- features:
- NERDTreeFind to reveal the node for the current buffer in the tree, see `|NERDTreeFind|`. This effectively merges the FindInNERDTree plugin (by **Doug McInnes**) into the script.
- make NERDTreeQuitOnOpen apply to the t/T keymaps too. Thanks to **Stefan Ritter** and **Rémi Prévost**.
- truncate the root node if wider than the tree window. Thanks to **Victor Gonzalez**.
- bugfixes:
- really fix window state restoring
- fix some win32 path escaping issues. Thanks to **Stephan Baumeister**, **Ricky**, **jfilip1024**, and **Chris Chambers**.
#### 4.0.0
- add a new programmable menu system (see `:help NERDTreeMenu`).
- add new APIs to add menus/menu-items to the menu system as well as custom key mappings to the NERD tree buffer (see `:help NERDTreeAPI`).
- removed the old API functions
- added a mapping to maximize/restore the size of nerd tree window, thanks to Guillaume Duranceau for the patch. See :help NERDTree-A for details.
- fix a bug where secondary nerd trees (netrw hijacked trees) and NERDTreeQuitOnOpen didnt play nicely, thanks to **Curtis Harvey**.
- fix a bug where the script ignored directories whose name ended in a dot, thanks to **Aggelos Orfanakos** for the patch.
- fix a bug when using the x mapping on the tree root, thanks to **Bryan Venteicher** for the patch.
- fix a bug where the cursor position/window size of the nerd tree buffer wasnt being stored on closing the window, thanks to **Richard Hart**.
- fix a bug where NERDTreeMirror would mirror the wrong tree
#### 3.1.1
- fix a bug where a non-listed no-name buffer was getting created every time the tree windows was created, thanks to **Derek Wyatt** and **owen1**
- make `<CR>` behave the same as the `o` mapping
- some helptag fixes in the doc, thanks **strull**.
- fix a bug when using `:set nohidden` and opening a file where the previous buf was modified. Thanks **iElectric**.
- other minor fixes
#### 3.1.0
- New features:
- add mappings to open files in a vsplit, see `:help NERDTree-s` and `:help NERDTree-gs`
- make the statusline for the nerd tree window default to something hopefully more useful. See `:help 'NERDTreeStatusline'`
- Bugfixes:
- make the hijack netrw functionality work when vim is started with `vim <some dir>` (thanks to **Alf Mikula** for the patch).
- fix a bug where the CWD wasnt being changed for some operations even when NERDTreeChDirMode==2 (thanks to **Lucas S. Buchala**)
- add -bar to all the nerd tree :commands so they can chain with other :commands (thanks to **tpope**)
- fix bugs when ignorecase was set (thanks to **nach**)
- fix a bug with the relative path code (thanks to **nach**)
- fix a bug where doing a `:cd` would cause `:NERDTreeToggle` to fail (thanks **nach**)
#### 3.0.1
- Bugfixes:
- fix bugs with :NERDTreeToggle and :NERDTreeMirror when `'hidden'` was not set
- fix a bug where `:NERDTree <path>` would fail if `<path>` was relative and didnt start with a `./` or `../` Thanks to **James Kanze**.
- make the `q` mapping work with secondary (`:e <dir>` style) trees, thanks to **jamessan**
- fix a bunch of small bugs with secondary trees
- More insane refactoring.
#### 3.0.0
- hijack netrw so that doing an `:edit <directory>` will put a NERD tree in the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw'
- allow sharing of trees across tabs, see `:help :NERDTreeMirror`
- remove "top" and "bottom" as valid settings for NERDTreeWinPos
- change the `'<tab>'` mapping to `'i'`
- change the `'H'` mapping to `'I'`
- lots of refactoring

View File

@@ -1,13 +0,0 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@@ -1,227 +0,0 @@
![Help Wanted](http://blog.ncce.org/wp-content/uploads/2013/12/help-wanted.jpg)
**NERDTree** is on the lookout for a new maintainer. See [issue #1280](https://github.com/preservim/nerdtree/issues/1280) to submit your name for consideration.
---
# The NERDTree [![Vint](https://github.com/preservim/nerdtree/workflows/Vint/badge.svg)](https://github.com/preservim/nerdtree/actions?workflow=Vint)
## Introduction
The NERDTree is a file system explorer for the Vim editor. Using this plugin, users can visually browse complex directory hierarchies, quickly open files for reading or editing, and perform basic file system operations.
![NERDTree Screenshot](https://github.com/preservim/nerdtree/raw/master/screenshot.png)
## Installation
Use your favorite plugin manager to install this plugin. [tpope/vim-pathogen](https://github.com/tpope/vim-pathogen), [VundleVim/Vundle.vim](https://github.com/VundleVim/Vundle.vim), [junegunn/vim-plug](https://github.com/junegunn/vim-plug), and [Shougo/dein.vim](https://github.com/Shougo/dein.vim) are some of the more popular ones. A lengthy discussion of these and other managers can be found on [vi.stackexchange.com](https://vi.stackexchange.com/questions/388/what-is-the-difference-between-the-vim-plugin-managers). Basic instructions are provided below, but please **be sure to read, understand, and follow all the safety rules that come with your ~~power tools~~ plugin manager.**
If you have no favorite, or want to manage your plugins without 3rd-party dependencies, consider using Vim 8+ packages, as described in Greg Hurrell's excellent Youtube video: [Vim screencast #75: Plugin managers](https://www.youtube.com/watch?v=X2_R3uxDN6g).
<details>
<summary>Pathogen</summary>
Pathogen is more of a runtime path manager than a plugin manager. You must clone the plugins' repositories yourself to a specific location, and Pathogen makes sure they are available in Vim.
1. In the terminal,
```bash
git clone https://github.com/preservim/nerdtree.git ~/.vim/bundle/nerdtree
```
1. In your `vimrc`,
```vim
call pathogen#infect()
syntax on
filetype plugin indent on
```
1. Restart Vim, and run `:helptags ~/.vim/bundle/nerdtree/doc/` or `:Helptags`.
</details>
<details>
<summary>Vundle</summary>
1. Install Vundle, according to its instructions.
1. Add the following text to your `vimrc`.
```vim
call vundle#begin()
Plugin 'preservim/nerdtree'
call vundle#end()
```
1. Restart Vim, and run the `:PluginInstall` statement to install your plugins.
</details>
<details>
<summary>Vim-Plug</summary>
1. Install Vim-Plug, according to its instructions.
1. Add the following text to your `vimrc`.
```vim
call plug#begin()
Plug 'preservim/nerdtree'
call plug#end()
```
1. Restart Vim, and run the `:PlugInstall` statement to install your plugins.
</details>
<details>
<summary>Dein</summary>
1. Install Dein, according to its instructions.
1. Add the following text to your `vimrc`.
```vim
call dein#begin()
call dein#add('preservim/nerdtree')
call dein#end()
```
1. Restart Vim, and run the `:call dein#install()` statement to install your plugins.
</details>
<details>
<summary>Vim 8+ packages</summary>
If you are using Vim version 8 or higher you can use its built-in package management; see `:help packages` for more information. Just run these commands in your terminal:
```bash
git clone https://github.com/preservim/nerdtree.git ~/.vim/pack/vendor/start/nerdtree
vim -u NONE -c "helptags ~/.vim/pack/vendor/start/nerdtree/doc" -c q
```
</details>
## Getting Started
After installing NERDTree, the best way to learn it is to turn on the Quick Help. Open NERDTree with the `:NERDTree` command, and press `?` to turn on the Quick Help, which will show you all the mappings and commands available in the NERDTree. Of course, your most complete source of information is the documentation: `:help NERDTree`.
## NERDTree Plugins
NERDTree can be extended with custom mappings and functions using its built-in API. The details of this API are described in the included documentation. Several plugins have been written, and are available on Github for installation like any other plugin. The plugins in this list are maintained (or not) by their respective owners, and certain combinations may be incompatible.
* [Xuyuanp/nerdtree-git-plugin](https://github.com/Xuyuanp/nerdtree-git-plugin): Shows Git status flags for files and folders in NERDTree.
* [ryanoasis/vim-devicons](https://github.com/ryanoasis/vim-devicons): Adds filetype-specific icons to NERDTree files and folders,
* [tiagofumo/vim-nerdtree-syntax-highlight](https://github.com/tiagofumo/vim-nerdtree-syntax-highlight): Adds syntax highlighting to NERDTree based on filetype.
* [scrooloose/nerdtree-project-plugin](https://github.com/scrooloose/nerdtree-project-plugin): Saves and restores the state of the NERDTree between sessions.
* [PhilRunninger/nerdtree-buffer-ops](https://github.com/PhilRunninger/nerdtree-buffer-ops): 1) Highlights open files in a different color. 2) Closes a buffer directly from NERDTree.
* [PhilRunninger/nerdtree-visual-selection](https://github.com/PhilRunninger/nerdtree-visual-selection): Enables NERDTree to open, delete, move, or copy multiple Visually-selected files at once.
If any others should be listed, mention them in an issue or pull request.
## Frequently Asked Questions
In the answers to these questions, you will see code blocks that you can put in your `vimrc` file.
### How can I map a specific key or shortcut to open NERDTree?
NERDTree doesn't create any shortcuts outside of the NERDTree window, so as not to overwrite any of your other shortcuts. Use the `nnoremap` command in your `vimrc`. You, of course, have many keys and NERDTree commands to choose from. Here are but a few examples.
```vim
nnoremap <leader>n :NERDTreeFocus<CR>
nnoremap <C-n> :NERDTree<CR>
nnoremap <C-t> :NERDTreeToggle<CR>
nnoremap <C-f> :NERDTreeFind<CR>
```
### How do I open NERDTree automatically when Vim starts?
Each code block below is slightly different, as described in the `" Comment lines`.
```vim
" Start NERDTree and leave the cursor in it.
autocmd VimEnter * NERDTree
```
---
```vim
" Start NERDTree and put the cursor back in the other window.
autocmd VimEnter * NERDTree | wincmd p
```
---
```vim
" Start NERDTree when Vim is started without file arguments.
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 0 && !exists('s:std_in') | NERDTree | endif
```
---
```vim
" Start NERDTree. If a file is specified, move the cursor to its window.
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * NERDTree | if argc() > 0 || exists("s:std_in") | wincmd p | endif
```
---
```vim
" Start NERDTree, unless a file or session is specified, eg. vim -S session_file.vim.
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 0 && !exists('s:std_in') && v:this_session == '' | NERDTree | endif
```
---
```vim
" Start NERDTree when Vim starts with a directory argument.
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') |
\ execute 'NERDTree' argv()[0] | wincmd p | enew | execute 'cd '.argv()[0] | endif
```
### How can I close Vim or a tab automatically when NERDTree is the last window?
```vim
" Exit Vim if NERDTree is the only window remaining in the only tab.
autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif
```
---
```vim
" Close the tab if NERDTree is the only window remaining in it.
autocmd BufEnter * if winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif
```
### How can I prevent other buffers replacing NERDTree in its window?
```vim
" If another buffer tries to replace NERDTree, put it in the other window, and bring back NERDTree.
autocmd BufEnter * if bufname('#') =~ 'NERD_tree_\d\+' && bufname('%') !~ 'NERD_tree_\d\+' && winnr('$') > 1 |
\ let buf=bufnr() | buffer# | execute "normal! \<C-W>w" | execute 'buffer'.buf | endif
```
### Can I have the same NERDTree on every tab automatically?
```vim
" Open the existing NERDTree on each new tab.
autocmd BufWinEnter * if getcmdwintype() == '' | silent NERDTreeMirror | endif
```
or change your NERDTree-launching shortcut key like so:
```vim
" Mirror the NERDTree before showing it. This makes it the same on all tabs.
nnoremap <C-n> :NERDTreeMirror<CR>:NERDTreeFocus<CR>
```
### How can I change the default arrows?
```vim
let g:NERDTreeDirArrowExpandable = '?'
let g:NERDTreeDirArrowCollapsible = '?'
```
The preceding values are the non-Windows default arrow symbols. Setting these variables to empty strings will remove the arrows completely and shift the entire tree two character positions to the left. See `:h NERDTreeDirArrowExpandable` for more details.
### Can NERDTree access remote files via scp or ftp?
Short answer: No, and there are no plans to add that functionality. However, Vim ships with a plugin that does just that. It's called netrw, and by adding the following lines to your `.vimrc`, you can use it to open files over the `scp:`, `ftp:`, or other protocols, while still using NERDTree for all local files. The function seamlessly makes the decision to open NERDTree or netrw, and other supported protocols can be added to the regular expression.
```vim
" Function to open the file or NERDTree or netrw.
" Returns: 1 if either file explorer was opened; otherwise, 0.
function! s:OpenFileOrExplorer(...)
if a:0 == 0 || a:1 == ''
NERDTree
elseif filereadable(a:1)
execute 'edit '.a:1
return 0
elseif a:1 =~? '^\(scp\|ftp\)://' " Add other protocols as needed.
execute 'Vexplore '.a:1
elseif isdirectory(a:1)
execute 'NERDTree '.a:1
endif
return 1
endfunction
" Auto commands to handle OS commandline arguments
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc()==1 && !exists('s:std_in') | if <SID>OpenFileOrExplorer(argv()[0]) | wincmd p | enew | wincmd p | endif | endif
" Command to call the OpenFileOrExplorer function.
command! -n=? -complete=file -bar Edit :call <SID>OpenFileOrExplorer('<args>')
" Command-mode abbreviation to replace the :edit Vim command.
cnoreabbrev e Edit
```

View File

@@ -1 +0,0 @@
theme: jekyll-theme-cayman

View File

@@ -1,249 +0,0 @@
if exists('g:loaded_nerdtree_autoload')
finish
endif
let g:loaded_nerdtree_autoload = 1
let s:rootNERDTreePath = resolve(expand('<sfile>:p:h:h'))
"FUNCTION: nerdtree#version(...) {{{1
" If any value is given as an argument, the entire line of text from the
" change log is shown for the current version; otherwise, only the version
" number is shown.
function! nerdtree#version(...) abort
let l:text = 'Unknown'
try
let l:changelog = readfile(join([s:rootNERDTreePath, 'CHANGELOG.md'], nerdtree#slash()))
let l:line = 0
while l:line <= len(l:changelog)
if l:changelog[l:line] =~# '\d\+\.\d\+'
let l:text = substitute(l:changelog[l:line], '.*\(\d\+.\d\+\).*', '\1', '')
let l:text .= substitute(l:changelog[l:line+1], '^.\{-}\(\.\d\+\).\{-}:\(.*\)', a:0>0 ? '\1:\2' : '\1', '')
break
endif
let l:line += 1
endwhile
catch
endtry
return l:text
endfunction
" SECTION: General Functions {{{1
"============================================================
" FUNCTION: nerdtree#closeTreeOnOpen() {{{2
function! nerdtree#closeTreeOnOpen() abort
return g:NERDTreeQuitOnOpen == 1 || g:NERDTreeQuitOnOpen == 3
endfunction
" FUNCTION: nerdtree#closeBookmarksOnOpen() {{{2
function! nerdtree#closeBookmarksOnOpen() abort
return g:NERDTreeQuitOnOpen == 2 || g:NERDTreeQuitOnOpen == 3
endfunction
" FUNCTION: nerdtree#slash() {{{2
" Return the path separator used by the underlying file system. Special
" consideration is taken for the use of the 'shellslash' option on Windows
" systems.
function! nerdtree#slash() abort
if nerdtree#runningWindows()
if exists('+shellslash') && &shellslash
return '/'
endif
return '\'
endif
return '/'
endfunction
"FUNCTION: nerdtree#checkForBrowse(dir) {{{2
"inits a window tree in the current buffer if appropriate
function! nerdtree#checkForBrowse(dir) abort
if !isdirectory(a:dir)
return
endif
if s:reuseWin(a:dir)
return
endif
call g:NERDTreeCreator.CreateWindowTree(a:dir)
endfunction
"FUNCTION: s:reuseWin(dir) {{{2
"finds a NERDTree buffer with root of dir, and opens it.
function! s:reuseWin(dir) abort
let path = g:NERDTreePath.New(fnamemodify(a:dir, ':p'))
for i in range(1, bufnr('$'))
unlet! nt
let nt = getbufvar(i, 'NERDTree')
if empty(nt)
continue
endif
if nt.isWinTree() && nt.root.path.equals(path)
call nt.setPreviousBuf(bufnr('#'))
exec 'buffer ' . i
return 1
endif
endfor
return 0
endfunction
" FUNCTION: nerdtree#completeBookmarks(A,L,P) {{{2
" completion function for the bookmark commands
function! nerdtree#completeBookmarks(A,L,P) abort
return filter(g:NERDTreeBookmark.BookmarkNames(), 'v:val =~# "^' . a:A . '"')
endfunction
"FUNCTION: nerdtree#compareNodes(n1, n2) {{{2
function! nerdtree#compareNodes(n1, n2) abort
return nerdtree#compareNodePaths(a:n1.path, a:n2.path)
endfunction
"FUNCTION: nerdtree#compareNodePaths(p1, p2) {{{2
function! nerdtree#compareNodePaths(p1, p2) abort
let sortKey1 = a:p1.getSortKey()
let sortKey2 = a:p2.getSortKey()
let i = 0
while i < min([len(sortKey1), len(sortKey2)])
" Compare chunks upto common length.
" If chunks have different type, the one which has
" integer type is the lesser.
if type(sortKey1[i]) == type(sortKey2[i])
if sortKey1[i] <# sortKey2[i]
return - 1
elseif sortKey1[i] ># sortKey2[i]
return 1
endif
elseif type(sortKey1[i]) == type(0)
return -1
elseif type(sortKey2[i]) == type(0)
return 1
endif
let i += 1
endwhile
" Keys are identical upto common length.
" The key which has smaller chunks is the lesser one.
if len(sortKey1) < len(sortKey2)
return -1
elseif len(sortKey1) > len(sortKey2)
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
function! nerdtree#deprecated(func, ...) abort
let msg = a:0 ? a:func . ' ' . a:1 : a:func . ' is deprecated'
if !exists('s:deprecationWarnings')
let s:deprecationWarnings = {}
endif
if !has_key(s:deprecationWarnings, a:func)
let s:deprecationWarnings[a:func] = 1
echomsg msg
endif
endfunction
" FUNCTION: nerdtree#exec(cmd, ignoreAll) {{{2
" Same as :exec cmd but, if ignoreAll is TRUE, set eventignore=all for the duration
function! nerdtree#exec(cmd, ignoreAll) abort
let old_ei = &eventignore
if a:ignoreAll
set eventignore=all
endif
try
exec a:cmd
finally
let &eventignore = old_ei
endtry
endfunction
" FUNCTION: nerdtree#has_opt(options, name) {{{2
function! nerdtree#has_opt(options, name) abort
return has_key(a:options, a:name) && a:options[a:name] ==# 1
endfunction
" FUNCTION: nerdtree#loadClassFiles() {{{2
function! nerdtree#loadClassFiles() abort
runtime lib/nerdtree/path.vim
runtime lib/nerdtree/menu_controller.vim
runtime lib/nerdtree/menu_item.vim
runtime lib/nerdtree/key_map.vim
runtime lib/nerdtree/bookmark.vim
runtime lib/nerdtree/tree_file_node.vim
runtime lib/nerdtree/tree_dir_node.vim
runtime lib/nerdtree/opener.vim
runtime lib/nerdtree/creator.vim
runtime lib/nerdtree/flag_set.vim
runtime lib/nerdtree/nerdtree.vim
runtime lib/nerdtree/ui.vim
runtime lib/nerdtree/event.vim
runtime lib/nerdtree/notifier.vim
endfunction
" FUNCTION: nerdtree#postSourceActions() {{{2
function! nerdtree#postSourceActions() abort
call g:NERDTreeBookmark.CacheBookmarks(1)
call nerdtree#ui_glue#createDefaultBindings()
"load all nerdtree plugins
runtime! nerdtree_plugin/**/*.vim
endfunction
"FUNCTION: nerdtree#runningWindows(dir) {{{2
function! nerdtree#runningWindows() abort
return has('win16') || has('win32') || has('win64')
endfunction
"FUNCTION: nerdtree#runningCygwin(dir) {{{2
function! nerdtree#runningCygwin() abort
return has('win32unix')
endfunction
" SECTION: View Functions {{{1
"============================================================
"FUNCTION: nerdtree#echo {{{2
"A wrapper for :echo. Appends 'NERDTree:' on the front of all messages
"
"Args:
"msg: the message to echo
function! nerdtree#echo(msg) abort
redraw
echomsg empty(a:msg) ? '' : ('NERDTree: ' . a:msg)
endfunction
"FUNCTION: nerdtree#echoError {{{2
"Wrapper for nerdtree#echo, sets the message type to errormsg for this message
"Args:
"msg: the message to echo
function! nerdtree#echoError(msg) abort
echohl errormsg
call nerdtree#echo(a:msg)
echohl normal
endfunction
"FUNCTION: nerdtree#echoWarning {{{2
"Wrapper for nerdtree#echo, sets the message type to warningmsg for this message
"Args:
"msg: the message to echo
function! nerdtree#echoWarning(msg) abort
echohl warningmsg
call nerdtree#echo(a:msg)
echohl normal
endfunction
"FUNCTION: nerdtree#renderView {{{2
function! nerdtree#renderView() abort
call b:NERDTree.render()
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,732 +0,0 @@
if exists('g:loaded_nerdtree_ui_glue_autoload')
finish
endif
let g:loaded_nerdtree_ui_glue_autoload = 1
" FUNCTION: nerdtree#ui_glue#createDefaultBindings() {{{1
function! nerdtree#ui_glue#createDefaultBindings() abort
let s = '<SNR>' . s:SID() . '_'
call NERDTreeAddKeyMap({ 'key': '<MiddleMouse>', 'scope': 'all', 'callback': s . 'handleMiddleMouse' })
call NERDTreeAddKeyMap({ 'key': '<LeftRelease>', 'scope': 'all', 'callback': s.'handleLeftClick' })
call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': 'DirNode', 'callback': s.'activateDirNode' })
call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': 'FileNode', 'callback': s.'activateFileNode' })
call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': 'Bookmark', 'callback': s.'activateBookmark' })
call NERDTreeAddKeyMap({ 'key': '<2-LeftMouse>', 'scope': 'all', 'callback': s.'activateAll' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'FileNode', 'callback': s.'customOpenFile'})
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'DirNode', 'callback': s.'customOpenDir'})
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'Bookmark', 'callback': s.'customOpenBookmark'})
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCustomOpen, 'scope':'all', 'callback': s.'activateAll' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': 'DirNode', 'callback': s.'activateDirNode' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': 'FileNode', 'callback': s.'activateFileNode' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': 'Bookmark', 'callback': s.'activateBookmark' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreview, 'scope': 'Bookmark', 'callback': s.'previewBookmark' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapActivateNode, 'scope': 'all', 'callback': s.'activateAll' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenSplit, 'scope': 'FileNode', 'callback': s.'openHSplit' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenSplit, 'scope': 'Bookmark', 'callback': s.'openHSplitBookmark' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenVSplit, 'scope': 'FileNode', 'callback': s.'openVSplit' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenVSplit, 'scope': 'Bookmark', 'callback': s.'openVSplitBookmark' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreview, 'scope': 'FileNode', 'callback': s.'previewNodeCurrent' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewSplit, 'scope': 'FileNode', 'callback': s.'previewNodeHSplit' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewSplit, 'scope': 'Bookmark', 'callback': s.'previewNodeHSplitBookmark' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewVSplit, 'scope': 'FileNode', 'callback': s.'previewNodeVSplit' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapPreviewVSplit, 'scope': 'Bookmark', 'callback': s.'previewNodeVSplitBookmark' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenRecursively, 'scope': 'DirNode', 'callback': s.'openNodeRecursively' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapUpdir, 'scope': 'all', 'callback': s . 'upDirCurrentRootClosed' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapUpdirKeepOpen, 'scope': 'all', 'callback': s . 'upDirCurrentRootOpen' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapChangeRoot, 'scope': 'Node', 'callback': s . 'chRoot' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapChdir, 'scope': 'Node', 'callback': s.'chCwd' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapQuit, 'scope': 'all', 'callback': s.'closeTreeWindow' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCWD, 'scope': 'all', 'callback': 'nerdtree#ui_glue#chRootCwd' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapRefreshRoot, 'scope': 'all', 'callback': s.'refreshRoot' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapRefresh, 'scope': 'Node', 'callback': s.'refreshCurrent' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapHelp, 'scope': 'all', 'callback': s.'displayHelp' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleZoom, 'scope': 'all', 'callback': s.'toggleZoom' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleHidden, 'scope': 'all', 'callback': s.'toggleShowHidden' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleFilters, 'scope': 'all', 'callback': s.'toggleIgnoreFilter' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleFiles, 'scope': 'all', 'callback': s.'toggleShowFiles' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapToggleBookmarks, 'scope': 'all', 'callback': s.'toggleShowBookmarks' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCloseDir, 'scope': 'Node', 'callback': s.'closeCurrentDir' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapCloseChildren, 'scope': 'DirNode', 'callback': s.'closeChildren' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapMenu, 'scope': 'Node', 'callback': s.'showMenu' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpParent, 'scope': 'Node', 'callback': s.'jumpToParent' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpFirstChild, 'scope': 'Node', 'callback': s.'jumpToFirstChild' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpLastChild, 'scope': 'Node', 'callback': s.'jumpToLastChild' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpRoot, 'scope': 'all', 'callback': s.'jumpToRoot' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpNextSibling, 'scope': 'Node', 'callback': s.'jumpToNextSibling' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapJumpPrevSibling, 'scope': 'Node', 'callback': s.'jumpToPrevSibling' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTab, 'scope': 'Node', 'callback': s . 'openInNewTab' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTabSilent, 'scope': 'Node', 'callback': s . 'openInNewTabSilent' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTab, 'scope': 'Bookmark', 'callback': s . 'openInNewTab' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenInTabSilent, 'scope': 'Bookmark', 'callback': s . 'openInNewTabSilent' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenExpl, 'scope': 'DirNode', 'callback': s.'openExplorer' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapOpenExpl, 'scope': 'FileNode', 'callback': s.'openExplorer' })
call NERDTreeAddKeyMap({ 'key': g:NERDTreeMapDeleteBookmark, 'scope': 'Bookmark', 'callback': s.'deleteBookmark' })
endfunction
"SECTION: Interface bindings {{{1
"============================================================
"FUNCTION: s:customOpenFile() {{{1
" Open file node with the 'custom' key, initially <CR>.
function! s:customOpenFile(node) abort
call a:node.activate(s:initCustomOpenArgs().file)
endfunction
"FUNCTION: s:customOpenDir() {{{1
" Open directory node with the 'custom' key, initially <CR>.
function! s:customOpenDir(node) abort
call s:activateDirNode(a:node, s:initCustomOpenArgs().dir)
endfunction
"FUNCTION: s:customOpenBookmark() {{{1
" Open bookmark node with the 'custom' key, initially <CR>.
function! s:customOpenBookmark(node) abort
if a:node.path.isDirectory
call a:node.activate(b:NERDTree, s:initCustomOpenArgs().dir)
else
call a:node.activate(b:NERDTree, s:initCustomOpenArgs().file)
endif
endfunction
"FUNCTION: s:initCustomOpenArgs() {{{1
function! s:initCustomOpenArgs() abort
let l:defaultOpenArgs = {'file': {'reuse': 'all', 'where': 'p', 'keepopen':!nerdtree#closeTreeOnOpen()}, 'dir': {}}
try
let g:NERDTreeCustomOpenArgs = get(g:, 'NERDTreeCustomOpenArgs', {})
call extend(g:NERDTreeCustomOpenArgs, l:defaultOpenArgs, 'keep')
catch /^Vim(\a\+):E712:/
call nerdtree#echoWarning('g:NERDTreeCustomOpenArgs is not set properly. Using default value.')
let g:NERDTreeCustomOpenArgs = l:defaultOpenArgs
finally
return g:NERDTreeCustomOpenArgs
endtry
endfunction
"FUNCTION: s:activateAll() {{{1
"handle the user activating the updir line
function! s:activateAll() abort
if getline('.') ==# g:NERDTreeUI.UpDirLine()
return nerdtree#ui_glue#upDir(0)
endif
endfunction
" FUNCTION: s:activateDirNode(directoryNode, options) {{{1
" Open a directory with optional options
function! s:activateDirNode(directoryNode, ...) abort
if a:directoryNode.isRoot() && a:directoryNode.isOpen
call nerdtree#echo('cannot close tree root')
return
endif
call a:directoryNode.activate((a:0 > 0) ? a:1 : {})
endfunction
"FUNCTION: s:activateFileNode() {{{1
"handle the user activating a tree node
function! s:activateFileNode(node) abort
call a:node.activate({'reuse': 'all', 'where': 'p', 'keepopen': !nerdtree#closeTreeOnOpen()})
endfunction
"FUNCTION: s:activateBookmark(bookmark) {{{1
"handle the user activating a bookmark
function! s:activateBookmark(bm) abort
call a:bm.activate(b:NERDTree, !a:bm.path.isDirectory ? {'where': 'p', 'keepopen': !nerdtree#closeTreeOnOpen()} : {})
endfunction
" FUNCTION: nerdtree#ui_glue#bookmarkNode(name) {{{1
" Associate the current node with the given name
function! nerdtree#ui_glue#bookmarkNode(...) abort
let currentNode = g:NERDTreeFileNode.GetSelected()
if currentNode !=# {}
let name = a:1
if empty(name)
let name = currentNode.path.getLastPathComponent(0)
endif
try
call currentNode.bookmark(name)
call b:NERDTree.render()
catch /^NERDTree.IllegalBookmarkNameError/
call nerdtree#echo('bookmark names must not contain spaces')
endtry
else
call nerdtree#echo('select a node first')
endif
endfunction
" FUNCTION: s:chCwd(node) {{{1
function! s:chCwd(node) abort
try
call a:node.path.changeToDir()
catch /^NERDTree.PathChangeError/
call nerdtree#echoWarning('could not change cwd')
endtry
endfunction
" FUNCTION: s:chRoot(node) {{{1
" changes the current root to the selected one
function! s:chRoot(node) abort
call b:NERDTree.changeRoot(a:node)
endfunction
" FUNCTION: s:nerdtree#ui_glue#chRootCwd() {{{1
" Change the NERDTree root to match the current working directory.
function! nerdtree#ui_glue#chRootCwd() abort
NERDTreeCWD
endfunction
" FUNCTION: nnerdtree#ui_glue#clearBookmarks(bookmarks) {{{1
function! nerdtree#ui_glue#clearBookmarks(bookmarks) abort
if a:bookmarks ==# ''
let currentNode = g:NERDTreeFileNode.GetSelected()
if currentNode !=# {}
call currentNode.clearBookmarks()
endif
else
for name in split(a:bookmarks, ' ')
let bookmark = g:NERDTreeBookmark.BookmarkFor(name)
call bookmark.delete()
endfor
endif
call b:NERDTree.root.refresh()
call b:NERDTree.render()
endfunction
" FUNCTION: s:closeChildren(node) {{{1
" closes all childnodes of the current node
function! s:closeChildren(node) abort
call a:node.closeChildren()
call b:NERDTree.render()
call a:node.putCursorHere(0, 0)
endfunction
" FUNCTION: s:closeCurrentDir(node) {{{1
" Close the parent directory of the current node.
function! s:closeCurrentDir(node) abort
if a:node.isRoot()
call nerdtree#echo('cannot close parent of tree root')
return
endif
let l:parent = a:node.parent
while l:parent.isCascadable()
let l:parent = l:parent.parent
endwhile
if l:parent.isRoot()
call nerdtree#echo('cannot close tree root')
return
endif
call l:parent.close()
call b:NERDTree.render()
call l:parent.putCursorHere(0, 0)
endfunction
" FUNCTION: s:closeTreeWindow() {{{1
" close the tree window
function! s:closeTreeWindow() abort
if b:NERDTree.isWinTree() && b:NERDTree.previousBuf() !=# -1
exec 'buffer ' . b:NERDTree.previousBuf()
else
if winnr('$') > 1
call g:NERDTree.Close()
else
call nerdtree#echo('Cannot close last window')
endif
endif
endfunction
" FUNCTION: s:deleteBookmark(bookmark) {{{1
" Prompt the user to confirm the deletion of the selected bookmark.
function! s:deleteBookmark(bookmark) abort
let l:message = 'Delete the bookmark "' . a:bookmark.name
\ . '" from the bookmark list?'
let l:choices = "&Yes\n&No"
echo | redraw
let l:selection = confirm(l:message, l:choices, 1, 'Warning')
if l:selection !=# 1
call nerdtree#echo('bookmark not deleted')
return
endif
try
call a:bookmark.delete()
silent call b:NERDTree.root.refresh()
call b:NERDTree.render()
echo | redraw
catch /^NERDTree/
call nerdtree#echoWarning('could not remove bookmark')
endtry
endfunction
" FUNCTION: s:displayHelp() {{{1
" toggles the help display
function! s:displayHelp() abort
call b:NERDTree.ui.toggleHelp()
call b:NERDTree.render()
call b:NERDTree.ui.centerView()
endfunction
" FUNCTION: s:findAndRevealPath(pathStr) {{{1
function! s:findAndRevealPath(pathStr) abort
let l:pathStr = !empty(a:pathStr) ? a:pathStr : expand('%:p')
let l:revealOpts = {}
if empty(l:pathStr)
call nerdtree#echoWarning('no file for the current buffer')
return
endif
if !filereadable(l:pathStr)
let l:pathStr = fnamemodify(l:pathStr, ':h')
let l:revealOpts['open'] = 1
endif
try
let l:pathStr = g:NERDTreePath.Resolve(l:pathStr)
let l:pathObj = g:NERDTreePath.New(l:pathStr)
catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echoWarning('invalid path')
return
endtry
if !g:NERDTree.ExistsForTab()
try
let l:cwd = g:NERDTreePath.New(getcwd())
catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echo('current directory does not exist.')
let l:cwd = l:pathObj.getParent()
endtry
if l:pathObj.isUnder(l:cwd)
call g:NERDTreeCreator.CreateTabTree(l:cwd.str())
else
call g:NERDTreeCreator.CreateTabTree(l:pathObj.getParent().str())
endif
else
NERDTreeFocus
if !l:pathObj.isUnder(b:NERDTree.root.path)
call s:chRoot(g:NERDTreeDirNode.New(l:pathObj.getParent(), b:NERDTree))
endif
endif
if l:pathObj.isHiddenUnder(b:NERDTree.root.path)
call b:NERDTree.ui.setShowHidden(1)
endif
let l:node = b:NERDTree.root.reveal(l:pathObj, l:revealOpts)
call b:NERDTree.render()
call l:node.putCursorHere(1, 0)
endfunction
"FUNCTION: s:handleLeftClick() {{{1
"Checks if the click should open the current node
function! s:handleLeftClick() abort
let currentNode = g:NERDTreeFileNode.GetSelected()
if currentNode !=# {}
"the dir arrows are multibyte chars, and vim's string functions only
"deal with single bytes - so split the line up with the hack below and
"take the line substring manually
let line = split(getline(line('.')), '\zs')
let startToCur = ''
for i in range(0,len(line)-1)
let startToCur .= line[i]
endfor
if currentNode.path.isDirectory
if startToCur =~# g:NERDTreeUI.MarkupReg() && startToCur =~# '[+~'.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.'] \?$'
call currentNode.activate()
return
endif
endif
if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3
let char = strpart(startToCur, strlen(startToCur)-1, 1)
if char !~# g:NERDTreeUI.MarkupReg()
if currentNode.path.isDirectory
call currentNode.activate()
else
call currentNode.activate({'reuse': 'all', 'where': 'p', 'keepopen':!nerdtree#closeTreeOnOpen()})
endif
return
endif
endif
endif
endfunction
" FUNCTION: s:handleMiddleMouse() {{{1
function! s:handleMiddleMouse() abort
" A middle mouse click does not automatically position the cursor as one
" would expect. Forcing the execution of a regular left mouse click here
" fixes this problem.
execute "normal! \<LeftMouse>"
let l:currentNode = g:NERDTreeFileNode.GetSelected()
if empty(l:currentNode)
call nerdtree#echoError('use the pointer to select a node')
return
endif
if l:currentNode.path.isDirectory
call l:currentNode.openExplorer()
else
call l:currentNode.open({'where': 'h'})
endif
endfunction
" FUNCTION: nerdtree#ui_glue#invokeKeyMap(key) {{{1
"this is needed since I cant figure out how to invoke dict functions from a
"key map
function! nerdtree#ui_glue#invokeKeyMap(key) abort
call g:NERDTreeKeyMap.Invoke(a:key)
endfunction
" FUNCTION: s:jumpToFirstChild(node) {{{1
function! s:jumpToFirstChild(node) abort
call s:jumpToChild(a:node, 0)
endfunction
" FUNCTION: s:jumpToLastChild(node) {{{1
function! s:jumpToLastChild(node) abort
call s:jumpToChild(a:node, 1)
endfunction
" FUNCTION: s:jumpToChild(node, last) {{{1
" Jump to the first or last child node at the same file system level.
"
" Args:
" node: the node on which the cursor currently sits
" last: 1 (true) if jumping to last child, 0 (false) if jumping to first
function! s:jumpToChild(node, last) abort
let l:node = a:node.path.isDirectory ? a:node.getCascadeRoot() : a:node
if l:node.isRoot()
return
endif
let l:parent = l:node.parent
let l:children = l:parent.getVisibleChildren()
let l:target = a:last ? l:children[len(l:children) - 1] : l:children[0]
call l:target.putCursorHere(1, 0)
call b:NERDTree.ui.centerView()
endfunction
" FUNCTION: s:jumpToParent(node) {{{1
" Move the cursor to the parent of the specified node. For a cascade, move to
" the parent of the cascade's first node. At the root node, do nothing.
function! s:jumpToParent(node) abort
let l:node = a:node.path.isDirectory ? a:node.getCascadeRoot() : a:node
if l:node.isRoot()
return
endif
if empty(l:node.parent)
call nerdtree#echo('could not jump to parent node')
return
endif
call l:node.parent.putCursorHere(1, 0)
call b:NERDTree.ui.centerView()
endfunction
" FUNCTION: s:jumpToRoot() {{{1
" moves the cursor to the root node
function! s:jumpToRoot() abort
call b:NERDTree.root.putCursorHere(1, 0)
call b:NERDTree.ui.centerView()
endfunction
" FUNCTION: s:jumpToNextSibling(node) {{{1
function! s:jumpToNextSibling(node) abort
call s:jumpToSibling(a:node, 1)
endfunction
" FUNCTION: s:jumpToPrevSibling(node) {{{1
function! s:jumpToPrevSibling(node) abort
call s:jumpToSibling(a:node, 0)
endfunction
" FUNCTION: s:jumpToSibling(node, forward) {{{1
" Move the cursor to the next or previous node at the same file system level.
"
" Args:
" node: the node on which the cursor currently sits
" forward: 0 to jump to previous sibling, 1 to jump to next sibling
function! s:jumpToSibling(node, forward) abort
let l:node = a:node.path.isDirectory ? a:node.getCascadeRoot() : a:node
let l:sibling = l:node.findSibling(a:forward)
if empty(l:sibling)
return
endif
call l:sibling.putCursorHere(1, 0)
call b:NERDTree.ui.centerView()
endfunction
" FUNCTION: nerdtree#ui_glue#openBookmark(name) {{{1
" Open the Bookmark that has the specified name. This function provides the
" implementation for the :OpenBookmark command.
function! nerdtree#ui_glue#openBookmark(name) abort
try
let l:bookmark = g:NERDTreeBookmark.BookmarkFor(a:name)
catch /^NERDTree.BookmarkNotFoundError/
call nerdtree#echoError('bookmark "' . a:name . '" not found')
return
endtry
if l:bookmark.path.isDirectory
call l:bookmark.open(b:NERDTree)
return
endif
call l:bookmark.open(b:NERDTree, s:initCustomOpenArgs().file)
endfunction
" FUNCTION: s:openHSplit(target) {{{1
function! s:openHSplit(target) abort
call a:target.activate({'where': 'h', 'keepopen': !nerdtree#closeTreeOnOpen()})
endfunction
" FUNCTION: s:openVSplit(target) {{{1
function! s:openVSplit(target) abort
call a:target.activate({'where': 'v', 'keepopen': !nerdtree#closeTreeOnOpen()})
endfunction
"FUNCTION: s:openHSplitBookmark(bookmark) {{{1
"handle the user activating a bookmark
function! s:openHSplitBookmark(bm) abort
call a:bm.activate(b:NERDTree, !a:bm.path.isDirectory ? {'where': 'h', 'keepopen': !nerdtree#closeTreeOnOpen()} : {})
endfunction
"FUNCTION: s:openVSplitBookmark(bookmark) {{{1
"handle the user activating a bookmark
function! s:openVSplitBookmark(bm) abort
call a:bm.activate(b:NERDTree, !a:bm.path.isDirectory ? {'where': 'v', 'keepopen': !nerdtree#closeTreeOnOpen()} : {})
endfunction
" FUNCTION: s:previewHSplitBookmark(bookmark) {{{1
function! s:previewNodeHSplitBookmark(bookmark) abort
call a:bookmark.activate(b:NERDTree, !a:bookmark.path.isDirectory ? {'stay': 1, 'where': 'h', 'keepopen': 1} : {})
endfunction
" FUNCTION: s:previewVSplitBookmark(bookmark) {{{1
function! s:previewNodeVSplitBookmark(bookmark) abort
call a:bookmark.activate(b:NERDTree, !a:bookmark.path.isDirectory ? {'stay': 1, 'where': 'v', 'keepopen': 1} : {})
endfunction
" FUNCTION: s:openExplorer(node) {{{1
function! s:openExplorer(node) abort
call a:node.openExplorer()
endfunction
" FUNCTION: s:openInNewTab(target) {{{1
function! s:openInNewTab(target) abort
let l:opener = g:NERDTreeOpener.New(a:target.path, {'where': 't', 'keepopen': !nerdtree#closeTreeOnOpen()})
call l:opener.open(a:target)
endfunction
" FUNCTION: s:openInNewTabSilent(target) {{{1
function! s:openInNewTabSilent(target) abort
let l:opener = g:NERDTreeOpener.New(a:target.path, {'where': 't', 'keepopen': !nerdtree#closeTreeOnOpen(), 'stay': 1})
call l:opener.open(a:target)
endfunction
" FUNCTION: s:openNodeRecursively(node) {{{1
function! s:openNodeRecursively(node) abort
call nerdtree#echo('Recursively opening node. Please wait...')
call a:node.openRecursively()
call b:NERDTree.render()
call nerdtree#echo('')
endfunction
" FUNCTION: s:previewBookmark(bookmark) {{{1
function! s:previewBookmark(bookmark) abort
if a:bookmark.path.isDirectory
execute 'NERDTreeFind '.a:bookmark.path.str()
else
call a:bookmark.activate(b:NERDTree, {'stay': 1, 'where': 'p', 'keepopen': 1})
endif
endfunction
"FUNCTION: s:previewNodeCurrent(node) {{{1
function! s:previewNodeCurrent(node) abort
call a:node.open({'stay': 1, 'where': 'p', 'keepopen': 1})
endfunction
"FUNCTION: s:previewNodeHSplit(node) {{{1
function! s:previewNodeHSplit(node) abort
call a:node.open({'stay': 1, 'where': 'h', 'keepopen': 1})
endfunction
"FUNCTION: s:previewNodeVSplit(node) {{{1
function! s:previewNodeVSplit(node) abort
call a:node.open({'stay': 1, 'where': 'v', 'keepopen': 1})
endfunction
" FUNCTION: nerdtree#ui_glue#revealBookmark(name) {{{1
" put the cursor on the node associate with the given name
function! nerdtree#ui_glue#revealBookmark(name) abort
try
let targetNode = g:NERDTreeBookmark.GetNodeForName(a:name, 0, b:NERDTree)
call targetNode.putCursorHere(0, 1)
catch /^NERDTree.BookmarkNotFoundError/
call nerdtree#echo('Bookmark isn''t cached under the current root')
endtry
endfunction
" FUNCTION: s:refreshRoot() {{{1
" Reloads the current root. All nodes below this will be lost and the root dir
" will be reloaded.
function! s:refreshRoot() abort
if !g:NERDTree.IsOpen()
return
endif
call nerdtree#echo('Refreshing the root node. This could take a while...')
let l:curWin = winnr()
call nerdtree#exec(g:NERDTree.GetWinNum() . 'wincmd w', 1)
call b:NERDTree.root.refresh()
call b:NERDTree.render()
redraw
call nerdtree#exec(l:curWin . 'wincmd w', 1)
call nerdtree#echo('')
endfunction
" FUNCTION: s:refreshCurrent(node) {{{1
" refreshes the root for the current node
function! s:refreshCurrent(node) abort
let node = a:node
if !node.path.isDirectory
let node = node.parent
endif
call nerdtree#echo('Refreshing node. This could take a while...')
call node.refresh()
call b:NERDTree.render()
call nerdtree#echo('')
endfunction
" FUNCTION: nerdtree#ui_glue#setupCommands() {{{1
function! nerdtree#ui_glue#setupCommands() abort
command! -n=? -complete=dir -bar NERDTree :call g:NERDTreeCreator.CreateTabTree('<args>')
command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.ToggleTabTree('<args>')
command! -n=0 -bar NERDTreeClose :call g:NERDTree.Close()
command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreateTabTree('<args>')
command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror()
command! -n=? -complete=file -bar NERDTreeFind call s:findAndRevealPath('<args>')
command! -n=0 -bar NERDTreeRefreshRoot call s:refreshRoot()
command! -n=0 -bar NERDTreeFocus call NERDTreeFocus()
command! -n=0 -bar NERDTreeCWD call NERDTreeCWD()
endfunction
" Function: s:SID() {{{1
function! s:SID() abort
if !exists('s:sid')
let s:sid = matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endif
return s:sid
endfun
" FUNCTION: s:showMenu(node) {{{1
function! s:showMenu(node) abort
let mc = g:NERDTreeMenuController.New(g:NERDTreeMenuItem.AllEnabled())
call mc.showMenu()
endfunction
" FUNCTION: s:toggleIgnoreFilter() {{{1
function! s:toggleIgnoreFilter() abort
call b:NERDTree.ui.toggleIgnoreFilter()
endfunction
" FUNCTION: s:toggleShowBookmarks() {{{1
function! s:toggleShowBookmarks() abort
call b:NERDTree.ui.toggleShowBookmarks()
endfunction
" FUNCTION: s:toggleShowFiles() {{{1
function! s:toggleShowFiles() abort
call b:NERDTree.ui.toggleShowFiles()
endfunction
" FUNCTION: s:toggleShowHidden() {{{1
" toggles the display of hidden files
function! s:toggleShowHidden() abort
call b:NERDTree.ui.toggleShowHidden()
endfunction
" FUNCTION: s:toggleZoom() {{{1
function! s:toggleZoom() abort
call b:NERDTree.ui.toggleZoom()
endfunction
" FUNCTION: nerdtree#ui_glue#upDir(preserveState) {{{1
" Move the NERDTree up one level.
"
" Args:
" preserveState: if 1, the current root is left open when the new tree is
" rendered; if 0, the current root node is closed
function! nerdtree#ui_glue#upDir(preserveState) abort
try
call b:NERDTree.root.cacheParent()
catch /^NERDTree.CannotCacheParentError/
call nerdtree#echo('already at root directory')
return
endtry
let l:oldRoot = b:NERDTree.root
let l:newRoot = b:NERDTree.root.parent
call l:newRoot.open()
call l:newRoot.transplantChild(l:oldRoot)
if !a:preserveState
call l:oldRoot.close()
endif
call b:NERDTree.changeRoot(l:newRoot)
call l:oldRoot.putCursorHere(0, 0)
endfunction
" FUNCTION: s:upDirCurrentRootOpen() {{{1
function! s:upDirCurrentRootOpen() abort
call nerdtree#ui_glue#upDir(1)
endfunction
" FUNCTION: s:upDirCurrentRootClosed() {{{1
function! s:upDirCurrentRootClosed() abort
call nerdtree#ui_glue#upDir(0)
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

File diff suppressed because it is too large Load Diff

View File

@@ -1,365 +0,0 @@
" ============================================================================
" CLASS: Bookmark
"
" The Bookmark class serves two purposes:
" (1) It is the top-level prototype for new, concrete Bookmark objects.
" (2) It provides an interface for client code to query and manipulate the
" global list of Bookmark objects within the current Vim session.
" ============================================================================
let s:Bookmark = {}
let g:NERDTreeBookmark = s:Bookmark
" FUNCTION: Bookmark.activate(nerdtree) {{{1
function! s:Bookmark.activate(nerdtree, ...)
call self.open(a:nerdtree, a:0 ? a:1 : {})
endfunction
" FUNCTION: Bookmark.AddBookmark(name, path) {{{1
" Class method to add a new bookmark to the list, if a previous bookmark exists
" with the same name, just update the path for that bookmark
function! s:Bookmark.AddBookmark(name, path)
for i in s:Bookmark.Bookmarks()
if i.name ==# a:name
let i.path = a:path
return
endif
endfor
call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path))
endfunction
" FUNCTION: Bookmark.Bookmarks() {{{1
" Class method to get all bookmarks. Lazily initializes the bookmarks global
" variable
function! s:Bookmark.Bookmarks()
if !exists('g:NERDTreeBookmarks')
let g:NERDTreeBookmarks = []
endif
return g:NERDTreeBookmarks
endfunction
" FUNCTION: Bookmark.BookmarkExistsFor(name) {{{1
" class method that returns 1 if a bookmark with the given name is found, 0
" otherwise
function! s:Bookmark.BookmarkExistsFor(name)
try
call s:Bookmark.BookmarkFor(a:name)
return 1
catch /^NERDTree.BookmarkNotFoundError/
return 0
endtry
endfunction
" FUNCTION: Bookmark.BookmarkFor(name) {{{1
" Class method that returns the Bookmark object having the specified name.
" Throws NERDTree.BookmarkNotFoundError if no Bookmark is found.
function! s:Bookmark.BookmarkFor(name)
let l:result = {}
for l:bookmark in s:Bookmark.Bookmarks()
if l:bookmark.name ==# a:name
let l:result = l:bookmark
break
endif
endfor
if empty(l:result)
throw 'NERDTree.BookmarkNotFoundError: "' . a:name . '" not found'
endif
return l:result
endfunction
" FUNCTION: Bookmark.BookmarkNames() {{{1
" Class method to return an array of all bookmark names
function! s:Bookmark.BookmarkNames()
let names = []
for i in s:Bookmark.Bookmarks()
call add(names, i.name)
endfor
return names
endfunction
" FUNCTION: Bookmark.CacheBookmarks(silent) {{{1
" Class method to read all bookmarks from the bookmarks file initialize
" bookmark objects for each one.
"
" Args:
" silent - dont echo an error msg if invalid bookmarks are found
function! s:Bookmark.CacheBookmarks(silent)
if filereadable(g:NERDTreeBookmarksFile)
let g:NERDTreeBookmarks = []
let g:NERDTreeInvalidBookmarks = []
let bookmarkStrings = readfile(g:NERDTreeBookmarksFile)
let invalidBookmarksFound = 0
for i in bookmarkStrings
"ignore blank lines
if i !=# ''
let name = substitute(i, '^\(.\{-}\) .*$', '\1', '')
let path = substitute(i, '^.\{-} \(.*\)$', '\1', '')
let path = fnamemodify(path, ':p')
try
let bookmark = s:Bookmark.New(name, g:NERDTreePath.New(path))
call add(g:NERDTreeBookmarks, bookmark)
catch /^NERDTree.InvalidArgumentsError/
call add(g:NERDTreeInvalidBookmarks, i)
let invalidBookmarksFound += 1
endtry
endif
endfor
if invalidBookmarksFound
call s:Bookmark.Write()
if !a:silent
call nerdtree#echo(invalidBookmarksFound . ' invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.')
endif
endif
endif
endfunction
" FUNCTION: Bookmark.CompareBookmarksByName(firstBookmark, secondBookmark) {{{1
" Class method that indicates the relative position of two bookmarks when
" placed in alphabetical order by name. Case-sensitivity is determined by an
" option. Supports the s:Bookmark.SortBookmarksList() method.
function! s:Bookmark.CompareBookmarksByName(firstBookmark, secondBookmark)
let l:result = 0
if g:NERDTreeBookmarksSort ==# 1
if a:firstBookmark.name <? a:secondBookmark.name
let l:result = -1
elseif a:firstBookmark.name >? a:secondBookmark.name
let l:result = 1
endif
elseif g:NERDTreeBookmarksSort ==# 2
if a:firstBookmark.name <# a:secondBookmark.name
let l:result = -1
elseif a:firstBookmark.name ># a:secondBookmark.name
let l:result = 1
endif
endif
return l:result
endfunction
" FUNCTION: Bookmark.ClearAll() {{{1
" Class method to delete all bookmarks.
function! s:Bookmark.ClearAll()
for i in s:Bookmark.Bookmarks()
call i.delete()
endfor
call s:Bookmark.Write()
endfunction
" FUNCTION: Bookmark.delete() {{{1
" Delete this bookmark. If the node for this bookmark is under the current
" root, then recache bookmarks for its Path object
function! s:Bookmark.delete()
call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self))
call s:Bookmark.Write()
endfunction
" FUNCTION: s:Edit() {{{1
" opens the NERDTreeBookmarks file for manual editing
function! s:Bookmark.Edit()
call nerdtree#exec('wincmd w', 1)
call nerdtree#exec('edit '.g:NERDTreeBookmarksFile, 1)
endfunction
" FUNCTION: Bookmark.getNode(nerdtree, searchFromAbsoluteRoot) {{{1
" Returns the tree node object associated with this Bookmark.
" Throws NERDTree.BookmarkedNodeNotFoundError if the node is not found.
"
" Args:
" searchFromAbsoluteRoot: boolean flag, search from the highest cached node
" if true and from the current tree root if false
function! s:Bookmark.getNode(nerdtree, searchFromAbsoluteRoot)
if a:searchFromAbsoluteRoot
let l:searchRoot = a:nerdtree.root.AbsoluteTreeRoot()
else
let l:searchRoot = a:nerdtree.root
endif
let l:targetNode = l:searchRoot.findNode(self.path)
if empty(l:targetNode)
throw 'NERDTree.BookmarkedNodeNotFoundError: node for bookmark "' . self.name . '" not found'
endif
return l:targetNode
endfunction
" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot, nerdtree) {{{1
" Class method that returns the tree node object for the Bookmark with the
" given name. Throws NERDTree.BookmarkNotFoundError if a Bookmark with the
" name does not exist. Throws NERDTree.BookmarkedNodeNotFoundError if a
" tree node for the named Bookmark could not be found.
function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot, nerdtree)
let l:bookmark = s:Bookmark.BookmarkFor(a:name)
return l:bookmark.getNode(a:nerdtree, a:searchFromAbsoluteRoot)
endfunction
" FUNCTION: Bookmark.GetSelected() {{{1
" returns the Bookmark the cursor is over, or {}
function! s:Bookmark.GetSelected()
let line = getline('.')
let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '')
if name !=# line
try
return s:Bookmark.BookmarkFor(name)
catch /^NERDTree.BookmarkNotFoundError/
return {}
endtry
endif
return {}
endfunction
" FUNCTION: Bookmark.InvalidBookmarks() {{{1
" Class method to get all invalid bookmark strings read from the bookmarks
" file
function! s:Bookmark.InvalidBookmarks()
if !exists('g:NERDTreeInvalidBookmarks')
let g:NERDTreeInvalidBookmarks = []
endif
return g:NERDTreeInvalidBookmarks
endfunction
" FUNCTION: Bookmark.mustExist() {{{1
function! s:Bookmark.mustExist()
if !self.path.exists()
call s:Bookmark.CacheBookmarks(1)
throw 'NERDTree.BookmarkPointsToInvalidLocationError: the bookmark "'.
\ self.name .'" points to a non existing location: "'. self.path.str()
endif
endfunction
" FUNCTION: Bookmark.New(name, path) {{{1
" Create a new bookmark object with the given name and path object
function! s:Bookmark.New(name, path)
if a:name =~# ' '
throw 'NERDTree.IllegalBookmarkNameError: illegal name:' . a:name
endif
let newBookmark = copy(self)
let newBookmark.name = a:name
let newBookmark.path = a:path
return newBookmark
endfunction
" FUNCTION: Bookmark.open(nerdtree, [options]) {{{1
"Args:
"
"nerdtree: the tree to load open the bookmark in
"
"A dictionary containing the following keys (all optional):
" 'where': Specifies whether the node should be opened in new split/tab or in
" the previous window. Can be either 'v' (vertical split), 'h'
" (horizontal split), 't' (new tab) or 'p' (previous window).
" 'reuse': if a window is displaying the file then jump the cursor there
" 'keepopen': dont close the tree window
" 'stay': open the file, but keep the cursor in the tree win
"
function! s:Bookmark.open(nerdtree, ...)
let opts = a:0 ? a:1 : {}
if nerdtree#closeBookmarksOnOpen()
call a:nerdtree.ui.toggleShowBookmarks()
endif
if self.path.isDirectory && !has_key(opts, 'where')
call self.toRoot(a:nerdtree)
else
let opener = g:NERDTreeOpener.New(self.path, opts)
call opener.open(self)
endif
endfunction
" FUNCTION: Bookmark.openInNewTab(options) {{{1
" Create a new bookmark object with the given name and path object
function! s:Bookmark.openInNewTab(options)
call nerdtree#deprecated('Bookmark.openInNewTab', 'is deprecated, use open() instead')
call self.open(a:options)
endfunction
" FUNCTION: Bookmark.setPath(path) {{{1
" makes this bookmark point to the given path
function! s:Bookmark.setPath(path)
let self.path = a:path
endfunction
" FUNCTION: Bookmark.SortBookmarksList() {{{1
" Class method that sorts the global list of bookmarks alphabetically by name.
" Note that case-sensitivity is determined by a user option.
function! s:Bookmark.SortBookmarksList()
call sort(s:Bookmark.Bookmarks(), s:Bookmark.CompareBookmarksByName, s:Bookmark)
endfunction
" FUNCTION: Bookmark.str() {{{1
" Get the string that should be rendered in the view for this bookmark
function! s:Bookmark.str()
let pathStrMaxLen = winwidth(g:NERDTree.GetWinNum()) - 4 - strdisplaywidth(self.name)
if &number
let pathStrMaxLen = pathStrMaxLen - &numberwidth
endif
let pathStr = self.path.str({'format': 'UI'})
if strdisplaywidth(pathStr) > pathStrMaxLen
while strdisplaywidth(pathStr) > pathStrMaxLen && strchars(pathStr) > 0
let pathStr = substitute(pathStr, '^.', '', '')
endwhile
let pathStr = '<' . pathStr
endif
return '>' . self.name . ' ' . pathStr
endfunction
" FUNCTION: Bookmark.toRoot(nerdtree) {{{1
" Set the root of the given NERDTree to the node for this Bookmark. If a node
" for this Bookmark does not exist, a new one is initialized.
function! s:Bookmark.toRoot(nerdtree)
if self.validate()
try
let l:targetNode = self.getNode(a:nerdtree, 1)
call l:targetNode.closeChildren()
catch /^NERDTree.BookmarkedNodeNotFoundError/
let l:targetNode = g:NERDTreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path, a:nerdtree)
endtry
call a:nerdtree.changeRoot(l:targetNode)
endif
endfunction
" FUNCTION: Bookmark.ToRoot(name, nerdtree) {{{1
" Class method that makes the Bookmark with the given name the root of
" specified NERDTree.
function! s:Bookmark.ToRoot(name, nerdtree)
let l:bookmark = s:Bookmark.BookmarkFor(a:name)
call l:bookmark.toRoot(a:nerdtree)
endfunction
" FUNCTION: Bookmark.validate() {{{1
function! s:Bookmark.validate()
if self.path.exists()
return 1
else
call s:Bookmark.CacheBookmarks(1)
call nerdtree#echo(self.name . 'now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.')
return 0
endif
endfunction
" FUNCTION: Bookmark.Write() {{{1
" Class method to write all bookmarks to the bookmarks file
function! s:Bookmark.Write()
let bookmarkStrings = []
for i in s:Bookmark.Bookmarks()
call add(bookmarkStrings, i.name . ' ' . fnamemodify(i.path.str(), ':~'))
endfor
"add a blank line before the invalid ones
call add(bookmarkStrings, '')
for j in s:Bookmark.InvalidBookmarks()
call add(bookmarkStrings, j)
endfor
try
call writefile(bookmarkStrings, g:NERDTreeBookmarksFile)
catch
call nerdtree#echoError('Failed to write bookmarks file. Make sure g:NERDTreeBookmarksFile points to a valid location.')
endtry
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,402 +0,0 @@
" ============================================================================
" CLASS: Creator
"
" This class is responsible for creating NERDTree instances. The new NERDTree
" may be a tab tree, a window tree, or a mirrored tree. In the process of
" creating a NERDTree, it sets up all of the window and buffer options and key
" mappings etc.
" ============================================================================
let s:Creator = {}
let g:NERDTreeCreator = s:Creator
" FUNCTION: s:Creator._bindMappings() {{{1
function! s:Creator._bindMappings()
call g:NERDTreeKeyMap.BindAll()
command! -buffer -nargs=? Bookmark :call nerdtree#ui_glue#bookmarkNode('<args>')
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 RevealBookmark :call nerdtree#ui_glue#revealBookmark('<args>')
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 OpenBookmark call nerdtree#ui_glue#openBookmark('<args>')
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=* ClearBookmarks call nerdtree#ui_glue#clearBookmarks('<args>')
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=+ BookmarkToRoot call g:NERDTreeBookmark.ToRoot('<args>', b:NERDTree)
command! -buffer -nargs=0 ClearAllBookmarks call g:NERDTreeBookmark.ClearAll() <bar> call b:NERDTree.render()
command! -buffer -nargs=0 ReadBookmarks call g:NERDTreeBookmark.CacheBookmarks(0) <bar> call b:NERDTree.render()
command! -buffer -nargs=0 WriteBookmarks call g:NERDTreeBookmark.Write()
command! -buffer -nargs=0 EditBookmarks call g:NERDTreeBookmark.Edit()
endfunction
" FUNCTION: s:Creator._broadcastInitEvent() {{{1
function! s:Creator._broadcastInitEvent()
if exists('#User#NERDTreeInit')
doautocmd User NERDTreeInit
endif
endfunction
" FUNCTION: s:Creator.BufNamePrefix() {{{1
function! s:Creator.BufNamePrefix()
return 'NERD_tree_'
endfunction
" FUNCTION: s:Creator.CreateTabTree(a:name) {{{1
function! s:Creator.CreateTabTree(name)
let creator = s:Creator.New()
call creator.createTabTree(a:name)
endfunction
" FUNCTION: s:Creator.createTabTree(a:name) {{{1
" name: the name of a bookmark or a directory
function! s:Creator.createTabTree(name)
let l:path = self._pathForString(a:name)
" Abort if an exception was thrown (i.e., if the bookmark or directory
" does not exist).
if empty(l:path)
return
endif
" Obey the user's preferences for changing the working directory.
if g:NERDTreeChDirMode != 0
call l:path.changeToDir()
endif
if g:NERDTree.ExistsForTab()
call g:NERDTree.Close()
call self._removeTreeBufForTab()
endif
call self._createTreeWin()
call self._createNERDTree(l:path, 'tab')
call b:NERDTree.render()
call b:NERDTree.root.putCursorHere(0, 0)
call self._broadcastInitEvent()
endfunction
" FUNCTION: s:Creator.CreateWindowTree(dir) {{{1
function! s:Creator.CreateWindowTree(dir)
let creator = s:Creator.New()
call creator.createWindowTree(a:dir)
endfunction
" FUNCTION: s:Creator.createWindowTree(dir) {{{1
function! s:Creator.createWindowTree(dir)
try
let path = g:NERDTreePath.New(a:dir)
catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echo('Invalid directory name:' . a:dir)
return
endtry
"we want the directory buffer to disappear when we do the :edit below
setlocal bufhidden=wipe
let previousBuf = expand('#')
"we need a unique name for each window tree buffer to ensure they are
"all independent
exec g:NERDTreeCreatePrefix . ' edit ' . self._nextBufferName()
call self._createNERDTree(path, 'window')
let b:NERDTree._previousBuf = bufnr(previousBuf)
call self._setCommonBufOptions()
call b:NERDTree.render()
call self._broadcastInitEvent()
endfunction
" FUNCTION: s:Creator._createNERDTree(path) {{{1
function! s:Creator._createNERDTree(path, type)
let b:NERDTree = g:NERDTree.New(a:path, a:type)
" TODO: This assignment is kept for compatibility reasons. Many other
" plugins use b:NERDTreeRoot instead of b:NERDTree.root. Remove this
" assignment in the future.
let b:NERDTreeRoot = b:NERDTree.root
call b:NERDTree.root.open()
endfunction
" FUNCTION: s:Creator.CreateMirror() {{{1
function! s:Creator.CreateMirror()
let creator = s:Creator.New()
call creator.createMirror()
endfunction
" FUNCTION: s:Creator.createMirror() {{{1
function! s:Creator.createMirror()
"get the names off all the nerd tree buffers
let treeBufNames = []
for i in range(1, tabpagenr('$'))
let nextName = self._tabpagevar(i, 'NERDTreeBufName')
if nextName != -1 && (!exists('t:NERDTreeBufName') || nextName != t:NERDTreeBufName)
call add(treeBufNames, nextName)
endif
endfor
let treeBufNames = self._uniq(treeBufNames)
"map the option names (that the user will be prompted with) to the nerd
"tree buffer names
let options = {}
let i = 0
while i < len(treeBufNames)
let bufName = treeBufNames[i]
let treeRoot = getbufvar(bufName, 'NERDTree').root
let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName
let i = i + 1
endwhile
"work out which tree to mirror, if there is more than 1 then ask the user
let bufferName = ''
if len(keys(options)) > 1
let choices = ['Choose a tree to mirror']
let choices = extend(choices, sort(keys(options)))
let choice = inputlist(choices)
if choice < 1 || choice > len(options) || choice ==# ''
return
endif
let bufferName = options[sort(keys(options))[choice-1]]
elseif len(keys(options)) ==# 1
let bufferName = values(options)[0]
else
call nerdtree#echo('No trees to mirror')
return
endif
if g:NERDTree.ExistsForTab() && g:NERDTree.IsOpen()
call g:NERDTree.Close()
endif
let t:NERDTreeBufName = bufferName
call self._createTreeWin()
exec 'buffer ' . bufferName
call b:NERDTree.ui.restoreScreenState()
if !&hidden
call b:NERDTree.render()
endif
endfunction
" FUNCTION: s:Creator._createTreeWin() {{{1
" Initialize the NERDTree window. Open the window, size it properly, set all
" local options, etc.
function! s:Creator._createTreeWin()
let l:splitLocation = g:NERDTreeWinPos ==# 'left' ? 'topleft ' : 'botright '
let l:splitSize = g:NERDTreeWinSize
if !g:NERDTree.ExistsForTab()
let t:NERDTreeBufName = self._nextBufferName()
silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' new'
silent! execute 'edit ' . t:NERDTreeBufName
silent! execute 'vertical resize '. l:splitSize
else
silent! execute l:splitLocation . 'vertical ' . l:splitSize . ' split'
silent! execute 'buffer ' . t:NERDTreeBufName
endif
setlocal winfixwidth
call self._setCommonBufOptions()
if has('patch-7.4.1925')
clearjumps
endif
endfunction
" FUNCTION: s:Creator._isBufHidden(nr) {{{1
function! s:Creator._isBufHidden(nr)
redir => bufs
silent ls!
redir END
return bufs =~ a:nr . '..h'
endfunction
" FUNCTION: s:Creator.New() {{{1
function! s:Creator.New()
let newCreator = copy(self)
return newCreator
endfunction
" FUNCTION: s:Creator._nextBufferName() {{{1
" returns the buffer name for the next nerd tree
function! s:Creator._nextBufferName()
let name = s:Creator.BufNamePrefix() . self._nextBufferNumber()
return name
endfunction
" FUNCTION: s:Creator._nextBufferNumber() {{{1
" the number to add to the nerd tree buffer name to make the buf name unique
function! s:Creator._nextBufferNumber()
if !exists('s:Creator._NextBufNum')
let s:Creator._NextBufNum = 1
else
let s:Creator._NextBufNum += 1
endif
return s:Creator._NextBufNum
endfunction
" FUNCTION: s:Creator._pathForString(str) {{{1
" find a bookmark or adirectory for the given string
function! s:Creator._pathForString(str)
let path = {}
if g:NERDTreeBookmark.BookmarkExistsFor(a:str)
let path = g:NERDTreeBookmark.BookmarkFor(a:str).path
else
let dir = a:str ==# '' ? getcwd() : a:str
"hack to get an absolute path if a relative path is given
if dir =~# '^\.'
let dir = getcwd() . nerdtree#slash() . dir
endif
"hack to prevent removing slash if dir is the root of the file system.
if dir !=# '/'
let dir = g:NERDTreePath.Resolve(dir)
endif
try
let path = g:NERDTreePath.New(dir)
catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echo('No bookmark or directory found for: ' . a:str)
return {}
endtry
endif
if !path.isDirectory
let path = path.getParent()
endif
return path
endfunction
" Function: s:Creator._removeTreeBufForTab() {{{1
function! s:Creator._removeTreeBufForTab()
let buf = bufnr(t:NERDTreeBufName)
"if &hidden is not set then it will already be gone
if buf != -1
"nerdtree buf may be mirrored/displayed elsewhere
if self._isBufHidden(buf)
exec 'bwipeout ' . buf
endif
endif
unlet t:NERDTreeBufName
endfunction
" FUNCTION: s:Creator._setCommonBufOptions() {{{1
function! s:Creator._setCommonBufOptions()
" Options for a non-file/control buffer.
setlocal bufhidden=hide
setlocal buftype=nofile
setlocal noswapfile
" Options for controlling buffer/window appearance.
setlocal foldcolumn=0
setlocal foldmethod=manual
setlocal nobuflisted
setlocal nofoldenable
setlocal nolist
setlocal nospell
setlocal nowrap
if g:NERDTreeShowLineNumbers
setlocal number
else
setlocal nonumber
if v:version >= 703
setlocal norelativenumber
endif
endif
iabc <buffer>
if g:NERDTreeHighlightCursorline
setlocal cursorline
endif
call self._setupStatusline()
call self._bindMappings()
setlocal filetype=nerdtree
endfunction
" FUNCTION: s:Creator._setupStatusline() {{{1
function! s:Creator._setupStatusline()
if g:NERDTreeStatusline != -1
let &l:statusline = g:NERDTreeStatusline
endif
endfunction
" FUNCTION: s:Creator._tabpagevar(tabnr, var) {{{1
function! s:Creator._tabpagevar(tabnr, var)
let currentTab = tabpagenr()
let old_ei = &eventignore
set eventignore=all
try
exec 'tabnext ' . a:tabnr
let v = -1
if exists('t:' . a:var)
exec 'let v = t:' . a:var
endif
exec 'tabnext ' . currentTab
finally
let &eventignore = old_ei
endtry
return v
endfunction
" FUNCTION: s:Creator.ToggleTabTree(dir) {{{1
function! s:Creator.ToggleTabTree(dir)
let creator = s:Creator.New()
call creator.toggleTabTree(a:dir)
endfunction
" FUNCTION: s:Creator.toggleTabTree(dir) {{{1
" Toggles the NERD tree. I.e if the NERD tree is open, it is closed. If it is
" closed, it is restored or initialized. If dir is not empty, it will be set
" as the new root.
"
" Args:
" dir: the full path for the root node (is used if the NERD tree is being
" initialized, or to change the root to a new dir.)
function! s:Creator.toggleTabTree(dir)
if g:NERDTree.ExistsForTab()
if !g:NERDTree.IsOpen()
call self._createTreeWin()
if !empty(a:dir) && a:dir !=# b:NERDTree.root.path.str()
call self.createTabTree(a:dir)
elseif !&hidden
call b:NERDTree.render()
endif
call b:NERDTree.ui.restoreScreenState()
else
call g:NERDTree.Close()
endif
else
call self.createTabTree(a:dir)
endif
endfunction
" Function: s:Creator._uniq(list) {{{1
" returns a:list without duplicates
function! s:Creator._uniq(list)
let uniqlist = []
for elem in a:list
if index(uniqlist, elem) ==# -1
let uniqlist += [elem]
endif
endfor
return uniqlist
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,13 +0,0 @@
"CLASS: Event
"============================================================
let s:Event = {}
let g:NERDTreeEvent = s:Event
function! s:Event.New(nerdtree, subject, action, params) abort
let newObj = copy(self)
let newObj.nerdtree = a:nerdtree
let newObj.subject = a:subject
let newObj.action = a:action
let newObj.params = a:params
return newObj
endfunction

View File

@@ -1,58 +0,0 @@
"CLASS: FlagSet
"============================================================
let s:FlagSet = {}
let g:NERDTreeFlagSet = s:FlagSet
"FUNCTION: FlagSet.addFlag(scope, flag) {{{1
function! s:FlagSet.addFlag(scope, flag)
let flags = self._flagsForScope(a:scope)
if index(flags, a:flag) == -1
call add(flags, a:flag)
end
endfunction
"FUNCTION: FlagSet.clearFlags(scope) {{{1
function! s:FlagSet.clearFlags(scope)
let self._flags[a:scope] = []
endfunction
"FUNCTION: FlagSet._flagsForScope(scope) {{{1
function! s:FlagSet._flagsForScope(scope)
if !has_key(self._flags, a:scope)
let self._flags[a:scope] = []
endif
return self._flags[a:scope]
endfunction
"FUNCTION: FlagSet.New() {{{1
function! s:FlagSet.New()
let newObj = copy(self)
let newObj._flags = {}
return newObj
endfunction
"FUNCTION: FlagSet.removeFlag(scope, flag) {{{1
function! s:FlagSet.removeFlag(scope, flag)
let flags = self._flagsForScope(a:scope)
let i = index(flags, a:flag)
if i >= 0
call remove(flags, i)
endif
endfunction
"FUNCTION: FlagSet.renderToString() {{{1
function! s:FlagSet.renderToString()
let flagstring = ''
for i in values(self._flags)
let flagstring .= join(i)
endfor
if len(flagstring) == 0
return ''
endif
return '[' . flagstring . ']'
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,164 +0,0 @@
"CLASS: KeyMap
"============================================================
let s:KeyMap = {}
let g:NERDTreeKeyMap = s:KeyMap
let s:keyMaps = {}
"FUNCTION: KeyMap.All() {{{1
function! s:KeyMap.All()
let sortedKeyMaps = values(s:keyMaps)
call sort(sortedKeyMaps, s:KeyMap.Compare, s:KeyMap)
return sortedKeyMaps
endfunction
"FUNCTION: KeyMap.Compare(keyMap1, keyMap2) {{{1
function! s:KeyMap.Compare(keyMap1, keyMap2)
if a:keyMap1.key >? a:keyMap2.key
return 1
endif
if a:keyMap1.key <? a:keyMap2.key
return -1
endif
return 0
endfunction
"FUNCTION: KeyMap.FindFor(key, scope) {{{1
function! s:KeyMap.FindFor(key, scope)
return get(s:keyMaps, a:key . a:scope, {})
endfunction
"FUNCTION: KeyMap.BindAll() {{{1
function! s:KeyMap.BindAll()
for i in values(s:keyMaps)
call i.bind()
endfor
endfunction
"FUNCTION: KeyMap.bind() {{{1
function! s:KeyMap.bind()
" If the key sequence we're trying to map contains any '<>' notation, we
" must replace each of the '<' characters with '<lt>' to ensure the string
" is not translated into its corresponding keycode during the later part
" of the map command below
" :he <>
let specialNotationRegex = '\m<\([[:alnum:]_-]\+>\)'
if self.key =~# specialNotationRegex
let keymapInvokeString = substitute(self.key, specialNotationRegex, '<lt>\1', 'g')
else
let keymapInvokeString = self.key
endif
let keymapInvokeString = escape(keymapInvokeString, '\"')
let premap = self.key ==# '<LeftRelease>' ? ' <LeftRelease>' : ' '
exec 'nnoremap <buffer> <silent> '. self.key . premap . ':call nerdtree#ui_glue#invokeKeyMap("'. keymapInvokeString .'")<cr>'
endfunction
"FUNCTION: KeyMap.Remove(key, scope) {{{1
function! s:KeyMap.Remove(key, scope)
return remove(s:keyMaps, a:key . a:scope)
endfunction
"FUNCTION: KeyMap.invoke() {{{1
"Call the KeyMaps callback function
function! s:KeyMap.invoke(...)
let l:Callback = type(self.callback) ==# type(function('tr')) ? self.callback : function(self.callback)
if a:0
call l:Callback(a:1)
else
call l:Callback()
endif
endfunction
"FUNCTION: KeyMap.Invoke() {{{1
"Find a keymapping for a:key and the current scope invoke it.
"
"Scope is determined as follows:
" * if the cursor is on a dir node then DirNode
" * if the cursor is on a file node then FileNode
" * if the cursor is on a bookmark then Bookmark
"
"If a keymap has the scope of 'all' then it will be called if no other keymap
"is found for a:key and the scope.
function! s:KeyMap.Invoke(key)
"required because clicking the command window below another window still
"invokes the <LeftRelease> mapping - but changes the window cursor
"is in first
"
"TODO: remove this check when the vim bug is fixed
if !g:NERDTree.ExistsForBuf()
return {}
endif
let node = g:NERDTreeFileNode.GetSelected()
if !empty(node)
"try file node
if !node.path.isDirectory
let km = s:KeyMap.FindFor(a:key, 'FileNode')
if !empty(km)
return km.invoke(node)
endif
endif
"try dir node
if node.path.isDirectory
let km = s:KeyMap.FindFor(a:key, 'DirNode')
if !empty(km)
return km.invoke(node)
endif
endif
"try generic node
let km = s:KeyMap.FindFor(a:key, 'Node')
if !empty(km)
return km.invoke(node)
endif
endif
"try bookmark
let bm = g:NERDTreeBookmark.GetSelected()
if !empty(bm)
let km = s:KeyMap.FindFor(a:key, 'Bookmark')
if !empty(km)
return km.invoke(bm)
endif
endif
"try all
let km = s:KeyMap.FindFor(a:key, 'all')
if !empty(km)
return km.invoke()
endif
endfunction
"FUNCTION: KeyMap.Create(options) {{{1
function! s:KeyMap.Create(options)
let opts = extend({'scope': 'all', 'quickhelpText': ''}, copy(a:options))
"dont override other mappings unless the 'override' option is given
if get(opts, 'override', 0) ==# 0 && !empty(s:KeyMap.FindFor(opts['key'], opts['scope']))
return
end
let newKeyMap = copy(self)
let newKeyMap.key = opts['key']
let newKeyMap.quickhelpText = opts['quickhelpText']
let newKeyMap.callback = opts['callback']
let newKeyMap.scope = opts['scope']
call s:KeyMap.Add(newKeyMap)
endfunction
"FUNCTION: KeyMap.Add(keymap) {{{1
function! s:KeyMap.Add(keymap)
let s:keyMaps[a:keymap.key . a:keymap.scope] = a:keymap
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,211 +0,0 @@
"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
if has('nvim')
mode
else
redraw!
endif
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 keyword = matchstr(selection, '[^ ]*([^ ]*')
let shortcuts = map(copy(self.menuItems), "v:val['shortcut']")
let shortcuts[self.selection] = ' ' . keyword . ' '
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:

View File

@@ -1,118 +0,0 @@
"CLASS: MenuItem
"============================================================
let s:MenuItem = {}
let g:NERDTreeMenuItem = s:MenuItem
"FUNCTION: MenuItem.All() {{{1
"get all top level menu items
function! s:MenuItem.All()
if !exists('s:menuItems')
let s:menuItems = []
endif
return s:menuItems
endfunction
"FUNCTION: MenuItem.AllEnabled() {{{1
"get all top level menu items that are currently enabled
function! s:MenuItem.AllEnabled()
let toReturn = []
for i in s:MenuItem.All()
if i.enabled()
call add(toReturn, i)
endif
endfor
return toReturn
endfunction
"FUNCTION: MenuItem.Create(options) {{{1
"make a new menu item and add it to the global list
function! s:MenuItem.Create(options)
let newMenuItem = copy(self)
let newMenuItem.text = a:options['text']
let newMenuItem.shortcut = a:options['shortcut']
let newMenuItem.children = []
let newMenuItem.isActiveCallback = -1
if has_key(a:options, 'isActiveCallback')
let newMenuItem.isActiveCallback = a:options['isActiveCallback']
endif
let newMenuItem.callback = -1
if has_key(a:options, 'callback')
let newMenuItem.callback = a:options['callback']
endif
if has_key(a:options, 'parent')
call add(a:options['parent'].children, newMenuItem)
else
call add(s:MenuItem.All(), newMenuItem)
endif
return newMenuItem
endfunction
"FUNCTION: MenuItem.CreateSeparator(options) {{{1
"make a new separator menu item and add it to the global list
function! s:MenuItem.CreateSeparator(options)
let standard_options = { 'text': '--------------------',
\ 'shortcut': -1,
\ 'callback': -1 }
let options = extend(a:options, standard_options, 'force')
return s:MenuItem.Create(options)
endfunction
"FUNCTION: MenuItem.CreateSubmenu(options) {{{1
"make a new submenu and add it to global list
function! s:MenuItem.CreateSubmenu(options)
let standard_options = { 'callback': -1 }
let options = extend(a:options, standard_options, 'force')
return s:MenuItem.Create(options)
endfunction
"FUNCTION: MenuItem.enabled() {{{1
"return 1 if this menu item should be displayed
"
"delegates off to the isActiveCallback, and defaults to 1 if no callback was
"specified
function! s:MenuItem.enabled()
if self.isActiveCallback != -1
return type(self.isActiveCallback) == type(function('tr')) ? self.isActiveCallback() : {self.isActiveCallback}()
endif
return 1
endfunction
"FUNCTION: MenuItem.execute() {{{1
"perform the action behind this menu item, if this menuitem has children then
"display a new menu for them, otherwise deletegate off to the menuitem's
"callback
function! s:MenuItem.execute()
if len(self.children)
let mc = g:NERDTreeMenuController.New(self.children)
call mc.showMenu()
else
if self.callback != -1
if type(self.callback) == type(function('tr'))
call self.callback()
else
call {self.callback}()
endif
endif
endif
endfunction
"FUNCTION: MenuItem.isSeparator() {{{1
"return 1 if this menuitem is a separator
function! s:MenuItem.isSeparator()
return self.callback == -1 && self.children == []
endfunction
"FUNCTION: MenuItem.isSubmenu() {{{1
"return 1 if this menuitem is a submenu
function! s:MenuItem.isSubmenu()
return self.callback == -1 && !empty(self.children)
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,209 +0,0 @@
"CLASS: NERDTree
"============================================================
let s:NERDTree = {}
let g:NERDTree = s:NERDTree
"FUNCTION: s:NERDTree.AddPathFilter() {{{1
function! s:NERDTree.AddPathFilter(callback)
call add(s:NERDTree.PathFilters(), a:callback)
endfunction
"FUNCTION: s:NERDTree.changeRoot(node) {{{1
function! s:NERDTree.changeRoot(node)
if a:node.path.isDirectory
let self.root = a:node
else
call a:node.cacheParent()
let self.root = a:node.parent
endif
call self.root.open()
"change dir to the dir of the new root if instructed to
if g:NERDTreeChDirMode >= 2
call self.root.path.changeToDir()
endif
call self.render()
call self.root.putCursorHere(0, 0)
if exists('#User#NERDTreeNewRoot')
doautocmd User NERDTreeNewRoot
endif
endfunction
"FUNCTION: s:NERDTree.Close() {{{1
"Closes the tab tree window for this tab
function! s:NERDTree.Close()
if !s:NERDTree.IsOpen()
return
endif
if winnr('$') !=# 1
" Use the window ID to identify the currently active window or fall
" back on the buffer ID if win_getid/win_gotoid are not available, in
" which case we'll focus an arbitrary window showing the buffer.
let l:useWinId = exists('*win_getid') && exists('*win_gotoid')
if winnr() ==# s:NERDTree.GetWinNum()
call nerdtree#exec('wincmd p', 1)
let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr('')
call nerdtree#exec('wincmd p', 1)
else
let l:activeBufOrWin = l:useWinId ? win_getid() : bufnr('')
endif
call nerdtree#exec(s:NERDTree.GetWinNum() . ' wincmd w', 1)
call nerdtree#exec('close', 0)
if l:useWinId
call nerdtree#exec('call win_gotoid(' . l:activeBufOrWin . ')', 0)
else
call nerdtree#exec(bufwinnr(l:activeBufOrWin) . ' wincmd w', 0)
endif
else
close
endif
endfunction
"FUNCTION: s:NERDTree.CursorToBookmarkTable(){{{1
"Places the cursor at the top of the bookmarks table
function! s:NERDTree.CursorToBookmarkTable()
if !b:NERDTree.ui.getShowBookmarks()
throw 'NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active'
endif
if g:NERDTreeMinimalUI
return cursor(1, 2)
endif
let rootNodeLine = b:NERDTree.ui.getRootLineNum()
let line = 1
while getline(line) !~# '^>-\+Bookmarks-\+$'
let line = line + 1
if line >= rootNodeLine
throw 'NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table'
endif
endwhile
call cursor(line, 2)
endfunction
"FUNCTION: s:NERDTree.CursorToTreeWin(){{{1
"Places the cursor in the nerd tree window
function! s:NERDTree.CursorToTreeWin(...)
call g:NERDTree.MustBeOpen()
call nerdtree#exec(g:NERDTree.GetWinNum() . 'wincmd w', a:0 >0 ? a:1 : 1)
endfunction
" Function: s:NERDTree.ExistsForBuffer() {{{1
" Returns 1 if a nerd tree root exists in the current buffer
function! s:NERDTree.ExistsForBuf()
return exists('b:NERDTree')
endfunction
" Function: s:NERDTree.ExistsForTab() {{{1
" Returns 1 if a nerd tree root exists in the current tab
function! s:NERDTree.ExistsForTab()
if !exists('t:NERDTreeBufName')
return
end
"check b:NERDTree is still there and hasn't been e.g. :bdeleted
return !empty(getbufvar(bufnr(t:NERDTreeBufName), 'NERDTree'))
endfunction
function! s:NERDTree.ForCurrentBuf()
if s:NERDTree.ExistsForBuf()
return b:NERDTree
else
return {}
endif
endfunction
"FUNCTION: s:NERDTree.ForCurrentTab() {{{1
function! s:NERDTree.ForCurrentTab()
if !s:NERDTree.ExistsForTab()
return
endif
let bufnr = bufnr(t:NERDTreeBufName)
return getbufvar(bufnr, 'NERDTree')
endfunction
"FUNCTION: s:NERDTree.getRoot() {{{1
function! s:NERDTree.getRoot()
return self.root
endfunction
"FUNCTION: s:NERDTree.GetWinNum() {{{1
"gets the nerd tree window number for this tab
function! s:NERDTree.GetWinNum()
if exists('t:NERDTreeBufName')
return bufwinnr(t:NERDTreeBufName)
endif
" If WindowTree, there is no t:NERDTreeBufName variable. Search all windows.
for w in range(1,winnr('$'))
if bufname(winbufnr(w)) =~# '^' . g:NERDTreeCreator.BufNamePrefix() . '\d\+$'
return w
endif
endfor
return -1
endfunction
"FUNCTION: s:NERDTree.IsOpen() {{{1
function! s:NERDTree.IsOpen()
return s:NERDTree.GetWinNum() !=# -1
endfunction
"FUNCTION: s:NERDTree.isTabTree() {{{1
function! s:NERDTree.isTabTree()
return self._type ==# 'tab'
endfunction
"FUNCTION: s:NERDTree.isWinTree() {{{1
function! s:NERDTree.isWinTree()
return self._type ==# 'window'
endfunction
"FUNCTION: s:NERDTree.MustBeOpen() {{{1
function! s:NERDTree.MustBeOpen()
if !s:NERDTree.IsOpen()
throw 'NERDTree.TreeNotOpen'
endif
endfunction
"FUNCTION: s:NERDTree.New() {{{1
function! s:NERDTree.New(path, type)
let newObj = copy(self)
let newObj.ui = g:NERDTreeUI.New(newObj)
let newObj.root = g:NERDTreeDirNode.New(a:path, newObj)
let newObj._type = a:type
return newObj
endfunction
"FUNCTION: s:NERDTree.PathFilters() {{{1
function! s:NERDTree.PathFilters()
if !exists('s:NERDTree._PathFilters')
let s:NERDTree._PathFilters = []
endif
return s:NERDTree._PathFilters
endfunction
"FUNCTION: s:NERDTree.previousBuf() {{{1
function! s:NERDTree.previousBuf()
return self._previousBuf
endfunction
function! s:NERDTree.setPreviousBuf(bnum)
let self._previousBuf = a:bnum
endfunction
"FUNCTION: s:NERDTree.render() {{{1
"A convenience function - since this is called often
function! s:NERDTree.render()
call self.ui.render()
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,35 +0,0 @@
"CLASS: Notifier
"============================================================
let s:Notifier = {}
function! s:Notifier.AddListener(event, funcname)
let listeners = s:Notifier.GetListenersForEvent(a:event)
if listeners == []
let listenersMap = s:Notifier.GetListenersMap()
let listenersMap[a:event] = listeners
endif
call add(listeners, a:funcname)
endfunction
function! s:Notifier.NotifyListeners(event, path, nerdtree, params)
let event = g:NERDTreeEvent.New(a:nerdtree, a:path, a:event, a:params)
for Listener in s:Notifier.GetListenersForEvent(a:event)
let l:Callback = type(Listener) == type(function('tr')) ? Listener : function(Listener)
call l:Callback(event)
endfor
endfunction
function! s:Notifier.GetListenersMap()
if !exists('s:refreshListenersMap')
let s:refreshListenersMap = {}
endif
return s:refreshListenersMap
endfunction
function! s:Notifier.GetListenersForEvent(name)
let listenersMap = s:Notifier.GetListenersMap()
return get(listenersMap, a:name, [])
endfunction
let g:NERDTreePathNotifier = deepcopy(s:Notifier)

View File

@@ -1,326 +0,0 @@
" ============================================================================
" CLASS: Opener
"
" The Opener class defines an API for 'opening' operations.
" ============================================================================
let s:Opener = {}
let g:NERDTreeOpener = s:Opener
" FUNCTION: s:Opener._bufInWindows(bnum) {{{1
" [[STOLEN FROM VTREEEXPLORER.VIM]]
" Determine the number of windows open to this buffer number.
" Care of Yegappan Lakshman. Thanks!
"
" Args:
" bnum: the subject buffers buffer number
function! s:Opener._bufInWindows(bnum)
let cnt = 0
let winnum = 1
while 1
let bufnum = winbufnr(winnum)
if bufnum < 0
break
endif
if bufnum ==# a:bnum
let cnt = cnt + 1
endif
let winnum = winnum + 1
endwhile
return cnt
endfunction
" FUNCTION: Opener._checkToCloseTree(newtab) {{{1
" Check the class options to see if the tree should be closed now.
"
" Args:
" a:newtab - boolean. If set, only close the tree now if we are opening the
" target in a new tab. This is needed because we have to close tree before we
" leave the tab
function! s:Opener._checkToCloseTree(newtab)
if self._keepopen
return
endif
if (a:newtab && self._where ==# 't') || !a:newtab
call g:NERDTree.Close()
endif
endfunction
" FUNCTION: s:Opener._firstUsableWindow() {{{1
" find the window number of the first normal window
function! s:Opener._firstUsableWindow()
let i = 1
while i <= winnr('$')
let bnum = winbufnr(i)
if bnum !=# -1 && getbufvar(bnum, '&buftype') ==# ''
\ && !getwinvar(i, '&previewwindow')
\ && (!getbufvar(bnum, '&modified') || &hidden)
return i
endif
let i += 1
endwhile
return -1
endfunction
" FUNCTION: Opener._gotoTargetWin() {{{1
function! s:Opener._gotoTargetWin()
if b:NERDTree.isWinTree()
if self._where ==# 'v'
call self._newVSplit()
elseif self._where ==# 'h'
call self._newSplit()
elseif self._where ==# 't'
tabnew
endif
else
call self._checkToCloseTree(1)
if self._where ==# 'v'
call self._newVSplit()
elseif self._where ==# 'h'
call self._newSplit()
elseif self._where ==# 't'
tabnew
elseif self._where ==# 'p'
call self._previousWindow()
endif
call self._checkToCloseTree(0)
endif
endfunction
" FUNCTION: s:Opener._isWindowUsable(winnumber) {{{1
" Returns 0 if opening a file from the tree in the given window requires it to
" be split, 1 otherwise
"
" Args:
" winnumber: the number of the window in question
function! s:Opener._isWindowUsable(winnumber)
"gotta split if theres only one window (i.e. the NERD tree)
if winnr('$') ==# 1
return 0
endif
let oldwinnr = winnr()
call nerdtree#exec(a:winnumber . 'wincmd p', 1)
let specialWindow = getbufvar('%', '&buftype') !=# '' || getwinvar('%', '&previewwindow')
let modified = &modified
call nerdtree#exec(oldwinnr . 'wincmd p', 1)
"if its a special window e.g. quickfix or another explorer plugin then we
"have to split
if specialWindow
return 0
endif
if &hidden
return 1
endif
return !modified || self._bufInWindows(winbufnr(a:winnumber)) >= 2
endfunction
" FUNCTION: Opener.New(path, opts) {{{1
" Instantiate a new NERDTreeOpener object.
" Args:
" a:path: the path object that is to be opened
" a:opts: a dictionary containing the following optional keys...
" 'where': specifies whether the node should be opened in new split, in
" a new tab or, in the last window; takes values 'v', 'h', or 't'
" 'reuse': if file is already shown in a window, jump there; takes values
" 'all', 'currenttab', or empty
" 'keepopen': boolean (0 or 1); if true, the tree window will not be closed
" 'stay': boolean (0 or 1); if true, remain in tree window after opening
function! s:Opener.New(path, opts)
let l:newOpener = copy(self)
let l:newOpener._keepopen = nerdtree#has_opt(a:opts, 'keepopen')
let l:newOpener._nerdtree = b:NERDTree
let l:newOpener._path = a:path
let l:newOpener._reuse = has_key(a:opts, 'reuse') ? a:opts['reuse'] : ''
let l:newOpener._stay = nerdtree#has_opt(a:opts, 'stay')
let l:newOpener._where = has_key(a:opts, 'where') ? a:opts['where'] : ''
call l:newOpener._saveCursorPos()
return l:newOpener
endfunction
" FUNCTION: Opener._newSplit() {{{1
function! s:Opener._newSplit()
let onlyOneWin = (winnr('$') ==# 1)
let savesplitright = &splitright
if onlyOneWin
let &splitright = (g:NERDTreeWinPos ==# 'left')
endif
" If only one window (ie. NERDTree), split vertically instead.
let splitMode = onlyOneWin ? 'vertical' : ''
" Open the new window
try
call nerdtree#exec('wincmd p', 1)
call nerdtree#exec(splitMode . ' split',1)
catch /^Vim\%((\a\+)\)\=:E37/
call g:NERDTree.CursorToTreeWin()
throw 'NERDTree.FileAlreadyOpenAndModifiedError: '. self._path.str() .' is already open and modified.'
catch /^Vim\%((\a\+)\)\=:/
"do nothing
endtry
"resize the tree window if no other window was open before
if onlyOneWin
call nerdtree#exec('wincmd p', 1)
call nerdtree#exec('silent '. splitMode .' resize '. g:NERDTreeWinSize, 1)
call nerdtree#exec('wincmd p', 0)
endif
let &splitright=savesplitright
endfunction
" FUNCTION: Opener._newVSplit() {{{1
function! s:Opener._newVSplit()
let l:winwidth = winwidth('.')
let onlyOneWin = (winnr('$') ==# 1)
let savesplitright = &splitright
if onlyOneWin
let &splitright = (g:NERDTreeWinPos ==# 'left')
let l:winwidth = g:NERDTreeWinSize
endif
call nerdtree#exec('wincmd p', 1)
call nerdtree#exec('vsplit', 1)
let l:currentWindowNumber = winnr()
" Restore the NERDTree to its original width.
call g:NERDTree.CursorToTreeWin()
execute 'silent vertical resize ' . l:winwidth
call nerdtree#exec(l:currentWindowNumber . 'wincmd w', 0)
let &splitright=savesplitright
endfunction
" FUNCTION: Opener.open(target) {{{1
function! s:Opener.open(target)
if self._path.isDirectory
call self._openDirectory(a:target)
return
endif
call self._openFile()
endfunction
" FUNCTION: Opener._openFile() {{{1
function! s:Opener._openFile()
if !self._stay && self._keepopen && get(b:, 'NERDTreeZoomed', 0)
call b:NERDTree.ui.toggleZoom()
endif
if self._reuseWindow()
return
endif
call self._gotoTargetWin()
if self._stay
silent call self._path.edit()
call self._restoreCursorPos()
return
endif
call self._path.edit()
endfunction
" FUNCTION: Opener._openDirectory(node) {{{1
function! s:Opener._openDirectory(node)
call self._gotoTargetWin()
if self._nerdtree.isWinTree()
call g:NERDTreeCreator.CreateWindowTree(a:node.path.str())
else
if empty(self._where)
call b:NERDTree.changeRoot(a:node)
elseif self._where ==# 't'
call g:NERDTreeCreator.CreateTabTree(a:node.path.str())
else
call g:NERDTreeCreator.CreateWindowTree(a:node.path.str())
endif
endif
if self._stay
call self._restoreCursorPos()
endif
endfunction
" FUNCTION: Opener._previousWindow() {{{1
function! s:Opener._previousWindow()
if !self._isWindowUsable(winnr('#')) && self._firstUsableWindow() ==# -1
call self._newSplit()
else
try
if !self._isWindowUsable(winnr('#'))
call nerdtree#exec(self._firstUsableWindow() . 'wincmd w', 1)
else
call nerdtree#exec('wincmd p', 1)
endif
catch /^Vim\%((\a\+)\)\=:E37/
call g:NERDTree.CursorToTreeWin()
throw 'NERDTree.FileAlreadyOpenAndModifiedError: '. self._path.str() .' is already open and modified.'
catch /^Vim\%((\a\+)\)\=:/
echo v:exception
endtry
endif
endfunction
" FUNCTION: Opener._restoreCursorPos() {{{1
function! s:Opener._restoreCursorPos()
call nerdtree#exec(self._tabnr . 'tabnext', 1)
call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w', 1)
endfunction
" FUNCTION: Opener._reuseWindow() {{{1
" put the cursor in the first window we find for this file
"
" return 1 if we were successful
function! s:Opener._reuseWindow()
if empty(self._reuse)
return 0
endif
"check the current tab for the window
let winnr = bufwinnr('^' . self._path.str() . '$')
if winnr !=# -1
call nerdtree#exec(winnr . 'wincmd w', 0)
call self._checkToCloseTree(0)
return 1
endif
if self._reuse ==# 'currenttab'
return 0
endif
"check other tabs
let tabnr = self._path.tabnr()
if tabnr
call self._checkToCloseTree(1)
call nerdtree#exec(tabnr . 'tabnext', 1)
let winnr = bufwinnr('^' . self._path.str() . '$')
call nerdtree#exec(winnr . 'wincmd w', 0)
return 1
endif
return 0
endfunction
" FUNCTION: Opener._saveCursorPos() {{{1
function! s:Opener._saveCursorPos()
let self._bufnr = bufnr('')
let self._tabnr = tabpagenr()
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,852 +0,0 @@
" ============================================================================
" CLASS: Path
"
" The Path class provides an abstracted representation of a file system
" pathname. Various operations on pathnames are provided and a number of
" representations of a given path name can be accessed here.
" ============================================================================
let s:Path = {}
let g:NERDTreePath = s:Path
" FUNCTION: Path.AbsolutePathFor(pathStr) {{{1
function! s:Path.AbsolutePathFor(pathStr)
let l:prependWorkingDir = 0
if nerdtree#runningWindows()
let l:prependWorkingDir = a:pathStr !~# '^.:\(\\\|\/\)\?' && a:pathStr !~# '^\(\\\\\|\/\/\)'
else
let l:prependWorkingDir = a:pathStr !~# '^/'
endif
let l:result = a:pathStr
if l:prependWorkingDir
let l:result = getcwd()
if l:result[-1:] == nerdtree#slash()
let l:result = l:result . a:pathStr
else
let l:result = l:result . nerdtree#slash() . a:pathStr
endif
endif
return l:result
endfunction
" FUNCTION: Path.bookmarkNames() {{{1
function! s:Path.bookmarkNames()
if !exists('self._bookmarkNames')
call self.cacheDisplayString()
endif
return self._bookmarkNames
endfunction
" FUNCTION: Path.cacheDisplayString() {{{1
function! s:Path.cacheDisplayString() abort
let self.cachedDisplayString = g:NERDTreeNodeDelimiter . self.getLastPathComponent(1)
if self.isExecutable
let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . '*'
endif
let self._bookmarkNames = []
for i in g:NERDTreeBookmark.Bookmarks()
if i.path.equals(self)
call add(self._bookmarkNames, i.name)
endif
endfor
if !empty(self._bookmarkNames) && g:NERDTreeMarkBookmarks ==# 1
let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' {' . join(self._bookmarkNames) . '}'
endif
if self.isSymLink
let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' -> ' . self.symLinkDest
endif
if self.isReadOnly
let self.cachedDisplayString = self.addDelimiter(self.cachedDisplayString) . ' ['.g:NERDTreeGlyphReadOnly.']'
endif
endfunction
" FUNCTION: Path.addDelimiter() {{{1
function! s:Path.addDelimiter(line)
if a:line =~# '\(.*' . g:NERDTreeNodeDelimiter . '\)\{2}'
return a:line
else
return a:line . g:NERDTreeNodeDelimiter
endif
endfunction
" FUNCTION: Path.changeToDir() {{{1
function! s:Path.changeToDir()
let dir = self.str({'format': 'Cd'})
if self.isDirectory ==# 0
let dir = self.getParent().str({'format': 'Cd'})
endif
try
if g:NERDTreeUseTCD && exists(':tcd') ==# 2
execute 'tcd ' . dir
call nerdtree#echo("Tab's CWD is now: " . getcwd())
else
execute 'cd ' . dir
call nerdtree#echo('CWD is now: ' . getcwd())
endif
catch
throw 'NERDTree.PathChangeError: cannot change CWD to ' . dir
endtry
endfunction
" FUNCTION: Path.Create(fullpath) {{{1
"
" Factory method.
"
" Creates a path object with the given path. The path is also created on the
" filesystem. If the path already exists, a NERDTree.Path.Exists exception is
" thrown. If any other errors occur, a NERDTree.Path exception is thrown.
"
" Args:
" fullpath: the full filesystem path to the file/dir to create
function! s:Path.Create(fullpath)
"bail if the a:fullpath already exists
if isdirectory(a:fullpath) || filereadable(a:fullpath)
throw "NERDTree.CreatePathError: Directory Exists: '" . a:fullpath . "'"
endif
try
"if it ends with a slash, assume its a dir create it
if a:fullpath =~# '\(\\\|\/\)$'
"whack the trailing slash off the end if it exists
let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '')
call mkdir(fullpath, 'p')
"assume its a file and create
else
call s:Path.createParentDirectories(a:fullpath)
call writefile([], a:fullpath)
endif
catch
throw "NERDTree.CreatePathError: Could not create path: '" . a:fullpath . "'"
endtry
return s:Path.New(a:fullpath)
endfunction
" FUNCTION: Path.copy(dest) {{{1
"
" Copies the file/dir represented by this Path to the given location
"
" Args:
" dest: the location to copy this dir/file to
function! s:Path.copy(dest)
if !s:Path.CopyingSupported()
throw 'NERDTree.CopyingNotSupportedError: Copying is not supported on this OS'
endif
call s:Path.createParentDirectories(a:dest)
if exists('g:NERDTreeCopyCmd')
let cmd_prefix = g:NERDTreeCopyCmd
else
let cmd_prefix = (self.isDirectory ? g:NERDTreeCopyDirCmd : g:NERDTreeCopyFileCmd)
endif
let cmd = cmd_prefix . ' ' . shellescape(self.str()) . ' ' . shellescape(a:dest)
let success = system(cmd)
if v:shell_error !=# 0
throw "NERDTree.CopyError: Could not copy '". self.str() ."' to: '" . a:dest . "'"
endif
endfunction
" FUNCTION: Path.CopyingSupported() {{{1
"
" returns 1 if copying is supported for this OS
function! s:Path.CopyingSupported()
return exists('g:NERDTreeCopyCmd') || (exists('g:NERDTreeCopyDirCmd') && exists('g:NERDTreeCopyFileCmd'))
endfunction
" FUNCTION: Path.copyingWillOverwrite(dest) {{{1
"
" returns 1 if copy this path to the given location will cause files to
" overwritten
"
" Args:
" dest: the location this path will be copied to
function! s:Path.copyingWillOverwrite(dest)
if filereadable(a:dest)
return 1
endif
if isdirectory(a:dest)
let path = s:Path.JoinPathStrings(a:dest, self.getLastPathComponent(0))
if filereadable(path)
return 1
endif
endif
endfunction
" FUNCTION: Path.createParentDirectories(path) {{{1
"
" create parent directories for this path if needed
" without throwing any errors if those directories already exist
"
" Args:
" path: full path of the node whose parent directories may need to be created
function! s:Path.createParentDirectories(path)
let dir_path = fnamemodify(a:path, ':h')
if !isdirectory(dir_path)
call mkdir(dir_path, 'p')
endif
endfunction
" FUNCTION: Path.delete() {{{1
"
" Deletes the file or directory represented by this path.
"
" Throws NERDTree.Path.Deletion exceptions
function! s:Path.delete()
if self.isDirectory
let cmd = g:NERDTreeRemoveDirCmd . self.str({'escape': 1})
let success = system(cmd)
if v:shell_error !=# 0
throw "NERDTree.PathDeletionError: Could not delete directory: '" . self.str() . "'"
endif
else
if exists('g:NERDTreeRemoveFileCmd')
let cmd = g:NERDTreeRemoveFileCmd . self.str({'escape': 1})
let success = system(cmd)
else
let success = delete(self.str())
endif
if success !=# 0
throw "NERDTree.PathDeletionError: Could not delete file: '" . self.str() . "'"
endif
endif
"delete all bookmarks for this path
for i in self.bookmarkNames()
let bookmark = g:NERDTreeBookmark.BookmarkFor(i)
call bookmark.delete()
endfor
endfunction
" FUNCTION: Path.displayString() {{{1
"
" Returns a string that specifies how the path should be represented as a
" string
function! s:Path.displayString()
if self.cachedDisplayString ==# ''
call self.cacheDisplayString()
endif
return self.cachedDisplayString
endfunction
" FUNCTION: Path.edit() {{{1
function! s:Path.edit()
let l:bufname = self.str({'format': 'Edit'})
if bufname('%') !=# l:bufname
exec 'edit ' . l:bufname
endif
endfunction
" FUNCTION: Path.extractDriveLetter(fullpath) {{{1
"
" If running windows, cache the drive letter for this path
function! s:Path.extractDriveLetter(fullpath)
if nerdtree#runningWindows()
if a:fullpath =~# '^\(\\\\\|\/\/\)'
"For network shares, the 'drive' consists of the first two parts of the path, i.e. \\boxname\share
let self.drive = substitute(a:fullpath, '^\(\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\).*', '\1', '')
let self.drive = substitute(self.drive, '/', '\', 'g')
else
let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '')
endif
else
let self.drive = ''
endif
endfunction
" FUNCTION: Path.exists() {{{1
" return 1 if this path points to a location that is readable or is a directory
function! s:Path.exists()
let p = self.str()
return filereadable(p) || isdirectory(p)
endfunction
" FUNCTION: Path._escChars() {{{1
function! s:Path._escChars()
if nerdtree#runningWindows()
return " `\|\"#%&,?()\*^<>$"
endif
return " \\`\|\"#%&,?()\*^<>[]{}$"
endfunction
" FUNCTION: Path.getDir() {{{1
"
" Returns this path if it is a directory, else this paths parent.
"
" Return:
" a Path object
function! s:Path.getDir()
if self.isDirectory
return self
else
return self.getParent()
endif
endfunction
" FUNCTION: Path.getParent() {{{1
"
" Returns a new path object for this paths parent
"
" Return:
" a new Path object
function! s:Path.getParent()
if nerdtree#runningWindows()
let path = self.drive . '\' . join(self.pathSegments[0:-2], '\')
else
let path = '/'. join(self.pathSegments[0:-2], '/')
endif
return s:Path.New(path)
endfunction
" FUNCTION: Path.getLastPathComponent(dirSlash) {{{1
"
" Gets the last part of this path.
"
" Args:
" dirSlash: if 1 then a trailing slash will be added to the returned value for
" directory nodes.
function! s:Path.getLastPathComponent(dirSlash)
if empty(self.pathSegments)
return ''
endif
let toReturn = self.pathSegments[-1]
if a:dirSlash && self.isDirectory
let toReturn = toReturn . '/'
endif
return toReturn
endfunction
" FUNCTION: Path.getSortOrderIndex() {{{1
" returns the index of the pattern in g:NERDTreeSortOrder that this path matches
function! s:Path.getSortOrderIndex()
let i = 0
while i < len(g:NERDTreeSortOrder)
if g:NERDTreeSortOrder[i] !~? '\[\[-\?\(timestamp\|size\|extension\)\]\]' &&
\ self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i]
return i
endif
let i = i + 1
endwhile
return index(g:NERDTreeSortOrder, '*')
endfunction
" FUNCTION: Path._splitChunks(path) {{{1
" returns a list of path chunks
function! s:Path._splitChunks(path)
let chunks = split(a:path, '\(\D\+\|\d\+\)\zs')
let i = 0
while i < len(chunks)
"convert number literals to numbers
if match(chunks[i], '^\d\+$') ==# 0
let chunks[i] = str2nr(chunks[i])
endif
let i = i + 1
endwhile
return chunks
endfunction
" FUNCTION: Path.getSortKey() {{{1
" returns a key used in compare function for sorting
function! s:Path.getSortKey()
if !exists('self._sortKey') || g:NERDTreeSortOrder !=# g:NERDTreeOldSortOrder
" Look for file metadata tags: [[timestamp]], [[extension]], [[size]]
let metadata = []
for tag in g:NERDTreeSortOrder
if tag =~? '\[\[-\?timestamp\]\]'
let metadata += [self.isDirectory ? 0 : getftime(self.str()) * (tag =~# '-' ? -1 : 1)]
elseif tag =~? '\[\[-\?size\]\]'
let metadata += [self.isDirectory ? 0 : getfsize(self.str()) * (tag =~# '-' ? -1 : 1)]
elseif tag =~? '\[\[extension\]\]'
let extension = matchstr(self.getLastPathComponent(0), '[^.]\+\.\zs[^.]\+$')
let metadata += [self.isDirectory ? '' : (extension ==# '' ? nr2char(str2nr('0x10ffff',16)) : extension)]
endif
endfor
if g:NERDTreeSortOrder[0] =~# '\[\[.*\]\]'
" Apply tags' sorting first if specified first.
let self._sortKey = metadata + [self.getSortOrderIndex()]
else
" Otherwise, do regex grouping first.
let self._sortKey = [self.getSortOrderIndex()] + metadata
endif
let path = self.getLastPathComponent(0)
if !g:NERDTreeSortHiddenFirst
let path = substitute(path, '^[._]', '', '')
endif
if !g:NERDTreeCaseSensitiveSort
let path = tolower(path)
endif
call extend(self._sortKey, (g:NERDTreeNaturalSort ? self._splitChunks(path) : [path]))
endif
return self._sortKey
endfunction
" FUNCTION: Path.isHiddenUnder(path) {{{1
function! s:Path.isHiddenUnder(path)
if !self.isUnder(a:path)
return 0
endif
let l:startIndex = len(a:path.pathSegments)
let l:segments = self.pathSegments[l:startIndex : ]
for l:segment in l:segments
if l:segment =~# '^\.'
return 1
endif
endfor
return 0
endfunction
" FUNCTION: Path.isUnixHiddenFile() {{{1
" check for unix hidden files
function! s:Path.isUnixHiddenFile()
return self.getLastPathComponent(0) =~# '^\.'
endfunction
" FUNCTION: Path.isUnixHiddenPath() {{{1
" check for unix path with hidden components
function! s:Path.isUnixHiddenPath()
if self.getLastPathComponent(0) =~# '^\.'
return 1
else
for segment in self.pathSegments
if segment =~# '^\.'
return 1
endif
endfor
return 0
endif
endfunction
" FUNCTION: Path.ignore(nerdtree) {{{1
" returns true if this path should be ignored
function! s:Path.ignore(nerdtree)
"filter out the user specified paths to ignore
if a:nerdtree.ui.isIgnoreFilterEnabled()
for i in g:NERDTreeIgnore
if self._ignorePatternMatches(i)
return 1
endif
endfor
for l:Callback in g:NERDTree.PathFilters()
let l:Callback = type(l:Callback) ==# type(function('tr')) ? l:Callback : function(l:Callback)
if l:Callback({'path': self, 'nerdtree': a:nerdtree})
return 1
endif
endfor
endif
"dont show hidden files unless instructed to
if !a:nerdtree.ui.getShowHidden() && self.isUnixHiddenFile()
return 1
endif
if a:nerdtree.ui.getShowFiles() ==# 0 && self.isDirectory ==# 0
return 1
endif
return 0
endfunction
" FUNCTION: Path._ignorePatternMatches(pattern) {{{1
" returns true if this path matches the given ignore pattern
function! s:Path._ignorePatternMatches(pattern)
let pat = a:pattern
if strpart(pat,len(pat)-8) ==# '[[path]]'
let pat = strpart(pat,0, len(pat)-8)
return self.str() =~# pat
elseif strpart(pat,len(pat)-7) ==# '[[dir]]'
if !self.isDirectory
return 0
endif
let pat = strpart(pat,0, len(pat)-7)
elseif strpart(pat,len(pat)-8) ==# '[[file]]'
if self.isDirectory
return 0
endif
let pat = strpart(pat,0, len(pat)-8)
endif
return self.getLastPathComponent(0) =~# pat
endfunction
" FUNCTION: Path.isAncestor(path) {{{1
" return 1 if this path is somewhere above the given path in the filesystem.
"
" a:path should be a dir
function! s:Path.isAncestor(child)
return a:child.isUnder(self)
endfunction
" FUNCTION: Path.isUnder(path) {{{1
" return 1 if this path is somewhere under the given path in the filesystem.
function! s:Path.isUnder(parent)
if a:parent.isDirectory ==# 0
return 0
endif
if nerdtree#runningWindows() && a:parent.drive !=# self.drive
return 0
endif
let l:this_count = len(self.pathSegments)
if l:this_count ==# 0
return 0
endif
let l:that_count = len(a:parent.pathSegments)
if l:that_count ==# 0
return 1
endif
if l:that_count >= l:this_count
return 0
endif
for i in range(0, l:that_count-1)
if self.pathSegments[i] !=# a:parent.pathSegments[i]
return 0
endif
endfor
return 1
endfunction
" FUNCTION: Path.JoinPathStrings(...) {{{1
function! s:Path.JoinPathStrings(...)
let components = []
for i in a:000
let components = extend(components, split(i, '/'))
endfor
return '/' . join(components, '/')
endfunction
" FUNCTION: Path.equals() {{{1
"
" Determines whether 2 path objects are "equal".
" They are equal if the paths they represent are the same
"
" 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
endfunction
" FUNCTION: Path.New(pathStr) {{{1
function! s:Path.New(pathStr)
let l:newPath = copy(self)
call l:newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:pathStr))
let l:newPath.cachedDisplayString = ''
let l:newPath.flagSet = g:NERDTreeFlagSet.New()
return l:newPath
endfunction
" FUNCTION: Path.Resolve() {{{1
" Invoke the vim resolve() function and return the result
" This is necessary because in some versions of vim resolve() removes trailing
" slashes while in other versions it doesn't. This always removes the trailing
" slash
function! s:Path.Resolve(path)
let tmp = resolve(a:path)
return tmp =~# '.\+/$' ? substitute(tmp, '/$', '', '') : tmp
endfunction
" FUNCTION: Path.readInfoFromDisk(fullpath) {{{1
"
"
" Throws NERDTree.Path.InvalidArguments exception.
function! s:Path.readInfoFromDisk(fullpath)
call self.extractDriveLetter(a:fullpath)
let fullpath = s:Path.WinToUnixPath(a:fullpath)
if getftype(fullpath) ==# 'fifo'
throw 'NERDTree.InvalidFiletypeError: Cant handle FIFO files: ' . a:fullpath
endif
let self.pathSegments = filter(split(fullpath, '/'), '!empty(v:val)')
let self.isReadOnly = 0
if isdirectory(a:fullpath)
let self.isDirectory = 1
elseif filereadable(a:fullpath)
let self.isDirectory = 0
let self.isReadOnly = filewritable(a:fullpath) ==# 0
else
throw 'NERDTree.InvalidArgumentsError: Invalid path = ' . a:fullpath
endif
let self.isExecutable = 0
if !self.isDirectory
let self.isExecutable = getfperm(a:fullpath) =~# 'x'
endif
"grab the last part of the path (minus the trailing slash)
let lastPathComponent = self.getLastPathComponent(0)
"get the path to the new node with the parent dir fully resolved
let hardPath = s:Path.Resolve(self.strTrunk()) . '/' . lastPathComponent
"if the last part of the path is a symlink then flag it as such
let self.isSymLink = (s:Path.Resolve(hardPath) !=# hardPath)
if self.isSymLink
let self.symLinkDest = s:Path.Resolve(fullpath)
"if the link is a dir then slap a / on the end of its dest
if isdirectory(self.symLinkDest)
"we always wanna treat MS windows shortcuts as files for
"simplicity
if hardPath !~# '\.lnk$'
let self.symLinkDest = self.symLinkDest . '/'
endif
endif
endif
endfunction
" FUNCTION: Path.refresh(nerdtree) {{{1
function! s:Path.refresh(nerdtree)
call self.readInfoFromDisk(self.str())
call g:NERDTreePathNotifier.NotifyListeners('refresh', self, a:nerdtree, {})
call self.cacheDisplayString()
endfunction
" FUNCTION: Path.refreshFlags(nerdtree) {{{1
function! s:Path.refreshFlags(nerdtree)
call g:NERDTreePathNotifier.NotifyListeners('refreshFlags', self, a:nerdtree, {})
call self.cacheDisplayString()
endfunction
" FUNCTION: Path.rename() {{{1
"
" Renames this node on the filesystem
function! s:Path.rename(newPath)
if a:newPath ==# ''
throw 'NERDTree.InvalidArgumentsError: Invalid newPath for renaming = '. a:newPath
endif
call s:Path.createParentDirectories(a:newPath)
let success = rename(self.str(), a:newPath)
if success !=# 0
throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath
endif
call self.readInfoFromDisk(a:newPath)
for i in self.bookmarkNames()
let b = g:NERDTreeBookmark.BookmarkFor(i)
call b.setPath(copy(self))
endfor
call g:NERDTreeBookmark.Write()
endfunction
" FUNCTION: Path.str() {{{1
" Return a string representation of this Path object.
"
" Args:
" This function takes a single dictionary (optional) with keys and values that
" specify how the returned pathname should be formatted.
"
" The dictionary may have the following keys:
" 'format'
" 'escape'
" 'truncateTo'
"
" The 'format' key may have a value of:
" 'Cd' - a string to be used with ":cd" and similar commands
" 'Edit' - a string to be used with ":edit" and similar commands
" 'UI' - a string to be displayed in the NERDTree user interface
"
" The 'escape' key, if specified, will cause the output to be escaped with
" Vim's internal "shellescape()" function.
"
" The 'truncateTo' key shortens the length of the path to that given by the
" value associated with 'truncateTo'. A '<' is prepended.
function! s:Path.str(...)
let options = a:0 ? a:1 : {}
let toReturn = ''
if has_key(options, 'format')
let format = options['format']
if has_key(self, '_strFor' . format)
exec 'let toReturn = self._strFor' . format . '()'
else
throw 'NERDTree.UnknownFormatError: unknown format "'. format .'"'
endif
else
let toReturn = self._str()
endif
if nerdtree#has_opt(options, 'escape')
let toReturn = shellescape(toReturn)
endif
if has_key(options, 'truncateTo')
let limit = options['truncateTo']
if strdisplaywidth(toReturn) > limit-1
while strdisplaywidth(toReturn) > limit-1 && strchars(toReturn) > 0
let toReturn = substitute(toReturn, '^.', '', '')
endwhile
if len(split(toReturn, '/')) > 1
let toReturn = '</' . join(split(toReturn, '/')[1:], '/') . '/'
else
let toReturn = '<' . toReturn
endif
endif
endif
return toReturn
endfunction
" FUNCTION: Path._strForUI() {{{1
function! s:Path._strForUI()
let toReturn = '/' . join(self.pathSegments, '/')
if self.isDirectory && toReturn !=# '/'
let toReturn = toReturn . '/'
endif
return toReturn
endfunction
" FUNCTION: Path._strForCd() {{{1
" Return a string representation of this Path that is suitable for use as an
" argument to Vim's internal ":cd" command.
function! s:Path._strForCd()
return fnameescape(self.str())
endfunction
" FUNCTION: Path._strForEdit() {{{1
" Return a string representation of this Path that is suitable for use as an
" argument to Vim's internal ":edit" command.
function! s:Path._strForEdit()
" Make the path relative to the current working directory, if possible.
let l:result = fnamemodify(self.str(), ':.')
" On Windows, the drive letter may be removed by "fnamemodify()". Add it
" back, if necessary.
if nerdtree#runningWindows() && l:result[0] == nerdtree#slash()
let l:result = self.drive . l:result
endif
let l:result = fnameescape(l:result)
if empty(l:result)
let l:result = '.'
endif
return l:result
endfunction
" FUNCTION: Path._strForGlob() {{{1
function! s:Path._strForGlob()
let lead = nerdtree#slash()
"if we are running windows then slap a drive letter on the front
if nerdtree#runningWindows()
let lead = self.drive . '\'
endif
let toReturn = lead . join(self.pathSegments, nerdtree#slash())
if !nerdtree#runningWindows()
let toReturn = escape(toReturn, self._escChars())
endif
return toReturn
endfunction
" FUNCTION: Path._str() {{{1
" Return the absolute pathname associated with this Path object. The pathname
" returned is appropriate for the underlying file system.
function! s:Path._str()
let l:separator = nerdtree#slash()
let l:leader = l:separator
if nerdtree#runningWindows()
let l:leader = self.drive . l:separator
endif
return l:leader . join(self.pathSegments, l:separator)
endfunction
" FUNCTION: Path.strTrunk() {{{1
" Gets the path without the last segment on the end.
function! s:Path.strTrunk()
return self.drive . '/' . join(self.pathSegments[0:-2], '/')
endfunction
" FUNCTION: Path.tabnr() {{{1
" return the number of the first tab that is displaying this file
"
" return 0 if no tab was found
function! s:Path.tabnr()
let str = self.str()
for t in range(tabpagenr('$'))
for b in tabpagebuflist(t+1)
if str ==# expand('#' . b . ':p')
return t+1
endif
endfor
endfor
return 0
endfunction
" FUNCTION: Path.WinToUnixPath(pathstr){{{1
" Takes in a windows path and returns the unix equiv
"
" A class level method
"
" Args:
" pathstr: the windows path to convert
function! s:Path.WinToUnixPath(pathstr)
if !nerdtree#runningWindows()
return a:pathstr
endif
let toReturn = a:pathstr
"remove the x:\ of the front
let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', '')
"remove the \\ network share from the front
let toReturn = substitute(toReturn, '^\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\(\\\|\/\)\?', '/', '')
"convert all \ chars to /
let toReturn = substitute(toReturn, '\', '/', 'g')
return toReturn
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,706 +0,0 @@
" ============================================================================
" CLASS: TreeDirNode
"
" A subclass of NERDTreeFileNode.
"
" The 'composite' part of the file/dir composite.
" ============================================================================
let s:TreeDirNode = copy(g:NERDTreeFileNode)
let g:NERDTreeDirNode = s:TreeDirNode
" FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{1
" Class method that returns the highest cached ancestor of the current root.
function! s:TreeDirNode.AbsoluteTreeRoot()
let currentNode = b:NERDTree.root
while currentNode.parent !=# {}
let currentNode = currentNode.parent
endwhile
return currentNode
endfunction
" FUNCTION: TreeDirNode.activate([options]) {{{1
function! s:TreeDirNode.activate(...)
let l:options = (a:0 > 0) ? a:1 : {}
call self.toggleOpen(l:options)
" Note that we only re-render the NERDTree for this node if we did NOT
" create a new node and render it in a new window or tab. In the latter
" case, rendering the NERDTree for this node could overwrite the text of
" the new NERDTree!
if !has_key(l:options, 'where') || empty(l:options['where'])
call self.getNerdtree().render()
call self.putCursorHere(0, 0)
endif
endfunction
" FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{1
" Adds the given treenode to the list of children for this node
"
" Args:
" -treenode: the node to add
" -inOrder: 1 if the new node should be inserted in sorted order
function! s:TreeDirNode.addChild(treenode, inOrder)
call add(self.children, a:treenode)
let a:treenode.parent = self
if a:inOrder
call self.sortChildren()
endif
endfunction
" FUNCTION: TreeDirNode.close() {{{1
" Mark this TreeDirNode as closed.
function! s:TreeDirNode.close()
" Close all directories in this directory node's cascade. This is
" necessary to ensure consistency when cascades are rendered.
for l:dirNode in self.getCascade()
let l:dirNode.isOpen = 0
endfor
endfunction
" FUNCTION: TreeDirNode.closeChildren() {{{1
" Recursively close any directory nodes that are descendants of this node.
function! s:TreeDirNode.closeChildren()
for l:child in self.children
if l:child.path.isDirectory
call l:child.close()
call l:child.closeChildren()
endif
endfor
endfunction
" FUNCTION: TreeDirNode.createChild(path, inOrder) {{{1
" Instantiates a new child node for this node with the given path. The new
" nodes parent is set to this node.
"
" Args:
" path: a Path object that this node will represent/contain
" inOrder: 1 if the new node should be inserted in sorted order
"
" Returns:
" the newly created node
function! s:TreeDirNode.createChild(path, inOrder)
let newTreeNode = g:NERDTreeFileNode.New(a:path, self.getNerdtree())
call self.addChild(newTreeNode, a:inOrder)
return newTreeNode
endfunction
" FUNCTION: TreeDirNode.displayString() {{{1
" Assemble and return a string that can represent this TreeDirNode object in
" the NERDTree window.
function! s:TreeDirNode.displayString()
let l:result = ''
" Build a label that identifies this TreeDirNode.
let l:label = ''
let l:cascade = self.getCascade()
for l:dirNode in l:cascade
let l:next = l:dirNode.path.displayString()
let l:label .= l:label ==# '' ? l:next : substitute(l:next,'^.','','')
endfor
" Select the appropriate open/closed status indicator symbol.
let l:symbol = (l:cascade[-1].isOpen ? g:NERDTreeDirArrowCollapsible : g:NERDTreeDirArrowExpandable )
let l:symbol .= (g:NERDTreeDirArrowExpandable ==# '' ? '' : ' ')
let l:flags = l:cascade[-1].path.flagSet.renderToString()
return l:symbol . l:flags . l:label
endfunction
" FUNCTION: TreeDirNode.findNode(path) {{{1
" Will find one of the children (recursively) that has the given path
"
" Args:
" path: a path object
unlet s:TreeDirNode.findNode
function! s:TreeDirNode.findNode(path)
if a:path.equals(self.path)
return self
endif
if stridx(a:path.str(), self.path.str(), 0) ==# -1
return {}
endif
if self.path.isDirectory
for i in self.children
let retVal = i.findNode(a:path)
if retVal !=# {}
return retVal
endif
endfor
endif
return {}
endfunction
" FUNCTION: TreeDirNode.getCascade() {{{1
" Return an array of dir nodes (starting from self) that can be cascade opened.
function! s:TreeDirNode.getCascade()
if !self.isCascadable()
return [self]
endif
let vc = self.getVisibleChildren()
let visChild = vc[0]
return [self] + visChild.getCascade()
endfunction
" FUNCTION: TreeDirNode.getCascadeRoot() {{{1
" Return the first directory node in the cascade in which this directory node
" is rendered.
function! s:TreeDirNode.getCascadeRoot()
" Don't search above the current NERDTree root node.
if self.isRoot()
return self
endif
let l:cascadeRoot = self
let l:parent = self.parent
while !empty(l:parent) && !l:parent.isRoot()
if index(l:parent.getCascade(), self) ==# -1
break
endif
let l:cascadeRoot = l:parent
let l:parent = l:parent.parent
endwhile
return l:cascadeRoot
endfunction
" FUNCTION: TreeDirNode.getChildCount() {{{1
" Returns the number of children this node has
function! s:TreeDirNode.getChildCount()
return len(self.children)
endfunction
" FUNCTION: TreeDirNode.getChild(path) {{{1
" Returns child node of this node that has the given path or {} if no such node
" exists.
"
" This function doesnt not recurse into child dir nodes
"
" Args:
" path: a path object
function! s:TreeDirNode.getChild(path)
if stridx(a:path.str(), self.path.str(), 0) ==# -1
return {}
endif
let index = self.getChildIndex(a:path)
if index ==# -1
return {}
else
return self.children[index]
endif
endfunction
" FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{1
" returns the child at the given index
"
" Args:
" indx: the index to get the child from
" visible: 1 if only the visible children array should be used, 0 if all the
" children should be searched.
function! s:TreeDirNode.getChildByIndex(indx, visible)
let array_to_search = a:visible? self.getVisibleChildren() : self.children
if a:indx > len(array_to_search)
throw 'NERDTree.InvalidArgumentsError: Index is out of bounds.'
endif
return array_to_search[a:indx]
endfunction
" FUNCTION: TreeDirNode.getChildIndex(path) {{{1
" Returns the index of the child node of this node that has the given path or
" -1 if no such node exists.
"
" This function doesnt not recurse into child dir nodes
"
" Args:
" path: a path object
function! s:TreeDirNode.getChildIndex(path)
if stridx(a:path.str(), self.path.str(), 0) ==# -1
return -1
endif
"do a binary search for the child
let a = 0
let z = self.getChildCount()
while a < z
let mid = (a+z)/2
let diff = nerdtree#compareNodePaths(a:path, self.children[mid].path)
if diff ==# -1
let z = mid
elseif diff ==# 1
let a = mid+1
else
return mid
endif
endwhile
return -1
endfunction
" FUNCTION: TreeDirNode.getDirChildren() {{{1
" Return a list of all child nodes from 'self.children' that are of type
" TreeDirNode. This function supports http://github.com/scrooloose/nerdtree-project-plugin.git.
function! s:TreeDirNode.getDirChildren()
return filter(copy(self.children), 'v:val.path.isDirectory ==# 1')
endfunction
" FUNCTION: TreeDirNode._glob(pattern, all) {{{1
" Return a list of strings naming the descendants of the directory in this
" TreeDirNode object that match the specified glob pattern.
"
" Args:
" pattern: (string) the glob pattern to apply
" all: (0 or 1) if 1, include '.' and '..' if they match 'pattern'; if 0,
" always exclude them
"
" Note: If the pathnames in the result list are below the working directory,
" they are returned as pathnames relative to that directory. This is because
" this function, internally, attempts to obey 'wildignore' rules that use
" relative paths.
function! s:TreeDirNode._glob(pattern, all)
" Construct a path specification such that globpath() will return
" relative pathnames, if possible.
if self.path.str() ==# getcwd()
let l:pathSpec = ','
else
let l:pathSpec = escape(fnamemodify(self.path.str({'format': 'Glob'}), ':.'), ',')
" On Windows, the drive letter may be removed by "fnamemodify()".
if nerdtree#runningWindows() && l:pathSpec[0] == nerdtree#slash()
let l:pathSpec = self.path.drive . l:pathSpec
endif
endif
let l:globList = []
" See ':h version7.txt' and ':h version8.txt' for details on the
" development of the glob() and globpath() functions.
if v:version > 704 || (v:version ==# 704 && has('patch654'))
let l:globList = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore, 1, 0)
elseif v:version ==# 704 && has('patch279')
let l:globList = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore, 1)
elseif v:version > 702 || (v:version ==# 702 && has('patch051'))
let l:globString = globpath(l:pathSpec, a:pattern, !g:NERDTreeRespectWildIgnore)
let l:globList = split(l:globString, "\n")
else
let l:globString = globpath(l:pathSpec, a:pattern)
let l:globList = split(l:globString, "\n")
endif
" If a:all is false, filter '.' and '..' from the output.
if !a:all
let l:toRemove = []
for l:file in l:globList
let l:tail = fnamemodify(l:file, ':t')
" If l:file has a trailing slash, then its :tail will be ''. Use
" :h to drop the slash and the empty string after it; then use :t
" to get the directory name.
if l:tail ==# ''
let l:tail = fnamemodify(l:file, ':h:t')
endif
if l:tail ==# '.' || l:tail ==# '..'
call add(l:toRemove, l:file)
if len(l:toRemove) ==# 2
break
endif
endif
endfor
for l:file in l:toRemove
call remove(l:globList, index(l:globList, l:file))
endfor
endif
return l:globList
endfunction
" FUNCTION: TreeDirNode.GetSelected() {{{1
" Returns the current node if it is a dir node, or else returns the current
" nodes parent
unlet s:TreeDirNode.GetSelected
function! s:TreeDirNode.GetSelected()
let currentDir = g:NERDTreeFileNode.GetSelected()
if currentDir !=# {} && !currentDir.isRoot()
if currentDir.path.isDirectory ==# 0
let currentDir = currentDir.parent
endif
endif
return currentDir
endfunction
" FUNCTION: TreeDirNode.getVisibleChildCount() {{{1
" Returns the number of visible children this node has
function! s:TreeDirNode.getVisibleChildCount()
return len(self.getVisibleChildren())
endfunction
" FUNCTION: TreeDirNode.getVisibleChildren() {{{1
" Returns a list of children to display for this node, in the correct order
"
" Return:
" an array of treenodes
function! s:TreeDirNode.getVisibleChildren()
let toReturn = []
for i in self.children
if i.path.ignore(self.getNerdtree()) ==# 0
call add(toReturn, i)
endif
endfor
return toReturn
endfunction
" FUNCTION: TreeDirNode.hasVisibleChildren() {{{1
" returns 1 if this node has any childre, 0 otherwise..
function! s:TreeDirNode.hasVisibleChildren()
return self.getVisibleChildCount() !=# 0
endfunction
" FUNCTION: TreeDirNode.isCascadable() {{{1
" true if this dir has only one visible child that is also a dir
" false if this dir is bookmarked or symlinked. Why? Two reasons:
" 1. If cascaded, we don't know which dir is bookmarked or is a symlink.
" 2. If the parent is a symlink or is bookmarked, you end up with unparsable
" text, and NERDTree cannot get the path of any child node.
" Also, return false if this directory is the tree root, which should never be
" part of a cascade.
function! s:TreeDirNode.isCascadable()
if g:NERDTreeCascadeSingleChildDir ==# 0
return 0
endif
if self.isRoot()
return 0
endif
if self.path.isSymLink
return 0
endif
for i in g:NERDTreeBookmark.Bookmarks()
if i.path.equals(self.path)
return 0
endif
endfor
let c = self.getVisibleChildren()
return len(c) ==# 1 && c[0].path.isDirectory
endfunction
" FUNCTION: TreeDirNode._initChildren() {{{1
" Removes all childen from this node and re-reads them
"
" Args:
" silent: 1 if the function should not echo any 'please wait' messages for
" large directories
"
" Return: the number of child nodes read
function! s:TreeDirNode._initChildren(silent)
"remove all the current child nodes
let self.children = []
let files = self._glob('*', 1) + self._glob('.*', 0)
if !a:silent && len(files) > g:NERDTreeNotificationThreshold
call nerdtree#echo('Please wait, caching a large dir ...')
endif
let invalidFilesFound = 0
for i in files
try
let path = g:NERDTreePath.New(i)
call self.createChild(path, 0)
call g:NERDTreePathNotifier.NotifyListeners('init', path, self.getNerdtree(), {})
catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
let invalidFilesFound += 1
endtry
endfor
let g:NERDTreeOldSortOrder = g:NERDTreeSortOrder
call self.sortChildren()
call nerdtree#echo('')
if invalidFilesFound
call nerdtree#echoWarning(invalidFilesFound . ' file(s) could not be loaded into the NERD tree')
endif
return self.getChildCount()
endfunction
" FUNCTION: TreeDirNode.New(path, nerdtree) {{{1
" Return a new TreeDirNode object with the given path and parent.
"
" Args:
" path: dir that the node represents
" nerdtree: the tree the node belongs to
function! s:TreeDirNode.New(path, nerdtree)
if a:path.isDirectory !=# 1
throw 'NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object.'
endif
let newTreeNode = copy(self)
let newTreeNode.path = a:path
let newTreeNode.isOpen = 0
let newTreeNode.children = []
let newTreeNode.parent = {}
let newTreeNode._nerdtree = a:nerdtree
return newTreeNode
endfunction
" FUNCTION: TreeDirNode.open([options]) {{{1
" Open this directory node in the current tree or elsewhere if special options
" are provided. Return 0 if options were processed. Otherwise, return the
" number of new cached nodes.
function! s:TreeDirNode.open(...)
let l:options = a:0 ? a:1 : {}
" If special options were specified, process them and return.
if has_key(l:options, 'where') && !empty(l:options['where'])
let l:opener = g:NERDTreeOpener.New(self.path, l:options)
call l:opener.open(self)
return 0
endif
" Open any ancestors of this node that render within the same cascade.
let l:parent = self.parent
while !empty(l:parent) && !l:parent.isRoot()
if index(l:parent.getCascade(), self) >= 0
let l:parent.isOpen = 1
let l:parent = l:parent.parent
else
break
endif
endwhile
let self.isOpen = 1
let l:numChildrenCached = 0
if empty(self.children)
let l:numChildrenCached = self._initChildren(0)
endif
return l:numChildrenCached
endfunction
" FUNCTION: TreeDirNode.openAlong([opts]) {{{1
" recursive open the dir if it has only one directory child.
"
" return the level of opened directories.
function! s:TreeDirNode.openAlong(...)
let opts = a:0 ? a:1 : {}
let level = 0
let node = self
while node.path.isDirectory
call node.open(opts)
let level += 1
if node.getVisibleChildCount() ==# 1
let node = node.getChildByIndex(0, 1)
else
break
endif
endwhile
return level
endfunction
" FUNCTION: TreeDirNode.openExplorer() {{{1
" Open an explorer window for this node in the previous window. The explorer
" can be a NERDTree window or a netrw window.
function! s:TreeDirNode.openExplorer()
execute 'wincmd p'
execute 'edit '.self.path.str({'format':'Edit'})
endfunction
" FUNCTION: TreeDirNode.openInNewTab(options) {{{1
unlet s:TreeDirNode.openInNewTab
function! s:TreeDirNode.openInNewTab(options)
call nerdtree#deprecated('TreeDirNode.openInNewTab', 'is deprecated, use open() instead')
call self.open({'where': 't'})
endfunction
" FUNCTION: TreeDirNode._openInNewTab() {{{1
function! s:TreeDirNode._openInNewTab()
tabnew
call g:NERDTreeCreator.CreateTabTree(self.path.str())
endfunction
" FUNCTION: TreeDirNode.openRecursively() {{{1
" Open this directory node and any descendant directory nodes whose pathnames
" are not ignored.
function! s:TreeDirNode.openRecursively()
silent call self.open()
for l:child in self.children
if l:child.path.isDirectory && !l:child.path.ignore(l:child.getNerdtree())
call l:child.openRecursively()
endif
endfor
endfunction
" FUNCTION: TreeDirNode.refresh() {{{1
function! s:TreeDirNode.refresh()
call self.path.refresh(self.getNerdtree())
"if this node was ever opened, refresh its children
if self.isOpen || !empty(self.children)
let files = self._glob('*', 1) + self._glob('.*', 0)
let newChildNodes = []
let invalidFilesFound = 0
for i in files
try
"create a new path and see if it exists in this nodes children
let path = g:NERDTreePath.New(i)
let newNode = self.getChild(path)
if newNode !=# {}
call newNode.refresh()
call add(newChildNodes, newNode)
"the node doesnt exist so create it
else
let newNode = g:NERDTreeFileNode.New(path, self.getNerdtree())
let newNode.parent = self
call add(newChildNodes, newNode)
endif
catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
let invalidFilesFound = 1
endtry
endfor
"swap this nodes children out for the children we just read/refreshed
let self.children = newChildNodes
call self.sortChildren()
if invalidFilesFound
call nerdtree#echoWarning('some files could not be loaded into the NERD tree')
endif
endif
endfunction
" FUNCTION: TreeDirNode.refreshFlags() {{{1
unlet s:TreeDirNode.refreshFlags
function! s:TreeDirNode.refreshFlags()
call self.path.refreshFlags(self.getNerdtree())
for i in self.children
call i.refreshFlags()
endfor
endfunction
" FUNCTION: TreeDirNode.refreshDirFlags() {{{1
function! s:TreeDirNode.refreshDirFlags()
call self.path.refreshFlags(self.getNerdtree())
endfunction
" FUNCTION: TreeDirNode.reveal(path) {{{1
" reveal the given path, i.e. cache and open all treenodes needed to display it
" in the UI
" Returns the revealed node
function! s:TreeDirNode.reveal(path, ...)
let opts = a:0 ? a:1 : {}
if !a:path.isUnder(self.path)
throw 'NERDTree.InvalidArgumentsError: ' . a:path.str() . ' should be under ' . self.path.str()
endif
call self.open()
if self.path.equals(a:path.getParent())
let n = self.findNode(a:path)
" We may be looking for a newly-saved file that isn't in the tree yet.
if n ==# {}
call self.refresh()
let n = self.findNode(a:path)
endif
if has_key(opts, 'open')
call n.open()
endif
return n
endif
let p = a:path
while !p.getParent().equals(self.path)
let p = p.getParent()
endwhile
let n = self.findNode(p)
return n.reveal(a:path, opts)
endfunction
" FUNCTION: TreeDirNode.removeChild(treenode) {{{1
" Remove the given treenode from self.children.
" Throws NERDTree.ChildNotFoundError if the node is not found.
"
" Args:
" treenode: the node object to remove
function! s:TreeDirNode.removeChild(treenode)
for i in range(0, self.getChildCount()-1)
if self.children[i].equals(a:treenode)
call remove(self.children, i)
return
endif
endfor
throw 'NERDTree.ChildNotFoundError: child node was not found'
endfunction
" FUNCTION: TreeDirNode.sortChildren() {{{1
" Sort self.children by alphabetical order and directory priority.
function! s:TreeDirNode.sortChildren()
if count(g:NERDTreeSortOrder, '*') < 1
call add(g:NERDTreeSortOrder, '*')
endif
let CompareFunc = function('nerdtree#compareNodes')
call sort(self.children, CompareFunc)
let g:NERDTreeOldSortOrder = g:NERDTreeSortOrder
endfunction
" FUNCTION: TreeDirNode.toggleOpen([options]) {{{1
" Opens this directory if it is closed and vice versa
function! s:TreeDirNode.toggleOpen(...)
let opts = a:0 ? a:1 : {}
if self.isOpen ==# 1
call self.close()
else
if g:NERDTreeCascadeOpenSingleChildDir ==# 0
call self.open(opts)
else
call self.openAlong(opts)
endif
endif
endfunction
" FUNCTION: TreeDirNode.transplantChild(newNode) {{{1
" Replaces the child of this with the given node (where the child node's full
" path matches a:newNode's fullpath). The search for the matching node is
" non-recursive
"
" Arg:
" newNode: the node to graft into the tree
function! s:TreeDirNode.transplantChild(newNode)
for i in range(0, self.getChildCount()-1)
if self.children[i].equals(a:newNode)
let self.children[i] = a:newNode
let a:newNode.parent = self
break
endif
endfor
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,349 +0,0 @@
" ============================================================================
" CLASS: TreeFileNode
"
" This class is the parent of the TreeDirNode class and is the 'Component'
" part of the composite design pattern between the NERDTree node classes.
" ============================================================================
let s:TreeFileNode = {}
let g:NERDTreeFileNode = s:TreeFileNode
" FUNCTION: TreeFileNode.activate(...) {{{1
function! s:TreeFileNode.activate(...)
call self.open(a:0 ? a:1 : {})
endfunction
" FUNCTION: TreeFileNode.bookmark(name) {{{1
" bookmark this node with a:name
function! s:TreeFileNode.bookmark(name)
" if a bookmark exists with the same name and the node is cached then save
" it so we can update its display string
let oldMarkedNode = {}
try
let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1, self.getNerdtree())
catch /^NERDTree.BookmarkNotFoundError/
catch /^NERDTree.BookmarkedNodeNotFoundError/
endtry
call g:NERDTreeBookmark.AddBookmark(a:name, self.path)
call self.path.cacheDisplayString()
call g:NERDTreeBookmark.Write()
if !empty(oldMarkedNode)
call oldMarkedNode.path.cacheDisplayString()
endif
endfunction
" FUNCTION: TreeFileNode.cacheParent() {{{1
" initializes self.parent if it isnt already
function! s:TreeFileNode.cacheParent()
if empty(self.parent)
let parentPath = self.path.getParent()
if parentPath.equals(self.path)
throw 'NERDTree.CannotCacheParentError: already at root'
endif
let self.parent = s:TreeFileNode.New(parentPath, self.getNerdtree())
endif
endfunction
" FUNCTION: TreeFileNode.clearBookmarks() {{{1
function! s:TreeFileNode.clearBookmarks()
for i in g:NERDTreeBookmark.Bookmarks()
if i.path.equals(self.path)
call i.delete()
end
endfor
call self.path.cacheDisplayString()
endfunction
" FUNCTION: TreeFileNode.copy(dest) {{{1
function! s:TreeFileNode.copy(dest)
call self.path.copy(a:dest)
let newPath = g:NERDTreePath.New(a:dest)
let parent = self.getNerdtree().root.findNode(newPath.getParent())
if !empty(parent)
call parent.refresh()
return parent.findNode(newPath)
else
return {}
endif
endfunction
" FUNCTION: TreeFileNode.delete {{{1
" Removes this node from the tree and calls the Delete method for its path obj
function! s:TreeFileNode.delete()
call self.path.delete()
call self.parent.removeChild(self)
endfunction
" FUNCTION: TreeFileNode.displayString() {{{1
"
" Returns a string that specifies how the node should be represented as a
" string
"
" Return:
" a string that can be used in the view to represent this node
function! s:TreeFileNode.displayString()
return self.path.flagSet.renderToString() . self.path.displayString()
endfunction
" FUNCTION: TreeFileNode.equals(treenode) {{{1
"
" Compares this treenode to the input treenode and returns 1 if they are the
" same node.
"
" Use this method instead of == because sometimes when the treenodes contain
" many children, vim seg faults when doing ==
"
" Args:
" treenode: the other treenode to compare to
function! s:TreeFileNode.equals(treenode)
return self.path.str() ==# a:treenode.path.str()
endfunction
" FUNCTION: TreeFileNode.findNode(path) {{{1
" Returns self if this node.path.Equals the given path.
" Returns {} if not equal.
"
" Args:
" path: the path object to compare against
function! s:TreeFileNode.findNode(path)
if a:path.equals(self.path)
return self
endif
return {}
endfunction
" FUNCTION: TreeFileNode.findSibling(direction) {{{1
" Find the next or previous sibling of this node.
"
" Args:
" direction: 0 for previous, 1 for next
"
" Return:
" The next/previous TreeFileNode object or an empty dictionary if not found.
function! s:TreeFileNode.findSibling(direction)
" There can be no siblings if there is no parent.
if empty(self.parent)
return {}
endif
let l:nodeIndex = self.parent.getChildIndex(self.path)
if l:nodeIndex == -1
return {}
endif
" Get the next index to begin the search.
let l:nodeIndex += a:direction ? 1 : -1
while 0 <= l:nodeIndex && l:nodeIndex < self.parent.getChildCount()
" Return the next node if it is not ignored.
if !self.parent.children[l:nodeIndex].path.ignore(self.getNerdtree())
return self.parent.children[l:nodeIndex]
endif
let l:nodeIndex += a:direction ? 1 : -1
endwhile
return {}
endfunction
" FUNCTION: TreeFileNode.getNerdtree(){{{1
function! s:TreeFileNode.getNerdtree()
return self._nerdtree
endfunction
" FUNCTION: TreeFileNode.GetRootForTab(){{{1
" get the root node for this tab
function! s:TreeFileNode.GetRootForTab()
if g:NERDTree.ExistsForTab()
return getbufvar(t:NERDTreeBufName, 'NERDTree').root
end
return {}
endfunction
" FUNCTION: TreeFileNode.GetSelected() {{{1
" If the cursor is currently positioned on a tree node, return the node.
" Otherwise, return the empty dictionary.
function! s:TreeFileNode.GetSelected()
try
let l:path = b:NERDTree.ui.getPath(line('.'))
if empty(l:path)
return {}
endif
return b:NERDTree.root.findNode(l:path)
catch
return {}
endtry
endfunction
" FUNCTION: TreeFileNode.isVisible() {{{1
" returns 1 if this node should be visible according to the tree filters and
" hidden file filters (and their on/off status)
function! s:TreeFileNode.isVisible()
return !self.path.ignore(self.getNerdtree())
endfunction
" FUNCTION: TreeFileNode.isRoot() {{{1
function! s:TreeFileNode.isRoot()
if !g:NERDTree.ExistsForBuf()
throw 'NERDTree.NoTreeError: No tree exists for the current buffer'
endif
return self.equals(self.getNerdtree().root)
endfunction
" FUNCTION: TreeFileNode.New(path, nerdtree) {{{1
" Returns a new TreeNode object with the given path and parent
"
" Args:
" path: file/dir that the node represents
" nerdtree: the tree the node belongs to
function! s:TreeFileNode.New(path, nerdtree)
if a:path.isDirectory
return g:NERDTreeDirNode.New(a:path, a:nerdtree)
else
let newTreeNode = copy(self)
let newTreeNode.path = a:path
let newTreeNode.parent = {}
let newTreeNode._nerdtree = a:nerdtree
return newTreeNode
endif
endfunction
" FUNCTION: TreeFileNode.open() {{{1
function! s:TreeFileNode.open(...)
let opts = a:0 ? a:1 : {}
let opener = g:NERDTreeOpener.New(self.path, opts)
call opener.open(self)
endfunction
" FUNCTION: TreeFileNode.openSplit() {{{1
" Open this node in a new window
function! s:TreeFileNode.openSplit()
call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.')
call self.open({'where': 'h'})
endfunction
" FUNCTION: TreeFileNode.openVSplit() {{{1
" Open this node in a new vertical window
function! s:TreeFileNode.openVSplit()
call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.')
call self.open({'where': 'v'})
endfunction
" FUNCTION: TreeFileNode.openInNewTab(options) {{{1
function! s:TreeFileNode.openInNewTab(options)
call nerdtree#deprecated('TreeFileNode.openinNewTab', 'is deprecated, use .open() instead.')
call self.open(extend({'where': 't'}, a:options))
endfunction
" FUNCTION: TreeFileNode.openExplorer()
function! s:TreeFileNode.openExplorer()
execute 'wincmd p'
execute 'edit '.self.path.getParent().str({'format':'Edit'})
endfunction
" FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1
" Places the cursor on the line number this node is rendered on
"
" Args:
" isJump: 1 if this cursor movement should be counted as a jump by vim
" recurseUpward: try to put the cursor on the parent if the this node isnt
" visible
function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
let ln = self.getNerdtree().ui.getLineNum(self)
if ln != -1
if a:isJump
mark '
endif
call cursor(ln, col('.'))
else
if a:recurseUpward
let node = self
while node != {} && self.getNerdtree().ui.getLineNum(node) ==# -1
let node = node.parent
call node.open()
endwhile
call self._nerdtree.render()
call node.putCursorHere(a:isJump, 0)
endif
endif
endfunction
" FUNCTION: TreeFileNode.refresh() {{{1
function! s:TreeFileNode.refresh()
call self.path.refresh(self.getNerdtree())
endfunction
" FUNCTION: TreeFileNode.refreshFlags() {{{1
function! s:TreeFileNode.refreshFlags()
call self.path.refreshFlags(self.getNerdtree())
endfunction
" FUNCTION: TreeFileNode.rename() {{{1
" Calls the rename method for this nodes path obj
function! s:TreeFileNode.rename(newName)
let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
call self.path.rename(newName)
call self.parent.removeChild(self)
let parentPath = self.path.getParent()
let newParent = self.getNerdtree().root.findNode(parentPath)
if newParent != {}
call newParent.createChild(self.path, 1)
call newParent.refresh()
endif
endfunction
" FUNCTION: TreeFileNode.renderToString {{{1
" returns a string representation for this tree to be rendered in the view
function! s:TreeFileNode.renderToString()
return self._renderToString(0, 0)
endfunction
" Args:
" depth: the current depth in the tree for this call
" drawText: 1 if we should actually draw the line for this node (if 0 then the
" child nodes are rendered only)
" for each depth in the tree
function! s:TreeFileNode._renderToString(depth, drawText)
let output = ''
if a:drawText ==# 1
let treeParts = repeat(' ', a:depth - 1)
let treeParts .= (self.path.isDirectory || g:NERDTreeDirArrowExpandable ==# '' ? '' : ' ')
let line = treeParts . self.displayString()
let output = output . line . "\n"
endif
" if the node is an open dir, draw its children
if self.path.isDirectory ==# 1 && self.isOpen ==# 1
let childNodesToDraw = self.getVisibleChildren()
if self.isCascadable() && a:depth > 0
let output = output . childNodesToDraw[0]._renderToString(a:depth, 0)
elseif len(childNodesToDraw) > 0
for i in childNodesToDraw
let output = output . i._renderToString(a:depth + 1, 1)
endfor
endif
endif
return output
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,532 +0,0 @@
" ============================================================================
" CLASS: UI
" ============================================================================
let s:UI = {}
let g:NERDTreeUI = s:UI
" FUNCTION: s:UI.centerView() {{{1
" centers the nerd tree window around the cursor (provided the nerd tree
" options permit)
function! s:UI.centerView()
if g:NERDTreeAutoCenter
let current_line = winline()
let lines_to_top = current_line
let lines_to_bottom = winheight(g:NERDTree.GetWinNum()) - current_line
if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold
normal! zz
endif
endif
endfunction
" FUNCTION: s:UI._dumpHelp {{{1
" prints out the quick help
function! s:UI._dumpHelp()
if self.getShowHelp()
let help = "\" NERDTree (" . nerdtree#version() . ") quickhelp~\n"
let help .= "\" ============================\n"
let help .= "\" File node mappings~\n"
let help .= '" '. (g:NERDTreeMouseMode ==# 3 ? 'single' : 'double') ."-click,\n"
if self.nerdtree.isTabTree()
let help .= '" '. g:NERDTreeMapActivateNode .": open in prev window\n"
else
let help .= '" '. g:NERDTreeMapActivateNode .": open in current window\n"
endif
if self.nerdtree.isTabTree()
let help .= '" '. g:NERDTreeMapPreview .": preview\n"
endif
let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n"
let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
let help .= "\" middle-click,\n"
let help .= '" '. g:NERDTreeMapOpenSplit .": open split\n"
let help .= '" '. g:NERDTreeMapPreviewSplit .": preview split\n"
let help .= '" '. g:NERDTreeMapOpenVSplit .": open vsplit\n"
let help .= '" '. g:NERDTreeMapPreviewVSplit .": preview vsplit\n"
let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n"
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Directory node mappings~\n"
let help .= '" '. (g:NERDTreeMouseMode ==# 1 ? 'double' : 'single') ."-click,\n"
let help .= '" '. g:NERDTreeMapActivateNode .": open & close node\n"
let help .= '" '. g:NERDTreeMapOpenRecursively .": recursively open node\n"
let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n"
let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n"
let help .= '" '. g:NERDTreeMapCloseDir .": close parent of node\n"
let help .= '" '. g:NERDTreeMapCloseChildren .": close all child nodes of\n"
let help .= "\" current node recursively\n"
let help .= "\" middle-click,\n"
let help .= '" '. g:NERDTreeMapOpenExpl.": explore selected dir\n"
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Bookmark table mappings~\n"
let help .= "\" double-click,\n"
let help .= '" '. g:NERDTreeMapActivateNode .": open bookmark\n"
let help .= '" '. g:NERDTreeMapPreview .": preview file\n"
let help .= '" '. g:NERDTreeMapPreview .": find dir in tree\n"
let help .= '" '. g:NERDTreeMapOpenInTab.": open in new tab\n"
let help .= '" '. g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n"
let help .= '" '. g:NERDTreeMapOpenSplit .": open split\n"
let help .= '" '. g:NERDTreeMapPreviewSplit .": preview split\n"
let help .= '" '. g:NERDTreeMapOpenVSplit .": open vsplit\n"
let help .= '" '. g:NERDTreeMapPreviewVSplit .": preview vsplit\n"
let help .= '" '. g:NERDTreeMapCustomOpen .": custom open\n"
let help .= '" '. g:NERDTreeMapDeleteBookmark .": delete bookmark\n"
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Tree navigation mappings~\n"
let help .= '" '. g:NERDTreeMapJumpRoot .": go to root\n"
let help .= '" '. g:NERDTreeMapJumpParent .": go to parent\n"
let help .= '" '. g:NERDTreeMapJumpFirstChild .": go to first child\n"
let help .= '" '. g:NERDTreeMapJumpLastChild .": go to last child\n"
let help .= '" '. g:NERDTreeMapJumpNextSibling .": go to next sibling\n"
let help .= '" '. g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n"
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Filesystem mappings~\n"
let help .= '" '. g:NERDTreeMapChangeRoot .": change tree root to the\n"
let help .= "\" selected dir\n"
let help .= '" '. g:NERDTreeMapUpdir .": move tree root up a dir\n"
let help .= '" '. g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n"
let help .= "\" but leave old root open\n"
let help .= '" '. g:NERDTreeMapRefresh .": refresh cursor dir\n"
let help .= '" '. g:NERDTreeMapRefreshRoot .": refresh current root\n"
let help .= '" '. g:NERDTreeMapMenu .": Show menu\n"
let help .= '" '. g:NERDTreeMapChdir .":change the CWD to the\n"
let help .= "\" selected dir\n"
let help .= '" '. g:NERDTreeMapCWD .":change tree root to CWD\n"
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Tree filtering mappings~\n"
let help .= '" '. g:NERDTreeMapToggleHidden .': hidden files (' . (self.getShowHidden() ? 'on' : 'off') . ")\n"
let help .= '" '. g:NERDTreeMapToggleFilters .': file filters (' . (self.isIgnoreFilterEnabled() ? 'on' : 'off') . ")\n"
let help .= '" '. g:NERDTreeMapToggleFiles .': files (' . (self.getShowFiles() ? 'on' : 'off') . ")\n"
let help .= '" '. g:NERDTreeMapToggleBookmarks .': bookmarks (' . (self.getShowBookmarks() ? 'on' : 'off') . ")\n"
" add quickhelp entries for each custom key map
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Custom mappings~\n"
for i in g:NERDTreeKeyMap.All()
if !empty(i.quickhelpText)
let help .= '" '. i.key .': '. i.quickhelpText ."\n"
endif
endfor
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Other mappings~\n"
let help .= '" '. g:NERDTreeMapQuit .": Close the NERDTree window\n"
let help .= '" '. g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n"
let help .= "\" the NERDTree window\n"
let help .= '" '. g:NERDTreeMapHelp .": toggle help\n"
let help .= "\"\n\" ----------------------------\n"
let help .= "\" Bookmark commands~\n"
let help .= "\" :Bookmark [<name>]\n"
let help .= "\" :BookmarkToRoot <name>\n"
let help .= "\" :RevealBookmark <name>\n"
let help .= "\" :OpenBookmark <name>\n"
let help .= "\" :ClearBookmarks [<names>]\n"
let help .= "\" :ClearAllBookmarks\n"
let help .= "\" :ReadBookmarks\n"
let help .= "\" :WriteBookmarks\n"
let help .= "\" :EditBookmarks\n"
silent! put =help
elseif !self.isMinimal()
let help ='" Press '. g:NERDTreeMapHelp ." for help\n"
silent! put =help
endif
endfunction
" FUNCTION: s:UI.new(nerdtree) {{{1
function! s:UI.New(nerdtree)
let newObj = copy(self)
let newObj.nerdtree = a:nerdtree
let newObj._showHelp = 0
let newObj._ignoreEnabled = 1
let newObj._showFiles = g:NERDTreeShowFiles
let newObj._showHidden = g:NERDTreeShowHidden
let newObj._showBookmarks = g:NERDTreeShowBookmarks
return newObj
endfunction
" FUNCTION: s:UI.getPath(ln) {{{1
" Return the Path object for the node that is rendered on the given line
" number. If the 'up a dir' line is selected, return the Path object for
" the parent of the root. Return the empty dictionary if the given line
" does not reference a tree node.
function! s:UI.getPath(ln)
let line = getline(a:ln)
let rootLine = self.getRootLineNum()
if a:ln ==# rootLine
return self.nerdtree.root.path
endif
if line ==# s:UI.UpDirLine()
return self.nerdtree.root.path.getParent()
endif
if a:ln < rootLine
return {}
endif
let indent = self._indentLevelFor(line)
" remove the tree parts and the leading space
let curFile = self._stripMarkup(line)
let dir = ''
let lnum = a:ln
while lnum > 0
let lnum = lnum - 1
let curLine = getline(lnum)
let curLineStripped = self._stripMarkup(curLine)
" have we reached the top of the tree?
if lnum ==# rootLine
let dir = self.nerdtree.root.path.str({'format': 'UI'}) . dir
break
endif
if curLineStripped =~# '/$'
let lpindent = self._indentLevelFor(curLine)
if lpindent < indent
let indent = indent - 1
let dir = substitute (curLineStripped,'^\\', '', '') . dir
continue
endif
endif
endwhile
let curFile = self.nerdtree.root.path.drive . dir . curFile
let toReturn = g:NERDTreePath.New(curFile)
return toReturn
endfunction
" FUNCTION: s:UI.getLineNum(node) {{{1
" Return the line number where the given node is rendered. Return -1 if the
" given node is not visible.
function! s:UI.getLineNum(node)
if a:node.isRoot()
return self.getRootLineNum()
endif
let l:pathComponents = [substitute(self.nerdtree.root.path.str({'format': 'UI'}), '/\s*$', '', '')]
let l:currentPathComponent = 1
let l:fullPath = a:node.path.str({'format': 'UI'})
for l:lineNumber in range(self.getRootLineNum() + 1, line('$'))
let l:currentLine = getline(l:lineNumber)
let l:indentLevel = self._indentLevelFor(l:currentLine)
if l:indentLevel !=# l:currentPathComponent
continue
endif
let l:currentLine = self._stripMarkup(l:currentLine)
let l:currentPath = join(l:pathComponents, '/') . '/' . l:currentLine
" Directories: If the current path 'starts with' the full path, then
" either the paths are equal or the line is a cascade containing the
" full path.
if l:fullPath[-1:] ==# '/' && stridx(l:currentPath, l:fullPath) ==# 0
return l:lineNumber
endif
" Files: The paths must exactly match.
if l:fullPath ==# l:currentPath
return l:lineNumber
endif
" Otherwise: If the full path starts with the current path and the
" current path is a directory, we add a new path component.
if stridx(l:fullPath, l:currentPath) ==# 0 && l:currentPath[-1:] ==# '/'
let l:currentLine = substitute(l:currentLine, '/\s*$', '', '')
call add(l:pathComponents, l:currentLine)
let l:currentPathComponent += 1
endif
endfor
return -1
endfunction
" FUNCTION: s:UI.getRootLineNum(){{{1
" gets the line number of the root node
function! s:UI.getRootLineNum()
let rootLine = 1
while rootLine <= line('$') && getline(rootLine) !~# '^\(/\|<\)'
let rootLine = rootLine + 1
endwhile
return rootLine
endfunction
" FUNCTION: s:UI.getShowBookmarks() {{{1
function! s:UI.getShowBookmarks()
return self._showBookmarks
endfunction
" FUNCTION: s:UI.getShowFiles() {{{1
function! s:UI.getShowFiles()
return self._showFiles
endfunction
" FUNCTION: s:UI.getShowHelp() {{{1
function! s:UI.getShowHelp()
return self._showHelp
endfunction
" FUNCTION: s:UI.getShowHidden() {{{1
function! s:UI.getShowHidden()
return self._showHidden
endfunction
" FUNCTION: s:UI._indentLevelFor(line) {{{1
function! s:UI._indentLevelFor(line)
" Replace multi-character DirArrows with a single space so the
" indentation calculation doesn't get messed up.
if g:NERDTreeDirArrowExpandable ==# ''
let l:line = ' '.a:line
else
let l:line = substitute(substitute(a:line, '\V'.g:NERDTreeDirArrowExpandable, ' ', ''), '\V'.g:NERDTreeDirArrowCollapsible, ' ', '')
endif
let leadChars = match(l:line, '\M\[^ ]')
return leadChars / s:UI.IndentWid()
endfunction
" FUNCTION: s:UI.IndentWid() {{{1
function! s:UI.IndentWid()
return 2
endfunction
" FUNCTION: s:UI.isIgnoreFilterEnabled() {{{1
function! s:UI.isIgnoreFilterEnabled()
return self._ignoreEnabled ==# 1
endfunction
" FUNCTION: s:UI.isMinimal() {{{1
function! s:UI.isMinimal()
return g:NERDTreeMinimalUI
endfunction
" FUNCTION: s:UI.MarkupReg() {{{1
function! s:UI.MarkupReg()
return '^ *['.g:NERDTreeDirArrowExpandable.g:NERDTreeDirArrowCollapsible.']\? '
endfunction
" FUNCTION: s:UI._renderBookmarks {{{1
function! s:UI._renderBookmarks()
if !self.isMinimal()
call setline(line('.')+1, '>----------Bookmarks----------')
call cursor(line('.')+1, col('.'))
endif
if g:NERDTreeBookmarksSort ==# 1 || g:NERDTreeBookmarksSort ==# 2
call g:NERDTreeBookmark.SortBookmarksList()
endif
for i in g:NERDTreeBookmark.Bookmarks()
call setline(line('.')+1, i.str())
call cursor(line('.')+1, col('.'))
endfor
call setline(line('.')+1, '')
call cursor(line('.')+1, col('.'))
endfunction
" FUNCTION: s:UI.restoreScreenState() {{{1
"
" Sets the screen state back to what it was when nerdtree#saveScreenState was last
" called.
"
" Assumes the cursor is in the NERDTree window
function! s:UI.restoreScreenState()
if !has_key(self, '_screenState')
return
endif
call nerdtree#exec('silent vertical resize ' . self._screenState['oldWindowSize'], 1)
let old_scrolloff=&scrolloff
let &scrolloff=0
call cursor(self._screenState['oldTopLine'], 0)
normal! zt
call setpos('.', self._screenState['oldPos'])
let &scrolloff=old_scrolloff
endfunction
" FUNCTION: s:UI.saveScreenState() {{{1
" Saves the current cursor position in the current buffer and the window
" scroll position
function! s:UI.saveScreenState()
let win = winnr()
let self._screenState = {}
try
call g:NERDTree.CursorToTreeWin()
let self._screenState['oldPos'] = getpos('.')
let self._screenState['oldTopLine'] = line('w0')
let self._screenState['oldWindowSize'] = winnr('$')==1 ? g:NERDTreeWinSize : winwidth('')
call nerdtree#exec(win . 'wincmd w', 1)
catch
endtry
endfunction
" FUNCTION: s:UI.setShowHidden(val) {{{1
function! s:UI.setShowHidden(val)
let self._showHidden = a:val
endfunction
" FUNCTION: s:UI._stripMarkup(line){{{1
" find the filename in the given line, and return it.
"
" Args:
" line: the subject line
function! s:UI._stripMarkup(line)
let l:line = substitute(a:line, '^.\{-}' . g:NERDTreeNodeDelimiter, '', '')
return substitute(l:line, g:NERDTreeNodeDelimiter.'.*$', '', '')
endfunction
" FUNCTION: s:UI.render() {{{1
function! s:UI.render()
setlocal noreadonly modifiable
" remember the top line of the buffer and the current line so we can
" restore the view exactly how it was
let curLine = line('.')
let curCol = col('.')
let topLine = line('w0')
" delete all lines in the buffer (being careful not to clobber a register)
silent 1,$delete _
call self._dumpHelp()
" delete the blank line before the help and add one after it
if !self.isMinimal()
call setline(line('.')+1, '')
call cursor(line('.')+1, col('.'))
endif
if self.getShowBookmarks()
call self._renderBookmarks()
endif
" add the 'up a dir' line
if !self.isMinimal()
call setline(line('.')+1, s:UI.UpDirLine())
call cursor(line('.')+1, col('.'))
endif
" draw the header line
let header = self.nerdtree.root.path.str({'format': 'UI', 'truncateTo': winwidth(0)})
call setline(line('.')+1, header)
call cursor(line('.')+1, col('.'))
" draw the tree
silent put =self.nerdtree.root.renderToString()
" delete the blank line at the top of the buffer
silent 1,1delete _
" restore the view
let old_scrolloff=&scrolloff
let &scrolloff=0
call cursor(topLine, 1)
normal! zt
call cursor(curLine, curCol)
let &scrolloff = old_scrolloff
setlocal readonly nomodifiable
endfunction
" FUNCTION: UI.renderViewSavingPosition {{{1
" Renders the tree and ensures the cursor stays on the current node or the
" current nodes parent if it is no longer available upon re-rendering
function! s:UI.renderViewSavingPosition()
let currentNode = g:NERDTreeFileNode.GetSelected()
" go up the tree till we find a node that will be visible or till we run
" out of nodes
while currentNode !=# {} && !currentNode.isVisible() && !currentNode.isRoot()
let currentNode = currentNode.parent
endwhile
call self.render()
if currentNode !=# {}
call currentNode.putCursorHere(0, 0)
endif
endfunction
" FUNCTION: s:UI.toggleHelp() {{{1
function! s:UI.toggleHelp()
let self._showHelp = !self._showHelp
endfunction
" FUNCTION: s:UI.toggleIgnoreFilter() {{{1
" toggles the use of the NERDTreeIgnore option
function! s:UI.toggleIgnoreFilter()
let self._ignoreEnabled = !self._ignoreEnabled
call self.renderViewSavingPosition()
call self.centerView()
endfunction
" FUNCTION: s:UI.toggleShowBookmarks() {{{1
" Toggle the visibility of the Bookmark table.
function! s:UI.toggleShowBookmarks()
let self._showBookmarks = !self._showBookmarks
if self.getShowBookmarks()
call self.nerdtree.render()
call g:NERDTree.CursorToBookmarkTable()
else
if empty(g:NERDTreeFileNode.GetSelected())
call b:NERDTree.root.putCursorHere(0, 0)
normal! 0
endif
call self.renderViewSavingPosition()
endif
call self.centerView()
endfunction
" FUNCTION: s:UI.toggleShowFiles() {{{1
" toggles the display of hidden files
function! s:UI.toggleShowFiles()
let self._showFiles = !self._showFiles
call self.renderViewSavingPosition()
call self.centerView()
endfunction
" FUNCTION: s:UI.toggleShowHidden() {{{1
" toggles the display of hidden files
function! s:UI.toggleShowHidden()
let self._showHidden = !self._showHidden
call self.renderViewSavingPosition()
call self.centerView()
endfunction
" FUNCTION: s:UI.toggleZoom() {{{1
" zoom (maximize/minimize) the NERDTree window
function! s:UI.toggleZoom()
if exists('b:NERDTreeZoomed') && b:NERDTreeZoomed
call nerdtree#exec('silent vertical resize '. g:NERDTreeWinSize, 1)
let b:NERDTreeZoomed = 0
else
call nerdtree#exec('vertical resize '. get(g:, 'NERDTreeWinSizeMax', ''), 1)
let b:NERDTreeZoomed = 1
endif
endfunction
" FUNCTION: s:UI.UpDirLine() {{{1
function! s:UI.UpDirLine()
return '.. (up a dir)'
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,40 +0,0 @@
" ============================================================================
" File: exec_menuitem.vim
" Description: plugin for NERD Tree that provides an execute file menu item
" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
"
" ============================================================================
if exists('g:loaded_nerdtree_exec_menuitem')
finish
endif
let g:loaded_nerdtree_exec_menuitem = 1
call NERDTreeAddMenuItem({
\ 'text': '(!)Execute file',
\ 'shortcut': '!',
\ 'callback': 'NERDTreeExecFile',
\ 'isActiveCallback': 'NERDTreeExecFileActive' })
function! NERDTreeExecFileActive()
let node = g:NERDTreeFileNode.GetSelected()
return !node.path.isDirectory && node.path.isExecutable
endfunction
function! NERDTreeExecFile()
let treenode = g:NERDTreeFileNode.GetSelected()
echo "==========================================================\n"
echo "Complete the command to execute (add arguments etc):\n"
let cmd = treenode.path.str({'escape': 1})
let cmd = input(':!', cmd . ' ')
if cmd !=# ''
exec ':!' . cmd
else
echo 'Aborted'
endif
endfunction

View File

@@ -1,484 +0,0 @@
" ============================================================================
" File: fs_menu.vim
" Description: plugin for the NERD Tree that provides a file system menu
" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
"
" ============================================================================
if exists('g:loaded_nerdtree_fs_menu')
finish
endif
let g:loaded_nerdtree_fs_menu = 1
"Automatically delete the buffer after deleting or renaming a file
if !exists('g:NERDTreeAutoDeleteBuffer')
let g:NERDTreeAutoDeleteBuffer = 0
endif
call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callback': 'NERDTreeAddNode'})
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')
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'})
endif
if executable('xdg-open')
call NERDTreeAddMenuItem({'text': '(r)eveal the current node in file manager', 'shortcut': 'r', 'callback': 'NERDTreeRevealFileLinux'})
call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFileLinux'})
endif
if nerdtree#runningWindows()
call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFileWindows'})
endif
if g:NERDTreePath.CopyingSupported()
call NERDTreeAddMenuItem({'text': '(c)opy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'})
endif
call NERDTreeAddMenuItem({'text': (has('clipboard')?'copy (p)ath to clipboard':'print (p)ath to screen'), 'shortcut': 'p', 'callback': 'NERDTreeCopyPath'})
if has('unix') || has('osx')
call NERDTreeAddMenuItem({'text': '(l)ist the current node', 'shortcut': 'l', 'callback': 'NERDTreeListNode'})
else
call NERDTreeAddMenuItem({'text': '(l)ist the current node', 'shortcut': 'l', 'callback': 'NERDTreeListNodeWin32'})
endif
if exists('*system')
call NERDTreeAddMenuItem({'text': 'Run (s)ystem command in this directory', 'shortcut':'s', 'callback': 'NERDTreeSystemCommand'})
endif
"FUNCTION: s:inputPrompt(action){{{1
"returns the string that should be prompted to the user for the given action
"
"Args:
"action: the action that is being performed, e.g. 'delete'
function! s:inputPrompt(action)
if a:action ==# 'add'
let title = 'Add a childnode'
let info = "Enter the dir/file name to be created. Dirs end with a '/'"
let minimal = 'Add node:'
elseif a:action ==# 'copy'
let title = 'Copy the current node'
let info = 'Enter the new path to copy the node to:'
let minimal = 'Copy to:'
elseif a:action ==# 'delete'
let title = 'Delete the current node'
let info = 'Are you sure you wish to delete the node:'
let minimal = 'Delete?'
elseif a:action ==# 'deleteNonEmpty'
let title = 'Delete the current node'
let info = "STOP! Directory is not empty! To delete, type 'yes'"
let minimal = 'Delete directory?'
elseif a:action ==# 'move'
let title = 'Rename the current node'
let info = 'Enter the new path for the node:'
let minimal = 'Move to:'
endif
if g:NERDTreeMenuController.isMinimal()
redraw! " Clear the menu
return minimal . ' '
else
let divider = '=========================================================='
return title . "\n" . divider . "\n" . info . "\n"
end
endfunction
"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{1
"prints out the given msg and, if the user responds by pushing 'y' then the
"buffer with the given bufnum is deleted
"
"Args:
"bufnum: the buffer that may be deleted
"msg: a message that will be echoed to the user asking them if they wish to
" del the buffer
function! s:promptToDelBuffer(bufnum, msg)
echo a:msg
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
" 1. ensure that all windows which display the just deleted filename
" now display an empty buffer (so a layout is preserved).
" Is not it better to close single tabs with this file only ?
let s:originalTabNumber = tabpagenr()
let s:originalWindowNumber = winnr()
" Go to the next buffer in buffer list if at least one extra buffer is listed
" Otherwise open a new empty buffer
if v:version >= 800
let l:listedBufferCount = len(getbufinfo({'buflisted':1}))
elseif v:version >= 702
let l:listedBufferCount = len(filter(range(1, bufnr('$')), 'buflisted(v:val)'))
else
" Ignore buffer count in this case to make sure we keep the old
" behavior
let l:listedBufferCount = 0
endif
if l:listedBufferCount > 1
call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . a:bufnum . " | exec ':bnext! ' | endif", 1)
else
call nerdtree#exec('tabdo windo if winbufnr(0) ==# ' . a:bufnum . " | exec ':enew! ' | endif", 1)
endif
call nerdtree#exec('tabnext ' . s:originalTabNumber, 1)
call nerdtree#exec(s:originalWindowNumber . 'wincmd w', 1)
" 3. We don't need a previous buffer anymore
call nerdtree#exec('bwipeout! ' . a:bufnum, 0)
endif
endfunction
"FUNCTION: s:renameBuffer(bufNum, newNodeName, isDirectory){{{1
"The buffer with the given bufNum is replaced with a new one
"
"Args:
"bufNum: the buffer that may be deleted
"newNodeName: the name given to the renamed node
"isDirectory: determines how to do the create the new filenames
function! s:renameBuffer(bufNum, newNodeName, isDirectory)
if a:isDirectory
let quotedFileName = fnameescape(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t'))
let editStr = g:NERDTreePath.New(a:newNodeName . '/' . fnamemodify(bufname(a:bufNum),':t')).str({'format': 'Edit'})
else
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)
call nerdtree#exec('tabnext ' . s:originalTabNumber, 1)
call nerdtree#exec(s:originalWindowNumber . 'wincmd w', 1)
" 3. We don't need a previous buffer anymore
try
call nerdtree#exec('confirm bwipeout ' . a:bufNum, 0)
catch
" This happens when answering Cancel if confirmation is needed. Do nothing.
endtry
endfunction
"FUNCTION: NERDTreeAddNode(){{{1
function! NERDTreeAddNode()
let curDirNode = g:NERDTreeDirNode.GetSelected()
let prompt = s:inputPrompt('add')
let newNodeName = substitute(input(prompt, curDirNode.path.str() . nerdtree#slash(), 'file'), '\(^\s*\|\s*$\)', '', 'g')
if newNodeName ==# ''
call nerdtree#echo('Node Creation Aborted.')
return
endif
try
let newPath = g:NERDTreePath.Create(newNodeName)
let parentNode = b:NERDTree.root.findNode(newPath.getParent())
let newTreeNode = g:NERDTreeFileNode.New(newPath, b:NERDTree)
" Emptying g:NERDTreeOldSortOrder forces the sort to
" recalculate the cached sortKey so nodes sort correctly.
let g:NERDTreeOldSortOrder = []
if empty(parentNode)
call b:NERDTree.root.refresh()
call b:NERDTree.render()
elseif parentNode.isOpen || !empty(parentNode.children)
call parentNode.addChild(newTreeNode, 1)
call NERDTreeRender()
call newTreeNode.putCursorHere(1, 0)
endif
redraw!
catch /^NERDTree/
call nerdtree#echoWarning('Node Not Created.')
endtry
endfunction
"FUNCTION: NERDTreeMoveNode(){{{1
function! NERDTreeMoveNode()
let curNode = g:NERDTreeFileNode.GetSelected()
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.')
let newNodePath = substitute(input(prompt, curNode.path.str(), 'file'), '\(^\s*\|\s*$\)', '', 'g')
endwhile
if newNodePath ==# ''
call nerdtree#echo('Node Renaming Aborted.')
return
endif
try
if curNode.path.isDirectory
let l:curPath = escape(curNode.path.str(),'\') . (nerdtree#runningWindows()?'\\':'/') . '.*'
let l:openBuffers = filter(range(1,bufnr('$')),'bufexists(v:val) && fnamemodify(bufname(v:val),":p") =~# "'.escape(l:curPath,'\').'"')
else
let l:openBuffers = filter(range(1,bufnr('$')),'bufexists(v:val) && fnamemodify(bufname(v:val),":p") ==# curNode.path.str()')
endif
call curNode.rename(newNodePath)
" Emptying g:NERDTreeOldSortOrder forces the sort to
" recalculate the cached sortKey so nodes sort correctly.
let g:NERDTreeOldSortOrder = []
call b:NERDTree.root.refresh()
call NERDTreeRender()
" If the file node is open, or files under the directory node are
" open, ask the user if they want to replace the file(s) with the
" renamed files.
if !empty(l:openBuffers)
if curNode.path.isDirectory
echo "\nDirectory renamed.\n\nFiles with the old directory name are open in buffers " . join(l:openBuffers, ', ') . '. Replace these buffers with the new files? (yN)'
else
echo "\nFile renamed.\n\nThe old file is open in buffer " . l:openBuffers[0] . '. Replace this buffer with the new file? (yN)'
endif
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
for bufNum in l:openBuffers
call s:renameBuffer(bufNum, newNodePath, curNode.path.isDirectory)
endfor
endif
endif
call curNode.putCursorHere(1, 0)
redraw!
catch /^NERDTree/
call nerdtree#echoWarning('Node Not Renamed.')
endtry
endfunction
" FUNCTION: NERDTreeDeleteNode() {{{1
function! NERDTreeDeleteNode()
let currentNode = g:NERDTreeFileNode.GetSelected()
let confirmed = 0
if currentNode.path.isDirectory && ((currentNode.isOpen && currentNode.getChildCount() > 0) ||
\ (len(currentNode._glob('*', 1)) > 0))
let prompt = s:inputPrompt('deleteNonEmpty') . currentNode.path.str() . ': '
let choice = input(prompt)
let confirmed = choice ==# 'yes'
else
let prompt = s:inputPrompt('delete') . currentNode.path.str() . ' (yN): '
echo prompt
let choice = nr2char(getchar())
let confirmed = choice ==# 'y'
endif
if confirmed
try
call currentNode.delete()
call NERDTreeRender()
"if the node is open in a buffer, ask the user if they want to
"close that buffer
let bufnum = bufnr('^'.currentNode.path.str().'$')
if buflisted(bufnum)
let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? ' (hidden)' : '') .'. Delete this buffer? (yN)'
call s:promptToDelBuffer(bufnum, prompt)
endif
redraw!
catch /^NERDTree/
call nerdtree#echoWarning('Could not remove node')
endtry
else
call nerdtree#echo('delete aborted')
endif
endfunction
" FUNCTION: NERDTreeListNode() {{{1
function! NERDTreeListNode()
let treenode = g:NERDTreeFileNode.GetSelected()
if !empty(treenode)
let s:uname = system('uname')
let stat_cmd = 'stat -c "%s" '
if s:uname =~? 'Darwin'
let stat_cmd = 'stat -f "%z" '
endif
let cmd = 'size=$(' . stat_cmd . shellescape(treenode.path.str()) . ') && ' .
\ 'size_with_commas=$(echo $size | sed -e :a -e "s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta") && ' .
\ 'ls -ld ' . shellescape(treenode.path.str()) . ' | sed -e "s/ $size / $size_with_commas /"'
let metadata = split(system(cmd),'\n')
call nerdtree#echo(metadata[0])
else
call nerdtree#echo('No information available')
endif
endfunction
" FUNCTION: NERDTreeListNodeWin32() {{{1
function! NERDTreeListNodeWin32()
let l:node = g:NERDTreeFileNode.GetSelected()
if !empty(l:node)
let l:path = l:node.path.str()
call nerdtree#echo(printf('%s:%s MOD:%s BYTES:%d PERMISSIONS:%s',
\ toupper(getftype(l:path)),
\ fnamemodify(l:path, ':t'),
\ strftime('%c', getftime(l:path)),
\ getfsize(l:path),
\ getfperm(l:path)))
return
endif
call nerdtree#echo('node not recognized')
endfunction
" FUNCTION: NERDTreeCopyNode() {{{1
function! NERDTreeCopyNode()
let currentNode = g:NERDTreeFileNode.GetSelected()
let prompt = s:inputPrompt('copy')
let newNodePath = substitute(input(prompt, currentNode.path.str(), 'file'), '\(^\s*\|\s*$\)', '', 'g')
if newNodePath !=# ''
"strip trailing slash
let newNodePath = substitute(newNodePath, '\/$', '', '')
let confirmed = 1
if currentNode.path.copyingWillOverwrite(newNodePath)
call nerdtree#echo('Warning: copying may overwrite files! Continue? (yN)')
let choice = nr2char(getchar())
let confirmed = choice ==# 'y'
endif
if confirmed
try
let newNode = currentNode.copy(newNodePath)
" Emptying g:NERDTreeOldSortOrder forces the sort to
" recalculate the cached sortKey so nodes sort correctly.
let g:NERDTreeOldSortOrder = []
if empty(newNode)
call b:NERDTree.root.refresh()
call b:NERDTree.render()
else
call NERDTreeRender()
call newNode.putCursorHere(0, 0)
endif
catch /^NERDTree/
call nerdtree#echoWarning('Could not copy node')
endtry
endif
else
call nerdtree#echo('Copy aborted.')
endif
redraw!
endfunction
" FUNCTION: NERDTreeCopyPath() {{{1
function! NERDTreeCopyPath()
let l:nodePath = g:NERDTreeFileNode.GetSelected().path.str()
if has('clipboard')
if &clipboard ==# 'unnamedplus'
let @+ = l:nodePath
else
let @* = l:nodePath
endif
call nerdtree#echo('The path [' . l:nodePath . '] was copied to your clipboard.')
else
call nerdtree#echo('The full path is: ' . l:nodePath)
endif
endfunction
" FUNCTION: NERDTreeQuickLook() {{{1
function! NERDTreeQuickLook()
let l:node = g:NERDTreeFileNode.GetSelected()
if empty(l:node)
return
endif
call system('qlmanage -p 2>/dev/null ' . shellescape(l:node.path.str()))
endfunction
" FUNCTION: NERDTreeRevealInFinder() {{{1
function! NERDTreeRevealInFinder()
let l:node = g:NERDTreeFileNode.GetSelected()
if empty(l:node)
return
endif
call system('open -R ' . shellescape(l:node.path.str()))
endfunction
" FUNCTION: NERDTreeExecuteFile() {{{1
function! NERDTreeExecuteFile()
let l:node = g:NERDTreeFileNode.GetSelected()
if empty(l:node)
return
endif
call system('open ' . shellescape(l:node.path.str()))
endfunction
" FUNCTION: NERDTreeRevealFileLinux() {{{1
function! NERDTreeRevealFileLinux()
let l:node = g:NERDTreeFileNode.GetSelected()
if empty(l:node)
return
endif
" Handle the edge case of "/", which has no parent.
if l:node.path.str() ==# '/'
call system('xdg-open /')
return
endif
if empty(l:node.parent)
return
endif
call system('xdg-open ' . shellescape(l:node.parent.path.str()))
endfunction
" FUNCTION: NERDTreeExecuteFileLinux() {{{1
function! NERDTreeExecuteFileLinux()
let l:node = g:NERDTreeFileNode.GetSelected()
if empty(l:node)
return
endif
call system('xdg-open ' . shellescape(l:node.path.str()))
endfunction
" FUNCTION: NERDTreeExecuteFileWindows() {{{1
function! NERDTreeExecuteFileWindows()
let l:node = g:NERDTreeFileNode.GetSelected()
if empty(l:node)
return
endif
call system('cmd.exe /c start "" ' . shellescape(l:node.path.str()))
endfunction
" FUNCTION: NERDTreeSystemCommand() {{{1
function! NERDTreeSystemCommand()
let l:node = g:NERDTreeFileNode.GetSelected()
if empty(l:node)
return
endif
let l:cwd = getcwd()
let l:directory = l:node.path.isDirectory ? l:node.path.str() : l:node.parent.path.str()
execute 'cd '.l:directory
let l:nl = nr2char(10)
echo l:nl . system(input(l:directory . (nerdtree#runningWindows() ? '> ' : ' $ ')))
execute 'cd '.l:cwd
endfunction
" vim: set sw=4 sts=4 et fdm=marker:

View File

@@ -1,47 +0,0 @@
" ============================================================================
" File: vcs.vim
" Description: NERDTree plugin that provides a command to open on the root of
" a version control system repository.
" Maintainer: Phil Runninger
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
"
" ============================================================================
command! -n=? -complete=dir -bar NERDTreeVCS :call <SID>CreateTabTreeVCS('<args>')
command! -n=? -complete=dir -bar NERDTreeToggleVCS :call <SID>ToggleTabTreeVCS('<args>')
" FUNCTION: s:CreateTabTreeVCS(a:name) {{{1
function! s:CreateTabTreeVCS(name)
let l:path = g:NERDTreeCreator._pathForString(a:name)
let l:path = s:FindParentVCSRoot(l:path)
call g:NERDTreeCreator.createTabTree(empty(l:path) ? '' : l:path._str())
endfunction
" FUNCTION: s:ToggleTabTreeVCS(a:name) {{{1
" Behaves the same as ToggleTabTree except roots directory at VCS root
function! s:ToggleTabTreeVCS(name)
let l:path = g:NERDTreeCreator._pathForString(a:name)
let l:path = s:FindParentVCSRoot(l:path)
call g:NERDTreeCreator.toggleTabTree(empty(l:path) ? '' : l:path._str())
endfunction
" FUNCTION: s:FindParentVCSRoot(a:path) {{{1
" Finds the root version control system folder of the given path. If a:path is
" not part of a repository, return the original path.
function! s:FindParentVCSRoot(path)
let l:path = a:path
while !empty(l:path) &&
\ l:path._str() !~# '^\(\a:[\\\/]\|\/\)$' &&
\ !isdirectory(l:path._str() . '/.git') &&
\ !isdirectory(l:path._str() . '/.svn') &&
\ !isdirectory(l:path._str() . '/.hg') &&
\ !isdirectory(l:path._str() . '/.bzr') &&
\ !isdirectory(l:path._str() . '/_darcs')
let l:path = l:path.getParent()
endwhile
return (empty(l:path) || l:path._str() =~# '^\(\a:[\\\/]\|\/\)$') ? a:path : l:path
endfunction

View File

@@ -1,234 +0,0 @@
" ============================================================================
" File: NERD_tree.vim
" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
"
" ============================================================================
"
" SECTION: Script init stuff {{{1
"============================================================
scriptencoding utf-8
if exists('loaded_nerd_tree')
finish
endif
if v:version < 703
echoerr "NERDTree: this plugin requires vim >= 7.3. DOWNLOAD IT! You'll thank me later!"
finish
endif
let loaded_nerd_tree = 1
"for line continuation - i.e dont want C in &cpoptions
let s:old_cpo = &cpoptions
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:NERDTreeCaseSensitiveSort = get(g:, 'NERDTreeCaseSensitiveSort', 0)
let g:NERDTreeNaturalSort = get(g:, 'NERDTreeNaturalSort', 0)
let g:NERDTreeSortHiddenFirst = get(g:, 'NERDTreeSortHiddenFirst', 1)
let g:NERDTreeUseTCD = get(g:, 'NERDTreeUseTCD', 0)
let g:NERDTreeChDirMode = get(g:, 'NERDTreeChDirMode', 0)
let g:NERDTreeCreatePrefix = get(g:, 'NERDTreeCreatePrefix', 'silent')
let g:NERDTreeMinimalUI = get(g:, 'NERDTreeMinimalUI', 0)
let g:NERDTreeMinimalMenu = get(g:, 'NERDTreeMinimalMenu', 0)
let g:NERDTreeIgnore = get(g:, 'NERDTreeIgnore', ['\~$'])
let g:NERDTreeBookmarksFile = get(g:, 'NERDTreeBookmarksFile', expand('$HOME') . '/.NERDTreeBookmarks')
let g:NERDTreeBookmarksSort = get(g:, 'NERDTreeBookmarksSort', 1)
let g:NERDTreeHighlightCursorline = get(g:, 'NERDTreeHighlightCursorline', 1)
let g:NERDTreeHijackNetrw = get(g:, 'NERDTreeHijackNetrw', 1)
let g:NERDTreeMarkBookmarks = get(g:, 'NERDTreeMarkBookmarks', 1)
let g:NERDTreeMouseMode = get(g:, 'NERDTreeMouseMode', 1)
let g:NERDTreeNotificationThreshold = get(g:, 'NERDTreeNotificationThreshold', 100)
let g:NERDTreeQuitOnOpen = get(g:, 'NERDTreeQuitOnOpen', 0)
let g:NERDTreeRespectWildIgnore = get(g:, 'NERDTreeRespectWildIgnore', 0)
let g:NERDTreeShowBookmarks = get(g:, 'NERDTreeShowBookmarks', 0)
let g:NERDTreeShowFiles = get(g:, 'NERDTreeShowFiles', 1)
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', '▾')
else
let g:NERDTreeDirArrowExpandable = get(g:, 'NERDTreeDirArrowExpandable', '+')
let g:NERDTreeDirArrowCollapsible = get(g:, 'NERDTreeDirArrowCollapsible', '~')
endif
let g:NERDTreeCascadeOpenSingleChildDir = get(g:, 'NERDTreeCascadeOpenSingleChildDir', 1)
let g:NERDTreeCascadeSingleChildDir = get(g:, 'NERDTreeCascadeSingleChildDir', 1)
let g:NERDTreeSortOrder = get(g:, 'NERDTreeSortOrder', ['\/$', '*', '\.swp$', '\.bak$', '\~$'])
let g:NERDTreeOldSortOrder = []
let g:NERDTreeGlyphReadOnly = get(g:, 'NERDTreeGlyphReadOnly', 'RO')
if has('conceal')
let g:NERDTreeNodeDelimiter = get(g:, 'NERDTreeNodeDelimiter', "\x07")
elseif (g:NERDTreeDirArrowExpandable ==# "\u00a0" || g:NERDTreeDirArrowCollapsible ==# "\u00a0")
let g:NERDTreeNodeDelimiter = get(g:, 'NERDTreeNodeDelimiter', "\u00b7")
else
let g:NERDTreeNodeDelimiter = get(g:, 'NERDTreeNodeDelimiter', "\u00a0")
endif
"the exists() crap here is a hack to stop vim spazzing out when
"loading a session that was created with an open nerd tree. It spazzes
"because it doesnt store b:NERDTree(its a b: var, and its a hash)
let g:NERDTreeStatusline = get(g:, 'NERDTreeStatusline', "%{exists('b:NERDTree')?b:NERDTree.root.path.str():''}")
let g:NERDTreeWinPos = get(g:, 'NERDTreeWinPos', 'left')
let g:NERDTreeWinSize = get(g:, 'NERDTreeWinSize', 31)
"init the shell commands that will be used to copy nodes, and remove dir trees
"Note: the space after the command is important
if nerdtree#runningWindows()
let g:NERDTreeRemoveDirCmd = get(g:, 'NERDTreeRemoveDirCmd', 'rmdir /s /q ')
let g:NERDTreeCopyDirCmd = get(g:, 'NERDTreeCopyDirCmd', 'xcopy /s /e /i /y /q ')
let g:NERDTreeCopyFileCmd = get(g:, 'NERDTreeCopyFileCmd', 'copy /y ')
else
let g:NERDTreeRemoveDirCmd = get(g:, 'NERDTreeRemoveDirCmd', 'rm -rf ')
let g:NERDTreeCopyCmd = get(g:, 'NERDTreeCopyCmd', 'cp -r ')
endif
"SECTION: Init variable calls for key mappings {{{2
let g:NERDTreeMapCustomOpen = get(g:, 'NERDTreeMapCustomOpen', '<CR>')
let g:NERDTreeMapActivateNode = get(g:, 'NERDTreeMapActivateNode', 'o')
let g:NERDTreeMapChangeRoot = get(g:, 'NERDTreeMapChangeRoot', 'C')
let g:NERDTreeMapChdir = get(g:, 'NERDTreeMapChdir', 'cd')
let g:NERDTreeMapCloseChildren = get(g:, 'NERDTreeMapCloseChildren', 'X')
let g:NERDTreeMapCloseDir = get(g:, 'NERDTreeMapCloseDir', 'x')
let g:NERDTreeMapDeleteBookmark = get(g:, 'NERDTreeMapDeleteBookmark', 'D')
let g:NERDTreeMapMenu = get(g:, 'NERDTreeMapMenu', 'm')
let g:NERDTreeMapHelp = get(g:, 'NERDTreeMapHelp', '?')
let g:NERDTreeMapJumpFirstChild = get(g:, 'NERDTreeMapJumpFirstChild', 'K')
let g:NERDTreeMapJumpLastChild = get(g:, 'NERDTreeMapJumpLastChild', 'J')
let g:NERDTreeMapJumpNextSibling = get(g:, 'NERDTreeMapJumpNextSibling', '<C-j>')
let g:NERDTreeMapJumpParent = get(g:, 'NERDTreeMapJumpParent', 'p')
let g:NERDTreeMapJumpPrevSibling = get(g:, 'NERDTreeMapJumpPrevSibling', '<C-k>')
let g:NERDTreeMapJumpRoot = get(g:, 'NERDTreeMapJumpRoot', 'P')
let g:NERDTreeMapOpenExpl = get(g:, 'NERDTreeMapOpenExpl', 'e')
let g:NERDTreeMapOpenInTab = get(g:, 'NERDTreeMapOpenInTab', 't')
let g:NERDTreeMapOpenInTabSilent = get(g:, 'NERDTreeMapOpenInTabSilent', 'T')
let g:NERDTreeMapOpenRecursively = get(g:, 'NERDTreeMapOpenRecursively', 'O')
let g:NERDTreeMapOpenSplit = get(g:, 'NERDTreeMapOpenSplit', 'i')
let g:NERDTreeMapOpenVSplit = get(g:, 'NERDTreeMapOpenVSplit', 's')
let g:NERDTreeMapPreview = get(g:, 'NERDTreeMapPreview', 'g'.NERDTreeMapActivateNode)
let g:NERDTreeMapPreviewSplit = get(g:, 'NERDTreeMapPreviewSplit', 'g'.NERDTreeMapOpenSplit)
let g:NERDTreeMapPreviewVSplit = get(g:, 'NERDTreeMapPreviewVSplit', 'g'.NERDTreeMapOpenVSplit)
let g:NERDTreeMapQuit = get(g:, 'NERDTreeMapQuit', 'q')
let g:NERDTreeMapRefresh = get(g:, 'NERDTreeMapRefresh', 'r')
let g:NERDTreeMapRefreshRoot = get(g:, 'NERDTreeMapRefreshRoot', 'R')
let g:NERDTreeMapToggleBookmarks = get(g:, 'NERDTreeMapToggleBookmarks', 'B')
let g:NERDTreeMapToggleFiles = get(g:, 'NERDTreeMapToggleFiles', 'F')
let g:NERDTreeMapToggleFilters = get(g:, 'NERDTreeMapToggleFilters', 'f')
let g:NERDTreeMapToggleHidden = get(g:, 'NERDTreeMapToggleHidden', 'I')
let g:NERDTreeMapToggleZoom = get(g:, 'NERDTreeMapToggleZoom', 'A')
let g:NERDTreeMapUpdir = get(g:, 'NERDTreeMapUpdir', 'u')
let g:NERDTreeMapUpdirKeepOpen = get(g:, 'NERDTreeMapUpdirKeepOpen', 'U')
let g:NERDTreeMapCWD = get(g:, 'NERDTreeMapCWD', 'CD')
let g:NERDTreeMenuDown = get(g:, 'NERDTreeMenuDown', 'j')
let g:NERDTreeMenuUp = get(g:, 'NERDTreeMenuUp', 'k')
"SECTION: Load class files{{{2
call nerdtree#loadClassFiles()
" SECTION: Commands {{{1
"============================================================
call nerdtree#ui_glue#setupCommands()
" SECTION: Auto commands {{{1
"============================================================
augroup NERDTree
"Save the cursor position whenever we close the nerd tree
exec 'autocmd BufLeave,WinLeave '. g:NERDTreeCreator.BufNamePrefix() .'* if g:NERDTree.IsOpen() | call b:NERDTree.ui.saveScreenState() | endif'
"disallow insert mode in the NERDTree
exec 'autocmd BufEnter,WinEnter '. g:NERDTreeCreator.BufNamePrefix() .'* stopinsert'
augroup END
if g:NERDTreeHijackNetrw
augroup NERDTreeHijackNetrw
autocmd VimEnter * silent! autocmd! FileExplorer
au BufEnter,VimEnter * call nerdtree#checkForBrowse(expand('<amatch>'))
augroup END
endif
if g:NERDTreeChDirMode ==# 3
augroup NERDTreeChDirOnTabSwitch
autocmd TabEnter * if g:NERDTree.ExistsForTab()|call g:NERDTree.ForCurrentTab().getRoot().path.changeToDir()|endif
augroup END
endif
" SECTION: Public API {{{1
"============================================================
function! NERDTreeAddMenuItem(options)
call g:NERDTreeMenuItem.Create(a:options)
endfunction
function! NERDTreeAddMenuSeparator(...)
let opts = a:0 ? a:1 : {}
call g:NERDTreeMenuItem.CreateSeparator(opts)
endfunction
function! NERDTreeAddSubmenu(options)
return g:NERDTreeMenuItem.Create(a:options)
endfunction
function! NERDTreeAddKeyMap(options)
call g:NERDTreeKeyMap.Create(a:options)
endfunction
function! NERDTreeRender()
call nerdtree#renderView()
endfunction
function! NERDTreeFocus()
if g:NERDTree.IsOpen()
call g:NERDTree.CursorToTreeWin(0)
else
call g:NERDTreeCreator.ToggleTabTree('')
endif
endfunction
function! NERDTreeCWD()
if empty(getcwd())
call nerdtree#echoWarning('current directory does not exist')
return
endif
try
let l:cwdPath = g:NERDTreePath.New(getcwd())
catch /^NERDTree.InvalidArgumentsError/
call nerdtree#echoWarning('current directory does not exist')
return
endtry
call NERDTreeFocus()
if b:NERDTree.root.path.equals(l:cwdPath)
return
endif
let l:newRoot = g:NERDTreeFileNode.New(l:cwdPath, b:NERDTree)
call b:NERDTree.changeRoot(l:newRoot)
normal! ^
endfunction
function! NERDTreeAddPathFilter(callback)
call g:NERDTree.AddPathFilter(a:callback)
endfunction
" SECTION: Post Source Actions {{{1
call nerdtree#postSourceActions()
"reset &cpoptions back to users setting
let &cpoptions = s:old_cpo
" vim: set sw=4 sts=4 et fdm=marker:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,97 +0,0 @@
let s:tree_up_dir_line = '.. (up a dir)'
syn match NERDTreeIgnore #\~#
exec 'syn match NERDTreeIgnore #\['.g:NERDTreeGlyphReadOnly.'\]#'
"highlighting for the .. (up dir) line at the top of the tree
execute "syn match NERDTreeUp #\\V". s:tree_up_dir_line .'#'
"quickhelp syntax elements
syn match NERDTreeHelpKey #" \{1,2\}[^ ]*:#ms=s+2,me=e-1
syn match NERDTreeHelpKey #" \{1,2\}[^ ]*,#ms=s+2,me=e-1
syn match NERDTreeHelpTitle #" .*\~$#ms=s+2,me=e-1
syn match NERDTreeToggleOn #(on)#ms=s+1,he=e-1
syn match NERDTreeToggleOff #(off)#ms=e-3,me=e-1
syn match NERDTreeHelpCommand #" :.\{-}\>#hs=s+3
syn match NERDTreeHelp #^".*# contains=NERDTreeHelpKey,NERDTreeHelpTitle,NERDTreeIgnore,NERDTreeToggleOff,NERDTreeToggleOn,NERDTreeHelpCommand
"highlighting for sym links
syn match NERDTreeLinkTarget #->.*# containedin=NERDTreeDir,NERDTreeFile
syn match NERDTreeLinkFile #.* ->#me=e-3 containedin=NERDTreeFile
syn match NERDTreeLinkDir #.*/ ->#me=e-3 containedin=NERDTreeDir
"highlighting to conceal the delimiter around the file/dir name
if has('conceal')
exec 'syn match NERDTreeNodeDelimiters #\%d' . char2nr(g:NERDTreeNodeDelimiter) . '# conceal containedin=ALL'
setlocal conceallevel=2 concealcursor=nvic
else
exec 'syn match NERDTreeNodeDelimiters #\%d' . char2nr(g:NERDTreeNodeDelimiter) . '# containedin=ALL'
hi! link NERDTreeNodeDelimiters Ignore
endif
"highlighing for directory nodes and file nodes
syn match NERDTreeDirSlash #/# containedin=NERDTreeDir
if g:NERDTreeDirArrowExpandable !=# ''
exec 'syn match NERDTreeClosable #' . escape(g:NERDTreeDirArrowCollapsible, '~') . '\ze .*/# containedin=NERDTreeDir,NERDTreeFile'
exec 'syn match NERDTreeOpenable #' . escape(g:NERDTreeDirArrowExpandable, '~') . '\ze .*/# containedin=NERDTreeDir,NERDTreeFile'
let s:dirArrows = escape(g:NERDTreeDirArrowCollapsible, '~]\-').escape(g:NERDTreeDirArrowExpandable, '~]\-')
exec 'syn match NERDTreeDir #[^'.s:dirArrows.' ].*/#'
exec 'syn match NERDTreeExecFile #^.*'.g:NERDTreeNodeDelimiter.'\*\($\| \)# contains=NERDTreeRO,NERDTreeBookmarkName'
exec 'syn match NERDTreeFile #^[^"\.'.s:dirArrows.'] *[^'.s:dirArrows.']*# contains=NERDTreeLink,NERDTreeRO,NERDTreeBookmarkName,NERDTreeExecFile'
else
exec 'syn match NERDTreeDir #[^'.g:NERDTreeNodeDelimiter.']\{-}/\ze\($\|'.g:NERDTreeNodeDelimiter.'\)#'
exec 'syn match NERDTreeExecFile #[^'.g:NERDTreeNodeDelimiter.']\{-}'.g:NERDTreeNodeDelimiter.'\*\($\| \)# contains=NERDTreeRO,NERDTreeBookmarkName'
exec 'syn match NERDTreeFile #^.*'.g:NERDTreeNodeDelimiter.'.*[^\/]\($\|'.g:NERDTreeNodeDelimiter.'.*\)# contains=NERDTreeLink,NERDTreeRO,NERDTreeBookmarkName,NERDTreeExecFile'
endif
"highlighting for readonly files
exec 'syn match NERDTreeRO #.*'.g:NERDTreeNodeDelimiter.'\zs.*\ze'.g:NERDTreeNodeDelimiter.'.*\['.g:NERDTreeGlyphReadOnly.'\]# contains=NERDTreeIgnore,NERDTreeBookmarkName,NERDTreeFile'
exec 'syn match NERDTreeFlags #\[[^\]]*\]\ze'.g:NERDTreeNodeDelimiter.'# containedin=NERDTreeFile,NERDTreeExecFile,NERDTreeLinkFile,NERDTreeRO,NERDTreeDir'
syn match NERDTreeCWD #^[</].*$#
"highlighting for bookmarks
syn match NERDTreeBookmarkName # {.*}#hs=s+2,he=e-1
"highlighting for the bookmarks table
syn match NERDTreeBookmarksLeader #^>#
syn match NERDTreeBookmarksHeader #^>-\+Bookmarks-\+$# contains=NERDTreeBookmarksLeader
syn match NERDTreeBookmarkName #^>.\{-} #he=e-1 contains=NERDTreeBookmarksLeader
syn match NERDTreeBookmark #^>.*$# contains=NERDTreeBookmarksLeader,NERDTreeBookmarkName,NERDTreeBookmarksHeader
hi def link NERDTreePart Special
hi def link NERDTreePartFile Type
hi def link NERDTreeExecFile Title
hi def link NERDTreeDirSlash Identifier
hi def link NERDTreeBookmarksHeader statement
hi def link NERDTreeBookmarksLeader ignore
hi def link NERDTreeBookmarkName Identifier
hi def link NERDTreeBookmark normal
hi def link NERDTreeHelp String
hi def link NERDTreeHelpKey Identifier
hi def link NERDTreeHelpCommand Identifier
hi def link NERDTreeHelpTitle Macro
hi def link NERDTreeToggleOn Question
hi def link NERDTreeToggleOff WarningMsg
hi def link NERDTreeLinkTarget Type
hi def link NERDTreeLinkFile Macro
hi def link NERDTreeLinkDir Macro
hi def link NERDTreeDir Directory
hi def link NERDTreeUp Directory
hi def link NERDTreeFile Normal
hi def link NERDTreeCWD Statement
hi def link NERDTreeOpenable Directory
hi def link NERDTreeClosable Directory
hi def link NERDTreeIgnore ignore
hi def link NERDTreeRO WarningMsg
hi def link NERDTreeBookmark Statement
hi def link NERDTreeFlags Number
hi def link NERDTreeCurrentNode Search
hi NERDTreeFile ctermbg=NONE guibg=NONE

View File

@@ -1 +0,0 @@
doc/tags

View File

@@ -1,110 +0,0 @@
### [Project on Vim.org](http://www.vim.org/scripts/script.php?script_id=4177)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mbbill/undotree?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Screenshot
![](doc/_static/undotree.png)
### Table of Contents
<!-- TOC -->
- [Description](#description)
- [Download and Install](#download-and-install)
- [Usage](#usage)
- [Configuration](#configuration)
- [Debug](#debug)
- [License](#license)
- [Author](#author)
<!-- /TOC -->
### Description
The plug-in visualizes undo history and makes it easier to browse and switch between different undo branches. You might wonder what is undo "branches"? It's a vim feature that allows you to go back to a state when it is overwritten by the latest edit. For most editors, if you make a change A, followed by B, then go back to A and make another change C, normally you won't be able to go back to B because undo history is linear. That's not the case for Vim because it internally keeps all the edit history as a tree structure, and this plug-in exposes the tree to you so that you not only can switch back and forth but also can switch between branches.
Some people have questions about file contents being changed when switching between undo history states. Don't worry, *undotree* will **NEVER** save your data or write to disk. All it does is to change the current buffer a little bit, just like those auto-completion plug-ins do. It just adds or removes something in the buffer temporarily, and if you don't like you can always go back to the last state easily. Let's say, you made some change but didn't save it, then you use *undotree* and go back to an arbitrary version, your unsaved change doesn't get lost - it stores in the latest undo history node. Clicking that node on *undotree* will bring you back instantly. Play with undo/redo on other editors is always dangerous because when you step back and accidentally typed something, boom! You lose your edits. But don't worry, that won't happen in Vim. Then you might ask what if I make some changes without saving and switch back to an old version and then **exit**? Well, imagine what would happen if you don't have *undotree*? You lose your latest edits and the file on disk is your last saved version. This behavior **remains the same** with *undotree*. So, if you saved, you won't lose anything.
We all know that usually undo/redo is only for the current edit session. It's stored in memory and once the process exits, the undo history is lost. Although *undotree* makes switching between history states easier, it doesn't do more than that. Sometimes it would be much safer or more convenient to keep the undo history across edit sessions. In this case, you might need to enable a Vim feature called *persistent undo*. Let me explain how persistent undo works: instead of keeping undo history in *RAM*, persistent undo keeps undo history in a file. Let's say you make a change A, followed by B, then go back to A and make another change C, then you *save* the file. Now Vim save the file with content state C, and in the meantime it saves **the entire** undo history to a file including state A, B and C. Next time when you open the file, Vim will also restore undo history. So you can still go back to B. The history file is incremental, and every change will be recorded permanently, kind of like Git. You might think that's too much, well, *undotree* does provide a way to clean them up. If you need to enable *persistent undo*, type ```:h persistent-undo``` or follow the instructions below.
Undotree is written in **pure Vim script** and doesn't rely on any third-party tools. It's lightweight, simple, and fast. It only does what it supposed to do, and it only runs when you need it.
### Download and Install
Using Vim's built-in package manager:
```sh
mkdir -p ~/.vim/pack/mbbill/start
cd ~/.vim/pack/mbbill/start
git clone https://github.com/mbbill/undotree.git
vim -u NONE -c "helptags undotree/doc" -c q
```
Use whatever plug-in manager to pull the master branch. I've included 2 examples of the most used:
- *Vundle:* `Plugin 'mbbill/undotree'`
- *Vim-Plug:* `Plug 'mbbill/undotree'`
And install them with the following:
- *Vundle:* `:PluginInstall`
- *Vim-Plug:* `:PlugInstall`
### Usage
1. Use `:UndotreeToggle` to toggle the undo-tree panel. You may want to map this command to whatever hotkey by adding the following line to your vimrc, take `F5` for example.
```vim
nnoremap <F5> :UndotreeToggle<CR>
```
1. Markers
* Every change has a sequence number and it is displayed before timestamps.
* The current state is marked as `> number <`.
* The next state which will be restored by `:redo` or `<ctrl-r>` is marked as `{ number }`.
* The `[ number ]` marks the most recent change.
* The undo history is sorted by timestamps.
* Saved changes are marked as `s` and the big `S` indicates the most recent saved change.
2. Press `?` in undotree window for quick help.
3. Persistent undo
* Usually, I would like to store the undo files in a separate place like below.
```vim
if has("persistent_undo")
let target_path = expand('~/.undodir')
" create the directory and any parent directories
" if the location does not exist.
if !isdirectory(target_path)
call mkdir(target_path, "p", 0700)
endif
let &undodir=target_path
set undofile
endif
```
#### Configuration
[Here](https://github.com/mbbill/undotree/blob/master/plugin/undotree.vim#L15) is a list of options.
#### Debug
1. Create a file under $HOME with the name `undotree_debug.log`
* `$touch ~/undotree_debug.log`
2. Run vim, and the log will automatically be appended to the file, and you may watch it using `tail`:
* `$tail -F ~/undotree_debug.log`
3. If you want to disable debug, just delete that file.
### License
**BSD**
### Author
Ming Bai &lt;mbbill AT gmail DOT COM&gt;

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

View File

@@ -1,480 +0,0 @@
*undotree.txt* The undo history visualizer for VIM
Author: Ming Bai <mbbill AT gmail DOT COM>
Licence: BSD
Homepage: https://github.com/mbbill/undotree/
==============================================================================
CONTENTS *undotree-contents*
1. Intro ................................ |undotree-intro|
2. Usage ................................ |undotree-usage|
3. Configuration ........................ |undotree-config|
3.1 undotree_WindowLayout .......... |undotree_WindowLayout|
3.2 undotree_CustomUndotreeCmd...... |undotree_CustomUndotreeCmd|
undotree_CustomDiffpanelCmd..... |undotree_CustomDiffpanelCmd|
3.3 undotree_SplitWidth ............ |undotree_SplitWidth|
3.4 undotree_DiffpanelHeight ....... |undotree_DiffpanelHeight|
3.5 undotree_DiffAutoOpen .......... |undotree_DiffAutoOpen|
3.6 undotree_SetFocusWhenToggle .... |undotree_SetFocusWhenToggle|
3.7 undotree_TreeNodeShape ......... |undotree_TreeNodeShape|
undotree_TreeVertShape ......... |undotree_TreeVertShape|
undotree_TreeSplitShape ........ |undotree_TreeSplitShape|
undotree_TreeReturnShape ....... |undotree_TreeReturnShape|
3.8 undotree_DiffCommand ........... |undotree_DiffCommand|
3.9 undotree_RelativeTimestamp ..... |undotree_RelativeTimestamp|
3.10 undotree_ShortIndicators ....... |undotree_ShortIndicators|
3.11 undotree_HighlightChangedText .. |undotree_HighlightChangedText|
3.12 undotree_HighlightSyntaxAdd .... |undotree_HighlightSyntaxAdd|
undotree_HighlightSyntaxChange . |undotree_HighlightSyntaxChange|
3.13 Undotree_CustomMap ............. |Undotree_CustomMap|
3.14 undotree_HelpLine .............. |undotree_HelpLine|
3.15 undotree_CursorLine ............ |undotree_CursorLine|
4. Bugs ................................. |undotree-bugs|
5. Changelog ............................ |undotree-changelog|
6. License .............................. |undotree-license|
==============================================================================
1. Intro *undotree-intro*
The plug-in visualizes undo history and makes it easier to browse and switch
between different undo branches. You might wonder what are undo "branches"?
It's vim feature that allows you to go back to a state when it is overwritten
by a latest edit. For most editors, if you make a change A, then B, then go
back to A and make change C, normally you won't be able to go back to B
because undo history is linear. That's not the case for Vim because it
internally keeps all the edit history like a tree structure, and this plug-in
exposes the tree to you so that you not only can switch back and forth but
also can switch between branches.
Some people have questions about file contents being changed when switching
between undo history states. Don't worry, undotree will NEVER save your data
or write to disk. All it does is to change the current buffer little bit, just
like those auto-completion plug-ins do. It just adds or removes something in
the buffer temporarily, and if you don't like you can always go back to the
last state easily. Let's say, you made some change but didn't save, then you
use undotree and go back to an arbitrary version, your unsaved change doesn't
get lost - it stores in the latest undo history node. Clicking that node on
undotree will bring you back instantly. Play with undo/redo on other editors
is always dangerous because when you step back and accidentally typed
something, boom! You lose your edits. But don't worry, that won't happen in
Vim. Then you might ask what if I make some changes without saving and switch
back to an old version and then exit? Well, imagine what would happen if you
don't have undotree? You lose your latest edits and the file on disk is your
last saved version. This behaviour remains the same with undotree. So, if you
saved, you won't lose anything.
We all know that usually undo/redo is only for the current edit session. It's
stored in memory and once the process exits, the undo history is lost.
Although undotree makes switching between history states easier, it doesn't do
more than that. Sometimes it would be much safer or more convenient to keep
the undo history across edit sessions. In this case you might need to enable a
Vim feature called persistent undo. Let me explain how persistent undo works:
instead of keeping undo history in RAM, persistent undo keeps undo history in
file. Let's say you make a change A, then B, then go back to A and make change
C, then you save the file. Now Vim save the file with content state C, and in
the mean time it saves the entire undo history to a file including state A, B
and C. Next time when you open the file, Vim will also restore undo history.
So you can still go back to B. The history file is incremental, and every
change will be recorded permanently, kind of like Git. You might think that's
too much, well, undotree does provide a way to clean them up. If you need to
enable persistent undo, type :h persistent-undo or follow the instructions
below.
Undotree is written in pure Vim script and doesn't rely on any third party
tools. It's lightweight, simple and fast. It only does what it supposed to do,
and it only runs when you need it.
==============================================================================
2. Usage *undotree-usage*
Use :UndotreeToggle to toggle the undo-tree panel. You may want to map this
command to whatever hotkey by adding the following line to your vimrc, take F5
for example.
>
nnoremap <F5> :UndotreeToggle<cr>
<
Markers
* Every change has a sequence number and it is displayed before timestamps.
* The current state is marked as > number <.
* The next state which will be restored by :redo or <ctrl-r> is marked as
{ number }.
* The [ number ] marks the most recent change.
* The undo history is sorted by timestamps.
* Saved changes are marked as s and the big S indicates the most recent
saved change.
* Press ? in undotree window for quick help.
Persistent undo
Usually I would like to store the undo files in a seperate place like below.
>
if has("persistent_undo")
set undodir=$HOME."/.undodir"
set undofile
endif
<
==============================================================================
3. Configuration *undotree-config*
------------------------------------------------------------------------------
3.1 g:undotree_WindowLayout *undotree_WindowLayout*
Set the undotree window layout.
Style 1
>
+----------+------------------------+
| | |
| | |
| undotree | |
| | |
| | |
+----------+ |
| | |
| diff | |
| | |
+----------+------------------------+
<
Style 2
>
+----------+------------------------+
| | |
| | |
| undotree | |
| | |
| | |
+----------+------------------------+
| |
| diff |
| |
+-----------------------------------+
<
Style 3
>
+------------------------+----------+
| | |
| | |
| | undotree |
| | |
| | |
| +----------+
| | |
| | diff |
| | |
+------------------------+----------+
<
Style 4
>
+------------------------+----------+
| | |
| | |
| | undotree |
| | |
| | |
+------------------------+----------+
| |
| diff |
| |
+-----------------------------------+
<
Default: 1
------------------------------------------------------------------------------
3.2 g:undotree_CustomUndotreeCmd *undotree_CustomUndotreeCmd*
g:undotree_CustomDiffpanelCmd *undotree_CustomDiffpanelCmd*
Set up custom window layout.
Setting |undotree_CustomUndotreeCmd| will ignore |undotree_SplitWidth|, and
setting |undotree_CustomDiffpanelCmd| will ignore |undotree_DiffpanelHeight|.
An |undotree_CustomUndotreeCmd| will always open the undotree window relative
to the tracked window and |undotree_CustomDiffpanelCmd| will always open the
diffpanel relative to the undotree window.
Useful when
* absolute positioning commands (|topleft|, |botright|) don't play well
with other plugins
* you have a preferred split window layout and would like to use
UndoTree relative to one specific window only
Examples:
* To recreate Style 1:
>
let g:undotree_CustomUndotreeCmd = 'topleft vertical 30 new'
let g:undotree_CustomDiffpanelCmd = 'belowright 10 new'
<
* To recreate Style 2:
>
let g:undotree_CustomUndotreeCmd = 'topleft vertical 30 new'
let g:undotree_CustomDiffpanelCmd = 'botright 10 new'
<
* A custom layout example:
>
+------------------------+----------+
| | |
| | w |
| | i |
| | n |
| window_1 | d |
| | o |
| | w |
| | | |
| | 2 |
| | |
+------------------------+----------+
| |
| window_3 |
| |
+-----------------------------------+
<
Using the following setup wouldn't mess up the current layout as it
does not use absolute positioning:
>
let g:undotree_CustomUndotreeCmd = 'vertical 32 new'
let g:undotree_CustomDiffpanelCmd= 'belowright 12 new'
<
Issuing :UndotreeToggle now in window_1 would result in:
>
+--------+---------------+----------+
| | | |
| u | | w |
| n | | i |
| d | | n |
| o | window_1 | d |
| | | o |
+--------+ | w |
| | | | |
| diff | | 2 |
| | | |
+--------+---------------+----------+
| |
| window_3 |
| |
+-----------------------------------+
<
Executing :UndotreeToggle again would turn off UndoTree (independently
of which window was active at the time). Moving between window1, window_2
and window_3 would result in showing the respective window's changelog
in the undotree panel.
CAVEAT: To avoid the Vim's default behaviour of equalizing window sizes
when closing a window, set the 'noequalalways' option.
------------------------------------------------------------------------------
3.3 g:undotree_SplitWidth *undotree_SplitWidth*
Set the undotree window width.
Default: 30
------------------------------------------------------------------------------
3.4 g:undotree_DiffpanelHeight *undotree_DiffpanelHeight*
Set the diff window height.
Default: 10
------------------------------------------------------------------------------
3.5 g:undotree_DiffAutoOpen *undotree_DiffAutoOpen*
Set this to 1 to auto open the diff window.
Default: 1
------------------------------------------------------------------------------
3.6 g:undotree_SetFocusWhenToggle *undotree_SetFocusWhenToggle*
If set to 1, the undotree window will get focus after being opened, otherwise
focus will stay in current window.
Default: 0
------------------------------------------------------------------------------
3.7 g:undotree_TreeNodeShape *undotree_TreeNodeShape*
g:undotree_TreeVertShape *undotree_TreeVertShape*
g:undotree_TreeSplitShape *undotree_TreeSplitShape*
g:undotree_TreeReturnShape *undotree_TreeReturnShape*
Set the characters used to draw the tree. Although you can put any character
you want in these shape variables, the only Unicode box drawing characters
that work well are these three. Make sure your font will render them; you can
easily see if that's the case in the last column of this table.
Variable | Default | Unicode Box Character
---------------------------+---------------+-----------------------
g:undotree_TreeNodeShape | * |
g:undotree_TreeReturnShape | \ (backslash) | ╲ (U+2572)
g:undotree_TreeVertShape | | (pipe) | │ (U+2502)
g:undotree_TreeSplitShape | / (slash) | (U+2571)
------------------------------------------------------------------------------
3.8 g:undotree_DiffCommand *undotree_DiffCommand*
Set the command used to get the diff output.
Default: "diff"
------------------------------------------------------------------------------
3.9 g:undotree_RelativeTimestamp *undotree_RelativeTimestamp*
Set to 1 to use relative timestamp.
Default: 1
------------------------------------------------------------------------------
3.10 g:undotree_ShortIndicators *undotree_ShortIndicators*
Set to 1 to get short timestamps when |undotree_RelativeTimestamp| is also
enabled:
>
Before | After
===========================
(5 seconds ago) | (5 s)
----------------|----------
(1 minute ago) | (1 m)
----------------|----------
(2 minutes ago) | (2 m)
----------------|----------
(1 hour ago) | (1 h)
----------------|----------
(Original) | (Orig)
<
Default: 0
------------------------------------------------------------------------------
3.11 g:undotree_HighlightChangedText *undotree_HighlightChangedText*
Set to 1 to highlight the changed text.
Default: 1
------------------------------------------------------------------------------
3.12 g:undotree_HighlightSyntaxAdd *undotree_HighlightSyntaxAdd*
g:undotree_HighlightSyntaxChange *undotree_HighlightSyntaxChange*
Set the highlight linked syntax type.
You may chose your favorite through ":hi" command.
Default: "DiffAdd" and "DiffChange"
------------------------------------------------------------------------------
3.13 g:Undotree_CustomMap *Undotree_CustomMap*
There are two ways of changing the default key mappings:
The first way is to define global mappings as the following example:
>
nmap <buffer> J <plug>UndotreeNextState
nmap <buffer> K <plug>UndotreePreviousState
<
A better approach is to define the callback function g:Undotree_CustomMap().
The function will be called after the undotree windows is initialized, so the
key mappings only works on the undotree windows.
>
function g:Undotree_CustomMap()
nmap <buffer> J <plug>UndotreeNextState
nmap <buffer> K <plug>UndotreePreviousState
endfunc
<
List of the commands available for redefinition.
>
<plug>UndotreeHelp
<plug>UndotreeClose
<plug>UndotreeFocusTarget
<plug>UndotreeClearHistory
<plug>UndotreeTimestampToggle
<plug>UndotreeDiffToggle
<plug>UndotreeNextState
<plug>UndotreePreviousState
<plug>UndotreeNextSavedState
<plug>UndotreePreviousSavedState
<plug>UndotreeRedo
<plug>UndotreeUndo
<plug>UndotreeEnter
<
------------------------------------------------------------------------------
3.14 g:undotree_HelpLine *undotree_HelpLine*
Set to 0 to hide "Press ? for help".
Default: 1
------------------------------------------------------------------------------
3.15 g:undotree_CursorLine
Set to 0 to disable cursorline.
Default: 1
==============================================================================
4. Bugs *undotree-bugs*
Post any issue and feature request here:
https://github.com/mbbill/undotree/issues
==============================================================================
5. Changelog *undotree-changelog*
Further changes will not be recorded. Please go to github page for more
information.
4.4 (2017-10-15)
- Autoload plugin functions
4.3 (2013-02-18)
- Several fixes and enhancements.
4.2 (2012-11-24)
- Fixed some small issue.
4.1 (2012-09-05)
- Enhanced tree style.
- Multi-window switching support.
4.0 (2012-08-30)
- Live updated highlight for changed text.
- Customizable key mappings.
- Fixed some minor bugs.
3.1 (2012-08-25)
- Add saved status.
- Add relative timestamp.
- Add ability of clear undo history.
3.0 (2012-08-24)
- Add diff panel.
- Performance improvement.
2.2 (2012-08-21)
- Stable version.
2.1 (2012-08-20)
- Fixed some annoying issues.
2.0 (2012-08-19)
- Hotkey support.
- Handle undo levels.
- Auto refresh.
- And so on.
1.0 (2012-08-18)
- Initial upload
==============================================================================
6. License *undotree-license*
BSD
vim:tw=78:ts=8:ft=help:norl:

View File

@@ -1,186 +0,0 @@
"=================================================
" File: plugin/undotree.vim
" Description: Manage your undo history in a graph.
" Author: Ming Bai <mbbill@gmail.com>
" License: BSD
" Avoid installing twice.
if exists('g:loaded_undotree')
finish
endif
let g:loaded_undotree = 0
" At least version 7.3 with 005 patch is needed for undo branches.
" Refer to https://github.com/mbbill/undotree/issues/4 for details.
" Thanks kien
if v:version < 703
command! -n=0 -bar UndotreeToggle :echoerr "undotree.vim needs Vim version >= 7.3"
finish
endif
if (v:version == 703 && !has("patch005"))
command! -n=0 -bar UndotreeToggle :echoerr "undotree.vim needs vim7.3 with patch005 applied."
finish
endif
let g:loaded_undotree = 1 " Signal plugin availability with a value of 1.
"=================================================
"Options:
" Window layout
" style 1
" +----------+------------------------+
" | | |
" | | |
" | undotree | |
" | | |
" | | |
" +----------+ |
" | | |
" | diff | |
" | | |
" +----------+------------------------+
" Style 2
" +----------+------------------------+
" | | |
" | | |
" | undotree | |
" | | |
" | | |
" +----------+------------------------+
" | |
" | diff |
" | |
" +-----------------------------------+
" Style 3
" +------------------------+----------+
" | | |
" | | |
" | | undotree |
" | | |
" | | |
" | +----------+
" | | |
" | | diff |
" | | |
" +------------------------+----------+
" Style 4
" +-----------------------++----------+
" | | |
" | | |
" | | undotree |
" | | |
" | | |
" +------------------------+----------+
" | |
" | diff |
" | |
" +-----------------------------------+
if !exists('g:undotree_WindowLayout')
let g:undotree_WindowLayout = 1
endif
" e.g. using 'd' instead of 'days' to save some space.
if !exists('g:undotree_ShortIndicators')
let g:undotree_ShortIndicators = 0
endif
" undotree window width
if !exists('g:undotree_SplitWidth')
if g:undotree_ShortIndicators == 1
let g:undotree_SplitWidth = 24
else
let g:undotree_SplitWidth = 30
endif
endif
" diff window height
if !exists('g:undotree_DiffpanelHeight')
let g:undotree_DiffpanelHeight = 10
endif
" auto open diff window
if !exists('g:undotree_DiffAutoOpen')
let g:undotree_DiffAutoOpen = 1
endif
" if set, let undotree window get focus after being opened, otherwise
" focus will stay in current window.
if !exists('g:undotree_SetFocusWhenToggle')
let g:undotree_SetFocusWhenToggle = 0
endif
" tree node shape.
if !exists('g:undotree_TreeNodeShape')
let g:undotree_TreeNodeShape = '*'
endif
" tree vertical shape.
if !exists('g:undotree_TreeVertShape')
let g:undotree_TreeVertShape = '|'
endif
" tree split shape.
if !exists('g:undotree_TreeSplitShape')
let g:undotree_TreeSplitShape = '/'
endif
" tree return shape.
if !exists('g:undotree_TreeReturnShape')
let g:undotree_TreeReturnShape = '\'
endif
if !exists('g:undotree_DiffCommand')
let g:undotree_DiffCommand = "diff"
endif
" relative timestamp
if !exists('g:undotree_RelativeTimestamp')
let g:undotree_RelativeTimestamp = 1
endif
" Highlight changed text
if !exists('g:undotree_HighlightChangedText')
let g:undotree_HighlightChangedText = 1
endif
" Highlight changed text using signs in the gutter
if !exists('g:undotree_HighlightChangedWithSign')
let g:undotree_HighlightChangedWithSign = 1
endif
" Highlight linked syntax type.
" You may chose your favorite through ":hi" command
if !exists('g:undotree_HighlightSyntaxAdd')
let g:undotree_HighlightSyntaxAdd = "DiffAdd"
endif
if !exists('g:undotree_HighlightSyntaxChange')
let g:undotree_HighlightSyntaxChange = "DiffChange"
endif
if !exists('g:undotree_HighlightSyntaxDel')
let g:undotree_HighlightSyntaxDel = "DiffDelete"
endif
" Deprecates the old style configuration.
if exists('g:undotree_SplitLocation')
echo "g:undotree_SplitLocation is deprecated,
\ please use g:undotree_WindowLayout instead."
endif
" Show help line
if !exists('g:undotree_HelpLine')
let g:undotree_HelpLine = 1
endif
" Show cursorline
if !exists('g:undotree_CursorLine')
let g:undotree_CursorLine = 1
endif
"=================================================
" User commands.
command! -n=0 -bar UndotreeToggle :call undotree#UndotreeToggle()
command! -n=0 -bar UndotreeHide :call undotree#UndotreeHide()
command! -n=0 -bar UndotreeShow :call undotree#UndotreeShow()
command! -n=0 -bar UndotreeFocus :call undotree#UndotreeFocus()
" vim: set et fdm=marker sts=4 sw=4:

View File

@@ -1,37 +0,0 @@
"=================================================
" File: undotree.vim
" Description: undotree syntax
" Author: Ming Bai <mbbill@gmail.com>
" License: BSD
execute "syn match UndotreeNode ' \\zs".escape(g:undotree_TreeNodeShape,'*')."\\ze '"
execute "syn match UndotreeNodeCurrent '\\zs".escape(g:undotree_TreeNodeShape,'*')."\\ze.*>\d\+<'"
syn match UndotreeTimeStamp '(.*)$'
syn match UndotreeFirstNode 'Original'
execute "syn match UndotreeBranch '[".escape(g:undotree_TreeVertShape.g:undotree_TreeSplitShape.g:undotree_TreeReturnShape,'\')."]'"
syn match UndotreeSeq ' \zs\d\+\ze '
syn match UndotreeCurrent '>\d\+<'
syn match UndotreeNext '{\d\+}'
syn match UndotreeHead '\[\d\+]'
syn match UndotreeHelp '^".*$' contains=UndotreeHelpKey,UndotreeHelpTitle
syn match UndotreeHelpKey '^" \zs.\{-}\ze:' contained
syn match UndotreeHelpTitle '===.*===' contained
syn match UndotreeSavedSmall ' \zss\ze '
syn match UndotreeSavedBig ' \zsS\ze '
hi def link UndotreeNode Question
hi def link UndotreeNodeCurrent Statement
hi def link UndotreeTimeStamp Function
hi def link UndotreeFirstNode Function
hi def link UndotreeBranch Constant
hi def link UndotreeSeq Comment
hi def link UndotreeCurrent Statement
hi def link UndotreeNext Type
hi def link UndotreeHead Identifier
hi def link UndotreeHelp Comment
hi def link UndotreeHelpKey Function
hi def link UndotreeHelpTitle Type
hi def link UndotreeSavedSmall WarningMsg
hi def link UndotreeSavedBig MatchParen
" vim: set et fdm=marker sts=4 sw=4:

View File

@@ -1 +0,0 @@
doc/tags

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (C) 2013 Bailey Ling
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,38 +0,0 @@
# vim-bufferline
Super simple vim plugin to show the list of buffers in the command bar.
# screenshots
#### in the statusline
![img](img/bufferline-status.png)
#### or the command bar
![img](img/bufferline-command.png)
# configuration
`:help bufferline`
# installation
* [pathogen](https://github.com/tpope/vim-pathogen)
* `git clone https://github.com/bling/vim-bufferline ~/.vim/bundle/vim-bufferline`
* [neobundle](https://github.com/Shougo/neobundle.vim)
* `NeoBundle 'bling/vim-bufferline'`
* [vundle](https://github.com/gmarik/vundle)
* `Plugin 'bling/vim-bufferline'`
* [vam](https://github.com/MarcWeber/vim-addon-manager)
* `call vam#ActivateAddons([ 'vim-bufferline' ])`
* [vim-plug](https://github.com/junegunn/vim-plug)
* `Plug 'bling/vim-bufferline'`
# credits
This was inspired by the [buftabs](http://www.vim.org/scripts/script.php?script_id=1664) script.
# license
MIT License. Copyright (c) 2013 Bailey Ling.

View File

@@ -1,130 +0,0 @@
" keep track of vimrc setting
let s:updatetime = &updatetime
" keep track of scrollinf window start
let s:window_start = 0
function! s:generate_names()
let names = []
let i = 1
let last_buffer = bufnr('$')
let current_buffer = bufnr('%')
while i <= last_buffer
if bufexists(i) && buflisted(i)
let modified = ' '
if getbufvar(i, '&mod')
let modified = g:bufferline_modified
endif
let fname = fnamemodify(bufname(i), g:bufferline_fname_mod)
if g:bufferline_pathshorten != 0
let fname = pathshorten(fname)
endif
let fname = substitute(fname, "%", "%%", "g")
let skip = 0
for ex in g:bufferline_excludes
if match(fname, ex) > -1
let skip = 1
break
endif
endfor
if !skip
let name = ''
if g:bufferline_show_bufnr != 0 && g:bufferline_status_info.count >= g:bufferline_show_bufnr
let name = i . ':'
endif
let name .= fname . modified
if current_buffer == i
let name = g:bufferline_active_buffer_left . name . g:bufferline_active_buffer_right
let g:bufferline_status_info.current = name
else
let name = g:bufferline_separator . name . g:bufferline_separator
endif
call add(names, [i, name])
endif
endif
let i += 1
endwhile
if len(names) > 1
if g:bufferline_rotate == 1
call bufferline#algos#fixed_position#modify(names)
endif
endif
return names
endfunction
function! bufferline#get_echo_string()
" check for special cases like help files
let current = bufnr('%')
if !bufexists(current) || !buflisted(current)
return bufname('%')
endif
let names = s:generate_names()
let line = ''
for val in names
let line .= val[1]
endfor
let index = match(line, '\V'.g:bufferline_status_info.current)
let g:bufferline_status_info.count = len(names)
let g:bufferline_status_info.before = strpart(line, 0, index)
let g:bufferline_status_info.after = strpart(line, index + len(g:bufferline_status_info.current))
return line
endfunction
function! s:echo()
if &filetype ==# 'unite'
return
endif
let line = bufferline#get_echo_string()
" 12 is magical and is the threshold for when it doesn't wrap text anymore
let width = &columns - 12
if g:bufferline_rotate == 2
let current_buffer_start = stridx(line, g:bufferline_active_buffer_left)
let current_buffer_end = stridx(line, g:bufferline_active_buffer_right)
if current_buffer_start < s:window_start
let s:window_start = current_buffer_start
endif
if current_buffer_end > (s:window_start + width)
let s:window_start = current_buffer_end - width + 1
endif
let line = strpart(line, s:window_start, width)
else
let line = strpart(line, 0, width)
endif
echo line
if &updatetime != s:updatetime
let &updatetime = s:updatetime
endif
endfunction
function! s:cursorhold_callback()
call s:echo()
autocmd! bufferline CursorHold
endfunction
function! s:refresh(updatetime)
let &updatetime = a:updatetime
autocmd bufferline CursorHold * call s:cursorhold_callback()
endfunction
function! bufferline#init_echo()
augroup bufferline
au!
" events which output a message which should be immediately overwritten
autocmd BufWinEnter,WinEnter,InsertLeave,VimResized * call s:refresh(1)
augroup END
autocmd CursorHold * call s:echo()
endfunction

View File

@@ -1,9 +0,0 @@
" pins the active buffer to a specific index in the list
function! bufferline#algos#fixed_position#modify(names)
let current = bufnr('%')
while a:names[g:bufferline_fixed_index][0] != current
let first = remove(a:names, 0)
call add(a:names, first)
endwhile
endfunction

View File

@@ -1,119 +0,0 @@
*bufferline.txt* Simple plugin for generating buffer list names
==============================================================================
INTRODUCTION *bufferline*
vim-bufferline is a simple plugin that helps you keep track of all your open
buffers. It also integrates nicely with vim-airline.
==============================================================================
CONFIGURATION *bufferline-configuration*
There are a couple configuration values available (shown with their default
values):
* denotes whether bufferline should automatically echo to the command bar
>
let g:bufferline_echo = 1
<
* the separator used on the left side of a buffer
>
let g:bufferline_active_buffer_left = '['
<
* the separator used on the right side of a buffer
>
let g:bufferline_active_buffer_right = ']'
<
* the symbol to denote that a buffer is modified
>
let g:bufferline_modified = '+'
<
* denotes whether buffer numbers should be displayed
>
let g:bufferline_show_bufnr = 1
<
* denotes whether the bufferline should have rotation applied
>
" default, no rotate, no scrolling
let g:bufferline_rotate = 0
" scrolling with fixed current buffer position
let g:bufferline_rotate = 1
" scrolling without fixed current buffer position
let g:bufferline_rotate = 2
<
* only valid when `g:bufferline_rotate` is set to 1:
>
let g:bufferline_fixed_index = 0 "always first
let g:bufferline_fixed_index = 1 "always second (default)
let g:bufferline_fixed_index = -1 "always last
<
* denotes how to display the filename of a buffer (see |filename-modifiers|
for more details)
>
let g:bufferline_fname_mod = ':t'
<
* denotes the highlight group for inactive buffers when used in the
|statusline|
>
let g:bufferline_inactive_highlight = 'StatusLineNC'
<
* denotes the highlight group for the active buffer when used in the
|statusline|
>
let g:bufferline_active_highlight = 'StatusLine'
<
* denotes whether the active highlight should be used when there is only one
buffer.
>
let g:bufferline_solo_highlight = 0
<
* denotes any exclude patterns.
>
let g:bufferline_excludes = [] "see source for defaults
<
* denotes whether paths in buffer names should be |pathshorten()|-ed.
>
let g:bufferline_pathshorten = 0
<
==============================================================================
STATUSLINE INTEGRATION *bufferline-statusline*
>
let g:bufferline_echo = 0
autocmd VimEnter *
\ let &statusline='%{bufferline#refresh_status()}'
\ .bufferline#get_status_string()
<
The function refresh_status() returns an empty string and only exists to
populate some global variables. Since it is inside an %{} block, the
variables will get updated whenever the statusline needs to be drawn.
get_status_string() creates a string which references these variables.
==============================================================================
CONTRIBUTIONS *bufferline-contributions*
Contributions and pull requests are welcome.
==============================================================================
LICENSE *bufferline-license*
MIT License. Copyright © 2013 Bailey Ling.
vim:tw=78:ts=8:ft=help:norl:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,61 +0,0 @@
if exists('g:loaded_bufferline')
finish
endif
let g:loaded_bufferline = 1
function! s:check_defined(variable, default)
if !exists(a:variable)
let {a:variable} = a:default
endif
endfunction
call s:check_defined('g:bufferline_active_buffer_left', '[')
call s:check_defined('g:bufferline_active_buffer_right', ']')
call s:check_defined('g:bufferline_separator', ' ')
call s:check_defined('g:bufferline_modified', '+')
call s:check_defined('g:bufferline_echo', 1)
call s:check_defined('g:bufferline_show_bufnr', 1)
call s:check_defined('g:bufferline_fname_mod', ':t')
call s:check_defined('g:bufferline_inactive_highlight', 'StatusLineNC')
call s:check_defined('g:bufferline_active_highlight', 'StatusLine')
call s:check_defined('g:bufferline_rotate', 0)
call s:check_defined('g:bufferline_fixed_index', 1)
call s:check_defined('g:bufferline_solo_highlight', 0)
call s:check_defined('g:bufferline_excludes', ['\[vimfiler\]'])
call s:check_defined('g:bufferline_pathshorten', 0)
function! bufferline#generate_string()
return "bufferline#generate_string() is obsolete! Please consult README."
endfunction
let g:bufferline_status_info = {
\ 'count': 0,
\ 'before': '',
\ 'current': '',
\ 'after': '',
\ }
function! bufferline#refresh_status()
if g:bufferline_solo_highlight
if g:bufferline_status_info.count == 1
exec printf('highlight! link %s %s', g:bufferline_active_highlight, g:bufferline_inactive_highlight)
else
exec printf('highlight! link %s NONE', g:bufferline_active_highlight)
endif
endif
call bufferline#get_echo_string()
return ''
endfunction
function! bufferline#get_status_string()
return
\ '%#'.g:bufferline_inactive_highlight.'#'
\.'%{g:bufferline_status_info.before}'
\.'%#'.g:bufferline_active_highlight.'#'
\.' %{g:bufferline_status_info.current} '
\.'%#'.g:bufferline_inactive_highlight.'#'
\.'%{g:bufferline_status_info.after}'
endfunction
if g:bufferline_echo
call bufferline#init_echo()
endif

View File

@@ -1,12 +0,0 @@
# These are supported funding model platforms
github: [haya14busa] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -1,36 +0,0 @@
name: reviewdog
on:
push:
branches:
- master
pull_request:
jobs:
vint:
name: runner / vint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: reviewdog/action-vint@v1
if: github.event_name == 'pull_request'
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-check
level: warning
- uses: reviewdog/action-vint@v1
if: github.event_name != 'pull_request'
with:
github_token: ${{ secrets.github_token }}
reporter: github-check
level: warning
languagetool:
name: runner / languagetool
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: reviewdog/action-languagetool@v1
with:
github_token: ${{ secrets.github_token }}
reporter: github-check
level: info

View File

@@ -1,4 +0,0 @@
doc/tags
tmp*
*.lock
.vim-flavor

View File

@@ -1,31 +0,0 @@
# This config is based on lightline.vim <https://github.com/itchyny/lightline.vim/blob/master/.travis.yml>
language: ruby
rvm:
- 2.0.0
install:
- git clone https://github.com/kana/vim-vspec.git
before_script:
- bundle install
- bundle show
- (if ! test -d $HOME/vim-$VIM_VERSION/bin; then
git clone https://github.com/vim/vim $HOME/vim &&
cd $HOME/vim &&
git checkout v$VIM_VERSION &&
./configure --prefix=$HOME/vim-$VIM_VERSION &&
make &&
make install;
fi)
cache:
directories:
- $HOME/vim-$VIM_VERSION
env:
- VIM_VERSION=8.0.0000
- VIM_VERSION=7.4
script:
- export PATH=$HOME/vim-$VIM_VERSION/bin:$PATH
- cd $TRAVIS_BUILD_DIR
- rake ci

View File

@@ -1,4 +0,0 @@
source 'https://rubygems.org'
gem 'vim-flavor', '~> 2.2.2'
gem 'rake'

View File

@@ -1,406 +0,0 @@
Vim motion on speed!
=====
[![Build Status](https://travis-ci.org/easymotion/vim-easymotion.svg?branch=master)](https://travis-ci.org/easymotion/vim-easymotion)
[![reviewdog](https://github.com/easymotion/vim-easymotion/workflows/reviewdog/badge.svg?branch=master&event=push)](https://github.com/easymotion/vim-easymotion/actions?query=workflow%3Areviewdog+event%3Apush+branch%3Amaster)
![Animated demonstration](https://f.cloud.github.com/assets/3797062/2039359/a8e938d6-899f-11e3-8789-60025ea83656.gif)
About the authors
=====
| Authors | |
|------------------|-------------------------------|
| Kim Silkebækken | https://github.com/Lokaltog |
| haya14busa | https://github.com/haya14busa |
The EasyMotion project, revived!
======
Starting from version 2.0 [haya14busa](https://github.com/haya14busa) will be
taking over the project from [Lokaltog](https://github.com/Lokaltog). He's
improved the default motions, implemented many useful new features, and fixed
some bugs.
EasyMotion is now completely:
- **Well-behaved**: It's consistent with the default motions of Vim and works
well in all modes. And it now supports repeating with the dot operator.
- **Configurable**: You can easily configure its behavior and map it to any key
- **Sophisticated**: Provide flawless, smooth and fast motions with minimal keystrokes
Even though some default behaviors were modified and many new features were
added, I carefully considered backward compatibility. So those of you updating
from older versions can do so without worry and start benefiting immediately
from all the new features!
Introduction
=====
EasyMotion provides a much simpler way to use some motions in vim. It
takes the `<number>` out of `<number>w` or `<number>f{char}` by
highlighting all possible choices and allowing you to press one key to
jump directly to the target.
When one of the available motions is triggered, all visible text
preceding or following the cursor is faded, and motion targets are
highlighted.
EasyMotion is triggered by the provided mappings. This readme only covers the
basics; please refer to
[`:help easymotion.txt`](https://github.com/easymotion/vim-easymotion/blob/master/doc/easymotion.txt#L86)
to see all the available mappings.
Important notes
=====
### Default bindings
**The default leader has been changed to `<Leader><Leader>` to avoid
conflicts with other plugins you may have installed.** This can easily be
changed back to pre-1.3 behavior by rebinding the leader in your vimrc:
```vim
map <Leader> <Plug>(easymotion-prefix)
```
All motions will then be triggered with `<Leader>` by default, e.g.
`<Leader>s`, `<Leader>gE`.
### For users of the forked version
SelectLines and SelectPhrase are not actually *motions*, so I've moved them into
separate plugins.
- https://github.com/haya14busa/vim-easyoperator-line
- https://github.com/haya14busa/vim-easyoperator-phrase
Usage example for the base features
=====
<cursor>Lorem ipsum dolor sit amet.
Type `<Leader><Leader>w`(`<Plug>(easymotion-w)`) to trigger the word motion `w`.
When the motion is triggered, the text is updated (no braces are actually added,
the text is highlighted in red by default):
<cursor>Lorem {a}psum {b}olor {c}it {d}met.
Press `c` to jump to the beginning of the word "sit":
Lorem ipsum dolor <cursor>sit amet.
Similarly, if you're looking for an "o", you can use the `f` motion.
Type `<Leader><Leader>fo`, and all "o" characters are highlighted:
<cursor>L{a}rem ipsum d{b}l{c}r sit amet.
Press `b` to jump to the second "o":
Lorem ipsum d<cursor>olor sit amet.
Jeffrey Way of Nettuts+ has also [written
a tutorial](https://code.tutsplus.com/tutorials/vim-essential-plugin-easymotion--net-19223)
about EasyMotion.
New features in version 3.0
====
### Overwin motions
![](https://raw.githubusercontent.com/haya14busa/i/2753bd4dd1dfdf5962dbdbffabf24244e4e14243/easymotion/overwin-motions.gif)
EasyMotion now supports moving cursor across/over window.
Since it doesn't make sense that moving cursor to other window while Visual or
Operator-pending mode, overwin motions only provides mappings for Normal
mode. Please use `nmap` to use overwin motions. Overwin motions only
supports bi-directional motions.
#### Example configuration
```vim
" <Leader>f{char} to move to {char}
map <Leader>f <Plug>(easymotion-bd-f)
nmap <Leader>f <Plug>(easymotion-overwin-f)
" s{char}{char} to move to {char}{char}
nmap s <Plug>(easymotion-overwin-f2)
" Move to line
map <Leader>L <Plug>(easymotion-bd-jk)
nmap <Leader>L <Plug>(easymotion-overwin-line)
" Move to word
map <Leader>w <Plug>(easymotion-bd-w)
nmap <Leader>w <Plug>(easymotion-overwin-w)
```
#### Integration with incsearch.vim
- [haya14busa/incsearch.vim](https://github.com/haya14busa/incsearch.vim)
- [haya14busa/incsearch-easymotion.vim](https://github.com/haya14busa/incsearch-easymotion.vim)
```vim
" You can use other keymappings like <C-l> instead of <CR> if you want to
" use these mappings as default search and sometimes want to move cursor with
" EasyMotion.
function! s:incsearch_config(...) abort
return incsearch#util#deepextend(deepcopy({
\ 'modules': [incsearch#config#easymotion#module({'overwin': 1})],
\ 'keymap': {
\ "\<CR>": '<Over>(easymotion)'
\ },
\ 'is_expr': 0
\ }), get(a:, 1, {}))
endfunction
noremap <silent><expr> / incsearch#go(<SID>incsearch_config())
noremap <silent><expr> ? incsearch#go(<SID>incsearch_config({'command': '?'}))
noremap <silent><expr> g/ incsearch#go(<SID>incsearch_config({'is_stay': 1}))
```
### Bonus fuzzy-search with EasyMotion
![](https://raw.githubusercontent.com/haya14busa/i/eab1d12a8bd322223d551956a4fd8a21d5c4bfe9/easymotion/fuzzy-incsearch-easymotion.gif)
- [haya14busa/incsearch.vim](https://github.com/haya14busa/incsearch.vim)
- [haya14busa/incsearch-fuzzy.vim](https://github.com/haya14busa/incsearch-fuzzy.vim)
- [haya14busa/incsearch-easymotion.vim](https://github.com/haya14busa/incsearch-easymotion.vim)
```vim
function! s:config_easyfuzzymotion(...) abort
return extend(copy({
\ 'converters': [incsearch#config#fuzzyword#converter()],
\ 'modules': [incsearch#config#easymotion#module({'overwin': 1})],
\ 'keymap': {"\<CR>": '<Over>(easymotion)'},
\ 'is_expr': 0,
\ 'is_stay': 1
\ }), get(a:, 1, {}))
endfunction
noremap <silent><expr> <Space>/ incsearch#go(<SID>config_easyfuzzymotion())
```
New features in version 2.0
====
### Two key highlighting
When EasyMotion runs out of single characters to highlight movement targets, it
immediately shows you the keys you have to press.
In previous versions you could not see the next character you would need to
press until you entered the first one. This made movement over long distances
less fluid. Now you can see at a glance exactly which characters to select to
get to your destination.
### Bidirectional motions
All motions now come in bidirectional variants (e.g. `<Plug>(easymotion-s)`,
`<Plug>(easymotion-bd-w)` and so forth).
By default, you can already jump forward or backward with `<Leader>s`. A useful
trick is to map `nmap s <Plug>(easymotion-s)` to use `s` instead and save one
keystroke!
### 2-character search motion
You can now also perform a 2-character search, similar to [vim-seek](https://github.com/goldfeld/vim-seek)/[vim-sneak](https://github.com/justinmk/vim-sneak) with `<Plug>(easymotion-s2)`. For example, you can highlight all words that start with `fu`.
![2-key-find-motion](https://f.cloud.github.com/assets/3797062/2039612/7cafcec8-89a5-11e3-8f2c-5f26a6b83efd.gif)
```vim
" Gif config
nmap s <Plug>(easymotion-s2)
nmap t <Plug>(easymotion-t2)
```
### n-character search motion
You can also search for `n` characters, which can be used to replace the default search of Vim.
It supports incremental highlighting and you can use `<Tab>` and `<S-Tab>` to scroll down/up a page. If you press
`<CR>`, you get the usual EasyMotion highlighting and can jump to any matching target destination with a
single keystroke.
What sounds complicated should become clear if you look at the following examples.
![n-key-motion-scroll](https://f.cloud.github.com/assets/3797062/2039254/4fbf7276-899e-11e3-9bf3-1e446cabc097.gif)
![replace-search](https://f.cloud.github.com/assets/3797062/2039751/64b72bd8-89a8-11e3-80ea-2a6b578040b2.gif)
```vim
" Gif config
map / <Plug>(easymotion-sn)
omap / <Plug>(easymotion-tn)
" These `n` & `N` mappings are options. You do not have to map `n` & `N` to EasyMotion.
" Without these mappings, `n` & `N` works fine. (These mappings just provide
" different highlight method and have some other features )
map n <Plug>(easymotion-next)
map N <Plug>(easymotion-prev)
```
### Within line motion
Every motion also has variants that are restricted to just the current line
(e.g. `<Plug>(easymotion-sl)`, `<Plug>(easymotion-bd-wl)`, etc...). This can be
helpful if you find the full search distracting or slows down vim.
### hjkl motions
EasyMotion can be configured to avoid repetitive use of the `h` `j` `k` and
`l` keys.
![hjkl-motion](https://f.cloud.github.com/assets/3797062/2039413/d8b32ab2-89a0-11e3-894f-3e81db084cfd.gif)
```vim
" Gif config
map <Leader>l <Plug>(easymotion-lineforward)
map <Leader>j <Plug>(easymotion-j)
map <Leader>k <Plug>(easymotion-k)
map <Leader>h <Plug>(easymotion-linebackward)
let g:EasyMotion_startofline = 0 " keep cursor column when JK motion
```
### Smartcase & Smartsign
This setting makes EasyMotion work similarly to Vim's `smartcase` option for
global searches.
```vim
let g:EasyMotion_smartcase = 1
```
With this option set, `v` will match both `v` and `V`, but `V` will match `V`
only. Default: 0.
```vim
let g:EasyMotion_use_smartsign_us = 1 " US layout
" or
let g:EasyMotion_use_smartsign_jp = 1 " JP layout
```
This applies the same concept, but for symbols and numerals. `1` will match `1`
and `!`; `!` matches `!` only. Default: 0.
### Migemo feature (for Japanese user)
```vim
let g:EasyMotion_use_migemo = 1
```
Easymotion can match multibyte Japanese characters with alphabetical input.
For example, `<Leader><Leader>sa` can search 'あ'.
This feature doesn't require cmigemo because Easymotion includes regex
patterns generated by cmigemo. However, installing `cmigemo` will make
2-character and n-character search motions to also support the migemo feature.
Default:0
### Repeat motions
#### Repeat the last motion
`<Plug>(easymotion-repeat)`
#### Repeat the last find motion
In a find motion (e.g. `<Plug>(easymotion-s)`), type `<CR>` without
input characters to find the last motion again.
#### Jump to next/previous match (even on next/previous page)
* `<Plug>(easymotion-next)`
* `<Plug>(easymotion-prev)`
#### Support for dot repeat
This requires https://github.com/tpope/vim-repeat.
You can use EasyMotion with operators and press `.` to repeat!
It is well-behaved and consistent with the default behavior of Vim.
![repeat-motion](https://f.cloud.github.com/assets/3797062/2039538/0aef66aa-89a4-11e3-8242-c27a5208cfca.gif)
```vim
" Gif config
" Require tpope/vim-repeat to enable dot repeat support
" Jump to anywhere with only `s{char}{target}`
" `s<CR>` repeat last find motion.
nmap s <Plug>(easymotion-s)
" Bidirectional & within line 't' motion
omap t <Plug>(easymotion-bd-tl)
" Use uppercase target labels and type as a lower case
let g:EasyMotion_use_upper = 1
" type `l` and match `l`&`L`
let g:EasyMotion_smartcase = 1
" Smartsign (type `3` and match `3`&`#`)
let g:EasyMotion_use_smartsign_us = 1
```
Installation
------------
### Pathogen (https://github.com/tpope/vim-pathogen)
```
git clone https://github.com/easymotion/vim-easymotion ~/.vim/bundle/vim-easymotion
```
### Vundle (https://github.com/gmarik/vundle)
```
Plugin 'easymotion/vim-easymotion'
```
### NeoBundle (https://github.com/Shougo/neobundle.vim)
```
NeoBundle 'easymotion/vim-easymotion'
```
### Vim-Plug (https://github.com/junegunn/vim-plug)
```
Plug 'easymotion/vim-easymotion'
```
### Vim8 Native Plugin Manager (https://vimhelp.org/repeat.txt.html#packages)
```
git clone https://github.com/easymotion/vim-easymotion.git ~/.vim/pack/plugins/start/vim-easymotion
```
Minimal Configuration Tutorial
------------------------------
**I recommend configuring and map keys by yourself if you are true Vimmer.**
**Please do not be satisfied with just installing vim-easymotion, configuring it yourself boost your productivity more and more!**
Default `<Leader><Leader>` prefix isn't easy to press, and I leave them just for backwards compatibility.
You should at least change the prefix key like this `map <Leader> <Plug>(easymotion-prefix)`
Minimal but useful vimrc example:
```vim
let g:EasyMotion_do_mapping = 0 " Disable default mappings
" Jump to anywhere you want with minimal keystrokes, with just one key binding.
" `s{char}{label}`
nmap s <Plug>(easymotion-overwin-f)
" or
" `s{char}{char}{label}`
" Need one more keystroke, but on average, it may be more comfortable.
nmap s <Plug>(easymotion-overwin-f2)
" Turn on case-insensitive feature
let g:EasyMotion_smartcase = 1
" JK motions: Line motions
map <Leader>j <Plug>(easymotion-j)
map <Leader>k <Plug>(easymotion-k)
```
Now, all you need to remember is `s` and JK motions bindings, and it's good enough to boost your cursor speed!
**`s`** is bidirectional find motion, you can move to anywhere with it.
**`<Leader>j`** & **`<Leader>k`** make it easy to move to the lines.
Of course, you can use any key you want instead of `s` such as `<Space>`, `<Leader>s`, etc...
If you want to use more useful mappings, please see [:h easymotion.txt](https://github.com/easymotion/vim-easymotion/blob/master/doc/easymotion.txt) for more detail.

View File

@@ -1,11 +0,0 @@
#!/usr/bin/env rake
task :ci => [:dump, :test]
task :dump do
sh 'vim --version'
end
task :test do
sh 'bundle exec vim-flavor test'
end

View File

@@ -1,117 +0,0 @@
"=============================================================================
" FILE: autoload/EasyMotion/cmigemo.vim
" AUTHOR: haya14busa
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
scriptencoding utf-8
" Saving 'cpoptions' {{{
let s:save_cpo = &cpo
set cpo&vim
" }}}
function! s:has_vimproc() "{{{
if !exists('s:exists_vimproc')
try
silent call vimproc#version()
let s:exists_vimproc = 1
catch
let s:exists_vimproc = 0
endtry
endif
return s:exists_vimproc
endfunction "}}}
function! EasyMotion#cmigemo#system(...) "{{{
return call(s:has_vimproc() ? 'vimproc#system' : 'system', a:000)
endfunction "}}}
function! s:SearchDict2(name) "{{{
let path = $VIM . ',' . &runtimepath
let dict = globpath(path, "dict/".a:name)
if dict == ''
let dict = globpath(path, a:name)
endif
if dict == ''
for path in [
\ '/usr/local/share/migemo/',
\ '/usr/local/share/cmigemo/',
\ '/usr/local/share/',
\ '/usr/share/cmigemo/',
\ '/usr/share/',
\ ]
let path = path . a:name
if filereadable(path)
let dict = path
break
endif
endfor
endif
let dict = matchstr(dict, "^[^\<NL>]*")
return dict
endfunction "}}}
function! s:SearchDict() "{{{
for path in [
\ 'migemo/'.&encoding.'/migemo-dict',
\ &encoding.'/migemo-dict',
\ 'migemo-dict',
\ ]
let dict = s:SearchDict2(path)
if dict != ''
return dict
endif
endfor
echoerr 'a dictionary for migemo is not found'
echoerr 'your encoding is '.&encoding
endfunction "}}}
function! EasyMotion#cmigemo#getMigemoPattern(input) "{{{
if !exists('s:migemodict')
let s:migemodict = s:SearchDict()
endif
if has('migemo')
" Use migemo().
if &migemodict !=# ''
return migemo(a:input)
endif
let &migemodict = s:migemodict
try
return migemo(a:input)
finally
let &migemodict = ''
endtry
elseif executable('cmigemo')
" Use cmigemo.
return EasyMotion#cmigemo#system('cmigemo -v -w "'.a:input.'" -d "'.s:migemodict.'"')
else
" Not supported
return a:input
endif
endfunction "}}}
" Restore 'cpoptions' {{{
let &cpo = s:save_cpo
unlet s:save_cpo
" }}}
" vim: fdm=marker:et:ts=4:sw=4:sts=4

View File

@@ -1,283 +0,0 @@
"=============================================================================
" FILE: autoload/EasyMotion/command_line.vim
" AUTHOR: haya14busa
" Reference: https://github.com/osyo-manga/vim-over
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
scriptencoding utf-8
" Saving 'cpoptions' {{{
let s:save_cpo = &cpo
set cpo&vim
" }}}
" CommandLine:
let s:V = vital#easymotion#new()
let s:cmdline = s:V.import('Over.Commandline.Base')
let s:modules = s:V.import("Over.Commandline.Modules")
let s:search = s:cmdline.make()
let s:search.highlights.prompt = 'Question'
" Add Module: {{{
call s:search.connect('Exit')
call s:search.connect('Cancel')
call s:search.connect('Redraw')
call s:search.connect('DrawCommandline')
call s:search.connect('Delete')
call s:search.connect('CursorMove')
call s:search.connect('Paste')
call s:search.connect('BufferComplete')
call s:search.connect('InsertRegister')
call s:search.connect('ExceptionExit')
call s:search.connect(s:modules.get('ExceptionMessage').make('EasyMotion: ', 'echom'))
call s:search.connect(s:modules.get('History').make('/'))
call s:search.connect(s:modules.get('NoInsert').make_special_chars())
call s:search.connect(s:modules.get('KeyMapping').make_emacs())
call s:search.connect(s:modules.get('Doautocmd').make('EMCommandLine'))
let s:module = {
\ "name" : "EasyMotion",
\}
function! s:module.on_char_pre(cmdline)
if a:cmdline.is_input("<Over>(em-scroll-f)")
call s:scroll(0)
call a:cmdline.setchar('')
elseif a:cmdline.is_input("<Over>(em-scroll-b)")
call s:scroll(1)
call a:cmdline.setchar('')
elseif a:cmdline.is_input("<Over>(em-jumpback)")
keepjumps call setpos('.', s:save_orig_pos)
let s:orig_pos = s:save_orig_pos
let s:orig_line_start = getpos('w0')
let s:orig_line_end = getpos('w$')
let s:direction = s:save_direction
call a:cmdline.setchar('')
elseif a:cmdline.is_input("<Over>(em-openallfold)")
" TODO: better solution
normal! zR
call a:cmdline.setchar('')
endif
endfunction
call s:search.connect(s:module)
"}}}
" CommandLine Keymap: {{{
" .keymapping() won't be remapped by user defined KeyMappings.
function! s:search.keymapping() "{{{
return {
\ "\<CR>" : {
\ "key" : "<Over>(exit)",
\ "noremap" : 1,
\ "lock" : 1,
\ },
\ }
endfunction "}}}
call s:search.cnoremap("\<C-l>", '<Over>(buffer-complete)')
call s:search.cnoremap("\<Tab>", '<Over>(em-scroll-f)')
call s:search.cnoremap("\<S-Tab>", '<Over>(em-scroll-b)')
call s:search.cnoremap("\<C-o>", '<Over>(em-jumpback)')
call s:search.cnoremap("\<C-z>", '<Over>(em-openallfold)')
" Fins Motion CommandLine Mapping Command: {{{
function! EasyMotion#command_line#cmap(args)
let lhs = s:as_keymapping(a:args[0])
let rhs = s:as_keymapping(a:args[1])
call s:search.cmap(lhs, rhs)
endfunction
function! EasyMotion#command_line#cnoremap(args)
let lhs = s:as_keymapping(a:args[0])
let rhs = s:as_keymapping(a:args[1])
call s:search.cnoremap(lhs, rhs)
endfunction
function! EasyMotion#command_line#cunmap(lhs)
let lhs = s:as_keymapping(a:lhs)
call s:search.cunmap(lhs)
endfunction
function! s:as_keymapping(key)
execute 'let result = "' . substitute(a:key, '\(<.\{-}>\)', '\\\1', 'g') . '"'
return result
endfunction
"}}}
"}}}
" Event: {{{
function! s:search.on_enter(cmdline) "{{{
if s:num_strokes == -1
call EasyMotion#highlight#delete_highlight()
call EasyMotion#helper#VarReset('&scrolloff', 0)
if g:EasyMotion_do_shade
call EasyMotion#highlight#add_highlight('\_.*',
\ g:EasyMotion_hl_group_shade)
endif
endif
if g:EasyMotion_cursor_highlight
call EasyMotion#highlight#add_highlight('\%#',
\ g:EasyMotion_hl_inc_cursor)
endif
endfunction "}}}
function! s:search.on_leave(cmdline) "{{{
if s:num_strokes == -1
call EasyMotion#highlight#delete_highlight(g:EasyMotion_hl_inc_search)
if g:EasyMotion_do_shade
call EasyMotion#highlight#delete_highlight(g:EasyMotion_hl_group_shade)
endif
endif
if g:EasyMotion_cursor_highlight
call EasyMotion#highlight#delete_highlight(g:EasyMotion_hl_inc_cursor)
endif
endfunction "}}}
function! s:search.on_char(cmdline) "{{{
if s:num_strokes == -1
let re = s:search.getline()
if EasyMotion#helper#should_case_sensitive(re, 1)
let case_flag = '\c'
else
let case_flag = '\C'
endif
let re .= case_flag
if g:EasyMotion_inc_highlight
call s:inc_highlight(re)
endif
if g:EasyMotion_off_screen_search
call s:off_screen_search(re)
endif
elseif s:search.line.length() >= s:num_strokes
call s:search.exit()
endif
endfunction "}}}
"}}}
" Main:
function! EasyMotion#command_line#GetInput(num_strokes, prev, direction) "{{{
let s:num_strokes = a:num_strokes
let s:prompt_base = s:getPromptMessage(a:num_strokes)
call s:search.set_prompt(s:prompt_base)
" Screen: cursor position, first and last line
let s:orig_pos = getpos('.')
let s:orig_line_start = getpos('w0')
let s:orig_line_end = getpos('w$')
let s:save_orig_pos = deepcopy(s:orig_pos)
" Direction:
let s:direction = a:direction == 1 ? 'b' : ''
let s:save_direction = deepcopy(s:direction)
let input = s:search.get()
if input == '' && ! s:search.exit_code()
return a:prev
elseif s:search.exit_code() == 1 || s:search.exit_code() == -1
call s:Cancell()
return ''
else
return input
endif
endfunction "}}}
" Helper:
function! s:Cancell() " {{{
call EasyMotion#highlight#delete_highlight()
call EasyMotion#helper#VarReset('&scrolloff')
keepjumps call setpos('.', s:save_orig_pos)
if g:EasyMotion_verbose
echo 'EasyMotion: Cancelled'
endif
return ''
endfunction " }}}
function! s:getPromptMessage(num_strokes) "{{{
if a:num_strokes == 1
let prompt = substitute(
\ substitute(g:EasyMotion_prompt,'{n}', a:num_strokes, 'g'),
\ '(s)', '', 'g')
elseif a:num_strokes == -1
let prompt = substitute(
\ substitute(g:EasyMotion_prompt, '{n}\s\{0,1}', '', 'g'),
\ '(s)', 's', 'g')
else
let prompt = substitute(
\ substitute(g:EasyMotion_prompt,'{n}', a:num_strokes, 'g'),
\ '(s)', 's', 'g')
endif
return prompt
endfunction "}}}
function! s:off_screen_search(re) "{{{
" First: search within visible screen range
call s:adjust_screen()
" Error occur when '\zs' without '!'
silent! let pos = searchpos(a:re, s:direction . 'n', s:orig_line_end[1])
if pos != [0, 0]
" Restore cursor posision
keepjumps call setpos('.', s:orig_pos)
else
" Second: if there were no much, search off screen
silent! let pos = searchpos(a:re, s:direction)
if pos != [0, 0]
" Match
keepjumps call setpos('.', pos)
" Move cursor
if s:save_direction != 'b'
normal! zzH0
else
normal! zzL0
endif
else
" No much
call s:adjust_screen()
keepjumps call setpos('.', s:orig_pos)
endif
endif
" redraw
endfunction "}}}
function! s:adjust_screen() "{{{
if s:save_direction != 'b'
" Forward
keepjumps call setpos('.', s:orig_line_start)
normal! zt
else
" Backward
keepjumps call setpos('.', s:orig_line_end)
normal! zb
endif
endfunction "}}}
function! s:scroll(direction) "{{{
" direction: 0 -> forward, 1 -> backward
exec a:direction == 0 ? "normal! \<C-f>" : "normal! \<C-b>"
let s:orig_pos = getpos('.')
let s:orig_line_start = getpos('w0')
let s:orig_line_end = getpos('w$')
let s:direction = a:direction == 0 ? '' : 'b'
endfunction "}}}
function! s:inc_highlight(re) "{{{
call EasyMotion#highlight#delete_highlight(g:EasyMotion_hl_inc_search)
if s:search.line.length() > 0
" Error occur when '\zs' without '!'
silent! call EasyMotion#highlight#add_highlight(a:re, g:EasyMotion_hl_inc_search)
endif
endfunction "}}}
" Restore 'cpoptions' {{{
let &cpo = s:save_cpo
unlet s:save_cpo
" }}}
" vim: fdm=marker:et:ts=4:sw=4:sts=4

View File

@@ -1,185 +0,0 @@
"=============================================================================
" FILE: autoload/EasyMotion/helper.vim
" AUTHOR: haya14busa
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
scriptencoding utf-8
" Saving 'cpoptions' {{{
let s:save_cpo = &cpo
set cpo&vim
" }}}
function! EasyMotion#helper#mode(flag) "{{{
return mode(a:flag) == "\<C-v>" ? "C-v" : mode(a:flag)
endfunction "}}}
function! EasyMotion#helper#get_char_by_coord(coord) "{{{
" @param coord: [lnum, col] or [bufnum, lnum, col, off]
if len(a:coord) == 4
let [line_num, col_num] = [a:coord[1], a:coord[2]]
else
let [line_num, col_num] = a:coord
endif
let target_col_regexp = '\%' . (col_num) . 'c.'
return matchstr(getline(line_num), target_col_regexp)
endfunction "}}}
function! EasyMotion#helper#is_greater_coords(coords1, coords2) "{{{
" [line_num, col_num] < [line_num, col_num]
"
" coords1 < coords2 : return 1
" coords1 > coords2 : return -1
" coords1 == coords2 : return 0
if a:coords1 == a:coords2 | return 0 | endif
if a:coords1[0] < a:coords2[0]
return 1
elseif a:coords1[0] > a:coords2[0]
return -1
endif
" Same line
if a:coords1[1] < a:coords2[1]
return 1
elseif a:coords1[1] > a:coords2[1]
return -1
endif
endfunction "}}}
function! EasyMotion#helper#is_folded(line) "{{{
" Return false if g:EasyMotion_skipfoldedline == 1
" and line is start of folded lines
let _foldclosed = foldclosed(a:line)
return _foldclosed != -1 &&
\ (g:EasyMotion_skipfoldedline == 1 || a:line != _foldclosed)
endfunction "}}}
function! EasyMotion#helper#should_case_sensitive(input, is_search) "{{{
if !a:is_search
if g:EasyMotion_smartcase == 0
return 0
else
" return 1 if input didn't match uppercase letter
return match(a:input, '\u') == -1
endif
endif
if (g:EasyMotion_smartcase == 1 && match(a:input, '\u') == -1) ||
\ (&ignorecase && &smartcase && match(a:input, '\u') == -1) ||
\ (&ignorecase && !&smartcase)
return 1
endif
return 0
endfunction "}}}
function! EasyMotion#helper#silent_feedkeys(expr, name, ...) "{{{
" Ref:
" https://github.com/osyo-manga/vim-over/blob/d51b028c29661d4a5f5b79438ad6d69266753711/autoload/over.vim#L6
let mode = get(a:, 1, "m")
let name = "easymotion-" . a:name
let map = printf("<Plug>(%s)", name)
if mode == "n"
let command = "nnoremap"
else
let command = "nmap"
endif
execute command "<silent>" map printf("%s:nunmap %s<CR>", a:expr, map)
if mode(1) !=# 'ce'
" FIXME: mode(1) !=# 'ce' exists only for the test
" :h feedkeys() doesn't work while runnning a test script
" https://github.com/kana/vim-vspec/issues/27
call feedkeys(printf("\<Plug>(%s)", name))
endif
endfunction "}}}
function! EasyMotion#helper#VarReset(var, ...) "{{{
if ! exists('s:var_reset')
let s:var_reset = {}
endif
if a:0 == 0 && has_key(s:var_reset, a:var)
" Reset var to original value
" setbufvar( or bufname): '' or '%' can be used for the current buffer
call setbufvar('%', a:var, s:var_reset[a:var])
elseif a:0 == 1
" Save original value and set new var value
let new_value = a:0 == 1 ? a:1 : ''
" Store original value
let s:var_reset[a:var] = getbufvar("", a:var)
" Set new var value
call setbufvar('%', a:var, new_value)
endif
endfunction "}}}
" Migemo {{{
function! EasyMotion#helper#load_migemo_dict() "{{{
let enc = &l:encoding
if enc ==# 'utf-8'
return EasyMotion#migemo#utf8#load_dict()
elseif enc ==# 'cp932'
return EasyMotion#migemo#cp932#load_dict()
elseif enc ==# 'euc-jp'
return EasyMotion#migemo#eucjp#load_dict()
else
let g:EasyMotion_use_migemo = 0
throw "Error: ".enc." is not supported. Migemo is made disabled."
endif
endfunction "}}}
" EasyMotion#helper#strchars() {{{
if exists('*strchars')
function! EasyMotion#helper#strchars(str)
return strchars(a:str)
endfunction
else
function! EasyMotion#helper#strchars(str)
return strlen(substitute(a:str, ".", "x", "g"))
endfunction
endif "}}}
function! EasyMotion#helper#include_multibyte_char(str) "{{{
return strlen(a:str) != EasyMotion#helper#strchars(a:str)
endfunction "}}}
function! EasyMotion#helper#vcol(expr) abort
let col_num = col(a:expr)
let line = getline(a:expr)
let before_line = col_num > 2 ? line[: col_num - 2]
\ : col_num is# 2 ? line[0]
\ : ''
let vcol_num = 1
for c in split(before_line, '\zs')
let vcol_num += c is# "\t" ? s:_virtual_tab2spacelen(vcol_num) : len(c)
endfor
return vcol_num
endfunction
function! s:_virtual_tab2spacelen(col_num) abort
return &tabstop - ((a:col_num - 1) % &tabstop)
endfunction
"}}}
" Restore 'cpoptions' {{{
let &cpo = s:save_cpo
unlet s:save_cpo
" }}}
" vim: fdm=marker:et:ts=4:sw=4:sts=4

View File

@@ -1,251 +0,0 @@
"=============================================================================
" FILE: highlight.vim
" AUTHOR: haya14busa
" Reference: https://github.com/t9md/vim-smalls
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
scriptencoding utf-8
" Saving 'cpoptions' {{{
let s:save_cpo = &cpo
set cpo&vim
" }}}
function! EasyMotion#highlight#load()
"load
endfunction
" -- Default highlighting ---------------- {{{
let g:EasyMotion_hl_group_target = get(g:,
\ 'EasyMotion_hl_group_target', 'EasyMotionTarget')
let g:EasyMotion_hl2_first_group_target = get(g:,
\ 'EasyMotion_hl2_first_group_target', 'EasyMotionTarget2First')
let g:EasyMotion_hl2_second_group_target = get(g:,
\ 'EasyMotion_hl2_second_group_target', 'EasyMotionTarget2Second')
let g:EasyMotion_hl_group_shade = get(g:,
\ 'EasyMotion_hl_group_shade', 'EasyMotionShade')
let g:EasyMotion_hl_inc_search = get(g:,
\ 'EasyMotion_hl_inc_search', 'EasyMotionIncSearch')
let g:EasyMotion_hl_inc_cursor = get(g:,
\ 'EasyMotion_hl_inc_cursor', 'EasyMotionIncCursor')
let g:EasyMotion_hl_move = get(g:,
\ 'EasyMotion_hl_move', 'EasyMotionMoveHL')
let s:target_hl_defaults = {
\ 'gui' : ['NONE', '#ff0000' , 'bold']
\ , 'cterm256': ['NONE', '196' , 'bold']
\ , 'cterm' : ['NONE', 'red' , 'bold']
\ }
let s:target_hl2_first_defaults = {
\ 'gui' : ['NONE', '#ffb400' , 'bold']
\ , 'cterm256': ['NONE', '11' , 'bold']
\ , 'cterm' : ['NONE', 'yellow' , 'bold']
\ }
let s:target_hl2_second_defaults = {
\ 'gui' : ['NONE', '#b98300' , 'bold']
\ , 'cterm256': ['NONE', '3' , 'bold']
\ , 'cterm' : ['NONE', 'yellow' , 'bold']
\ }
let s:shade_hl_defaults = {
\ 'gui' : ['NONE', '#777777' , 'NONE']
\ , 'cterm256': ['NONE', '242' , 'NONE']
\ , 'cterm' : ['NONE', 'grey' , 'NONE']
\ }
let s:shade_hl_line_defaults = {
\ 'gui' : ['red' , '#FFFFFF' , 'NONE']
\ , 'cterm256': ['red' , '242' , 'NONE']
\ , 'cterm' : ['red' , 'grey' , 'NONE']
\ }
let s:target_hl_inc = {
\ 'gui' : ['NONE', '#7fbf00' , 'bold']
\ , 'cterm256': ['NONE', '40' , 'bold']
\ , 'cterm' : ['NONE', 'green' , 'bold']
\ }
let s:target_hl_inc_cursor = {
\ 'gui' : ['#ACDBDA', '#121813' , 'bold']
\ , 'cterm256': ['cyan' , '232' , 'bold']
\ , 'cterm' : ['cyan' , 'black' , 'bold']
\ }
let s:target_hl_move = {
\ 'gui' : ['#7fbf00', '#121813' , 'bold']
\ , 'cterm256': ['green' , '15' , 'bold']
\ , 'cterm' : ['green' , 'white' , 'bold']
\ }
" }}}
function! EasyMotion#highlight#InitHL(group, colors) " {{{
let group_default = a:group . 'Default'
" Prepare highlighting variables
let guihl = printf('guibg=%s guifg=%s gui=%s', a:colors.gui[0], a:colors.gui[1], a:colors.gui[2])
let ctermhl = &t_Co == 256
\ ? printf('ctermbg=%s ctermfg=%s cterm=%s', a:colors.cterm256[0], a:colors.cterm256[1], a:colors.cterm256[2])
\ : printf('ctermbg=%s ctermfg=%s cterm=%s', a:colors.cterm[0], a:colors.cterm[1], a:colors.cterm[2])
" Create default highlighting group
execute printf('hi default %s %s %s', group_default, guihl, ctermhl)
" Check if the hl group exists
if hlexists(a:group)
redir => hlstatus | exec 'silent hi ' . a:group | redir END
" Return if the group isn't cleared
if hlstatus !~ 'cleared'
return
endif
endif
" No colors are defined for this group, link to defaults
execute printf('hi default link %s %s', a:group, group_default)
endfunction " }}}
function! EasyMotion#highlight#init() "{{{
call EasyMotion#highlight#InitHL(g:EasyMotion_hl_group_target, s:target_hl_defaults)
call EasyMotion#highlight#InitHL(g:EasyMotion_hl2_first_group_target, s:target_hl2_first_defaults)
call EasyMotion#highlight#InitHL(g:EasyMotion_hl2_second_group_target, s:target_hl2_second_defaults)
call EasyMotion#highlight#InitHL(g:EasyMotion_hl_group_shade, s:shade_hl_defaults)
call EasyMotion#highlight#InitHL(g:EasyMotion_hl_inc_search, s:target_hl_inc)
call EasyMotion#highlight#InitHL(g:EasyMotion_hl_inc_cursor, s:target_hl_inc_cursor)
call EasyMotion#highlight#InitHL(g:EasyMotion_hl_move, s:target_hl_move)
if exists(':CSApprox') == 2 && g:EasyMotion_force_csapprox
"TODO: better solution or remove completly
CSApprox!
endif
endfunction "}}}
" Reset highlighting after loading a new color scheme {{{
augroup EasyMotionInitHL
autocmd!
autocmd ColorScheme * call EasyMotion#highlight#init()
augroup end
" }}}
call EasyMotion#highlight#init()
" Init: {{{
let s:h = {}
let s:h.ids = {}
let s:priorities = {
\ g:EasyMotion_hl_group_target : 100,
\ g:EasyMotion_hl2_first_group_target : 100,
\ g:EasyMotion_hl2_second_group_target : 100,
\ g:EasyMotion_hl_group_shade : 0,
\ g:EasyMotion_hl_inc_search : 1,
\ g:EasyMotion_hl_inc_cursor : 2,
\ g:EasyMotion_hl_move : 0,
\ }
for s:group in keys(s:priorities)
let s:h.ids[s:group] = []
endfor
unlet s:group
"}}}
function! EasyMotion#highlight#delete_highlight(...) "{{{
let groups = !empty(a:000) ? a:000 : keys(s:priorities)
for group in groups
for id in s:h.ids[group]
silent! call matchdelete(id)
endfor
let s:h.ids[group] = []
endfor
endfunction "}}}
function! EasyMotion#highlight#add_highlight(re, group) "{{{
call add(s:h.ids[a:group], matchadd(a:group, a:re, s:priorities[a:group]))
endfunction "}}}
function! EasyMotion#highlight#add_pos_highlight(line_num, col_num, group) "{{{
call add(s:h.ids[a:group], matchaddpos(a:group, [[a:line_num, a:col_num]], s:priorities[a:group]))
endfunction "}}}
function! EasyMotion#highlight#attach_autocmd() "{{{
" Reference: https://github.com/justinmk/vim-sneak
augroup plugin-easymotion
autocmd!
autocmd InsertEnter,WinLeave,BufLeave <buffer>
\ silent! call EasyMotion#highlight#delete_highlight()
\ | autocmd! plugin-easymotion * <buffer>
autocmd CursorMoved <buffer>
\ autocmd plugin-easymotion CursorMoved <buffer>
\ silent! call EasyMotion#highlight#delete_highlight()
\ | autocmd! plugin-easymotion * <buffer>
augroup END
endfunction "}}}
function! EasyMotion#highlight#add_color_group(new_groups) "{{{
let s:priorities = extend(deepcopy(s:priorities), a:new_groups)
for group in keys(a:new_groups)
let s:h.ids[group] = []
endfor
endfunction "}}}
function! EasyMotion#highlight#capture(hlname) "{{{
" Based On: https://github.com/t9md/vim-ezbar
" https://github.com/osyo-manga/vital-over
let hlname = a:hlname
if !hlexists(hlname)
return
endif
while 1
let save_verbose = &verbose
let &verbose = 0
try
redir => HL_SAVE
execute 'silent! highlight ' . hlname
redir END
finally
let &verbose = save_verbose
endtry
if !empty(matchstr(HL_SAVE, 'xxx cleared$'))
return ''
endif
" follow highlight link
let ml = matchlist(HL_SAVE, 'links to \zs.*')
if !empty(ml)
let hlname = ml[0]
continue
endif
break
endwhile
let HL_SAVE = substitute(matchstr(HL_SAVE, 'xxx \zs.*'),
\ '[ \t\n]\+', ' ', 'g')
return [hlname, HL_SAVE]
endfunction "}}}
function! EasyMotion#highlight#turn_off(hl) "{{{
if type(a:hl) != type([])
return
endif
execute 'highlight ' . a:hl[0] . ' NONE'
endfunction "}}}
function! EasyMotion#highlight#turn_on(hl) "{{{
if type(a:hl) != type([])
return
endif
execute 'highlight ' . a:hl[0] . ' ' . a:hl[1]
endfunction "}}}
" Restore 'cpoptions' {{{
let &cpo = s:save_cpo
unlet s:save_cpo
" }}}
" __END__ {{{
" vim: expandtab softtabstop=4 shiftwidth=4
" vim: foldmethod=marker
" }}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,27 +0,0 @@
let s:V = vital#easymotion#new()
let s:HitAHintMotion = s:V.import('HitAHint.Motion')
call EasyMotion#init()
function! EasyMotion#overwin#move(pattern) abort
return s:HitAHintMotion.move(a:pattern, {
\ 'keys': g:EasyMotion_keys,
\ 'use_upper': g:EasyMotion_use_upper,
\ 'highlight': {
\ 'shade': g:EasyMotion_hl_group_shade,
\ 'target': g:EasyMotion_hl_group_target,
\ },
\ 'jump_first_target_keys':
\ (g:EasyMotion_enter_jump_first ? ["\<CR>"] : []) +
\ (g:EasyMotion_space_jump_first ? ["\<Space>"] : []),
\ 'do_shade': g:EasyMotion_do_shade,
\ })
endfunction
function! EasyMotion#overwin#line() abort
return EasyMotion#overwin#move('^')
endfunction
function! EasyMotion#overwin#w() abort
return EasyMotion#overwin#move('\(\<.\|^$\)')
endfunction

View File

@@ -1,24 +0,0 @@
" Saving 'cpoptions' {{{
let s:save_cpo = &cpo
set cpo&vim
" }}}
"
let EasyMotion#sticky_table#us = {
\',' : '<', '.' : '>', '/' : '?',
\'1' : '!', '2' : '@', '3' : '#', '4' : '$', '5' : '%',
\'6' : '^', '7' : '&', '8' : '*', '9' : '(', '0' : ')', '-' : '_', '=' : '+',
\';' : ':', '[' : '{', ']' : '}', '`' : '~', "'" : "\"", '\' : '|',
\}
let EasyMotion#sticky_table#jp = {
\',' : '<', '.' : '>', '/' : '?',
\'1' : '!', '2' : '"', '3' : '#', '4' : '$', '5' : '%',
\'6' : '&', '7' : "'", '8' : '(', '9' : ')', '0' : '_', '-' : '=', '^' : '~',
\';' : '+', ':' : '*', '[' : '{', ']' : '}', '@' : '`', '\' : '|',
\}
" Restore 'cpoptions' {{{
let &cpo = s:save_cpo
unlet s:save_cpo
" }}}
" vim: fdm=marker:et:ts=4:sw=4:sts=4

View File

@@ -1,50 +0,0 @@
let s:Buffer = vital#easymotion#import('Vim.Buffer')
function! EasyMotion#undo#save() abort
return s:undo_lock.save()
endfunction
let s:undo_lock = {}
function! s:undo_lock.save() abort
let undo = deepcopy(self)
call undo._save()
return undo
endfunction
function! s:undo_lock._save() abort
if undotree().seq_last == 0
" if there are no undo history, disable undo feature by setting
" 'undolevels' to -1 and restore it.
let self.save_undolevels = &l:undolevels
let &l:undolevels = -1
elseif !s:Buffer.is_cmdwin()
" command line window doesn't support :wundo.
let self.undofile = tempname()
execute 'wundo!' self.undofile
else
let self.is_cmdwin = s:TRUE
endif
endfunction
function! s:undo_lock.restore() abort
if has_key(self, 'save_undolevels')
let &l:undolevels = self.save_undolevels
endif
if has_key(self, 'undofile') && filereadable(self.undofile)
silent execute 'rundo' self.undofile
call delete(self.undofile)
endif
if has_key(self, 'is_cmdwin')
" XXX: it breaks undo history. AFAIK, there are no way to save and restore
" undo history in commandline window.
call self.undobreak()
endif
endfunction
function! s:undo_lock.undobreak() abort
let old_undolevels = &l:undolevels
setlocal undolevels=-1
keepjumps call setline('.', getline('.'))
let &l:undolevels = old_undolevels
endfunction

View File

@@ -1,12 +0,0 @@
function! vital#of(name) abort
let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital', 1)
let file = split(files, "\n")
if empty(file)
throw 'vital: version file not found: ' . a:name
endif
let ver = readfile(file[0], 'b')
if empty(ver)
throw 'vital: invalid version file: ' . a:name
endif
return vital#_{substitute(ver[0], '\W', '', 'g')}#new()
endfunction

View File

@@ -1,5 +0,0 @@
let s:_plugin_name = expand('<sfile>:t:r')
function! vital#{s:_plugin_name}#new() abort
return vital#{s:_plugin_name[1:]}#new()
endfunction

View File

@@ -1,116 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Data#Dict#import() abort
return map({'pick': '', 'clear': '', 'max_by': '', 'foldl': '', 'swap': '', 'omit': '', 'min_by': '', 'foldr': '', 'make_index': '', 'make': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Data#Dict#import() abort', printf("return map({'pick': '', 'clear': '', 'max_by': '', 'foldl': '', 'swap': '', 'omit': '', 'min_by': '', 'foldr': '', 'make_index': '', 'make': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
" Utilities for dictionary.
let s:save_cpo = &cpo
set cpo&vim
" Makes a dict from keys and values
function! s:make(keys, values, ...) abort
let dict = {}
let fill = a:0 ? a:1 : 0
for i in range(len(a:keys))
let key = type(a:keys[i]) == type('') ? a:keys[i] : string(a:keys[i])
if key ==# ''
throw "vital: Data.Dict: Can't use an empty string for key."
endif
let dict[key] = get(a:values, i, fill)
endfor
return dict
endfunction
" Swaps keys and values
function! s:swap(dict) abort
return s:make(values(a:dict), keys(a:dict))
endfunction
" Makes a index dict from a list
function! s:make_index(list, ...) abort
let value = a:0 ? a:1 : 1
return s:make(a:list, [], value)
endfunction
function! s:pick(dict, keys) abort
let new_dict = {}
for key in a:keys
if has_key(a:dict, key)
let new_dict[key] = a:dict[key]
endif
endfor
return new_dict
endfunction
function! s:omit(dict, keys) abort
let new_dict = copy(a:dict)
for key in a:keys
if has_key(a:dict, key)
call remove(new_dict, key)
endif
endfor
return new_dict
endfunction
function! s:clear(dict) abort
for key in keys(a:dict)
call remove(a:dict, key)
endfor
return a:dict
endfunction
function! s:_max_by(dict, expr) abort
let dict = s:swap(map(copy(a:dict), a:expr))
let key = dict[max(keys(dict))]
return [key, a:dict[key]]
endfunction
function! s:max_by(dict, expr) abort
if empty(a:dict)
throw 'vital: Data.Dict: Empty dictionary'
endif
return s:_max_by(a:dict, a:expr)
endfunction
function! s:min_by(dict, expr) abort
if empty(a:dict)
throw 'vital: Data.Dict: Empty dictionary'
endif
return s:_max_by(a:dict, '-(' . a:expr . ')')
endfunction
function! s:_foldl(f, init, xs) abort
let memo = a:init
for [k, v] in a:xs
let expr = substitute(a:f, 'v:key', string(k), 'g')
let expr = substitute(expr, 'v:val', string(v), 'g')
let expr = substitute(expr, 'v:memo', string(memo), 'g')
unlet memo
let memo = eval(expr)
endfor
return memo
endfunction
function! s:foldl(f, init, dict) abort
return s:_foldl(a:f, a:init, items(a:dict))
endfunction
function! s:foldr(f, init, dict) abort
return s:_foldl(a:f, a:init, reverse(items(a:dict)))
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:

View File

@@ -1,457 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Data#List#import() abort
return map({'combinations': '', 'and': '', 'sort_by': '', 'foldr1': '', 'sort': '', 'flatten': '', 'has_index': '', 'find_indices': '', 'any': '', 'unshift': '', 'span': '', 'pop': '', 'binary_search': '', 'uniq_by': '', 'or': '', 'all': '', 'zip': '', 'find_last_index': '', 'find': '', 'partition': '', 'map_accum': '', 'permutations': '', 'break': '', 'max_by': '', 'foldl': '', 'foldr': '', 'find_index': '', 'group_by': '', 'take_while': '', 'conj': '', 'push': '', 'char_range': '', 'cons': '', 'foldl1': '', 'intersect': '', 'concat': '', 'shift': '', 'clear': '', 'has_common_items': '', 'product': '', 'zip_fill': '', 'uniq': '', 'has': '', 'min_by': '', 'with_index': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Data#List#import() abort', printf("return map({'combinations': '', 'and': '', 'sort_by': '', 'foldr1': '', 'sort': '', 'flatten': '', 'has_index': '', 'find_indices': '', 'any': '', 'unshift': '', 'span': '', 'pop': '', 'binary_search': '', 'uniq_by': '', 'or': '', 'all': '', 'zip': '', 'find_last_index': '', 'find': '', 'partition': '', 'map_accum': '', 'permutations': '', 'break': '', 'max_by': '', 'foldl': '', 'foldr': '', 'find_index': '', 'group_by': '', 'take_while': '', 'conj': '', 'push': '', 'char_range': '', 'cons': '', 'foldl1': '', 'intersect': '', 'concat': '', 'shift': '', 'clear': '', 'has_common_items': '', 'product': '', 'zip_fill': '', 'uniq': '', 'has': '', 'min_by': '', 'with_index': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
" Utilities for list.
let s:save_cpo = &cpo
set cpo&vim
function! s:pop(list) abort
return remove(a:list, -1)
endfunction
function! s:push(list, val) abort
call add(a:list, a:val)
return a:list
endfunction
function! s:shift(list) abort
return remove(a:list, 0)
endfunction
function! s:unshift(list, val) abort
return insert(a:list, a:val)
endfunction
function! s:cons(x, xs) abort
return [a:x] + a:xs
endfunction
function! s:conj(xs, x) abort
return a:xs + [a:x]
endfunction
" Removes duplicates from a list.
function! s:uniq(list) abort
return s:uniq_by(a:list, 'v:val')
endfunction
" Removes duplicates from a list.
function! s:uniq_by(list, f) abort
let list = map(copy(a:list), printf('[v:val, %s]', a:f))
let i = 0
let seen = {}
while i < len(list)
let key = string(list[i][1])
if has_key(seen, key)
call remove(list, i)
else
let seen[key] = 1
let i += 1
endif
endwhile
return map(list, 'v:val[0]')
endfunction
function! s:clear(list) abort
if !empty(a:list)
unlet! a:list[0 : len(a:list) - 1]
endif
return a:list
endfunction
" Concatenates a list of lists.
" XXX: Should we verify the input?
function! s:concat(list) abort
let memo = []
for Value in a:list
let memo += Value
endfor
return memo
endfunction
" Take each elements from lists to a new list.
function! s:flatten(list, ...) abort
let limit = a:0 > 0 ? a:1 : -1
let memo = []
if limit == 0
return a:list
endif
let limit -= 1
for Value in a:list
let memo +=
\ type(Value) == type([]) ?
\ s:flatten(Value, limit) :
\ [Value]
unlet! Value
endfor
return memo
endfunction
" Sorts a list with expression to compare each two values.
" a:a and a:b can be used in {expr}.
function! s:sort(list, expr) abort
if type(a:expr) == type(function('function'))
return sort(a:list, a:expr)
endif
let s:expr = a:expr
return sort(a:list, 's:_compare')
endfunction
function! s:_compare(a, b) abort
return eval(s:expr)
endfunction
" Sorts a list using a set of keys generated by mapping the values in the list
" through the given expr.
" v:val is used in {expr}
function! s:sort_by(list, expr) abort
let pairs = map(a:list, printf('[v:val, %s]', a:expr))
return map(s:sort(pairs,
\ 'a:a[1] ==# a:b[1] ? 0 : a:a[1] ># a:b[1] ? 1 : -1'), 'v:val[0]')
endfunction
" Returns a maximum value in {list} through given {expr}.
" Returns 0 if {list} is empty.
" v:val is used in {expr}
function! s:max_by(list, expr) abort
if empty(a:list)
return 0
endif
let list = map(copy(a:list), a:expr)
return a:list[index(list, max(list))]
endfunction
" Returns a minimum value in {list} through given {expr}.
" Returns 0 if {list} is empty.
" v:val is used in {expr}
" FIXME: -0x80000000 == 0x80000000
function! s:min_by(list, expr) abort
return s:max_by(a:list, '-(' . a:expr . ')')
endfunction
" Returns List of character sequence between [a:from, a:to]
" e.g.: s:char_range('a', 'c') returns ['a', 'b', 'c']
function! s:char_range(from, to) abort
return map(
\ range(char2nr(a:from), char2nr(a:to)),
\ 'nr2char(v:val)'
\)
endfunction
" Returns true if a:list has a:value.
" Returns false otherwise.
function! s:has(list, value) abort
return index(a:list, a:value) isnot -1
endfunction
" Returns true if a:list[a:index] exists.
" Returns false otherwise.
" NOTE: Returns false when a:index is negative number.
function! s:has_index(list, index) abort
" Return true when negative index?
" let index = a:index >= 0 ? a:index : len(a:list) + a:index
return 0 <= a:index && a:index < len(a:list)
endfunction
" similar to Haskell's Data.List.span
function! s:span(f, xs) abort
let border = len(a:xs)
for i in range(len(a:xs))
if !eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
let border = i
break
endif
endfor
return border == 0 ? [[], copy(a:xs)] : [a:xs[: border - 1], a:xs[border :]]
endfunction
" similar to Haskell's Data.List.break
function! s:break(f, xs) abort
return s:span(printf('!(%s)', a:f), a:xs)
endfunction
" similar to Haskell's Data.List.takeWhile
function! s:take_while(f, xs) abort
return s:span(a:f, a:xs)[0]
endfunction
" similar to Haskell's Data.List.partition
function! s:partition(f, xs) abort
return [filter(copy(a:xs), a:f), filter(copy(a:xs), '!(' . a:f . ')')]
endfunction
" similar to Haskell's Prelude.all
function! s:all(f, xs) abort
return !s:any(printf('!(%s)', a:f), a:xs)
endfunction
" similar to Haskell's Prelude.any
function! s:any(f, xs) abort
return !empty(filter(map(copy(a:xs), a:f), 'v:val'))
endfunction
" similar to Haskell's Prelude.and
function! s:and(xs) abort
return s:all('v:val', a:xs)
endfunction
" similar to Haskell's Prelude.or
function! s:or(xs) abort
return s:any('v:val', a:xs)
endfunction
function! s:map_accum(expr, xs, init) abort
let memo = []
let init = a:init
for x in a:xs
let expr = substitute(a:expr, 'v:memo', init, 'g')
let expr = substitute(expr, 'v:val', x, 'g')
let [tmp, init] = eval(expr)
call add(memo, tmp)
endfor
return memo
endfunction
" similar to Haskell's Prelude.foldl
function! s:foldl(f, init, xs) abort
let memo = a:init
for x in a:xs
let expr = substitute(a:f, 'v:val', string(x), 'g')
let expr = substitute(expr, 'v:memo', string(memo), 'g')
unlet memo
let memo = eval(expr)
endfor
return memo
endfunction
" similar to Haskell's Prelude.foldl1
function! s:foldl1(f, xs) abort
if len(a:xs) == 0
throw 'vital: Data.List: foldl1'
endif
return s:foldl(a:f, a:xs[0], a:xs[1:])
endfunction
" similar to Haskell's Prelude.foldr
function! s:foldr(f, init, xs) abort
return s:foldl(a:f, a:init, reverse(copy(a:xs)))
endfunction
" similar to Haskell's Prelude.fold11
function! s:foldr1(f, xs) abort
if len(a:xs) == 0
throw 'vital: Data.List: foldr1'
endif
return s:foldr(a:f, a:xs[-1], a:xs[0:-2])
endfunction
" similar to python's zip()
function! s:zip(...) abort
return map(range(min(map(copy(a:000), 'len(v:val)'))), "map(copy(a:000), 'v:val['.v:val.']')")
endfunction
" similar to zip(), but goes until the longer one.
function! s:zip_fill(xs, ys, filler) abort
if empty(a:xs) && empty(a:ys)
return []
elseif empty(a:ys)
return s:cons([a:xs[0], a:filler], s:zip_fill(a:xs[1 :], [], a:filler))
elseif empty(a:xs)
return s:cons([a:filler, a:ys[0]], s:zip_fill([], a:ys[1 :], a:filler))
else
return s:cons([a:xs[0], a:ys[0]], s:zip_fill(a:xs[1 :], a:ys[1: ], a:filler))
endif
endfunction
" Inspired by Ruby's with_index method.
function! s:with_index(list, ...) abort
let base = a:0 > 0 ? a:1 : 0
return map(copy(a:list), '[v:val, v:key + base]')
endfunction
" similar to Ruby's detect or Haskell's find.
function! s:find(list, default, f) abort
for x in a:list
if eval(substitute(a:f, 'v:val', string(x), 'g'))
return x
endif
endfor
return a:default
endfunction
" Returns the index of the first element which satisfies the given expr.
function! s:find_index(xs, f, ...) abort
let len = len(a:xs)
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
let default = a:0 > 1 ? a:2 : -1
if start >=# len || start < 0
return default
endif
for i in range(start, len - 1)
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
return i
endif
endfor
return default
endfunction
" Returns the index of the last element which satisfies the given expr.
function! s:find_last_index(xs, f, ...) abort
let len = len(a:xs)
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : len - 1
let default = a:0 > 1 ? a:2 : -1
if start >=# len || start < 0
return default
endif
for i in range(start, 0, -1)
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
return i
endif
endfor
return default
endfunction
" Similar to find_index but returns the list of indices satisfying the given expr.
function! s:find_indices(xs, f, ...) abort
let len = len(a:xs)
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
let result = []
if start >=# len || start < 0
return result
endif
for i in range(start, len - 1)
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
call add(result, i)
endif
endfor
return result
endfunction
" Return non-zero if a:list1 and a:list2 have any common item(s).
" Return zero otherwise.
function! s:has_common_items(list1, list2) abort
return !empty(filter(copy(a:list1), 'index(a:list2, v:val) isnot -1'))
endfunction
function! s:intersect(list1, list2) abort
let items = []
" for funcref
for X in a:list1
if index(a:list2, X) != -1 && index(items, X) == -1
let items += [X]
endif
endfor
return items
endfunction
" similar to Ruby's group_by.
function! s:group_by(xs, f) abort
let result = {}
let list = map(copy(a:xs), printf('[v:val, %s]', a:f))
for x in list
let Val = x[0]
let key = type(x[1]) !=# type('') ? string(x[1]) : x[1]
if has_key(result, key)
call add(result[key], Val)
else
let result[key] = [Val]
endif
unlet Val
endfor
return result
endfunction
function! s:_default_compare(a, b) abort
return a:a <# a:b ? -1 : a:a ># a:b ? 1 : 0
endfunction
function! s:binary_search(list, value, ...) abort
let Predicate = a:0 >= 1 ? a:1 : 's:_default_compare'
let dic = a:0 >= 2 ? a:2 : {}
let start = 0
let end = len(a:list) - 1
while 1
if start > end
return -1
endif
let middle = (start + end) / 2
let compared = call(Predicate, [a:value, a:list[middle]], dic)
if compared < 0
let end = middle - 1
elseif compared > 0
let start = middle + 1
else
return middle
endif
endwhile
endfunction
function! s:product(lists) abort
let result = [[]]
for pool in a:lists
let tmp = []
for x in result
let tmp += map(copy(pool), 'x + [v:val]')
endfor
let result = tmp
endfor
return result
endfunction
function! s:permutations(list, ...) abort
if a:0 > 1
throw 'vital: Data.List: too many arguments'
endif
let r = a:0 == 1 ? a:1 : len(a:list)
if r > len(a:list)
return []
elseif r < 0
throw 'vital: Data.List: {r} must be non-negative integer'
endif
let n = len(a:list)
let result = []
for indices in s:product(map(range(r), 'range(n)'))
if len(s:uniq(indices)) == r
call add(result, map(indices, 'a:list[v:val]'))
endif
endfor
return result
endfunction
function! s:combinations(list, r) abort
if a:r > len(a:list)
return []
elseif a:r < 0
throw 'vital: Data:List: {r} must be non-negative integer'
endif
let n = len(a:list)
let result = []
for indices in s:permutations(range(n), a:r)
if s:sort(copy(indices), 'a:a - a:b') == indices
call add(result, map(indices, 'a:list[v:val]'))
endif
endfor
return result
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:

View File

@@ -1,284 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Data#Set#import() abort
return map({'set': '', 'frozenset': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Data#Set#import() abort', printf("return map({'set': '', 'frozenset': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
let s:save_cpo = &cpo
set cpo&vim
let s:TRUE = !0
let s:FALSE = 0
function! s:set(...) abort
return call(s:set._new, a:000, s:set)
endfunction
function! s:frozenset(...) abort
return call(s:frozenset._new, a:000, s:frozenset)
endfunction
function! s:_hash_func(x) abort
return a:x
endfunction
let s:_base_set = {
\ '_is_set' : s:TRUE,
\ '_data' : {},
\ '_hash_func' : function('s:_hash_func')
\ }
function! s:_base_set._new(...) abort
let obj = deepcopy(self)
let xs = get(a:, 1, [])
let obj._hash_func = get(a:, 2, obj._hash_func)
call obj._set_data(xs)
return obj
endfunction
"" Return the union of two sets as a new set.
" (I.e. all elements that are in either set.)
function! s:_base_set.union(t) abort
let r = deepcopy(self)
call r._update(a:t)
return r
endfunction
let s:_base_set.or = s:_base_set.union
"" Return the intersection of two sets as a new set.
" (I.e. all elements that are in both sets.)
function! s:_base_set.intersection(t) abort
let t = self._to_set(a:t)
let [little, big] = self.len() <= t.len() ? [self, t] : [t, self]
return self._new(filter(copy(big.to_list()), 'little.in(v:val)'))
endfunction
let s:_base_set.and = s:_base_set.intersection
"" Return the symmetric difference of two sets as a new set.
" (I.e. all elements that are in exactly one of the sets.)
function! s:_base_set.symmetric_difference(t) abort
let t = self._to_set(a:t)
return self._new(filter(copy(self.to_list()), '!t.in(v:val)')
\ + filter(copy(t.to_list()), '!self.in(v:val)'))
endfunction
let s:_base_set.xor = s:_base_set.symmetric_difference
"" Return the difference of two sets as a new Set.
function! s:_base_set.difference(t) abort
let t = self._to_set(a:t)
return self._new(filter(copy(self.to_list()), '!t.in(v:val)'))
endfunction
let s:_base_set.sub = s:_base_set.difference
"" Report whether another set contains this set.
function! s:_base_set.issubset(t) abort
let t = self._to_set(a:t)
return self.len() > t.len() ? s:FALSE
\ : empty(filter(copy(self.to_list()), '!t.in(v:val)'))
endfunction
"" Report whether this set contains another set.
function! s:_base_set.issuperset(t) abort
let t = self._to_set(a:t)
return self.len() < t.len() ? s:FALSE
\ : empty(filter(copy(t.to_list()), '!self.in(v:val)'))
endfunction
" less than equal & greater than equal
let s:_base_set.le = s:_base_set.issubset
let s:_base_set.ge = s:_base_set.issuperset
" less than
function! s:_base_set.lt(t) abort
let t = self._to_set(a:t)
return self.len() < t.len() && self.issubset(t)
endfunction
" greater than
function! s:_base_set.gt(t) abort
let t = self._to_set(a:t)
return self.len() > t.len() && self.issuperset(t)
endfunction
function! s:_base_set.len() abort
return len(self._data)
endfunction
function! s:_base_set.to_list() abort
return values(self._data)
endfunction
function! s:_base_set._update(xs) abort
for X in (s:_is_set(a:xs) ? a:xs.to_list() : a:xs)
call self._add(X)
unlet X
endfor
endfunction
function! s:_base_set._add(x) abort
let key = self._hash(a:x)
if !has_key(self._data, key)
let self._data[key] = a:x
endif
endfunction
" Report whether an element is a member of a set.
function! s:_base_set.in(x) abort
return has_key(self._data, self._hash(a:x))
endfunction
function! s:_base_set._to_set(x) abort
return s:_is_set(a:x) ? a:x : self._new(a:x)
endfunction
function! s:_base_set._clear() abort
let self._data = {}
endfunction
function! s:_base_set._set_data(xs) abort
call self._clear()
call self._update(a:xs)
endfunction
function! s:_base_set._hash(x) abort
return string(self._hash_func(a:x))
endfunction
" frozenset: Immutable set class.
let s:frozenset = deepcopy(s:_base_set)
" Set: Mutable set class.
let s:set = deepcopy(s:_base_set)
" Update a set with the union of itself and another.
function! s:set.update(iterable) abort
call self._update(a:iterable)
endfunction
" Update a set with the union of itself and another.
function! s:set.ior(t) abort
call self.update(a:t)
return self
endfunction
" Update a set with the intersection of itself and another.
function! s:set.intersection_update(t) abort
let r = self.and(a:t).to_list()
call self.clear()
call self.update(r)
endfunction
" Update a set with the intersection of itself and another.
function! s:set.iand(t) abort
call self.intersection_update(a:t)
return self
endfunction
" Update a set with the symmetric difference of itself and another.
function! s:set.symmetric_difference_update(t) abort
let t = self._to_set(a:t)
if self is t
call self.clear()
return
endif
for X in t.to_list()
if self.in(X)
call self.remove(X)
else
call self._add(X)
endif
unlet X
endfor
endfunction
" Update a set with the symmetric difference of itself and another.
function! s:set.ixor(t) abort
call self.symmetric_difference_update(a:t)
return self
endfunction
" Remove all elements of another set from this set.
function! s:set.difference_update(t) abort
let t = self._to_set(a:t)
if self is t
call self.clear()
return
endif
for X in filter(t.to_list(), 'self.in(v:val)')
call self.remove(X)
unlet X
endfor
endfunction
" Remove all elements of another set from this set.
function! s:set.isub(t) abort
call self.difference_update(a:t)
return self
endfunction
" Remove all elements from this set.
function! s:set.clear() abort
call self._clear()
endfunction
"" Add an element to a set.
" This has no effect if the element is already present.
function! s:set.add(x) abort
return self._add(a:x)
endfunction
"" Remove an element from a set; it must be a member.
" If the element is not a member, throw Exception.
function! s:set.remove(e) abort
try
unlet self._data[self._hash(a:e)]
catch /^Vim\%((\a\+)\)\?:E716/
call s:_throw('the element is not a member')
endtry
endfunction
"" Remove an element from a set if it is a member.
" If the element is not a member, do nothing.
function! s:set.discard(e) abort
try
call self.remove(a:e)
catch /vital: Data.Set: the element is not a member/
" Do nothing
endtry
endfunction
" Remove and return an arbitrary set element.
function! s:set.pop() abort
try
let k = keys(self._data)[0]
catch /^Vim\%((\a\+)\)\?:E684/
call s:_throw('set is empty')
endtry
let v = self._data[k]
unlet self._data[k]
return v
endfunction
" Helper:
function! s:_is_set(x) abort
return type(a:x) is type({}) && get(a:x, '_is_set', s:FALSE)
endfunction
function! s:_throw(message) abort
throw 'vital: Data.Set: ' . a:message
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@@ -1,126 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#HitAHint#Hint#import() abort
return map({'create': '', '_vital_loaded': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#HitAHint#Hint#import() abort', printf("return map({'create': '', '_vital_loaded': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
" function() wrapper
if v:version > 703 || v:version == 703 && has('patch1170')
let s:_function = function('function')
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
let s:_s = '<SNR>' . s:_SID() . '_'
function! s:_function(fstr) abort
return function(substitute(a:fstr, 's:', s:_s, 'g'))
endfunction
endif
function! s:_assert(...) abort
return ''
endfunction
function! s:_vital_loaded(V) abort
if a:V.exists('Vim.PowerAssert')
let s:assert = a:V.import('Vim.PowerAssert').assert
else
let s:assert = s:_function('s:_assert')
endif
endfunction
" TERMS:
" key: A character to generate hint. e.g. a,b,c,d,e,f,...
" hint: A hint is a combination of keys. e.g. a,b,ab,abc,..
" s:create() assigns keys to each targets and generate hint dict.
" Example:
" let targets = [1, 2, 3, 4, 5, 6]
" echo s:label(targets, ['a', 'b', 'c'])
" " => {
" 'a': 1,
" 'b': {
" 'a': 2,
" 'b': 3
" },
" 'c': {
" 'a': 4,
" 'b': 5,
" 'c': 6
" }
" }
" Hint-to-target:
" a -> 1
" ba -> 2
" bb -> 3
" ca -> 4
" cb -> 5
" cc -> 6
" @param {list<T>} targets
" @param {list<string>} keys each key should be uniq
" @return Tree{string: (T|Tree)}
function! s:create(targets, keys) abort
exe s:assert('len(a:keys) > 1')
let groups = {}
let keys_count = reverse(s:_keys_count(len(a:targets), len(a:keys)))
let target_idx = 0
let key_idx = 0
for key_count in keys_count
if key_count > 1
" We need to create a subgroup
" Recurse one level deeper
let sub_targets = a:targets[target_idx : target_idx + key_count - 1]
let groups[a:keys[key_idx]] = s:create(sub_targets, a:keys)
elseif key_count == 1
" Assign single target key_idx
let groups[a:keys[key_idx]] = a:targets[target_idx]
else
" No target
continue
endif
let key_idx += 1
let target_idx += key_count
endfor
return groups
endfunction
" s:_keys_count() generates list which represents how many targets to be
" assigned to the key.
" If the count > 1, use tree recursively.
" Example:
" echo s:_keys_count(5, 3)
" " => [3, 1, 1]
" echo s:_keys_count(8, 3)
" " => [3, 3, 2]
" @param {number} target_len
" @param {number} keys_len
function! s:_keys_count(targets_len, keys_len) abort
exe s:assert('a:keys_len > 1')
let _keys_count = repeat([0], a:keys_len)
let is_first_level = 1
let targets_left_cnt = a:targets_len
while targets_left_cnt > 0
let cnt_to_add = is_first_level ? 1 : a:keys_len - 1
for i in range(a:keys_len)
let _keys_count[i] += cnt_to_add
let targets_left_cnt -= cnt_to_add
if targets_left_cnt <= 0
let _keys_count[i] += targets_left_cnt
break
endif
endfor
let is_first_level = 0
endwhile
exe s:assert('len(_keys_count) is# a:keys_len')
return _keys_count
endfunction

View File

@@ -1,806 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#HitAHint#Motion#import() abort
return map({'deepextend': '', 'gather_poses': '', 'tab2spacelen': '', 'move_f': '', 'setline': '', '_vital_depends': '', 'wincall': '', 'move': '', 'move_to_winpos': '', 'pos2hint_to_line2col2hint': '', 'gather_visible_matched_poses': '', 'move_to_win': '', 'throw': '', 'has_patch': '', 'win2pos2hint_to_w2l2c2h': '', 'move_f2': '', 'new_overwin': '', 'create_win2pos2hint': '', 'pos2poskey': '', 'winnr2poses_to_list': '', 'poskey2pos': '', 'is_in_fold': '', '_vital_loaded': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#HitAHint#Motion#import() abort', printf("return map({'deepextend': '', 'gather_poses': '', 'tab2spacelen': '', 'move_f': '', 'setline': '', '_vital_depends': '', 'wincall': '', 'move': '', 'move_to_winpos': '', 'pos2hint_to_line2col2hint': '', 'gather_visible_matched_poses': '', 'move_to_win': '', 'throw': '', 'has_patch': '', 'win2pos2hint_to_w2l2c2h': '', 'move_f2': '', 'new_overwin': '', 'create_win2pos2hint': '', 'pos2poskey': '', 'winnr2poses_to_list': '', 'poskey2pos': '', 'is_in_fold': '', '_vital_loaded': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
function! s:_vital_loaded(V) abort
let s:Hint = a:V.import('HitAHint.Hint')
let s:PHighlight = a:V.import('Palette.Highlight')
let s:Buffer = a:V.import('Vim.Buffer')
let s:Prelude = a:V.import('Prelude')
let s:Set = a:V.import('Data.Set')
let s:Input = a:V.import('Over.Input')
endfunction
function! s:_vital_depends() abort
return [
\ 'HitAHint.Hint',
\ 'Palette.Highlight',
\ 'Vim.Buffer',
\ 'Prelude',
\ 'Data.Set',
\ 'Over.Input',
\ ]
endfunction
let s:TRUE = !0
let s:FALSE = 0
let s:DIRECTION = {'forward': 0, 'backward': 1}
" Check Vim version
function! s:has_patch(major, minor, patch) abort
let l:version = (a:major * 100 + a:minor)
return has('patch-' . a:major . '.' . a:minor . '.' . a:patch) ||
\ (v:version > l:version) ||
\ (v:version == l:version && 'patch' . a:patch)
endfunction
" matchadd('Conceal', {pattern}, {priority}, -1, {'conceal': {char}}}) can
" highlight pattern and conceal target correctly even if the target is keyword
" characters.
" - http://ftp.vim.org/vim/patches/7.4/7.4.792
" - https://groups.google.com/forum/#!searchin/vim_dev/matchadd$20conceal/vim_dev/8bKa98GhHdk/VOzIBhd1m8YJ
let s:can_preserve_syntax = s:has_patch(7, 4, 792)
" s:move() moves cursor over/across window with Hit-A-Hint feature like
" vim-easymotion
" @param {dict} config
function! s:move(pattern, ...) abort
let o = s:new_overwin(get(a:, 1, {}))
return o.pattern(a:pattern)
endfunction
function! s:move_f(...) abort
echo 'Target: '
let c = s:Input.getchar()
return s:move(c, get(a:, 1, {}))
endfunction
function! s:move_f2() abort
echo 'Target: '
let c = s:Input.getchar()
redraw
echo 'Target: ' . c
let c2 = s:Input.getchar()
return s:move(s:Prelude.escape_pattern(c . c2), get(a:, 1, {}))
endfunction
let s:overwin = {
\ 'config': {
\ 'keys': 'asdghklqwertyuiopzxcvbnmfj;',
\ 'use_upper': s:FALSE,
\ 'auto_land': s:TRUE,
\ 'highlight': {
\ 'shade': 'HitAHintShade',
\ 'target': 'HitAHintTarget',
\ 'cursor': 'HitAHintCursor',
\ },
\ 'jump_first_target_keys': [],
\ 'do_shade': s:TRUE,
\ }
\ }
function! s:_init_hl() abort
highlight default HitAHintShade ctermfg=242 guifg=#777777
highlight default HitAHintTarget ctermfg=81 guifg=#66D9EF
" Cursor highlight doesn't exist for some environment with some
" colorscheme ref:#275
" e.g.
" - :colorscheme default
" - :colorscheme hybrid
if hlexists('Cursor')
highlight default link HitAHintCursor Cursor
else
highlight default HitAHintCursor term=reverse cterm=reverse gui=reverse
endif
endfunction
call s:_init_hl()
augroup vital-hit-a-hint-motion-default-highlight
autocmd!
autocmd ColorScheme * call s:_init_hl()
augroup END
function! s:new_overwin(...) abort
let o = deepcopy(s:overwin)
call s:deepextend(o.config, get(a:, 1, {}))
return o
endfunction
function! s:overwin.pattern(pattern) abort
let winpos = self.select_winpos(self.gather_poses_overwin(a:pattern), self.config.keys)
if winpos is# -1
else
call s:move_to_winpos(winpos)
endif
endfunction
" @param {{winnr: [lnum, cnum]}}
function! s:move_to_winpos(winpos) abort
let [winnr_str, pos] = a:winpos
let winnr = str2nr(winnr_str)
let is_win_moved = !(winnr is# winnr())
if is_win_moved
if exists('#WinLeave')
silent doautocmd WinLeave
endif
call s:move_to_win(winnr)
else
normal! m`
endif
call cursor(pos)
if is_win_moved && exists('#WinEnter')
silent doautocmd WinEnter
endif
endfunction
function! s:overwin.select_winpos(winnr2poses, keys) abort
let wposes = s:winnr2poses_to_list(a:winnr2poses)
if self.config.auto_land && len(wposes) is# 1
return wposes[0]
endif
call self.set_options()
try
return self.choose_prompt(s:Hint.create(wposes, a:keys))
finally
call self.restore_options()
endtry
endfunction
function! s:overwin.set_options() abort
" s:move_to_win() takes long time if 'foldmethod' == 'syntax' or 'expr'
let self.save_foldmethod = {}
for winnr in range(1, winnr('$'))
let self.save_foldmethod[winnr] = getwinvar(winnr, '&foldmethod')
call setwinvar(winnr, '&foldmethod', 'manual')
endfor
endfunction
function! s:overwin.restore_options() abort
for winnr in range(1, winnr('$'))
call setwinvar(winnr, '&foldmethod', self.save_foldmethod[winnr])
endfor
endfunction
" s:wpos_to_hint() returns dict whose key is position with window and whose
" value is the hints.
" @param Tree{string: ((winnr, (number,number))|Tree)} hint_dict
" @return {{winnr: {string: list<char>}}} poskey to hint for each window
" e.g.
" {
" '1': {
" '00168:00004': ['b', 'c', 'b'],
" '00174:00001': ['b', 'c', 'a'],
" '00188:00004': ['b', 'b'],
" '00190:00001': ['b', 'a'],
" '00191:00016': ['a', 'c'],
" '00192:00004': ['a', 'b'],
" '00195:00035': ['a', 'a']
" },
" '3': {
" '00168:00004': ['c', 'c', 'c'],
" '00174:00001': ['c', 'c', 'b'],
" '00188:00004': ['c', 'c', 'a'],
" '00190:00001': ['c', 'b'],
" '00191:00016': ['c', 'a'],
" '00192:00004': ['b', 'c', 'c']
" }
" }
function! s:create_win2pos2hint(hint_dict) abort
return s:_create_win2pos2hint({}, a:hint_dict)
endfunction
function! s:_create_win2pos2hint(dict, hint_dict, ...) abort
let prefix = get(a:, 1, [])
for [hint, v] in items(a:hint_dict)
if type(v) is# type({})
call s:_create_win2pos2hint(a:dict, v, prefix + [hint])
else
let [winnr, pos] = v
let a:dict[winnr] = get(a:dict, winnr, {})
let a:dict[winnr][s:pos2poskey(pos)] = prefix + [hint]
endif
unlet v
endfor
return a:dict
endfunction
" s:pos2poskey() convertes pos to poskey to use pos as dictionary keys and
" sort pos correctly.
" @param {(number,number)} pos
" @return string
" e.g. [1, 1] -> '00001:00001'
function! s:pos2poskey(pos) abort
return join(map(copy(a:pos), "printf('%05d', v:val)"), ':')
endfunction
" s:poskey2pos() convertes poskey to pos.
" @param {string} poskey e.g. '00001:00001'
" @return {(number,number)}
" e.g. '00001:00001' -> [1, 1]
function! s:poskey2pos(poskey) abort
return map(split(a:poskey, ':'), 'str2nr(v:val)')
endfunction
function! s:overwin.choose_prompt(hint_dict) abort
if empty(a:hint_dict)
redraw
echo 'No target'
return -1
endif
let hinter = s:Hinter.new(a:hint_dict, self.config)
try
call hinter.before()
call hinter.show_hint()
redraw
echo 'Target key: '
let c = s:Input.getchar()
if self.config.use_upper
let c = toupper(c)
endif
catch
echo v:throwpoint . ':' . v:exception
return -1
finally
call hinter.after()
endtry
" Jump to first target if target key is in config.jump_first_target_keys.
if index(self.config.jump_first_target_keys, c) isnot# -1
let c = split(self.config.keys, '\zs')[0]
endif
if has_key(a:hint_dict, c)
let target = a:hint_dict[c]
return type(target) is# type({}) ? self.choose_prompt(target) : target
else
redraw
echo 'Invalid target: ' . c
return -1
endif
endfunction
" Hinter show hints accross window.
" save_lines: {{winnr: {lnum: string}}}
" w2l2c2h: winnr to lnum to col num to hints. col2hints is tuple because we
" need sorted col to hints pair.
" save_syntax: {{winnr: &syntax}}
" {{winnr: {lnum: list<(cnum, list<char>)>}}}
let s:Hinter = {
\ 'save_lines': {},
\ 'w2l2c2h': {},
\ 'winnrs': [],
\ 'save_syntax': {},
\ 'save_conceallevel': {},
\ 'save_concealcursor': {},
\ 'save_modified': {},
\ 'save_modifiable': {},
\ 'save_readonly': {},
\ 'save_undo': {},
\ 'highlight_ids': {},
\ }
function! s:Hinter.new(hint_dict, config) abort
let s = deepcopy(self)
let s.config = a:config
call s.init(a:hint_dict)
return s
endfunction
function! s:Hinter.init(hint_dict) abort
let win2pos2hint = s:create_win2pos2hint(a:hint_dict)
let self.winnrs = sort(map(keys(win2pos2hint), 'str2nr(v:val)'))
let self.win2pos2hint = win2pos2hint
let self.w2l2c2h = s:win2pos2hint_to_w2l2c2h(win2pos2hint)
let self.hl_target_ids = {}
for winnr in self.winnrs
let self.hl_target_ids[winnr] = []
endfor
call self._save_lines()
endfunction
function! s:Hinter.before() abort
let self.highlight_id_cursor = matchadd(self.config.highlight.cursor, '\%#', 101)
call self.save_options()
call self.disable_conceal_in_other_win()
endfunction
function! s:Hinter.after() abort
call matchdelete(self.highlight_id_cursor)
call self.restore_env()
call self.restore_conceal_in_other_win()
endfunction
function! s:Hinter._save_lines() abort
let nr = winnr()
try
for [winnr, pos2hint] in items(self.win2pos2hint)
call s:move_to_win(winnr)
let lnums = map(copy(keys(pos2hint)), 's:poskey2pos(v:val)[0]')
let self.save_lines[winnr] = get(self.save_lines, winnr, {})
for lnum in lnums
let self.save_lines[winnr][lnum] = getline(lnum)
endfor
endfor
finally
call s:move_to_win(nr)
endtry
endfunction
function! s:Hinter.restore_lines_for_win(winnr) abort
let lnum2line = self.save_lines[a:winnr]
for [lnum, line] in items(lnum2line)
call s:setline(lnum, line)
endfor
endfunction
function! s:Hinter.save_options() abort
for winnr in self.winnrs
let self.save_syntax[winnr] = getwinvar(winnr, '&syntax')
let self.save_conceallevel[winnr] = getwinvar(winnr, '&conceallevel')
let self.save_concealcursor[winnr] = getwinvar(winnr, '&concealcursor')
let self.save_modified[winnr] = getwinvar(winnr, '&modified')
let self.save_modifiable[winnr] = getwinvar(winnr, '&modifiable')
let self.save_readonly[winnr] = getwinvar(winnr, '&readonly')
endfor
endfunction
function! s:Hinter.restore_options() abort
for winnr in self.winnrs
call setwinvar(winnr, '&conceallevel', self.save_conceallevel[winnr])
call setwinvar(winnr, '&concealcursor', self.save_concealcursor[winnr])
call setwinvar(winnr, '&modified', self.save_modified[winnr])
call setwinvar(winnr, '&modifiable', self.save_modifiable[winnr])
call setwinvar(winnr, '&readonly', self.save_readonly[winnr])
endfor
endfunction
function! s:Hinter.modify_env_for_win(winnr) abort
let self.save_conceal = s:PHighlight.get('Conceal')
let self.save_undo[a:winnr] = s:undo_lock.save()
setlocal modifiable
setlocal noreadonly
if !s:can_preserve_syntax
ownsyntax overwin
endif
setlocal conceallevel=2
setlocal concealcursor=ncv
let self.highlight_ids[a:winnr] = get(self.highlight_ids, a:winnr, [])
if self.config.do_shade
if !s:can_preserve_syntax
syntax clear
endif
let self.highlight_ids[a:winnr] += [matchadd(self.config.highlight.shade, '\_.*', 100)]
endif
" XXX: other plugins specific handling
if getbufvar('%', 'indentLine_enabled', 0)
silent! syntax clear IndentLine
endif
endfunction
function! s:Hinter.restore_env() abort
call s:PHighlight.set('Conceal', self.save_conceal)
let nr = winnr()
try
for winnr in self.winnrs
call s:move_to_win(winnr)
call self.restore_lines_for_win(winnr)
call self.remove_hints(winnr)
if !s:can_preserve_syntax && self.config.do_shade
let &syntax = self.save_syntax[winnr]
endif
call self.save_undo[winnr].restore()
for id in self.highlight_ids[winnr]
call matchdelete(id)
endfor
" XXX: other plugins specific handling
if getbufvar('%', 'indentLine_enabled', 0) && exists(':IndentLinesEnable') is# 2
call setbufvar('%', 'indentLine_enabled', 0)
:IndentLinesEnable
endif
endfor
catch
call s:throw(v:throwpoint . ' ' . v:exception)
finally
call s:move_to_win(nr)
endtry
call self.restore_options()
endfunction
let s:undo_lock = {}
function! s:undo_lock.save() abort
let undo = deepcopy(self)
call undo._save()
return undo
endfunction
function! s:undo_lock._save() abort
if undotree().seq_last == 0
" if there are no undo history, disable undo feature by setting
" 'undolevels' to -1 and restore it.
let self.save_undolevels = &l:undolevels
let &l:undolevels = -1
elseif !s:Buffer.is_cmdwin()
" command line window doesn't support :wundo.
let self.undofile = tempname()
execute 'wundo!' self.undofile
else
let self.is_cmdwin = s:TRUE
endif
endfunction
function! s:undo_lock.restore() abort
if has_key(self, 'save_undolevels')
let &l:undolevels = self.save_undolevels
endif
if has_key(self, 'undofile') && filereadable(self.undofile)
silent execute 'rundo' self.undofile
call delete(self.undofile)
endif
if has_key(self, 'is_cmdwin')
" XXX: it breaks undo history. AFAIK, there are no way to save and restore
" undo history in commandline window.
call self.undobreak()
endif
endfunction
function! s:undo_lock.undobreak() abort
let old_undolevels = &l:undolevels
setlocal undolevels=-1
keepjumps call setline('.', getline('.'))
let &l:undolevels = old_undolevels
endfunction
function! s:Hinter.disable_conceal_in_other_win() abort
let allwinnrs = s:Set.set(range(1, winnr('$')))
let other_winnrs = allwinnrs.sub(self.winnrs).to_list()
for w in other_winnrs
if 'help' !=# getwinvar(w, '&buftype')
call setwinvar(w, 'overwin_save_conceallevel', getwinvar(w, '&conceallevel'))
call setwinvar(w, '&conceallevel', 0)
endif
endfor
endfunction
function! s:Hinter.restore_conceal_in_other_win() abort
let allwinnrs = s:Set.set(range(1, winnr('$')))
let other_winnrs = allwinnrs.sub(self.winnrs).to_list()
for w in other_winnrs
if 'help' !=# getwinvar(w, '&buftype')
call setwinvar(w, '&conceallevel', getwinvar(w, 'overwin_save_conceallevel'))
endif
endfor
endfunction
" ._pos2hint_to_line2col2hint() converts pos2hint to line2col2hint dict whose
" key is line number and whose value is list of tuple of col number to hint.
" line2col2hint is for show hint with replacing line by line.
" col should be sorted.
" @param {{string: list<char>}} pos2hint
" @return {number: [(number, list<char>)]}
function! s:Hinter._pos2hint_to_line2col2hint(pos2hint) abort
let line2col2hint = {}
let poskeys = sort(keys(a:pos2hint))
for poskey in poskeys
let [lnum, cnum] = s:poskey2pos(poskey)
let line2col2hint[lnum] = get(line2col2hint, lnum, [])
let line2col2hint[lnum] += [[cnum, a:pos2hint[poskey]]]
endfor
return line2col2hint
endfunction
function! s:Hinter.show_hint() abort
let nr = winnr()
try
for winnr in self.winnrs
call s:move_to_win(winnr)
call self._show_hint_for_win(winnr)
endfor
finally
call s:move_to_win(nr)
endtry
endfunction
function! s:Hinter._show_hint_for_win(winnr) abort
call self.modify_env_for_win(a:winnr)
let hints = []
for [lnum, col2hint] in items(self.w2l2c2h[a:winnr])
let hints += self._show_hint_for_line(a:winnr, lnum, col2hint)
endfor
" Restore syntax and show hints after replacing all lines for performance.
if !s:can_preserve_syntax && !self.config.do_shade
let &l:syntax = self.save_syntax[a:winnr]
endif
execute 'highlight! link Conceal' self.config.highlight.target
for [lnum, cnum, char] in hints
call self.show_hint_pos(lnum, cnum, char, a:winnr)
endfor
endfunction
function! s:Hinter._show_hint_for_line(winnr, lnum, col2hint) abort
let hints = [] " [lnum, cnum, char]
let line = self.save_lines[a:winnr][a:lnum]
let col_offset = 0
let prev_cnum = -1
let next_offset = 0
for [cnum, hint] in a:col2hint
let col_num = cnum + col_offset
let is_consecutive = cnum is# prev_cnum + 1
if !is_consecutive
let col_num += next_offset
endif
let save_next_offset = next_offset
let [line, offset, next_offset] = self._replace_line_for_hint(col_num, line, hint)
if is_consecutive
let col_offset += save_next_offset
endif
let col_offset += offset
let hints = [[a:lnum, col_num, hint[0]]] + hints
if len(hint) > 1
let hints = [[a:lnum, col_num + 1, hint[1]]] + hints
endif
let prev_cnum = cnum
endfor
call s:setline(a:lnum, line)
return hints
endfunction
" ._replace_line_for_hint() replaces line to show hints.
" - It appends space if the line is empty
" - It replaces <Tab> to space if the target character is <Tab>
" - It replaces next target character if it's <Tab> and len(hint) > 1
" Replacing line changes col number, so it returns offset of col number.
" As for replaceing next target character, the timing to calculate offset
" depends on the col number of next hint in the same line, so it returns
" `next_offset` instead of returning offset all at once.
" @return {(string, number, number)} (line, offset, next_offset)
function! s:Hinter._replace_line_for_hint(col_num, line, hint) abort
let line = a:line
let col_num = a:col_num
let do_replace_target = !(self.config.do_shade || s:can_preserve_syntax)
let target = matchstr(line, '\%' . col_num .'c.')
" Append one space for empty line or match at end of line
if target is# ''
let hintwidth = strdisplaywidth(join(a:hint[:1], ''))
let char = do_replace_target ? ' ' : '.'
let line .= repeat(char, hintwidth)
return [line, hintwidth, 0]
endif
let offset = 0
if target is# "\t"
let [line, offset] = self._replace_tab_target(col_num, line)
elseif strdisplaywidth(target) > 1
let line = self._replace_text_to_space(line, col_num, strdisplaywidth(target))
let offset = strdisplaywidth(target) - len(target)
else
if do_replace_target
" The priority of :syn-cchar is always under the priority of keywords.
" So, Hit-A-Hint replaces targets character with '.'.
let space = '.'
let line = substitute(line, '\%' . col_num . 'c.', space, '')
let offset = len(space) - len(target)
endif
endif
let next_offset = 0
if len(a:hint) > 1 && target isnot# "\t"
" pass [' '] as hint to stop recursion.
let [line, next_offset, _] = self._replace_line_for_hint(col_num + offset + 1, line, [' '])
endif
return [line, offset, next_offset]
endfunction
" @return {(line, offset)}
function! s:Hinter._replace_tab_target(col_num, line) abort
let space_len = s:tab2spacelen(a:line, a:col_num)
let line = self._replace_text_to_space(a:line, a:col_num, space_len)
return [line, space_len - 1]
endfunction
function! s:Hinter._replace_text_to_space(line, col_num, len) abort
let target = printf('\%%%dc.', a:col_num)
let line = substitute(a:line, target, repeat(' ', a:len), '')
return line
endfunction
function! s:Hinter.show_hint_pos(lnum, cnum, char, winnr) abort
let p = '\%'. a:lnum . 'l\%'. a:cnum . 'c.'
if s:can_preserve_syntax
let self.hl_target_ids[a:winnr] += [matchadd('Conceal', p, 101, -1, {'conceal': a:char})]
else
exec "syntax match HitAHintTarget '". p . "' contains=NONE containedin=.* conceal cchar=". a:char
endif
endfunction
function! s:Hinter.remove_hints(winnr) abort
if s:can_preserve_syntax
for id in self.hl_target_ids[a:winnr]
call matchdelete(id)
endfor
else
" Clear syntax defined by Hit-A-Hint motion before restoring syntax.
syntax clear HitAHintTarget
endif
endfunction
" @param {number} col_num col_num is 1 origin like col()
function! s:tab2spacelen(line, col_num) abort
let before_line = a:col_num > 2 ? a:line[: a:col_num - 2]
\ : a:col_num is# 2 ? a:line[0]
\ : ''
let vcol_num = 1
for c in split(before_line, '\zs')
let vcol_num += c is# "\t" ? s:_virtual_tab2spacelen(vcol_num) : len(c)
endfor
return s:_virtual_tab2spacelen(vcol_num)
endfunction
function! s:_virtual_tab2spacelen(col_num) abort
return &tabstop - ((a:col_num - 1) % &tabstop)
endfunction
function! s:win2pos2hint_to_w2l2c2h(win2pos2hint) abort
let w2l2c2h = {}
for [winnr, pos2hint] in items(a:win2pos2hint)
let w2l2c2h[winnr] = s:pos2hint_to_line2col2hint(pos2hint)
endfor
return w2l2c2h
endfunction
" s:pos2hint_to_line2col2hint() converts pos2hint to line2col2hint dict whose
" key is line number and whose value is list of tuple of col number to hint.
" line2col2hint is for show hint with replacing line by line.
" col should be sorted.
" @param {{string: list<char>}} pos2hint
" @return {number: [(number, list<char>)]}
function! s:pos2hint_to_line2col2hint(pos2hint) abort
let line2col2hint = {}
let poskeys = sort(keys(a:pos2hint))
for poskey in poskeys
let [lnum, cnum] = s:poskey2pos(poskey)
let line2col2hint[lnum] = get(line2col2hint, lnum, [])
let line2col2hint[lnum] += [[cnum, a:pos2hint[poskey]]]
endfor
return line2col2hint
endfunction
" @param {number} winnr
function! s:move_to_win(winnr) abort
if a:winnr !=# winnr()
execute 'noautocmd' a:winnr . 'wincmd w'
endif
endfunction
" @param {regex} pattern
" @return {{winnr: list<list<(number,number))>}}
function! s:overwin.gather_poses_overwin(pattern) abort
return s:wincall(function('s:gather_poses'), [a:pattern])
endfunction
" s:gather_poses() aggregates patterm matched positions in visible current
" window for both direction excluding poses in fold.
" @return {{list<list<(number,number))>}}
function! s:gather_poses(pattern) abort
let f = s:gather_visible_matched_poses(a:pattern, s:DIRECTION.forward, s:TRUE)
let b = s:gather_visible_matched_poses(a:pattern, s:DIRECTION.backward, s:FALSE)
return filter(f + b, '!s:is_in_fold(v:val[0])')
endfunction
" s:gather_visible_matched_poses() aggregates pattern matched positions in visible current
" window.
" @param {regex} pattern
" @param {enum<DIRECTION>} direction see s:DIRECTION
" @param {bool} allow_cursor_pos_match
" @return {list<list<(number,number)>>} positions
function! s:gather_visible_matched_poses(pattern, direction, allow_cursor_pos_match) abort
let stop_line = line(a:direction is# s:DIRECTION.forward ? 'w$' : 'w0')
let search_flag = (a:direction is# s:DIRECTION.forward ? '' : 'b')
let c_flag = a:allow_cursor_pos_match ? 'c' : ''
let view = winsaveview()
let poses = []
keepjumps let pos = searchpos(a:pattern, c_flag . search_flag, stop_line)
while pos != [0, 0]
let poses += [pos]
keepjumps let pos = searchpos(a:pattern, search_flag, stop_line)
endwhile
call winrestview(view)
return poses
endfunction
" @param {{winnr: list<list<(number,number))>}} winnr2poses
" @param {number?} first_winnr the top winnr poses in returned list
" @return {list<{list<(winnr, (number,number))}>}
function! s:winnr2poses_to_list(winnr2poses, ...) abort
let first_winnr = get(a:, 1, winnr())
let first_winnr_poses = []
let other_poses = []
for [winnr_str, poses] in items(a:winnr2poses)
let winnr = str2nr(winnr_str)
if winnr is# first_winnr
let first_winnr_poses = map(copy(poses), '[winnr, v:val]')
else
let other_poses += map(copy(poses), '[winnr, v:val]')
endif
endfor
return first_winnr_poses + other_poses
endfunction
" @param {number} lnum line number
function! s:is_in_fold(lnum) abort
return foldclosed(a:lnum) != -1
endfunction
" @param {funcref} func
" @param {arglist} list<S>
" @param {dict?} dict for :h call()
" @return {{winnr: <T>}}
function! s:wincall(func, arglist, ...) abort
let dict = get(a:, 1, {})
let r = {}
let start_winnr = winnr()
let r[start_winnr] = call(a:func, a:arglist, dict)
if s:Buffer.is_cmdwin()
return r
endif
noautocmd wincmd w
while winnr() isnot# start_winnr
let r[winnr()] = call(a:func, a:arglist, dict)
noautocmd wincmd w
endwhile
return r
endfunction
" deepextend (nest: 1)
function! s:deepextend(expr1, expr2) abort
let expr2 = copy(a:expr2)
for [k, V] in items(a:expr1)
if (type(V) is type({}) || type(V) is type([])) && has_key(expr2, k)
let a:expr1[k] = extend(a:expr1[k], expr2[k])
unlet expr2[k]
endif
unlet V
endfor
return extend(a:expr1, expr2)
endfunction
function! s:setline(lnum, text) abort
if getline(a:lnum) isnot# a:text
call setline(a:lnum, a:text)
endif
endfunction
function! s:throw(message) abort
throw 'vital: HitAHint.Motion: ' . a:message
endfunction

View File

@@ -1,606 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Over#Commandline#Base#import() abort
return map({'_vital_depends': '', 'make_plain': '', 'is_input_waiting': '', 'make': '', '_vital_loaded': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Over#Commandline#Base#import() abort', printf("return map({'_vital_depends': '', 'make_plain': '', 'is_input_waiting': '', 'make': '', '_vital_loaded': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! s:_vital_loaded(V)
let s:V = a:V
let s:String = s:V.import("Over.String")
let s:Signals = s:V.import("Over.Signals")
let s:Input = s:V.import("Over.Input")
let s:Keymapping = s:V.import("Over.Keymapping")
let s:Module = s:V.import("Over.Commandline.Modules")
let s:base.variables.modules = s:Signals.make()
function! s:base.variables.modules.get_slot(val)
return a:val.slot.module
endfunction
let s:Highlight = s:V.import("Palette.Highlight")
endfunction
function! s:_vital_depends()
return [
\ "Over.String",
\ "Over.Signals",
\ "Over.Input",
\ "Over.Keymapping",
\ "Over.Commandline.Modules",
\ "Palette.Highlight",
\ ]
endfunction
function! s:make(...)
let result = deepcopy(s:base)
call result.set_prompt(get(a:, 1, ":"))
call result.connect(result, "_")
return result
endfunction
function! s:make_plain()
return deepcopy(s:base)
endfunction
let s:base = {
\ "line" : {},
\ "variables" : {
\ "prompt" : "",
\ "char" : "",
\ "input" : "",
\ "tap_key" : "",
\ "exit" : 0,
\ "keymapping" : {},
\ "suffix" : "",
\ "is_setted" : 0,
\ },
\ "highlights" : {
\ "prompt" : "NONE",
\ "cursor" : "VitalOverCommandLineCursor",
\ "cursor_on" : "VitalOverCommandLineCursorOn",
\ "cursor_insert" : "VitalOverCommandLineOnCursor",
\ },
\}
if exists("s:Signals")
let s:base.variables.modules = s:Signals.make()
function! s:base.variables.modules.get_slot(val)
return a:val.slot.module
endfunction
endif
function! s:base.getline()
return self.line.str()
endfunction
function! s:base.setline(line)
return self.line.set(a:line)
endfunction
function! s:base.char()
return self.variables.char
endfunction
function! s:base.setchar(char, ...)
" 1 の場合は既に設定されていても上書きする
" 0 の場合は既に設定されていれば上書きしない
let overwrite = get(a:, 1, 1)
if overwrite || self.variables.is_setted == 0
let self.variables.input = a:char
let self.variables.is_setted = 1
endif
endfunction
function! s:base.getpos()
return self.line.pos()
endfunction
function! s:base.setpos(pos)
return self.line.set_pos(a:pos)
endfunction
function! s:base.tap_keyinput(key)
let self.variables.tap_key = a:key
endfunction
function! s:base.untap_keyinput(key)
if self.variables.tap_key == a:key
let self.variables.tap_key = ""
return 1
endif
endfunction
function! s:base.get_tap_key()
return self.variables.tap_key
endfunction
function! s:base.is_input(key, ...)
let prekey = get(a:, 1, "")
return self.get_tap_key() ==# prekey
\ && self.char() ==# a:key
" \ && self.char() == (prekey . a:key)
endfunction
function! s:base.input_key()
return self.variables.input_key
endfunction
function! s:base.set_prompt(prompt)
let self.variables.prompt = a:prompt
endfunction
function! s:base.get_prompt()
return self.variables.prompt
endfunction
function! s:base.set_suffix(str)
let self.variables.suffix = a:str
endfunction
function! s:base.get_suffix()
return self.variables.suffix
endfunction
function! s:base.insert(word, ...)
if a:0
call self.line.set(a:1)
endif
call self.line.input(a:word)
endfunction
function! s:base.forward()
return self.line.forward()
endfunction
function! s:base.backward()
return self.line.backward()
endfunction
function! s:base.backward_word(...)
let pat = get(a:, 1, '\k\+\s*\|.')
return matchstr(self.backward(), '\%(' . pat . '\)$')
endfunction
function! s:base.connect(module, ...)
if type(a:module) == type("")
return call(self.connect, [s:Module.make(a:module)] + a:000, self)
endif
if empty(a:module)
return
endif
let name = a:0 > 0 ? a:1 : a:module.name
let slot = self.variables.modules.find_first_by("get(v:val.slot, 'name', '') == " . string(name))
if empty(slot)
call self.variables.modules.connect({ "name" : name, "module" : a:module })
else
let slot.slot.module = a:module
endif
" let self.variables.modules[name] = a:module
endfunction
function! s:base.disconnect(name)
return self.variables.modules.disconnect_by(
\ "get(v:val.slot, 'name', '') == " . string(a:name)
\ )
" unlet self.variables.modules[a:name]
endfunction
function! s:base.get_module(name)
let slot = self.variables.modules.find_first_by("get(v:val.slot, 'name', '') == " . string(a:name))
return empty(slot) ? {} : slot.slot.module
endfunction
function! s:base.callevent(event)
call self.variables.modules.sort_by("has_key(v:val.slot.module, 'priority') ? v:val.slot.module.priority('" . a:event . "') : 0")
return self.variables.modules.call(a:event, [self])
" call map(filter(copy(self.variables.modules), "has_key(v:val, a:event)"), "v:val." . a:event . "(self)")
endfunction
function! s:base.cmap(lhs, rhs)
let self.variables.keymapping[a:lhs] = a:rhs
endfunction
function! s:base.cnoremap(lhs, rhs)
let key = s:Keymapping.as_key_config(a:rhs)
let key.noremap = 1
let self.variables.keymapping[a:lhs] = key
endfunction
function! s:base.cunmap(lhs)
unlet self.variables.keymapping[a:lhs]
endfunction
function! s:base.keymapping()
return self.__keymapping__()
endfunction
function! s:base.__keymapping__()
return {}
endfunction
function! s:base.execute(...)
let command = get(a:, 1, self.getline())
call self.__execute(command)
endfunction
function! s:base.draw()
call self.callevent("on_draw_pre")
call self.callevent("on_draw")
endfunction
function! s:base.exit(...)
let self.variables.exit = 1
let self.variables.exit_code = get(a:, 1, 0)
endfunction
function! s:base.enable_keymapping()
let self.variables.enable_keymapping = 1
endfunction
function! s:base.disable_keymapping()
let self.variables.enable_keymapping = 0
endfunction
function! s:base.is_enable_keymapping()
return self.variables.enable_keymapping
endfunction
" function! s:base.cancel()
" call self.exit(1)
" call self.__on_cancel()
" endfunction
function! s:base.exit_code()
return self.variables.exit_code
endfunction
function! s:base.hl_cursor_on()
if exists("self.variables.old_guicursor")
set guicursor&
let &guicursor = self.variables.old_guicursor
unlet self.variables.old_guicursor
endif
if exists("self.variables.old_t_ve")
let &t_ve = self.variables.old_t_ve
unlet self.variables.old_t_ve
endif
endfunction
function! s:base.hl_cursor_off()
if exists("self.variables.old_t_ve")
return
endif
let self.variables.old_guicursor = &guicursor
set guicursor=n:block-NONE
let self.variables.old_t_ve = &t_ve
set t_ve=
endfunction
function! s:base.start(...)
let exit_code = call(self.__main, a:000, self)
return exit_code
endfunction
function! s:base.__empty(...)
endfunction
function! s:base.get(...)
let Old_execute = self.execute
let self.execute = self.__empty
try
let exit_code = call(self.start, a:000, self)
if exit_code == 0
return self.getline()
endif
finally
let self.execute = Old_execute
endtry
return ""
endfunction
function! s:base.input_key_stack()
return self.variables.input_key_stack
endfunction
function! s:base.input_key_stack_string()
return join(self.variables.input_key_stack, "")
endfunction
function! s:base.set_input_key_stack(stack)
let self.variables.input_key_stack = a:stack
return self.variables.input_key_stack
endfunction
function! s:base.input_key_stack_pop()
return remove(self.input_key_stack(), 0)
endfunction
function! s:base.getchar(...)
if empty(self.input_key_stack())
return call(s:Input.getchar, a:000, s:Input)
endif
return self.input_key_stack_pop()
endfunction
function! s:base.__init_variables()
let self.variables.tap_key = ""
let self.variables.char = ""
let self.variables.input = ""
let self.variables.exit = 0
let self.variables.exit_code = 1
let self.variables.enable_keymapping = 1
let self.variables.input_key_stack = []
let self.line = deepcopy(s:String.make())
endfunction
function! s:_is_valid_highlight(name)
let highlight = s:Highlight.get(a:name)
if empty(highlight)
return 0
endif
if has("gui_running")
\ && (has_key(highlight, "guifg") || has_key(highlight, "guibg"))
return 1
elseif (has_key(highlight, "ctermfg") || has_key(highlight, "ctermbg"))
return 1
endif
return 0
endfunction
function! s:base.__init()
call self.__init_variables()
call self.hl_cursor_off()
if !hlexists(self.highlights.cursor)
if s:_is_valid_highlight("Cursor")
execute "highlight link " . self.highlights.cursor . " Cursor"
else
" Workaround by CUI Vim Cursor Highlight
" issues #92
" https://github.com/osyo-manga/vital-over/issues/92
execute "highlight " . self.highlights.cursor . " term=reverse cterm=reverse gui=reverse"
endif
endif
if !hlexists(self.highlights.cursor_on)
execute "highlight link " . self.highlights.cursor_on . " " . self.highlights.cursor
endif
if !hlexists(self.highlights.cursor_insert)
execute "highlight " . self.highlights.cursor_insert . " cterm=underline term=underline gui=underline"
endif
endfunction
function! s:base.__execute(command)
call self.callevent("on_execute_pre")
try
call self.__execute__(a:command)
catch
echohl ErrorMsg
echom matchstr(v:exception, 'Vim\((\w*)\)\?:\zs.*\ze')
echohl None
call self.callevent("on_execute_failed")
finally
call self.callevent("on_execute")
endtry
endfunction
function! s:base.__execute__(cmd)
execute a:cmd
endfunction
function! s:base.__input_char(char)
let char = a:char
let self.variables.input_key = char
let self.variables.char = char
call self.setchar(self.variables.char)
let self.variables.is_setted = 0
call self.callevent("on_char_pre")
call self.insert(self.variables.input)
call self.callevent("on_char")
endfunction
function! s:base.__input(input, ...)
if a:input == ""
return
endif
let self.variables.input_key = a:input
if a:0 == 0
let keymapping = self.__get_keymapping()
else
let keymapping = a:1
endif
if self.is_enable_keymapping()
let key = s:Keymapping.unmapping(keymapping, a:input)
else
let key = a:input
endif
if key == ""
return
endif
call self.set_input_key_stack(s:String.split_by_keys(key))
while !(empty(self.input_key_stack()) || self.is_exit())
call self.__input_char(self.input_key_stack_pop())
endwhile
endfunction
function! s:is_input_waiting(keymapping, input)
let num = len(filter(copy(a:keymapping), 'stridx(v:key, a:input) == 0'))
return num > 1 || (num == 1 && !has_key(a:keymapping, a:input))
endfunction
function! s:base.__inputting()
if !self.is_enable_keymapping()
return self.__input(s:Input.getchar())
endif
let input = s:Input.getchar()
let old_line = self.getline()
let old_pos = self.getpos()
let keymapping = self.__get_keymapping()
try
let t = reltime()
while s:is_input_waiting(keymapping, input)
\ && str2nr(reltimestr(reltime(t))) * 1000 < &timeoutlen
call self.setline(old_line)
call self.insert(input)
call self.setpos(old_pos)
call self.draw()
let input .= s:Input.getchar(0)
endwhile
finally
call self.setline(old_line)
call self.setpos(old_pos)
endtry
call self.__input(input, keymapping)
endfunction
function! s:base.__update()
" call self.callevent("on_update")
" if !getchar(1)
" continue
" endif
"
" call self.__input(s:getchar(0))
" call self.draw()
call self.callevent("on_update")
call self.__inputting()
" call self.__input(s:Input.getchar())
if self.is_exit()
return -1
endif
call self.draw()
endfunction
function! s:base.__main(...)
try
call self.__init()
call self.callevent("on_enter")
call self.__input(get(a:, 1, ""))
call self.draw()
while !self.is_exit()
try
if self.__update()
break
endif
catch
call self.callevent("on_exception")
endtry
endwhile
catch
echohl ErrorMsg | echom v:throwpoint . " " . v:exception | echohl None
let self.variables.exit_code = -1
finally
call self.__finish()
call self.callevent("on_leave")
endtry
return self.exit_code()
endfunction
function! s:base.__finish()
call self.hl_cursor_on()
endfunction
function! s:base.__is_exit()
return self.is_exit()
endfunction
function! s:base.is_exit()
return self.variables.exit
endfunction
function! s:base.__get_keymapping()
let result = {}
" for module in values(self.variables.modules)
for module in self.variables.modules.slots()
if has_key(module, "keymapping")
if module isnot self
call extend(result, module.keymapping(self))
endif
endif
endfor
return extend(extend(result, self.variables.keymapping), self.keymapping())
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@@ -1,42 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Over#Commandline#Modules#import() abort
return map({'get': '', 'make': '', '_vital_loaded': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Over#Commandline#Modules#import() abort', printf("return map({'get': '', 'make': '', '_vital_loaded': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! s:_vital_loaded(V)
let s:V = a:V
endfunction
function! s:get(name)
if exists("s:" . a:name)
return s:{a:name}
endif
let s:{a:name} = s:V.import('Over.Commandline.Modules.' . a:name)
return s:{a:name}
endfunction
function! s:make(name, ...)
let module = s:get(a:name)
return call(module.make, a:000, module)
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@@ -1,179 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Over#Commandline#Modules#BufferComplete#import() abort
return map({'make': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Over#Commandline#Modules#BufferComplete#import() abort', printf("return map({'make': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! s:_uniq(list)
let dict = {}
for _ in a:list
let dict[_] = 0
endfor
return keys(dict)
endfunction
let s:module = {
\ "name" : "BufferComplete",
\}
function! s:_buffer_complete()
return sort(s:_uniq(filter(split(join(getline(1, '$')), '\W'), '!empty(v:val)')), 1)
endfunction
function! s:_parse_line(line)
let keyword = matchstr(a:line, '\zs\w\+\ze$')
let pos = strchars(a:line) - strchars(keyword)
return [pos, keyword]
endfunction
function! s:_as_statusline(list, count)
if empty(a:list)
return
endif
let hl_none = "%#StatusLine#"
let hl_select = "%#StatusLineNC#"
let tail = " > "
let result = a:list[0]
let pos = 0
for i in range(1, len(a:list)-1)
if strdisplaywidth(result . " " . a:list[i]) > &columns - len(tail)
if a:count < i
break
else
let pos = -i
endif
let result = a:list[i]
else
let result .= (" " . a:list[i])
endif
if a:count == i
let pos = pos + i
endif
endfor
return join(map(split(result, " "), 'v:key == pos ? hl_select . v:val . hl_none : v:val'))
endfunction
function! s:module.get_complete_words()
return s:_buffer_complete()
endfunction
function! s:module.complete(cmdline)
call s:_finish()
let s:old_statusline = &statusline
let backward = a:cmdline.backward()
let [pos, keyword] = s:_parse_line(backward)
if !exists("s:complete")
let s:complete = self.get_complete_words()
endif
let s:complete_list = filter(copy(s:complete), 'v:val =~ ''^''.keyword')
if empty(s:complete_list)
return -1
endif
if pos == 0
let backward = ""
else
let backward = join(split(backward, '\zs')[ : pos-1 ], "")
endif
let s:line = backward . a:cmdline.forward()
let s:pos = pos
call a:cmdline.setline(s:line)
let s:count = 0
endfunction
function! s:_finish()
if exists("s:old_statusline")
let &statusline = s:old_statusline
unlet s:old_statusline
redrawstatus
endif
endfunction
function! s:module.on_char_pre(cmdline)
if a:cmdline.is_input("<Over>(buffer-complete)")
\ || a:cmdline.is_input("<Over>(buffer-complete-prev)")
if self.complete(a:cmdline) == -1
call s:_finish()
call a:cmdline.setchar('')
return
endif
if a:cmdline.is_input("<Over>(buffer-complete-prev)")
let s:count = len(s:complete_list) - 1
endif
call a:cmdline.setchar('')
call a:cmdline.tap_keyinput("Completion")
" elseif a:cmdline.is_input("\<Tab>", "Completion")
elseif a:cmdline.is_input("<Over>(buffer-complete)", "Completion")
\ || a:cmdline.is_input("\<Right>", "Completion")
call a:cmdline.setchar('')
let s:count += 1
if s:count >= len(s:complete_list)
let s:count = 0
endif
elseif a:cmdline.is_input("<Over>(buffer-complete-prev)", "Completion")
\ || a:cmdline.is_input("\<Left>", "Completion")
call a:cmdline.setchar('')
let s:count -= 1
if s:count < 0
let s:count = len(s:complete_list) - 1
endif
else
if a:cmdline.untap_keyinput("Completion")
call a:cmdline.callevent("on_char_pre")
endif
call s:_finish()
return
endif
call a:cmdline.setline(s:line)
call a:cmdline.insert(s:complete_list[s:count], s:pos)
if len(s:complete_list) > 1
let &statusline = s:_as_statusline(s:complete_list, s:count)
redrawstatus
endif
if len(s:complete_list) == 1
call a:cmdline.untap_keyinput("Completion")
endif
endfunction
function! s:module.on_draw_pre(...)
" redrawstatus
endfunction
function! s:module.on_leave(cmdline)
call s:_finish()
unlet! s:complete
endfunction
function! s:make()
return deepcopy(s:module)
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@@ -1,40 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Over#Commandline#Modules#Cancel#import() abort
return map({'make': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Over#Commandline#Modules#Cancel#import() abort', printf("return map({'make': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
let s:module = {
\ "name" : "Cancel"
\}
function! s:module.on_char_pre(cmdline)
if a:cmdline.is_input("\<Esc>")
\ || a:cmdline.is_input("\<C-c>")
" call a:cmdline.cancel()
call a:cmdline.exit(1)
call a:cmdline.setchar("")
endif
endfunction
function! s:make()
return deepcopy(s:module)
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@@ -1,58 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not mofidify the code nor insert new lines before '" ___vital___'
if v:version > 703 || v:version == 703 && has('patch1170')
function! vital#_easymotion#Over#Commandline#Modules#CursorMove#import() abort
return map({'make': ''}, 'function("s:" . v:key)')
endfunction
else
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_easymotion#Over#Commandline#Modules#CursorMove#import() abort', printf("return map({'make': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
endif
" ___vital___
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
let s:module = {
\ "name" : "CursorMove"
\}
function! s:module.on_char_pre(cmdline)
if a:cmdline.is_input("\<Right>")
call a:cmdline.line.next()
call a:cmdline.setchar('')
elseif a:cmdline.is_input("\<Left>")
call a:cmdline.line.prev()
call a:cmdline.setchar('')
elseif a:cmdline.is_input("\<C-b>")
\ || a:cmdline.is_input("\<Home>")
call a:cmdline.setline(0)
call a:cmdline.setchar('')
elseif a:cmdline.is_input("\<C-e>")
\ || a:cmdline.is_input("\<End>")
call a:cmdline.setline(a:cmdline.line.length())
call a:cmdline.setchar('')
elseif a:cmdline.is_input("\<C-Left>")
\ || a:cmdline.is_input("\<S-Left>")
call a:cmdline.setline(strridx(a:cmdline.backward()[:-2], ' ') + 1)
call a:cmdline.setchar('')
elseif a:cmdline.is_input("\<C-Right>")
\ || a:cmdline.is_input("\<S-Right>")
let p = stridx(a:cmdline.forward()[1:], ' ')
call a:cmdline.setline(p != -1 ? a:cmdline.line.pos() + p + 2 : a:cmdline.line.length())
call a:cmdline.setchar('')
endif
endfunction
function! s:make()
return deepcopy(s:module)
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

Some files were not shown because too many files have changed in this diff Show More