Add jedi
Fix error in powerline (ascii can't decode) Get vim plugins directly from git
This commit is contained in:
parent
dff73a7a8b
commit
8385ed00af
73 changed files with 7702 additions and 7360 deletions
2
.hgignore
Normal file
2
.hgignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
syntax: glob
|
||||||
|
*.pyc
|
5
common/.config/ipython/profile_default/ipython_config.py
Normal file
5
common/.config/ipython/profile_default/ipython_config.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
c = get_config()
|
||||||
|
|
||||||
|
c.InteractiveShellApp.extensions = [
|
||||||
|
'powerline.bindings.ipython.post_0_11'
|
||||||
|
]
|
|
@ -24,10 +24,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shell": {
|
"shell": {
|
||||||
"colorscheme": "default",
|
|
||||||
"theme": "default"
|
|
||||||
},
|
|
||||||
"tmux": {
|
|
||||||
"colorscheme": "default",
|
"colorscheme": "default",
|
||||||
"theme": "default",
|
"theme": "default",
|
||||||
"segments" : {
|
"segments" : {
|
||||||
|
@ -37,6 +33,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tmux": {
|
||||||
|
"colorscheme": "default",
|
||||||
|
"theme": "default"
|
||||||
|
},
|
||||||
"vim": {
|
"vim": {
|
||||||
"colorscheme": "default",
|
"colorscheme": "default",
|
||||||
"theme": "default",
|
"theme": "default",
|
||||||
|
|
325
common/.local/bin/powerline-zsh.py
Executable file
325
common/.local/bin/powerline-zsh.py
Executable file
|
@ -0,0 +1,325 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def warn(msg):
|
||||||
|
print '[powerline-zsh] ', msg
|
||||||
|
|
||||||
|
|
||||||
|
class Color:
|
||||||
|
# The following link is a pretty good resources for color values:
|
||||||
|
# http://www.calmar.ws/vim/color-output.png
|
||||||
|
|
||||||
|
PATH_BG = 237 # dark grey
|
||||||
|
PATH_FG = 250 # light grey
|
||||||
|
CWD_FG = 254 # nearly-white grey
|
||||||
|
SEPARATOR_FG = 244
|
||||||
|
|
||||||
|
REPO_CLEAN_BG = 148 # a light green color
|
||||||
|
REPO_CLEAN_FG = 0 # black
|
||||||
|
REPO_DIRTY_BG = 161 # pink/red
|
||||||
|
REPO_DIRTY_FG = 15 # white
|
||||||
|
|
||||||
|
CMD_PASSED_BG = 236
|
||||||
|
CMD_PASSED_FG = 15
|
||||||
|
CMD_FAILED_BG = 161
|
||||||
|
CMD_FAILED_FG = 15
|
||||||
|
|
||||||
|
SVN_CHANGES_BG = 148
|
||||||
|
SVN_CHANGES_FG = 22 # dark green
|
||||||
|
|
||||||
|
VIRTUAL_ENV_BG = 35 # a mid-tone green
|
||||||
|
VIRTUAL_ENV_FG = 22
|
||||||
|
|
||||||
|
|
||||||
|
class Powerline:
|
||||||
|
symbols = {
|
||||||
|
'compatible': {
|
||||||
|
'separator': u'\u25B6',
|
||||||
|
'separator_thin': u'\u276F'
|
||||||
|
},
|
||||||
|
'patched': {
|
||||||
|
'separator': u'\u2B80',
|
||||||
|
'separator_thin': u'\u2B81'
|
||||||
|
},
|
||||||
|
'default': {
|
||||||
|
'separator': '⮀',
|
||||||
|
'separator_thin': '⮁'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LSQESCRSQ = '\\[\\e%s\\]'
|
||||||
|
reset = ' %f%k'
|
||||||
|
|
||||||
|
def __init__(self, mode='default'):
|
||||||
|
self.separator = Powerline.symbols[mode]['separator']
|
||||||
|
self.separator_thin = Powerline.symbols[mode]['separator_thin']
|
||||||
|
self.segments = []
|
||||||
|
|
||||||
|
def color(self, prefix, code):
|
||||||
|
if prefix == '38':
|
||||||
|
return '%%F{%s}' % code
|
||||||
|
elif prefix == '48':
|
||||||
|
return '%%K{%s}' % code
|
||||||
|
|
||||||
|
def fgcolor(self, code):
|
||||||
|
return self.color('38', code)
|
||||||
|
|
||||||
|
def bgcolor(self, code):
|
||||||
|
return self.color('48', code)
|
||||||
|
|
||||||
|
def append(self, segment):
|
||||||
|
self.segments.append(segment)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
return (''.join((s[0].draw(self, s[1]) for s in zip(self.segments, self.segments[1:] + [None])))
|
||||||
|
+ self.reset)
|
||||||
|
|
||||||
|
|
||||||
|
class Segment:
|
||||||
|
def __init__(self, powerline, content, fg, bg, separator=None, separator_fg=None):
|
||||||
|
self.powerline = powerline
|
||||||
|
self.content = content
|
||||||
|
self.fg = fg
|
||||||
|
self.bg = bg
|
||||||
|
self.separator = separator or powerline.separator
|
||||||
|
self.separator_fg = separator_fg or bg
|
||||||
|
|
||||||
|
def draw(self, powerline, next_segment=None):
|
||||||
|
if next_segment:
|
||||||
|
separator_bg = powerline.bgcolor(next_segment.bg)
|
||||||
|
else:
|
||||||
|
separator_bg = powerline.reset
|
||||||
|
|
||||||
|
return ''.join((
|
||||||
|
powerline.fgcolor(self.fg),
|
||||||
|
powerline.bgcolor(self.bg),
|
||||||
|
self.content,
|
||||||
|
separator_bg,
|
||||||
|
powerline.fgcolor(self.separator_fg),
|
||||||
|
self.separator))
|
||||||
|
|
||||||
|
|
||||||
|
def add_cwd_segment(powerline, cwd, maxdepth, cwd_only=False):
|
||||||
|
#powerline.append(' \\w ', 15, 237)
|
||||||
|
home = os.getenv('HOME')
|
||||||
|
cwd = os.getenv('PWD')
|
||||||
|
|
||||||
|
if cwd.find(home) == 0:
|
||||||
|
cwd = cwd.replace(home, '~', 1)
|
||||||
|
|
||||||
|
if cwd[0] == '/':
|
||||||
|
cwd = cwd[1:]
|
||||||
|
|
||||||
|
names = cwd.split('/')
|
||||||
|
if len(names) > maxdepth:
|
||||||
|
names = names[:2] + ['⋯ '] + names[2 - maxdepth:]
|
||||||
|
|
||||||
|
if not cwd_only:
|
||||||
|
for n in names[:-1]:
|
||||||
|
powerline.append(Segment(powerline, ' %s ' % n, Color.PATH_FG, Color.PATH_BG, powerline.separator_thin, Color.SEPARATOR_FG))
|
||||||
|
powerline.append(Segment(powerline, ' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG))
|
||||||
|
|
||||||
|
|
||||||
|
def get_hg_status():
|
||||||
|
has_modified_files = False
|
||||||
|
has_untracked_files = False
|
||||||
|
has_missing_files = False
|
||||||
|
output = subprocess.Popen(['hg', 'status'], stdout=subprocess.PIPE).communicate()[0]
|
||||||
|
for line in output.split('\n'):
|
||||||
|
if line == '':
|
||||||
|
continue
|
||||||
|
elif line[0] == '?':
|
||||||
|
has_untracked_files = True
|
||||||
|
elif line[0] == '!':
|
||||||
|
has_missing_files = True
|
||||||
|
else:
|
||||||
|
has_modified_files = True
|
||||||
|
return has_modified_files, has_untracked_files, has_missing_files
|
||||||
|
|
||||||
|
|
||||||
|
def add_hg_segment(powerline, cwd):
|
||||||
|
branch = os.popen('hg branch 2> /dev/null').read().rstrip()
|
||||||
|
if len(branch) == 0:
|
||||||
|
return False
|
||||||
|
bg = Color.REPO_CLEAN_BG
|
||||||
|
fg = Color.REPO_CLEAN_FG
|
||||||
|
has_modified_files, has_untracked_files, has_missing_files = get_hg_status()
|
||||||
|
if has_modified_files or has_untracked_files or has_missing_files:
|
||||||
|
bg = Color.REPO_DIRTY_BG
|
||||||
|
fg = Color.REPO_DIRTY_FG
|
||||||
|
extra = ''
|
||||||
|
if has_untracked_files:
|
||||||
|
extra += '+'
|
||||||
|
if has_missing_files:
|
||||||
|
extra += '!'
|
||||||
|
branch += (' ' + extra if extra != '' else '')
|
||||||
|
powerline.append(Segment(powerline, ' %s ' % branch, fg, bg))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_git_status():
|
||||||
|
has_pending_commits = True
|
||||||
|
has_untracked_files = False
|
||||||
|
detached_head = False
|
||||||
|
origin_position = ""
|
||||||
|
current_branch = ''
|
||||||
|
output = subprocess.Popen(['git', 'status', '-unormal'], stdout=subprocess.PIPE).communicate()[0]
|
||||||
|
for line in output.split('\n'):
|
||||||
|
origin_status = re.findall("Your branch is (ahead|behind).*?(\d+) comm", line)
|
||||||
|
if len(origin_status) > 0:
|
||||||
|
origin_position = " %d" % int(origin_status[0][1])
|
||||||
|
if origin_status[0][0] == 'behind':
|
||||||
|
origin_position += '⇣'
|
||||||
|
if origin_status[0][0] == 'ahead':
|
||||||
|
origin_position += '⇡'
|
||||||
|
|
||||||
|
if line.find('nothing to commit (working directory clean)') >= 0:
|
||||||
|
has_pending_commits = False
|
||||||
|
if line.find('Untracked files') >= 0:
|
||||||
|
has_untracked_files = True
|
||||||
|
if line.find('Not currently on any branch') >= 0:
|
||||||
|
detached_head = True
|
||||||
|
if line.find('On branch') >= 0:
|
||||||
|
current_branch = re.findall('On branch ([^ ]+)', line)[0]
|
||||||
|
return has_pending_commits, has_untracked_files, origin_position, detached_head, current_branch
|
||||||
|
|
||||||
|
|
||||||
|
def add_git_segment(powerline, cwd):
|
||||||
|
#cmd = "git branch 2> /dev/null | grep -e '\\*'"
|
||||||
|
p1 = subprocess.Popen(['git', 'branch'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
p2 = subprocess.Popen(['grep', '-e', '\\*'], stdin=p1.stdout, stdout=subprocess.PIPE)
|
||||||
|
output = p2.communicate()[0].strip()
|
||||||
|
if len(output) == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
|
has_pending_commits, has_untracked_files, origin_position, detached_head, current_branch = get_git_status()
|
||||||
|
|
||||||
|
if len(current_branch) > 0:
|
||||||
|
branch = current_branch
|
||||||
|
elif detached_head:
|
||||||
|
branch = subprocess.Popen(['git', 'describe', '--all', '--contains', '--abbrev=4', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
branch = '((' + branch.communicate()[0].strip() + '))'
|
||||||
|
else:
|
||||||
|
return 'master'
|
||||||
|
|
||||||
|
branch += origin_position
|
||||||
|
|
||||||
|
if has_untracked_files:
|
||||||
|
branch += ' +'
|
||||||
|
|
||||||
|
bg = Color.REPO_CLEAN_BG
|
||||||
|
fg = Color.REPO_CLEAN_FG
|
||||||
|
|
||||||
|
if has_pending_commits:
|
||||||
|
bg = Color.REPO_DIRTY_BG
|
||||||
|
fg = Color.REPO_DIRTY_FG
|
||||||
|
|
||||||
|
powerline.append(Segment(powerline, ' %s ' % branch, fg, bg))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def add_svn_segment(powerline, cwd):
|
||||||
|
if not os.path.exists(os.path.join(cwd, '.svn')):
|
||||||
|
return
|
||||||
|
'''svn info:
|
||||||
|
First column: Says if item was added, deleted, or otherwise changed
|
||||||
|
' ' no modifications
|
||||||
|
'A' Added
|
||||||
|
'C' Conflicted
|
||||||
|
'D' Deleted
|
||||||
|
'I' Ignored
|
||||||
|
'M' Modified
|
||||||
|
'R' Replaced
|
||||||
|
'X' an unversioned directory created by an externals definition
|
||||||
|
'?' item is not under version control
|
||||||
|
'!' item is missing (removed by non-svn command) or incomplete
|
||||||
|
'~' versioned item obstructed by some item of a different kind
|
||||||
|
'''
|
||||||
|
#TODO: Color segment based on above status codes
|
||||||
|
try:
|
||||||
|
#cmd = '"svn status | grep -c "^[ACDIMRX\\!\\~]"'
|
||||||
|
p1 = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
p2 = subprocess.Popen(['grep', '-c', '^[ACDIMRX\\!\\~]'], stdin=p1.stdout, stdout=subprocess.PIPE)
|
||||||
|
output = p2.communicate()[0].strip()
|
||||||
|
if len(output) > 0 and int(output) > 0:
|
||||||
|
changes = output.strip()
|
||||||
|
powerline.append(Segment(powerline, ' %s ' % changes, Color.SVN_CHANGES_FG, Color.SVN_CHANGES_BG))
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def add_repo_segment(powerline, cwd):
|
||||||
|
for add_repo_segment in [add_git_segment, add_svn_segment, add_hg_segment]:
|
||||||
|
try:
|
||||||
|
if add_repo_segment(p, cwd):
|
||||||
|
return
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
pass
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def add_virtual_env_segment(powerline, cwd):
|
||||||
|
env = os.getenv("VIRTUAL_ENV")
|
||||||
|
if env is None:
|
||||||
|
return False
|
||||||
|
env_name = os.path.basename(env)
|
||||||
|
bg = Color.VIRTUAL_ENV_BG
|
||||||
|
fg = Color.VIRTUAL_ENV_FG
|
||||||
|
powerline.append(Segment(powerline, ' %s ' % env_name, fg, bg))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def add_root_indicator(powerline, error):
|
||||||
|
bg = Color.CMD_PASSED_BG
|
||||||
|
fg = Color.CMD_PASSED_FG
|
||||||
|
if int(error) != 0:
|
||||||
|
fg = Color.CMD_FAILED_FG
|
||||||
|
bg = Color.CMD_FAILED_BG
|
||||||
|
powerline.append(Segment(powerline, ' $ ', fg, bg))
|
||||||
|
|
||||||
|
|
||||||
|
def get_valid_cwd():
|
||||||
|
try:
|
||||||
|
cwd = os.getcwd()
|
||||||
|
except:
|
||||||
|
cwd = os.getenv('PWD') # This is where the OS thinks we are
|
||||||
|
parts = cwd.split(os.sep)
|
||||||
|
up = cwd
|
||||||
|
while parts and not os.path.exists(up):
|
||||||
|
parts.pop()
|
||||||
|
up = os.sep.join(parts)
|
||||||
|
try:
|
||||||
|
os.chdir(up)
|
||||||
|
except:
|
||||||
|
warn("Your current directory is invalid.")
|
||||||
|
sys.exit(1)
|
||||||
|
warn("Your current directory is invalid. Lowest valid directory: " + up)
|
||||||
|
return cwd
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
arg_parser = argparse.ArgumentParser()
|
||||||
|
arg_parser.add_argument('--cwd-only', action="store_true")
|
||||||
|
arg_parser.add_argument('prev_error', nargs='?', default=0)
|
||||||
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
p = Powerline(mode='default')
|
||||||
|
cwd = get_valid_cwd()
|
||||||
|
add_virtual_env_segment(p, cwd)
|
||||||
|
#p.append(Segment(' \\u ', 250, 240))
|
||||||
|
#p.append(Segment(' \\h ', 250, 238))
|
||||||
|
add_cwd_segment(p, cwd, 5, args.cwd_only)
|
||||||
|
add_repo_segment(p, cwd)
|
||||||
|
add_root_indicator(p, args.prev_error)
|
||||||
|
sys.stdout.write(p.draw())
|
||||||
|
|
||||||
|
# vim: set expandtab:
|
|
@ -0,0 +1,282 @@
|
||||||
|
Metadata-Version: 1.1
|
||||||
|
Name: jedi
|
||||||
|
Version: 0.5b5
|
||||||
|
Summary: An autocompletion tool for Python that can be used for text editors.
|
||||||
|
Home-page: https://github.com/davidhalter/jedi
|
||||||
|
Author: David Halter
|
||||||
|
Author-email: davidhalter88@gmail.com
|
||||||
|
License: LGPLv3
|
||||||
|
Description: ########################################
|
||||||
|
Jedi - an awesome Python auto-completion
|
||||||
|
########################################
|
||||||
|
|
||||||
|
.. image:: https://secure.travis-ci.org/davidhalter/jedi.png?branch=master
|
||||||
|
:target: http://travis-ci.org/davidhalter/jedi
|
||||||
|
:alt: Travis-CI build status
|
||||||
|
|
||||||
|
**beta testing**
|
||||||
|
|
||||||
|
*If you have any comments or feature requests, please tell me! I really want to
|
||||||
|
know, what you think about Jedi.*
|
||||||
|
|
||||||
|
Jedi is an autocompletion tool for Python. It works. With and without syntax
|
||||||
|
errors. Sometimes it sucks, but that's normal in dynamic languages. But it
|
||||||
|
sucks less than other tools. It understands almost all of the basic Python
|
||||||
|
syntax elements including many builtins.
|
||||||
|
|
||||||
|
Jedi suports two different goto functions and has support for renaming.
|
||||||
|
Probably it will also have some support for refactoring in the future.
|
||||||
|
|
||||||
|
Jedi uses a very simple interface to connect with IDE's. As an reference, there
|
||||||
|
is a VIM implementation, which uses Jedi's autocompletion. However, I encourage
|
||||||
|
you to use Jedi in your IDEs. Start writing plugins! If there are problems with
|
||||||
|
licensing, just contact me.
|
||||||
|
|
||||||
|
At the moment Jedi can be used as a
|
||||||
|
`VIM-Plugin <http://github.com/davidhalter/jedi-vim>`_. So, if you want to test
|
||||||
|
Jedi for now, you'll have to use VIM. But there are new plugins emerging:
|
||||||
|
|
||||||
|
- `Emacs-Plugin <https://github.com/tkf/emacs-jedi>`_
|
||||||
|
- `Sublime-Plugin <https://github.com/svaiter/SublimeJEDI>`_ **Under construction**
|
||||||
|
|
||||||
|
Here are some pictures:
|
||||||
|
|
||||||
|
.. image:: https://github.com/davidhalter/jedi/raw/master/screenshot_complete.png
|
||||||
|
|
||||||
|
Completion for almost anything (Ctrl+Space).
|
||||||
|
|
||||||
|
.. image:: https://github.com/davidhalter/jedi/raw/master/screenshot_function.png
|
||||||
|
|
||||||
|
Display of function/class bodies, docstrings.
|
||||||
|
|
||||||
|
.. image:: https://github.com/davidhalter/jedi/raw/master/screenshot_pydoc.png
|
||||||
|
|
||||||
|
Pydoc support (with highlighting, Shift+k).
|
||||||
|
|
||||||
|
There is also support for goto and renaming.
|
||||||
|
|
||||||
|
Get the latest from `github <http://github.com/davidhalter/jedi>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
You can either include Jedi as a submodule in your text editor plugin (like
|
||||||
|
jedi-vim_ does it by default), or you
|
||||||
|
can install Jedi systemwide.
|
||||||
|
|
||||||
|
The preferred way to install the Jedi library into your system is by using
|
||||||
|
pip_::
|
||||||
|
|
||||||
|
sudo pip install jedi
|
||||||
|
|
||||||
|
If you want to install the current development version::
|
||||||
|
|
||||||
|
sudo pip install -e git://github.com/davidhalter/jedi.git#egg=jedi
|
||||||
|
|
||||||
|
Note: This just installs the Jedi library, not the editor plugins. For
|
||||||
|
information about how to make it work with your editor, refer to the
|
||||||
|
corresponding documentation.
|
||||||
|
|
||||||
|
|
||||||
|
Support
|
||||||
|
=======
|
||||||
|
|
||||||
|
Jedi supports Python 2.5 up to 3.x. There is just one code base, for both
|
||||||
|
Python 2 and 3.
|
||||||
|
Jedi supports many of the widely used Python features:
|
||||||
|
|
||||||
|
- builtin functions/classes support
|
||||||
|
- complex module / function / class structures
|
||||||
|
- ignores syntax and indentation errors
|
||||||
|
- multiple returns / yields
|
||||||
|
- tuple assignments / array indexing / dictionary indexing
|
||||||
|
- exceptions / with-statement
|
||||||
|
- \*args / \*\*kwargs
|
||||||
|
- decorators
|
||||||
|
- descriptors -> property / staticmethod / classmethod
|
||||||
|
- closures
|
||||||
|
- generators (yield statement) / iterators
|
||||||
|
- support for some magic methods: ``__call__``, ``__iter__``, ``__next__``,
|
||||||
|
``__get__``, ``__getitem__``, ``__init__``
|
||||||
|
- support for list.append, set.add, list.extend, etc.
|
||||||
|
- (nested) list comprehensions / ternary expressions
|
||||||
|
- relative imports
|
||||||
|
- ``getattr()`` / ``__getattr__`` / ``__getattribute__``
|
||||||
|
- function annotations (py3k feature, are ignored right now, but being parsed.
|
||||||
|
I don't know what to do with them.)
|
||||||
|
- class decorators (py3k feature, are being ignored too, until I find a use
|
||||||
|
case, that doesn't work with Jedi)
|
||||||
|
- simple/usual ``sys.path`` modifications
|
||||||
|
- ``isinstance`` checks for if/while/assert
|
||||||
|
- virtualenv support
|
||||||
|
- infer function arguments with sphinx (and other) docstrings
|
||||||
|
|
||||||
|
However, it does not yet support (and probably will in future versions, because
|
||||||
|
they are on my todo list):
|
||||||
|
|
||||||
|
- manipulations of instances outside the instance variables, without using
|
||||||
|
functions
|
||||||
|
|
||||||
|
It does not support (and most probably will not in future versions):
|
||||||
|
|
||||||
|
- metaclasses (how could an auto-completion ever support this)
|
||||||
|
- ``setattr()``, ``__import__()``
|
||||||
|
- Writing to some dicts: ``globals()``, ``locals()``, ``object.__dict__``
|
||||||
|
- evaluate ``if`` / ``while``
|
||||||
|
|
||||||
|
|
||||||
|
Caveats
|
||||||
|
=======
|
||||||
|
|
||||||
|
This framework should work for both Python 2/3. However, some things were just
|
||||||
|
not as *pythonic* in Python 2 as things should be. To keep things simple, some
|
||||||
|
things have been held back:
|
||||||
|
|
||||||
|
- Classes: Always Python 3 like, therefore all classes inherit from ``object``.
|
||||||
|
- Generators: No ``next`` method. The ``__next__`` method is used instead.
|
||||||
|
- Exceptions are only looked at in the form of ``Exception as e``, no comma!
|
||||||
|
|
||||||
|
Syntax errors and other strange stuff, that is defined differently in the
|
||||||
|
Python language, may lead to undefined behaviour of the completion. Jedi is
|
||||||
|
**NOT** a Python compiler, that tries to correct you. It is a tool that wants
|
||||||
|
to help you. But **YOU** have to know Python, not Jedi.
|
||||||
|
|
||||||
|
Importing ``numpy`` can be quite slow sometimes, as well as loading the builtins
|
||||||
|
the first time. If you want to speed it up, you could write import hooks in
|
||||||
|
jedi, which preloads this stuff. However, once loaded, this is not a problem
|
||||||
|
anymore. The same is true for huge modules like ``PySide``, ``wx``, etc.
|
||||||
|
|
||||||
|
Security is an important issue for Jedi. Therefore no Python code is executed.
|
||||||
|
As long as you write pure python, everything is evaluated statically. But: If
|
||||||
|
you use builtin modules (`c_builtin`) there is no other option than to execute
|
||||||
|
those modules. However: Execute isn't that critical (as e.g. in pythoncomplete,
|
||||||
|
which used to execute *every* import!), because it means one import and no
|
||||||
|
more. So basically the only dangerous thing is using the import itself. If your
|
||||||
|
`c_builtin` uses some strange initializations, it might be dangerous. But if it
|
||||||
|
does you're screwed anyways, because eventualy you're going to execute your
|
||||||
|
code, which executes the import.
|
||||||
|
|
||||||
|
|
||||||
|
A little history
|
||||||
|
================
|
||||||
|
|
||||||
|
The Star Wars Jedi are awesome. My Jedi software tries to imitate a little bit
|
||||||
|
of the precognition the Jedi have. There is even an awesome `scene
|
||||||
|
<http://www.youtube.com/watch?v=5BDO3pyavOY>`_ of Monty Python Jedi's :-).
|
||||||
|
|
||||||
|
But actually the name hasn't so much to do with Star Wars. It's part of my
|
||||||
|
second name.
|
||||||
|
|
||||||
|
After I explained Guido van Rossum, how some parts of my auto-completion work,
|
||||||
|
he said (we drank a beer or two):
|
||||||
|
|
||||||
|
*Oh, that worries me*
|
||||||
|
|
||||||
|
When it's finished, I hope he'll like it :-)
|
||||||
|
|
||||||
|
I actually started Jedi, because there were no good solutions available for
|
||||||
|
VIM. Most auto-completions just didn't work well. The only good solution was
|
||||||
|
PyCharm. I just like my good old VIM. Rope was never really intended to be an
|
||||||
|
auto-completion (and also I really hate project folders for my Python scripts).
|
||||||
|
It's more of a refactoring suite. So I decided to do my own version of a
|
||||||
|
completion, which would execute non-dangerous code. But I soon realized, that
|
||||||
|
this wouldn't work. So I built an extremely recursive thing which understands
|
||||||
|
many of Python's key features.
|
||||||
|
|
||||||
|
By the way, I really tried to program it as understandable as possible. But I
|
||||||
|
think understanding it might need quite some time, because of its recursive
|
||||||
|
nature.
|
||||||
|
|
||||||
|
|
||||||
|
API-Design for IDEs
|
||||||
|
===================
|
||||||
|
|
||||||
|
If you want to set up an IDE with Jedi, you need to ``import jedi``. You should
|
||||||
|
have the following objects available:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Script(source, line, column, source_path)
|
||||||
|
|
||||||
|
``source`` would be the source of your python file/script, separated by new
|
||||||
|
lines. ``line`` is the current line you want to perform actions on (starting
|
||||||
|
with line #1 as the first line). ``column`` represents the current
|
||||||
|
column/indent of the cursor (starting with zero). ``source_path`` should be the
|
||||||
|
path of your file in the file system.
|
||||||
|
|
||||||
|
It returns a script object that contains the relevant information for the other
|
||||||
|
functions to work without params.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Script().complete
|
||||||
|
|
||||||
|
Returns ``api.Completion`` objects. Those objects have got
|
||||||
|
informations about the completions. More than just names.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Script().goto
|
||||||
|
|
||||||
|
Similar to complete. The returned ``api.Definition`` objects contain
|
||||||
|
information about the definitions found.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Script().get_definition
|
||||||
|
|
||||||
|
Mostly used for tests. Like goto, but follows statements and imports and
|
||||||
|
doesn't break there. You probably don't want to use this function. It's
|
||||||
|
mostly for testing.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Script().related_names
|
||||||
|
|
||||||
|
Returns all names that point to the definition of the name under the
|
||||||
|
cursor. This is also very useful for refactoring (renaming).
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Script().get_in_function_call
|
||||||
|
|
||||||
|
Get the ``Function`` object of the call you're currently in, e.g.: ``abs(``
|
||||||
|
with the cursor at the end would return the builtin ``abs`` function.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
NotFoundError
|
||||||
|
|
||||||
|
If you use the goto function and no valid identifier (name) is at the
|
||||||
|
place of the cursor (position). It will raise this exception.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
set_debug_function
|
||||||
|
|
||||||
|
Sets a callback function for ``debug.py``. This function is called with
|
||||||
|
multiple text objects, in python 3 you could insert ``print``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
settings
|
||||||
|
|
||||||
|
Access to the ``settings.py`` module. The settings are described there.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. _jedi-vim: http://github.com/davidhalter/jedi-vim
|
||||||
|
.. _pip: http://www.pip-installer.org/
|
||||||
|
|
||||||
|
Keywords: python completion refactoring vim
|
||||||
|
Platform: any
|
||||||
|
Classifier: Development Status :: 4 - Beta
|
||||||
|
Classifier: Environment :: Plugins
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||||
|
Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE)
|
||||||
|
Classifier: Topic :: Utilities
|
|
@ -0,0 +1,31 @@
|
||||||
|
AUTHORS.txt
|
||||||
|
LICENSE.txt
|
||||||
|
MANIFEST.in
|
||||||
|
README.rst
|
||||||
|
setup.cfg
|
||||||
|
setup.py
|
||||||
|
jedi/__init__.py
|
||||||
|
jedi/_compatibility.py
|
||||||
|
jedi/api.py
|
||||||
|
jedi/api_classes.py
|
||||||
|
jedi/builtin.py
|
||||||
|
jedi/debug.py
|
||||||
|
jedi/docstrings.py
|
||||||
|
jedi/dynamic.py
|
||||||
|
jedi/evaluate.py
|
||||||
|
jedi/helpers.py
|
||||||
|
jedi/imports.py
|
||||||
|
jedi/keywords.py
|
||||||
|
jedi/modules.py
|
||||||
|
jedi/parsing.py
|
||||||
|
jedi/settings.py
|
||||||
|
jedi.egg-info/PKG-INFO
|
||||||
|
jedi.egg-info/SOURCES.txt
|
||||||
|
jedi.egg-info/dependency_links.txt
|
||||||
|
jedi.egg-info/top_level.txt
|
||||||
|
jedi/mixin/_functools.pym
|
||||||
|
jedi/mixin/_sre.pym
|
||||||
|
jedi/mixin/_weakref.pym
|
||||||
|
jedi/mixin/builtins.pym
|
||||||
|
jedi/mixin/datetime.pym
|
||||||
|
jedi/mixin/posix.pym
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
../jedi/builtin.py
|
||||||
|
../jedi/evaluate.py
|
||||||
|
../jedi/debug.py
|
||||||
|
../jedi/helpers.py
|
||||||
|
../jedi/settings.py
|
||||||
|
../jedi/keywords.py
|
||||||
|
../jedi/api_classes.py
|
||||||
|
../jedi/api.py
|
||||||
|
../jedi/modules.py
|
||||||
|
../jedi/__init__.py
|
||||||
|
../jedi/parsing.py
|
||||||
|
../jedi/docstrings.py
|
||||||
|
../jedi/_compatibility.py
|
||||||
|
../jedi/imports.py
|
||||||
|
../jedi/dynamic.py
|
||||||
|
../jedi/mixin/builtins.pym
|
||||||
|
../jedi/mixin/posix.pym
|
||||||
|
../jedi/mixin/_functools.pym
|
||||||
|
../jedi/mixin/_weakref.pym
|
||||||
|
../jedi/mixin/_sre.pym
|
||||||
|
../jedi/mixin/datetime.pym
|
||||||
|
../jedi/builtin.pyc
|
||||||
|
../jedi/evaluate.pyc
|
||||||
|
../jedi/debug.pyc
|
||||||
|
../jedi/helpers.pyc
|
||||||
|
../jedi/settings.pyc
|
||||||
|
../jedi/keywords.pyc
|
||||||
|
../jedi/api_classes.pyc
|
||||||
|
../jedi/api.pyc
|
||||||
|
../jedi/modules.pyc
|
||||||
|
../jedi/__init__.pyc
|
||||||
|
../jedi/parsing.pyc
|
||||||
|
../jedi/docstrings.pyc
|
||||||
|
../jedi/_compatibility.pyc
|
||||||
|
../jedi/imports.pyc
|
||||||
|
../jedi/dynamic.pyc
|
||||||
|
./
|
||||||
|
SOURCES.txt
|
||||||
|
PKG-INFO
|
||||||
|
dependency_links.txt
|
||||||
|
top_level.txt
|
|
@ -0,0 +1 @@
|
||||||
|
jedi
|
16
common/.local/lib/python2.7/site-packages/jedi/__init__.py
Normal file
16
common/.local/lib/python2.7/site-packages/jedi/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# python imports are hell sometimes. Especially the combination of relative
|
||||||
|
# imports and circular imports... Just avoid it:
|
||||||
|
sys.path.insert(0, __path__[0])
|
||||||
|
|
||||||
|
from .api import Script, NotFoundError, set_debug_function
|
||||||
|
from . import settings
|
||||||
|
|
||||||
|
from . import api
|
||||||
|
|
||||||
|
__doc__ = api.__doc__
|
||||||
|
|
||||||
|
del api
|
||||||
|
|
||||||
|
sys.path.pop(0)
|
169
common/.local/lib/python2.7/site-packages/jedi/_compatibility.py
Normal file
169
common/.local/lib/python2.7/site-packages/jedi/_compatibility.py
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
"""
|
||||||
|
This is a compatibility module, to make it possible to use jedi also with older
|
||||||
|
python versions.
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
is_py3k = sys.hexversion >= 0x03000000
|
||||||
|
|
||||||
|
is_py25 = sys.hexversion < 0x02060000
|
||||||
|
|
||||||
|
# next was defined in python 2.6, in python 3 obj.next won't be possible
|
||||||
|
# anymore
|
||||||
|
try:
|
||||||
|
next = next
|
||||||
|
except NameError:
|
||||||
|
_raiseStopIteration = object()
|
||||||
|
|
||||||
|
def next(iterator, default=_raiseStopIteration):
|
||||||
|
if not hasattr(iterator, 'next'):
|
||||||
|
raise TypeError("not an iterator")
|
||||||
|
try:
|
||||||
|
return iterator.next()
|
||||||
|
except StopIteration:
|
||||||
|
if default is _raiseStopIteration:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
|
# ast module was defined in python 2.6
|
||||||
|
try:
|
||||||
|
from ast import literal_eval
|
||||||
|
except ImportError:
|
||||||
|
literal_eval = eval
|
||||||
|
|
||||||
|
|
||||||
|
# properties in 2.5
|
||||||
|
try:
|
||||||
|
property.setter
|
||||||
|
except AttributeError:
|
||||||
|
class property(property):
|
||||||
|
def __init__(self, fget, *args, **kwargs):
|
||||||
|
self.__doc__ = fget.__doc__
|
||||||
|
super(property, self).__init__(fget, *args, **kwargs)
|
||||||
|
|
||||||
|
def setter(self, fset):
|
||||||
|
cls_ns = sys._getframe(1).f_locals
|
||||||
|
for k, v in cls_ns.iteritems():
|
||||||
|
if v == self:
|
||||||
|
propname = k
|
||||||
|
break
|
||||||
|
cls_ns[propname] = property(self.fget, fset,
|
||||||
|
self.fdel, self.__doc__)
|
||||||
|
return cls_ns[propname]
|
||||||
|
else:
|
||||||
|
property = property
|
||||||
|
|
||||||
|
# unicode function
|
||||||
|
try:
|
||||||
|
unicode = unicode
|
||||||
|
except NameError:
|
||||||
|
unicode = str
|
||||||
|
|
||||||
|
if is_py3k:
|
||||||
|
utf8 = lambda s: s
|
||||||
|
else:
|
||||||
|
utf8 = lambda s: s.decode('utf-8')
|
||||||
|
|
||||||
|
utf8.__doc__ = """
|
||||||
|
Decode a raw string into unicode object. Do nothing in Python 3.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# exec function
|
||||||
|
if is_py3k:
|
||||||
|
def exec_function(source, global_map):
|
||||||
|
exec(source, global_map)
|
||||||
|
else:
|
||||||
|
eval(compile("""def exec_function(source, global_map):
|
||||||
|
exec source in global_map """, 'blub', 'exec'))
|
||||||
|
|
||||||
|
# StringIO (Python 2.5 has no io module), so use io only for py3k
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
# hasattr function used because python
|
||||||
|
if is_py3k:
|
||||||
|
hasattr = hasattr
|
||||||
|
else:
|
||||||
|
def hasattr(obj, name):
|
||||||
|
try:
|
||||||
|
getattr(obj, name)
|
||||||
|
return True
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class Python3Method(object):
|
||||||
|
def __init__(self, func):
|
||||||
|
self.func = func
|
||||||
|
|
||||||
|
def __get__(self, obj, objtype):
|
||||||
|
if obj is None:
|
||||||
|
return lambda *args, **kwargs: self.func(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
return lambda *args, **kwargs: self.func(obj, *args, **kwargs)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# the python3 way
|
||||||
|
from functools import reduce
|
||||||
|
except ImportError:
|
||||||
|
reduce = reduce
|
||||||
|
|
||||||
|
|
||||||
|
def use_metaclass(meta, *bases):
|
||||||
|
""" Create a class with a metaclass. """
|
||||||
|
if not bases:
|
||||||
|
bases = (object,)
|
||||||
|
return meta("HackClass", bases, {})
|
||||||
|
|
||||||
|
try:
|
||||||
|
from inspect import cleandoc
|
||||||
|
except ImportError:
|
||||||
|
# python 2.5 doesn't have this method
|
||||||
|
import string
|
||||||
|
|
||||||
|
def cleandoc(doc):
|
||||||
|
"""Clean up indentation from docstrings.
|
||||||
|
|
||||||
|
Any whitespace that can be uniformly removed from the second line
|
||||||
|
onwards is removed."""
|
||||||
|
try:
|
||||||
|
lines = string.split(string.expandtabs(doc), '\n')
|
||||||
|
except UnicodeError:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# Find minimum indentation of any non-blank lines after first line.
|
||||||
|
margin = sys.maxint
|
||||||
|
for line in lines[1:]:
|
||||||
|
content = len(string.lstrip(line))
|
||||||
|
if content:
|
||||||
|
indent = len(line) - content
|
||||||
|
margin = min(margin, indent)
|
||||||
|
# Remove indentation.
|
||||||
|
if lines:
|
||||||
|
lines[0] = lines[0].lstrip()
|
||||||
|
if margin < sys.maxint:
|
||||||
|
for i in range(1, len(lines)):
|
||||||
|
lines[i] = lines[i][margin:]
|
||||||
|
# Remove any trailing or leading blank lines.
|
||||||
|
while lines and not lines[-1]:
|
||||||
|
lines.pop()
|
||||||
|
while lines and not lines[0]:
|
||||||
|
lines.pop(0)
|
||||||
|
return string.join(lines, '\n')
|
||||||
|
|
||||||
|
if is_py25:
|
||||||
|
# adds the `itertools.chain.from_iterable` constructor
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
class chain(itertools.chain):
|
||||||
|
@staticmethod
|
||||||
|
def from_iterable(iterables):
|
||||||
|
# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
|
||||||
|
for it in iterables:
|
||||||
|
for element in it:
|
||||||
|
yield element
|
||||||
|
itertools.chain = chain
|
||||||
|
del chain
|
457
common/.local/lib/python2.7/site-packages/jedi/api.py
Normal file
457
common/.local/lib/python2.7/site-packages/jedi/api.py
Normal file
|
@ -0,0 +1,457 @@
|
||||||
|
"""
|
||||||
|
Jedi is an autocompletion library for Python. It offers additonal
|
||||||
|
services such as goto / get_definition / pydoc support /
|
||||||
|
get_in_function_call / related names.
|
||||||
|
|
||||||
|
To give you a simple exmple how you can use the jedi library,
|
||||||
|
here is an exmple for the autocompletion feature:
|
||||||
|
|
||||||
|
>>> import jedi
|
||||||
|
>>> source = '''import json; json.l'''
|
||||||
|
>>> script = jedi.Script(source, 1, 19, '')
|
||||||
|
>>> script
|
||||||
|
<jedi.api.Script at 0x7f6d40f3db90>
|
||||||
|
>>> completions = script.complete()
|
||||||
|
>>> completions
|
||||||
|
[<Completion: load>, <Completion: loads>]
|
||||||
|
>>> completions[0].complete
|
||||||
|
'oad'
|
||||||
|
>>> completions[0].word
|
||||||
|
'load'
|
||||||
|
|
||||||
|
As you see Jedi is pretty simple and allows you to concentrate
|
||||||
|
writing a good text editor, while still having very good IDE features
|
||||||
|
for Python.
|
||||||
|
"""
|
||||||
|
from __future__ import with_statement
|
||||||
|
__all__ = ['Script', 'NotFoundError', 'set_debug_function']
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
import parsing
|
||||||
|
import dynamic
|
||||||
|
import imports
|
||||||
|
import evaluate
|
||||||
|
import modules
|
||||||
|
import debug
|
||||||
|
import settings
|
||||||
|
import keywords
|
||||||
|
import helpers
|
||||||
|
import builtin
|
||||||
|
import api_classes
|
||||||
|
|
||||||
|
from _compatibility import next, unicode
|
||||||
|
|
||||||
|
|
||||||
|
class NotFoundError(Exception):
|
||||||
|
""" A custom error to avoid catching the wrong exceptions """
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Script(object):
|
||||||
|
"""
|
||||||
|
A Script is the base for a completion, goto or whatever call.
|
||||||
|
|
||||||
|
:param source: The source code of the current file
|
||||||
|
:type source: string
|
||||||
|
:param line: The line to complete in.
|
||||||
|
:type line: int
|
||||||
|
:param col: The column to complete in.
|
||||||
|
:type col: int
|
||||||
|
:param source_path: The path in the os, the current module is in.
|
||||||
|
:type source_path: string or None
|
||||||
|
:param source_encoding: encoding for decoding `source`, when it
|
||||||
|
is not a `unicode` object.
|
||||||
|
:type source_encoding: string
|
||||||
|
"""
|
||||||
|
def __init__(self, source, line, column, source_path,
|
||||||
|
source_encoding='utf-8'):
|
||||||
|
debug.reset_time()
|
||||||
|
try:
|
||||||
|
source = unicode(source, source_encoding, 'replace')
|
||||||
|
# Use 'replace' over 'ignore' to hold code structure.
|
||||||
|
except TypeError: # `source` is already a unicode object
|
||||||
|
pass
|
||||||
|
self.pos = line, column
|
||||||
|
self.module = modules.ModuleWithCursor(source_path, source=source,
|
||||||
|
position=self.pos)
|
||||||
|
self.source_path = source_path
|
||||||
|
debug.speed('init')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parser(self):
|
||||||
|
""" The lazy parser """
|
||||||
|
return self.module.parser
|
||||||
|
|
||||||
|
def complete(self):
|
||||||
|
"""
|
||||||
|
An auto completer for python files.
|
||||||
|
|
||||||
|
:return: list of Completion objects, sorted by name and __ comes last.
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
def follow_imports_if_possible(name):
|
||||||
|
# TODO remove this, or move to another place (not used)
|
||||||
|
par = name.parent
|
||||||
|
if isinstance(par, parsing.Import) and not \
|
||||||
|
isinstance(self.parser.user_stmt, parsing.Import):
|
||||||
|
new = imports.ImportPath(par).follow(is_goto=True)
|
||||||
|
# Only remove the old entry if a new one has been found.
|
||||||
|
#print par, new, par.parent
|
||||||
|
if new:
|
||||||
|
try:
|
||||||
|
return new
|
||||||
|
except AttributeError: # .name undefined
|
||||||
|
pass
|
||||||
|
return [name]
|
||||||
|
|
||||||
|
|
||||||
|
debug.speed('complete start')
|
||||||
|
path = self.module.get_path_until_cursor()
|
||||||
|
path, dot, like = self._get_completion_parts(path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
scopes = list(self._prepare_goto(path, True))
|
||||||
|
except NotFoundError:
|
||||||
|
scopes = []
|
||||||
|
scope_generator = evaluate.get_names_for_scope(
|
||||||
|
self.parser.user_scope, self.pos)
|
||||||
|
completions = []
|
||||||
|
for scope, name_list in scope_generator:
|
||||||
|
for c in name_list:
|
||||||
|
completions.append((c, scope))
|
||||||
|
else:
|
||||||
|
completions = []
|
||||||
|
debug.dbg('possible scopes', scopes)
|
||||||
|
for s in scopes:
|
||||||
|
if s.isinstance(evaluate.Function):
|
||||||
|
names = s.get_magic_method_names()
|
||||||
|
else:
|
||||||
|
if isinstance(s, imports.ImportPath):
|
||||||
|
if like == 'import':
|
||||||
|
l = self.module.get_line(self.pos[0])[:self.pos[1]]
|
||||||
|
if not l.endswith('import import'):
|
||||||
|
continue
|
||||||
|
names = s.get_defined_names(on_import_stmt=True)
|
||||||
|
else:
|
||||||
|
names = s.get_defined_names()
|
||||||
|
|
||||||
|
for c in names:
|
||||||
|
completions.append((c, s))
|
||||||
|
|
||||||
|
if not dot: # named_params have no dots
|
||||||
|
call_def = self.get_in_function_call()
|
||||||
|
if call_def:
|
||||||
|
if not call_def.module.is_builtin():
|
||||||
|
for p in call_def.params:
|
||||||
|
completions.append((p.get_name(), p))
|
||||||
|
|
||||||
|
# Do the completion if there is no path before and no import stmt.
|
||||||
|
if (not scopes or not isinstance(scopes[0], imports.ImportPath)) \
|
||||||
|
and not path:
|
||||||
|
# add keywords
|
||||||
|
bs = builtin.Builtin.scope
|
||||||
|
completions += ((k, bs) for k in keywords.get_keywords(
|
||||||
|
all=True))
|
||||||
|
|
||||||
|
needs_dot = not dot and path
|
||||||
|
|
||||||
|
comps = []
|
||||||
|
for c, s in set(completions):
|
||||||
|
n = c.names[-1]
|
||||||
|
if settings.case_insensitive_completion \
|
||||||
|
and n.lower().startswith(like.lower()) \
|
||||||
|
or n.startswith(like):
|
||||||
|
if not evaluate.filter_private_variable(s,
|
||||||
|
self.parser.user_stmt, n):
|
||||||
|
new = api_classes.Completion(c, needs_dot,
|
||||||
|
len(like), s)
|
||||||
|
comps.append(new)
|
||||||
|
|
||||||
|
debug.speed('complete end')
|
||||||
|
|
||||||
|
return sorted(comps, key=lambda x: (x.word.startswith('__'),
|
||||||
|
x.word.startswith('_'),
|
||||||
|
x.word.lower()))
|
||||||
|
|
||||||
|
def _prepare_goto(self, goto_path, is_like_search=False):
|
||||||
|
""" Base for complete, goto and get_definition. Basically it returns
|
||||||
|
the resolved scopes under cursor. """
|
||||||
|
debug.dbg('start: %s in %s' % (goto_path, self.parser.scope))
|
||||||
|
|
||||||
|
user_stmt = self.parser.user_stmt
|
||||||
|
debug.speed('parsed')
|
||||||
|
if not user_stmt and len(goto_path.split('\n')) > 1:
|
||||||
|
# If the user_stmt is not defined and the goto_path is multi line,
|
||||||
|
# something's strange. Most probably the backwards tokenizer
|
||||||
|
# matched to much.
|
||||||
|
return []
|
||||||
|
|
||||||
|
if isinstance(user_stmt, parsing.Import):
|
||||||
|
scopes = [self._get_on_import_stmt(is_like_search)[0]]
|
||||||
|
else:
|
||||||
|
# just parse one statement, take it and evaluate it
|
||||||
|
stmt = self._get_under_cursor_stmt(goto_path)
|
||||||
|
scopes = evaluate.follow_statement(stmt)
|
||||||
|
return scopes
|
||||||
|
|
||||||
|
def _get_under_cursor_stmt(self, cursor_txt):
|
||||||
|
r = parsing.PyFuzzyParser(cursor_txt, self.source_path, no_docstr=True)
|
||||||
|
try:
|
||||||
|
stmt = r.module.statements[0]
|
||||||
|
except IndexError:
|
||||||
|
raise NotFoundError()
|
||||||
|
stmt.start_pos = self.pos
|
||||||
|
stmt.parent = self.parser.user_scope
|
||||||
|
return stmt
|
||||||
|
|
||||||
|
def get_definition(self):
|
||||||
|
"""
|
||||||
|
Returns the definitions of a the path under the cursor. This is
|
||||||
|
not a goto function! This follows complicated paths and returns the
|
||||||
|
end, not the first definition.
|
||||||
|
The big difference of goto and get_definition is that goto doesn't
|
||||||
|
follow imports and statements.
|
||||||
|
Multiple objects may be returned, because Python itself is a dynamic
|
||||||
|
language, which means depending on an option you can have two different
|
||||||
|
versions of a function.
|
||||||
|
|
||||||
|
:return: list of Definition objects, which are basically scopes.
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
def resolve_import_paths(scopes):
|
||||||
|
for s in scopes.copy():
|
||||||
|
if isinstance(s, imports.ImportPath):
|
||||||
|
scopes.remove(s)
|
||||||
|
scopes.update(resolve_import_paths(set(s.follow())))
|
||||||
|
return scopes
|
||||||
|
|
||||||
|
goto_path = self.module.get_path_under_cursor()
|
||||||
|
|
||||||
|
context = self.module.get_context()
|
||||||
|
if next(context) in ('class', 'def'):
|
||||||
|
scopes = set([self.module.parser.user_scope])
|
||||||
|
elif not goto_path:
|
||||||
|
op = self.module.get_operator_under_cursor()
|
||||||
|
scopes = set([keywords.get_operator(op, self.pos)] if op else [])
|
||||||
|
else:
|
||||||
|
scopes = set(self._prepare_goto(goto_path))
|
||||||
|
|
||||||
|
scopes = resolve_import_paths(scopes)
|
||||||
|
|
||||||
|
# add keywords
|
||||||
|
scopes |= keywords.get_keywords(string=goto_path, pos=self.pos)
|
||||||
|
|
||||||
|
d = set([api_classes.Definition(s) for s in scopes
|
||||||
|
if not isinstance(s, imports.ImportPath._GlobalNamespace)])
|
||||||
|
return sorted(d, key=lambda x: (x.module_path, x.start_pos))
|
||||||
|
|
||||||
|
def goto(self):
|
||||||
|
"""
|
||||||
|
Returns the first definition found by goto. This means: It doesn't
|
||||||
|
follow imports and statements.
|
||||||
|
Multiple objects may be returned, because Python itself is a dynamic
|
||||||
|
language, which means depending on an option you can have two different
|
||||||
|
versions of a function.
|
||||||
|
|
||||||
|
:return: list of Definition objects, which are basically scopes.
|
||||||
|
"""
|
||||||
|
d = [api_classes.Definition(d) for d in set(self._goto()[0])]
|
||||||
|
return sorted(d, key=lambda x: (x.module_path, x.start_pos))
|
||||||
|
|
||||||
|
def _goto(self, add_import_name=False):
|
||||||
|
"""
|
||||||
|
Used for goto and related_names.
|
||||||
|
:param add_import_name: TODO add description
|
||||||
|
"""
|
||||||
|
def follow_inexistent_imports(defs):
|
||||||
|
""" Imports can be generated, e.g. following
|
||||||
|
`multiprocessing.dummy` generates an import dummy in the
|
||||||
|
multiprocessing module. The Import doesn't exist -> follow.
|
||||||
|
"""
|
||||||
|
definitions = set(defs)
|
||||||
|
for d in defs:
|
||||||
|
if isinstance(d.parent, parsing.Import) \
|
||||||
|
and d.start_pos == (0, 0):
|
||||||
|
i = imports.ImportPath(d.parent).follow(is_goto=True)
|
||||||
|
definitions.remove(d)
|
||||||
|
definitions |= follow_inexistent_imports(i)
|
||||||
|
return definitions
|
||||||
|
|
||||||
|
goto_path = self.module.get_path_under_cursor()
|
||||||
|
context = self.module.get_context()
|
||||||
|
if next(context) in ('class', 'def'):
|
||||||
|
user_scope = self.parser.user_scope
|
||||||
|
definitions = set([user_scope.name])
|
||||||
|
search_name = str(user_scope.name)
|
||||||
|
elif isinstance(self.parser.user_stmt, parsing.Import):
|
||||||
|
s, name_part = self._get_on_import_stmt()
|
||||||
|
try:
|
||||||
|
definitions = [s.follow(is_goto=True)[0]]
|
||||||
|
except IndexError:
|
||||||
|
definitions = []
|
||||||
|
search_name = str(name_part)
|
||||||
|
|
||||||
|
if add_import_name:
|
||||||
|
import_name = self.parser.user_stmt.get_defined_names()
|
||||||
|
# imports have only one name
|
||||||
|
if name_part == import_name[0].names[-1]:
|
||||||
|
definitions.append(import_name[0])
|
||||||
|
else:
|
||||||
|
stmt = self._get_under_cursor_stmt(goto_path)
|
||||||
|
defs, search_name = evaluate.goto(stmt)
|
||||||
|
definitions = follow_inexistent_imports(defs)
|
||||||
|
return definitions, search_name
|
||||||
|
|
||||||
|
def related_names(self, additional_module_paths=[]):
|
||||||
|
"""
|
||||||
|
Returns `dynamic.RelatedName` objects, which contain all names, that
|
||||||
|
are defined by the same variable, function, class or import.
|
||||||
|
This function can be used either to show all the usages of a variable
|
||||||
|
or for renaming purposes.
|
||||||
|
|
||||||
|
TODO implement additional_module_paths
|
||||||
|
"""
|
||||||
|
user_stmt = self.parser.user_stmt
|
||||||
|
definitions, search_name = self._goto(add_import_name=True)
|
||||||
|
if isinstance(user_stmt, parsing.Statement) \
|
||||||
|
and self.pos < user_stmt.get_assignment_calls().start_pos:
|
||||||
|
# the search_name might be before `=`
|
||||||
|
definitions = [v for v in user_stmt.set_vars
|
||||||
|
if str(v) == search_name]
|
||||||
|
if not isinstance(user_stmt, parsing.Import):
|
||||||
|
# import case is looked at with add_import_name option
|
||||||
|
definitions = dynamic.related_name_add_import_modules(definitions,
|
||||||
|
search_name)
|
||||||
|
|
||||||
|
module = set([d.get_parent_until() for d in definitions])
|
||||||
|
module.add(self.parser.module)
|
||||||
|
names = dynamic.related_names(definitions, search_name, module)
|
||||||
|
|
||||||
|
for d in set(definitions):
|
||||||
|
if isinstance(d, parsing.Module):
|
||||||
|
names.append(api_classes.RelatedName(d, d))
|
||||||
|
else:
|
||||||
|
names.append(api_classes.RelatedName(d.names[0], d))
|
||||||
|
|
||||||
|
return sorted(set(names), key=lambda x: (x.module_path, x.start_pos),
|
||||||
|
reverse=True)
|
||||||
|
|
||||||
|
def get_in_function_call(self):
|
||||||
|
"""
|
||||||
|
Return the function, that the cursor is in, e.g.:
|
||||||
|
>>> isinstance(| # | <-- cursor is here
|
||||||
|
|
||||||
|
This would return the `isinstance` function. In contrary:
|
||||||
|
>>> isinstance()| # | <-- cursor is here
|
||||||
|
|
||||||
|
This would return `None`.
|
||||||
|
"""
|
||||||
|
def check_user_stmt(user_stmt):
|
||||||
|
if user_stmt is None \
|
||||||
|
or not isinstance(user_stmt, parsing.Statement):
|
||||||
|
return None, 0
|
||||||
|
ass = helpers.fast_parent_copy(user_stmt.get_assignment_calls())
|
||||||
|
|
||||||
|
call, index, stop = helpers.scan_array_for_pos(ass, self.pos)
|
||||||
|
return call, index
|
||||||
|
|
||||||
|
def check_cache():
|
||||||
|
""" Do the parsing with a part parser, therefore reduce ressource
|
||||||
|
costs.
|
||||||
|
TODO this is not working with multi-line docstrings, improve.
|
||||||
|
"""
|
||||||
|
if self.source_path is None:
|
||||||
|
return None, 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
timestamp, parser = builtin.CachedModule.cache[
|
||||||
|
self.source_path]
|
||||||
|
except KeyError:
|
||||||
|
return None, 0
|
||||||
|
part_parser = self.module.get_part_parser()
|
||||||
|
user_stmt = part_parser.user_stmt
|
||||||
|
call, index = check_user_stmt(user_stmt)
|
||||||
|
if call:
|
||||||
|
old_stmt = parser.module.get_statement_for_position(self.pos)
|
||||||
|
if old_stmt is None:
|
||||||
|
return None, 0
|
||||||
|
old_call, old_index = check_user_stmt(old_stmt)
|
||||||
|
if old_call:
|
||||||
|
# compare repr because that should definitely be the same.
|
||||||
|
# Otherwise the whole thing is out of sync.
|
||||||
|
if repr(old_call) == repr(call):
|
||||||
|
# return the index of the part_parser
|
||||||
|
return old_call, index
|
||||||
|
return None, 0
|
||||||
|
else:
|
||||||
|
raise NotFoundError()
|
||||||
|
|
||||||
|
debug.speed('func_call start')
|
||||||
|
try:
|
||||||
|
call, index = check_cache()
|
||||||
|
except NotFoundError:
|
||||||
|
return None
|
||||||
|
debug.speed('func_call parsed')
|
||||||
|
|
||||||
|
if call is None:
|
||||||
|
# This is a backup, if the above is not successful.
|
||||||
|
user_stmt = self.parser.user_stmt
|
||||||
|
call, index = check_user_stmt(user_stmt)
|
||||||
|
if call is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
debug.speed('func_call user_stmt')
|
||||||
|
with helpers.scale_speed_settings(settings.scale_get_in_function_call):
|
||||||
|
origins = evaluate.follow_call(call)
|
||||||
|
debug.speed('func_call followed')
|
||||||
|
|
||||||
|
if len(origins) == 0:
|
||||||
|
return None
|
||||||
|
# just take entry zero, because we need just one.
|
||||||
|
executable = origins[0]
|
||||||
|
|
||||||
|
return api_classes.CallDef(executable, index, call)
|
||||||
|
|
||||||
|
def _get_on_import_stmt(self, is_like_search=False):
|
||||||
|
""" Resolve the user statement, if it is an import. Only resolve the
|
||||||
|
parts until the user position. """
|
||||||
|
user_stmt = self.parser.user_stmt
|
||||||
|
import_names = user_stmt.get_all_import_names()
|
||||||
|
kill_count = -1
|
||||||
|
cur_name_part = None
|
||||||
|
for i in import_names:
|
||||||
|
if user_stmt.alias == i:
|
||||||
|
continue
|
||||||
|
for name_part in i.names:
|
||||||
|
if name_part.end_pos >= self.pos:
|
||||||
|
if not cur_name_part:
|
||||||
|
cur_name_part = name_part
|
||||||
|
kill_count += 1
|
||||||
|
|
||||||
|
i = imports.ImportPath(user_stmt, is_like_search,
|
||||||
|
kill_count=kill_count, direct_resolve=True)
|
||||||
|
return i, cur_name_part
|
||||||
|
|
||||||
|
def _get_completion_parts(self, path):
|
||||||
|
"""
|
||||||
|
Returns the parts for the completion
|
||||||
|
:return: tuple - (path, dot, like)
|
||||||
|
"""
|
||||||
|
match = re.match(r'^(.*?)(\.|)(\w?[\w\d]*)$', path, flags=re.S)
|
||||||
|
return match.groups()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
evaluate.clear_caches()
|
||||||
|
|
||||||
|
|
||||||
|
def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
|
||||||
|
notices=True, speed=True):
|
||||||
|
"""
|
||||||
|
You can define a callback debug function to get all the debug messages.
|
||||||
|
:param func_cb: The callback function for debug messages, with n params.
|
||||||
|
"""
|
||||||
|
debug.debug_function = func_cb
|
||||||
|
debug.enable_warning = warnings
|
||||||
|
debug.enable_notice = notices
|
||||||
|
debug.enable_speed = speed
|
311
common/.local/lib/python2.7/site-packages/jedi/api_classes.py
Normal file
311
common/.local/lib/python2.7/site-packages/jedi/api_classes.py
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
""" The classes returned by the api """
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
import settings
|
||||||
|
import evaluate
|
||||||
|
import imports
|
||||||
|
import parsing
|
||||||
|
import keywords
|
||||||
|
|
||||||
|
|
||||||
|
class BaseDefinition(object):
|
||||||
|
_mapping = {'posixpath': 'os.path',
|
||||||
|
'riscospath': 'os.path',
|
||||||
|
'ntpath': 'os.path',
|
||||||
|
'os2emxpath': 'os.path',
|
||||||
|
'macpath': 'os.path',
|
||||||
|
'genericpath': 'os.path',
|
||||||
|
'_io': 'io',
|
||||||
|
'__builtin__': '',
|
||||||
|
'builtins': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
_tuple_mapping = dict((tuple(k.split('.')), v) for (k, v) in {
|
||||||
|
'argparse._ActionsContainer': 'argparse.ArgumentParser',
|
||||||
|
'_sre.SRE_Match': 're.MatchObject',
|
||||||
|
'_sre.SRE_Pattern': 're.RegexObject',
|
||||||
|
}.items())
|
||||||
|
|
||||||
|
def __init__(self, definition, start_pos):
|
||||||
|
self.start_pos = start_pos
|
||||||
|
self.definition = definition
|
||||||
|
self.is_keyword = isinstance(definition, keywords.Keyword)
|
||||||
|
|
||||||
|
# generate a path to the definition
|
||||||
|
self.module_path = str(definition.get_parent_until().path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
# generate the type
|
||||||
|
stripped = self.definition
|
||||||
|
if isinstance(self.definition, evaluate.InstanceElement):
|
||||||
|
stripped = self.definition.var
|
||||||
|
return type(stripped).__name__
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path(self):
|
||||||
|
path = []
|
||||||
|
if not isinstance(self.definition, keywords.Keyword):
|
||||||
|
par = self.definition
|
||||||
|
while par is not None:
|
||||||
|
try:
|
||||||
|
path.insert(0, par.name)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
par = par.parent
|
||||||
|
return path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def module_name(self):
|
||||||
|
path = self.module_path
|
||||||
|
sep = os.path.sep
|
||||||
|
p = re.sub(r'^.*?([\w\d]+)(%s__init__)?.py$' % sep, r'\1', path)
|
||||||
|
return p
|
||||||
|
|
||||||
|
def in_builtin_module(self):
|
||||||
|
return not self.module_path.endswith('.py')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def line_nr(self):
|
||||||
|
return self.start_pos[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def column(self):
|
||||||
|
return self.start_pos[1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def doc(self):
|
||||||
|
""" Return a document string for this completion object. """
|
||||||
|
try:
|
||||||
|
return self.definition.doc
|
||||||
|
except AttributeError:
|
||||||
|
return self.raw_doc
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raw_doc(self):
|
||||||
|
""" Returns the raw docstring `__doc__` for any object """
|
||||||
|
try:
|
||||||
|
return str(self.definition.docstr)
|
||||||
|
except AttributeError:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
return str(self.definition)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_name(self):
|
||||||
|
"""
|
||||||
|
Returns the path to a certain class/function, see #61.
|
||||||
|
"""
|
||||||
|
path = [str(p) for p in self.path]
|
||||||
|
# TODO add further checks, the mapping should only occur on stdlib.
|
||||||
|
try:
|
||||||
|
path[0] = self._mapping[path[0]]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
for key, repl in self._tuple_mapping.items():
|
||||||
|
if tuple(path[:len(key)]) == key:
|
||||||
|
path = [repl] + path[len(key):]
|
||||||
|
|
||||||
|
return '.'.join(path if path[0] else path[1:])
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s %s>" % (type(self).__name__, self.description)
|
||||||
|
|
||||||
|
|
||||||
|
class Completion(BaseDefinition):
|
||||||
|
""" `Completion` objects are returned from `Script.complete`. Providing
|
||||||
|
some useful functions for IDE's. """
|
||||||
|
def __init__(self, name, needs_dot, like_name_length, base):
|
||||||
|
super(Completion, self).__init__(name.parent, name.start_pos)
|
||||||
|
|
||||||
|
self.name = name
|
||||||
|
self.needs_dot = needs_dot
|
||||||
|
self.like_name_length = like_name_length
|
||||||
|
self.base = base
|
||||||
|
|
||||||
|
self._followed_definitions = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def complete(self):
|
||||||
|
""" Delievers the rest of the word, e.g. completing `isinstance`
|
||||||
|
>>> isinstan
|
||||||
|
|
||||||
|
would return the string 'ce'. It also adds additional stuff, depending
|
||||||
|
on your `settings.py`
|
||||||
|
"""
|
||||||
|
dot = '.' if self.needs_dot else ''
|
||||||
|
append = ''
|
||||||
|
if settings.add_bracket_after_function \
|
||||||
|
and self.type == 'Function':
|
||||||
|
append = '('
|
||||||
|
|
||||||
|
if settings.add_dot_after_module:
|
||||||
|
if isinstance(self.base, parsing.Module):
|
||||||
|
append += '.'
|
||||||
|
if isinstance(self.base, parsing.Param):
|
||||||
|
append += '='
|
||||||
|
return dot + self.name.names[-1][self.like_name_length:] + append
|
||||||
|
|
||||||
|
@property
|
||||||
|
def word(self):
|
||||||
|
""" In contrary to `complete` returns the whole word, e.g.
|
||||||
|
>>> isinstan
|
||||||
|
|
||||||
|
would return 'isinstance'.
|
||||||
|
"""
|
||||||
|
return str(self.name.names[-1])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
""" Provides a description of the completion object
|
||||||
|
TODO return value is just __repr__ of some objects, improve! """
|
||||||
|
parent = self.name.parent
|
||||||
|
if parent is None:
|
||||||
|
return ''
|
||||||
|
t = self.type
|
||||||
|
if t == 'Statement' or t == 'Import':
|
||||||
|
desc = self.definition.get_code(False)
|
||||||
|
else:
|
||||||
|
desc = '.'.join(str(p) for p in self.path)
|
||||||
|
|
||||||
|
line_nr = '' if self.in_builtin_module else '@%s' % self.line_nr
|
||||||
|
return '%s: %s%s' % (t, desc, line_nr)
|
||||||
|
|
||||||
|
def follow_definition(self):
|
||||||
|
""" Returns you the original definitions. I strongly recommend not
|
||||||
|
using it for your completions, because it might slow down Jedi. If you
|
||||||
|
want to read only a few objects (<=20). I think it might be useful,
|
||||||
|
especially to get the original docstrings.
|
||||||
|
The basic problem of this function is that it follows all results. This
|
||||||
|
means with 1000 completions (e.g. numpy), it's just PITA slow.
|
||||||
|
"""
|
||||||
|
if self._followed_definitions is None:
|
||||||
|
if self.definition.isinstance(parsing.Statement):
|
||||||
|
defs = evaluate.follow_statement(self.definition)
|
||||||
|
elif self.definition.isinstance(parsing.Import):
|
||||||
|
defs = imports.strip_imports([self.definition])
|
||||||
|
else:
|
||||||
|
return [self]
|
||||||
|
|
||||||
|
self._followed_definitions = \
|
||||||
|
[BaseDefinition(d, d.start_pos) for d in defs]
|
||||||
|
evaluate.clear_caches()
|
||||||
|
|
||||||
|
return self._followed_definitions
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s: %s>' % (type(self).__name__, self.name)
|
||||||
|
|
||||||
|
|
||||||
|
class Definition(BaseDefinition):
|
||||||
|
""" These are the objects returned by either `Script.goto` or
|
||||||
|
`Script.get_definition`. """
|
||||||
|
def __init__(self, definition):
|
||||||
|
super(Definition, self).__init__(definition, definition.start_pos)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
""" A description of the Definition object, which is heavily used in
|
||||||
|
testing. e.g. for `isinstance` it returns 'def isinstance' """
|
||||||
|
d = self.definition
|
||||||
|
if isinstance(d, evaluate.InstanceElement):
|
||||||
|
d = d.var
|
||||||
|
if isinstance(d, evaluate.parsing.Name):
|
||||||
|
d = d.parent
|
||||||
|
|
||||||
|
if isinstance(d, evaluate.Array):
|
||||||
|
d = 'class ' + d.type
|
||||||
|
elif isinstance(d, (parsing.Class, evaluate.Class, evaluate.Instance)):
|
||||||
|
d = 'class ' + str(d.name)
|
||||||
|
elif isinstance(d, (evaluate.Function, evaluate.parsing.Function)):
|
||||||
|
d = 'def ' + str(d.name)
|
||||||
|
elif isinstance(d, evaluate.parsing.Module):
|
||||||
|
# only show module name
|
||||||
|
d = 'module %s' % self.module_name
|
||||||
|
elif self.is_keyword:
|
||||||
|
d = 'keyword %s' % d.name
|
||||||
|
else:
|
||||||
|
d = d.get_code().replace('\n', '')
|
||||||
|
return d
|
||||||
|
|
||||||
|
@property
|
||||||
|
def desc_with_module(self):
|
||||||
|
""" In addition to the Definition, it also returns the module. Don't
|
||||||
|
use it yet, its behaviour may change. If you really need it, talk to me
|
||||||
|
TODO add full path. This function is should return a
|
||||||
|
module.class.function path. """
|
||||||
|
if self.module_path.endswith('.py') \
|
||||||
|
and not isinstance(self.definition, parsing.Module):
|
||||||
|
position = '@%s' % (self.line_nr)
|
||||||
|
else:
|
||||||
|
# is a builtin or module
|
||||||
|
position = ''
|
||||||
|
return "%s:%s%s" % (self.module_name, self.description, position)
|
||||||
|
|
||||||
|
|
||||||
|
class RelatedName(BaseDefinition):
|
||||||
|
def __init__(self, name_part, scope):
|
||||||
|
super(RelatedName, self).__init__(scope, name_part.start_pos)
|
||||||
|
self.name_part = name_part
|
||||||
|
self.text = str(name_part)
|
||||||
|
self.end_pos = name_part.end_pos
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
return "%s@%s,%s" % (self.text, self.start_pos[0], self.start_pos[1])
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.start_pos == other.start_pos \
|
||||||
|
and self.module_path == other.module_path
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.start_pos, self.module_path))
|
||||||
|
|
||||||
|
|
||||||
|
class CallDef(object):
|
||||||
|
""" `CallDef` objects is the return value of `Script.get_in_function_call`.
|
||||||
|
It knows what functions you are currently in. e.g. `isinstance(` would
|
||||||
|
return the `isinstance` function. without `(` it would return nothing."""
|
||||||
|
def __init__(self, executable, index, call):
|
||||||
|
self.executable = executable
|
||||||
|
self.index = index
|
||||||
|
self.call = call
|
||||||
|
|
||||||
|
@property
|
||||||
|
def params(self):
|
||||||
|
if self.executable.isinstance(evaluate.Function):
|
||||||
|
if isinstance(self.executable, evaluate.InstanceElement):
|
||||||
|
return self.executable.params[1:]
|
||||||
|
return self.executable.params
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
sub = self.executable.get_subscope_by_name('__init__')
|
||||||
|
return sub.params[1:] # ignore self
|
||||||
|
except KeyError:
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bracket_start(self):
|
||||||
|
""" The indent of the bracket that is responsible for the last function
|
||||||
|
call. """
|
||||||
|
c = self.call
|
||||||
|
while c.next is not None:
|
||||||
|
c = c.next
|
||||||
|
return c.name.end_pos
|
||||||
|
|
||||||
|
@property
|
||||||
|
def call_name(self):
|
||||||
|
""" The name (e.g. 'isinstance') as a string. """
|
||||||
|
return str(self.executable.name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def module(self):
|
||||||
|
return self.executable.get_parent_until()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s: %s index %s>' % (type(self).__name__, self.executable,
|
||||||
|
self.index)
|
472
common/.local/lib/python2.7/site-packages/jedi/builtin.py
Normal file
472
common/.local/lib/python2.7/site-packages/jedi/builtin.py
Normal file
|
@ -0,0 +1,472 @@
|
||||||
|
from __future__ import with_statement
|
||||||
|
from _compatibility import exec_function, is_py3k
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
if is_py3k:
|
||||||
|
import io
|
||||||
|
import types
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
import debug
|
||||||
|
import parsing
|
||||||
|
import imports
|
||||||
|
import evaluate
|
||||||
|
|
||||||
|
|
||||||
|
def get_sys_path():
|
||||||
|
def check_virtual_env(sys_path):
|
||||||
|
""" Add virtualenv's site-packages to the `sys.path`."""
|
||||||
|
venv = os.getenv('VIRTUAL_ENV')
|
||||||
|
if not venv:
|
||||||
|
return
|
||||||
|
venv = os.path.abspath(venv)
|
||||||
|
p = os.path.join(
|
||||||
|
venv, 'lib', 'python%d.%d' % sys.version_info[:2], 'site-packages')
|
||||||
|
sys_path.insert(0, p)
|
||||||
|
|
||||||
|
p = sys.path[1:]
|
||||||
|
check_virtual_env(p)
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
class CachedModule(object):
|
||||||
|
"""
|
||||||
|
The base type for all modules, which is not to be confused with
|
||||||
|
`parsing.Module`. Caching happens here.
|
||||||
|
"""
|
||||||
|
cache = {}
|
||||||
|
|
||||||
|
def __init__(self, path=None, name=None):
|
||||||
|
self.path = path and os.path.abspath(path)
|
||||||
|
self.name = name
|
||||||
|
self._parser = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parser(self):
|
||||||
|
""" get the parser lazy """
|
||||||
|
if not self._parser:
|
||||||
|
try:
|
||||||
|
timestamp, parser = self.cache[self.path or self.name]
|
||||||
|
if not self.path or os.path.getmtime(self.path) <= timestamp:
|
||||||
|
self._parser = parser
|
||||||
|
else:
|
||||||
|
# In case there is already a module cached and this module
|
||||||
|
# has to be reparsed, we also need to invalidate the import
|
||||||
|
# caches.
|
||||||
|
imports.invalidate_star_import_cache(parser.module)
|
||||||
|
raise KeyError()
|
||||||
|
except KeyError:
|
||||||
|
self._load_module()
|
||||||
|
return self._parser
|
||||||
|
|
||||||
|
def _get_source(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def _load_module(self):
|
||||||
|
source = self._get_source()
|
||||||
|
self._parser = parsing.PyFuzzyParser(source, self.path or self.name)
|
||||||
|
p_time = None if not self.path else os.path.getmtime(self.path)
|
||||||
|
|
||||||
|
if self.path or self.name:
|
||||||
|
self.cache[self.path or self.name] = p_time, self._parser
|
||||||
|
|
||||||
|
|
||||||
|
class Parser(CachedModule):
|
||||||
|
"""
|
||||||
|
This module is a parser for all builtin modules, which are programmed in
|
||||||
|
C/C++. It should also work on third party modules.
|
||||||
|
It can be instantiated with either a path or a name of the module. The path
|
||||||
|
is important for third party modules.
|
||||||
|
|
||||||
|
:param name: The name of the module.
|
||||||
|
:param path: The path of the module.
|
||||||
|
:param sys_path: The sys.path, which is can be customizable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
map_types = {
|
||||||
|
'floating point number': '0.0',
|
||||||
|
'string': '""',
|
||||||
|
'str': '""',
|
||||||
|
'character': '"a"',
|
||||||
|
'integer': '0',
|
||||||
|
'int': '0',
|
||||||
|
'dictionary': '{}',
|
||||||
|
'list': '[]',
|
||||||
|
'file object': 'file("")',
|
||||||
|
# TODO things like dbg: ('not working', 'tuple of integers')
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_py3k:
|
||||||
|
map_types['file object'] = 'import io; return io.TextIOWrapper()'
|
||||||
|
|
||||||
|
module_cache = {}
|
||||||
|
|
||||||
|
def __init__(self, path=None, name=None, sys_path=None):
|
||||||
|
if sys_path is None:
|
||||||
|
sys_path = get_sys_path()
|
||||||
|
if not name:
|
||||||
|
name = os.path.basename(path)
|
||||||
|
name = name.rpartition('.')[0] # cut file type (normally .so)
|
||||||
|
super(Parser, self).__init__(path=path, name=name)
|
||||||
|
|
||||||
|
self.sys_path = list(sys_path)
|
||||||
|
self._module = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def module(self):
|
||||||
|
def load_module(name, path):
|
||||||
|
if path:
|
||||||
|
self.sys_path.insert(0, path)
|
||||||
|
|
||||||
|
temp, sys.path = sys.path, self.sys_path
|
||||||
|
content = {}
|
||||||
|
try:
|
||||||
|
exec_function('import %s as module' % name, content)
|
||||||
|
self._module = content['module']
|
||||||
|
except AttributeError:
|
||||||
|
# use sys.modules, because you cannot access some modules
|
||||||
|
# directly. -> #59
|
||||||
|
self._module = sys.modules[name]
|
||||||
|
sys.path = temp
|
||||||
|
|
||||||
|
if path:
|
||||||
|
self.sys_path.pop(0)
|
||||||
|
|
||||||
|
# module might already be defined
|
||||||
|
if not self._module:
|
||||||
|
path = self.path
|
||||||
|
name = self.name
|
||||||
|
if self.path:
|
||||||
|
|
||||||
|
dot_path = []
|
||||||
|
p = self.path
|
||||||
|
# search for the builtin with the correct path
|
||||||
|
while p and p not in sys.path:
|
||||||
|
p, sep, mod = p.rpartition(os.path.sep)
|
||||||
|
dot_path.append(mod.partition('.')[0])
|
||||||
|
if p:
|
||||||
|
name = ".".join(reversed(dot_path))
|
||||||
|
path = p
|
||||||
|
else:
|
||||||
|
path = os.path.dirname(self.path)
|
||||||
|
|
||||||
|
load_module(name, path)
|
||||||
|
return self._module
|
||||||
|
|
||||||
|
def _get_source(self):
|
||||||
|
""" Override this abstract method """
|
||||||
|
return _generate_code(self.module, self._load_mixins())
|
||||||
|
|
||||||
|
def _load_mixins(self):
|
||||||
|
"""
|
||||||
|
Load functions that are mixed in to the standard library.
|
||||||
|
E.g. builtins are written in C (binaries), but my autocompletion only
|
||||||
|
understands Python code. By mixing in Python code, the autocompletion
|
||||||
|
should work much better for builtins.
|
||||||
|
"""
|
||||||
|
regex = r'^(def|class)\s+([\w\d]+)'
|
||||||
|
|
||||||
|
def process_code(code, depth=0):
|
||||||
|
funcs = {}
|
||||||
|
matches = list(re.finditer(regex, code, re.MULTILINE))
|
||||||
|
positions = [m.start() for m in matches]
|
||||||
|
for i, pos in enumerate(positions):
|
||||||
|
try:
|
||||||
|
code_block = code[pos:positions[i + 1]]
|
||||||
|
except IndexError:
|
||||||
|
code_block = code[pos:len(code)]
|
||||||
|
structure_name = matches[i].group(1)
|
||||||
|
name = matches[i].group(2)
|
||||||
|
if structure_name == 'def':
|
||||||
|
funcs[name] = code_block
|
||||||
|
elif structure_name == 'class':
|
||||||
|
if depth > 0:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
# remove class line
|
||||||
|
c = re.sub(r'^[^\n]+', '', code_block)
|
||||||
|
# remove whitespace
|
||||||
|
c = re.compile(r'^[ ]{4}', re.MULTILINE).sub('', c)
|
||||||
|
|
||||||
|
funcs[name] = process_code(c)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
return funcs
|
||||||
|
|
||||||
|
try:
|
||||||
|
name = self.name
|
||||||
|
if name == '__builtin__' and not is_py3k:
|
||||||
|
name = 'builtins'
|
||||||
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
with open(os.path.sep.join([path, 'mixin', name]) + '.pym') as f:
|
||||||
|
s = f.read()
|
||||||
|
except IOError:
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
mixin_dct = process_code(s)
|
||||||
|
if is_py3k and self.name == Builtin.name:
|
||||||
|
# in the case of Py3k xrange is now range
|
||||||
|
mixin_dct['range'] = mixin_dct['xrange']
|
||||||
|
return mixin_dct
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_code(scope, mixin_funcs={}, depth=0):
|
||||||
|
"""
|
||||||
|
Generate a string, which uses python syntax as an input to the
|
||||||
|
PyFuzzyParser.
|
||||||
|
"""
|
||||||
|
def get_doc(obj, indent=False):
|
||||||
|
doc = inspect.getdoc(obj)
|
||||||
|
if doc:
|
||||||
|
doc = ('r"""\n%s\n"""\n' % doc)
|
||||||
|
if indent:
|
||||||
|
doc = parsing.indent_block(doc)
|
||||||
|
return doc
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def is_in_base_classes(cls, name, comparison):
|
||||||
|
""" Base classes may contain the exact same object """
|
||||||
|
if name in mixin_funcs:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
mro = cls.mro()
|
||||||
|
except TypeError:
|
||||||
|
# this happens, if cls == type
|
||||||
|
return False
|
||||||
|
for base in mro[1:]:
|
||||||
|
try:
|
||||||
|
attr = getattr(base, name)
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
if attr == comparison:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_scope_objects(names):
|
||||||
|
"""
|
||||||
|
Looks for the names defined with dir() in an objects and divides
|
||||||
|
them into different object types.
|
||||||
|
"""
|
||||||
|
classes = {}
|
||||||
|
funcs = {}
|
||||||
|
stmts = {}
|
||||||
|
members = {}
|
||||||
|
for n in names:
|
||||||
|
try:
|
||||||
|
# this has a builtin_function_or_method
|
||||||
|
exe = getattr(scope, n)
|
||||||
|
except AttributeError:
|
||||||
|
# happens e.g. in properties of
|
||||||
|
# PyQt4.QtGui.QStyleOptionComboBox.currentText
|
||||||
|
# -> just set it to None
|
||||||
|
members[n] = None
|
||||||
|
else:
|
||||||
|
if inspect.isclass(scope):
|
||||||
|
if is_in_base_classes(scope, n, exe):
|
||||||
|
continue
|
||||||
|
if inspect.isbuiltin(exe) or inspect.ismethod(exe) \
|
||||||
|
or inspect.ismethoddescriptor(exe):
|
||||||
|
funcs[n] = exe
|
||||||
|
elif inspect.isclass(exe):
|
||||||
|
classes[n] = exe
|
||||||
|
elif inspect.ismemberdescriptor(exe):
|
||||||
|
members[n] = exe
|
||||||
|
else:
|
||||||
|
stmts[n] = exe
|
||||||
|
return classes, funcs, stmts, members
|
||||||
|
|
||||||
|
code = ''
|
||||||
|
if inspect.ismodule(scope): # generate comment where the code's from.
|
||||||
|
try:
|
||||||
|
path = scope.__file__
|
||||||
|
except AttributeError:
|
||||||
|
path = '?'
|
||||||
|
code += '# Generated module %s from %s\n' % (scope.__name__, path)
|
||||||
|
|
||||||
|
code += get_doc(scope)
|
||||||
|
|
||||||
|
names = set(dir(scope)) - set(['__file__', '__name__', '__doc__',
|
||||||
|
'__path__', '__package__']) \
|
||||||
|
| set(['mro'])
|
||||||
|
|
||||||
|
classes, funcs, stmts, members = get_scope_objects(names)
|
||||||
|
|
||||||
|
# classes
|
||||||
|
for name, cl in classes.items():
|
||||||
|
bases = (c.__name__ for c in cl.__bases__)
|
||||||
|
code += 'class %s(%s):\n' % (name, ','.join(bases))
|
||||||
|
if depth == 0:
|
||||||
|
try:
|
||||||
|
mixin = mixin_funcs[name]
|
||||||
|
except KeyError:
|
||||||
|
mixin = {}
|
||||||
|
cl_code = _generate_code(cl, mixin, depth + 1)
|
||||||
|
code += parsing.indent_block(cl_code)
|
||||||
|
code += '\n'
|
||||||
|
|
||||||
|
# functions
|
||||||
|
for name, func in funcs.items():
|
||||||
|
params, ret = parse_function_doc(func)
|
||||||
|
if depth > 0:
|
||||||
|
params = 'self, ' + params
|
||||||
|
doc_str = get_doc(func, indent=True)
|
||||||
|
try:
|
||||||
|
mixin = mixin_funcs[name]
|
||||||
|
except KeyError:
|
||||||
|
# normal code generation
|
||||||
|
code += 'def %s(%s):\n' % (name, params)
|
||||||
|
code += doc_str
|
||||||
|
code += parsing.indent_block('%s\n\n' % ret)
|
||||||
|
else:
|
||||||
|
# generation of code with mixins
|
||||||
|
# the parser only supports basic functions with a newline after
|
||||||
|
# the double dots
|
||||||
|
# find doc_str place
|
||||||
|
pos = re.search(r'\):\s*\n', mixin).end()
|
||||||
|
if pos is None:
|
||||||
|
raise Exception("Builtin function not parsed correctly")
|
||||||
|
code += mixin[:pos] + doc_str + mixin[pos:]
|
||||||
|
|
||||||
|
# class members (functions) properties?
|
||||||
|
for name, func in members.items():
|
||||||
|
# recursion problem in properties TODO remove
|
||||||
|
if name in ['fget', 'fset', 'fdel']:
|
||||||
|
continue
|
||||||
|
ret = 'pass'
|
||||||
|
code += '@property\ndef %s(self):\n' % (name)
|
||||||
|
code += parsing.indent_block(get_doc(func) + '%s\n\n' % ret)
|
||||||
|
|
||||||
|
# variables
|
||||||
|
for name, value in stmts.items():
|
||||||
|
if is_py3k:
|
||||||
|
file_type = io.TextIOWrapper
|
||||||
|
else:
|
||||||
|
file_type = types.FileType
|
||||||
|
if type(value) == file_type:
|
||||||
|
value = 'open()'
|
||||||
|
elif name == 'None':
|
||||||
|
value = ''
|
||||||
|
elif type(value).__name__ in ['int', 'bool', 'float',
|
||||||
|
'dict', 'list', 'tuple']:
|
||||||
|
value = repr(value)
|
||||||
|
else:
|
||||||
|
# get the type, if the type is not simple.
|
||||||
|
mod = type(value).__module__
|
||||||
|
value = type(value).__name__ + '()'
|
||||||
|
if mod != '__builtin__':
|
||||||
|
value = '%s.%s' % (mod, value)
|
||||||
|
code += '%s = %s\n' % (name, value)
|
||||||
|
|
||||||
|
if depth == 0:
|
||||||
|
#with open('writeout.py', 'w') as f:
|
||||||
|
# f.write(code)
|
||||||
|
#import sys
|
||||||
|
#sys.stdout.write(code)
|
||||||
|
#exit()
|
||||||
|
pass
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def parse_function_doc(func):
|
||||||
|
"""
|
||||||
|
Takes a function and returns the params and return value as a tuple.
|
||||||
|
This is nothing more than a docstring parser.
|
||||||
|
"""
|
||||||
|
# TODO: things like utime(path, (atime, mtime)) and a(b [, b]) -> None
|
||||||
|
doc = inspect.getdoc(func)
|
||||||
|
|
||||||
|
# get full string, parse round parentheses: def func(a, (b,c))
|
||||||
|
try:
|
||||||
|
count = 0
|
||||||
|
debug.dbg(func, func.__name__, doc)
|
||||||
|
start = doc.index('(')
|
||||||
|
for i, s in enumerate(doc[start:]):
|
||||||
|
if s == '(':
|
||||||
|
count += 1
|
||||||
|
elif s == ')':
|
||||||
|
count -= 1
|
||||||
|
if count == 0:
|
||||||
|
end = start + i
|
||||||
|
break
|
||||||
|
param_str = doc[start + 1:end]
|
||||||
|
|
||||||
|
# remove square brackets, that show an optional param ( = None)
|
||||||
|
def change_options(m):
|
||||||
|
args = m.group(1).split(',')
|
||||||
|
for i, a in enumerate(args):
|
||||||
|
if a and '=' not in a:
|
||||||
|
args[i] += '=None'
|
||||||
|
return ','.join(args)
|
||||||
|
while True:
|
||||||
|
param_str, changes = re.subn(r' ?\[([^\[\]]+)\]',
|
||||||
|
change_options, param_str)
|
||||||
|
if changes == 0:
|
||||||
|
break
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
debug.dbg('no brackets found - no param')
|
||||||
|
end = 0
|
||||||
|
param_str = ''
|
||||||
|
|
||||||
|
param_str = param_str.replace('-', '_') # see: isinstance.__doc__
|
||||||
|
|
||||||
|
if doc is not None:
|
||||||
|
r = re.search('-[>-]* ', doc[end:end + 7])
|
||||||
|
if doc is None or r is None:
|
||||||
|
ret = 'pass'
|
||||||
|
else:
|
||||||
|
index = end + r.end()
|
||||||
|
# get result type, which can contain newlines
|
||||||
|
pattern = re.compile(r'(,\n|[^\n-])+')
|
||||||
|
ret_str = pattern.match(doc, index).group(0).strip()
|
||||||
|
# New object -> object()
|
||||||
|
ret_str = re.sub(r'[nN]ew (.*)', r'\1()', ret_str)
|
||||||
|
|
||||||
|
ret = Parser.map_types.get(ret_str, ret_str)
|
||||||
|
if ret == ret_str and ret not in ['None', 'object', 'tuple', 'set']:
|
||||||
|
debug.dbg('not working', ret_str)
|
||||||
|
if ret != 'pass':
|
||||||
|
ret = ('return ' if 'return' not in ret else '') + ret
|
||||||
|
return param_str, ret
|
||||||
|
|
||||||
|
|
||||||
|
class Builtin(object):
|
||||||
|
""" The builtin scope / module """
|
||||||
|
# Python 3 compatibility
|
||||||
|
if is_py3k:
|
||||||
|
name = 'builtins'
|
||||||
|
else:
|
||||||
|
name = '__builtin__'
|
||||||
|
|
||||||
|
_builtin = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def builtin(self):
|
||||||
|
if self._builtin is None:
|
||||||
|
self._builtin = Parser(name=self.name)
|
||||||
|
return self._builtin
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scope(self):
|
||||||
|
return self.builtin.parser.module
|
||||||
|
|
||||||
|
@property
|
||||||
|
def magic_function_scope(self):
|
||||||
|
try:
|
||||||
|
return self._magic_function_scope
|
||||||
|
except AttributeError:
|
||||||
|
# depth = 1 because this is not a module
|
||||||
|
class Container(object):
|
||||||
|
FunctionType = types.FunctionType
|
||||||
|
source = _generate_code(Container, depth=0)
|
||||||
|
parser = parsing.PyFuzzyParser(source, None)
|
||||||
|
module = parser.module
|
||||||
|
module.parent = self.scope
|
||||||
|
typ = evaluate.follow_path(iter(['FunctionType']), module, module)
|
||||||
|
|
||||||
|
s = self._magic_function_scope = typ.pop()
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
Builtin = Builtin()
|
64
common/.local/lib/python2.7/site-packages/jedi/debug.py
Normal file
64
common/.local/lib/python2.7/site-packages/jedi/debug.py
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import inspect
|
||||||
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use colorama for nicer console output.
|
||||||
|
from colorama import Fore, init
|
||||||
|
init()
|
||||||
|
except ImportError:
|
||||||
|
class Fore(object):
|
||||||
|
RED = ''
|
||||||
|
GREEN = ''
|
||||||
|
YELLOW = ''
|
||||||
|
RESET = ''
|
||||||
|
|
||||||
|
NOTICE = object()
|
||||||
|
WARNING = object()
|
||||||
|
SPEED = object()
|
||||||
|
|
||||||
|
enable_speed = False
|
||||||
|
enable_warning = False
|
||||||
|
enable_notice = False
|
||||||
|
|
||||||
|
# callback, interface: level, str
|
||||||
|
debug_function = None
|
||||||
|
ignored_modules = ['parsing', 'builtin', 'jedi.builtin', 'jedi.parsing']
|
||||||
|
|
||||||
|
|
||||||
|
def reset_time():
|
||||||
|
global start_time
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
|
||||||
|
def dbg(*args):
|
||||||
|
""" Looks at the stack, to see if a debug message should be printed. """
|
||||||
|
if debug_function and enable_notice:
|
||||||
|
frm = inspect.stack()[1]
|
||||||
|
mod = inspect.getmodule(frm[0])
|
||||||
|
if not (mod.__name__ in ignored_modules):
|
||||||
|
debug_function(NOTICE, 'dbg: ' + ', '.join(str(a) for a in args))
|
||||||
|
|
||||||
|
|
||||||
|
def warning(*args):
|
||||||
|
if debug_function and enable_warning:
|
||||||
|
debug_function(WARNING, 'warning: ' + ', '.join(str(a) for a in args))
|
||||||
|
|
||||||
|
|
||||||
|
def speed(name):
|
||||||
|
if debug_function and enable_speed:
|
||||||
|
now = time.time()
|
||||||
|
debug_function(SPEED, 'speed: ' + '%s %s' % (name, now - start_time))
|
||||||
|
|
||||||
|
|
||||||
|
def print_to_stdout(level, str_out):
|
||||||
|
""" The default debug function """
|
||||||
|
if level == NOTICE:
|
||||||
|
col = Fore.GREEN
|
||||||
|
elif level == WARNING:
|
||||||
|
col = Fore.RED
|
||||||
|
else:
|
||||||
|
col = Fore.YELLOW
|
||||||
|
print(col + str_out + Fore.RESET)
|
||||||
|
|
||||||
|
|
||||||
|
#debug_function = print_to_stdout
|
34
common/.local/lib/python2.7/site-packages/jedi/docstrings.py
Normal file
34
common/.local/lib/python2.7/site-packages/jedi/docstrings.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
""" Processing of docstrings, which means parsing for types. """
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
import evaluate
|
||||||
|
|
||||||
|
|
||||||
|
#@evaluate.memoize_default() # TODO add
|
||||||
|
def follow_param(param):
|
||||||
|
func = param.parent_function
|
||||||
|
#print func, param, param.parent_function
|
||||||
|
param_str = search_param_in_docstr(func.docstr, str(param.get_name()))
|
||||||
|
|
||||||
|
if param_str is not None:
|
||||||
|
scope = func.get_parent_until()
|
||||||
|
return evaluate.get_scopes_for_name(scope, param_str,
|
||||||
|
search_global=True)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def search_param_in_docstr(docstr, param_str):
|
||||||
|
lines = docstr.split('\n')
|
||||||
|
|
||||||
|
# look at #40 to see definitions of those params
|
||||||
|
sphinx_comp = ':type %s:' % param_str
|
||||||
|
googley_comp = re.compile('\s*%s\s+\(([^()]+)\)' % re.escape(param_str))
|
||||||
|
for l in lines:
|
||||||
|
if l.startswith(sphinx_comp):
|
||||||
|
return l.replace(sphinx_comp, '', 1).strip()
|
||||||
|
|
||||||
|
r = re.match(googley_comp, l)
|
||||||
|
if r is not None:
|
||||||
|
return r.group(1)
|
||||||
|
return None
|
507
common/.local/lib/python2.7/site-packages/jedi/dynamic.py
Normal file
507
common/.local/lib/python2.7/site-packages/jedi/dynamic.py
Normal file
|
@ -0,0 +1,507 @@
|
||||||
|
"""
|
||||||
|
For dynamic completion.
|
||||||
|
|
||||||
|
Sorry to everyone who is reading this code. Especially the array parts are
|
||||||
|
really cryptic and not understandable. It's just a hack, that turned out to be
|
||||||
|
working quite good.
|
||||||
|
"""
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import parsing
|
||||||
|
import modules
|
||||||
|
import evaluate
|
||||||
|
import helpers
|
||||||
|
import settings
|
||||||
|
import debug
|
||||||
|
import builtin
|
||||||
|
import imports
|
||||||
|
import api_classes
|
||||||
|
|
||||||
|
# This is something like the sys.path, but only for searching params. It means
|
||||||
|
# that this is the order in which Jedi searches params.
|
||||||
|
search_param_modules = ['.']
|
||||||
|
search_param_cache = {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_directory_modules_for_name(mods, name):
|
||||||
|
"""
|
||||||
|
Search a name in the directories of modules.
|
||||||
|
"""
|
||||||
|
def check_python_file(path):
|
||||||
|
try:
|
||||||
|
return builtin.CachedModule.cache[path][1].module
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
return check_fs(path)
|
||||||
|
except IOError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_fs(path):
|
||||||
|
with open(path) as f:
|
||||||
|
source = f.read()
|
||||||
|
if name in source:
|
||||||
|
return modules.Module(path, source).parser.module
|
||||||
|
|
||||||
|
# skip non python modules
|
||||||
|
mods = set(m for m in mods if m.path.endswith('.py'))
|
||||||
|
mod_paths = set()
|
||||||
|
for m in mods:
|
||||||
|
mod_paths.add(m.path)
|
||||||
|
yield m
|
||||||
|
|
||||||
|
if settings.dynamic_params_for_other_modules:
|
||||||
|
paths = set(settings.additional_dynamic_modules)
|
||||||
|
for p in mod_paths:
|
||||||
|
d = os.path.dirname(p)
|
||||||
|
for entry in os.listdir(d):
|
||||||
|
if entry not in mod_paths:
|
||||||
|
if entry.endswith('.py'):
|
||||||
|
paths.add(d + os.path.sep + entry)
|
||||||
|
|
||||||
|
for p in paths:
|
||||||
|
c = check_python_file(p)
|
||||||
|
if c is not None and c not in mods:
|
||||||
|
yield c
|
||||||
|
|
||||||
|
|
||||||
|
def search_param_memoize(func):
|
||||||
|
"""
|
||||||
|
Is only good for search params memoize, respectively the closure,
|
||||||
|
because it just caches the input, not the func, like normal memoize does.
|
||||||
|
"""
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
key = (args, frozenset(kwargs.items()))
|
||||||
|
if key in search_param_cache:
|
||||||
|
return search_param_cache[key]
|
||||||
|
else:
|
||||||
|
rv = func(*args, **kwargs)
|
||||||
|
search_param_cache[key] = rv
|
||||||
|
return rv
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class ParamListener(object):
|
||||||
|
"""
|
||||||
|
This listener is used to get the params for a function.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.param_possibilities = []
|
||||||
|
|
||||||
|
def execute(self, params):
|
||||||
|
self.param_possibilities.append(params)
|
||||||
|
|
||||||
|
|
||||||
|
@evaluate.memoize_default([])
|
||||||
|
def search_params(param):
|
||||||
|
"""
|
||||||
|
This is a dynamic search for params. If you try to complete a type:
|
||||||
|
>>> def func(foo):
|
||||||
|
>>> # here is the completion
|
||||||
|
>>> foo
|
||||||
|
>>> func(1)
|
||||||
|
>>> func("")
|
||||||
|
|
||||||
|
It is not known what the type is, because it cannot be guessed with
|
||||||
|
recursive madness. Therefore one has to analyse the statements that are
|
||||||
|
calling the function, as well as analyzing the incoming params.
|
||||||
|
"""
|
||||||
|
if not settings.dynamic_params:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_params_for_module(module):
|
||||||
|
"""
|
||||||
|
Returns the values of a param, or an empty array.
|
||||||
|
"""
|
||||||
|
@search_param_memoize
|
||||||
|
def get_posibilities(module, func_name):
|
||||||
|
try:
|
||||||
|
possible_stmts = module.used_names[func_name]
|
||||||
|
except KeyError:
|
||||||
|
return []
|
||||||
|
|
||||||
|
for stmt in possible_stmts:
|
||||||
|
if not isinstance(stmt, parsing.Import):
|
||||||
|
calls = _scan_array(stmt.get_assignment_calls(), func_name)
|
||||||
|
for c in calls:
|
||||||
|
# no execution means that params cannot be set
|
||||||
|
call_path = c.generate_call_path()
|
||||||
|
pos = c.start_pos
|
||||||
|
scope = stmt.parent
|
||||||
|
evaluate.follow_call_path(call_path, scope, pos)
|
||||||
|
return listener.param_possibilities
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for params in get_posibilities(module, func_name):
|
||||||
|
for p in params:
|
||||||
|
if str(p) == param_name:
|
||||||
|
result += evaluate.follow_statement(p.parent)
|
||||||
|
return result
|
||||||
|
|
||||||
|
func = param.get_parent_until(parsing.Function)
|
||||||
|
current_module = param.get_parent_until()
|
||||||
|
func_name = str(func.name)
|
||||||
|
if func_name == '__init__' and isinstance(func.parent, parsing.Class):
|
||||||
|
func_name = str(func.parent.name)
|
||||||
|
|
||||||
|
# get the param name
|
||||||
|
if param.assignment_details:
|
||||||
|
arr = param.assignment_details[0][1]
|
||||||
|
else:
|
||||||
|
arr = param.get_assignment_calls()
|
||||||
|
offset = 1 if arr[0][0] in ['*', '**'] else 0
|
||||||
|
param_name = str(arr[0][offset].name)
|
||||||
|
|
||||||
|
# add the listener
|
||||||
|
listener = ParamListener()
|
||||||
|
func.listeners.add(listener)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
# This is like backtracking: Get the first possible result.
|
||||||
|
for mod in get_directory_modules_for_name([current_module], func_name):
|
||||||
|
result = get_params_for_module(mod)
|
||||||
|
if result:
|
||||||
|
break
|
||||||
|
|
||||||
|
# cleanup: remove the listener; important: should not stick.
|
||||||
|
func.listeners.remove(listener)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def check_array_additions(array):
|
||||||
|
""" Just a mapper function for the internal _check_array_additions """
|
||||||
|
if array._array.type not in ['list', 'set']:
|
||||||
|
# TODO also check for dict updates
|
||||||
|
return []
|
||||||
|
|
||||||
|
is_list = array._array.type == 'list'
|
||||||
|
current_module = array._array.parent_stmt.get_parent_until()
|
||||||
|
res = _check_array_additions(array, current_module, is_list)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def _scan_array(arr, search_name):
|
||||||
|
""" Returns the function Call that match search_name in an Array. """
|
||||||
|
result = []
|
||||||
|
for sub in arr:
|
||||||
|
for s in sub:
|
||||||
|
if isinstance(s, parsing.Array):
|
||||||
|
result += _scan_array(s, search_name)
|
||||||
|
elif isinstance(s, parsing.Call):
|
||||||
|
s_new = s
|
||||||
|
while s_new is not None:
|
||||||
|
n = s_new.name
|
||||||
|
if isinstance(n, parsing.Name) and search_name in n.names:
|
||||||
|
result.append(s)
|
||||||
|
|
||||||
|
if s_new.execution is not None:
|
||||||
|
result += _scan_array(s_new.execution, search_name)
|
||||||
|
s_new = s_new.next
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
def dec(func):
|
||||||
|
""" TODO delete this """
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
global counter
|
||||||
|
element = args[0]
|
||||||
|
if isinstance(element, evaluate.Array):
|
||||||
|
stmt = element._array.parent_stmt
|
||||||
|
else:
|
||||||
|
# must be instance
|
||||||
|
stmt = element.var_args.parent_stmt
|
||||||
|
print(' ' * counter + 'recursion,', stmt)
|
||||||
|
counter += 1
|
||||||
|
res = func(*args, **kwargs)
|
||||||
|
counter -= 1
|
||||||
|
#print ' '*counter + 'end,'
|
||||||
|
return res
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
#@dec
|
||||||
|
@evaluate.memoize_default([])
|
||||||
|
def _check_array_additions(compare_array, module, is_list):
|
||||||
|
"""
|
||||||
|
Checks if a `parsing.Array` has "add" statements:
|
||||||
|
>>> a = [""]
|
||||||
|
>>> a.append(1)
|
||||||
|
"""
|
||||||
|
if not settings.dynamic_array_additions or module.is_builtin():
|
||||||
|
return []
|
||||||
|
|
||||||
|
def check_calls(calls, add_name):
|
||||||
|
"""
|
||||||
|
Calls are processed here. The part before the call is searched and
|
||||||
|
compared with the original Array.
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
for c in calls:
|
||||||
|
call_path = list(c.generate_call_path())
|
||||||
|
separate_index = call_path.index(add_name)
|
||||||
|
if add_name == call_path[-1] or separate_index == 0:
|
||||||
|
# this means that there is no execution -> [].append
|
||||||
|
# or the keyword is at the start -> append()
|
||||||
|
continue
|
||||||
|
backtrack_path = iter(call_path[:separate_index])
|
||||||
|
|
||||||
|
position = c.start_pos
|
||||||
|
scope = c.parent_stmt.parent
|
||||||
|
|
||||||
|
found = evaluate.follow_call_path(backtrack_path, scope, position)
|
||||||
|
if not compare_array in found:
|
||||||
|
continue
|
||||||
|
|
||||||
|
params = call_path[separate_index + 1]
|
||||||
|
if not params.values:
|
||||||
|
continue # no params: just ignore it
|
||||||
|
if add_name in ['append', 'add']:
|
||||||
|
result += evaluate.follow_call_list(params)
|
||||||
|
elif add_name in ['insert']:
|
||||||
|
try:
|
||||||
|
second_param = params[1]
|
||||||
|
except IndexError:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
result += evaluate.follow_call_list([second_param])
|
||||||
|
elif add_name in ['extend', 'update']:
|
||||||
|
iterators = evaluate.follow_call_list(params)
|
||||||
|
result += evaluate.get_iterator_types(iterators)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_execution_parent(element, *stop_classes):
|
||||||
|
""" Used to get an Instance/Execution parent """
|
||||||
|
if isinstance(element, evaluate.Array):
|
||||||
|
stmt = element._array.parent_stmt
|
||||||
|
else:
|
||||||
|
# must be instance
|
||||||
|
stmt = element.var_args.parent_stmt
|
||||||
|
if isinstance(stmt, evaluate.InstanceElement):
|
||||||
|
stop_classes = list(stop_classes) + [evaluate.Function]
|
||||||
|
return stmt.get_parent_until(stop_classes)
|
||||||
|
|
||||||
|
temp_param_add = settings.dynamic_params_for_other_modules
|
||||||
|
settings.dynamic_params_for_other_modules = False
|
||||||
|
|
||||||
|
search_names = ['append', 'extend', 'insert'] if is_list else \
|
||||||
|
['add', 'update']
|
||||||
|
comp_arr_parent = get_execution_parent(compare_array, evaluate.Execution)
|
||||||
|
possible_stmts = []
|
||||||
|
res = []
|
||||||
|
for n in search_names:
|
||||||
|
try:
|
||||||
|
possible_stmts += module.used_names[n]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
for stmt in possible_stmts:
|
||||||
|
# Check if the original scope is an execution. If it is, one
|
||||||
|
# can search for the same statement, that is in the module
|
||||||
|
# dict. Executions are somewhat special in jedi, since they
|
||||||
|
# literally copy the contents of a function.
|
||||||
|
if isinstance(comp_arr_parent, evaluate.Execution):
|
||||||
|
stmt = comp_arr_parent. \
|
||||||
|
get_statement_for_position(stmt.start_pos)
|
||||||
|
if stmt is None:
|
||||||
|
continue
|
||||||
|
# InstanceElements are special, because they don't get copied,
|
||||||
|
# but have this wrapper around them.
|
||||||
|
if isinstance(comp_arr_parent, evaluate.InstanceElement):
|
||||||
|
stmt = evaluate.InstanceElement(comp_arr_parent.instance, stmt)
|
||||||
|
|
||||||
|
if evaluate.follow_statement.push_stmt(stmt):
|
||||||
|
# check recursion
|
||||||
|
continue
|
||||||
|
res += check_calls(_scan_array(stmt.get_assignment_calls(), n), n)
|
||||||
|
evaluate.follow_statement.pop_stmt()
|
||||||
|
# reset settings
|
||||||
|
settings.dynamic_params_for_other_modules = temp_param_add
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def check_array_instances(instance):
|
||||||
|
""" Used for set() and list() instances. """
|
||||||
|
if not settings.dynamic_arrays_instances:
|
||||||
|
return instance.var_args
|
||||||
|
ai = ArrayInstance(instance)
|
||||||
|
return helpers.generate_param_array([ai], instance.var_args.parent_stmt)
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayInstance(parsing.Base):
|
||||||
|
"""
|
||||||
|
Used for the usage of set() and list().
|
||||||
|
This is definitely a hack, but a good one :-)
|
||||||
|
It makes it possible to use set/list conversions.
|
||||||
|
"""
|
||||||
|
def __init__(self, instance):
|
||||||
|
self.instance = instance
|
||||||
|
self.var_args = instance.var_args
|
||||||
|
|
||||||
|
def iter_content(self):
|
||||||
|
"""
|
||||||
|
The index is here just ignored, because of all the appends, etc.
|
||||||
|
lists/sets are too complicated too handle that.
|
||||||
|
"""
|
||||||
|
items = []
|
||||||
|
for array in evaluate.follow_call_list(self.var_args):
|
||||||
|
if isinstance(array, evaluate.Instance) and len(array.var_args):
|
||||||
|
temp = array.var_args[0][0]
|
||||||
|
if isinstance(temp, ArrayInstance):
|
||||||
|
# prevent recursions
|
||||||
|
# TODO compare Modules
|
||||||
|
if self.var_args.start_pos != temp.var_args.start_pos:
|
||||||
|
items += temp.iter_content()
|
||||||
|
else:
|
||||||
|
debug.warning('ArrayInstance recursion', self.var_args)
|
||||||
|
continue
|
||||||
|
items += evaluate.get_iterator_types([array])
|
||||||
|
|
||||||
|
if self.var_args.parent_stmt is None:
|
||||||
|
return [] # generated var_args should not be checked for arrays
|
||||||
|
|
||||||
|
module = self.var_args.parent_stmt.get_parent_until()
|
||||||
|
is_list = str(self.instance.name) == 'list'
|
||||||
|
items += _check_array_additions(self.instance, module, is_list)
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def related_names(definitions, search_name, mods):
|
||||||
|
def check_call(call):
|
||||||
|
result = []
|
||||||
|
follow = [] # There might be multiple search_name's in one call_path
|
||||||
|
call_path = list(call.generate_call_path())
|
||||||
|
for i, name in enumerate(call_path):
|
||||||
|
# name is `parsing.NamePart`.
|
||||||
|
if name == search_name:
|
||||||
|
follow.append(call_path[:i + 1])
|
||||||
|
|
||||||
|
for f in follow:
|
||||||
|
follow_res, search = evaluate.goto(call.parent_stmt, f)
|
||||||
|
follow_res = related_name_add_import_modules(follow_res, search)
|
||||||
|
|
||||||
|
#print follow_res, [d.parent for d in follow_res]
|
||||||
|
# compare to see if they match
|
||||||
|
if any(r in definitions for r in follow_res):
|
||||||
|
scope = call.parent_stmt
|
||||||
|
result.append(api_classes.RelatedName(search, scope))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not definitions:
|
||||||
|
return set()
|
||||||
|
|
||||||
|
def is_definition(arr):
|
||||||
|
try:
|
||||||
|
for a in arr:
|
||||||
|
assert len(a) == 1
|
||||||
|
a = a[0]
|
||||||
|
if a.isinstance(parsing.Array):
|
||||||
|
assert is_definition(a)
|
||||||
|
elif a.isinstance(parsing.Call):
|
||||||
|
assert a.execution is None
|
||||||
|
return True
|
||||||
|
except AssertionError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
mods |= set([d.get_parent_until() for d in definitions])
|
||||||
|
names = []
|
||||||
|
for m in get_directory_modules_for_name(mods, search_name):
|
||||||
|
try:
|
||||||
|
stmts = m.used_names[search_name]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
for stmt in stmts:
|
||||||
|
if isinstance(stmt, parsing.Import):
|
||||||
|
count = 0
|
||||||
|
imps = []
|
||||||
|
for i in stmt.get_all_import_names():
|
||||||
|
for name_part in i.names:
|
||||||
|
count += 1
|
||||||
|
if name_part == search_name:
|
||||||
|
imps.append((count, name_part))
|
||||||
|
|
||||||
|
for used_count, name_part in imps:
|
||||||
|
i = imports.ImportPath(stmt, kill_count=count - used_count,
|
||||||
|
direct_resolve=True)
|
||||||
|
f = i.follow(is_goto=True)
|
||||||
|
if set(f) & set(definitions):
|
||||||
|
names.append(api_classes.RelatedName(name_part, stmt))
|
||||||
|
else:
|
||||||
|
calls = _scan_array(stmt.get_assignment_calls(), search_name)
|
||||||
|
for d in stmt.assignment_details:
|
||||||
|
if not is_definition(d[1]):
|
||||||
|
calls += _scan_array(d[1], search_name)
|
||||||
|
for call in calls:
|
||||||
|
names += check_call(call)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def related_name_add_import_modules(definitions, search_name):
|
||||||
|
""" Adds the modules of the imports """
|
||||||
|
new = set()
|
||||||
|
for d in definitions:
|
||||||
|
if isinstance(d.parent, parsing.Import):
|
||||||
|
s = imports.ImportPath(d.parent, direct_resolve=True)
|
||||||
|
try:
|
||||||
|
new.add(s.follow(is_goto=True)[0])
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
return set(definitions) | new
|
||||||
|
|
||||||
|
|
||||||
|
def check_flow_information(flow, search_name, pos):
|
||||||
|
""" Try to find out the type of a variable just with the information that
|
||||||
|
is given by the flows: e.g. It is also responsible for assert checks.
|
||||||
|
>>> if isinstance(k, str):
|
||||||
|
>>> k. # <- completion here
|
||||||
|
|
||||||
|
ensures that `k` is a string.
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
if isinstance(flow, parsing.Scope) and not result:
|
||||||
|
for ass in reversed(flow.asserts):
|
||||||
|
if pos is None or ass.start_pos > pos:
|
||||||
|
continue
|
||||||
|
result = check_statement_information(ass, search_name)
|
||||||
|
if result:
|
||||||
|
break
|
||||||
|
|
||||||
|
if isinstance(flow, parsing.Flow) and not result:
|
||||||
|
if flow.command in ['if', 'while'] and len(flow.inits) == 1:
|
||||||
|
result = check_statement_information(flow.inits[0], search_name)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def check_statement_information(stmt, search_name):
|
||||||
|
try:
|
||||||
|
ass = stmt.get_assignment_calls()
|
||||||
|
try:
|
||||||
|
call = ass.get_only_subelement()
|
||||||
|
except AttributeError:
|
||||||
|
assert False
|
||||||
|
assert type(call) == parsing.Call and str(call.name) == 'isinstance'
|
||||||
|
assert bool(call.execution)
|
||||||
|
|
||||||
|
# isinstance check
|
||||||
|
isinst = call.execution.values
|
||||||
|
assert len(isinst) == 2 # has two params
|
||||||
|
assert len(isinst[0]) == 1
|
||||||
|
assert len(isinst[1]) == 1
|
||||||
|
assert isinstance(isinst[0][0], parsing.Call)
|
||||||
|
# names fit?
|
||||||
|
assert str(isinst[0][0].name) == search_name
|
||||||
|
classes_call = isinst[1][0] # class_or_type_or_tuple
|
||||||
|
assert isinstance(classes_call, parsing.Call)
|
||||||
|
result = []
|
||||||
|
for c in evaluate.follow_call(classes_call):
|
||||||
|
if isinstance(c, evaluate.Array):
|
||||||
|
result += c.get_index_types()
|
||||||
|
else:
|
||||||
|
result.append(c)
|
||||||
|
for i, c in enumerate(result):
|
||||||
|
result[i] = evaluate.Instance(c)
|
||||||
|
return result
|
||||||
|
except AssertionError:
|
||||||
|
return []
|
1614
common/.local/lib/python2.7/site-packages/jedi/evaluate.py
Normal file
1614
common/.local/lib/python2.7/site-packages/jedi/evaluate.py
Normal file
File diff suppressed because it is too large
Load diff
266
common/.local/lib/python2.7/site-packages/jedi/helpers.py
Normal file
266
common/.local/lib/python2.7/site-packages/jedi/helpers.py
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
import copy
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
import parsing
|
||||||
|
import evaluate
|
||||||
|
import debug
|
||||||
|
import builtin
|
||||||
|
import settings
|
||||||
|
|
||||||
|
|
||||||
|
class RecursionDecorator(object):
|
||||||
|
"""
|
||||||
|
A decorator to detect recursions in statements. In a recursion a statement
|
||||||
|
at the same place, in the same module may not be executed two times.
|
||||||
|
"""
|
||||||
|
def __init__(self, func):
|
||||||
|
self.func = func
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def __call__(self, stmt, *args, **kwargs):
|
||||||
|
#print stmt, len(self.node_statements())
|
||||||
|
if self.push_stmt(stmt):
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
result = self.func(stmt, *args, **kwargs)
|
||||||
|
self.pop_stmt()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def push_stmt(self, stmt):
|
||||||
|
self.current = RecursionNode(stmt, self.current)
|
||||||
|
if self._check_recursion():
|
||||||
|
debug.warning('catched recursion', stmt)
|
||||||
|
self.pop_stmt()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def pop_stmt(self):
|
||||||
|
if self.current is not None:
|
||||||
|
# I don't know how current can be None, but sometimes it happens
|
||||||
|
# with Python3.
|
||||||
|
self.current = self.current.parent
|
||||||
|
|
||||||
|
def _check_recursion(self):
|
||||||
|
test = self.current
|
||||||
|
while True:
|
||||||
|
test = test.parent
|
||||||
|
if self.current == test:
|
||||||
|
return True
|
||||||
|
if not test:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.top = None
|
||||||
|
self.current = None
|
||||||
|
|
||||||
|
def node_statements(self):
|
||||||
|
result = []
|
||||||
|
n = self.current
|
||||||
|
while n:
|
||||||
|
result.insert(0, n.stmt)
|
||||||
|
n = n.parent
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class RecursionNode(object):
|
||||||
|
""" A node of the RecursionDecorator. """
|
||||||
|
def __init__(self, stmt, parent):
|
||||||
|
self.script = stmt.get_parent_until()
|
||||||
|
self.position = stmt.start_pos
|
||||||
|
self.parent = parent
|
||||||
|
self.stmt = stmt
|
||||||
|
|
||||||
|
# Don't check param instances, they are not causing recursions
|
||||||
|
# The same's true for the builtins, because the builtins are really
|
||||||
|
# simple.
|
||||||
|
self.is_ignored = isinstance(stmt, parsing.Param) \
|
||||||
|
or (self.script == builtin.Builtin.scope)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not other:
|
||||||
|
return None
|
||||||
|
return self.script == other.script \
|
||||||
|
and self.position == other.position \
|
||||||
|
and not self.is_ignored and not other.is_ignored
|
||||||
|
|
||||||
|
|
||||||
|
class ExecutionRecursionDecorator(object):
|
||||||
|
"""
|
||||||
|
Catches recursions of executions.
|
||||||
|
It is designed like a Singelton. Only one instance should exist.
|
||||||
|
"""
|
||||||
|
def __init__(self, func):
|
||||||
|
self.func = func
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def __call__(self, execution, evaluate_generator=False):
|
||||||
|
debug.dbg('Execution recursions: %s' % execution, self.recursion_level,
|
||||||
|
self.execution_count, len(self.execution_funcs))
|
||||||
|
if self.check_recursion(execution, evaluate_generator):
|
||||||
|
result = []
|
||||||
|
else:
|
||||||
|
result = self.func(execution, evaluate_generator)
|
||||||
|
self.cleanup()
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def cleanup(cls):
|
||||||
|
cls.parent_execution_funcs.pop()
|
||||||
|
cls.recursion_level -= 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_recursion(cls, execution, evaluate_generator):
|
||||||
|
in_par_execution_funcs = execution.base in cls.parent_execution_funcs
|
||||||
|
in_execution_funcs = execution.base in cls.execution_funcs
|
||||||
|
cls.recursion_level += 1
|
||||||
|
cls.execution_count += 1
|
||||||
|
cls.execution_funcs.add(execution.base)
|
||||||
|
cls.parent_execution_funcs.append(execution.base)
|
||||||
|
|
||||||
|
if cls.execution_count > settings.max_executions:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if isinstance(execution.base, (evaluate.Generator, evaluate.Array)):
|
||||||
|
return False
|
||||||
|
module = execution.get_parent_until()
|
||||||
|
if evaluate_generator or module == builtin.Builtin.scope:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if in_par_execution_funcs:
|
||||||
|
if cls.recursion_level > settings.max_function_recursion_level:
|
||||||
|
return True
|
||||||
|
if in_execution_funcs and \
|
||||||
|
len(cls.execution_funcs) > settings.max_until_execution_unique:
|
||||||
|
return True
|
||||||
|
if cls.execution_count > settings.max_executions_without_builtins:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def reset(cls):
|
||||||
|
cls.recursion_level = 0
|
||||||
|
cls.parent_execution_funcs = []
|
||||||
|
cls.execution_funcs = set()
|
||||||
|
cls.execution_count = 0
|
||||||
|
|
||||||
|
|
||||||
|
def fast_parent_copy(obj):
|
||||||
|
"""
|
||||||
|
Much, much faster than copy.deepcopy, but just for certain elements.
|
||||||
|
"""
|
||||||
|
new_elements = {}
|
||||||
|
|
||||||
|
def recursion(obj):
|
||||||
|
new_obj = copy.copy(obj)
|
||||||
|
new_elements[obj] = new_obj
|
||||||
|
|
||||||
|
items = new_obj.__dict__.items()
|
||||||
|
for key, value in items:
|
||||||
|
# replace parent (first try _parent and then parent)
|
||||||
|
if key in ['parent', '_parent', '_parent_stmt'] \
|
||||||
|
and value is not None:
|
||||||
|
if key == 'parent' and '_parent' in items:
|
||||||
|
# parent can be a property
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
setattr(new_obj, key, new_elements[value])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
elif key in ['parent_stmt', 'parent_function']:
|
||||||
|
continue
|
||||||
|
elif isinstance(value, list):
|
||||||
|
setattr(new_obj, key, list_rec(value))
|
||||||
|
elif isinstance(value, (parsing.Simple, parsing.Call)):
|
||||||
|
setattr(new_obj, key, recursion(value))
|
||||||
|
return new_obj
|
||||||
|
|
||||||
|
def list_rec(list_obj):
|
||||||
|
copied_list = list_obj[:] # lists, tuples, strings, unicode
|
||||||
|
for i, el in enumerate(copied_list):
|
||||||
|
if isinstance(el, (parsing.Simple, parsing.Call)):
|
||||||
|
copied_list[i] = recursion(el)
|
||||||
|
elif isinstance(el, list):
|
||||||
|
copied_list[i] = list_rec(el)
|
||||||
|
return copied_list
|
||||||
|
return recursion(obj)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_param_array(args_tuple, parent_stmt=None):
|
||||||
|
""" This generates an array, that can be used as a param. """
|
||||||
|
values = []
|
||||||
|
for arg in args_tuple:
|
||||||
|
if arg is None:
|
||||||
|
values.append([])
|
||||||
|
else:
|
||||||
|
values.append([arg])
|
||||||
|
pos = None
|
||||||
|
arr = parsing.Array(pos, parsing.Array.TUPLE, parent_stmt, values=values)
|
||||||
|
evaluate.faked_scopes.append(arr)
|
||||||
|
return arr
|
||||||
|
|
||||||
|
|
||||||
|
def scan_array_for_pos(arr, pos):
|
||||||
|
"""
|
||||||
|
Returns the function Call that match search_name in an Array.
|
||||||
|
Makes changes to arr!
|
||||||
|
"""
|
||||||
|
def check_arr_index():
|
||||||
|
positions = arr.arr_el_pos
|
||||||
|
for index, comma_pos in enumerate(positions):
|
||||||
|
if pos < comma_pos:
|
||||||
|
return index
|
||||||
|
return len(positions)
|
||||||
|
|
||||||
|
call = None
|
||||||
|
stop = False
|
||||||
|
for sub in arr.values:
|
||||||
|
call = None
|
||||||
|
for s in sub:
|
||||||
|
if isinstance(s, parsing.Array):
|
||||||
|
new = scan_array_for_pos(s, pos)
|
||||||
|
if new[0] is not None:
|
||||||
|
call, index, stop = new
|
||||||
|
if stop:
|
||||||
|
return call, index, stop
|
||||||
|
elif isinstance(s, parsing.Call):
|
||||||
|
start_s = s
|
||||||
|
# check parts of calls
|
||||||
|
while s is not None:
|
||||||
|
if s.start_pos >= pos:
|
||||||
|
return call, check_arr_index(), stop
|
||||||
|
elif s.execution is not None:
|
||||||
|
end = s.execution.end_pos
|
||||||
|
if s.execution.start_pos < pos and \
|
||||||
|
(end is None or pos < end):
|
||||||
|
c, index, stop = scan_array_for_pos(
|
||||||
|
s.execution, pos)
|
||||||
|
if stop:
|
||||||
|
return c, index, stop
|
||||||
|
|
||||||
|
# call should return without execution and
|
||||||
|
# next
|
||||||
|
reset = c or s
|
||||||
|
if reset.execution.type not in \
|
||||||
|
[parsing.Array.TUPLE,
|
||||||
|
parsing.Array.NOARRAY]:
|
||||||
|
return start_s, index, False
|
||||||
|
|
||||||
|
reset.execution = None
|
||||||
|
reset.next = None
|
||||||
|
return c or start_s, index, True
|
||||||
|
s = s.next
|
||||||
|
|
||||||
|
# The third return is just necessary for recursion inside, because
|
||||||
|
# it needs to know when to stop iterating.
|
||||||
|
return call, check_arr_index(), stop
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def scale_speed_settings(factor):
|
||||||
|
a = settings.max_executions
|
||||||
|
b = settings.max_until_execution_unique
|
||||||
|
settings.max_executions *= factor
|
||||||
|
settings.max_until_execution_unique *= factor
|
||||||
|
yield
|
||||||
|
settings.max_executions = a
|
||||||
|
settings.max_until_execution_unique = b
|
332
common/.local/lib/python2.7/site-packages/jedi/imports.py
Normal file
332
common/.local/lib/python2.7/site-packages/jedi/imports.py
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
import imp
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
import builtin
|
||||||
|
import modules
|
||||||
|
import debug
|
||||||
|
import parsing
|
||||||
|
import evaluate
|
||||||
|
import itertools
|
||||||
|
import settings
|
||||||
|
|
||||||
|
# for debugging purposes only
|
||||||
|
imports_processed = 0
|
||||||
|
|
||||||
|
star_import_cache = {}
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleNotFound(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ImportPath(parsing.Base):
|
||||||
|
"""
|
||||||
|
An ImportPath is the path of a `parsing.Import` object.
|
||||||
|
"""
|
||||||
|
class _GlobalNamespace(object):
|
||||||
|
def get_defined_names(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_imports(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def start_pos(self):
|
||||||
|
return (0, 0)
|
||||||
|
|
||||||
|
def get_parent_until(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
GlobalNamespace = _GlobalNamespace()
|
||||||
|
|
||||||
|
def __init__(self, import_stmt, is_like_search=False, kill_count=0,
|
||||||
|
direct_resolve=False):
|
||||||
|
self.import_stmt = import_stmt
|
||||||
|
self.is_like_search = is_like_search
|
||||||
|
self.direct_resolve = direct_resolve
|
||||||
|
self.is_partial_import = bool(kill_count)
|
||||||
|
path = import_stmt.get_parent_until().path
|
||||||
|
self.file_path = os.path.dirname(path) if path is not None else None
|
||||||
|
|
||||||
|
# rest is import_path resolution
|
||||||
|
self.import_path = []
|
||||||
|
if import_stmt.from_ns:
|
||||||
|
self.import_path += import_stmt.from_ns.names
|
||||||
|
if import_stmt.namespace:
|
||||||
|
if self.is_nested_import() and not direct_resolve:
|
||||||
|
self.import_path.append(import_stmt.namespace.names[0])
|
||||||
|
else:
|
||||||
|
self.import_path += import_stmt.namespace.names
|
||||||
|
|
||||||
|
for i in range(kill_count + int(is_like_search)):
|
||||||
|
self.import_path.pop()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s: %s>' % (type(self).__name__, self.import_stmt)
|
||||||
|
|
||||||
|
def is_nested_import(self):
|
||||||
|
"""
|
||||||
|
This checks for the special case of nested imports, without aliases and
|
||||||
|
from statement:
|
||||||
|
>>> import foo.bar
|
||||||
|
"""
|
||||||
|
return not self.import_stmt.alias and not self.import_stmt.from_ns \
|
||||||
|
and len(self.import_stmt.namespace.names) > 1 \
|
||||||
|
and not self.direct_resolve
|
||||||
|
|
||||||
|
def get_nested_import(self, parent):
|
||||||
|
"""
|
||||||
|
See documentation of `self.is_nested_import`.
|
||||||
|
Generates an Import statement, that can be used to fake nested imports.
|
||||||
|
"""
|
||||||
|
i = self.import_stmt
|
||||||
|
# This is not an existing Import statement. Therefore, set position to
|
||||||
|
# 0 (0 is not a valid line number).
|
||||||
|
zero = (0, 0)
|
||||||
|
n = parsing.Name(i.namespace.names[1:], zero, zero, self.import_stmt)
|
||||||
|
new = parsing.Import(zero, zero, n)
|
||||||
|
new.parent = parent
|
||||||
|
evaluate.faked_scopes.append(new)
|
||||||
|
debug.dbg('Generated a nested import: %s' % new)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def get_defined_names(self, on_import_stmt=False):
|
||||||
|
names = []
|
||||||
|
for scope in self.follow():
|
||||||
|
if scope is ImportPath.GlobalNamespace:
|
||||||
|
if self.import_stmt.relative_count == 0:
|
||||||
|
names += self.get_module_names()
|
||||||
|
|
||||||
|
if self.file_path is not None:
|
||||||
|
path = os.path.abspath(self.file_path)
|
||||||
|
for i in range(self.import_stmt.relative_count - 1):
|
||||||
|
path = os.path.dirname(path)
|
||||||
|
names += self.get_module_names([path])
|
||||||
|
else:
|
||||||
|
if on_import_stmt and isinstance(scope, parsing.Module) \
|
||||||
|
and scope.path.endswith('__init__.py'):
|
||||||
|
pkg_path = os.path.dirname(scope.path)
|
||||||
|
names += self.get_module_names([pkg_path])
|
||||||
|
for s, scope_names in evaluate.get_names_for_scope(scope,
|
||||||
|
include_builtin=False):
|
||||||
|
for n in scope_names:
|
||||||
|
if self.import_stmt.from_ns is None \
|
||||||
|
or self.is_partial_import:
|
||||||
|
# from_ns must be defined to access module
|
||||||
|
# values plus a partial import means that there
|
||||||
|
# is something after the import, which
|
||||||
|
# automatically implies that there must not be
|
||||||
|
# any non-module scope.
|
||||||
|
continue
|
||||||
|
names.append(n)
|
||||||
|
return names
|
||||||
|
|
||||||
|
def get_module_names(self, search_path=None):
|
||||||
|
"""
|
||||||
|
Get the names of all modules in the search_path. This means file names
|
||||||
|
and not names defined in the files.
|
||||||
|
"""
|
||||||
|
if not search_path:
|
||||||
|
search_path = self.sys_path_with_modifications()
|
||||||
|
names = []
|
||||||
|
for module_loader, name, is_pkg in pkgutil.iter_modules(search_path):
|
||||||
|
inf_pos = (float('inf'), float('inf'))
|
||||||
|
names.append(parsing.Name([(name, inf_pos)], inf_pos, inf_pos,
|
||||||
|
self.import_stmt))
|
||||||
|
return names
|
||||||
|
|
||||||
|
def sys_path_with_modifications(self):
|
||||||
|
module = self.import_stmt.get_parent_until()
|
||||||
|
return modules.sys_path_with_modifications(module)
|
||||||
|
|
||||||
|
def follow(self, is_goto=False):
|
||||||
|
"""
|
||||||
|
Returns the imported modules.
|
||||||
|
"""
|
||||||
|
if evaluate.follow_statement.push_stmt(self.import_stmt):
|
||||||
|
# check recursion
|
||||||
|
return []
|
||||||
|
|
||||||
|
if self.import_path:
|
||||||
|
try:
|
||||||
|
scope, rest = self._follow_file_system()
|
||||||
|
except ModuleNotFound:
|
||||||
|
debug.warning('Module not found: ' + str(self.import_stmt))
|
||||||
|
evaluate.follow_statement.pop_stmt()
|
||||||
|
return []
|
||||||
|
|
||||||
|
scopes = [scope]
|
||||||
|
scopes += itertools.chain.from_iterable(
|
||||||
|
remove_star_imports(s) for s in scopes)
|
||||||
|
|
||||||
|
# follow the rest of the import (not FS -> classes, functions)
|
||||||
|
if len(rest) > 1 or rest and self.is_like_search:
|
||||||
|
scopes = []
|
||||||
|
elif rest:
|
||||||
|
if is_goto:
|
||||||
|
scopes = itertools.chain.from_iterable(
|
||||||
|
evaluate.get_scopes_for_name(s, rest[0], is_goto=True)
|
||||||
|
for s in scopes)
|
||||||
|
else:
|
||||||
|
scopes = itertools.chain.from_iterable(
|
||||||
|
evaluate.follow_path(iter(rest), s, s)
|
||||||
|
for s in scopes)
|
||||||
|
scopes = list(scopes)
|
||||||
|
|
||||||
|
if self.is_nested_import():
|
||||||
|
scopes.append(self.get_nested_import(scope))
|
||||||
|
else:
|
||||||
|
scopes = [ImportPath.GlobalNamespace]
|
||||||
|
debug.dbg('after import', scopes)
|
||||||
|
|
||||||
|
evaluate.follow_statement.pop_stmt()
|
||||||
|
return scopes
|
||||||
|
|
||||||
|
def _follow_file_system(self):
|
||||||
|
"""
|
||||||
|
Find a module with a path (of the module, like usb.backend.libusb10).
|
||||||
|
"""
|
||||||
|
def follow_str(ns, string):
|
||||||
|
debug.dbg('follow_module', ns, string)
|
||||||
|
path = None
|
||||||
|
if ns:
|
||||||
|
path = ns[1]
|
||||||
|
elif self.import_stmt.relative_count:
|
||||||
|
module = self.import_stmt.get_parent_until()
|
||||||
|
path = os.path.abspath(module.path)
|
||||||
|
for i in range(self.import_stmt.relative_count):
|
||||||
|
path = os.path.dirname(path)
|
||||||
|
|
||||||
|
global imports_processed
|
||||||
|
imports_processed += 1
|
||||||
|
if path is not None:
|
||||||
|
return imp.find_module(string, [path])
|
||||||
|
else:
|
||||||
|
debug.dbg('search_module', string, self.file_path)
|
||||||
|
# Override the sys.path. It works only good that way.
|
||||||
|
# Injecting the path directly into `find_module` did not work.
|
||||||
|
sys.path, temp = sys_path_mod, sys.path
|
||||||
|
try:
|
||||||
|
i = imp.find_module(string)
|
||||||
|
except ImportError:
|
||||||
|
sys.path = temp
|
||||||
|
raise
|
||||||
|
sys.path = temp
|
||||||
|
return i
|
||||||
|
|
||||||
|
if self.file_path:
|
||||||
|
sys_path_mod = list(self.sys_path_with_modifications())
|
||||||
|
sys_path_mod.insert(0, self.file_path)
|
||||||
|
else:
|
||||||
|
sys_path_mod = list(builtin.get_sys_path())
|
||||||
|
|
||||||
|
current_namespace = None
|
||||||
|
# now execute those paths
|
||||||
|
rest = []
|
||||||
|
for i, s in enumerate(self.import_path):
|
||||||
|
try:
|
||||||
|
current_namespace = follow_str(current_namespace, s)
|
||||||
|
except ImportError:
|
||||||
|
if current_namespace:
|
||||||
|
rest = self.import_path[i:]
|
||||||
|
else:
|
||||||
|
raise ModuleNotFound(
|
||||||
|
'The module you searched has not been found')
|
||||||
|
|
||||||
|
sys_path_mod.pop(0) # TODO why is this here?
|
||||||
|
path = current_namespace[1]
|
||||||
|
is_package_directory = current_namespace[2][2] == imp.PKG_DIRECTORY
|
||||||
|
|
||||||
|
f = None
|
||||||
|
if is_package_directory or current_namespace[0]:
|
||||||
|
# is a directory module
|
||||||
|
if is_package_directory:
|
||||||
|
path += '/__init__.py'
|
||||||
|
with open(path) as f:
|
||||||
|
source = f.read()
|
||||||
|
else:
|
||||||
|
source = current_namespace[0].read()
|
||||||
|
current_namespace[0].close()
|
||||||
|
if path.endswith('.py'):
|
||||||
|
f = modules.Module(path, source)
|
||||||
|
else:
|
||||||
|
f = builtin.Parser(path=path)
|
||||||
|
else:
|
||||||
|
f = builtin.Parser(name=path)
|
||||||
|
|
||||||
|
return f.parser.module, rest
|
||||||
|
|
||||||
|
|
||||||
|
def strip_imports(scopes):
|
||||||
|
"""
|
||||||
|
Here we strip the imports - they don't get resolved necessarily.
|
||||||
|
Really used anymore? Merge with remove_star_imports?
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
for s in scopes:
|
||||||
|
if isinstance(s, parsing.Import):
|
||||||
|
result += ImportPath(s).follow()
|
||||||
|
else:
|
||||||
|
result.append(s)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def cache_star_import(func):
|
||||||
|
def wrapper(scope, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
mods = star_import_cache[scope]
|
||||||
|
if mods[0] + settings.star_import_cache_validity > time.time():
|
||||||
|
return mods[1]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
# cache is too old and therefore invalid or not available
|
||||||
|
invalidate_star_import_cache(scope)
|
||||||
|
mods = func(scope, *args, **kwargs)
|
||||||
|
star_import_cache[scope] = time.time(), mods
|
||||||
|
|
||||||
|
return mods
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def invalidate_star_import_cache(module, only_main=False):
|
||||||
|
""" Important if some new modules are being reparsed """
|
||||||
|
try:
|
||||||
|
t, mods = star_import_cache[module]
|
||||||
|
|
||||||
|
del star_import_cache[module]
|
||||||
|
|
||||||
|
for m in mods:
|
||||||
|
invalidate_star_import_cache(m, only_main=True)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not only_main:
|
||||||
|
# We need a list here because otherwise the list is being changed
|
||||||
|
# during the iteration in py3k: iteritems -> items.
|
||||||
|
for key, (t, mods) in list(star_import_cache.items()):
|
||||||
|
if module in mods:
|
||||||
|
invalidate_star_import_cache(key)
|
||||||
|
|
||||||
|
|
||||||
|
@cache_star_import
|
||||||
|
def remove_star_imports(scope, ignored_modules=[]):
|
||||||
|
"""
|
||||||
|
Check a module for star imports:
|
||||||
|
>>> from module import *
|
||||||
|
|
||||||
|
and follow these modules.
|
||||||
|
"""
|
||||||
|
modules = strip_imports(i for i in scope.get_imports() if i.star)
|
||||||
|
new = []
|
||||||
|
for m in modules:
|
||||||
|
if m not in ignored_modules:
|
||||||
|
new += remove_star_imports(m, modules)
|
||||||
|
modules += new
|
||||||
|
|
||||||
|
# Filter duplicate modules.
|
||||||
|
return set(modules)
|
86
common/.local/lib/python2.7/site-packages/jedi/keywords.py
Normal file
86
common/.local/lib/python2.7/site-packages/jedi/keywords.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import keyword
|
||||||
|
|
||||||
|
from _compatibility import is_py3k
|
||||||
|
import builtin
|
||||||
|
|
||||||
|
import pydoc
|
||||||
|
try:
|
||||||
|
from pydoc_data import topics as pydoc_topics
|
||||||
|
except ImportError:
|
||||||
|
# Python 2.6
|
||||||
|
try:
|
||||||
|
import pydoc_topics
|
||||||
|
except ImportError:
|
||||||
|
# Python 2.5
|
||||||
|
pydoc_topics = None
|
||||||
|
|
||||||
|
if is_py3k:
|
||||||
|
keys = keyword.kwlist
|
||||||
|
else:
|
||||||
|
keys = keyword.kwlist + ['None', 'False', 'True']
|
||||||
|
|
||||||
|
|
||||||
|
def get_keywords(string='', pos=(0, 0), all=False):
|
||||||
|
if all:
|
||||||
|
return set([Keyword(k, pos) for k in keys])
|
||||||
|
if string in keys:
|
||||||
|
return set([Keyword(string, pos)])
|
||||||
|
return set()
|
||||||
|
|
||||||
|
|
||||||
|
def get_operator(string, pos):
|
||||||
|
return Keyword(string, pos)
|
||||||
|
|
||||||
|
|
||||||
|
class Keyword(object):
|
||||||
|
def __init__(self, name, pos):
|
||||||
|
self.name = name
|
||||||
|
self.start_pos = pos
|
||||||
|
self.parent = builtin.Builtin.scope
|
||||||
|
|
||||||
|
def get_parent_until(self):
|
||||||
|
return self.parent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def names(self):
|
||||||
|
""" For a `parsing.Name` like comparision """
|
||||||
|
return [self.name]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def docstr(self):
|
||||||
|
return imitate_pydoc(self.name)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s: %s>' % (type(self).__name__, self.name)
|
||||||
|
|
||||||
|
|
||||||
|
def imitate_pydoc(string):
|
||||||
|
"""
|
||||||
|
It's not possible to get the pydoc's without starting the annoying pager
|
||||||
|
stuff.
|
||||||
|
"""
|
||||||
|
# str needed because of possible unicode stuff in py2k (pydoc doesn't work
|
||||||
|
# with unicode strings)
|
||||||
|
string = str(string)
|
||||||
|
h = pydoc.help
|
||||||
|
try:
|
||||||
|
# try to access symbols
|
||||||
|
string = h.symbols[string]
|
||||||
|
string, _, related = string.partition(' ')
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
get_target = lambda s: h.topics.get(s, h.keywords.get(s))
|
||||||
|
while isinstance(string, str):
|
||||||
|
string = get_target(string)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# is a tuple now
|
||||||
|
label, related = string
|
||||||
|
except TypeError:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
return pydoc_topics.topics[label] if pydoc_topics else ''
|
||||||
|
except KeyError:
|
||||||
|
return ''
|
|
@ -0,0 +1,9 @@
|
||||||
|
class partial():
|
||||||
|
def __init__(self, func, *args, **keywords):
|
||||||
|
self.__func = func
|
||||||
|
self.__args = args
|
||||||
|
self.__keywords = keywords
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
# I know this doesn't work in Python, but Jedi can this ;-)
|
||||||
|
return self.__func(*self.__args, *args, **self.keywords, **kwargs)
|
|
@ -0,0 +1,99 @@
|
||||||
|
def compile():
|
||||||
|
class SRE_Match():
|
||||||
|
endpos = 1
|
||||||
|
lastgroup = 0
|
||||||
|
lastindex = 1
|
||||||
|
pos = 0
|
||||||
|
string = 'a'
|
||||||
|
regs = ((0, 1),)
|
||||||
|
|
||||||
|
def __init__(self, pattern):
|
||||||
|
self.re = pattern
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def span(self):
|
||||||
|
return 0, 1
|
||||||
|
|
||||||
|
def expand(self):
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def group(self):
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def groupdict(self):
|
||||||
|
return {'a', 'a'}
|
||||||
|
|
||||||
|
def groups(self):
|
||||||
|
return ('a',)
|
||||||
|
|
||||||
|
class SRE_Pattern():
|
||||||
|
flags = 0
|
||||||
|
groupindex = {}
|
||||||
|
groups = 0
|
||||||
|
pattern = 'a'
|
||||||
|
|
||||||
|
def findall(self):
|
||||||
|
"""
|
||||||
|
findall(string[, pos[, endpos]]) --> list.
|
||||||
|
Return a list of all non-overlapping matches of pattern in string.
|
||||||
|
"""
|
||||||
|
return ['a']
|
||||||
|
|
||||||
|
def finditer(self):
|
||||||
|
"""
|
||||||
|
finditer(string[, pos[, endpos]]) --> iterator.
|
||||||
|
Return an iterator over all non-overlapping matches for the
|
||||||
|
RE pattern in string. For each match, the iterator returns a
|
||||||
|
match object.
|
||||||
|
"""
|
||||||
|
yield SRE_Match(self)
|
||||||
|
|
||||||
|
def match(self):
|
||||||
|
"""
|
||||||
|
match(string[, pos[, endpos]]) --> match object or None.
|
||||||
|
Matches zero or more characters at the beginning of the string
|
||||||
|
pattern
|
||||||
|
"""
|
||||||
|
return SRE_Match(self)
|
||||||
|
|
||||||
|
def scanner(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def search(self):
|
||||||
|
"""
|
||||||
|
search(string[, pos[, endpos]]) --> match object or None.
|
||||||
|
Scan through string looking for a match, and return a corresponding
|
||||||
|
MatchObject instance. Return None if no position in the string matches.
|
||||||
|
"""
|
||||||
|
return SRE_Match(self)
|
||||||
|
|
||||||
|
def split(self):
|
||||||
|
"""
|
||||||
|
split(string[, maxsplit = 0]) --> list.
|
||||||
|
Split string by the occurrences of pattern.
|
||||||
|
"""
|
||||||
|
return ['a']
|
||||||
|
|
||||||
|
def sub(self):
|
||||||
|
"""
|
||||||
|
sub(repl, string[, count = 0]) --> newstring
|
||||||
|
Return the string obtained by replacing the leftmost non-overlapping
|
||||||
|
occurrences of pattern in string by the replacement repl.
|
||||||
|
"""
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def subn(self):
|
||||||
|
"""
|
||||||
|
subn(repl, string[, count = 0]) --> (newstring, number of subs)
|
||||||
|
Return the tuple (new_string, number_of_subs_made) found by replacing
|
||||||
|
the leftmost non-overlapping occurrences of pattern with the
|
||||||
|
replacement repl.
|
||||||
|
"""
|
||||||
|
return ('', 1)
|
||||||
|
|
||||||
|
return SRE_Pattern()
|
|
@ -0,0 +1,8 @@
|
||||||
|
def proxy(object, callback=None):
|
||||||
|
return object
|
||||||
|
|
||||||
|
class ref():
|
||||||
|
def __init__(self, object, callback=None):
|
||||||
|
self.__object = object
|
||||||
|
def __call__(self):
|
||||||
|
return self.__object
|
|
@ -0,0 +1,218 @@
|
||||||
|
"""
|
||||||
|
Pure Python implementation of some builtins.
|
||||||
|
This code is not going to be executed anywhere.
|
||||||
|
These implementations are not always correct, but should work as good as
|
||||||
|
possible for the auto completion.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def next(iterator, default=None):
|
||||||
|
if hasattr("next"):
|
||||||
|
return iterator.next()
|
||||||
|
else:
|
||||||
|
return iterator.__next__()
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def iter(collection, sentinel=None):
|
||||||
|
if sentinel:
|
||||||
|
yield collection()
|
||||||
|
else:
|
||||||
|
for c in collection:
|
||||||
|
yield c
|
||||||
|
|
||||||
|
|
||||||
|
def range(start, stop=None, step=1):
|
||||||
|
return [0]
|
||||||
|
|
||||||
|
|
||||||
|
class xrange():
|
||||||
|
# Attention: this function doesn't exist in Py3k (there it is range).
|
||||||
|
def __iter__(self):
|
||||||
|
yield 1
|
||||||
|
|
||||||
|
def count(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def index(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# descriptors
|
||||||
|
#--------------------------------------------------------
|
||||||
|
class property():
|
||||||
|
def __init__(self, fget, fset=None, fdel=None, doc=None):
|
||||||
|
self.fget = fget
|
||||||
|
self.fset = fset
|
||||||
|
self.fdel = fdel
|
||||||
|
self.__doc__ = doc
|
||||||
|
|
||||||
|
def __get__(self, obj, cls):
|
||||||
|
return self.fget(obj)
|
||||||
|
|
||||||
|
def __set__(self, obj, value):
|
||||||
|
self.fset(obj, value)
|
||||||
|
|
||||||
|
def __delete__(self, obj):
|
||||||
|
self.fdel(obj)
|
||||||
|
|
||||||
|
def setter(self, func):
|
||||||
|
self.fset = func
|
||||||
|
return self
|
||||||
|
|
||||||
|
def getter(self, func):
|
||||||
|
self.fget = func
|
||||||
|
return self
|
||||||
|
|
||||||
|
def deleter(self, func):
|
||||||
|
self.fdel = func
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class staticmethod():
|
||||||
|
def __init__(self, func):
|
||||||
|
self.__func = func
|
||||||
|
|
||||||
|
def __get__(self, obj, cls):
|
||||||
|
return self.__func
|
||||||
|
|
||||||
|
|
||||||
|
class classmethod():
|
||||||
|
def __init__(self, func):
|
||||||
|
self.__func = func
|
||||||
|
|
||||||
|
def __get__(self, obj, cls):
|
||||||
|
def _method(*args, **kwargs):
|
||||||
|
return self.__func(cls, *args, **kwargs)
|
||||||
|
return _method
|
||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# array stuff
|
||||||
|
#--------------------------------------------------------
|
||||||
|
class list():
|
||||||
|
def __init__(self, iterable=[]):
|
||||||
|
self.__iterable = []
|
||||||
|
for i in iterable:
|
||||||
|
self.__iterable += [i]
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for i in self.__iterable:
|
||||||
|
yield i
|
||||||
|
|
||||||
|
def __getitem__(self, y):
|
||||||
|
return self.__iterable[y]
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
return self.__iterable[-1]
|
||||||
|
|
||||||
|
|
||||||
|
class tuple():
|
||||||
|
def __init__(self, iterable=[]):
|
||||||
|
self.__iterable = []
|
||||||
|
for i in iterable:
|
||||||
|
self.__iterable += [i]
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for i in self.__iterable:
|
||||||
|
yield i
|
||||||
|
|
||||||
|
def __getitem__(self, y):
|
||||||
|
return self.__iterable[y]
|
||||||
|
|
||||||
|
def index(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def count(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
class set():
|
||||||
|
def __init__(self, iterable=[]):
|
||||||
|
self.__iterable = iterable
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for i in self.__iterable:
|
||||||
|
yield i
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
return self.__iterable.pop()
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def difference(self, other):
|
||||||
|
return self - other
|
||||||
|
|
||||||
|
def intersection(self, other):
|
||||||
|
return self & other
|
||||||
|
|
||||||
|
def symmetric_difference(self, other):
|
||||||
|
return self ^ other
|
||||||
|
|
||||||
|
def union(self, other):
|
||||||
|
return self | other
|
||||||
|
|
||||||
|
|
||||||
|
class frozenset():
|
||||||
|
def __init__(self, iterable=[]):
|
||||||
|
self.__iterable = iterable
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for i in self.__iterable:
|
||||||
|
yield i
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class dict():
|
||||||
|
def __init__(self, **elements):
|
||||||
|
self.__elements = elements
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
# has a strange docstr
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get(self, k, d=None):
|
||||||
|
# TODO implement
|
||||||
|
try:
|
||||||
|
#return self.__elements[k]
|
||||||
|
pass
|
||||||
|
except KeyError:
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
class reversed():
|
||||||
|
def __init__(self, sequence):
|
||||||
|
self.__sequence = sequence
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for i in self.__sequence:
|
||||||
|
yield i
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
return next(self.__iter__())
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return self.__next__()
|
||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------------------------
|
||||||
|
# basic types
|
||||||
|
#--------------------------------------------------------
|
||||||
|
class int():
|
||||||
|
def __init__(self, x, base=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class str():
|
||||||
|
def __init__(self, obj):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class object():
|
||||||
|
def mro():
|
||||||
|
""" mro() -> list
|
||||||
|
return a type's method resolution order """
|
||||||
|
return [object]
|
|
@ -0,0 +1,4 @@
|
||||||
|
class datetime():
|
||||||
|
@staticmethod
|
||||||
|
def now():
|
||||||
|
return datetime()
|
|
@ -0,0 +1,5 @@
|
||||||
|
def getcwd():
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def getcwdu():
|
||||||
|
return ''
|
312
common/.local/lib/python2.7/site-packages/jedi/modules.py
Normal file
312
common/.local/lib/python2.7/site-packages/jedi/modules.py
Normal file
|
@ -0,0 +1,312 @@
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
from _compatibility import exec_function
|
||||||
|
|
||||||
|
import re
|
||||||
|
import tokenize
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
import parsing
|
||||||
|
import builtin
|
||||||
|
import debug
|
||||||
|
import evaluate
|
||||||
|
import settings
|
||||||
|
import imports
|
||||||
|
|
||||||
|
|
||||||
|
class Module(builtin.CachedModule):
|
||||||
|
"""
|
||||||
|
Manages all files, that are parsed and caches them.
|
||||||
|
|
||||||
|
:param path: The module path of the file.
|
||||||
|
:param source: The source code of the file.
|
||||||
|
"""
|
||||||
|
def __init__(self, path, source):
|
||||||
|
super(Module, self).__init__(path=path)
|
||||||
|
self.source = source
|
||||||
|
self._line_cache = None
|
||||||
|
|
||||||
|
def _get_source(self):
|
||||||
|
""" Just one time """
|
||||||
|
s = self.source
|
||||||
|
del self.source # memory efficiency
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleWithCursor(Module):
|
||||||
|
"""
|
||||||
|
Manages all files, that are parsed and caches them.
|
||||||
|
Important are the params source and path, one of them has to
|
||||||
|
be there.
|
||||||
|
|
||||||
|
:param source: The source code of the file.
|
||||||
|
:param path: The module path of the file or None.
|
||||||
|
:param position: The position, the user is currently in. Only important \
|
||||||
|
for the main file.
|
||||||
|
"""
|
||||||
|
def __init__(self, path, source, position):
|
||||||
|
super(ModuleWithCursor, self).__init__(path, source)
|
||||||
|
self.position = position
|
||||||
|
|
||||||
|
# this two are only used, because there is no nonlocal in Python 2
|
||||||
|
self._line_temp = None
|
||||||
|
self._relevant_temp = None
|
||||||
|
|
||||||
|
self.source = source
|
||||||
|
self._part_parser = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parser(self):
|
||||||
|
""" get the parser lazy """
|
||||||
|
if not self._parser:
|
||||||
|
try:
|
||||||
|
ts, parser = builtin.CachedModule.cache[self.path]
|
||||||
|
imports.invalidate_star_import_cache(parser.module)
|
||||||
|
|
||||||
|
del builtin.CachedModule.cache[self.path]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
# Call the parser already here, because it will be used anyways.
|
||||||
|
# Also, the position is here important (which will not be used by
|
||||||
|
# default), therefore fill the cache here.
|
||||||
|
self._parser = parsing.PyFuzzyParser(self.source, self.path,
|
||||||
|
self.position)
|
||||||
|
if self.path is not None:
|
||||||
|
builtin.CachedModule.cache[self.path] = time.time(), \
|
||||||
|
self._parser
|
||||||
|
return self._parser
|
||||||
|
|
||||||
|
def get_path_until_cursor(self):
|
||||||
|
""" Get the path under the cursor. """
|
||||||
|
result = self._get_path_until_cursor()
|
||||||
|
self._start_cursor_pos = self._line_temp + 1, self._column_temp
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _get_path_until_cursor(self, start_pos=None):
|
||||||
|
def fetch_line():
|
||||||
|
line = self.get_line(self._line_temp)
|
||||||
|
if self._is_first:
|
||||||
|
self._is_first = False
|
||||||
|
self._line_length = self._column_temp
|
||||||
|
line = line[:self._column_temp]
|
||||||
|
else:
|
||||||
|
self._line_length = len(line)
|
||||||
|
line = line + '\n'
|
||||||
|
# add lines with a backslash at the end
|
||||||
|
while 1:
|
||||||
|
self._line_temp -= 1
|
||||||
|
last_line = self.get_line(self._line_temp)
|
||||||
|
if last_line and last_line[-1] == '\\':
|
||||||
|
line = last_line[:-1] + ' ' + line
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return line[::-1]
|
||||||
|
|
||||||
|
self._is_first = True
|
||||||
|
if start_pos is None:
|
||||||
|
self._line_temp = self.position[0]
|
||||||
|
self._column_temp = self.position[1]
|
||||||
|
else:
|
||||||
|
self._line_temp, self._column_temp = start_pos
|
||||||
|
|
||||||
|
open_brackets = ['(', '[', '{']
|
||||||
|
close_brackets = [')', ']', '}']
|
||||||
|
|
||||||
|
gen = tokenize.generate_tokens(fetch_line)
|
||||||
|
string = ''
|
||||||
|
level = 0
|
||||||
|
force_point = False
|
||||||
|
try:
|
||||||
|
for token_type, tok, start, end, line in gen:
|
||||||
|
#print 'tok', token_type, tok, force_point
|
||||||
|
if level > 0:
|
||||||
|
if tok in close_brackets:
|
||||||
|
level += 1
|
||||||
|
if tok in open_brackets:
|
||||||
|
level -= 1
|
||||||
|
elif tok == '.':
|
||||||
|
force_point = False
|
||||||
|
elif force_point:
|
||||||
|
# it is reversed, therefore a number is getting recognized
|
||||||
|
# as a floating point number
|
||||||
|
if token_type == tokenize.NUMBER and tok[0] == '.':
|
||||||
|
force_point = False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
elif tok in close_brackets:
|
||||||
|
level += 1
|
||||||
|
elif token_type in [tokenize.NAME, tokenize.STRING]:
|
||||||
|
force_point = True
|
||||||
|
elif token_type == tokenize.NUMBER:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
self._column_temp = self._line_length - end[1]
|
||||||
|
string += tok
|
||||||
|
except tokenize.TokenError:
|
||||||
|
debug.warning("Tokenize couldn't finish", sys.exc_info)
|
||||||
|
|
||||||
|
return string[::-1]
|
||||||
|
|
||||||
|
def get_path_under_cursor(self):
|
||||||
|
"""
|
||||||
|
Return the path under the cursor. If there is a rest of the path left,
|
||||||
|
it will be added to the stuff before it.
|
||||||
|
"""
|
||||||
|
line = self.get_line(self.position[0])
|
||||||
|
after = re.search("[\w\d]*", line[self.position[1]:]).group(0)
|
||||||
|
return self.get_path_until_cursor() + after
|
||||||
|
|
||||||
|
def get_operator_under_cursor(self):
|
||||||
|
line = self.get_line(self.position[0])
|
||||||
|
after = re.match("[^\w\s]+", line[self.position[1]:])
|
||||||
|
before = re.match("[^\w\s]+", line[:self.position[1]][::-1])
|
||||||
|
return (before.group(0) if before is not None else '') \
|
||||||
|
+ (after.group(0) if after is not None else '')
|
||||||
|
|
||||||
|
def get_context(self):
|
||||||
|
pos = self._start_cursor_pos
|
||||||
|
while pos > (1, 0):
|
||||||
|
# remove non important white space
|
||||||
|
line = self.get_line(pos[0])
|
||||||
|
while pos[1] > 0 and line[pos[1] - 1].isspace():
|
||||||
|
pos = pos[0], pos[1] - 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield self._get_path_until_cursor(start_pos=pos)
|
||||||
|
except StopIteration:
|
||||||
|
yield ''
|
||||||
|
pos = self._line_temp, self._column_temp
|
||||||
|
|
||||||
|
while True:
|
||||||
|
yield ''
|
||||||
|
|
||||||
|
def get_line(self, line_nr):
|
||||||
|
if not self._line_cache:
|
||||||
|
self._line_cache = self.source.split('\n')
|
||||||
|
|
||||||
|
if line_nr == 0:
|
||||||
|
# This is a fix for the zeroth line. We need a newline there, for
|
||||||
|
# the backwards parser.
|
||||||
|
return ''
|
||||||
|
if line_nr < 0:
|
||||||
|
raise StopIteration()
|
||||||
|
try:
|
||||||
|
return self._line_cache[line_nr - 1]
|
||||||
|
except IndexError:
|
||||||
|
raise StopIteration()
|
||||||
|
|
||||||
|
def get_part_parser(self):
|
||||||
|
""" Returns a parser that contains only part of the source code. This
|
||||||
|
exists only because of performance reasons.
|
||||||
|
"""
|
||||||
|
if self._part_parser:
|
||||||
|
return self._part_parser
|
||||||
|
|
||||||
|
# TODO check for docstrings
|
||||||
|
length = settings.part_line_length
|
||||||
|
offset = max(self.position[0] - length, 0)
|
||||||
|
s = '\n'.join(self.source.split('\n')[offset:offset + length])
|
||||||
|
self._part_parser = parsing.PyFuzzyParser(s, self.path, self.position,
|
||||||
|
line_offset=offset)
|
||||||
|
return self._part_parser
|
||||||
|
|
||||||
|
|
||||||
|
@evaluate.memoize_default([])
|
||||||
|
def sys_path_with_modifications(module):
|
||||||
|
def execute_code(code):
|
||||||
|
c = "import os; from os.path import *; result=%s"
|
||||||
|
variables = {'__file__': module.path}
|
||||||
|
try:
|
||||||
|
exec_function(c % code, variables)
|
||||||
|
except Exception:
|
||||||
|
debug.warning('sys path detected, but failed to evaluate')
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
res = variables['result']
|
||||||
|
if isinstance(res, str):
|
||||||
|
return os.path.abspath(res)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_module(module):
|
||||||
|
try:
|
||||||
|
possible_stmts = module.used_names['path']
|
||||||
|
except KeyError:
|
||||||
|
return builtin.get_sys_path()
|
||||||
|
|
||||||
|
sys_path = list(builtin.get_sys_path()) # copy
|
||||||
|
for p in possible_stmts:
|
||||||
|
try:
|
||||||
|
call = p.get_assignment_calls().get_only_subelement()
|
||||||
|
except AttributeError:
|
||||||
|
continue
|
||||||
|
n = call.name
|
||||||
|
if not isinstance(n, parsing.Name) or len(n.names) != 3:
|
||||||
|
continue
|
||||||
|
if n.names[:2] != ('sys', 'path'):
|
||||||
|
continue
|
||||||
|
array_cmd = n.names[2]
|
||||||
|
if call.execution is None:
|
||||||
|
continue
|
||||||
|
exe = call.execution
|
||||||
|
if not (array_cmd == 'insert' and len(exe) == 2
|
||||||
|
or array_cmd == 'append' and len(exe) == 1):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if array_cmd == 'insert':
|
||||||
|
exe_type, exe.type = exe.type, parsing.Array.NOARRAY
|
||||||
|
exe_pop = exe.values.pop(0)
|
||||||
|
res = execute_code(exe.get_code())
|
||||||
|
if res is not None:
|
||||||
|
sys_path.insert(0, res)
|
||||||
|
debug.dbg('sys path inserted: %s' % res)
|
||||||
|
exe.type = exe_type
|
||||||
|
exe.values.insert(0, exe_pop)
|
||||||
|
elif array_cmd == 'append':
|
||||||
|
res = execute_code(exe.get_code())
|
||||||
|
if res is not None:
|
||||||
|
sys_path.append(res)
|
||||||
|
debug.dbg('sys path added: %s' % res)
|
||||||
|
return sys_path
|
||||||
|
|
||||||
|
if module.path is None:
|
||||||
|
return [] # support for modules without a path is intentionally bad.
|
||||||
|
|
||||||
|
curdir = os.path.abspath(os.curdir)
|
||||||
|
try:
|
||||||
|
os.chdir(os.path.dirname(module.path))
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = check_module(module)
|
||||||
|
result += detect_django_path(module.path)
|
||||||
|
|
||||||
|
# cleanup, back to old directory
|
||||||
|
os.chdir(curdir)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def detect_django_path(module_path):
|
||||||
|
""" Detects the path of the very well known Django library (if used) """
|
||||||
|
result = []
|
||||||
|
while True:
|
||||||
|
new = os.path.dirname(module_path)
|
||||||
|
# If the module_path doesn't change anymore, we're finished -> /
|
||||||
|
if new == module_path:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
module_path = new
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(module_path + os.path.sep + 'manage.py'):
|
||||||
|
debug.dbg('Found django path: %s' % module_path)
|
||||||
|
result.append(module_path)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
return result
|
1855
common/.local/lib/python2.7/site-packages/jedi/parsing.py
Normal file
1855
common/.local/lib/python2.7/site-packages/jedi/parsing.py
Normal file
File diff suppressed because it is too large
Load diff
87
common/.local/lib/python2.7/site-packages/jedi/settings.py
Normal file
87
common/.local/lib/python2.7/site-packages/jedi/settings.py
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
# ----------------
|
||||||
|
# completion output settings
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
# The completion is by default case insensitive.
|
||||||
|
case_insensitive_completion = True
|
||||||
|
|
||||||
|
# Adds a dot after a module, because a module that is not accessed this way is
|
||||||
|
# definitely not the normal case. However, in VIM this doesn't work, that's why
|
||||||
|
# it isn't used at the moment.
|
||||||
|
add_dot_after_module = False
|
||||||
|
|
||||||
|
# Adds an opening bracket after a function, because that's normal behaviour.
|
||||||
|
# Removed it again, because in VIM that is not very practical.
|
||||||
|
add_bracket_after_function = False
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------
|
||||||
|
# dynamic stuff
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
# check for `append`, etc. on array instances like list()
|
||||||
|
dynamic_arrays_instances = True
|
||||||
|
# check for `append`, etc. on arrays: [], {}, ()
|
||||||
|
dynamic_array_additions = True
|
||||||
|
|
||||||
|
# A dynamic param completion, finds the callees of the function, which define
|
||||||
|
# the params of a function.
|
||||||
|
dynamic_params = True
|
||||||
|
# Do the same for other modules.
|
||||||
|
dynamic_params_for_other_modules = True
|
||||||
|
|
||||||
|
# Additional modules in which Jedi checks if statements are to be found. This
|
||||||
|
# is practical for IDE's, that want to administrate their modules themselves.
|
||||||
|
additional_dynamic_modules = []
|
||||||
|
|
||||||
|
# ----------------
|
||||||
|
# recursions
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
# Recursion settings are important if you don't want extremly recursive python
|
||||||
|
# code to go absolutely crazy. First of there is a global limit
|
||||||
|
# `max_executions`. This limit is important, to set a maximum amount of time,
|
||||||
|
# the completion may use.
|
||||||
|
#
|
||||||
|
# The `max_until_execution_unique` limit is probably the most important one,
|
||||||
|
# because if that limit is passed, functions can only be one time executed. So
|
||||||
|
# new functions will be executed, complex recursions with the same functions
|
||||||
|
# again and again, are ignored.
|
||||||
|
#
|
||||||
|
# `max_function_recursion_level` is more about whether the recursions are
|
||||||
|
# stopped in deepth or in width. The ratio beetween this and
|
||||||
|
# `max_until_execution_unique` is important here. It stops a recursion (after
|
||||||
|
# the number of function calls in the recursion), if it was already used
|
||||||
|
# earlier.
|
||||||
|
#
|
||||||
|
# The values are based on my experimental tries, used on the jedi library. But
|
||||||
|
# I don't think there's any other Python library, that uses recursion in a
|
||||||
|
# similar (extreme) way. This makes the completion definitely worse in some
|
||||||
|
# cases. But a completion should also be fast.
|
||||||
|
|
||||||
|
max_function_recursion_level = 5
|
||||||
|
max_until_execution_unique = 50
|
||||||
|
max_executions_without_builtins = 200
|
||||||
|
max_executions = 250
|
||||||
|
|
||||||
|
# Because get_in_function_call is normally used on every single key hit, it has
|
||||||
|
# to be faster than a normal completion. This is the factor that is used to
|
||||||
|
# scale `max_executions` and `max_until_execution_unique`:
|
||||||
|
scale_get_in_function_call = 0.1
|
||||||
|
|
||||||
|
# ----------------
|
||||||
|
# various
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
# Size of the current code part, which is used to speed up parsing.
|
||||||
|
part_line_length = 20
|
||||||
|
|
||||||
|
# ----------------
|
||||||
|
# star import caching
|
||||||
|
# ----------------
|
||||||
|
|
||||||
|
# In huge packages like numpy, checking all star imports on every completion
|
||||||
|
# might be slow, therefore we do a star import caching, that lasts a certain
|
||||||
|
# time span (in seconds).
|
||||||
|
|
||||||
|
star_import_cache_validity = 60.0
|
|
@ -184,7 +184,7 @@ def file_name(pl, segment_info, display_no_file=False, no_file_text='[No file]')
|
||||||
}]
|
}]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
file_name = vim_funcs['fnamemodify'](name, ':~:.:t')
|
file_name = vim_funcs['fnamemodify'](name, ':~:.:t').decode('utf-8')
|
||||||
return file_name
|
return file_name
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
ref: refs/heads/master
|
|
|
@ -1,11 +0,0 @@
|
||||||
[core]
|
|
||||||
repositoryformatversion = 0
|
|
||||||
filemode = true
|
|
||||||
bare = false
|
|
||||||
logallrefupdates = true
|
|
||||||
[remote "origin"]
|
|
||||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
|
||||||
url = https://github.com/scrooloose/nerdtree.git
|
|
||||||
[branch "master"]
|
|
||||||
remote = origin
|
|
||||||
merge = refs/heads/master
|
|
|
@ -1 +0,0 @@
|
||||||
Unnamed repository; edit this file 'description' to name the repository.
|
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# An example hook script to check the commit log message taken by
|
|
||||||
# applypatch from an e-mail message.
|
|
||||||
#
|
|
||||||
# The hook should exit with non-zero status after issuing an
|
|
||||||
# appropriate message if it wants to stop the commit. The hook is
|
|
||||||
# allowed to edit the commit message file.
|
|
||||||
#
|
|
||||||
# To enable this hook, rename this file to "applypatch-msg".
|
|
||||||
|
|
||||||
. git-sh-setup
|
|
||||||
test -x "$GIT_DIR/hooks/commit-msg" &&
|
|
||||||
exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
|
|
||||||
:
|
|
|
@ -1,24 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# An example hook script to check the commit log message.
|
|
||||||
# Called by "git commit" with one argument, the name of the file
|
|
||||||
# that has the commit message. The hook should exit with non-zero
|
|
||||||
# status after issuing an appropriate message if it wants to stop the
|
|
||||||
# commit. The hook is allowed to edit the commit message file.
|
|
||||||
#
|
|
||||||
# To enable this hook, rename this file to "commit-msg".
|
|
||||||
|
|
||||||
# Uncomment the below to add a Signed-off-by line to the message.
|
|
||||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
|
||||||
# hook is more suited to it.
|
|
||||||
#
|
|
||||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
|
||||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
|
||||||
|
|
||||||
# This example catches duplicate Signed-off-by lines.
|
|
||||||
|
|
||||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
|
||||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
|
||||||
echo >&2 Duplicate Signed-off-by lines.
|
|
||||||
exit 1
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# An example hook script to prepare a packed repository for use over
|
|
||||||
# dumb transports.
|
|
||||||
#
|
|
||||||
# To enable this hook, rename this file to "post-update".
|
|
||||||
|
|
||||||
exec git update-server-info
|
|
|
@ -1,14 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# An example hook script to verify what is about to be committed
|
|
||||||
# by applypatch from an e-mail message.
|
|
||||||
#
|
|
||||||
# The hook should exit with non-zero status after issuing an
|
|
||||||
# appropriate message if it wants to stop the commit.
|
|
||||||
#
|
|
||||||
# To enable this hook, rename this file to "pre-applypatch".
|
|
||||||
|
|
||||||
. git-sh-setup
|
|
||||||
test -x "$GIT_DIR/hooks/pre-commit" &&
|
|
||||||
exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
|
|
||||||
:
|
|
|
@ -1,50 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# An example hook script to verify what is about to be committed.
|
|
||||||
# Called by "git commit" with no arguments. The hook should
|
|
||||||
# exit with non-zero status after issuing an appropriate message if
|
|
||||||
# it wants to stop the commit.
|
|
||||||
#
|
|
||||||
# To enable this hook, rename this file to "pre-commit".
|
|
||||||
|
|
||||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
against=HEAD
|
|
||||||
else
|
|
||||||
# Initial commit: diff against an empty tree object
|
|
||||||
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If you want to allow non-ascii filenames set this variable to true.
|
|
||||||
allownonascii=$(git config hooks.allownonascii)
|
|
||||||
|
|
||||||
# Redirect output to stderr.
|
|
||||||
exec 1>&2
|
|
||||||
|
|
||||||
# Cross platform projects tend to avoid non-ascii filenames; prevent
|
|
||||||
# them from being added to the repository. We exploit the fact that the
|
|
||||||
# printable range starts at the space character and ends with tilde.
|
|
||||||
if [ "$allownonascii" != "true" ] &&
|
|
||||||
# Note that the use of brackets around a tr range is ok here, (it's
|
|
||||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
|
||||||
# the square bracket bytes happen to fall in the designated range.
|
|
||||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
|
||||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
|
||||||
then
|
|
||||||
echo "Error: Attempt to add a non-ascii file name."
|
|
||||||
echo
|
|
||||||
echo "This can cause problems if you want to work"
|
|
||||||
echo "with people on other platforms."
|
|
||||||
echo
|
|
||||||
echo "To be portable it is advisable to rename the file ..."
|
|
||||||
echo
|
|
||||||
echo "If you know what you are doing you can disable this"
|
|
||||||
echo "check using:"
|
|
||||||
echo
|
|
||||||
echo " git config hooks.allownonascii true"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If there are whitespace errors, print the offending file names and fail.
|
|
||||||
exec git diff-index --check --cached $against --
|
|
|
@ -1,169 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Copyright (c) 2006, 2008 Junio C Hamano
|
|
||||||
#
|
|
||||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
|
||||||
# its job, and can prevent the command from running by exiting with
|
|
||||||
# non-zero status.
|
|
||||||
#
|
|
||||||
# The hook is called with the following parameters:
|
|
||||||
#
|
|
||||||
# $1 -- the upstream the series was forked from.
|
|
||||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
|
||||||
#
|
|
||||||
# This sample shows how to prevent topic branches that are already
|
|
||||||
# merged to 'next' branch from getting rebased, because allowing it
|
|
||||||
# would result in rebasing already published history.
|
|
||||||
|
|
||||||
publish=next
|
|
||||||
basebranch="$1"
|
|
||||||
if test "$#" = 2
|
|
||||||
then
|
|
||||||
topic="refs/heads/$2"
|
|
||||||
else
|
|
||||||
topic=`git symbolic-ref HEAD` ||
|
|
||||||
exit 0 ;# we do not interrupt rebasing detached HEAD
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$topic" in
|
|
||||||
refs/heads/??/*)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 0 ;# we do not interrupt others.
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Now we are dealing with a topic branch being rebased
|
|
||||||
# on top of master. Is it OK to rebase it?
|
|
||||||
|
|
||||||
# Does the topic really exist?
|
|
||||||
git show-ref -q "$topic" || {
|
|
||||||
echo >&2 "No such branch $topic"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Is topic fully merged to master?
|
|
||||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
|
||||||
if test -z "$not_in_master"
|
|
||||||
then
|
|
||||||
echo >&2 "$topic is fully merged to master; better remove it."
|
|
||||||
exit 1 ;# we could allow it, but there is no point.
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Is topic ever merged to next? If so you should not be rebasing it.
|
|
||||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
|
||||||
only_next_2=`git rev-list ^master ${publish} | sort`
|
|
||||||
if test "$only_next_1" = "$only_next_2"
|
|
||||||
then
|
|
||||||
not_in_topic=`git rev-list "^$topic" master`
|
|
||||||
if test -z "$not_in_topic"
|
|
||||||
then
|
|
||||||
echo >&2 "$topic is already up-to-date with master"
|
|
||||||
exit 1 ;# we could allow it, but there is no point.
|
|
||||||
else
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
|
||||||
/usr/bin/perl -e '
|
|
||||||
my $topic = $ARGV[0];
|
|
||||||
my $msg = "* $topic has commits already merged to public branch:\n";
|
|
||||||
my (%not_in_next) = map {
|
|
||||||
/^([0-9a-f]+) /;
|
|
||||||
($1 => 1);
|
|
||||||
} split(/\n/, $ARGV[1]);
|
|
||||||
for my $elem (map {
|
|
||||||
/^([0-9a-f]+) (.*)$/;
|
|
||||||
[$1 => $2];
|
|
||||||
} split(/\n/, $ARGV[2])) {
|
|
||||||
if (!exists $not_in_next{$elem->[0]}) {
|
|
||||||
if ($msg) {
|
|
||||||
print STDERR $msg;
|
|
||||||
undef $msg;
|
|
||||||
}
|
|
||||||
print STDERR " $elem->[1]\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
' "$topic" "$not_in_next" "$not_in_master"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
<<\DOC_END
|
|
||||||
|
|
||||||
This sample hook safeguards topic branches that have been
|
|
||||||
published from being rewound.
|
|
||||||
|
|
||||||
The workflow assumed here is:
|
|
||||||
|
|
||||||
* Once a topic branch forks from "master", "master" is never
|
|
||||||
merged into it again (either directly or indirectly).
|
|
||||||
|
|
||||||
* Once a topic branch is fully cooked and merged into "master",
|
|
||||||
it is deleted. If you need to build on top of it to correct
|
|
||||||
earlier mistakes, a new topic branch is created by forking at
|
|
||||||
the tip of the "master". This is not strictly necessary, but
|
|
||||||
it makes it easier to keep your history simple.
|
|
||||||
|
|
||||||
* Whenever you need to test or publish your changes to topic
|
|
||||||
branches, merge them into "next" branch.
|
|
||||||
|
|
||||||
The script, being an example, hardcodes the publish branch name
|
|
||||||
to be "next", but it is trivial to make it configurable via
|
|
||||||
$GIT_DIR/config mechanism.
|
|
||||||
|
|
||||||
With this workflow, you would want to know:
|
|
||||||
|
|
||||||
(1) ... if a topic branch has ever been merged to "next". Young
|
|
||||||
topic branches can have stupid mistakes you would rather
|
|
||||||
clean up before publishing, and things that have not been
|
|
||||||
merged into other branches can be easily rebased without
|
|
||||||
affecting other people. But once it is published, you would
|
|
||||||
not want to rewind it.
|
|
||||||
|
|
||||||
(2) ... if a topic branch has been fully merged to "master".
|
|
||||||
Then you can delete it. More importantly, you should not
|
|
||||||
build on top of it -- other people may already want to
|
|
||||||
change things related to the topic as patches against your
|
|
||||||
"master", so if you need further changes, it is better to
|
|
||||||
fork the topic (perhaps with the same name) afresh from the
|
|
||||||
tip of "master".
|
|
||||||
|
|
||||||
Let's look at this example:
|
|
||||||
|
|
||||||
o---o---o---o---o---o---o---o---o---o "next"
|
|
||||||
/ / / /
|
|
||||||
/ a---a---b A / /
|
|
||||||
/ / / /
|
|
||||||
/ / c---c---c---c B /
|
|
||||||
/ / / \ /
|
|
||||||
/ / / b---b C \ /
|
|
||||||
/ / / / \ /
|
|
||||||
---o---o---o---o---o---o---o---o---o---o---o "master"
|
|
||||||
|
|
||||||
|
|
||||||
A, B and C are topic branches.
|
|
||||||
|
|
||||||
* A has one fix since it was merged up to "next".
|
|
||||||
|
|
||||||
* B has finished. It has been fully merged up to "master" and "next",
|
|
||||||
and is ready to be deleted.
|
|
||||||
|
|
||||||
* C has not merged to "next" at all.
|
|
||||||
|
|
||||||
We would want to allow C to be rebased, refuse A, and encourage
|
|
||||||
B to be deleted.
|
|
||||||
|
|
||||||
To compute (1):
|
|
||||||
|
|
||||||
git rev-list ^master ^topic next
|
|
||||||
git rev-list ^master next
|
|
||||||
|
|
||||||
if these match, topic has not merged in next at all.
|
|
||||||
|
|
||||||
To compute (2):
|
|
||||||
|
|
||||||
git rev-list master..topic
|
|
||||||
|
|
||||||
if this is empty, it is fully merged to "master".
|
|
||||||
|
|
||||||
DOC_END
|
|
|
@ -1,36 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# An example hook script to prepare the commit log message.
|
|
||||||
# Called by "git commit" with the name of the file that has the
|
|
||||||
# commit message, followed by the description of the commit
|
|
||||||
# message's source. The hook's purpose is to edit the commit
|
|
||||||
# message file. If the hook fails with a non-zero status,
|
|
||||||
# the commit is aborted.
|
|
||||||
#
|
|
||||||
# To enable this hook, rename this file to "prepare-commit-msg".
|
|
||||||
|
|
||||||
# This hook includes three examples. The first comments out the
|
|
||||||
# "Conflicts:" part of a merge commit.
|
|
||||||
#
|
|
||||||
# The second includes the output of "git diff --name-status -r"
|
|
||||||
# into the message, just before the "git status" output. It is
|
|
||||||
# commented because it doesn't cope with --amend or with squashed
|
|
||||||
# commits.
|
|
||||||
#
|
|
||||||
# The third example adds a Signed-off-by line to the message, that can
|
|
||||||
# still be edited. This is rarely a good idea.
|
|
||||||
|
|
||||||
case "$2,$3" in
|
|
||||||
merge,)
|
|
||||||
/usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
|
|
||||||
|
|
||||||
# ,|template,)
|
|
||||||
# /usr/bin/perl -i.bak -pe '
|
|
||||||
# print "\n" . `git diff --cached --name-status -r`
|
|
||||||
# if /^#/ && $first++ == 0' "$1" ;;
|
|
||||||
|
|
||||||
*) ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
|
||||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
|
|
@ -1,128 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# An example hook script to blocks unannotated tags from entering.
|
|
||||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
|
||||||
#
|
|
||||||
# To enable this hook, rename this file to "update".
|
|
||||||
#
|
|
||||||
# Config
|
|
||||||
# ------
|
|
||||||
# hooks.allowunannotated
|
|
||||||
# This boolean sets whether unannotated tags will be allowed into the
|
|
||||||
# repository. By default they won't be.
|
|
||||||
# hooks.allowdeletetag
|
|
||||||
# This boolean sets whether deleting tags will be allowed in the
|
|
||||||
# repository. By default they won't be.
|
|
||||||
# hooks.allowmodifytag
|
|
||||||
# This boolean sets whether a tag may be modified after creation. By default
|
|
||||||
# it won't be.
|
|
||||||
# hooks.allowdeletebranch
|
|
||||||
# This boolean sets whether deleting branches will be allowed in the
|
|
||||||
# repository. By default they won't be.
|
|
||||||
# hooks.denycreatebranch
|
|
||||||
# This boolean sets whether remotely creating branches will be denied
|
|
||||||
# in the repository. By default this is allowed.
|
|
||||||
#
|
|
||||||
|
|
||||||
# --- Command line
|
|
||||||
refname="$1"
|
|
||||||
oldrev="$2"
|
|
||||||
newrev="$3"
|
|
||||||
|
|
||||||
# --- Safety check
|
|
||||||
if [ -z "$GIT_DIR" ]; then
|
|
||||||
echo "Don't run this script from the command line." >&2
|
|
||||||
echo " (if you want, you could supply GIT_DIR then run" >&2
|
|
||||||
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
|
||||||
echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Config
|
|
||||||
allowunannotated=$(git config --bool hooks.allowunannotated)
|
|
||||||
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
|
|
||||||
denycreatebranch=$(git config --bool hooks.denycreatebranch)
|
|
||||||
allowdeletetag=$(git config --bool hooks.allowdeletetag)
|
|
||||||
allowmodifytag=$(git config --bool hooks.allowmodifytag)
|
|
||||||
|
|
||||||
# check for no description
|
|
||||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
|
||||||
case "$projectdesc" in
|
|
||||||
"Unnamed repository"* | "")
|
|
||||||
echo "*** Project description file hasn't been set" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# --- Check types
|
|
||||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
|
||||||
zero="0000000000000000000000000000000000000000"
|
|
||||||
if [ "$newrev" = "$zero" ]; then
|
|
||||||
newrev_type=delete
|
|
||||||
else
|
|
||||||
newrev_type=$(git cat-file -t $newrev)
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$refname","$newrev_type" in
|
|
||||||
refs/tags/*,commit)
|
|
||||||
# un-annotated tag
|
|
||||||
short_refname=${refname##refs/tags/}
|
|
||||||
if [ "$allowunannotated" != "true" ]; then
|
|
||||||
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
|
||||||
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
refs/tags/*,delete)
|
|
||||||
# delete tag
|
|
||||||
if [ "$allowdeletetag" != "true" ]; then
|
|
||||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
refs/tags/*,tag)
|
|
||||||
# annotated tag
|
|
||||||
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
|
||||||
then
|
|
||||||
echo "*** Tag '$refname' already exists." >&2
|
|
||||||
echo "*** Modifying a tag is not allowed in this repository." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
refs/heads/*,commit)
|
|
||||||
# branch
|
|
||||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
|
||||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
refs/heads/*,delete)
|
|
||||||
# delete branch
|
|
||||||
if [ "$allowdeletebranch" != "true" ]; then
|
|
||||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
refs/remotes/*,commit)
|
|
||||||
# tracking branch
|
|
||||||
;;
|
|
||||||
refs/remotes/*,delete)
|
|
||||||
# delete tracking branch
|
|
||||||
if [ "$allowdeletebranch" != "true" ]; then
|
|
||||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# Anything else (is there anything else?)
|
|
||||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# --- Finished
|
|
||||||
exit 0
|
|
Binary file not shown.
|
@ -1,6 +0,0 @@
|
||||||
# git ls-files --others --exclude-from=.git/info/exclude
|
|
||||||
# Lines that start with '#' are comments.
|
|
||||||
# For a project mostly in C, the following would be a good set of
|
|
||||||
# exclude patterns (uncomment them if you want to use them):
|
|
||||||
# *.[oa]
|
|
||||||
# *~
|
|
|
@ -1 +0,0 @@
|
||||||
0000000000000000000000000000000000000000 c3b63d2fd9c929359231363bcabc880ba29eb96e Christophe Buffenoir <kujiu@pakunoda.kujiu.org> 1357751567 +0100 clone: from https://github.com/scrooloose/nerdtree.git
|
|
|
@ -1 +0,0 @@
|
||||||
0000000000000000000000000000000000000000 c3b63d2fd9c929359231363bcabc880ba29eb96e Christophe Buffenoir <kujiu@pakunoda.kujiu.org> 1357751567 +0100 clone: from https://github.com/scrooloose/nerdtree.git
|
|
|
@ -1 +0,0 @@
|
||||||
0000000000000000000000000000000000000000 c3b63d2fd9c929359231363bcabc880ba29eb96e Christophe Buffenoir <kujiu@pakunoda.kujiu.org> 1357751567 +0100 clone: from https://github.com/scrooloose/nerdtree.git
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,23 +0,0 @@
|
||||||
# pack-refs with: peeled
|
|
||||||
c3b63d2fd9c929359231363bcabc880ba29eb96e refs/remotes/origin/master
|
|
||||||
57ccede2509ed5c421cc7baacc9fade973069cd6 refs/remotes/origin/refactor-open
|
|
||||||
a856622f0cc38223b5147531394829a8456ec566 refs/tags/2.10.0
|
|
||||||
95ee07c9d377c4e844d95e5272ea0152323b96e1 refs/tags/2.10.0rc1
|
|
||||||
e6d2f12bf68a55f68ec9d99d467042fc799f677d refs/tags/2.11.0
|
|
||||||
3cb3227d56959cca112f20973b41327213e3ba5a refs/tags/2.12.0
|
|
||||||
0620b91efa4041288dc69325c53b3d98e8478536 refs/tags/2.13.0
|
|
||||||
2ca4573b016a150bdb25e6a81062489e10f59463 refs/tags/2.14.0
|
|
||||||
5fcdd03f1233305be3277dc72af3d0d1e3a41c9f refs/tags/2.14.1
|
|
||||||
090791407e0b451838ad4f2eff086945f81a9d54 refs/tags/2.14.2
|
|
||||||
9aba1c17f6a2803a8cc36ffea3d5ca2f63f544b7 refs/tags/2.14.3
|
|
||||||
6a77424c253b1e2ec0d8f7d1f00a21b2fb27cb07 refs/tags/2.7.0
|
|
||||||
a5bc034851fabe38e53527b569860fdc8a4a8cce refs/tags/2.7.1
|
|
||||||
c008fb3983775f553b06db8f806757677b759113 refs/tags/2.8.0
|
|
||||||
80e0bca4dc7f5ca80712f501d662efddc83755a7 refs/tags/2.9.0
|
|
||||||
6f2401346381ccae42a818cb16ac1c52ee6728e2 refs/tags/3.0.0
|
|
||||||
efe03d6988f6835c857ff27c99ebbe6d158a0c78 refs/tags/3.0.1
|
|
||||||
bdfac3e25cd37ce757703c569f5abbcd70a2da83 refs/tags/3.1.0
|
|
||||||
e7ebee3084cfe97b2084782f004a723f83be243f refs/tags/3.1.1
|
|
||||||
241f2e9dfe866010889c9c190278b95080d944ed refs/tags/4.0.0
|
|
||||||
153041ac939502746e5a24468910eb7214a3f593 refs/tags/4.1.0
|
|
||||||
205367ab3f46dcc88b6ebb819a276e793a21e995 refs/tags/4.2.0
|
|
|
@ -1 +0,0 @@
|
||||||
c3b63d2fd9c929359231363bcabc880ba29eb96e
|
|
|
@ -1 +0,0 @@
|
||||||
ref: refs/remotes/origin/master
|
|
3
common/.vim/bundle/nerdtree/.gitignore
vendored
3
common/.vim/bundle/nerdtree/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
||||||
*~
|
|
||||||
*.swp
|
|
||||||
tags
|
|
|
@ -1,108 +0,0 @@
|
||||||
The NERD Tree
|
|
||||||
=============
|
|
||||||
|
|
||||||
Intro
|
|
||||||
-----
|
|
||||||
|
|
||||||
The NERD tree allows you to explore your filesystem and to open files and
|
|
||||||
directories. It presents the filesystem to you in the form of a tree which you
|
|
||||||
manipulate with the keyboard and/or mouse. It also allows you to perform
|
|
||||||
simple filesystem operations.
|
|
||||||
|
|
||||||
The following features and functionality are provided by the NERD tree:
|
|
||||||
|
|
||||||
* Files and directories are displayed in a hierarchical tree structure
|
|
||||||
* Different highlighting is provided for the following types of nodes:
|
|
||||||
* files
|
|
||||||
* directories
|
|
||||||
* sym-links
|
|
||||||
* windows .lnk files
|
|
||||||
* read-only files
|
|
||||||
* executable files
|
|
||||||
* Many (customisable) mappings are provided to manipulate the tree:
|
|
||||||
* Mappings to open/close/explore directory nodes
|
|
||||||
* Mappings to open files in new/existing windows/tabs
|
|
||||||
* Mappings to change the current root of the tree
|
|
||||||
* Mappings to navigate around the tree
|
|
||||||
* ...
|
|
||||||
* Directories and files can be bookmarked.
|
|
||||||
* Most NERD tree navigation can also be done with the mouse
|
|
||||||
* Filtering of tree content (can be toggled at runtime)
|
|
||||||
* custom file filters to prevent e.g. vim backup files being displayed
|
|
||||||
* optional displaying of hidden files (. files)
|
|
||||||
* files can be "turned off" so that only directories are displayed
|
|
||||||
* The position and size of the NERD tree window can be customised
|
|
||||||
* The order in which the nodes in the tree are listed can be customised.
|
|
||||||
* A model of your filesystem is created/maintained as you explore it. This
|
|
||||||
has several advantages:
|
|
||||||
* All filesystem information is cached and is only re-read on demand
|
|
||||||
* If you revisit a part of the tree that you left earlier in your
|
|
||||||
session, the directory nodes will be opened/closed as you left them
|
|
||||||
* The script remembers the cursor position and window position in the NERD
|
|
||||||
tree so you can toggle it off (or just close the tree window) and then
|
|
||||||
reopen it (with NERDTreeToggle) the NERD tree window will appear exactly
|
|
||||||
as you left it
|
|
||||||
* You can have a separate NERD tree for each tab, share trees across tabs,
|
|
||||||
or a mix of both.
|
|
||||||
* By default the script overrides the default file browser (netw), so if
|
|
||||||
you :edit a directory a (slighly modified) NERD tree will appear in the
|
|
||||||
current window
|
|
||||||
* A programmable menu system is provided (simulates right clicking on a node)
|
|
||||||
* one default menu plugin is provided to perform basic filesytem
|
|
||||||
operations (create/delete/move/copy files/directories)
|
|
||||||
* There's an API for adding your own keymappings
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
[pathogen.vim](https://github.com/tpope/vim-pathogen) is the recommended way to install nerdtree.
|
|
||||||
|
|
||||||
cd ~/.vim/bundle
|
|
||||||
git clone https://github.com/scrooloose/nerdtree.git
|
|
||||||
|
|
||||||
Then reload vim, run `:helptags`, and check out `:help NERD_tree.txt`.
|
|
||||||
|
|
||||||
|
|
||||||
Faq
|
|
||||||
---
|
|
||||||
|
|
||||||
__Q. Can I have the nerdtree on every tab automatically?__
|
|
||||||
|
|
||||||
A. Nope. If this is something you want then chances are you aren't using tabs
|
|
||||||
and buffers as they were intended to be used. Read this
|
|
||||||
http://stackoverflow.com/questions/102384/using-vims-tabs-like-buffers
|
|
||||||
|
|
||||||
If you are interested in this behaviour then consider [vim-nerdtree-tabs](https://github.com/jistr/vim-nerdtree-tabs)
|
|
||||||
|
|
||||||
__Q. How can I open a NERDTree automatically when vim starts up?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc: `autocmd vimenter * NERDTree`
|
|
||||||
|
|
||||||
__Q. How can I open a NERDTree automatically when vim starts up if no files were specified?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc `autocmd vimenter * if !argc() | NERDTree | endif`
|
|
||||||
|
|
||||||
__Q. How can I map a specific key or shortcut to open NERDTree?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc to open NERDTree with `Ctrl+n` (you can set whatever key you want): `map <C-n> :NERDTreeToggle<CR>`
|
|
||||||
|
|
||||||
__Q. How can I close vim if the only window left open is a NERDTree?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc:
|
|
||||||
|
|
||||||
`autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif`
|
|
||||||
|
|
||||||
|
|
||||||
Changelog
|
|
||||||
---------
|
|
||||||
|
|
||||||
4.2.0 (2011-12-28)
|
|
||||||
|
|
||||||
* 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 (paddyoloughlin, sdewald, camthompson, Vitaly Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!)
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,41 +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>
|
|
||||||
" Last Change: 22 July, 2009
|
|
||||||
" 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
|
|
|
@ -1,262 +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>
|
|
||||||
" Last Change: 17 July, 2009
|
|
||||||
" 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")
|
|
||||||
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 g:NERDTreePath.CopyingSupported()
|
|
||||||
call NERDTreeAddMenuItem({'text': '(c)opy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'})
|
|
||||||
endif
|
|
||||||
|
|
||||||
"FUNCTION: s:echo(msg){{{1
|
|
||||||
function! s:echo(msg)
|
|
||||||
redraw
|
|
||||||
echomsg "NERDTree: " . a:msg
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:echoWarning(msg){{{1
|
|
||||||
function! s:echoWarning(msg)
|
|
||||||
echohl warningmsg
|
|
||||||
call s:echo(a:msg)
|
|
||||||
echohl normal
|
|
||||||
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()
|
|
||||||
exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':enew! ' | endif"
|
|
||||||
exec "tabnext " . s:originalTabNumber
|
|
||||||
exec s:originalWindowNumber . "wincmd w"
|
|
||||||
" 3. We don't need a previous buffer anymore
|
|
||||||
exec "bwipeout! " . a:bufnum
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:promptToRenameBuffer(bufnum, msg){{{1
|
|
||||||
"prints out the given msg and, if the user responds by pushing 'y' then the
|
|
||||||
"buffer with the given bufnum is replaced with a new one
|
|
||||||
"
|
|
||||||
"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:promptToRenameBuffer(bufnum, msg, newFileName)
|
|
||||||
echo a:msg
|
|
||||||
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
|
|
||||||
" 1. ensure that a new buffer is loaded
|
|
||||||
exec "badd " . a:newFileName
|
|
||||||
" 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()
|
|
||||||
exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':e! " . a:newFileName . "' | endif"
|
|
||||||
exec "tabnext " . s:originalTabNumber
|
|
||||||
exec s:originalWindowNumber . "wincmd w"
|
|
||||||
" 3. We don't need a previous buffer anymore
|
|
||||||
exec "bwipeout! " . a:bufnum
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
"FUNCTION: NERDTreeAddNode(){{{1
|
|
||||||
function! NERDTreeAddNode()
|
|
||||||
let curDirNode = g:NERDTreeDirNode.GetSelected()
|
|
||||||
|
|
||||||
let newNodeName = input("Add a childnode\n".
|
|
||||||
\ "==========================================================\n".
|
|
||||||
\ "Enter the dir/file name to be created. Dirs end with a '/'\n" .
|
|
||||||
\ "", curDirNode.path.str() . g:NERDTreePath.Slash(), "file")
|
|
||||||
|
|
||||||
if newNodeName ==# ''
|
|
||||||
call s:echo("Node Creation Aborted.")
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
try
|
|
||||||
let newPath = g:NERDTreePath.Create(newNodeName)
|
|
||||||
let parentNode = b:NERDTreeRoot.findNode(newPath.getParent())
|
|
||||||
|
|
||||||
let newTreeNode = g:NERDTreeFileNode.New(newPath)
|
|
||||||
if parentNode.isOpen || !empty(parentNode.children)
|
|
||||||
call parentNode.addChild(newTreeNode, 1)
|
|
||||||
call NERDTreeRender()
|
|
||||||
call newTreeNode.putCursorHere(1, 0)
|
|
||||||
endif
|
|
||||||
catch /^NERDTree/
|
|
||||||
call s:echoWarning("Node Not Created.")
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: NERDTreeMoveNode(){{{1
|
|
||||||
function! NERDTreeMoveNode()
|
|
||||||
let curNode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
let newNodePath = input("Rename the current node\n" .
|
|
||||||
\ "==========================================================\n" .
|
|
||||||
\ "Enter the new path for the node: \n" .
|
|
||||||
\ "", curNode.path.str(), "file")
|
|
||||||
|
|
||||||
if newNodePath ==# ''
|
|
||||||
call s:echo("Node Renaming Aborted.")
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
try
|
|
||||||
let bufnum = bufnr(curNode.path.str())
|
|
||||||
|
|
||||||
call curNode.rename(newNodePath)
|
|
||||||
call NERDTreeRender()
|
|
||||||
|
|
||||||
"if the node is open in a buffer, ask the user if they want to
|
|
||||||
"close that buffer
|
|
||||||
if bufnum != -1
|
|
||||||
let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Replace this buffer with a new file? (yN)"
|
|
||||||
call s:promptToRenameBuffer(bufnum, prompt, newNodePath)
|
|
||||||
endif
|
|
||||||
|
|
||||||
call curNode.putCursorHere(1, 0)
|
|
||||||
|
|
||||||
redraw
|
|
||||||
catch /^NERDTree/
|
|
||||||
call s:echoWarning("Node Not Renamed.")
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: NERDTreeDeleteNode() {{{1
|
|
||||||
function! NERDTreeDeleteNode()
|
|
||||||
let currentNode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
let confirmed = 0
|
|
||||||
|
|
||||||
if currentNode.path.isDirectory
|
|
||||||
let choice =input("Delete the current node\n" .
|
|
||||||
\ "==========================================================\n" .
|
|
||||||
\ "STOP! To delete this entire directory, type 'yes'\n" .
|
|
||||||
\ "" . currentNode.path.str() . ": ")
|
|
||||||
let confirmed = choice ==# 'yes'
|
|
||||||
else
|
|
||||||
echo "Delete the current node\n" .
|
|
||||||
\ "==========================================================\n".
|
|
||||||
\ "Are you sure you wish to delete the node:\n" .
|
|
||||||
\ "" . currentNode.path.str() . " (yN):"
|
|
||||||
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 s:echoWarning("Could not remove node")
|
|
||||||
endtry
|
|
||||||
else
|
|
||||||
call s:echo("delete aborted")
|
|
||||||
endif
|
|
||||||
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: NERDTreeCopyNode() {{{1
|
|
||||||
function! NERDTreeCopyNode()
|
|
||||||
let currentNode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
let newNodePath = input("Copy the current node\n" .
|
|
||||||
\ "==========================================================\n" .
|
|
||||||
\ "Enter the new path to copy the node to: \n" .
|
|
||||||
\ "", currentNode.path.str(), "file")
|
|
||||||
|
|
||||||
if newNodePath != ""
|
|
||||||
"strip trailing slash
|
|
||||||
let newNodePath = substitute(newNodePath, '\/$', '', '')
|
|
||||||
|
|
||||||
let confirmed = 1
|
|
||||||
if currentNode.path.copyingWillOverwrite(newNodePath)
|
|
||||||
call s: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)
|
|
||||||
if !empty(newNode)
|
|
||||||
call NERDTreeRender()
|
|
||||||
call newNode.putCursorHere(0, 0)
|
|
||||||
endif
|
|
||||||
catch /^NERDTree/
|
|
||||||
call s:echoWarning("Could not copy node")
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call s:echo("Copy aborted.")
|
|
||||||
endif
|
|
||||||
redraw
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeQuickLook()
|
|
||||||
let treenode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if treenode != {}
|
|
||||||
call system("qlmanage -p 2>/dev/null '" . treenode.path.str() . "'")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeRevealInFinder()
|
|
||||||
let treenode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if treenode != {}
|
|
||||||
let x = system("open -R '" . treenode.path.str() . "'")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeExecuteFile()
|
|
||||||
let treenode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if treenode != {}
|
|
||||||
let x = system("open '" . treenode.path.str() . "'")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
|
@ -1,218 +0,0 @@
|
||||||
" ============================================================================
|
|
||||||
" File: NERD_tree.vim
|
|
||||||
" Description: vim global plugin that provides a nice tree explorer
|
|
||||||
" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
|
|
||||||
" Last Change: 28 December, 2011
|
|
||||||
" 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
|
|
||||||
"============================================================
|
|
||||||
if exists("loaded_nerd_tree")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
if v:version < 700
|
|
||||||
echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let loaded_nerd_tree = 1
|
|
||||||
|
|
||||||
"for line continuation - i.e dont want C in &cpo
|
|
||||||
let s:old_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
"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)
|
|
||||||
if !exists(a:var)
|
|
||||||
exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", "g") . "'"
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"SECTION: Init variable calls and other random constants {{{2
|
|
||||||
call s:initVariable("g:NERDChristmasTree", 1)
|
|
||||||
call s:initVariable("g:NERDTreeAutoCenter", 1)
|
|
||||||
call s:initVariable("g:NERDTreeAutoCenterThreshold", 3)
|
|
||||||
call s:initVariable("g:NERDTreeCaseSensitiveSort", 0)
|
|
||||||
call s:initVariable("g:NERDTreeChDirMode", 0)
|
|
||||||
call s:initVariable("g:NERDTreeMinimalUI", 0)
|
|
||||||
if !exists("g:NERDTreeIgnore")
|
|
||||||
let g:NERDTreeIgnore = ['\~$']
|
|
||||||
endif
|
|
||||||
call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks')
|
|
||||||
call s:initVariable("g:NERDTreeHighlightCursorline", 1)
|
|
||||||
call s:initVariable("g:NERDTreeHijackNetrw", 1)
|
|
||||||
call s:initVariable("g:NERDTreeMouseMode", 1)
|
|
||||||
call s:initVariable("g:NERDTreeNotificationThreshold", 100)
|
|
||||||
call s:initVariable("g:NERDTreeQuitOnOpen", 0)
|
|
||||||
call s:initVariable("g:NERDTreeShowBookmarks", 0)
|
|
||||||
call s:initVariable("g:NERDTreeShowFiles", 1)
|
|
||||||
call s:initVariable("g:NERDTreeShowHidden", 0)
|
|
||||||
call s:initVariable("g:NERDTreeShowLineNumbers", 0)
|
|
||||||
call s:initVariable("g:NERDTreeSortDirs", 1)
|
|
||||||
call s:initVariable("g:NERDTreeDirArrows", !nerdtree#runningWindows())
|
|
||||||
call s:initVariable("g:NERDTreeCasadeOpenSingleChildDir", 1)
|
|
||||||
|
|
||||||
if !exists("g:NERDTreeSortOrder")
|
|
||||||
let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$']
|
|
||||||
else
|
|
||||||
"if there isnt a * in the sort sequence then add one
|
|
||||||
if count(g:NERDTreeSortOrder, '*') < 1
|
|
||||||
call add(g:NERDTreeSortOrder, '*')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists('g:NERDTreeStatusline')
|
|
||||||
|
|
||||||
"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:NERDTreeRoot (its a b: var, and its a hash)
|
|
||||||
let g:NERDTreeStatusline = "%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''}"
|
|
||||||
|
|
||||||
endif
|
|
||||||
call s:initVariable("g:NERDTreeWinPos", "left")
|
|
||||||
call s:initVariable("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()
|
|
||||||
call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ')
|
|
||||||
else
|
|
||||||
call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ')
|
|
||||||
call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ')
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
"SECTION: Init variable calls for key mappings {{{2
|
|
||||||
call s:initVariable("g:NERDTreeMapActivateNode", "o")
|
|
||||||
call s:initVariable("g:NERDTreeMapChangeRoot", "C")
|
|
||||||
call s:initVariable("g:NERDTreeMapChdir", "cd")
|
|
||||||
call s:initVariable("g:NERDTreeMapCloseChildren", "X")
|
|
||||||
call s:initVariable("g:NERDTreeMapCloseDir", "x")
|
|
||||||
call s:initVariable("g:NERDTreeMapDeleteBookmark", "D")
|
|
||||||
call s:initVariable("g:NERDTreeMapMenu", "m")
|
|
||||||
call s:initVariable("g:NERDTreeMapHelp", "?")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpFirstChild", "K")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpLastChild", "J")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpNextSibling", "<C-j>")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpParent", "p")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpPrevSibling", "<C-k>")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpRoot", "P")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenExpl", "e")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenInTab", "t")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenRecursively", "O")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenSplit", "i")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenVSplit", "s")
|
|
||||||
call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode)
|
|
||||||
call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit)
|
|
||||||
call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit)
|
|
||||||
call s:initVariable("g:NERDTreeMapQuit", "q")
|
|
||||||
call s:initVariable("g:NERDTreeMapRefresh", "r")
|
|
||||||
call s:initVariable("g:NERDTreeMapRefreshRoot", "R")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleBookmarks", "B")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleFiles", "F")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleFilters", "f")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleHidden", "I")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleZoom", "A")
|
|
||||||
call s:initVariable("g:NERDTreeMapUpdir", "u")
|
|
||||||
call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U")
|
|
||||||
call s:initVariable("g:NERDTreeMapCWD", "CD")
|
|
||||||
|
|
||||||
"SECTION: Load class files{{{2
|
|
||||||
runtime plugin/nerdtree/path.vim
|
|
||||||
runtime plugin/nerdtree/menu_controller.vim
|
|
||||||
runtime plugin/nerdtree/menu_item.vim
|
|
||||||
runtime plugin/nerdtree/key_map.vim
|
|
||||||
runtime plugin/nerdtree/bookmark.vim
|
|
||||||
runtime plugin/nerdtree/tree_file_node.vim
|
|
||||||
runtime plugin/nerdtree/tree_dir_node.vim
|
|
||||||
runtime plugin/nerdtree/opener.vim
|
|
||||||
runtime plugin/nerdtree/creator.vim
|
|
||||||
|
|
||||||
" SECTION: Commands {{{1
|
|
||||||
"============================================================
|
|
||||||
"init the command that users start the nerd tree with
|
|
||||||
command! -n=? -complete=dir -bar NERDTree :call g:NERDTreeCreator.CreatePrimary('<args>')
|
|
||||||
command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.TogglePrimary('<args>')
|
|
||||||
command! -n=0 -bar NERDTreeClose :call nerdtree#closeTreeIfOpen()
|
|
||||||
command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreatePrimary('<args>')
|
|
||||||
command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror()
|
|
||||||
command! -n=0 -bar NERDTreeFind call nerdtree#findAndRevealPath()
|
|
||||||
command! -n=0 -bar NERDTreeFocus call NERDTreeFocus()
|
|
||||||
command! -n=0 -bar NERDTreeCWD call NERDTreeCWD()
|
|
||||||
" SECTION: Auto commands {{{1
|
|
||||||
"============================================================
|
|
||||||
augroup NERDTree
|
|
||||||
"Save the cursor position whenever we close the nerd tree
|
|
||||||
exec "autocmd BufWinLeave ". nerdtree#bufNamePrefix() ."* call nerdtree#saveScreenState()"
|
|
||||||
|
|
||||||
"disallow insert mode in the NERDTree
|
|
||||||
exec "autocmd BufEnter ". nerdtree#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
|
|
||||||
|
|
||||||
" 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 nerdtree#isTreeOpen()
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
else
|
|
||||||
call g:NERDTreeCreator.TogglePrimary("")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeCWD()
|
|
||||||
call NERDTreeFocus()
|
|
||||||
call nerdtree#chRootCwd()
|
|
||||||
endfunction
|
|
||||||
" SECTION: Post Source Actions {{{1
|
|
||||||
call nerdtree#postSourceActions()
|
|
||||||
|
|
||||||
"reset &cpo back to users setting
|
|
||||||
let &cpo = s:old_cpo
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
|
@ -1,315 +0,0 @@
|
||||||
"CLASS: Bookmark
|
|
||||||
"============================================================
|
|
||||||
let s:Bookmark = {}
|
|
||||||
let g:NERDTreeBookmark = s:Bookmark
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.activate() {{{1
|
|
||||||
function! s:Bookmark.activate(...)
|
|
||||||
call self.open(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))
|
|
||||||
call s:Bookmark.Sort()
|
|
||||||
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 to get the bookmark that has the given name. {} is return if no
|
|
||||||
" bookmark is found
|
|
||||||
function! s:Bookmark.BookmarkFor(name)
|
|
||||||
for i in s:Bookmark.Bookmarks()
|
|
||||||
if i.name ==# a:name
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"'
|
|
||||||
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 intialize
|
|
||||||
" 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', '')
|
|
||||||
|
|
||||||
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
|
|
||||||
call s:Bookmark.Sort()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.compareTo(otherbookmark) {{{1
|
|
||||||
" Compare these two bookmarks for sorting purposes
|
|
||||||
function! s:Bookmark.compareTo(otherbookmark)
|
|
||||||
return a:otherbookmark.name < self.name
|
|
||||||
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()
|
|
||||||
let node = {}
|
|
||||||
try
|
|
||||||
let node = self.getNode(1)
|
|
||||||
catch /^NERDTree.BookmarkedNodeNotFoundError/
|
|
||||||
endtry
|
|
||||||
call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self))
|
|
||||||
if !empty(node)
|
|
||||||
call node.path.cacheDisplayString()
|
|
||||||
endif
|
|
||||||
call s:Bookmark.Write()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{1
|
|
||||||
" Gets the treenode for this bookmark
|
|
||||||
"
|
|
||||||
" Args:
|
|
||||||
" searchFromAbsoluteRoot: specifies whether we should search from the current
|
|
||||||
" tree root, or the highest cached node
|
|
||||||
function! s:Bookmark.getNode(searchFromAbsoluteRoot)
|
|
||||||
let searchRoot = a:searchFromAbsoluteRoot ? g:NERDTreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot
|
|
||||||
let targetNode = searchRoot.findNode(self.path)
|
|
||||||
if empty(targetNode)
|
|
||||||
throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name
|
|
||||||
endif
|
|
||||||
return targetNode
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{1
|
|
||||||
" Class method that finds the bookmark with the given name and returns the
|
|
||||||
" treenode for it.
|
|
||||||
function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot)
|
|
||||||
let bookmark = s:Bookmark.BookmarkFor(a:name)
|
|
||||||
return bookmark.getNode(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([options]) {{{1
|
|
||||||
"Args:
|
|
||||||
"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(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
|
|
||||||
if self.path.isDirectory && !has_key(opts, 'where')
|
|
||||||
call self.toRoot()
|
|
||||||
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.Sort() {{{1
|
|
||||||
" Class method that sorts all bookmarks
|
|
||||||
function! s:Bookmark.Sort()
|
|
||||||
let CompareFunc = function("nerdtree#compareBookmarks")
|
|
||||||
call sort(s:Bookmark.Bookmarks(), CompareFunc)
|
|
||||||
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(nerdtree#getTreeWinNum()) - 4 - len(self.name)
|
|
||||||
if &nu
|
|
||||||
let pathStrMaxLen = pathStrMaxLen - &numberwidth
|
|
||||||
endif
|
|
||||||
|
|
||||||
let pathStr = self.path.str({'format': 'UI'})
|
|
||||||
if len(pathStr) > pathStrMaxLen
|
|
||||||
let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen)
|
|
||||||
endif
|
|
||||||
return '>' . self.name . ' ' . pathStr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.toRoot() {{{1
|
|
||||||
" Make the node for this bookmark the new tree root
|
|
||||||
function! s:Bookmark.toRoot()
|
|
||||||
if self.validate()
|
|
||||||
try
|
|
||||||
let targetNode = self.getNode(1)
|
|
||||||
catch /^NERDTree.BookmarkedNodeNotFoundError/
|
|
||||||
let targetNode = g:NERDTreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path)
|
|
||||||
endtry
|
|
||||||
call targetNode.makeRoot()
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call targetNode.putCursorHere(0, 0)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.ToRoot(name) {{{1
|
|
||||||
" Make the node for this bookmark the new tree root
|
|
||||||
function! s:Bookmark.ToRoot(name)
|
|
||||||
let bookmark = s:Bookmark.BookmarkFor(a:name)
|
|
||||||
call bookmark.toRoot()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.validate() {{{1
|
|
||||||
function! s:Bookmark.validate()
|
|
||||||
if self.path.exists()
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
call s:Bookmark.CacheBookmarks(1)
|
|
||||||
call nerdtree#renderView()
|
|
||||||
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 . ' ' . 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
|
|
||||||
call writefile(bookmarkStrings, g:NERDTreeBookmarksFile)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
|
@ -1,298 +0,0 @@
|
||||||
"CLASS: Creator
|
|
||||||
"Creates primary/secondary/mirror nerdtree windows. Sets up all 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()
|
|
||||||
|
|
||||||
"make <cr> do the same as the default 'o' mapping
|
|
||||||
exec "nnoremap <silent> <buffer> <cr> :call nerdtree#invokeKeyMap('". g:NERDTreeMapActivateNode ."')<cr>"
|
|
||||||
|
|
||||||
command! -buffer -nargs=? Bookmark :call nerdtree#bookmarkNode('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 RevealBookmark :call nerdtree#revealBookmark('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 OpenBookmark :call nerdtree#openBookmark('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=* ClearBookmarks call nerdtree#clearBookmarks('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=+ BookmarkToRoot call g:NERDTreeBookmark.ToRoot('<args>')
|
|
||||||
command! -buffer -nargs=0 ClearAllBookmarks call g:NERDTreeBookmark.ClearAll() <bar> call nerdtree#renderView()
|
|
||||||
command! -buffer -nargs=0 ReadBookmarks call g:NERDTreeBookmark.CacheBookmarks(0) <bar> call nerdtree#renderView()
|
|
||||||
command! -buffer -nargs=0 WriteBookmarks call g:NERDTreeBookmark.Write()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._broadcastInitEvent() {{{1
|
|
||||||
function! s:Creator._broadcastInitEvent()
|
|
||||||
silent doautocmd User NERDTreeInit
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.CreatePrimary(a:name) {{{1
|
|
||||||
function! s:Creator.CreatePrimary(name)
|
|
||||||
let creator = s:Creator.New()
|
|
||||||
call creator.createPrimary(a:name)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.createPrimary(a:name) {{{1
|
|
||||||
"name: the name of a bookmark or a directory
|
|
||||||
function! s:Creator.createPrimary(name)
|
|
||||||
let path = self._pathForString(a:name)
|
|
||||||
|
|
||||||
"if instructed to, then change the vim CWD to the dir the NERDTree is
|
|
||||||
"inited in
|
|
||||||
if g:NERDTreeChDirMode != 0
|
|
||||||
call path.changeToDir()
|
|
||||||
endif
|
|
||||||
|
|
||||||
if nerdtree#treeExistsForTab()
|
|
||||||
if nerdtree#isTreeOpen()
|
|
||||||
call nerdtree#closeTree()
|
|
||||||
endif
|
|
||||||
unlet t:NERDTreeBufName
|
|
||||||
endif
|
|
||||||
|
|
||||||
let newRoot = g:NERDTreeDirNode.New(path)
|
|
||||||
call newRoot.open()
|
|
||||||
|
|
||||||
call self._createTreeWin()
|
|
||||||
let b:treeShowHelp = 0
|
|
||||||
let b:NERDTreeIgnoreEnabled = 1
|
|
||||||
let b:NERDTreeShowFiles = g:NERDTreeShowFiles
|
|
||||||
let b:NERDTreeShowHidden = g:NERDTreeShowHidden
|
|
||||||
let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
|
|
||||||
let b:NERDTreeRoot = newRoot
|
|
||||||
let b:NERDTreeType = "primary"
|
|
||||||
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call b:NERDTreeRoot.putCursorHere(0, 0)
|
|
||||||
|
|
||||||
call self._broadcastInitEvent()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.CreateSecondary(dir) {{{1
|
|
||||||
function! s:Creator.CreateSecondary(dir)
|
|
||||||
let creator = s:Creator.New()
|
|
||||||
call creator.createSecondary(a:dir)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.createSecondary(dir) {{{1
|
|
||||||
function! s:Creator.createSecondary(dir)
|
|
||||||
try
|
|
||||||
let path = g:NERDTreePath.New(a:dir)
|
|
||||||
catch /^NERDTree.InvalidArgumentsError/
|
|
||||||
call nerdtree#echo("Invalid directory name:" . a:name)
|
|
||||||
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 secondary tree buffer to ensure they are
|
|
||||||
"all independent
|
|
||||||
exec "silent edit " . nerdtree#nextBufferName()
|
|
||||||
|
|
||||||
let b:NERDTreePreviousBuf = bufnr(previousBuf)
|
|
||||||
|
|
||||||
let b:NERDTreeRoot = g:NERDTreeDirNode.New(path)
|
|
||||||
call b:NERDTreeRoot.open()
|
|
||||||
|
|
||||||
call self._setCommonBufOptions()
|
|
||||||
let b:NERDTreeType = "secondary"
|
|
||||||
|
|
||||||
call nerdtree#renderView()
|
|
||||||
|
|
||||||
call self._broadcastInitEvent()
|
|
||||||
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 = nerdtree#tabpagevar(i, 'NERDTreeBufName')
|
|
||||||
if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName)
|
|
||||||
call add(treeBufNames, nextName)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let treeBufNames = nerdtree#unique(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, "NERDTreeRoot")
|
|
||||||
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 nerdtree#treeExistsForTab() && nerdtree#isTreeOpen()
|
|
||||||
call nerdtree#closeTree()
|
|
||||||
endif
|
|
||||||
|
|
||||||
let t:NERDTreeBufName = bufferName
|
|
||||||
call self._createTreeWin()
|
|
||||||
exec 'buffer ' . bufferName
|
|
||||||
if !&hidden
|
|
||||||
call nerdtree#renderView()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._createTreeWin() {{{1
|
|
||||||
"Inits the NERD tree window. ie. opens it, sizes it, sets all the local
|
|
||||||
"options etc
|
|
||||||
function! s:Creator._createTreeWin()
|
|
||||||
"create the nerd tree window
|
|
||||||
let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright "
|
|
||||||
let splitSize = g:NERDTreeWinSize
|
|
||||||
|
|
||||||
if !exists('t:NERDTreeBufName')
|
|
||||||
let t:NERDTreeBufName = nerdtree#nextBufferName()
|
|
||||||
silent! exec splitLocation . 'vertical ' . splitSize . ' new'
|
|
||||||
silent! exec "edit " . t:NERDTreeBufName
|
|
||||||
else
|
|
||||||
silent! exec splitLocation . 'vertical ' . splitSize . ' split'
|
|
||||||
silent! exec "buffer " . t:NERDTreeBufName
|
|
||||||
endif
|
|
||||||
|
|
||||||
setlocal winfixwidth
|
|
||||||
call self._setCommonBufOptions()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.New() {{{1
|
|
||||||
function! s:Creator.New()
|
|
||||||
let newCreator = copy(self)
|
|
||||||
return newCreator
|
|
||||||
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() . g:NERDTreePath.Slash() . dir
|
|
||||||
endif
|
|
||||||
let dir = g:NERDTreePath.Resolve(dir)
|
|
||||||
|
|
||||||
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._setCommonBufOptions() {{{1
|
|
||||||
function! s:Creator._setCommonBufOptions()
|
|
||||||
"throwaway buffer options
|
|
||||||
setlocal noswapfile
|
|
||||||
setlocal buftype=nofile
|
|
||||||
setlocal bufhidden=hide
|
|
||||||
setlocal nowrap
|
|
||||||
setlocal foldcolumn=0
|
|
||||||
setlocal foldmethod=manual
|
|
||||||
setlocal nofoldenable
|
|
||||||
setlocal nobuflisted
|
|
||||||
setlocal nospell
|
|
||||||
if g:NERDTreeShowLineNumbers
|
|
||||||
setlocal nu
|
|
||||||
else
|
|
||||||
setlocal nonu
|
|
||||||
if v:version >= 703
|
|
||||||
setlocal nornu
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
iabc <buffer>
|
|
||||||
|
|
||||||
if g:NERDTreeHighlightCursorline
|
|
||||||
setlocal cursorline
|
|
||||||
endif
|
|
||||||
|
|
||||||
call self._setupStatusline()
|
|
||||||
|
|
||||||
let b:treeShowHelp = 0
|
|
||||||
let b:NERDTreeIgnoreEnabled = 1
|
|
||||||
let b:NERDTreeShowFiles = g:NERDTreeShowFiles
|
|
||||||
let b:NERDTreeShowHidden = g:NERDTreeShowHidden
|
|
||||||
let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
|
|
||||||
setfiletype nerdtree
|
|
||||||
call self._bindMappings()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._setupStatusline() {{{1
|
|
||||||
function! s:Creator._setupStatusline()
|
|
||||||
if g:NERDTreeStatusline != -1
|
|
||||||
let &l:statusline = g:NERDTreeStatusline
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.TogglePrimary(dir) {{{1
|
|
||||||
function! s:Creator.TogglePrimary(dir)
|
|
||||||
let creator = s:Creator.New()
|
|
||||||
call creator.togglePrimary(a:dir)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.togglePrimary(dir) {{{1
|
|
||||||
"Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is
|
|
||||||
"closed it is restored or initialized (if it doesnt exist)
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"dir: the full path for the root node (is only used if the NERD tree is being
|
|
||||||
"initialized.
|
|
||||||
function! s:Creator.togglePrimary(dir)
|
|
||||||
if nerdtree#treeExistsForTab()
|
|
||||||
if !nerdtree#isTreeOpen()
|
|
||||||
call self._createTreeWin()
|
|
||||||
if !&hidden
|
|
||||||
call nerdtree#renderView()
|
|
||||||
endif
|
|
||||||
call nerdtree#restoreScreenState()
|
|
||||||
else
|
|
||||||
call nerdtree#closeTree()
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call self.createPrimary(a:dir)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
|
@ -1,143 +0,0 @@
|
||||||
"CLASS: KeyMap
|
|
||||||
"============================================================
|
|
||||||
let s:KeyMap = {}
|
|
||||||
let g:NERDTreeKeyMap = s:KeyMap
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.All() {{{1
|
|
||||||
function! s:KeyMap.All()
|
|
||||||
if !exists("s:keyMaps")
|
|
||||||
let s:keyMaps = []
|
|
||||||
endif
|
|
||||||
return s:keyMaps
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.FindFor(key, scope) {{{1
|
|
||||||
function! s:KeyMap.FindFor(key, scope)
|
|
||||||
for i in s:KeyMap.All()
|
|
||||||
if i.key ==# a:key && i.scope ==# a:scope
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.BindAll() {{{1
|
|
||||||
function! s:KeyMap.BindAll()
|
|
||||||
for i in s:KeyMap.All()
|
|
||||||
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 premap = self.key == "<LeftRelease>" ? " <LeftRelease>" : " "
|
|
||||||
|
|
||||||
exec 'nnoremap <buffer> <silent> '. self.key . premap . ':call nerdtree#invokeKeyMap("'. keymapInvokeString .'")<cr>'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.Remove(key, scope) {{{1
|
|
||||||
function! s:KeyMap.Remove(key, scope)
|
|
||||||
let maps = s:KeyMap.All()
|
|
||||||
for i in range(len(maps))
|
|
||||||
if maps[i].key ==# a:key && maps[i].scope ==# a:scope
|
|
||||||
return remove(maps, i)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.invoke() {{{1
|
|
||||||
"Call the KeyMaps callback function
|
|
||||||
function! s:KeyMap.invoke(...)
|
|
||||||
let Callback = function(self.callback)
|
|
||||||
if a:0
|
|
||||||
call Callback(a:1)
|
|
||||||
else
|
|
||||||
call 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)
|
|
||||||
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 newKeyMap = copy(self)
|
|
||||||
let opts = extend({'scope': 'all', 'quickhelpText': ''}, copy(a:options))
|
|
||||||
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)
|
|
||||||
call s:KeyMap.Remove(a:keymap.key, a:keymap.scope)
|
|
||||||
call add(s:KeyMap.All(), a:keymap)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
|
@ -1,180 +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: MenuController.showMenu() {{{1
|
|
||||||
"start the main loop of the menu and get the user to choose/execute a menu
|
|
||||||
"item
|
|
||||||
function! s:MenuController.showMenu()
|
|
||||||
call self._saveOptions()
|
|
||||||
|
|
||||||
try
|
|
||||||
let self.selection = 0
|
|
||||||
|
|
||||||
let done = 0
|
|
||||||
while !done
|
|
||||||
redraw!
|
|
||||||
call self._echoPrompt()
|
|
||||||
let key = nr2char(getchar())
|
|
||||||
let done = self._handleKeypress(key)
|
|
||||||
endwhile
|
|
||||||
finally
|
|
||||||
call self._restoreOptions()
|
|
||||||
endtry
|
|
||||||
|
|
||||||
if self.selection != -1
|
|
||||||
let m = self._current()
|
|
||||||
call m.execute()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._echoPrompt() {{{1
|
|
||||||
function! s:MenuController._echoPrompt()
|
|
||||||
echo "NERDTree Menu. Use j/k/enter and 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
|
|
||||||
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 == 'j'
|
|
||||||
call self._cursorDown()
|
|
||||||
elseif a:key == 'k'
|
|
||||||
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()
|
|
||||||
let &cmdheight = len(self.menuItems) + 3
|
|
||||||
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:
|
|
|
@ -1,114 +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 {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 = s:MenuController.New(self.children)
|
|
||||||
call mc.showMenu()
|
|
||||||
else
|
|
||||||
if self.callback != -1
|
|
||||||
call {self.callback}()
|
|
||||||
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:
|
|
|
@ -1,264 +0,0 @@
|
||||||
"CLASS: Opener
|
|
||||||
"============================================================
|
|
||||||
let s:Opener = {}
|
|
||||||
let g:NERDTreeOpener = s:Opener
|
|
||||||
|
|
||||||
"FUNCTION: Opener._checkToCloseTree(newtab) {{{1
|
|
||||||
"Check the class options and global options (i.e. NERDTreeQuitOnOpen) 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 nerdtree#closeTreeIfQuitOnOpen()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._gotoTargetWin() {{{1
|
|
||||||
function! s:Opener._gotoTargetWin()
|
|
||||||
if b:NERDTreeType ==# "secondary"
|
|
||||||
if self._where == 'v'
|
|
||||||
vsplit
|
|
||||||
elseif self._where == 'h'
|
|
||||||
split
|
|
||||||
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: Opener.New(path, opts) {{{1
|
|
||||||
"Args:
|
|
||||||
"
|
|
||||||
"a:path: The path object that is to be opened.
|
|
||||||
"
|
|
||||||
"a:opts:
|
|
||||||
"
|
|
||||||
"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' or 'h' or 't' (for open in
|
|
||||||
" new tab)
|
|
||||||
" '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:Opener.New(path, opts)
|
|
||||||
let newObj = copy(self)
|
|
||||||
|
|
||||||
let newObj._path = a:path
|
|
||||||
let newObj._stay = nerdtree#has_opt(a:opts, 'stay')
|
|
||||||
let newObj._reuse = nerdtree#has_opt(a:opts, 'reuse')
|
|
||||||
let newObj._keepopen = nerdtree#has_opt(a:opts, 'keepopen')
|
|
||||||
let newObj._where = has_key(a:opts, 'where') ? a:opts['where'] : ''
|
|
||||||
let newObj._treetype = b:NERDTreeType
|
|
||||||
call newObj._saveCursorPos()
|
|
||||||
|
|
||||||
return newObj
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._newSplit() {{{1
|
|
||||||
function! s:Opener._newSplit()
|
|
||||||
" Save the user's settings for splitbelow and splitright
|
|
||||||
let savesplitbelow=&splitbelow
|
|
||||||
let savesplitright=&splitright
|
|
||||||
|
|
||||||
" 'there' will be set to a command to move from the split window
|
|
||||||
" back to the explorer window
|
|
||||||
"
|
|
||||||
" 'back' will be set to a command to move from the explorer window
|
|
||||||
" back to the newly split window
|
|
||||||
"
|
|
||||||
" 'right' and 'below' will be set to the settings needed for
|
|
||||||
" splitbelow and splitright IF the explorer is the only window.
|
|
||||||
"
|
|
||||||
let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l"
|
|
||||||
let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h"
|
|
||||||
let right= g:NERDTreeWinPos ==# "left"
|
|
||||||
let below=0
|
|
||||||
|
|
||||||
" Attempt to go to adjacent window
|
|
||||||
call nerdtree#exec(back)
|
|
||||||
|
|
||||||
let onlyOneWin = (winnr("$") ==# 1)
|
|
||||||
|
|
||||||
" If no adjacent window, set splitright and splitbelow appropriately
|
|
||||||
if onlyOneWin
|
|
||||||
let &splitright=right
|
|
||||||
let &splitbelow=below
|
|
||||||
else
|
|
||||||
" found adjacent window - invert split direction
|
|
||||||
let &splitright=!right
|
|
||||||
let &splitbelow=!below
|
|
||||||
endif
|
|
||||||
|
|
||||||
let splitMode = onlyOneWin ? "vertical" : ""
|
|
||||||
|
|
||||||
" Open the new window
|
|
||||||
try
|
|
||||||
exec(splitMode." sp ")
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E37/
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
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
|
|
||||||
let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize
|
|
||||||
call nerdtree#exec(there)
|
|
||||||
exec("silent ". splitMode ." resize ". size)
|
|
||||||
call nerdtree#exec('wincmd p')
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Restore splitmode settings
|
|
||||||
let &splitbelow=savesplitbelow
|
|
||||||
let &splitright=savesplitright
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._newVSplit() {{{1
|
|
||||||
function! s:Opener._newVSplit()
|
|
||||||
let winwidth = winwidth(".")
|
|
||||||
if winnr("$")==#1
|
|
||||||
let winwidth = g:NERDTreeWinSize
|
|
||||||
endif
|
|
||||||
|
|
||||||
call nerdtree#exec("wincmd p")
|
|
||||||
vnew
|
|
||||||
|
|
||||||
"resize the nerd tree back to the original size
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
exec("silent vertical resize ". winwidth)
|
|
||||||
call nerdtree#exec('wincmd p')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener.open(target) {{{1
|
|
||||||
function! s:Opener.open(target)
|
|
||||||
if self._path.isDirectory
|
|
||||||
call self._openDirectory(a:target)
|
|
||||||
else
|
|
||||||
call self._openFile()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._openFile() {{{1
|
|
||||||
function! s:Opener._openFile()
|
|
||||||
if self._reuse && self._reuseWindow()
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
call self._gotoTargetWin()
|
|
||||||
|
|
||||||
if self._treetype ==# "secondary"
|
|
||||||
call self._path.edit()
|
|
||||||
else
|
|
||||||
call self._path.edit()
|
|
||||||
|
|
||||||
|
|
||||||
if self._stay
|
|
||||||
call self._restoreCursorPos()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._openDirectory(node) {{{1
|
|
||||||
function! s:Opener._openDirectory(node)
|
|
||||||
if self._treetype ==# "secondary"
|
|
||||||
call self._gotoTargetWin()
|
|
||||||
call g:NERDTreeCreator.CreateSecondary(a:node.path.str())
|
|
||||||
else
|
|
||||||
call self._gotoTargetWin()
|
|
||||||
if empty(self._where)
|
|
||||||
call a:node.makeRoot()
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call a:node.putCursorHere(0, 0)
|
|
||||||
elseif self._where == 't'
|
|
||||||
call g:NERDTreeCreator.CreatePrimary(a:node.path.str())
|
|
||||||
else
|
|
||||||
call g:NERDTreeCreator.CreateSecondary(a:node.path.str())
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if self._stay
|
|
||||||
call self._restoreCursorPos()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._previousWindow() {{{1
|
|
||||||
function! s:Opener._previousWindow()
|
|
||||||
if !nerdtree#isWindowUsable(winnr("#")) && nerdtree#firstUsableWindow() ==# -1
|
|
||||||
call self._newSplit()
|
|
||||||
else
|
|
||||||
try
|
|
||||||
if !nerdtree#isWindowUsable(winnr("#"))
|
|
||||||
call nerdtree#exec(nerdtree#firstUsableWindow() . "wincmd w")
|
|
||||||
else
|
|
||||||
call nerdtree#exec('wincmd p')
|
|
||||||
endif
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E37/
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
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('normal ' . self._tabnr . 'gt')
|
|
||||||
call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w')
|
|
||||||
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()
|
|
||||||
"check the current tab for the window
|
|
||||||
let winnr = bufwinnr('^' . self._path.str() . '$')
|
|
||||||
if winnr != -1
|
|
||||||
call nerdtree#exec(winnr . "wincmd w")
|
|
||||||
call self._checkToCloseTree(0)
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
"check other tabs
|
|
||||||
let tabnr = self._path.tabnr()
|
|
||||||
if tabnr
|
|
||||||
call self._checkToCloseTree(1)
|
|
||||||
call nerdtree#exec('normal! ' . tabnr . 'gt')
|
|
||||||
let winnr = bufwinnr('^' . self._path.str() . '$')
|
|
||||||
call nerdtree#exec(winnr . "wincmd w")
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
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:
|
|
|
@ -1,724 +0,0 @@
|
||||||
"we need to use this number many times for sorting... so we calculate it only
|
|
||||||
"once here
|
|
||||||
let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*')
|
|
||||||
|
|
||||||
"CLASS: Path
|
|
||||||
"============================================================
|
|
||||||
let s:Path = {}
|
|
||||||
let g:NERDTreePath = s:Path
|
|
||||||
|
|
||||||
"FUNCTION: Path.AbsolutePathFor(str) {{{1
|
|
||||||
function! s:Path.AbsolutePathFor(str)
|
|
||||||
let prependCWD = 0
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let prependCWD = a:str !~# '^.:\(\\\|\/\)' && a:str !~# '^\(\\\\\|\/\/\)'
|
|
||||||
else
|
|
||||||
let prependCWD = a:str !~# '^/'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let toReturn = a:str
|
|
||||||
if prependCWD
|
|
||||||
let toReturn = getcwd() . s:Path.Slash() . a:str
|
|
||||||
endif
|
|
||||||
|
|
||||||
return toReturn
|
|
||||||
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()
|
|
||||||
let self.cachedDisplayString = self.getLastPathComponent(1)
|
|
||||||
|
|
||||||
if self.isExecutable
|
|
||||||
let self.cachedDisplayString = 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)
|
|
||||||
let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if self.isSymLink
|
|
||||||
let self.cachedDisplayString .= ' -> ' . self.symLinkDest
|
|
||||||
endif
|
|
||||||
|
|
||||||
if self.isReadOnly
|
|
||||||
let self.cachedDisplayString .= ' [RO]'
|
|
||||||
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
|
|
||||||
execute "cd " . dir
|
|
||||||
call nerdtree#echo("CWD is now: " . getcwd())
|
|
||||||
catch
|
|
||||||
throw "NERDTree.PathChangeError: cannot change CWD to " . dir
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.compareTo() {{{1
|
|
||||||
"
|
|
||||||
"Compares this Path to the given path and returns 0 if they are equal, -1 if
|
|
||||||
"this Path is "less than" the given path, or 1 if it is "greater".
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: the path object to compare this to
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"1, -1 or 0
|
|
||||||
function! s:Path.compareTo(path)
|
|
||||||
let thisPath = self.getLastPathComponent(1)
|
|
||||||
let thatPath = a:path.getLastPathComponent(1)
|
|
||||||
|
|
||||||
"if the paths are the same then clearly we return 0
|
|
||||||
if thisPath ==# thatPath
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
let thisSS = self.getSortOrderIndex()
|
|
||||||
let thatSS = a:path.getSortOrderIndex()
|
|
||||||
|
|
||||||
"compare the sort sequences, if they are different then the return
|
|
||||||
"value is easy
|
|
||||||
if thisSS < thatSS
|
|
||||||
return -1
|
|
||||||
elseif thisSS > thatSS
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
"if the sort sequences are the same then compare the paths
|
|
||||||
"alphabetically
|
|
||||||
let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath <? thatPath
|
|
||||||
if pathCompare
|
|
||||||
return -1
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
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 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
|
|
||||||
|
|
||||||
let dest = s:Path.WinToUnixPath(a:dest)
|
|
||||||
|
|
||||||
let cmd = g:NERDTreeCopyCmd . " " . escape(self.str(), nerdtree#escChars()) . " " . escape(dest, nerdtree#escChars())
|
|
||||||
let success = system(cmd)
|
|
||||||
if success != 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')
|
|
||||||
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.delete() {{{1
|
|
||||||
"
|
|
||||||
"Deletes the file represented by this path.
|
|
||||||
"Deletion of directories is not supported
|
|
||||||
"
|
|
||||||
"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
|
|
||||||
let success = delete(self.str())
|
|
||||||
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()
|
|
||||||
exec "edit " . self.str({'format': 'Edit'})
|
|
||||||
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.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 self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i]
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
let i = i + 1
|
|
||||||
endwhile
|
|
||||||
return s:NERDTreeSortStarIndex
|
|
||||||
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() {{{1
|
|
||||||
"returns true if this path should be ignored
|
|
||||||
function! s:Path.ignore()
|
|
||||||
"filter out the user specified paths to ignore
|
|
||||||
if b:NERDTreeIgnoreEnabled
|
|
||||||
for i in g:NERDTreeIgnore
|
|
||||||
if self._ignorePatternMatches(i)
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
|
|
||||||
"dont show hidden files unless instructed to
|
|
||||||
if b:NERDTreeShowHidden ==# 0 && self.isUnixHiddenFile()
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if b:NERDTreeShowFiles ==# 0 && self.isDirectory ==# 0
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if exists("*NERDTreeCustomIgnoreFilter") && NERDTreeCustomIgnoreFilter(self)
|
|
||||||
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)-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.isUnder(path) {{{1
|
|
||||||
"return 1 if this path is somewhere under the given path in the filesystem.
|
|
||||||
"
|
|
||||||
"a:path should be a dir
|
|
||||||
function! s:Path.isUnder(path)
|
|
||||||
if a:path.isDirectory == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
let this = self.str()
|
|
||||||
let that = a:path.str()
|
|
||||||
return stridx(this, that . s:Path.Slash()) == 0
|
|
||||||
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)
|
|
||||||
return self.str() ==# a:path.str()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.New() {{{1
|
|
||||||
"The Constructor for the Path object
|
|
||||||
function! s:Path.New(path)
|
|
||||||
let newPath = copy(self)
|
|
||||||
|
|
||||||
call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path))
|
|
||||||
|
|
||||||
let newPath.cachedDisplayString = ""
|
|
||||||
|
|
||||||
return newPath
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.Slash() {{{1
|
|
||||||
"return the slash to use for the current OS
|
|
||||||
function! s:Path.Slash()
|
|
||||||
return nerdtree#runningWindows() ? '\' : '/'
|
|
||||||
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 = split(fullpath, '/')
|
|
||||||
|
|
||||||
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() {{{1
|
|
||||||
function! s:Path.refresh()
|
|
||||||
call self.readInfoFromDisk(self.str())
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
"
|
|
||||||
"Returns a string representation of this Path
|
|
||||||
"
|
|
||||||
"Takes an optional dictionary param to specify how the output should be
|
|
||||||
"formatted.
|
|
||||||
"
|
|
||||||
"The dict may have the following keys:
|
|
||||||
" 'format'
|
|
||||||
" 'escape'
|
|
||||||
" 'truncateTo'
|
|
||||||
"
|
|
||||||
"The 'format' key may have a value of:
|
|
||||||
" 'Cd' - a string to be used with the :cd command
|
|
||||||
" 'Edit' - a string to be used with :e :sp :new :tabedit etc
|
|
||||||
" 'UI' - a string used in the NERD tree UI
|
|
||||||
"
|
|
||||||
"The 'escape' key, if specified will cause the output to be escaped with
|
|
||||||
"shellescape()
|
|
||||||
"
|
|
||||||
"The 'truncateTo' key causes the resulting string to be truncated to the value
|
|
||||||
"'truncateTo' maps to. A '<' char will be 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
|
|
||||||
raise '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 len(toReturn) > limit
|
|
||||||
let toReturn = "<" . strpart(toReturn, len(toReturn) - limit + 1)
|
|
||||||
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
|
|
||||||
"
|
|
||||||
" returns a string that can be used with :cd
|
|
||||||
function! s:Path._strForCd()
|
|
||||||
return escape(self.str(), nerdtree#escChars())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._strForEdit() {{{1
|
|
||||||
"
|
|
||||||
"Return: the string for this path that is suitable to be used with the :edit
|
|
||||||
"command
|
|
||||||
function! s:Path._strForEdit()
|
|
||||||
let p = escape(self.str({'format': 'UI'}), nerdtree#escChars())
|
|
||||||
let cwd = getcwd() . s:Path.Slash()
|
|
||||||
|
|
||||||
"return a relative path if we can
|
|
||||||
let isRelative = 0
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let isRelative = stridx(tolower(p), tolower(cwd)) == 0
|
|
||||||
else
|
|
||||||
let isRelative = stridx(p, cwd) == 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
if isRelative
|
|
||||||
let p = strpart(p, strlen(cwd))
|
|
||||||
|
|
||||||
"handle the edge case where the file begins with a + (vim interprets
|
|
||||||
"the +foo in `:e +foo` as an option to :edit)
|
|
||||||
if p[0] == "+"
|
|
||||||
let p = '\' . p
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if p ==# ''
|
|
||||||
let p = '.'
|
|
||||||
endif
|
|
||||||
|
|
||||||
return p
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._strForGlob() {{{1
|
|
||||||
function! s:Path._strForGlob()
|
|
||||||
let lead = s:Path.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, s:Path.Slash())
|
|
||||||
|
|
||||||
if !nerdtree#runningWindows()
|
|
||||||
let toReturn = escape(toReturn, nerdtree#escChars())
|
|
||||||
endif
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._str() {{{1
|
|
||||||
"
|
|
||||||
"Gets the string path for this path object that is appropriate for the OS.
|
|
||||||
"EG, in windows c:\foo\bar
|
|
||||||
" in *nix /foo/bar
|
|
||||||
function! s:Path._str()
|
|
||||||
let lead = s:Path.Slash()
|
|
||||||
|
|
||||||
"if we are running windows then slap a drive letter on the front
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let lead = self.drive . '\'
|
|
||||||
endif
|
|
||||||
|
|
||||||
return lead . join(self.pathSegments, s:Path.Slash())
|
|
||||||
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:
|
|
|
@ -1,528 +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:NERDTreeRoot
|
|
||||||
while currentNode.parent != {}
|
|
||||||
let currentNode = currentNode.parent
|
|
||||||
endwhile
|
|
||||||
return currentNode
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.activate([options]) {{{1
|
|
||||||
unlet s:TreeDirNode.activate
|
|
||||||
function! s:TreeDirNode.activate(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
call self.toggleOpen(opts)
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call self.putCursorHere(0, 0)
|
|
||||||
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
|
|
||||||
"Closes this directory
|
|
||||||
function! s:TreeDirNode.close()
|
|
||||||
let self.isOpen = 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.closeChildren() {{{1
|
|
||||||
"Closes all the child dir nodes of this node
|
|
||||||
function! s:TreeDirNode.closeChildren()
|
|
||||||
for i in self.children
|
|
||||||
if i.path.isDirectory
|
|
||||||
call i.close()
|
|
||||||
call i.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)
|
|
||||||
call self.addChild(newTreeNode, a:inOrder)
|
|
||||||
return newTreeNode
|
|
||||||
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.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 = a:path.compareTo(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.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() ==# 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._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 = []
|
|
||||||
|
|
||||||
"get an array of all the files in the nodes dir
|
|
||||||
let dir = self.path
|
|
||||||
let globDir = dir.str({'format': 'Glob'})
|
|
||||||
|
|
||||||
if version >= 703
|
|
||||||
let filesStr = globpath(globDir, '*', 1) . "\n" . globpath(globDir, '.*', 1)
|
|
||||||
else
|
|
||||||
let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*')
|
|
||||||
endif
|
|
||||||
|
|
||||||
let files = split(filesStr, "\n")
|
|
||||||
|
|
||||||
if !a:silent && len(files) > g:NERDTreeNotificationThreshold
|
|
||||||
call nerdtree#echo("Please wait, caching a large dir ...")
|
|
||||||
endif
|
|
||||||
|
|
||||||
let invalidFilesFound = 0
|
|
||||||
for i in files
|
|
||||||
|
|
||||||
"filter out the .. and . directories
|
|
||||||
"Note: we must match .. AND ../ cos sometimes the globpath returns
|
|
||||||
"../ for path with strange chars (eg $)
|
|
||||||
if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$'
|
|
||||||
|
|
||||||
"put the next file in a new node and attach it
|
|
||||||
try
|
|
||||||
let path = g:NERDTreePath.New(i)
|
|
||||||
call self.createChild(path, 0)
|
|
||||||
catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
|
|
||||||
let invalidFilesFound += 1
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
call self.sortChildren()
|
|
||||||
|
|
||||||
if !a:silent && len(files) > g:NERDTreeNotificationThreshold
|
|
||||||
call nerdtree#echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).")
|
|
||||||
endif
|
|
||||||
|
|
||||||
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) {{{1
|
|
||||||
"Returns a new TreeNode object with the given path and parent
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a path object representing the full filesystem path to the file/dir that the node represents
|
|
||||||
unlet s:TreeDirNode.New
|
|
||||||
function! s:TreeDirNode.New(path)
|
|
||||||
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 = {}
|
|
||||||
|
|
||||||
return newTreeNode
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.open([opts]) {{{1
|
|
||||||
"Open the dir in the current tree or in a new tree elsewhere.
|
|
||||||
"
|
|
||||||
"If opening in the current tree, return the number of cached nodes.
|
|
||||||
unlet s:TreeDirNode.open
|
|
||||||
function! s:TreeDirNode.open(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
|
|
||||||
if has_key(opts, 'where') && !empty(opts['where'])
|
|
||||||
let opener = g:NERDTreeOpener.New(self.path, opts)
|
|
||||||
call opener.open(self)
|
|
||||||
else
|
|
||||||
let self.isOpen = 1
|
|
||||||
if self.children ==# []
|
|
||||||
return self._initChildren(0)
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
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
|
|
||||||
" opens an explorer window for this node in the previous window (could be a
|
|
||||||
" nerd tree or a netrw)
|
|
||||||
function! s:TreeDirNode.openExplorer()
|
|
||||||
call self.open({'where': 'p'})
|
|
||||||
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.CreatePrimary(self.path.str())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.openRecursively() {{{1
|
|
||||||
"Opens this treenode and all of its children whose paths arent 'ignored'
|
|
||||||
"because of the file filters.
|
|
||||||
"
|
|
||||||
"This method is actually a wrapper for the OpenRecursively2 method which does
|
|
||||||
"the work.
|
|
||||||
function! s:TreeDirNode.openRecursively()
|
|
||||||
call self._openRecursively2(1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode._openRecursively2() {{{1
|
|
||||||
"Opens this all children of this treenode recursively if either:
|
|
||||||
" *they arent filtered by file filters
|
|
||||||
" *a:forceOpen is 1
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"forceOpen: 1 if this node should be opened regardless of file filters
|
|
||||||
function! s:TreeDirNode._openRecursively2(forceOpen)
|
|
||||||
if self.path.ignore() ==# 0 || a:forceOpen
|
|
||||||
let self.isOpen = 1
|
|
||||||
if self.children ==# []
|
|
||||||
call self._initChildren(1)
|
|
||||||
endif
|
|
||||||
|
|
||||||
for i in self.children
|
|
||||||
if i.path.isDirectory ==# 1
|
|
||||||
call i._openRecursively2(0)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.refresh() {{{1
|
|
||||||
unlet s:TreeDirNode.refresh
|
|
||||||
function! s:TreeDirNode.refresh()
|
|
||||||
call self.path.refresh()
|
|
||||||
|
|
||||||
"if this node was ever opened, refresh its children
|
|
||||||
if self.isOpen || !empty(self.children)
|
|
||||||
"go thru all the files/dirs under this node
|
|
||||||
let newChildNodes = []
|
|
||||||
let invalidFilesFound = 0
|
|
||||||
let dir = self.path
|
|
||||||
let globDir = dir.str({'format': 'Glob'})
|
|
||||||
let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*')
|
|
||||||
let files = split(filesStr, "\n")
|
|
||||||
for i in files
|
|
||||||
"filter out the .. and . directories
|
|
||||||
"Note: we must match .. AND ../ cos sometimes the globpath returns
|
|
||||||
"../ for path with strange chars (eg $)
|
|
||||||
if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$'
|
|
||||||
|
|
||||||
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)
|
|
||||||
let newNode.parent = self
|
|
||||||
call add(newChildNodes, newNode)
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
catch /^NERDTree.InvalidArgumentsError/
|
|
||||||
let invalidFilesFound = 1
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
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.reveal(path) {{{1
|
|
||||||
"reveal the given path, i.e. cache and open all treenodes needed to display it
|
|
||||||
"in the UI
|
|
||||||
function! s:TreeDirNode.reveal(path)
|
|
||||||
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)
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call n.putCursorHere(1,0)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let p = a:path
|
|
||||||
while !p.getParent().equals(self.path)
|
|
||||||
let p = p.getParent()
|
|
||||||
endwhile
|
|
||||||
|
|
||||||
let n = self.findNode(p)
|
|
||||||
call n.reveal(a:path)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.removeChild(treenode) {{{1
|
|
||||||
"
|
|
||||||
"Removes the given treenode from this nodes set of children
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"treenode: the node to remove
|
|
||||||
"
|
|
||||||
"Throws a NERDTree.ChildNotFoundError if the given treenode is not found
|
|
||||||
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
|
|
||||||
"
|
|
||||||
"Sorts the children of this node according to alphabetical order and the
|
|
||||||
"directory priority.
|
|
||||||
"
|
|
||||||
function! s:TreeDirNode.sortChildren()
|
|
||||||
let CompareFunc = function("nerdtree#compareNodes")
|
|
||||||
call sort(self.children, CompareFunc)
|
|
||||||
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:NERDTreeCasadeOpenSingleChildDir == 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:
|
|
|
@ -1,485 +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 treenode
|
|
||||||
"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)
|
|
||||||
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)
|
|
||||||
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 = b:NERDTreeRoot.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.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.findOpenDirSiblingWithVisibleChildren(direction) {{{1
|
|
||||||
"
|
|
||||||
"Finds the next sibling for this node in the indicated direction. This sibling
|
|
||||||
"must be a directory and may/may not have children as specified.
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"direction: 0 if you want to find the previous sibling, 1 for the next sibling
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"a treenode object or {} if no appropriate sibling could be found
|
|
||||||
function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
|
|
||||||
"if we have no parent then we can have no siblings
|
|
||||||
if self.parent != {}
|
|
||||||
let nextSibling = self.findSibling(a:direction)
|
|
||||||
|
|
||||||
while nextSibling != {}
|
|
||||||
if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen
|
|
||||||
return nextSibling
|
|
||||||
endif
|
|
||||||
let nextSibling = nextSibling.findSibling(a:direction)
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.findSibling(direction) {{{1
|
|
||||||
"
|
|
||||||
"Finds the next sibling for this node in the indicated direction
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"direction: 0 if you want to find the previous sibling, 1 for the next sibling
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"a treenode object or {} if no sibling could be found
|
|
||||||
function! s:TreeFileNode.findSibling(direction)
|
|
||||||
"if we have no parent then we can have no siblings
|
|
||||||
if self.parent != {}
|
|
||||||
|
|
||||||
"get the index of this node in its parents children
|
|
||||||
let siblingIndx = self.parent.getChildIndex(self.path)
|
|
||||||
|
|
||||||
if siblingIndx != -1
|
|
||||||
"move a long to the next potential sibling node
|
|
||||||
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
|
|
||||||
|
|
||||||
"keep moving along to the next sibling till we find one that is valid
|
|
||||||
let numSiblings = self.parent.getChildCount()
|
|
||||||
while siblingIndx >= 0 && siblingIndx < numSiblings
|
|
||||||
|
|
||||||
"if the next node is not an ignored node (i.e. wont show up in the
|
|
||||||
"view) then return it
|
|
||||||
if self.parent.children[siblingIndx].path.ignore() ==# 0
|
|
||||||
return self.parent.children[siblingIndx]
|
|
||||||
endif
|
|
||||||
|
|
||||||
"go to next node
|
|
||||||
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.getLineNum(){{{1
|
|
||||||
"returns the line number this node is rendered on, or -1 if it isnt rendered
|
|
||||||
function! s:TreeFileNode.getLineNum()
|
|
||||||
"if the node is the root then return the root line no.
|
|
||||||
if self.isRoot()
|
|
||||||
return s:TreeFileNode.GetRootLineNum()
|
|
||||||
endif
|
|
||||||
|
|
||||||
let totalLines = line("$")
|
|
||||||
|
|
||||||
"the path components we have matched so far
|
|
||||||
let pathcomponents = [substitute(b:NERDTreeRoot.path.str({'format': 'UI'}), '/ *$', '', '')]
|
|
||||||
"the index of the component we are searching for
|
|
||||||
let curPathComponent = 1
|
|
||||||
|
|
||||||
let fullpath = self.path.str({'format': 'UI'})
|
|
||||||
|
|
||||||
|
|
||||||
let lnum = s:TreeFileNode.GetRootLineNum()
|
|
||||||
while lnum > 0
|
|
||||||
let lnum = lnum + 1
|
|
||||||
"have we reached the bottom of the tree?
|
|
||||||
if lnum ==# totalLines+1
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
let curLine = getline(lnum)
|
|
||||||
|
|
||||||
let indent = nerdtree#indentLevelFor(curLine)
|
|
||||||
if indent ==# curPathComponent
|
|
||||||
let curLine = nerdtree#stripMarkupFromLine(curLine, 1)
|
|
||||||
|
|
||||||
let curPath = join(pathcomponents, '/') . '/' . curLine
|
|
||||||
if stridx(fullpath, curPath, 0) ==# 0
|
|
||||||
if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/'
|
|
||||||
let curLine = substitute(curLine, '/ *$', '', '')
|
|
||||||
call add(pathcomponents, curLine)
|
|
||||||
let curPathComponent = curPathComponent + 1
|
|
||||||
|
|
||||||
if fullpath ==# curPath
|
|
||||||
return lnum
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.GetRootForTab(){{{1
|
|
||||||
"get the root node for this tab
|
|
||||||
function! s:TreeFileNode.GetRootForTab()
|
|
||||||
if nerdtree#treeExistsForTab()
|
|
||||||
return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot')
|
|
||||||
end
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.GetRootLineNum(){{{1
|
|
||||||
"gets the line number of the root node
|
|
||||||
function! s:TreeFileNode.GetRootLineNum()
|
|
||||||
let rootLine = 1
|
|
||||||
while getline(rootLine) !~# '^\(/\|<\)'
|
|
||||||
let rootLine = rootLine + 1
|
|
||||||
endwhile
|
|
||||||
return rootLine
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.GetSelected() {{{1
|
|
||||||
"gets the treenode that the cursor is currently over
|
|
||||||
function! s:TreeFileNode.GetSelected()
|
|
||||||
try
|
|
||||||
let path = nerdtree#getPath(line("."))
|
|
||||||
if path ==# {}
|
|
||||||
return {}
|
|
||||||
endif
|
|
||||||
return b:NERDTreeRoot.findNode(path)
|
|
||||||
catch /^NERDTree/
|
|
||||||
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()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.isRoot() {{{1
|
|
||||||
"returns 1 if this node is b:NERDTreeRoot
|
|
||||||
function! s:TreeFileNode.isRoot()
|
|
||||||
if !nerdtree#treeExistsForBuf()
|
|
||||||
throw "NERDTree.NoTreeError: No tree exists for the current buffer"
|
|
||||||
endif
|
|
||||||
|
|
||||||
return self.equals(b:NERDTreeRoot)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.makeRoot() {{{1
|
|
||||||
"Make this node the root of the tree
|
|
||||||
function! s:TreeFileNode.makeRoot()
|
|
||||||
if self.path.isDirectory
|
|
||||||
let b:NERDTreeRoot = self
|
|
||||||
else
|
|
||||||
call self.cacheParent()
|
|
||||||
let b:NERDTreeRoot = self.parent
|
|
||||||
endif
|
|
||||||
|
|
||||||
call b:NERDTreeRoot.open()
|
|
||||||
|
|
||||||
"change dir to the dir of the new root if instructed to
|
|
||||||
if g:NERDTreeChDirMode ==# 2
|
|
||||||
exec "cd " . b:NERDTreeRoot.path.str({'format': 'Edit'})
|
|
||||||
endif
|
|
||||||
|
|
||||||
silent doautocmd User NERDTreeNewRoot
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.New(path) {{{1
|
|
||||||
"Returns a new TreeNode object with the given path and parent
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a path object representing the full filesystem path to the file/dir that the node represents
|
|
||||||
function! s:TreeFileNode.New(path)
|
|
||||||
if a:path.isDirectory
|
|
||||||
return g:NERDTreeDirNode.New(a:path)
|
|
||||||
else
|
|
||||||
let newTreeNode = copy(self)
|
|
||||||
let newTreeNode.path = a:path
|
|
||||||
let newTreeNode.parent = {}
|
|
||||||
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)
|
|
||||||
echomsg 'TreeFileNode.openInNewTab is deprecated'
|
|
||||||
call self.open(extend({'where': 't'}, a:options))
|
|
||||||
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.getLineNum()
|
|
||||||
if ln != -1
|
|
||||||
if a:isJump
|
|
||||||
mark '
|
|
||||||
endif
|
|
||||||
call cursor(ln, col("."))
|
|
||||||
else
|
|
||||||
if a:recurseUpward
|
|
||||||
let node = self
|
|
||||||
while node != {} && node.getLineNum() ==# -1
|
|
||||||
let node = node.parent
|
|
||||||
call node.open()
|
|
||||||
endwhile
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call node.putCursorHere(a:isJump, 0)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.refresh() {{{1
|
|
||||||
function! s:TreeFileNode.refresh()
|
|
||||||
call self.path.refresh()
|
|
||||||
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 = b:NERDTreeRoot.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, [], self.getChildCount() ==# 1)
|
|
||||||
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)
|
|
||||||
"vertMap: a binary array that indicates whether a vertical bar should be draw
|
|
||||||
"for each depth in the tree
|
|
||||||
"isLastChild:true if this curNode is the last child of its parent
|
|
||||||
function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild)
|
|
||||||
let output = ""
|
|
||||||
if a:drawText ==# 1
|
|
||||||
|
|
||||||
let treeParts = ''
|
|
||||||
|
|
||||||
"get all the leading spaces and vertical tree parts for this line
|
|
||||||
if a:depth > 1
|
|
||||||
for j in a:vertMap[0:-2]
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . ' '
|
|
||||||
else
|
|
||||||
if j ==# 1
|
|
||||||
let treeParts = treeParts . '| '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . ' '
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
|
|
||||||
"get the last vertical tree part for this line which will be different
|
|
||||||
"if this node is the last child of its parent
|
|
||||||
if !g:NERDTreeDirArrows
|
|
||||||
if a:isLastChild
|
|
||||||
let treeParts = treeParts . '`'
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '|'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
"smack the appropriate dir/file symbol on the line before the file/dir
|
|
||||||
"name itself
|
|
||||||
if self.path.isDirectory
|
|
||||||
if self.isOpen
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . '▾ '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '~'
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . '▸ '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '+'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . ' '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '-'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
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 len(childNodesToDraw) > 0
|
|
||||||
|
|
||||||
"draw all the nodes children except the last
|
|
||||||
let lastIndx = len(childNodesToDraw)-1
|
|
||||||
if lastIndx > 0
|
|
||||||
for i in childNodesToDraw[0:lastIndx-1]
|
|
||||||
let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0)
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
|
|
||||||
"draw the last child, indicating that it IS the last
|
|
||||||
let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
return output
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
|
@ -1,88 +0,0 @@
|
||||||
let s:tree_up_dir_line = '.. (up a dir)'
|
|
||||||
"NERDTreeFlags are syntax items that should be invisible, but give clues as to
|
|
||||||
"how things should be highlighted
|
|
||||||
syn match NERDTreeFlag #\~#
|
|
||||||
syn match NERDTreeFlag #\[RO\]#
|
|
||||||
|
|
||||||
"highlighting for the .. (up dir) line at the top of the tree
|
|
||||||
execute "syn match NERDTreeUp #\\V". s:tree_up_dir_line ."#"
|
|
||||||
|
|
||||||
"highlighting for the ~/+ symbols for the directory nodes
|
|
||||||
syn match NERDTreeClosable #\~\<#
|
|
||||||
syn match NERDTreeClosable #\~\.#
|
|
||||||
syn match NERDTreeOpenable #+\<#
|
|
||||||
syn match NERDTreeOpenable #+\.#he=e-1
|
|
||||||
|
|
||||||
"highlighting for the tree structural parts
|
|
||||||
syn match NERDTreePart #|#
|
|
||||||
syn match NERDTreePart #`#
|
|
||||||
syn match NERDTreePartFile #[|`]-#hs=s+1 contains=NERDTreePart
|
|
||||||
|
|
||||||
"quickhelp syntax elements
|
|
||||||
syn match NERDTreeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1
|
|
||||||
syn match NERDTreeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1
|
|
||||||
syn match NERDTreeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=NERDTreeFlag
|
|
||||||
syn match NERDTreeToggleOn #".*(on)#hs=e-2,he=e-1 contains=NERDTreeHelpKey
|
|
||||||
syn match NERDTreeToggleOff #".*(off)#hs=e-3,he=e-1 contains=NERDTreeHelpKey
|
|
||||||
syn match NERDTreeHelpCommand #" :.\{-}\>#hs=s+3
|
|
||||||
syn match NERDTreeHelp #^".*# contains=NERDTreeHelpKey,NERDTreeHelpTitle,NERDTreeFlag,NERDTreeToggleOff,NERDTreeToggleOn,NERDTreeHelpCommand
|
|
||||||
|
|
||||||
"highlighting for readonly files
|
|
||||||
syn match NERDTreeRO #.*\[RO\]#hs=s+2 contains=NERDTreeFlag,NERDTreeBookmark,NERDTreePart,NERDTreePartFile
|
|
||||||
|
|
||||||
"highlighting for sym links
|
|
||||||
syn match NERDTreeLink #[^-| `].* -> # contains=NERDTreeBookmark,NERDTreeOpenable,NERDTreeClosable,NERDTreeDirSlash
|
|
||||||
|
|
||||||
"highlighing for directory nodes and file nodes
|
|
||||||
syn match NERDTreeDirSlash #/#
|
|
||||||
syn match NERDTreeDir #[^-| `].*/# contains=NERDTreeLink,NERDTreeDirSlash,NERDTreeOpenable,NERDTreeClosable
|
|
||||||
syn match NERDTreeExecFile #[|` ].*\*\($\| \)# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark
|
|
||||||
syn match NERDTreeFile #|-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile
|
|
||||||
syn match NERDTreeFile #`-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile
|
|
||||||
syn match NERDTreeCWD #^[</].*$#
|
|
||||||
|
|
||||||
"highlighting for bookmarks
|
|
||||||
syn match NERDTreeBookmark # {.*}#hs=s+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
|
|
||||||
|
|
||||||
if exists("g:NERDChristmasTree") && g:NERDChristmasTree
|
|
||||||
hi def link NERDTreePart Special
|
|
||||||
hi def link NERDTreePartFile Type
|
|
||||||
hi def link NERDTreeFile Normal
|
|
||||||
hi def link NERDTreeExecFile Title
|
|
||||||
hi def link NERDTreeDirSlash Identifier
|
|
||||||
hi def link NERDTreeClosable Type
|
|
||||||
else
|
|
||||||
hi def link NERDTreePart Normal
|
|
||||||
hi def link NERDTreePartFile Normal
|
|
||||||
hi def link NERDTreeFile Normal
|
|
||||||
hi def link NERDTreeClosable Title
|
|
||||||
endif
|
|
||||||
|
|
||||||
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 NERDTreeDir Directory
|
|
||||||
hi def link NERDTreeUp Directory
|
|
||||||
hi def link NERDTreeCWD Statement
|
|
||||||
hi def link NERDTreeLink Macro
|
|
||||||
hi def link NERDTreeOpenable Title
|
|
||||||
hi def link NERDTreeFlag ignore
|
|
||||||
hi def link NERDTreeRO WarningMsg
|
|
||||||
hi def link NERDTreeBookmark Statement
|
|
||||||
|
|
||||||
hi def link NERDTreeCurrentNode Search
|
|
|
@ -1,327 +0,0 @@
|
||||||
" File: closetag.vim
|
|
||||||
" Summary: Functions and mappings to close open HTML/XML tags
|
|
||||||
" Uses: <C-_> -- close matching open tag
|
|
||||||
" Author: Steven Mueller <diffusor@ugcs.caltech.edu>
|
|
||||||
" Last Modified: Tue May 24 13:29:48 PDT 2005
|
|
||||||
" Version: 0.9.1
|
|
||||||
" XXX - breaks if close attempted while XIM is in preedit mode
|
|
||||||
" TODO - allow usability as a global plugin -
|
|
||||||
" Add g:unaryTagsStack - always contains html tags settings
|
|
||||||
" and g:closetag_default_xml - user should define this to default to xml
|
|
||||||
" When a close is attempted but b:unaryTagsStack undefined,
|
|
||||||
" use b:closetag_html_style to determine if the file is to be treated
|
|
||||||
" as html or xml. Failing that, check the filetype for xml or html.
|
|
||||||
" Finally, default to g:closetag_html_style.
|
|
||||||
" If the file is html, let b:unaryTagsStack=g:unaryTagsStack
|
|
||||||
" otherwise, let b:unaryTagsStack=""
|
|
||||||
" TODO - make matching work for all comments
|
|
||||||
" -- kinda works now, but needs syn sync minlines to be very long
|
|
||||||
" -- Only check whether in syntax in the beginning, then store comment tags
|
|
||||||
" in the tagstacks to determine whether to move into or out of comment mode
|
|
||||||
" TODO - The new normal mode mapping clears recent messages with its <ESC>, and
|
|
||||||
" it doesn't fix the null-undo issue for vim 5.7 anyway.
|
|
||||||
" TODO - make use of the following neat features:
|
|
||||||
" -- the ternary ?: operator
|
|
||||||
" -- :echomsg and :echoerr
|
|
||||||
" -- curly brace expansion for variables and function name definitions?
|
|
||||||
" -- check up on map <blah> \FuncName
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This script eases redundant typing when writing html or xml files (even if
|
|
||||||
" you're very good with ctrl-p and ctrl-n :). Hitting ctrl-_ will initiate a
|
|
||||||
" search for the most recent open tag above that is not closed in the
|
|
||||||
" intervening space and then insert the matching close tag at the cursor. In
|
|
||||||
" normal mode, the close tag is inserted one character after cursor rather than
|
|
||||||
" at it, as if a<C-_> had been used. This allows putting close tags at the
|
|
||||||
" ends of lines while in normal mode, but disallows inserting them in the
|
|
||||||
" first column.
|
|
||||||
"
|
|
||||||
" For HTML, a configurable list of tags are ignored in the matching process.
|
|
||||||
" By default, the following tags will not be matched and thus not closed
|
|
||||||
" automatically: area, base, br, dd, dt, hr, img, input, link, meta, and
|
|
||||||
" param.
|
|
||||||
"
|
|
||||||
" For XML, all tags must have a closing match or be terminated by />, as in
|
|
||||||
" <empty-element/>. These empty element tags are ignored for matching.
|
|
||||||
"
|
|
||||||
" Comment checking is now handled by vim's internal syntax checking. If tag
|
|
||||||
" closing is initiated outside a comment, only tags outside of comments will
|
|
||||||
" be matched. When closing tags in comments, only tags within comments will
|
|
||||||
" be matched, skipping any non-commented out code (wee!). However, the
|
|
||||||
" process of determining the syntax ID of an arbitrary position can still be
|
|
||||||
" erroneous if a comment is not detected because the syntax highlighting is
|
|
||||||
" out of sync, or really slow if syn sync minlines is large.
|
|
||||||
" Set the b:closetag_disable_synID variable to disable this feature if you
|
|
||||||
" have really big chunks of comment in your code and closing tags is too slow.
|
|
||||||
"
|
|
||||||
" If syntax highlighting is not enabled, comments will not be handled very
|
|
||||||
" well. Commenting out HTML in certain ways may cause a "tag mismatch"
|
|
||||||
" message and no completion. For example, '<!--a href="blah">link!</a-->'
|
|
||||||
" between the cursor and the most recent unclosed open tag above causes
|
|
||||||
" trouble. Properly matched well formed tags in comments don't cause a
|
|
||||||
" problem.
|
|
||||||
"
|
|
||||||
" Install:
|
|
||||||
" To use, place this file in your standard vim scripts directory, and source
|
|
||||||
" it while editing the file you wish to close tags in. If the filetype is not
|
|
||||||
" set or the file is some sort of template with embedded HTML, you may force
|
|
||||||
" HTML style tag matching by first defining the b:closetag_html_style buffer
|
|
||||||
" variable. Otherwise, the default is XML style tag matching.
|
|
||||||
"
|
|
||||||
" Example:
|
|
||||||
" :let b:closetag_html_style=1
|
|
||||||
" :source ~/.vim/scripts/closetag.vim
|
|
||||||
"
|
|
||||||
" For greater convenience, load this script in an autocommand:
|
|
||||||
" :au Filetype html,xml,xsl source ~/.vim/scripts/closetag.vim
|
|
||||||
"
|
|
||||||
" Also, set noignorecase for html files or edit b:unaryTagsStack to match your
|
|
||||||
" capitalization style. You may set this variable before or after loading the
|
|
||||||
" script, or simply change the file itself.
|
|
||||||
"
|
|
||||||
" Configuration Variables:
|
|
||||||
"
|
|
||||||
" b:unaryTagsStack Buffer local string containing a whitespace
|
|
||||||
" seperated list of element names that should be
|
|
||||||
" ignored while finding matching closetags. Checking
|
|
||||||
" is done according to the current setting of the
|
|
||||||
" ignorecase option.
|
|
||||||
"
|
|
||||||
" b:closetag_html_style Define this (as with let b:closetag_html_style=1)
|
|
||||||
" and source the script again to set the
|
|
||||||
" unaryTagsStack to its default value for html.
|
|
||||||
"
|
|
||||||
" b:closetag_disable_synID Define this to disable comment checking if tag
|
|
||||||
" closing is too slow. This can be set or unset
|
|
||||||
" without having to source again.
|
|
||||||
"
|
|
||||||
" Changelog:
|
|
||||||
" May 24, 2005 Tuesday
|
|
||||||
" * Changed function names to be script-local to avoid conflicts with other
|
|
||||||
" scripts' stack implementations.
|
|
||||||
"
|
|
||||||
" June 07, 2001 Thursday
|
|
||||||
" * Added comment handling. Currently relies on synID, so if syn sync
|
|
||||||
" minlines is small, the chance for failure is high, but if minlines is
|
|
||||||
" large, tagclosing becomes rather slow...
|
|
||||||
"
|
|
||||||
" * Changed normal mode closetag mapping to use <C-R> in insert mode
|
|
||||||
" rather than p in normal mode. This has 2 implications:
|
|
||||||
" - Tag closing no longer clobbers the unnamed register
|
|
||||||
" - When tag closing fails or finds no match, no longer adds to the undo
|
|
||||||
" buffer for recent vim 6.0 development versions.
|
|
||||||
" - However, clears the last message when closing tags in normal mode
|
|
||||||
"
|
|
||||||
" * Changed the closetag_html_style variable to be buffer-local rather than
|
|
||||||
" global.
|
|
||||||
"
|
|
||||||
" * Expanded documentation
|
|
||||||
|
|
||||||
"------------------------------------------------------------------------------
|
|
||||||
" User configurable settings
|
|
||||||
"------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
" if html, don't close certain tags. Works best if ignorecase is set.
|
|
||||||
" otherwise, capitalize these elements according to your html editing style
|
|
||||||
if !exists("b:unaryTagsStack") || exists("b:closetag_html_style")
|
|
||||||
if &filetype == "html" || exists("b:closetag_html_style")
|
|
||||||
let b:unaryTagsStack="area base br dd dt hr img input link meta param"
|
|
||||||
else " for xsl and xsl
|
|
||||||
let b:unaryTagsStack=""
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Has this already been loaded?
|
|
||||||
if exists("loaded_closetag")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let loaded_closetag=1
|
|
||||||
|
|
||||||
" set up mappings for tag closing
|
|
||||||
inoremap <C-_> <C-R>=GetCloseTag()<CR>
|
|
||||||
map <C-_> a<C-_><ESC>
|
|
||||||
|
|
||||||
"------------------------------------------------------------------------------
|
|
||||||
" Tag closer - uses the stringstack implementation below
|
|
||||||
"------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
" Returns the most recent unclosed tag-name
|
|
||||||
" (ignores tags in the variable referenced by a:unaryTagsStack)
|
|
||||||
function! GetLastOpenTag(unaryTagsStack)
|
|
||||||
" Search backwards through the file line by line using getline()
|
|
||||||
" Overall strategy (moving backwards through the file from the cursor):
|
|
||||||
" Push closing tags onto a stack.
|
|
||||||
" On an opening tag, if the tag matches the stack top, discard both.
|
|
||||||
" -- if the tag doesn't match, signal an error.
|
|
||||||
" -- if the stack is empty, use this tag
|
|
||||||
let linenum=line(".")
|
|
||||||
let lineend=col(".") - 1 " start: cursor position
|
|
||||||
let first=1 " flag for first line searched
|
|
||||||
let b:TagStack="" " main stack of tags
|
|
||||||
let startInComment=s:InComment()
|
|
||||||
|
|
||||||
let tagpat='</\=\(\k\|[-:]\)\+\|/>'
|
|
||||||
" Search for: closing tags </tag, opening tags <tag, and unary tag ends />
|
|
||||||
while (linenum>0)
|
|
||||||
" Every time we see an end-tag, we push it on the stack. When we see an
|
|
||||||
" open tag, if the stack isn't empty, we pop it and see if they match.
|
|
||||||
" If no, signal an error.
|
|
||||||
" If yes, continue searching backwards.
|
|
||||||
" If stack is empty, return this open tag as the one that needs closing.
|
|
||||||
let line=getline(linenum)
|
|
||||||
if first
|
|
||||||
let line=strpart(line,0,lineend)
|
|
||||||
else
|
|
||||||
let lineend=strlen(line)
|
|
||||||
endif
|
|
||||||
let b:lineTagStack=""
|
|
||||||
let mpos=0
|
|
||||||
let b:TagCol=0
|
|
||||||
" Search the current line in the forward direction, pushing any tags
|
|
||||||
" onto a special stack for the current line
|
|
||||||
while (mpos > -1)
|
|
||||||
let mpos=matchend(line,tagpat)
|
|
||||||
if mpos > -1
|
|
||||||
let b:TagCol=b:TagCol+mpos
|
|
||||||
let tag=matchstr(line,tagpat)
|
|
||||||
|
|
||||||
if exists("b:closetag_disable_synID") || startInComment==s:InCommentAt(linenum, b:TagCol)
|
|
||||||
let b:TagLine=linenum
|
|
||||||
call s:Push(matchstr(tag,'[^<>]\+'),"b:lineTagStack")
|
|
||||||
endif
|
|
||||||
"echo "Tag: ".tag." ending at position ".mpos." in '".line."'."
|
|
||||||
let lineend=lineend-mpos
|
|
||||||
let line=strpart(line,mpos,lineend)
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
" Process the current line stack
|
|
||||||
while (!s:EmptystackP("b:lineTagStack"))
|
|
||||||
let tag=s:Pop("b:lineTagStack")
|
|
||||||
if match(tag, "^/") == 0 "found end tag
|
|
||||||
call s:Push(tag,"b:TagStack")
|
|
||||||
"echo linenum." ".b:TagStack
|
|
||||||
elseif s:EmptystackP("b:TagStack") && !s:Instack(tag, a:unaryTagsStack) "found unclosed tag
|
|
||||||
return tag
|
|
||||||
else
|
|
||||||
let endtag=s:Peekstack("b:TagStack")
|
|
||||||
if endtag == "/".tag || endtag == "/"
|
|
||||||
call s:Pop("b:TagStack") "found a open/close tag pair
|
|
||||||
"echo linenum." ".b:TagStack
|
|
||||||
elseif !s:Instack(tag, a:unaryTagsStack) "we have a mismatch error
|
|
||||||
echohl Error
|
|
||||||
echon "\rError:"
|
|
||||||
echohl None
|
|
||||||
echo " tag mismatch: <".tag."> doesn't match <".endtag.">. (Line ".linenum." Tagstack: ".b:TagStack.")"
|
|
||||||
return ""
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
let linenum=linenum-1 | let first=0
|
|
||||||
endwhile
|
|
||||||
" At this point, we have exhausted the file and not found any opening tag
|
|
||||||
echo "No opening tags."
|
|
||||||
return ""
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Returns closing tag for most recent unclosed tag, respecting the
|
|
||||||
" current setting of b:unaryTagsStack for tags that should not be closed
|
|
||||||
function! GetCloseTag()
|
|
||||||
let tag=GetLastOpenTag("b:unaryTagsStack")
|
|
||||||
if tag == ""
|
|
||||||
return ""
|
|
||||||
else
|
|
||||||
return "</".tag.">"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" return 1 if the cursor is in a syntactically identified comment field
|
|
||||||
" (fails for empty lines: always returns not-in-comment)
|
|
||||||
function! s:InComment()
|
|
||||||
return synIDattr(synID(line("."), col("."), 0), "name") =~ 'Comment'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" return 1 if the position specified is in a syntactically identified comment field
|
|
||||||
function! s:InCommentAt(line, col)
|
|
||||||
return synIDattr(synID(a:line, a:col, 0), "name") =~ 'Comment'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"------------------------------------------------------------------------------
|
|
||||||
" String Stacks
|
|
||||||
"------------------------------------------------------------------------------
|
|
||||||
" These are strings of whitespace-separated elements, matched using the \< and
|
|
||||||
" \> patterns after setting the iskeyword option.
|
|
||||||
"
|
|
||||||
" The sname argument should contain a symbolic reference to the stack variable
|
|
||||||
" on which method should operate on (i.e., sname should be a string containing
|
|
||||||
" a fully qualified (ie: g:, b:, etc) variable name.)
|
|
||||||
|
|
||||||
" Helper functions
|
|
||||||
function! s:SetKeywords()
|
|
||||||
let g:IsKeywordBak=&iskeyword
|
|
||||||
let &iskeyword="33-255"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:RestoreKeywords()
|
|
||||||
let &iskeyword=g:IsKeywordBak
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Push el onto the stack referenced by sname
|
|
||||||
function! s:Push(el, sname)
|
|
||||||
if !s:EmptystackP(a:sname)
|
|
||||||
exe "let ".a:sname."=a:el.' '.".a:sname
|
|
||||||
else
|
|
||||||
exe "let ".a:sname."=a:el"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Check whether the stack is empty
|
|
||||||
function! s:EmptystackP(sname)
|
|
||||||
exe "let stack=".a:sname
|
|
||||||
if match(stack,"^ *$") == 0
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return 1 if el is in stack sname, else 0.
|
|
||||||
function! s:Instack(el, sname)
|
|
||||||
exe "let stack=".a:sname
|
|
||||||
call s:SetKeywords()
|
|
||||||
let m=match(stack, "\\<".a:el."\\>")
|
|
||||||
call s:RestoreKeywords()
|
|
||||||
if m < 0
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return the first element in the stack
|
|
||||||
function! s:Peekstack(sname)
|
|
||||||
call s:SetKeywords()
|
|
||||||
exe "let stack=".a:sname
|
|
||||||
let top=matchstr(stack, "\\<.\\{-1,}\\>")
|
|
||||||
call s:RestoreKeywords()
|
|
||||||
return top
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Remove and return the first element in the stack
|
|
||||||
function! s:Pop(sname)
|
|
||||||
if s:EmptystackP(a:sname)
|
|
||||||
echo "Error! Stack ".a:sname." is empty and can't be popped."
|
|
||||||
return ""
|
|
||||||
endif
|
|
||||||
exe "let stack=".a:sname
|
|
||||||
" Find the first space, loc is 0-based. Marks the end of 1st elt in stack.
|
|
||||||
call s:SetKeywords()
|
|
||||||
let loc=matchend(stack,"\\<.\\{-1,}\\>")
|
|
||||||
exe "let ".a:sname."=strpart(stack, loc+1, strlen(stack))"
|
|
||||||
let top=strpart(stack, match(stack, "\\<"), loc)
|
|
||||||
call s:RestoreKeywords()
|
|
||||||
return top
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Clearstack(sname)
|
|
||||||
exe "let ".a:sname."=''"
|
|
||||||
endfunction
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
set encoding=utf-8
|
set encoding=utf-8
|
||||||
set nocompatible " désactivation de la compatibilité avec vi
|
set nocompatible " désactivation de la compatibilité avec vi
|
||||||
|
set shortmess+=filmnrxoOtT " retire le hit <Enter>
|
||||||
|
|
||||||
colorscheme distinguished " couleur
|
colorscheme distinguished " couleur
|
||||||
set background=dark " fond noir par défaut
|
set background=dark " fond noir par défaut
|
||||||
"hi CursorLine guibg=#606060 " couleur de la ligne de curseur
|
"hi CursorLine guibg=#606060 " couleur de la ligne de curseur
|
||||||
|
@ -78,6 +80,12 @@ set foldcolumn=6 " colonne de replis(fold colding)
|
||||||
set viminfo='10,\"100,:20,%,n~/.viminfo
|
set viminfo='10,\"100,:20,%,n~/.viminfo
|
||||||
au BufReadPost * if line("'\"") > 0|if line("'\"") <= line("$")|exe("norm '\"")|else|exe "norm $"|endif|endif
|
au BufReadPost * if line("'\"") > 0|if line("'\"") <= line("$")|exe("norm '\"")|else|exe "norm $"|endif|endif
|
||||||
|
|
||||||
|
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
"Appel des bundles avec pathogen
|
||||||
|
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
runtime! autoload/pathogen.vim
|
||||||
|
silent! call pathogen#helptags()
|
||||||
|
silent! call pathogen#runtime_append_all_bundles()
|
||||||
|
|
||||||
|
|
||||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
@ -106,18 +114,18 @@ imap <silent> <F11> <Esc>:set noexpandtab<CR>
|
||||||
"Sauvegarde automatique des vues, utiles pour les
|
"Sauvegarde automatique des vues, utiles pour les
|
||||||
"replis manuels
|
"replis manuels
|
||||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
au BufWinLeave *.html mkview
|
"au BufWinLeave *.html mkview
|
||||||
au BufWinEnter *.html silent loadview
|
"au BufWinEnter *.html silent loadview
|
||||||
au BufWinLeave *.css mkview
|
"au BufWinLeave *.css mkview
|
||||||
au BufWinEnter *.css silent loadview
|
"au BufWinEnter *.css silent loadview
|
||||||
au BufWinLeave *.php mkview
|
"au BufWinLeave *.php mkview
|
||||||
au BufWinEnter *.php silent loadview
|
"au BufWinEnter *.php silent loadview
|
||||||
au BufWinLeave *.js mkview
|
"au BufWinLeave *.js mkview
|
||||||
au BufWinEnter *.js silent loadview
|
"au BufWinEnter *.js silent loadview
|
||||||
au BufWinLeave *.py mkview
|
"au BufWinLeave *.py mkview
|
||||||
au BufWinEnter *.py silent loadview
|
"au BufWinEnter *.py silent loadview
|
||||||
au BufWinLeave *.java mkview
|
"au BufWinLeave *.java mkview
|
||||||
au BufWinEnter *.java silent loadview
|
"au BufWinEnter *.java silent loadview
|
||||||
|
|
||||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
"Options du fichier de syntaxe python
|
"Options du fichier de syntaxe python
|
||||||
|
@ -209,3 +217,5 @@ if ! has('gui_running')
|
||||||
au InsertLeave * set timeoutlen=1000
|
au InsertLeave * set timeoutlen=1000
|
||||||
augroup END
|
augroup END
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let g:jedi#autocompletion_command = "<C-f>"
|
||||||
|
|
|
@ -100,4 +100,3 @@ hisoka() { ssc hisoka.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2];
|
||||||
hl() { highlight --out-format=xterm256 -l ${argv} | less -R; }
|
hl() { highlight --out-format=xterm256 -l ${argv} | less -R; }
|
||||||
bindkey "^[[A" history-search-backward
|
bindkey "^[[A" history-search-backward
|
||||||
bindkey "^[[B" history-search-forward
|
bindkey "^[[B" history-search-forward
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,75 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Remove zsh completion dump
|
||||||
|
rm ~/.zcompdump
|
||||||
|
|
||||||
|
# Remove vim config directory
|
||||||
|
rm -rf ~/.vim-backup
|
||||||
|
mv ~/.vim ~/.vim-backup
|
||||||
|
mkdir -p ~/.vim/{autoload,bundle,colors,doc,ftplugin,plugin,spell,syntax}
|
||||||
|
|
||||||
|
# Install oh-my-zsh
|
||||||
rm -rf ~/.oh-my-zsh
|
rm -rf ~/.oh-my-zsh
|
||||||
git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
|
git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
|
||||||
|
|
||||||
|
# Copy the graphical part if needed
|
||||||
if [ "$1" == '--graphic' ]
|
if [ "$1" == '--graphic' ]
|
||||||
then
|
then
|
||||||
rsync -av graphic/ ~/
|
rsync -av graphic/ ~/
|
||||||
fc-cache -vf ~/.fonts
|
fc-cache -vf ~/.fonts
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Copy the common part
|
||||||
rsync -av common/ ~/
|
rsync -av common/ ~/
|
||||||
|
|
||||||
|
# Adjust the tmux conf
|
||||||
sed -i "s/REPLACEMEWITHFIRSTLETTEROFHOSTNAME/`expr substr \`hostname\` 1 1`/g" ~/.tmux.conf
|
sed -i "s/REPLACEMEWITHFIRSTLETTEROFHOSTNAME/`expr substr \`hostname\` 1 1`/g" ~/.tmux.conf
|
||||||
|
|
||||||
|
######### VIM Config ###########
|
||||||
|
|
||||||
|
# Install pathogen
|
||||||
|
|
||||||
|
curl -Sso ~/.vim/autoload/pathogen.vim https://raw.github.com/tpope/vim-pathogen/master/autoload/pathogen.vim
|
||||||
|
|
||||||
|
# Install jedi plugin for vim
|
||||||
|
rm -rf ~/.vim/bundle/jedi
|
||||||
|
git clone https://github.com/davidhalter/jedi-vim.git ~/.vim/bundle/jedi
|
||||||
|
|
||||||
|
# Install nerdtree for vim
|
||||||
|
rm -rf ~/.vim/bundle/nerdtree
|
||||||
|
git clone https://github.com/scrooloose/nerdtree.git ~/.vim/bundle/nerdtree
|
||||||
|
|
||||||
|
# Install xmledit for vim
|
||||||
|
rm -rf ~/.vim/bundle/xmledit
|
||||||
|
git clone https://github.com/sukima/xmledit.git ~/.vim/bundle/xmledit
|
||||||
|
pushd ~/.vim/bundle/xmledit
|
||||||
|
make install
|
||||||
|
popd
|
||||||
|
|
||||||
|
# Install pyflakes plugin
|
||||||
|
rm -rf ~/.vim/bundle/pyflakes
|
||||||
|
git clone --recursive git://github.com/kevinw/pyflakes-vim.git ~/.vim/bundle/pyflakes
|
||||||
|
|
||||||
|
# Install autoclose plugin
|
||||||
|
rm -rf ~/.vim/bundle/autoclose
|
||||||
|
git clone https://github.com/Townk/vim-autoclose.git ~/.vim/bundle/autoclose
|
||||||
|
|
||||||
|
# Install tagbar plugin
|
||||||
|
rm -rf ~/.vim/bundle/tagbar
|
||||||
|
git clone https://github.com/majutsushi/tagbar ~/.vim/bundle/tagbar
|
||||||
|
|
||||||
|
# Install vcscommand plugin
|
||||||
|
rm -rf ~/.vim/bundle/vcscommand
|
||||||
|
git clone https://github.com/vim-scripts/vcscommand.vim.git ~/.vim/bundle/vcscommand
|
||||||
|
|
||||||
|
# Install easytag plugin
|
||||||
|
rm -rf ~/.vim/bundle/easytag
|
||||||
|
git clone https://github.com/vim-scripts/easytags.vim.git ~/.vim/bundle/easytag
|
||||||
|
|
||||||
|
# Install closetag plugin
|
||||||
|
rm -rf ~/.vim/bundle/closetag
|
||||||
|
git clone https://github.com/vim-scripts/closetag.vim.git ~/.vim/bundle/closetag
|
||||||
|
|
||||||
|
# Install css3 syntax
|
||||||
|
rm -rf ~/.vim/bundle/css3-mod
|
||||||
|
git clone https://github.com/vim-scripts/css3-mod.git ~/.vim/bundle/css3-mod
|
||||||
|
|
Loading…
Reference in a new issue