New conf for zsh (powerline)
This commit is contained in:
parent
16b4350cdb
commit
c98bf2e7a6
102 changed files with 9836 additions and 98 deletions
25
common/.local/bin/powerline
Executable file
25
common/.local/bin/powerline
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
'''Powerline prompt and statusline script.'''
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
from powerline.shell import ShellPowerline, get_argparser
|
||||||
|
except ImportError:
|
||||||
|
import os
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
from powerline.shell import ShellPowerline, get_argparser # NOQA
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args = get_argparser(description=__doc__).parse_args()
|
||||||
|
powerline = ShellPowerline(args, run_once=True)
|
||||||
|
rendered = powerline.render(
|
||||||
|
width=args.width,
|
||||||
|
side=args.side,
|
||||||
|
segment_info={'args': args, 'environ': os.environ},
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
sys.stdout.write(rendered)
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
sys.stdout.write(rendered.encode('utf-8'))
|
14
common/.local/bin/powerline-lint
Executable file
14
common/.local/bin/powerline-lint
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
'''Powerline configuration checker.'''
|
||||||
|
import argparse
|
||||||
|
from powerline.lint import check
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('-p', '--config_path', metavar='PATH')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args = parser.parse_args()
|
||||||
|
sys.exit(check(args.config_path))
|
|
@ -0,0 +1,63 @@
|
||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: Powerline
|
||||||
|
Version: beta
|
||||||
|
Summary: The ultimate statusline/prompt utility.
|
||||||
|
Home-page: https://github.com/Lokaltog/powerline
|
||||||
|
Author: Kim Silkebækken
|
||||||
|
Author-email: kim.silkebaekken+vim@gmail.com
|
||||||
|
License: UNKNOWN
|
||||||
|
Description: Powerline
|
||||||
|
=========
|
||||||
|
|
||||||
|
:Author: Kim Silkebækken (kim.silkebaekken+vim@gmail.com)
|
||||||
|
:Source: https://github.com/Lokaltog/powerline
|
||||||
|
:Version: beta
|
||||||
|
:Build status:
|
||||||
|
.. image:: https://api.travis-ci.org/Lokaltog/powerline.png?branch=develop
|
||||||
|
:target: `travis-build-status`_
|
||||||
|
:alt: Build status
|
||||||
|
|
||||||
|
This is the upcoming version of Powerline, implemented in Python. The
|
||||||
|
project is currently in a stable beta and almost ready for release.
|
||||||
|
|
||||||
|
* Consult the `documentation
|
||||||
|
<https://powerline.readthedocs.org/en/latest/>`_ for more information and
|
||||||
|
installation instructions.
|
||||||
|
* Check out `powerline-fonts <https://github.com/Lokaltog/powerline-fonts>`_
|
||||||
|
for pre-patched versions of popular coding fonts.
|
||||||
|
|
||||||
|
.. _travis-build-status: https://travis-ci.org/Lokaltog/powerline
|
||||||
|
|
||||||
|
Screenshots
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Vim statusline
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
**Mode-dependent highlighting**
|
||||||
|
|
||||||
|
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-normal.png
|
||||||
|
:alt: Normal mode
|
||||||
|
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-insert.png
|
||||||
|
:alt: Insert mode
|
||||||
|
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-visual.png
|
||||||
|
:alt: Visual mode
|
||||||
|
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-mode-replace.png
|
||||||
|
:alt: Replace mode
|
||||||
|
|
||||||
|
**Automatic truncation of segments in small windows**
|
||||||
|
|
||||||
|
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-truncate1.png
|
||||||
|
:alt: Truncation illustration
|
||||||
|
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-truncate2.png
|
||||||
|
:alt: Truncation illustration
|
||||||
|
* .. image:: https://raw.github.com/Lokaltog/powerline/develop/docs/source/_static/img/pl-truncate3.png
|
||||||
|
:alt: Truncation illustration
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
The font in the screenshots is `Pragmata Pro`_ by Fabrizio Schiavi.
|
||||||
|
|
||||||
|
.. _`Pragmata Pro`: http://www.fsd.it/fonts/pragmatapro.htm
|
||||||
|
|
||||||
|
Platform: UNKNOWN
|
|
@ -0,0 +1,98 @@
|
||||||
|
MANIFEST.in
|
||||||
|
README.rst
|
||||||
|
Powerline.egg-info/PKG-INFO
|
||||||
|
Powerline.egg-info/SOURCES.txt
|
||||||
|
Powerline.egg-info/dependency_links.txt
|
||||||
|
Powerline.egg-info/not-zip-safe
|
||||||
|
Powerline.egg-info/requires.txt
|
||||||
|
Powerline.egg-info/top_level.txt
|
||||||
|
powerline/__init__.py
|
||||||
|
powerline/colorscheme.py
|
||||||
|
powerline/ipython.py
|
||||||
|
powerline/matcher.py
|
||||||
|
powerline/renderer.py
|
||||||
|
powerline/segment.py
|
||||||
|
powerline/shell.py
|
||||||
|
powerline/theme.py
|
||||||
|
powerline/vim.py
|
||||||
|
powerline/bindings/__init__.py
|
||||||
|
powerline/bindings/awesome/powerline-awesome.py
|
||||||
|
powerline/bindings/awesome/powerline.lua
|
||||||
|
powerline/bindings/bash/powerline.sh
|
||||||
|
powerline/bindings/ipython/__init__.py
|
||||||
|
powerline/bindings/ipython/post_0_11.py
|
||||||
|
powerline/bindings/ipython/pre_0_11.py
|
||||||
|
powerline/bindings/qtile/__init__.py
|
||||||
|
powerline/bindings/qtile/widget.py
|
||||||
|
powerline/bindings/tmux/powerline.conf
|
||||||
|
powerline/bindings/vim/__init__.py
|
||||||
|
powerline/bindings/vim/plugin/powerline.vim
|
||||||
|
powerline/bindings/zsh/__init__.py
|
||||||
|
powerline/bindings/zsh/powerline.zsh
|
||||||
|
powerline/config_files/colors.json
|
||||||
|
powerline/config_files/config.json
|
||||||
|
powerline/config_files/colorschemes/ipython/default.json
|
||||||
|
powerline/config_files/colorschemes/shell/default.json
|
||||||
|
powerline/config_files/colorschemes/shell/solarized.json
|
||||||
|
powerline/config_files/colorschemes/tmux/default.json
|
||||||
|
powerline/config_files/colorschemes/vim/default.json
|
||||||
|
powerline/config_files/colorschemes/vim/solarized.json
|
||||||
|
powerline/config_files/colorschemes/wm/default.json
|
||||||
|
powerline/config_files/themes/ipython/in.json
|
||||||
|
powerline/config_files/themes/ipython/in2.json
|
||||||
|
powerline/config_files/themes/ipython/out.json
|
||||||
|
powerline/config_files/themes/ipython/rewrite.json
|
||||||
|
powerline/config_files/themes/shell/default.json
|
||||||
|
powerline/config_files/themes/shell/default_leftonly.json
|
||||||
|
powerline/config_files/themes/tmux/default.json
|
||||||
|
powerline/config_files/themes/vim/cmdwin.json
|
||||||
|
powerline/config_files/themes/vim/default.json
|
||||||
|
powerline/config_files/themes/vim/help.json
|
||||||
|
powerline/config_files/themes/vim/quickfix.json
|
||||||
|
powerline/config_files/themes/wm/default.json
|
||||||
|
powerline/lib/__init__.py
|
||||||
|
powerline/lib/config.py
|
||||||
|
powerline/lib/file_watcher.py
|
||||||
|
powerline/lib/humanize_bytes.py
|
||||||
|
powerline/lib/inotify.py
|
||||||
|
powerline/lib/memoize.py
|
||||||
|
powerline/lib/monotonic.py
|
||||||
|
powerline/lib/threaded.py
|
||||||
|
powerline/lib/tree_watcher.py
|
||||||
|
powerline/lib/url.py
|
||||||
|
powerline/lib/vcs/__init__.py
|
||||||
|
powerline/lib/vcs/bzr.py
|
||||||
|
powerline/lib/vcs/git.py
|
||||||
|
powerline/lib/vcs/mercurial.py
|
||||||
|
powerline/lint/__init__.py
|
||||||
|
powerline/lint/inspect.py
|
||||||
|
powerline/lint/markedjson/__init__.py
|
||||||
|
powerline/lint/markedjson/composer.py
|
||||||
|
powerline/lint/markedjson/constructor.py
|
||||||
|
powerline/lint/markedjson/error.py
|
||||||
|
powerline/lint/markedjson/events.py
|
||||||
|
powerline/lint/markedjson/loader.py
|
||||||
|
powerline/lint/markedjson/markedvalue.py
|
||||||
|
powerline/lint/markedjson/nodes.py
|
||||||
|
powerline/lint/markedjson/parser.py
|
||||||
|
powerline/lint/markedjson/reader.py
|
||||||
|
powerline/lint/markedjson/resolver.py
|
||||||
|
powerline/lint/markedjson/scanner.py
|
||||||
|
powerline/lint/markedjson/tokens.py
|
||||||
|
powerline/matchers/__init__.py
|
||||||
|
powerline/matchers/vim.py
|
||||||
|
powerline/renderers/__init__.py
|
||||||
|
powerline/renderers/bash_prompt.py
|
||||||
|
powerline/renderers/ipython.py
|
||||||
|
powerline/renderers/pango_markup.py
|
||||||
|
powerline/renderers/shell.py
|
||||||
|
powerline/renderers/tmux.py
|
||||||
|
powerline/renderers/vim.py
|
||||||
|
powerline/renderers/zsh_prompt.py
|
||||||
|
powerline/segments/__init__.py
|
||||||
|
powerline/segments/common.py
|
||||||
|
powerline/segments/ipython.py
|
||||||
|
powerline/segments/shell.py
|
||||||
|
powerline/segments/vim.py
|
||||||
|
scripts/powerline
|
||||||
|
scripts/powerline-lint
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
../powerline/shell.py
|
||||||
|
../powerline/colorscheme.py
|
||||||
|
../powerline/ipython.py
|
||||||
|
../powerline/theme.py
|
||||||
|
../powerline/vim.py
|
||||||
|
../powerline/__init__.py
|
||||||
|
../powerline/matcher.py
|
||||||
|
../powerline/renderer.py
|
||||||
|
../powerline/segment.py
|
||||||
|
../powerline/matchers/vim.py
|
||||||
|
../powerline/matchers/__init__.py
|
||||||
|
../powerline/bindings/__init__.py
|
||||||
|
../powerline/lint/__init__.py
|
||||||
|
../powerline/lint/inspect.py
|
||||||
|
../powerline/segments/shell.py
|
||||||
|
../powerline/segments/ipython.py
|
||||||
|
../powerline/segments/common.py
|
||||||
|
../powerline/segments/vim.py
|
||||||
|
../powerline/segments/__init__.py
|
||||||
|
../powerline/renderers/shell.py
|
||||||
|
../powerline/renderers/ipython.py
|
||||||
|
../powerline/renderers/bash_prompt.py
|
||||||
|
../powerline/renderers/zsh_prompt.py
|
||||||
|
../powerline/renderers/vim.py
|
||||||
|
../powerline/renderers/__init__.py
|
||||||
|
../powerline/renderers/pango_markup.py
|
||||||
|
../powerline/renderers/tmux.py
|
||||||
|
../powerline/lib/memoize.py
|
||||||
|
../powerline/lib/monotonic.py
|
||||||
|
../powerline/lib/config.py
|
||||||
|
../powerline/lib/humanize_bytes.py
|
||||||
|
../powerline/lib/__init__.py
|
||||||
|
../powerline/lib/inotify.py
|
||||||
|
../powerline/lib/url.py
|
||||||
|
../powerline/lib/threaded.py
|
||||||
|
../powerline/lib/file_watcher.py
|
||||||
|
../powerline/lib/tree_watcher.py
|
||||||
|
../powerline/bindings/ipython/post_0_11.py
|
||||||
|
../powerline/bindings/ipython/pre_0_11.py
|
||||||
|
../powerline/bindings/ipython/__init__.py
|
||||||
|
../powerline/bindings/qtile/__init__.py
|
||||||
|
../powerline/bindings/qtile/widget.py
|
||||||
|
../powerline/bindings/vim/__init__.py
|
||||||
|
../powerline/bindings/zsh/__init__.py
|
||||||
|
../powerline/lint/markedjson/composer.py
|
||||||
|
../powerline/lint/markedjson/constructor.py
|
||||||
|
../powerline/lint/markedjson/loader.py
|
||||||
|
../powerline/lint/markedjson/nodes.py
|
||||||
|
../powerline/lint/markedjson/resolver.py
|
||||||
|
../powerline/lint/markedjson/scanner.py
|
||||||
|
../powerline/lint/markedjson/reader.py
|
||||||
|
../powerline/lint/markedjson/__init__.py
|
||||||
|
../powerline/lint/markedjson/parser.py
|
||||||
|
../powerline/lint/markedjson/markedvalue.py
|
||||||
|
../powerline/lint/markedjson/events.py
|
||||||
|
../powerline/lint/markedjson/tokens.py
|
||||||
|
../powerline/lint/markedjson/error.py
|
||||||
|
../powerline/lib/vcs/git.py
|
||||||
|
../powerline/lib/vcs/mercurial.py
|
||||||
|
../powerline/lib/vcs/__init__.py
|
||||||
|
../powerline/lib/vcs/bzr.py
|
||||||
|
../powerline/config_files/colors.json
|
||||||
|
../powerline/config_files/config.json
|
||||||
|
../powerline/config_files/colorschemes/ipython/default.json
|
||||||
|
../powerline/config_files/colorschemes/shell/default.json
|
||||||
|
../powerline/config_files/colorschemes/shell/solarized.json
|
||||||
|
../powerline/config_files/colorschemes/tmux/default.json
|
||||||
|
../powerline/config_files/colorschemes/vim/default.json
|
||||||
|
../powerline/config_files/colorschemes/vim/solarized.json
|
||||||
|
../powerline/config_files/colorschemes/wm/default.json
|
||||||
|
../powerline/config_files/themes/ipython/in.json
|
||||||
|
../powerline/config_files/themes/ipython/in2.json
|
||||||
|
../powerline/config_files/themes/ipython/out.json
|
||||||
|
../powerline/config_files/themes/ipython/rewrite.json
|
||||||
|
../powerline/config_files/themes/shell/default.json
|
||||||
|
../powerline/config_files/themes/shell/default_leftonly.json
|
||||||
|
../powerline/config_files/themes/tmux/default.json
|
||||||
|
../powerline/config_files/themes/vim/cmdwin.json
|
||||||
|
../powerline/config_files/themes/vim/default.json
|
||||||
|
../powerline/config_files/themes/vim/help.json
|
||||||
|
../powerline/config_files/themes/vim/quickfix.json
|
||||||
|
../powerline/config_files/themes/wm/default.json
|
||||||
|
../powerline/bindings/awesome/powerline-awesome.py
|
||||||
|
../powerline/bindings/awesome/powerline.lua
|
||||||
|
../powerline/bindings/bash/powerline.sh
|
||||||
|
../powerline/bindings/tmux/powerline.conf
|
||||||
|
../powerline/bindings/vim/plugin/powerline.vim
|
||||||
|
../powerline/bindings/zsh/powerline.zsh
|
||||||
|
../powerline/shell.pyc
|
||||||
|
../powerline/colorscheme.pyc
|
||||||
|
../powerline/ipython.pyc
|
||||||
|
../powerline/theme.pyc
|
||||||
|
../powerline/vim.pyc
|
||||||
|
../powerline/__init__.pyc
|
||||||
|
../powerline/matcher.pyc
|
||||||
|
../powerline/renderer.pyc
|
||||||
|
../powerline/segment.pyc
|
||||||
|
../powerline/matchers/vim.pyc
|
||||||
|
../powerline/matchers/__init__.pyc
|
||||||
|
../powerline/bindings/__init__.pyc
|
||||||
|
../powerline/lint/__init__.pyc
|
||||||
|
../powerline/lint/inspect.pyc
|
||||||
|
../powerline/segments/shell.pyc
|
||||||
|
../powerline/segments/ipython.pyc
|
||||||
|
../powerline/segments/common.pyc
|
||||||
|
../powerline/segments/vim.pyc
|
||||||
|
../powerline/segments/__init__.pyc
|
||||||
|
../powerline/renderers/shell.pyc
|
||||||
|
../powerline/renderers/ipython.pyc
|
||||||
|
../powerline/renderers/bash_prompt.pyc
|
||||||
|
../powerline/renderers/zsh_prompt.pyc
|
||||||
|
../powerline/renderers/vim.pyc
|
||||||
|
../powerline/renderers/__init__.pyc
|
||||||
|
../powerline/renderers/pango_markup.pyc
|
||||||
|
../powerline/renderers/tmux.pyc
|
||||||
|
../powerline/lib/memoize.pyc
|
||||||
|
../powerline/lib/monotonic.pyc
|
||||||
|
../powerline/lib/config.pyc
|
||||||
|
../powerline/lib/humanize_bytes.pyc
|
||||||
|
../powerline/lib/__init__.pyc
|
||||||
|
../powerline/lib/inotify.pyc
|
||||||
|
../powerline/lib/url.pyc
|
||||||
|
../powerline/lib/threaded.pyc
|
||||||
|
../powerline/lib/file_watcher.pyc
|
||||||
|
../powerline/lib/tree_watcher.pyc
|
||||||
|
../powerline/bindings/ipython/post_0_11.pyc
|
||||||
|
../powerline/bindings/ipython/pre_0_11.pyc
|
||||||
|
../powerline/bindings/ipython/__init__.pyc
|
||||||
|
../powerline/bindings/qtile/__init__.pyc
|
||||||
|
../powerline/bindings/qtile/widget.pyc
|
||||||
|
../powerline/bindings/vim/__init__.pyc
|
||||||
|
../powerline/bindings/zsh/__init__.pyc
|
||||||
|
../powerline/lint/markedjson/composer.pyc
|
||||||
|
../powerline/lint/markedjson/constructor.pyc
|
||||||
|
../powerline/lint/markedjson/loader.pyc
|
||||||
|
../powerline/lint/markedjson/nodes.pyc
|
||||||
|
../powerline/lint/markedjson/resolver.pyc
|
||||||
|
../powerline/lint/markedjson/scanner.pyc
|
||||||
|
../powerline/lint/markedjson/reader.pyc
|
||||||
|
../powerline/lint/markedjson/__init__.pyc
|
||||||
|
../powerline/lint/markedjson/parser.pyc
|
||||||
|
../powerline/lint/markedjson/markedvalue.pyc
|
||||||
|
../powerline/lint/markedjson/events.pyc
|
||||||
|
../powerline/lint/markedjson/tokens.pyc
|
||||||
|
../powerline/lint/markedjson/error.pyc
|
||||||
|
../powerline/lib/vcs/git.pyc
|
||||||
|
../powerline/lib/vcs/mercurial.pyc
|
||||||
|
../powerline/lib/vcs/__init__.pyc
|
||||||
|
../powerline/lib/vcs/bzr.pyc
|
||||||
|
../powerline/bindings/awesome/powerline-awesome.pyc
|
||||||
|
./
|
||||||
|
SOURCES.txt
|
||||||
|
PKG-INFO
|
||||||
|
not-zip-safe
|
||||||
|
dependency_links.txt
|
||||||
|
top_level.txt
|
||||||
|
requires.txt
|
||||||
|
../../../../bin/powerline
|
||||||
|
../../../../bin/powerline-lint
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
|
||||||
|
[docs]
|
||||||
|
Sphinx
|
|
@ -0,0 +1 @@
|
||||||
|
powerline
|
409
common/.local/lib/python2.7/site-packages/powerline/__init__.py
Normal file
409
common/.local/lib/python2.7/site-packages/powerline/__init__.py
Normal file
|
@ -0,0 +1,409 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from powerline.colorscheme import Colorscheme
|
||||||
|
from powerline.lib.config import ConfigLoader
|
||||||
|
|
||||||
|
from threading import Lock, Event
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_SYSTEM_CONFIG_DIR = None
|
||||||
|
|
||||||
|
|
||||||
|
def find_config_file(search_paths, config_file):
|
||||||
|
config_file += '.json'
|
||||||
|
for path in search_paths:
|
||||||
|
config_file_path = os.path.join(path, config_file)
|
||||||
|
if os.path.isfile(config_file_path):
|
||||||
|
return config_file_path
|
||||||
|
raise IOError('Config file not found in search path: {0}'.format(config_file))
|
||||||
|
|
||||||
|
|
||||||
|
class PowerlineLogger(object):
|
||||||
|
def __init__(self, use_daemon_threads, logger, ext):
|
||||||
|
self.logger = logger
|
||||||
|
self.ext = ext
|
||||||
|
self.use_daemon_threads = use_daemon_threads
|
||||||
|
self.prefix = ''
|
||||||
|
self.last_msgs = {}
|
||||||
|
|
||||||
|
def _log(self, attr, msg, *args, **kwargs):
|
||||||
|
prefix = kwargs.get('prefix') or self.prefix
|
||||||
|
prefix = self.ext + ((':' + prefix) if prefix else '')
|
||||||
|
if args or kwargs:
|
||||||
|
msg = msg.format(*args, **kwargs)
|
||||||
|
msg = prefix + ':' + msg
|
||||||
|
key = attr + ':' + prefix
|
||||||
|
if msg != self.last_msgs.get(key):
|
||||||
|
getattr(self.logger, attr)(msg)
|
||||||
|
self.last_msgs[key] = msg
|
||||||
|
|
||||||
|
def critical(self, msg, *args, **kwargs):
|
||||||
|
self._log('critical', msg, *args, **kwargs)
|
||||||
|
|
||||||
|
def exception(self, msg, *args, **kwargs):
|
||||||
|
self._log('exception', msg, *args, **kwargs)
|
||||||
|
|
||||||
|
def info(self, msg, *args, **kwargs):
|
||||||
|
self._log('info', msg, *args, **kwargs)
|
||||||
|
|
||||||
|
def error(self, msg, *args, **kwargs):
|
||||||
|
self._log('error', msg, *args, **kwargs)
|
||||||
|
|
||||||
|
def warn(self, msg, *args, **kwargs):
|
||||||
|
self._log('warning', msg, *args, **kwargs)
|
||||||
|
|
||||||
|
def debug(self, msg, *args, **kwargs):
|
||||||
|
self._log('debug', msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class Powerline(object):
|
||||||
|
'''Main powerline class, entrance point for all powerline uses. Sets
|
||||||
|
powerline up and loads the configuration.
|
||||||
|
|
||||||
|
:param str ext:
|
||||||
|
extension used. Determines where configuration files will
|
||||||
|
searched and what renderer module will be used. Affected: used ``ext``
|
||||||
|
dictionary from :file:`powerline/config.json`, location of themes and
|
||||||
|
colorschemes, render module (``powerline.renders.{ext}``).
|
||||||
|
:param str renderer_module:
|
||||||
|
Overrides renderer module (defaults to ``ext``). Should be the name of
|
||||||
|
the package imported like this: ``powerline.renders.{render_module}``.
|
||||||
|
If this parameter contains a dot, ``powerline.renderers.`` is not
|
||||||
|
prepended. There is also a special case for renderers defined in
|
||||||
|
toplevel modules: ``foo.`` (note: dot at the end) tries to get renderer
|
||||||
|
from module ``foo`` (because ``foo`` (without dot) tries to get renderer
|
||||||
|
from module ``powerline.renderers.foo``).
|
||||||
|
:param bool run_once:
|
||||||
|
Determines whether .renderer.render() method will be run only once
|
||||||
|
during python session.
|
||||||
|
:param Logger logger:
|
||||||
|
If present, no new logger will be created and this logger will be used.
|
||||||
|
:param bool use_daemon_threads:
|
||||||
|
Use daemon threads for.
|
||||||
|
:param Event shutdown_event:
|
||||||
|
Use this Event as shutdown_event.
|
||||||
|
:param ConfigLoader config_loader:
|
||||||
|
Class that manages (re)loading of configuration.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
ext,
|
||||||
|
renderer_module=None,
|
||||||
|
run_once=False,
|
||||||
|
logger=None,
|
||||||
|
use_daemon_threads=True,
|
||||||
|
shutdown_event=None,
|
||||||
|
config_loader=None):
|
||||||
|
self.ext = ext
|
||||||
|
self.renderer_module = renderer_module or ext
|
||||||
|
self.run_once = run_once
|
||||||
|
self.logger = logger
|
||||||
|
self.use_daemon_threads = use_daemon_threads
|
||||||
|
|
||||||
|
if '.' not in self.renderer_module:
|
||||||
|
self.renderer_module = 'powerline.renderers.' + self.renderer_module
|
||||||
|
elif self.renderer_module[-1] == '.':
|
||||||
|
self.renderer_module = self.renderer_module[:-1]
|
||||||
|
|
||||||
|
config_paths = self.get_config_paths()
|
||||||
|
self.find_config_file = lambda cfg_path: find_config_file(config_paths, cfg_path)
|
||||||
|
|
||||||
|
self.cr_kwargs_lock = Lock()
|
||||||
|
self.create_renderer_kwargs = {
|
||||||
|
'load_main': True,
|
||||||
|
'load_colors': True,
|
||||||
|
'load_colorscheme': True,
|
||||||
|
'load_theme': True,
|
||||||
|
}
|
||||||
|
self.shutdown_event = shutdown_event or Event()
|
||||||
|
self.config_loader = config_loader or ConfigLoader(shutdown_event=self.shutdown_event)
|
||||||
|
self.run_loader_update = False
|
||||||
|
|
||||||
|
self.renderer_options = {}
|
||||||
|
|
||||||
|
self.prev_common_config = None
|
||||||
|
self.prev_ext_config = None
|
||||||
|
self.pl = None
|
||||||
|
|
||||||
|
def create_renderer(self, load_main=False, load_colors=False, load_colorscheme=False, load_theme=False):
|
||||||
|
'''(Re)create renderer object. Can be used after Powerline object was
|
||||||
|
successfully initialized. If any of the below parameters except
|
||||||
|
``load_main`` is True renderer object will be recreated.
|
||||||
|
|
||||||
|
:param bool load_main:
|
||||||
|
Determines whether main configuration file (:file:`config.json`)
|
||||||
|
should be loaded. If appropriate configuration changes implies
|
||||||
|
``load_colorscheme`` and ``load_theme`` and recreation of renderer
|
||||||
|
object. Won’t trigger recreation if only unrelated configuration
|
||||||
|
changed.
|
||||||
|
:param bool load_colors:
|
||||||
|
Determines whether colors configuration from :file:`colors.json`
|
||||||
|
should be (re)loaded.
|
||||||
|
:param bool load_colorscheme:
|
||||||
|
Determines whether colorscheme configuration should be (re)loaded.
|
||||||
|
:param bool load_theme:
|
||||||
|
Determines whether theme configuration should be reloaded.
|
||||||
|
'''
|
||||||
|
common_config_differs = False
|
||||||
|
ext_config_differs = False
|
||||||
|
if load_main:
|
||||||
|
self._purge_configs('main')
|
||||||
|
config = self.load_main_config()
|
||||||
|
self.common_config = config['common']
|
||||||
|
if self.common_config != self.prev_common_config:
|
||||||
|
common_config_differs = True
|
||||||
|
self.prev_common_config = self.common_config
|
||||||
|
self.common_config['paths'] = [os.path.expanduser(path) for path in self.common_config.get('paths', [])]
|
||||||
|
self.import_paths = self.common_config['paths']
|
||||||
|
|
||||||
|
if not self.logger:
|
||||||
|
log_format = self.common_config.get('log_format', '%(asctime)s:%(levelname)s:%(message)s')
|
||||||
|
formatter = logging.Formatter(log_format)
|
||||||
|
|
||||||
|
level = getattr(logging, self.common_config.get('log_level', 'WARNING'))
|
||||||
|
handler = self.get_log_handler()
|
||||||
|
handler.setLevel(level)
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
self.logger = logging.getLogger('powerline')
|
||||||
|
self.logger.setLevel(level)
|
||||||
|
self.logger.addHandler(handler)
|
||||||
|
|
||||||
|
if not self.pl:
|
||||||
|
self.pl = PowerlineLogger(self.use_daemon_threads, self.logger, self.ext)
|
||||||
|
if not self.config_loader.pl:
|
||||||
|
self.config_loader.pl = self.pl
|
||||||
|
|
||||||
|
self.renderer_options.update(
|
||||||
|
pl=self.pl,
|
||||||
|
term_truecolor=self.common_config.get('term_truecolor', False),
|
||||||
|
ambiwidth=self.common_config.get('ambiwidth', 1),
|
||||||
|
tmux_escape=self.common_config.get('additional_escapes') == 'tmux',
|
||||||
|
screen_escape=self.common_config.get('additional_escapes') == 'screen',
|
||||||
|
theme_kwargs={
|
||||||
|
'ext': self.ext,
|
||||||
|
'common_config': self.common_config,
|
||||||
|
'run_once': self.run_once,
|
||||||
|
'shutdown_event': self.shutdown_event,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if not self.run_once and self.common_config.get('reload_config', True):
|
||||||
|
interval = self.common_config.get('interval', None)
|
||||||
|
self.config_loader.set_interval(interval)
|
||||||
|
self.run_loader_update = (interval is None)
|
||||||
|
if interval is not None and not self.config_loader.is_alive():
|
||||||
|
self.config_loader.start()
|
||||||
|
|
||||||
|
self.ext_config = config['ext'][self.ext]
|
||||||
|
if self.ext_config != self.prev_ext_config:
|
||||||
|
ext_config_differs = True
|
||||||
|
if not self.prev_ext_config or self.ext_config.get('local_themes') != self.prev_ext_config.get('local_themes'):
|
||||||
|
self.renderer_options['local_themes'] = self.get_local_themes(self.ext_config.get('local_themes'))
|
||||||
|
load_colorscheme = (load_colorscheme
|
||||||
|
or not self.prev_ext_config
|
||||||
|
or self.prev_ext_config['colorscheme'] != self.ext_config['colorscheme'])
|
||||||
|
load_theme = (load_theme
|
||||||
|
or not self.prev_ext_config
|
||||||
|
or self.prev_ext_config['theme'] != self.ext_config['theme'])
|
||||||
|
self.prev_ext_config = self.ext_config
|
||||||
|
|
||||||
|
create_renderer = load_colors or load_colorscheme or load_theme or common_config_differs or ext_config_differs
|
||||||
|
|
||||||
|
if load_colors:
|
||||||
|
self._purge_configs('colors')
|
||||||
|
self.colors_config = self.load_colors_config()
|
||||||
|
|
||||||
|
if load_colorscheme or load_colors:
|
||||||
|
self._purge_configs('colorscheme')
|
||||||
|
if load_colorscheme:
|
||||||
|
self.colorscheme_config = self.load_colorscheme_config(self.ext_config['colorscheme'])
|
||||||
|
self.renderer_options['colorscheme'] = Colorscheme(self.colorscheme_config, self.colors_config)
|
||||||
|
|
||||||
|
if load_theme:
|
||||||
|
self._purge_configs('theme')
|
||||||
|
self.renderer_options['theme_config'] = self.load_theme_config(self.ext_config.get('theme', 'default'))
|
||||||
|
|
||||||
|
if create_renderer:
|
||||||
|
try:
|
||||||
|
Renderer = __import__(self.renderer_module, fromlist=['renderer']).renderer
|
||||||
|
except Exception as e:
|
||||||
|
self.pl.exception('Failed to import renderer module: {0}', str(e))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Renderer updates configuration file via segments’ .startup thus it
|
||||||
|
# should be locked to prevent state when configuration was updated,
|
||||||
|
# but .render still uses old renderer.
|
||||||
|
try:
|
||||||
|
renderer = Renderer(**self.renderer_options)
|
||||||
|
except Exception as e:
|
||||||
|
self.pl.exception('Failed to construct renderer object: {0}', str(e))
|
||||||
|
if not hasattr(self, 'renderer'):
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
self.renderer = renderer
|
||||||
|
|
||||||
|
def get_log_handler(self):
|
||||||
|
'''Get log handler.
|
||||||
|
|
||||||
|
:param dict common_config:
|
||||||
|
Common configuration.
|
||||||
|
|
||||||
|
:return: logging.Handler subclass.
|
||||||
|
'''
|
||||||
|
log_file = self.common_config.get('log_file', None)
|
||||||
|
if log_file:
|
||||||
|
log_file = os.path.expanduser(log_file)
|
||||||
|
log_dir = os.path.dirname(log_file)
|
||||||
|
if not os.path.isdir(log_dir):
|
||||||
|
os.mkdir(log_dir)
|
||||||
|
return logging.FileHandler(log_file)
|
||||||
|
else:
|
||||||
|
return logging.StreamHandler()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_config_paths():
|
||||||
|
'''Get configuration paths.
|
||||||
|
|
||||||
|
:return: list of paths
|
||||||
|
'''
|
||||||
|
config_home = os.environ.get('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config'))
|
||||||
|
config_path = os.path.join(config_home, 'powerline')
|
||||||
|
config_paths = [config_path]
|
||||||
|
config_dirs = os.environ.get('XDG_CONFIG_DIRS', DEFAULT_SYSTEM_CONFIG_DIR)
|
||||||
|
if config_dirs is not None:
|
||||||
|
config_paths.extend([os.path.join(d, 'powerline') for d in config_dirs.split(':')])
|
||||||
|
plugin_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'config_files')
|
||||||
|
config_paths.append(plugin_path)
|
||||||
|
return config_paths
|
||||||
|
|
||||||
|
def _load_config(self, cfg_path, type):
|
||||||
|
'''Load configuration and setup watches.'''
|
||||||
|
function = getattr(self, 'on_' + type + '_change')
|
||||||
|
try:
|
||||||
|
path = self.find_config_file(cfg_path)
|
||||||
|
except IOError:
|
||||||
|
self.config_loader.register_missing(self.find_config_file, function, cfg_path)
|
||||||
|
raise
|
||||||
|
self.config_loader.register(function, path)
|
||||||
|
return self.config_loader.load(path)
|
||||||
|
|
||||||
|
def _purge_configs(self, type):
|
||||||
|
function = getattr(self, 'on_' + type + '_change')
|
||||||
|
self.config_loader.unregister_functions(set((function,)))
|
||||||
|
self.config_loader.unregister_missing(set(((self.find_config_file, function),)))
|
||||||
|
|
||||||
|
def load_theme_config(self, name):
|
||||||
|
'''Get theme configuration.
|
||||||
|
|
||||||
|
:param str name:
|
||||||
|
Name of the theme to load.
|
||||||
|
|
||||||
|
:return: dictionary with :ref:`theme configuration <config-themes>`
|
||||||
|
'''
|
||||||
|
return self._load_config(os.path.join('themes', self.ext, name), 'theme')
|
||||||
|
|
||||||
|
def load_main_config(self):
|
||||||
|
'''Get top-level configuration.
|
||||||
|
|
||||||
|
:return: dictionary with :ref:`top-level configuration <config-main>`.
|
||||||
|
'''
|
||||||
|
return self._load_config('config', 'main')
|
||||||
|
|
||||||
|
def load_colorscheme_config(self, name):
|
||||||
|
'''Get colorscheme.
|
||||||
|
|
||||||
|
:param str name:
|
||||||
|
Name of the colorscheme to load.
|
||||||
|
|
||||||
|
:return: dictionary with :ref:`colorscheme configuration <config-colorschemes>`.
|
||||||
|
'''
|
||||||
|
return self._load_config(os.path.join('colorschemes', self.ext, name), 'colorscheme')
|
||||||
|
|
||||||
|
def load_colors_config(self):
|
||||||
|
'''Get colorscheme.
|
||||||
|
|
||||||
|
:return: dictionary with :ref:`colors configuration <config-colors>`.
|
||||||
|
'''
|
||||||
|
return self._load_config('colors', 'colors')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_local_themes(local_themes):
|
||||||
|
'''Get local themes. No-op here, to be overridden in subclasses if
|
||||||
|
required.
|
||||||
|
|
||||||
|
:param dict local_themes:
|
||||||
|
Usually accepts ``{matcher_name : theme_name}``. May also receive
|
||||||
|
None in case there is no local_themes configuration.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
anything accepted by ``self.renderer.get_theme`` and processable by
|
||||||
|
``self.renderer.add_local_theme``. Renderer module is determined by
|
||||||
|
``__init__`` arguments, refer to its documentation.
|
||||||
|
'''
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_renderer(self):
|
||||||
|
'''Updates/creates a renderer if needed.'''
|
||||||
|
if self.run_loader_update:
|
||||||
|
self.config_loader.update()
|
||||||
|
create_renderer_kwargs = None
|
||||||
|
with self.cr_kwargs_lock:
|
||||||
|
if self.create_renderer_kwargs:
|
||||||
|
create_renderer_kwargs = self.create_renderer_kwargs.copy()
|
||||||
|
if create_renderer_kwargs:
|
||||||
|
try:
|
||||||
|
self.create_renderer(**create_renderer_kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
self.pl.exception('Failed to create renderer: {0}', str(e))
|
||||||
|
finally:
|
||||||
|
self.create_renderer_kwargs.clear()
|
||||||
|
|
||||||
|
def render(self, *args, **kwargs):
|
||||||
|
'''Update/create renderer if needed and pass all arguments further to
|
||||||
|
``self.renderer.render()``.
|
||||||
|
'''
|
||||||
|
self.update_renderer()
|
||||||
|
return self.renderer.render(*args, **kwargs)
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
'''Shut down all background threads. Must be run only prior to exiting
|
||||||
|
current application.
|
||||||
|
'''
|
||||||
|
self.shutdown_event.set()
|
||||||
|
self.renderer.shutdown()
|
||||||
|
functions = (
|
||||||
|
self.on_main_change,
|
||||||
|
self.on_colors_change,
|
||||||
|
self.on_colorscheme_change,
|
||||||
|
self.on_theme_change,
|
||||||
|
)
|
||||||
|
self.config_loader.unregister_functions(set(functions))
|
||||||
|
self.config_loader.unregister_missing(set(((find_config_file, function) for function in functions)))
|
||||||
|
|
||||||
|
def on_main_change(self, path):
|
||||||
|
with self.cr_kwargs_lock:
|
||||||
|
self.create_renderer_kwargs['load_main'] = True
|
||||||
|
|
||||||
|
def on_colors_change(self, path):
|
||||||
|
with self.cr_kwargs_lock:
|
||||||
|
self.create_renderer_kwargs['load_colors'] = True
|
||||||
|
|
||||||
|
def on_colorscheme_change(self, path):
|
||||||
|
with self.cr_kwargs_lock:
|
||||||
|
self.create_renderer_kwargs['load_colorscheme'] = True
|
||||||
|
|
||||||
|
def on_theme_change(self, path):
|
||||||
|
with self.cr_kwargs_lock:
|
||||||
|
self.create_renderer_kwargs['load_theme'] = True
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
self.shutdown()
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline import Powerline
|
||||||
|
import sys
|
||||||
|
from time import sleep
|
||||||
|
from powerline.lib.monotonic import monotonic
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
powerline = Powerline('wm', renderer_module='pango_markup')
|
||||||
|
powerline.update_renderer()
|
||||||
|
|
||||||
|
try:
|
||||||
|
interval = float(sys.argv[1])
|
||||||
|
except IndexError:
|
||||||
|
interval = 2
|
||||||
|
|
||||||
|
|
||||||
|
def read_to_log(pl, client):
|
||||||
|
for line in client.stdout:
|
||||||
|
if line:
|
||||||
|
pl.info(line, prefix='awesome-client')
|
||||||
|
for line in client.stderr:
|
||||||
|
if line:
|
||||||
|
pl.error(line, prefix='awesome-client')
|
||||||
|
if client.wait():
|
||||||
|
pl.error('Client exited with {0}', client.returncode, prefix='awesome')
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
start_time = monotonic()
|
||||||
|
s = powerline.render(side='right')
|
||||||
|
request = "powerline_widget:set_markup('" + s.replace('\\', '\\\\').replace("'", "\\'") + "')\n"
|
||||||
|
client = Popen(['awesome-client'], shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE)
|
||||||
|
client.stdin.write(request.encode('utf-8'))
|
||||||
|
client.stdin.close()
|
||||||
|
read_to_log(powerline.pl, client)
|
||||||
|
sleep(max(interval - (monotonic() - start_time), 0.1))
|
|
@ -0,0 +1,11 @@
|
||||||
|
local wibox = require('wibox')
|
||||||
|
local awful = require('awful')
|
||||||
|
|
||||||
|
powerline_widget = wibox.widget.textbox()
|
||||||
|
powerline_widget:set_align('right')
|
||||||
|
|
||||||
|
function powerline(mode, widget) end
|
||||||
|
|
||||||
|
bindings_path = string.gsub(debug.getinfo(1).source:match('@(.*)$'), '/[^/]+$', '')
|
||||||
|
powerline_cmd = bindings_path .. '/powerline-awesome.py'
|
||||||
|
awful.util.spawn_with_shell('ps -C powerline-awesome.py || ' .. powerline_cmd)
|
|
@ -0,0 +1,28 @@
|
||||||
|
_powerline_tmux_setenv() {
|
||||||
|
if [[ -n "$TMUX" ]]; then
|
||||||
|
tmux setenv TMUX_"$1"_$(tmux display -p "#D" | tr -d %) "$2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_powerline_tmux_set_pwd() {
|
||||||
|
_powerline_tmux_setenv PWD "$PWD"
|
||||||
|
}
|
||||||
|
|
||||||
|
_powerline_tmux_set_columns() {
|
||||||
|
_powerline_tmux_setenv COLUMNS "$COLUMNS"
|
||||||
|
}
|
||||||
|
|
||||||
|
_powerline_prompt() {
|
||||||
|
local last_exit_code=$?
|
||||||
|
[[ -z "$POWERLINE_OLD_PROMPT_COMMAND" ]] ||
|
||||||
|
eval $POWERLINE_OLD_PROMPT_COMMAND
|
||||||
|
PS1="$(powerline shell left -r bash_prompt --last_exit_code=$last_exit_code)"
|
||||||
|
_powerline_tmux_set_pwd
|
||||||
|
}
|
||||||
|
|
||||||
|
trap "_powerline_tmux_set_columns" SIGWINCH
|
||||||
|
_powerline_tmux_set_columns
|
||||||
|
|
||||||
|
[[ "$PROMPT_COMMAND" == "_powerline_prompt" ]] ||
|
||||||
|
POWERLINE_OLD_PROMPT_COMMAND="$PROMPT_COMMAND"
|
||||||
|
export PROMPT_COMMAND="_powerline_prompt"
|
|
@ -0,0 +1,61 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from powerline.ipython import IpythonPowerline
|
||||||
|
|
||||||
|
from IPython.core.prompts import PromptManager
|
||||||
|
from IPython.core.hooks import TryNext
|
||||||
|
|
||||||
|
|
||||||
|
class IpythonInfo(object):
|
||||||
|
def __init__(self, shell):
|
||||||
|
self._shell = shell
|
||||||
|
|
||||||
|
@property
|
||||||
|
def prompt_count(self):
|
||||||
|
return self._shell.execution_count
|
||||||
|
|
||||||
|
|
||||||
|
class PowerlinePromptManager(PromptManager):
|
||||||
|
powerline = None
|
||||||
|
|
||||||
|
def __init__(self, powerline, shell):
|
||||||
|
self.powerline = powerline
|
||||||
|
self.powerline_segment_info = IpythonInfo(shell)
|
||||||
|
self.shell = shell
|
||||||
|
|
||||||
|
def render(self, name, color=True, *args, **kwargs):
|
||||||
|
width = None if name == 'in' else self.width
|
||||||
|
res, res_nocolor = self.powerline.render(output_raw=True, width=width, matcher_info=name, segment_info=self.powerline_segment_info)
|
||||||
|
self.txtwidth = len(res_nocolor)
|
||||||
|
self.width = self.txtwidth
|
||||||
|
return res if color else res_nocolor
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurableIpythonPowerline(IpythonPowerline):
|
||||||
|
def __init__(self, ip):
|
||||||
|
config = ip.config.Powerline
|
||||||
|
self.config_overrides = config.get('config_overrides')
|
||||||
|
self.theme_overrides = config.get('theme_overrides', {})
|
||||||
|
self.path = config.get('path')
|
||||||
|
super(ConfigurableIpythonPowerline, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
old_prompt_manager = None
|
||||||
|
|
||||||
|
|
||||||
|
def load_ipython_extension(ip):
|
||||||
|
global old_prompt_manager
|
||||||
|
|
||||||
|
old_prompt_manager = ip.prompt_manager
|
||||||
|
powerline = ConfigurableIpythonPowerline(ip)
|
||||||
|
|
||||||
|
ip.prompt_manager = PowerlinePromptManager(powerline=powerline, shell=ip.prompt_manager.shell)
|
||||||
|
|
||||||
|
def shutdown_hook():
|
||||||
|
powerline.shutdown()
|
||||||
|
raise TryNext()
|
||||||
|
|
||||||
|
ip.hooks.shutdown_hook.add(shutdown_hook)
|
||||||
|
|
||||||
|
|
||||||
|
def unload_ipython_extension(ip):
|
||||||
|
ip.prompt_manager = old_prompt_manager
|
|
@ -0,0 +1,135 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from powerline.ipython import IpythonPowerline
|
||||||
|
from IPython.Prompts import BasePrompt
|
||||||
|
from IPython.ipapi import get as get_ipython
|
||||||
|
from IPython.ipapi import TryNext
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def string(s):
|
||||||
|
if type(s) is not str:
|
||||||
|
return s.encode('utf-8')
|
||||||
|
else:
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
# HACK: ipython tries to only leave us with plain ASCII
|
||||||
|
class RewriteResult(object):
|
||||||
|
def __init__(self, prompt):
|
||||||
|
self.prompt = string(prompt)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.prompt
|
||||||
|
|
||||||
|
def __add__(self, s):
|
||||||
|
if type(s) is not str:
|
||||||
|
try:
|
||||||
|
s = s.encode('utf-8')
|
||||||
|
except AttributeError:
|
||||||
|
raise NotImplementedError
|
||||||
|
return RewriteResult(self.prompt + s)
|
||||||
|
|
||||||
|
|
||||||
|
class IpythonInfo(object):
|
||||||
|
def __init__(self, cache):
|
||||||
|
self._cache = cache
|
||||||
|
|
||||||
|
@property
|
||||||
|
def prompt_count(self):
|
||||||
|
return self._cache.prompt_count
|
||||||
|
|
||||||
|
|
||||||
|
class PowerlinePrompt(BasePrompt):
|
||||||
|
def __init__(self, powerline, powerline_last_in, old_prompt):
|
||||||
|
self.powerline = powerline
|
||||||
|
self.powerline_last_in = powerline_last_in
|
||||||
|
self.powerline_segment_info = IpythonInfo(old_prompt.cache)
|
||||||
|
self.cache = old_prompt.cache
|
||||||
|
if hasattr(old_prompt, 'sep'):
|
||||||
|
self.sep = old_prompt.sep
|
||||||
|
self.pad_left = False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
self.set_p_str()
|
||||||
|
return string(self.p_str)
|
||||||
|
|
||||||
|
def set_p_str(self, width=None):
|
||||||
|
self.p_str, self.p_str_nocolor = (
|
||||||
|
self.powerline.render(output_raw=True,
|
||||||
|
segment_info=self.powerline_segment_info,
|
||||||
|
matcher_info=self.powerline_prompt_type,
|
||||||
|
width=width)
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_colors():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PowerlinePrompt1(PowerlinePrompt):
|
||||||
|
powerline_prompt_type = 'in'
|
||||||
|
rspace = re.compile(r'(\s*)$')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
self.cache.prompt_count += 1
|
||||||
|
self.set_p_str()
|
||||||
|
self.cache.last_prompt = self.p_str_nocolor.split('\n')[-1]
|
||||||
|
return string(self.p_str)
|
||||||
|
|
||||||
|
def set_p_str(self):
|
||||||
|
super(PowerlinePrompt1, self).set_p_str()
|
||||||
|
self.nrspaces = len(self.rspace.search(self.p_str_nocolor).group())
|
||||||
|
self.prompt_text_len = len(self.p_str_nocolor) - self.nrspaces
|
||||||
|
self.powerline_last_in['nrspaces'] = self.nrspaces
|
||||||
|
self.powerline_last_in['prompt_text_len'] = self.prompt_text_len
|
||||||
|
|
||||||
|
def auto_rewrite(self):
|
||||||
|
return RewriteResult(self.powerline.render(matcher_info='rewrite', width=self.prompt_text_len, segment_info=self.powerline_segment_info)
|
||||||
|
+ (' ' * self.nrspaces))
|
||||||
|
|
||||||
|
|
||||||
|
class PowerlinePromptOut(PowerlinePrompt):
|
||||||
|
powerline_prompt_type = 'out'
|
||||||
|
|
||||||
|
def set_p_str(self):
|
||||||
|
super(PowerlinePromptOut, self).set_p_str(width=self.powerline_last_in['prompt_text_len'])
|
||||||
|
spaces = ' ' * self.powerline_last_in['nrspaces']
|
||||||
|
self.p_str += spaces
|
||||||
|
self.p_str_nocolor += spaces
|
||||||
|
|
||||||
|
|
||||||
|
class PowerlinePrompt2(PowerlinePromptOut):
|
||||||
|
powerline_prompt_type = 'in2'
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurableIpythonPowerline(IpythonPowerline):
|
||||||
|
def __init__(self, config_overrides=None, theme_overrides={}, path=None):
|
||||||
|
self.config_overrides = config_overrides
|
||||||
|
self.theme_overrides = theme_overrides
|
||||||
|
self.path = path
|
||||||
|
super(ConfigurableIpythonPowerline, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def setup(**kwargs):
|
||||||
|
ip = get_ipython()
|
||||||
|
|
||||||
|
powerline = ConfigurableIpythonPowerline(**kwargs)
|
||||||
|
|
||||||
|
def late_startup_hook():
|
||||||
|
last_in = {'nrspaces': 0, 'prompt_text_len': None}
|
||||||
|
for attr, prompt_class in (
|
||||||
|
('prompt1', PowerlinePrompt1),
|
||||||
|
('prompt2', PowerlinePrompt2),
|
||||||
|
('prompt_out', PowerlinePromptOut)
|
||||||
|
):
|
||||||
|
old_prompt = getattr(ip.IP.outputcache, attr)
|
||||||
|
setattr(ip.IP.outputcache, attr, prompt_class(powerline, last_in, old_prompt))
|
||||||
|
raise TryNext()
|
||||||
|
|
||||||
|
def shutdown_hook():
|
||||||
|
powerline.shutdown()
|
||||||
|
raise TryNext()
|
||||||
|
|
||||||
|
ip.IP.hooks.late_startup_hook.add(late_startup_hook)
|
||||||
|
ip.IP.hooks.shutdown_hook.add(shutdown_hook)
|
|
@ -0,0 +1,36 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from libqtile import bar
|
||||||
|
from libqtile.widget import base
|
||||||
|
|
||||||
|
from powerline import Powerline as PowerlineCore
|
||||||
|
|
||||||
|
|
||||||
|
class Powerline(base._TextBox):
|
||||||
|
def __init__(self, timeout=2, text=" ", width=bar.CALCULATED, **config):
|
||||||
|
base._TextBox.__init__(self, text, width, **config)
|
||||||
|
self.timeout_add(timeout, self.update)
|
||||||
|
self.powerline = PowerlineCore(ext='wm', renderer_module='pango_markup')
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
if not self.configured:
|
||||||
|
return True
|
||||||
|
self.text = self.powerline.render(side='right')
|
||||||
|
self.bar.draw()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def cmd_update(self, text):
|
||||||
|
self.update(text)
|
||||||
|
|
||||||
|
def cmd_get(self):
|
||||||
|
return self.text
|
||||||
|
|
||||||
|
def _configure(self, qtile, bar):
|
||||||
|
base._TextBox._configure(self, qtile, bar)
|
||||||
|
self.layout = self.drawer.textlayout(
|
||||||
|
self.text,
|
||||||
|
self.foreground,
|
||||||
|
self.font,
|
||||||
|
self.fontsize,
|
||||||
|
self.fontshadow,
|
||||||
|
markup=True)
|
|
@ -0,0 +1,11 @@
|
||||||
|
set -g status on
|
||||||
|
set -g status-utf8 on
|
||||||
|
set -g status-interval 2
|
||||||
|
set -g status-fg colour231
|
||||||
|
set -g status-bg colour234
|
||||||
|
set -g status-left-length 20
|
||||||
|
set -g status-left '#[fg=colour16,bg=colour254,bold] #S #[fg=colour254,bg=colour234,nobold]#(powerline tmux left)'
|
||||||
|
set -g status-right '#(powerline tmux right)'
|
||||||
|
set -g status-right-length 150
|
||||||
|
set -g window-status-format "#[fg=colour244,bg=colour234]#I #[fg=colour240] #[fg=colour249]#W "
|
||||||
|
set -g window-status-current-format "#[fg=colour234,bg=colour31]#[fg=colour117,bg=colour31] #I #[fg=colour231,bold]#W #[fg=colour31,bg=colour234,nobold]"
|
|
@ -0,0 +1,64 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import vim
|
||||||
|
except ImportError:
|
||||||
|
vim = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
_vim_globals = vim.bindeval('g:')
|
||||||
|
|
||||||
|
def vim_set_global_var(var, val):
|
||||||
|
'''Set a global var in vim using bindeval().'''
|
||||||
|
_vim_globals[var] = val
|
||||||
|
|
||||||
|
def vim_get_func(f, rettype=None):
|
||||||
|
'''Return a vim function binding.'''
|
||||||
|
try:
|
||||||
|
func = vim.bindeval('function("' + f + '")')
|
||||||
|
if sys.version_info >= (3,) and rettype is str:
|
||||||
|
return (lambda *args, **kwargs: func(*args, **kwargs).decode('utf-8', errors='replace'))
|
||||||
|
return func
|
||||||
|
except vim.error:
|
||||||
|
return None
|
||||||
|
except AttributeError:
|
||||||
|
import json
|
||||||
|
|
||||||
|
def vim_set_global_var(var, val): # NOQA
|
||||||
|
'''Set a global var in vim using vim.command().
|
||||||
|
|
||||||
|
This is a fallback function for older vim versions.
|
||||||
|
'''
|
||||||
|
vim.command('let g:{0}={1}'.format(var, json.dumps(val)))
|
||||||
|
|
||||||
|
class VimFunc(object):
|
||||||
|
'''Evaluate a vim function using vim.eval().
|
||||||
|
|
||||||
|
This is a fallback class for older vim versions.
|
||||||
|
'''
|
||||||
|
__slots__ = ('f', 'rettype')
|
||||||
|
|
||||||
|
def __init__(self, f, rettype=None):
|
||||||
|
self.f = f
|
||||||
|
self.rettype = rettype
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
r = vim.eval(self.f + '(' + json.dumps(args)[1:-1] + ')')
|
||||||
|
if self.rettype:
|
||||||
|
return self.rettype(r)
|
||||||
|
return r
|
||||||
|
|
||||||
|
vim_get_func = VimFunc
|
||||||
|
|
||||||
|
if sys.version_info < (3,) or not hasattr(vim, 'bindeval'):
|
||||||
|
getbufvar = vim_get_func('getbufvar')
|
||||||
|
else:
|
||||||
|
_getbufvar = vim_get_func('getbufvar')
|
||||||
|
|
||||||
|
def getbufvar(*args):
|
||||||
|
r = _getbufvar(*args)
|
||||||
|
if type(r) is bytes:
|
||||||
|
return r.decode('utf-8')
|
||||||
|
return r
|
|
@ -0,0 +1,95 @@
|
||||||
|
if exists('g:powerline_loaded')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:powerline_loaded = 1
|
||||||
|
|
||||||
|
function! s:CriticalError(message)
|
||||||
|
echohl ErrorMsg
|
||||||
|
echomsg a:message
|
||||||
|
echohl None
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
if ! has('python') && ! has('python3')
|
||||||
|
call s:CriticalError('You need vim compiled with Python 2.6+ or 3.2+ support
|
||||||
|
\ for Powerline to work. Please consult the documentation for more details.')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:powerline_pycmd = substitute(get(g:, 'powerline_pycmd', has('python') ? 'py' : 'py3'),
|
||||||
|
\'\v^(py)%[thon](3?)$', '\1\2', '')
|
||||||
|
let s:powerline_pyeval = get(g:, 'powerline_pyeval', s:powerline_pycmd.'eval')
|
||||||
|
|
||||||
|
let s:import_cmd = 'from powerline.vim import VimPowerline'
|
||||||
|
try
|
||||||
|
exec s:powerline_pycmd "try:\n"
|
||||||
|
\ ." ".s:import_cmd."\n"
|
||||||
|
\ ."except ImportError:\n"
|
||||||
|
\ ." import sys, vim\n"
|
||||||
|
\ ." sys.path.append(vim.eval('expand(\"<sfile>:h:h:h:h:h\")'))\n"
|
||||||
|
\ ." ".s:import_cmd
|
||||||
|
let s:launched = 1
|
||||||
|
finally
|
||||||
|
if !exists('s:launched')
|
||||||
|
call s:CriticalError('An error occurred while importing the Powerline package.
|
||||||
|
\ This could be caused by an invalid sys.path setting, or by an incompatible
|
||||||
|
\ Python version (Powerline requires Python 2.6+ or 3.2+ to work). Please consult
|
||||||
|
\ the troubleshooting section in the documentation for possible solutions.')
|
||||||
|
finish
|
||||||
|
else
|
||||||
|
unlet s:launched
|
||||||
|
endif
|
||||||
|
endtry
|
||||||
|
|
||||||
|
if !get(g:, 'powerline_debugging_pyeval') && exists('*'. s:powerline_pyeval)
|
||||||
|
let s:pyeval = function(s:powerline_pyeval)
|
||||||
|
else
|
||||||
|
exec s:powerline_pycmd 'import json, vim'
|
||||||
|
exec "function! s:pyeval(e)\n".
|
||||||
|
\ s:powerline_pycmd." vim.command('return ' + json.dumps(eval(vim.eval('a:e'))))\n".
|
||||||
|
\"endfunction"
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:last_window_id = 0
|
||||||
|
function! s:GetWinID(winnr)
|
||||||
|
let r = getwinvar(a:winnr, 'window_id')
|
||||||
|
if empty(r)
|
||||||
|
let r = s:last_window_id
|
||||||
|
let s:last_window_id += 1
|
||||||
|
call setwinvar(a:winnr, 'window_id', r)
|
||||||
|
endif
|
||||||
|
" Without this condition it triggers unneeded statusline redraw
|
||||||
|
if getwinvar(a:winnr, '&statusline') isnot# '%!Powerline('.r.')'
|
||||||
|
call setwinvar(a:winnr, '&statusline', '%!Powerline('.r.')')
|
||||||
|
endif
|
||||||
|
return r
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! Powerline(window_id)
|
||||||
|
let winidx = index(map(range(1, winnr('$')), 's:GetWinID(v:val)'), a:window_id)
|
||||||
|
let current = w:window_id is# a:window_id
|
||||||
|
return s:pyeval('powerline.render('. a:window_id .', '. winidx .', '. current .')')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! PowerlineNew()
|
||||||
|
call map(range(1, winnr('$')), 's:GetWinID(v:val)')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! PowerlineRegisterCachePurgerEvent(event)
|
||||||
|
exec s:powerline_pycmd 'from powerline.segments.vim import launchevent as powerline_launchevent'
|
||||||
|
augroup Powerline
|
||||||
|
exec 'autocmd' a:event '*' s:powerline_pycmd.' powerline_launchevent("'.a:event.'")'
|
||||||
|
augroup END
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup Powerline
|
||||||
|
autocmd! ColorScheme * :exec s:powerline_pycmd 'powerline.reset_highlight()'
|
||||||
|
autocmd! VimEnter * :redrawstatus!
|
||||||
|
autocmd! VimLeavePre * :exec s:powerline_pycmd 'powerline.shutdown()'
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
exec s:powerline_pycmd 'powerline = VimPowerline()'
|
||||||
|
exec s:powerline_pycmd 'del VimPowerline'
|
||||||
|
" Is immediately changed when PowerlineNew() function is run. Good for global
|
||||||
|
" value.
|
||||||
|
set statusline=%!PowerlineNew()
|
||||||
|
call PowerlineNew()
|
|
@ -0,0 +1,128 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
import zsh
|
||||||
|
import atexit
|
||||||
|
from powerline.shell import ShellPowerline
|
||||||
|
from powerline.lib import parsedotval
|
||||||
|
|
||||||
|
|
||||||
|
used_powerlines = []
|
||||||
|
|
||||||
|
|
||||||
|
def shutdown():
|
||||||
|
for powerline in used_powerlines:
|
||||||
|
powerline.shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
def get_var_config(var):
|
||||||
|
try:
|
||||||
|
return [parsedotval(i) for i in zsh.getvalue(var).items()]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Args(object):
|
||||||
|
ext = ['shell']
|
||||||
|
renderer_module = 'zsh_prompt'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_exit_code(self):
|
||||||
|
return zsh.last_exit_code()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_pipe_status(self):
|
||||||
|
return zsh.pipestatus()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config(self):
|
||||||
|
try:
|
||||||
|
return get_var_config('POWERLINE_CONFIG')
|
||||||
|
except IndexError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def theme_option(self):
|
||||||
|
try:
|
||||||
|
return get_var_config('POWERLINE_THEME_CONFIG')
|
||||||
|
except IndexError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config_path(self):
|
||||||
|
try:
|
||||||
|
return zsh.getvalue('POWERLINE_CONFIG_PATH')
|
||||||
|
except IndexError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def string(s):
|
||||||
|
if type(s) is bytes:
|
||||||
|
return s.decode('utf-8', errors='replace')
|
||||||
|
else:
|
||||||
|
return str(s)
|
||||||
|
|
||||||
|
|
||||||
|
class Environment(object):
|
||||||
|
@staticmethod
|
||||||
|
def __getitem__(key):
|
||||||
|
try:
|
||||||
|
return string(zsh.getvalue(key))
|
||||||
|
except IndexError as e:
|
||||||
|
raise KeyError(*e.args)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(key, default=None):
|
||||||
|
try:
|
||||||
|
return string(zsh.getvalue(key))
|
||||||
|
except IndexError:
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
environ = Environment()
|
||||||
|
|
||||||
|
|
||||||
|
class Prompt(object):
|
||||||
|
__slots__ = ('powerline', 'side', 'savedpsvar', 'savedps', 'args')
|
||||||
|
|
||||||
|
def __init__(self, powerline, side, savedpsvar=None, savedps=None):
|
||||||
|
self.powerline = powerline
|
||||||
|
self.side = side
|
||||||
|
self.savedpsvar = savedpsvar
|
||||||
|
self.savedps = savedps
|
||||||
|
self.args = powerline.args
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
r = self.powerline.render(
|
||||||
|
width=zsh.columns(),
|
||||||
|
side=self.side,
|
||||||
|
segment_info={'args': self.args, 'environ': environ}
|
||||||
|
)
|
||||||
|
if type(r) is not str:
|
||||||
|
if type(r) is bytes:
|
||||||
|
return r.decode('utf-8')
|
||||||
|
else:
|
||||||
|
return r.encode('utf-8')
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
if self.savedps:
|
||||||
|
zsh.setvalue(self.savedpsvar, self.savedps)
|
||||||
|
used_powerlines.remove(self.powerline)
|
||||||
|
if self.powerline not in used_powerlines:
|
||||||
|
self.powerline.shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
def set_prompt(powerline, psvar, side):
|
||||||
|
savedps = zsh.getvalue(psvar)
|
||||||
|
zpyvar = 'ZPYTHON_POWERLINE_' + psvar
|
||||||
|
prompt = Prompt(powerline, side, psvar, savedps)
|
||||||
|
zsh.set_special_string(zpyvar, prompt)
|
||||||
|
zsh.setvalue(psvar, '${' + zpyvar + '}')
|
||||||
|
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
powerline = ShellPowerline(Args())
|
||||||
|
used_powerlines.append(powerline)
|
||||||
|
used_powerlines.append(powerline)
|
||||||
|
set_prompt(powerline, 'PS1', 'left')
|
||||||
|
set_prompt(powerline, 'RPS1', 'right')
|
||||||
|
atexit.register(shutdown)
|
|
@ -0,0 +1,39 @@
|
||||||
|
_powerline_tmux_setenv() {
|
||||||
|
emulate -L zsh
|
||||||
|
if [[ -n "$TMUX" ]]; then
|
||||||
|
tmux setenv TMUX_"$1"_$(tmux display -p "#D" | tr -d %) "$2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_powerline_tmux_set_pwd() {
|
||||||
|
_powerline_tmux_setenv PWD "$PWD"
|
||||||
|
}
|
||||||
|
|
||||||
|
_powerline_tmux_set_columns() {
|
||||||
|
_powerline_tmux_setenv COLUMNS "$COLUMNS"
|
||||||
|
}
|
||||||
|
|
||||||
|
_powerline_install_precmd() {
|
||||||
|
emulate zsh
|
||||||
|
for f in "${precmd_functions[@]}"; do
|
||||||
|
if [[ "$f" = "_powerline_precmd" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
chpwd_functions+=( _powerline_tmux_set_pwd )
|
||||||
|
setopt promptpercent
|
||||||
|
setopt promptsubst
|
||||||
|
if zmodload zsh/zpython &>/dev/null ; then
|
||||||
|
zpython 'from powerline.bindings.zsh import setup as powerline_setup'
|
||||||
|
zpython 'powerline_setup()'
|
||||||
|
zpython 'del powerline_setup'
|
||||||
|
else
|
||||||
|
PS1='$(powerline shell left -r zsh_prompt --last_exit_code=$? --last_pipe_status="$pipestatus")'
|
||||||
|
RPS1='$(powerline shell right -r zsh_prompt --last_exit_code=$? --last_pipe_status="$pipestatus")'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap "_powerline_tmux_set_columns" SIGWINCH
|
||||||
|
_powerline_tmux_set_columns
|
||||||
|
|
||||||
|
_powerline_install_precmd
|
|
@ -0,0 +1,143 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_MODE_KEY = None
|
||||||
|
ATTR_BOLD = 1
|
||||||
|
ATTR_ITALIC = 2
|
||||||
|
ATTR_UNDERLINE = 4
|
||||||
|
|
||||||
|
|
||||||
|
def get_attr_flag(attributes):
|
||||||
|
'''Convert an attribute array to a renderer flag.'''
|
||||||
|
attr_flag = 0
|
||||||
|
if 'bold' in attributes:
|
||||||
|
attr_flag |= ATTR_BOLD
|
||||||
|
if 'italic' in attributes:
|
||||||
|
attr_flag |= ATTR_ITALIC
|
||||||
|
if 'underline' in attributes:
|
||||||
|
attr_flag |= ATTR_UNDERLINE
|
||||||
|
return attr_flag
|
||||||
|
|
||||||
|
|
||||||
|
def pick_gradient_value(grad_list, gradient_level):
|
||||||
|
'''Given a list of colors and gradient percent, return a color that should be used.
|
||||||
|
|
||||||
|
Note: gradient level is not checked for being inside [0, 100] interval.
|
||||||
|
'''
|
||||||
|
return grad_list[int(round(gradient_level * (len(grad_list) - 1) / 100))]
|
||||||
|
|
||||||
|
|
||||||
|
def hl_iter(value):
|
||||||
|
if type(value) is list:
|
||||||
|
for v in value:
|
||||||
|
yield v
|
||||||
|
else:
|
||||||
|
yield value
|
||||||
|
|
||||||
|
|
||||||
|
class Colorscheme(object):
|
||||||
|
def __init__(self, colorscheme_config, colors_config):
|
||||||
|
'''Initialize a colorscheme.'''
|
||||||
|
self.colors = {}
|
||||||
|
self.gradients = {}
|
||||||
|
|
||||||
|
self.groups = colorscheme_config['groups']
|
||||||
|
self.translations = colorscheme_config.get('mode_translations', {})
|
||||||
|
|
||||||
|
# Create a dict of color tuples with both a cterm and hex value
|
||||||
|
for color_name, color in colors_config['colors'].items():
|
||||||
|
try:
|
||||||
|
self.colors[color_name] = (color[0], int(color[1], 16))
|
||||||
|
except TypeError:
|
||||||
|
self.colors[color_name] = (color, cterm_to_hex[color])
|
||||||
|
|
||||||
|
# Create a dict of gradient names with two lists: for cterm and hex
|
||||||
|
# values. Two lists in place of one list of pairs were chosen because
|
||||||
|
# true colors allow more precise gradients.
|
||||||
|
for gradient_name, gradient in colors_config['gradients'].items():
|
||||||
|
if len(gradient) == 2:
|
||||||
|
self.gradients[gradient_name] = (
|
||||||
|
(gradient[0], [int(color, 16) for color in gradient[1]]))
|
||||||
|
else:
|
||||||
|
self.gradients[gradient_name] = (
|
||||||
|
(gradient[0], [cterm_to_hex[color] for color in gradient[0]]))
|
||||||
|
|
||||||
|
def get_gradient(self, gradient, gradient_level):
|
||||||
|
if gradient in self.gradients:
|
||||||
|
return tuple((pick_gradient_value(grad_list, gradient_level) for grad_list in self.gradients[gradient]))
|
||||||
|
else:
|
||||||
|
return self.colors[gradient]
|
||||||
|
|
||||||
|
def get_highlighting(self, groups, mode, gradient_level=None):
|
||||||
|
trans = self.translations.get(mode, {})
|
||||||
|
for group in hl_iter(groups):
|
||||||
|
if 'groups' in trans and group in trans['groups']:
|
||||||
|
try:
|
||||||
|
group_props = trans['groups'][group]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
group_props = copy(self.groups[group])
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
ctrans = trans['colors']
|
||||||
|
for key in ('fg', 'bg'):
|
||||||
|
try:
|
||||||
|
group_props[key] = ctrans[group_props[key]]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise KeyError('Highlighting groups not found in colorscheme: ' + ', '.join(hl_iter(groups)))
|
||||||
|
|
||||||
|
if gradient_level is None:
|
||||||
|
pick_color = self.colors.__getitem__
|
||||||
|
else:
|
||||||
|
pick_color = lambda gradient: self.get_gradient(gradient, gradient_level)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'fg': pick_color(group_props['fg']),
|
||||||
|
'bg': pick_color(group_props['bg']),
|
||||||
|
'attr': get_attr_flag(group_props.get('attr', [])),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 0 1 2 3 4 5 6 7 8 9
|
||||||
|
cterm_to_hex = (
|
||||||
|
0x000000, 0xc00000, 0x008000, 0x804000, 0x0000c0, 0xc000c0, 0x008080, 0xc0c0c0, 0x808080, 0xff6060, # 0
|
||||||
|
0x00ff00, 0xffff00, 0x8080ff, 0xff40ff, 0x00ffff, 0xffffff, 0x000000, 0x00005f, 0x000087, 0x0000af, # 1
|
||||||
|
0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, # 2
|
||||||
|
0x008787, 0x0087af, 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, # 3
|
||||||
|
0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, 0x00ff87, 0x00ffaf, # 4
|
||||||
|
0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, # 5
|
||||||
|
0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, # 6
|
||||||
|
0x5faf00, 0x5faf5f, 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, # 7
|
||||||
|
0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, 0x870000, 0x87005f, # 8
|
||||||
|
0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, 0x875f87, 0x875faf, 0x875fd7, 0x875fff, # 9
|
||||||
|
0x878700, 0x87875f, 0x878787, 0x8787af, 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, # 10
|
||||||
|
0x87afd7, 0x87afff, 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, # 11
|
||||||
|
0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, 0xaf00d7, 0xaf00ff, # 12
|
||||||
|
0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, # 13
|
||||||
|
0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, # 14
|
||||||
|
0xafd787, 0xafd7af, 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, # 15
|
||||||
|
0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, 0xd75f87, 0xd75faf, # 16
|
||||||
|
0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, # 17
|
||||||
|
0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, # 18
|
||||||
|
0xd7ff00, 0xd7ff5f, 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af, # 19
|
||||||
|
0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, 0xff8700, 0xff875f, # 20
|
||||||
|
0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f, 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, # 21
|
||||||
|
0xffd700, 0xffd75f, 0xffd787, 0xffd7af, 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, # 22
|
||||||
|
0xffffd7, 0xffffff, 0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, # 23
|
||||||
|
0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, # 24
|
||||||
|
0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee # 25
|
||||||
|
)
|
|
@ -0,0 +1,106 @@
|
||||||
|
{
|
||||||
|
"colors": {
|
||||||
|
"black": 16,
|
||||||
|
"white": 231,
|
||||||
|
|
||||||
|
"darkestgreen": 22,
|
||||||
|
"darkgreen": 28,
|
||||||
|
"mediumgreen": 70,
|
||||||
|
"brightgreen": 148,
|
||||||
|
|
||||||
|
"darkestcyan": 23,
|
||||||
|
"darkcyan": 74,
|
||||||
|
"mediumcyan": 117,
|
||||||
|
"brightcyan": 159,
|
||||||
|
|
||||||
|
"darkestblue": 24,
|
||||||
|
"darkblue": 31,
|
||||||
|
|
||||||
|
"darkestred": 52,
|
||||||
|
"darkred": 88,
|
||||||
|
"mediumred": 124,
|
||||||
|
"brightred": 160,
|
||||||
|
"brightestred": 196,
|
||||||
|
|
||||||
|
"darkestpurple": 55,
|
||||||
|
"mediumpurple": 98,
|
||||||
|
"brightpurple": 189,
|
||||||
|
|
||||||
|
"darkorange": 94,
|
||||||
|
"mediumorange": 166,
|
||||||
|
"brightorange": 208,
|
||||||
|
"brightestorange": 214,
|
||||||
|
|
||||||
|
"brightyellow": 220,
|
||||||
|
|
||||||
|
"gray0": 233,
|
||||||
|
"gray1": 235,
|
||||||
|
"gray2": 236,
|
||||||
|
"gray3": 239,
|
||||||
|
"gray4": 240,
|
||||||
|
"gray5": 241,
|
||||||
|
"gray6": 244,
|
||||||
|
"gray7": 245,
|
||||||
|
"gray8": 247,
|
||||||
|
"gray9": 250,
|
||||||
|
"gray10": 252,
|
||||||
|
|
||||||
|
"gray61": [14, "93a1a1"],
|
||||||
|
"gray13": [8, "002b36"],
|
||||||
|
|
||||||
|
"royalblue5": [0, "073642"],
|
||||||
|
"darkgreencopper": [10, "586e75"],
|
||||||
|
"lightskyblue4": [11, "657b83"],
|
||||||
|
"azure4": [12, "839496"],
|
||||||
|
"lightyellow": [7, "eee8d5"],
|
||||||
|
"oldlace": [15, "fdf6e3"],
|
||||||
|
|
||||||
|
"green": [2, "719e07"],
|
||||||
|
"cyan": [6, "2aa198"],
|
||||||
|
"blue": [4, "268bd2"],
|
||||||
|
"red": [1, "dc322f"],
|
||||||
|
"magenta": [5, "d33682"],
|
||||||
|
"violet": [13, "6c71c4"],
|
||||||
|
"orange": [9, "cb4b16"],
|
||||||
|
"yellow": [3, "b58900"],
|
||||||
|
|
||||||
|
"lightyellowgreen": 106,
|
||||||
|
"gold3": 178,
|
||||||
|
"orangered": 202,
|
||||||
|
|
||||||
|
"steelblue": 67,
|
||||||
|
"darkorange3": 166,
|
||||||
|
"skyblue1": 117,
|
||||||
|
"khaki1": 228
|
||||||
|
},
|
||||||
|
"gradients": {
|
||||||
|
"dark_GREEN_Orange_red": [
|
||||||
|
[22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 94, 94, 94, 94, 94, 94, 94, 52],
|
||||||
|
["005f00", "015f00", "025f00", "035f00", "045f00", "055f00", "065f00", "075f00", "085f00", "095f00", "0b5f00", "0c5f00", "0d5f00", "0e5f00", "0f5f00", "105f00", "115f00", "125f00", "135f00", "145f00", "165f00", "175f00", "185f00", "195f00", "1a5f00", "1b5f00", "1c5f00", "1d5f00", "1e5f00", "1f5f00", "215f00", "225f00", "235f00", "245f00", "255f00", "265f00", "275f00", "285f00", "295f00", "2a5f00", "2c5f00", "2d5f00", "2e5f00", "2f5f00", "305f00", "315f00", "325f00", "335f00", "345f00", "355f00", "375f00", "385f00", "395f00", "3a5f00", "3b5f00", "3c5f00", "3d5f00", "3e5f00", "3f5f00", "415f00", "425f00", "435f00", "445f00", "455f00", "465f00", "475f00", "485f00", "495f00", "4a5f00", "4c5f00", "4d5f00", "4e5f00", "4f5f00", "505f00", "515f00", "525f00", "535f00", "545f00", "555f00", "575f00", "585f00", "595f00", "5a5f00", "5b5f00", "5c5f00", "5d5f00", "5e5f00", "615f00", "655f00", "685f00", "6c5f00", "6f5f00", "735f00", "765f00", "7a5f00", "7d5f00", "815f00", "845f00", "815200", "702900"]
|
||||||
|
],
|
||||||
|
"GREEN_Orange_red": [
|
||||||
|
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1],
|
||||||
|
["005f00", "015f00", "025f00", "035f00", "045f00", "055f00", "065f00", "075f00", "085f00", "095f00", "0b5f00", "0c5f00", "0d5f00", "0e5f00", "0f5f00", "105f00", "115f00", "125f00", "135f00", "145f00", "165f00", "175f00", "185f00", "195f00", "1a5f00", "1b5f00", "1c5f00", "1d5f00", "1e5f00", "1f5f00", "215f00", "225f00", "235f00", "245f00", "255f00", "265f00", "275f00", "285f00", "295f00", "2a5f00", "2c5f00", "2d5f00", "2e5f00", "2f5f00", "305f00", "315f00", "325f00", "335f00", "345f00", "355f00", "375f00", "385f00", "395f00", "3a5f00", "3b5f00", "3c5f00", "3d5f00", "3e5f00", "3f5f00", "415f00", "425f00", "435f00", "445f00", "455f00", "465f00", "475f00", "485f00", "495f00", "4a5f00", "4c5f00", "4d5f00", "4e5f00", "4f5f00", "505f00", "515f00", "525f00", "535f00", "545f00", "555f00", "575f00", "585f00", "595f00", "5a5f00", "5b5f00", "5c5f00", "5d5f00", "5e5f00", "615f00", "655f00", "685f00", "6c5f00", "6f5f00", "735f00", "765f00", "7a5f00", "7d5f00", "815f00", "845f00", "815200", "702900"]
|
||||||
|
],
|
||||||
|
"green_yellow_red": [
|
||||||
|
[190, 184, 178, 172, 166, 160],
|
||||||
|
["8ae71c", "8ce71c", "8fe71c", "92e71c", "95e71d", "98e71d", "9ae71d", "9de71d", "a0e71e", "a3e71e", "a6e71e", "a8e71e", "abe71f", "aee71f", "b1e71f", "b4e71f", "b6e720", "b9e720", "bce720", "bfe720", "c2e821", "c3e721", "c5e621", "c7e521", "c9e522", "cbe422", "cde322", "cfe222", "d1e223", "d3e123", "d5e023", "d7df23", "d9df24", "dbde24", "dddd24", "dfdc24", "e1dc25", "e3db25", "e5da25", "e7d925", "e9d926", "e9d626", "e9d426", "e9d126", "e9cf27", "e9cc27", "e9ca27", "e9c727", "e9c528", "e9c228", "e9c028", "e9bd28", "e9bb29", "e9b829", "e9b629", "e9b329", "e9b12a", "e9ae2a", "e9ac2a", "e9a92a", "eaa72b", "eaa42b", "eaa22b", "ea9f2b", "ea9d2c", "ea9b2c", "ea982c", "ea962c", "ea942d", "ea912d", "ea8f2d", "ea8d2d", "ea8a2e", "ea882e", "ea862e", "ea832e", "ea812f", "ea7f2f", "ea7c2f", "ea7a2f", "eb7830", "eb7530", "eb7330", "eb7130", "eb6f31", "eb6c31", "eb6a31", "eb6831", "eb6632", "eb6332", "eb6132", "eb5f32", "eb5d33", "eb5a33", "eb5833", "eb5633", "eb5434", "eb5134", "eb4f34", "eb4d34", "ec4b35"]
|
||||||
|
],
|
||||||
|
"green_yellow_orange_red": [
|
||||||
|
[2, 3, 9, 1],
|
||||||
|
["719e07", "739d06", "759c06", "779c06", "799b06", "7b9a05", "7d9a05", "7f9905", "819805", "839805", "859704", "879704", "899604", "8b9504", "8d9504", "8f9403", "919303", "949303", "969203", "989102", "9a9102", "9c9002", "9e9002", "a08f02", "a28e01", "a48e01", "a68d01", "a88c01", "aa8c01", "ac8b00", "ae8a00", "b08a00", "b28900", "b58900", "b58700", "b68501", "b78302", "b78102", "b87f03", "b97d04", "b97b04", "ba7905", "bb7806", "bb7606", "bc7407", "bd7208", "bd7008", "be6e09", "bf6c0a", "bf6a0a", "c0690b", "c1670c", "c1650c", "c2630d", "c3610e", "c35f0e", "c45d0f", "c55b10", "c55a10", "c65811", "c75612", "c75412", "c85213", "c95014", "c94e14", "ca4c15", "cb4b16", "cb4a16", "cc4917", "cc4818", "cd4719", "cd4719", "ce461a", "ce451b", "cf441c", "cf441c", "d0431d", "d0421e", "d1411f", "d1411f", "d24020", "d23f21", "d33e22", "d33e22", "d43d23", "d43c24", "d53b25", "d53b25", "d63a26", "d63927", "d73828", "d73828", "d83729", "d8362a", "d9352b", "d9352b", "da342c", "da332d", "db322e", "dc322f"]
|
||||||
|
],
|
||||||
|
"yellow_red": [
|
||||||
|
[220, 178, 172, 166, 160],
|
||||||
|
["ffd700", "fdd500", "fbd300", "fad200", "f8d000", "f7cf00", "f5cd00", "f3cb00", "f2ca00", "f0c800", "efc700", "edc500", "ebc300", "eac200", "e8c000", "e7bf00", "e5bd00", "e3bb00", "e2ba00", "e0b800", "dfb700", "ddb500", "dbb300", "dab200", "d8b000", "d7af00", "d7ad00", "d7ab00", "d7aa00", "d7a800", "d7a700", "d7a500", "d7a300", "d7a200", "d7a000", "d79f00", "d79d00", "d79b00", "d79a00", "d79800", "d79700", "d79500", "d79300", "d79200", "d79000", "d78f00", "d78d00", "d78b00", "d78a00", "d78800", "d78700", "d78500", "d78300", "d78200", "d78000", "d77f00", "d77d00", "d77b00", "d77a00", "d77800", "d77700", "d77500", "d77300", "d77200", "d77000", "d76f00", "d76d00", "d76b00", "d76a00", "d76800", "d76700", "d76500", "d76300", "d76200", "d76000", "d75f00", "d75b00", "d75700", "d75300", "d74f00", "d74c00", "d74800", "d74400", "d74000", "d73c00", "d73900", "d73500", "d73100", "d72d00", "d72900", "d72600", "d72200", "d71e00", "d71a00", "d71600", "d71300", "d70f00", "d70b00", "d70700"]
|
||||||
|
],
|
||||||
|
"yellow_orange_red": [
|
||||||
|
[3, 9, 1],
|
||||||
|
["b58900", "b58700", "b58600", "b68501", "b68401", "b78202", "b78102", "b88003", "b87f03", "b87d03", "b97c04", "b97b04", "ba7a05", "ba7805", "bb7706", "bb7606", "bc7507", "bc7307", "bc7207", "bd7108", "bd7008", "be6e09", "be6d09", "bf6c0a", "bf6b0a", "c06a0b", "c0680b", "c0670b", "c1660c", "c1650c", "c2630d", "c2620d", "c3610e", "c3600e", "c35e0e", "c45d0f", "c45c0f", "c55b10", "c55910", "c65811", "c65711", "c75612", "c75412", "c75312", "c85213", "c85113", "c94f14", "c94e14", "ca4d15", "ca4c15", "cb4b16", "cb4a16", "cb4a17", "cc4917", "cc4918", "cc4818", "cd4819", "cd4719", "cd471a", "ce461a", "ce461b", "ce451b", "cf451c", "cf441c", "cf441d", "d0431d", "d0431e", "d0421e", "d1421f", "d1411f", "d14120", "d24020", "d24021", "d23f21", "d33f22", "d33e22", "d33e23", "d43d23", "d43d24", "d43c24", "d53c25", "d53b25", "d53b26", "d63a26", "d63a27", "d63927", "d73928", "d73828", "d73829", "d83729", "d8372a", "d8362a", "d9362b", "d9352b", "d9352c", "da342c", "da342d", "da332d", "db332e"]
|
||||||
|
],
|
||||||
|
"blue_red": [
|
||||||
|
[39, 74, 68, 67, 103, 97, 96, 132, 131, 167, 203, 197],
|
||||||
|
["19b4fe", "1bb2fc", "1db1fa", "1faff8", "22aef6", "24adf4", "26abf2", "29aaf0", "2ba9ee", "2da7ec", "30a6ea", "32a5e8", "34a3e6", "36a2e4", "39a0e2", "3b9fe1", "3d9edf", "409cdd", "429bdb", "449ad9", "4798d7", "4997d5", "4b96d3", "4d94d1", "5093cf", "5292cd", "5490cb", "578fc9", "598dc7", "5b8cc6", "5e8bc4", "6089c2", "6288c0", "6487be", "6785bc", "6984ba", "6b83b8", "6e81b6", "7080b4", "727eb2", "757db0", "777cae", "797aac", "7b79ab", "7e78a9", "8076a7", "8275a5", "8574a3", "8772a1", "89719f", "8c709d", "8e6e9b", "906d99", "926b97", "956a95", "976993", "996791", "9c668f", "9e658e", "a0638c", "a3628a", "a56188", "a75f86", "a95e84", "ac5c82", "ae5b80", "b05a7e", "b3587c", "b5577a", "b75678", "ba5476", "bc5374", "be5273", "c05071", "c34f6f", "c54e6d", "c74c6b", "ca4b69", "cc4967", "ce4865", "d14763", "d34561", "d5445f", "d7435d", "da415b", "dc4059", "de3f58", "e13d56", "e33c54", "e53a52", "e83950", "ea384e", "ec364c", "ee354a", "f13448", "f33246", "f53144", "f83042", "fa2e40"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"name": "Default color scheme for IPython prompt",
|
||||||
|
"groups": {
|
||||||
|
"virtualenv": { "fg": "white", "bg": "darkcyan" },
|
||||||
|
"prompt": { "fg": "gray9", "bg": "gray4" },
|
||||||
|
"prompt_count": { "fg": "white", "bg": "gray4" }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "Default color scheme for shell prompts",
|
||||||
|
"groups": {
|
||||||
|
"user": { "fg": "white", "bg": "darkblue", "attr": ["bold"] },
|
||||||
|
"superuser": { "fg": "white", "bg": "brightred", "attr": ["bold"] },
|
||||||
|
"virtualenv": { "fg": "white", "bg": "darkcyan" },
|
||||||
|
"branch": { "fg": "gray9", "bg": "gray2" },
|
||||||
|
"branch_dirty": { "fg": "brightyellow", "bg": "gray2" },
|
||||||
|
"branch_clean": { "fg": "gray9", "bg": "gray2" },
|
||||||
|
"cwd": { "fg": "gray9", "bg": "gray4" },
|
||||||
|
"cwd:current_folder": { "fg": "gray10", "bg": "gray4", "attr": ["bold"] },
|
||||||
|
"cwd:divider": { "fg": "gray7", "bg": "gray4" },
|
||||||
|
"hostname": { "fg": "brightyellow", "bg": "mediumorange" },
|
||||||
|
"exit_fail": { "fg": "white", "bg": "darkestred" },
|
||||||
|
"exit_success": { "fg": "white", "bg": "darkestgreen" }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "Solarized Dark",
|
||||||
|
"groups": {
|
||||||
|
"user": { "fg": "oldlace", "bg": "blue", "attr": ["bold"] },
|
||||||
|
"superuser": { "fg": "oldlace", "bg": "red", "attr": ["bold"] },
|
||||||
|
"virtualenv": { "fg": "oldlace", "bg": "green" },
|
||||||
|
"branch": { "fg": "gray61", "bg": "royalblue5" },
|
||||||
|
"branch_dirty": { "fg": "yellow", "bg": "royalblue5" },
|
||||||
|
"branch_clean": { "fg": "gray61", "bg": "royalblue5" },
|
||||||
|
"cwd": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"cwd:current_folder": { "fg": "oldlace", "bg": "darkgreencopper", "attr": ["bold"] },
|
||||||
|
"cwd:divider": { "fg": "gray61", "bg": "darkgreencopper" },
|
||||||
|
"hostname": { "fg": "oldlace", "bg": "darkgreencopper" },
|
||||||
|
"exit_fail": { "fg": "oldlace", "bg": "red" },
|
||||||
|
"exit_success": { "fg": "oldlace", "bg": "green" }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "Default color scheme for terminal prompts",
|
||||||
|
"groups": {
|
||||||
|
"background:divider": { "fg": "gray5", "bg": "gray0" },
|
||||||
|
"session": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
|
||||||
|
"date": { "fg": "gray8", "bg": "gray2" },
|
||||||
|
"time": { "fg": "gray10", "bg": "gray2", "attr": ["bold"] },
|
||||||
|
"time:divider": { "fg": "gray5", "bg": "gray2" },
|
||||||
|
"email_alert": { "fg": "white", "bg": "brightred", "attr": ["bold"] },
|
||||||
|
"email_alert_gradient": { "fg": "white", "bg": "yellow_orange_red", "attr": ["bold"] },
|
||||||
|
"hostname": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
|
||||||
|
"weather": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"weather_temp_gradient": { "fg": "blue_red", "bg": "gray0" },
|
||||||
|
"weather_condition_hot": { "fg": "khaki1", "bg": "gray0" },
|
||||||
|
"weather_condition_snowy": { "fg": "skyblue1", "bg": "gray0" },
|
||||||
|
"weather_condition_rainy": { "fg": "skyblue1", "bg": "gray0" },
|
||||||
|
"uptime": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"external_ip": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"network_load": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"network_load_gradient": { "fg": "green_yellow_orange_red", "bg": "gray0" },
|
||||||
|
"system_load": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"system_load_gradient": { "fg": "green_yellow_orange_red", "bg": "gray0" }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
"name": "Default color scheme",
|
||||||
|
"groups": {
|
||||||
|
"background": { "fg": "white", "bg": "gray2" },
|
||||||
|
"background:divider": { "fg": "gray6", "bg": "gray2" },
|
||||||
|
"mode": { "fg": "darkestgreen", "bg": "brightgreen", "attr": ["bold"] },
|
||||||
|
"modified_indicator": { "fg": "brightyellow", "bg": "gray4", "attr": ["bold"] },
|
||||||
|
"paste_indicator": { "fg": "white", "bg": "mediumorange", "attr": ["bold"] },
|
||||||
|
"readonly_indicator": { "fg": "brightestred", "bg": "gray4" },
|
||||||
|
"branch": { "fg": "gray9", "bg": "gray4" },
|
||||||
|
"branch_dirty": { "fg": "brightyellow", "bg": "gray4" },
|
||||||
|
"branch_clean": { "fg": "gray9", "bg": "gray4" },
|
||||||
|
"branch:divider": { "fg": "gray7", "bg": "gray4" },
|
||||||
|
"file_directory": { "fg": "gray9", "bg": "gray4" },
|
||||||
|
"file_name": { "fg": "white", "bg": "gray4", "attr": ["bold"] },
|
||||||
|
"file_size": { "fg": "gray8", "bg": "gray2" },
|
||||||
|
"file_name_no_file": { "fg": "gray9", "bg": "gray4", "attr": ["bold"] },
|
||||||
|
"file_name_empty": { "fg": "gray9", "bg": "gray4" },
|
||||||
|
"file_format": { "fg": "gray8", "bg": "gray2" },
|
||||||
|
"file_encoding": { "fg": "gray8", "bg": "gray2" },
|
||||||
|
"file_type": { "fg": "gray8", "bg": "gray2" },
|
||||||
|
"file_vcs_status": { "fg": "brightestred", "bg": "gray4" },
|
||||||
|
"file_vcs_status_M": { "fg": "brightyellow", "bg": "gray4" },
|
||||||
|
"file_vcs_status_A": { "fg": "brightgreen", "bg": "gray4" },
|
||||||
|
"line_percent": { "fg": "gray9", "bg": "gray4" },
|
||||||
|
"line_percent_gradient": { "fg": "green_yellow_red", "bg": "gray4" },
|
||||||
|
"line_current": { "fg": "gray1", "bg": "gray10", "attr": ["bold"] },
|
||||||
|
"line_current_symbol": { "fg": "gray1", "bg": "gray10" },
|
||||||
|
"virtcol_current_gradient": { "fg": "dark_GREEN_Orange_red", "bg": "gray10" },
|
||||||
|
"col_current": { "fg": "gray6", "bg": "gray10" },
|
||||||
|
"modified_buffers": { "fg": "brightyellow", "bg": "gray2" }
|
||||||
|
},
|
||||||
|
"mode_translations": {
|
||||||
|
"nc": {
|
||||||
|
"colors": {
|
||||||
|
"brightyellow": "darkorange",
|
||||||
|
"brightestred": "darkred",
|
||||||
|
"gray0": "gray0",
|
||||||
|
"gray1": "gray0",
|
||||||
|
"gray2": "gray0",
|
||||||
|
"gray3": "gray1",
|
||||||
|
"gray4": "gray1",
|
||||||
|
"gray5": "gray1",
|
||||||
|
"gray6": "gray1",
|
||||||
|
"gray7": "gray4",
|
||||||
|
"gray8": "gray4",
|
||||||
|
"gray9": "gray4",
|
||||||
|
"gray10": "gray5",
|
||||||
|
"white": "gray6",
|
||||||
|
"green_yellow_red": "gray5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"i": {
|
||||||
|
"colors": {
|
||||||
|
"gray0": "darkestblue",
|
||||||
|
"gray1": "darkestblue",
|
||||||
|
"gray2": "darkestblue",
|
||||||
|
"gray3": "darkblue",
|
||||||
|
"gray4": "darkblue",
|
||||||
|
"gray5": "darkestcyan",
|
||||||
|
"gray6": "darkestcyan",
|
||||||
|
"gray7": "darkestcyan",
|
||||||
|
"gray8": "mediumcyan",
|
||||||
|
"gray9": "mediumcyan",
|
||||||
|
"gray10": "mediumcyan",
|
||||||
|
"green_yellow_red": "gray5"
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "darkestcyan", "bg": "white", "attr": ["bold"] },
|
||||||
|
"background:divider": { "fg": "darkcyan", "bg": "darkestblue" },
|
||||||
|
"branch:divider": { "fg": "darkcyan", "bg": "darkblue" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "darkorange", "bg": "brightestorange", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"V": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "darkorange", "bg": "brightestorange", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"^V": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "darkorange", "bg": "brightestorange", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"R": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "white", "bg": "brightred", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
{
|
||||||
|
"name": "Solarized Dark",
|
||||||
|
"groups": {
|
||||||
|
"background": { "fg": "oldlace", "bg": "royalblue5" },
|
||||||
|
"background:divider": { "fg": "lightskyblue4", "bg": "royalblue5" },
|
||||||
|
"mode": { "fg": "oldlace", "bg": "green", "attr": ["bold"] },
|
||||||
|
"modified_indicator": { "fg": "yellow", "bg": "darkgreencopper", "attr": ["bold"] },
|
||||||
|
"paste_indicator": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] },
|
||||||
|
"readonly_indicator": { "fg": "red", "bg": "darkgreencopper" },
|
||||||
|
"branch": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"branch_dirty": { "fg": "yellow", "bg": "darkgreencopper" },
|
||||||
|
"branch_clean": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"branch:divider": { "fg": "gray61", "bg": "darkgreencopper" },
|
||||||
|
"file_directory": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"file_name": { "fg": "oldlace", "bg": "darkgreencopper", "attr": ["bold"] },
|
||||||
|
"file_size": { "fg": "oldlace", "bg": "darkgreencopper" },
|
||||||
|
"file_name_no_file": { "fg": "oldlace", "bg": "darkgreencopper", "attr": ["bold"] },
|
||||||
|
"file_name_empty": { "fg": "oldlace", "bg": "darkgreencopper" },
|
||||||
|
"file_format": { "fg": "gray61", "bg": "royalblue5" },
|
||||||
|
"file_encoding": { "fg": "gray61", "bg": "royalblue5" },
|
||||||
|
"file_type": { "fg": "gray61", "bg": "royalblue5" },
|
||||||
|
"file_vcs_status": { "fg": "red", "bg": "darkgreencopper" },
|
||||||
|
"file_vcs_status_M": { "fg": "yellow", "bg": "darkgreencopper" },
|
||||||
|
"file_vcs_status_A": { "fg": "green", "bg": "darkgreencopper" },
|
||||||
|
"line_percent": { "fg": "oldlace", "bg": "lightskyblue4" },
|
||||||
|
"line_percent_gradient": { "fg": "green_yellow_orange_red", "bg": "lightskyblue4" },
|
||||||
|
"line_current": { "fg": "gray13", "bg": "lightyellow", "attr": ["bold"] },
|
||||||
|
"line_current_symbol": { "fg": "gray13", "bg": "lightyellow" },
|
||||||
|
"virtcol_current_gradient": { "fg": "GREEN_Orange_red", "bg": "gray10" },
|
||||||
|
"col_current": { "fg": "azure4", "bg": "lightyellow" }
|
||||||
|
},
|
||||||
|
"mode_translations": {
|
||||||
|
"nc": {
|
||||||
|
"colors": {
|
||||||
|
"darkgreencopper": "royalblue5",
|
||||||
|
"lightskyblue4": "royalblue5",
|
||||||
|
"azure4": "darkgreencopper",
|
||||||
|
"gray61": "lightskyblue4",
|
||||||
|
"lightyellow": "azure4",
|
||||||
|
"oldlace": "gray61"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"i": {
|
||||||
|
"groups": {
|
||||||
|
"background": { "fg": "oldlace", "bg": "darkgreencopper" },
|
||||||
|
"background:divider": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"mode": { "fg": "oldlace", "bg": "blue", "attr": ["bold"] },
|
||||||
|
"modified_indicator": { "fg": "yellow", "bg": "lightyellow", "attr": ["bold"] },
|
||||||
|
"paste_indicator": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] },
|
||||||
|
"readonly_indicator": { "fg": "red", "bg": "lightyellow" },
|
||||||
|
"branch": { "fg": "darkgreencopper", "bg": "lightyellow" },
|
||||||
|
"branch:divider": { "fg": "lightskyblue4", "bg": "lightyellow" },
|
||||||
|
"file_directory": { "fg": "darkgreencopper", "bg": "lightyellow" },
|
||||||
|
"file_name": { "fg": "royalblue5", "bg": "lightyellow", "attr": ["bold"] },
|
||||||
|
"file_size": { "fg": "royalblue5", "bg": "lightyellow" },
|
||||||
|
"file_name_no_file": { "fg": "royalblue5", "bg": "lightyellow", "attr": ["bold"] },
|
||||||
|
"file_name_empty": { "fg": "royalblue5", "bg": "lightyellow" },
|
||||||
|
"file_format": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"file_encoding": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"file_type": { "fg": "lightyellow", "bg": "darkgreencopper" },
|
||||||
|
"file_vcs_status": { "fg": "red", "bg": "lightyellow" },
|
||||||
|
"file_vcs_status_M": { "fg": "yellow", "bg": "lightyellow" },
|
||||||
|
"file_vcs_status_A": { "fg": "green", "bg": "lightyellow" },
|
||||||
|
"line_percent": { "fg": "oldlace", "bg": "gray61" },
|
||||||
|
"line_percent_gradient": { "fg": "oldlace", "bg": "gray61" },
|
||||||
|
"line_current": { "fg": "gray13", "bg": "oldlace", "attr": ["bold"] },
|
||||||
|
"line_current_symbol": { "fg": "gray13", "bg": "oldlace" },
|
||||||
|
"col_current": { "fg": "azure4", "bg": "oldlace" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"V": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"^V": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "oldlace", "bg": "orange", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"R": {
|
||||||
|
"groups": {
|
||||||
|
"mode": { "fg": "oldlace", "bg": "red", "attr": ["bold"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"name": "Default color scheme for window managers",
|
||||||
|
"groups": {
|
||||||
|
"background:divider": { "fg": "gray5", "bg": "gray0" },
|
||||||
|
"session": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
|
||||||
|
"date": { "fg": "gray8", "bg": "gray2" },
|
||||||
|
"time": { "fg": "gray10", "bg": "gray2", "attr": ["bold"] },
|
||||||
|
"time:divider": { "fg": "gray5", "bg": "gray2" },
|
||||||
|
"email_alert": { "fg": "white", "bg": "brightred", "attr": ["bold"] },
|
||||||
|
"email_alert_gradient": { "fg": "white", "bg": "yellow_orange_red", "attr": ["bold"] },
|
||||||
|
"hostname": { "fg": "black", "bg": "gray10", "attr": ["bold"] },
|
||||||
|
"weather": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"weather_temp_gradient": { "fg": "blue_red", "bg": "gray0" },
|
||||||
|
"weather_condition_hot": { "fg": "khaki1", "bg": "gray0" },
|
||||||
|
"weather_condition_snowy": { "fg": "skyblue1", "bg": "gray0" },
|
||||||
|
"weather_condition_rainy": { "fg": "skyblue1", "bg": "gray0" },
|
||||||
|
"uptime": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"external_ip": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"network_load": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"system_load": { "fg": "gray8", "bg": "gray0" },
|
||||||
|
"system_load_good": { "fg": "lightyellowgreen", "bg": "gray0" },
|
||||||
|
"system_load_bad": { "fg": "gold3", "bg": "gray0" },
|
||||||
|
"system_load_ugly": { "fg": "orangered", "bg": "gray0" }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"common": {
|
||||||
|
"term_truecolor": false,
|
||||||
|
"dividers": {
|
||||||
|
"left": {
|
||||||
|
"hard": " ",
|
||||||
|
"soft": " "
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"hard": " ",
|
||||||
|
"soft": " "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spaces": 1
|
||||||
|
},
|
||||||
|
"ext": {
|
||||||
|
"ipython": {
|
||||||
|
"colorscheme": "default",
|
||||||
|
"theme": "in",
|
||||||
|
"local_themes": {
|
||||||
|
"rewrite": "rewrite",
|
||||||
|
"out": "out",
|
||||||
|
"in2": "in2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shell": {
|
||||||
|
"colorscheme": "default",
|
||||||
|
"theme": "default"
|
||||||
|
},
|
||||||
|
"tmux": {
|
||||||
|
"colorscheme": "default",
|
||||||
|
"theme": "default"
|
||||||
|
},
|
||||||
|
"vim": {
|
||||||
|
"colorscheme": "default",
|
||||||
|
"theme": "default",
|
||||||
|
"local_themes": {
|
||||||
|
"cmdwin": "cmdwin",
|
||||||
|
"help": "help",
|
||||||
|
"quickfix": "quickfix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wm": {
|
||||||
|
"colorscheme": "default",
|
||||||
|
"theme": "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"default_module": "powerline.segments.common",
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"name": "virtualenv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": "In[",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"highlight_group": ["prompt"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "prompt_count",
|
||||||
|
"module": "powerline.segments.ipython",
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": "]",
|
||||||
|
"highlight_group": ["prompt"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"default_module": "powerline.segments.common",
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": "",
|
||||||
|
"width": "auto",
|
||||||
|
"highlight_group": ["prompt"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"default_module": "powerline.segments.common",
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": "Out[",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"width": "auto",
|
||||||
|
"align": "r",
|
||||||
|
"highlight_group": ["prompt"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "prompt_count",
|
||||||
|
"module": "powerline.segments.ipython",
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": "]",
|
||||||
|
"highlight_group": ["prompt"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": "",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"width": "auto",
|
||||||
|
"highlight_group": ["prompt"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "prompt_count",
|
||||||
|
"module": "powerline.segments.ipython",
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": ">",
|
||||||
|
"highlight_group": ["prompt"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"default_module": "powerline.segments.common",
|
||||||
|
"segment_data": {
|
||||||
|
"hostname": {
|
||||||
|
"before": " ",
|
||||||
|
"args": {
|
||||||
|
"only_if_ssh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"virtualenv": {
|
||||||
|
"before": "ⓔ "
|
||||||
|
},
|
||||||
|
"branch": {
|
||||||
|
"before": " "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"name": "hostname"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtualenv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cwd",
|
||||||
|
"args": {
|
||||||
|
"dir_limit_depth": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"module": "powerline.segments.shell",
|
||||||
|
"name": "last_pipe_status"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "branch"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"default_module": "powerline.segments.common",
|
||||||
|
"segment_data": {
|
||||||
|
"hostname": {
|
||||||
|
"before": " ",
|
||||||
|
"args": {
|
||||||
|
"only_if_ssh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"virtualenv": {
|
||||||
|
"before": "ⓔ "
|
||||||
|
},
|
||||||
|
"branch": {
|
||||||
|
"before": " "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"name": "hostname"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtualenv"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "branch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cwd",
|
||||||
|
"args": {
|
||||||
|
"dir_limit_depth": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_status",
|
||||||
|
"module": "powerline.segments.shell"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"default_module": "powerline.segments.common",
|
||||||
|
"segment_data": {
|
||||||
|
"uptime": {
|
||||||
|
"before": "⇑ "
|
||||||
|
},
|
||||||
|
"external_ip": {
|
||||||
|
"before": "ⓦ "
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"before": "⌚ "
|
||||||
|
},
|
||||||
|
"email_imap_alert": {
|
||||||
|
"before": "✉ ",
|
||||||
|
"args": {
|
||||||
|
"username": "",
|
||||||
|
"password": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"segments": {
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"name": "uptime",
|
||||||
|
"priority": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "external_ip",
|
||||||
|
"priority": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "network_load",
|
||||||
|
"priority": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "system_load",
|
||||||
|
"priority": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "weather",
|
||||||
|
"priority": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "date",
|
||||||
|
"args": {
|
||||||
|
"format": "%H:%M",
|
||||||
|
"istime": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "email_imap_alert",
|
||||||
|
"priority": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hostname"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"contents": "Command Line",
|
||||||
|
"highlight_group": ["file_name"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"highlight_group": ["background"],
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"draw_hard_divider": false,
|
||||||
|
"width": "auto"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
{
|
||||||
|
"segment_data": {
|
||||||
|
"branch": {
|
||||||
|
"before": " "
|
||||||
|
},
|
||||||
|
"modified_indicator": {
|
||||||
|
"args": { "text": "+" }
|
||||||
|
},
|
||||||
|
"line_percent": {
|
||||||
|
"args": { "gradient": true },
|
||||||
|
"after": "%"
|
||||||
|
},
|
||||||
|
"line_current_symbol": {
|
||||||
|
"contents": " "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"name": "mode",
|
||||||
|
"exclude_modes": ["nc"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "paste_indicator",
|
||||||
|
"exclude_modes": ["nc"],
|
||||||
|
"priority": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "branch",
|
||||||
|
"exclude_modes": ["nc"],
|
||||||
|
"priority": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "readonly_indicator",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"after": " "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "file_directory",
|
||||||
|
"priority": 40,
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "file_name",
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "file_vcs_status",
|
||||||
|
"before": " ",
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "modified_indicator",
|
||||||
|
"before": " "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"highlight_group": ["background"],
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"draw_hard_divider": false,
|
||||||
|
"width": "auto"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"name": "file_format",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"exclude_modes": ["nc"],
|
||||||
|
"priority": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "file_encoding",
|
||||||
|
"exclude_modes": ["nc"],
|
||||||
|
"priority": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "file_type",
|
||||||
|
"exclude_modes": ["nc"],
|
||||||
|
"priority": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "line_percent",
|
||||||
|
"priority": 50,
|
||||||
|
"width": 4,
|
||||||
|
"align": "r"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "line_current_symbol",
|
||||||
|
"highlight_group": ["line_current_symbol", "line_current"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "line_current",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"width": 3,
|
||||||
|
"align": "r"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "virtcol_current",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"priority": 20,
|
||||||
|
"before": ":",
|
||||||
|
"width": 3,
|
||||||
|
"align": "l"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"name": "file_name",
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"highlight_group": ["background"],
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"draw_hard_divider": false,
|
||||||
|
"width": "auto"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"name": "line_percent",
|
||||||
|
"priority": 30,
|
||||||
|
"width": 4,
|
||||||
|
"align": "r"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "line_current_symbol",
|
||||||
|
"highlight_group": ["line_current_symbol", "line_current"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "line_current",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"width": 3,
|
||||||
|
"align": "r"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"segment_data": {
|
||||||
|
"buffer_name": {
|
||||||
|
"contents": "Location List"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "buffer_name",
|
||||||
|
"highlight_group": ["file_name"],
|
||||||
|
"draw_soft_divider": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"highlight_group": ["background"],
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"draw_hard_divider": false,
|
||||||
|
"width": "auto"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "line_current_symbol",
|
||||||
|
"highlight_group": ["line_current_symbol", "line_current"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "line_current",
|
||||||
|
"draw_soft_divider": false,
|
||||||
|
"width": 3,
|
||||||
|
"align": "r"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"default_module": "powerline.segments.common",
|
||||||
|
"segments": {
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"name": "weather",
|
||||||
|
"priority": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "date",
|
||||||
|
"args": {
|
||||||
|
"format": "%H:%M",
|
||||||
|
"istime": true
|
||||||
|
},
|
||||||
|
"before": "⌚ "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "email_imap_alert",
|
||||||
|
"before": "✉ ",
|
||||||
|
"priority": 10,
|
||||||
|
"args": {
|
||||||
|
"username": "",
|
||||||
|
"password": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline import Powerline
|
||||||
|
from powerline.lib import mergedicts
|
||||||
|
|
||||||
|
|
||||||
|
class IpythonPowerline(Powerline):
|
||||||
|
def __init__(self):
|
||||||
|
super(IpythonPowerline, self).__init__('ipython', use_daemon_threads=True)
|
||||||
|
|
||||||
|
def get_config_paths(self):
|
||||||
|
if self.path:
|
||||||
|
return [self.path]
|
||||||
|
else:
|
||||||
|
return super(IpythonPowerline, self).get_config_paths()
|
||||||
|
|
||||||
|
def get_local_themes(self, local_themes):
|
||||||
|
return dict(((type, {'config': self.load_theme_config(name)}) for type, name in local_themes.items()))
|
||||||
|
|
||||||
|
def load_main_config(self):
|
||||||
|
r = super(IpythonPowerline, self).load_main_config()
|
||||||
|
if self.config_overrides:
|
||||||
|
mergedicts(r, self.config_overrides)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def load_theme_config(self, name):
|
||||||
|
r = super(IpythonPowerline, self).load_theme_config(name)
|
||||||
|
if name in self.theme_overrides:
|
||||||
|
mergedicts(r, self.theme_overrides[name])
|
||||||
|
return r
|
|
@ -0,0 +1,67 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from functools import wraps
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def wraps_saveargs(wrapped):
|
||||||
|
def dec(wrapper):
|
||||||
|
r = wraps(wrapped)(wrapper)
|
||||||
|
r.powerline_origin = getattr(wrapped, 'powerline_origin', wrapped)
|
||||||
|
return r
|
||||||
|
return dec
|
||||||
|
|
||||||
|
|
||||||
|
def mergedicts(d1, d2):
|
||||||
|
'''Recursively merge two dictionaries. First dictionary is modified in-place.
|
||||||
|
'''
|
||||||
|
for k in d2:
|
||||||
|
if k in d1 and type(d1[k]) is dict and type(d2[k]) is dict:
|
||||||
|
mergedicts(d1[k], d2[k])
|
||||||
|
else:
|
||||||
|
d1[k] = d2[k]
|
||||||
|
|
||||||
|
|
||||||
|
def add_divider_highlight_group(highlight_group):
|
||||||
|
def dec(func):
|
||||||
|
@wraps_saveargs(func)
|
||||||
|
def f(**kwargs):
|
||||||
|
r = func(**kwargs)
|
||||||
|
if r:
|
||||||
|
return [{
|
||||||
|
'contents': r,
|
||||||
|
'divider_highlight_group': highlight_group,
|
||||||
|
}]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
return f
|
||||||
|
return dec
|
||||||
|
|
||||||
|
|
||||||
|
def keyvaluesplit(s):
|
||||||
|
if '=' not in s:
|
||||||
|
raise TypeError('Option must look like option=json_value')
|
||||||
|
if s[0] == '_':
|
||||||
|
raise ValueError('Option names must not start with `_\'')
|
||||||
|
idx = s.index('=')
|
||||||
|
o = s[:idx]
|
||||||
|
val = json.loads(s[idx + 1:])
|
||||||
|
return (o, val)
|
||||||
|
|
||||||
|
|
||||||
|
def parsedotval(s):
|
||||||
|
if type(s) is tuple:
|
||||||
|
o, val = s
|
||||||
|
else:
|
||||||
|
o, val = keyvaluesplit(s)
|
||||||
|
|
||||||
|
keys = o.split('.')
|
||||||
|
if len(keys) > 1:
|
||||||
|
r = (keys[0], {})
|
||||||
|
rcur = r[1]
|
||||||
|
for key in keys[1:-1]:
|
||||||
|
rcur[key] = {}
|
||||||
|
rcur = rcur[key]
|
||||||
|
rcur[keys[-1]] = val
|
||||||
|
return r
|
||||||
|
else:
|
||||||
|
return (o, val)
|
|
@ -0,0 +1,156 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.lib.threaded import MultiRunnedThread
|
||||||
|
from powerline.lib.file_watcher import create_file_watcher
|
||||||
|
|
||||||
|
from threading import Event, Lock
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def open_file(path):
|
||||||
|
return open(path, 'r')
|
||||||
|
|
||||||
|
|
||||||
|
def load_json_config(config_file_path, load=json.load, open_file=open_file):
|
||||||
|
with open_file(config_file_path) as config_file_fp:
|
||||||
|
return load(config_file_fp)
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigLoader(MultiRunnedThread):
|
||||||
|
def __init__(self, shutdown_event=None, watcher=None, load=load_json_config):
|
||||||
|
super(ConfigLoader, self).__init__()
|
||||||
|
self.shutdown_event = shutdown_event or Event()
|
||||||
|
self.watcher = watcher or create_file_watcher()
|
||||||
|
self._load = load
|
||||||
|
|
||||||
|
self.pl = None
|
||||||
|
self.interval = None
|
||||||
|
|
||||||
|
self.lock = Lock()
|
||||||
|
|
||||||
|
self.watched = defaultdict(set)
|
||||||
|
self.missing = defaultdict(set)
|
||||||
|
self.loaded = {}
|
||||||
|
|
||||||
|
def set_pl(self, pl):
|
||||||
|
self.pl = pl
|
||||||
|
|
||||||
|
def set_interval(self, interval):
|
||||||
|
self.interval = interval
|
||||||
|
|
||||||
|
def register(self, function, path):
|
||||||
|
'''Register function that will be run when file changes.
|
||||||
|
|
||||||
|
:param function function:
|
||||||
|
Function that will be called when file at the given path changes.
|
||||||
|
:param str path:
|
||||||
|
Path that will be watched for.
|
||||||
|
'''
|
||||||
|
with self.lock:
|
||||||
|
self.watched[path].add(function)
|
||||||
|
self.watcher.watch(path)
|
||||||
|
|
||||||
|
def register_missing(self, condition_function, function, key):
|
||||||
|
'''Register any function that will be called with given key each
|
||||||
|
interval seconds (interval is defined at __init__). Its result is then
|
||||||
|
passed to ``function``, but only if the result is true.
|
||||||
|
|
||||||
|
:param function condition_function:
|
||||||
|
Function which will be called each ``interval`` seconds. All
|
||||||
|
exceptions from it will be ignored.
|
||||||
|
:param function function:
|
||||||
|
Function which will be called if condition_function returns
|
||||||
|
something that is true. Accepts result of condition_function as an
|
||||||
|
argument.
|
||||||
|
:param str key:
|
||||||
|
Any value, it will be passed to condition_function on each call.
|
||||||
|
|
||||||
|
Note: registered functions will be automatically removed if
|
||||||
|
condition_function results in something true.
|
||||||
|
'''
|
||||||
|
with self.lock:
|
||||||
|
self.missing[key].add((condition_function, function))
|
||||||
|
|
||||||
|
def unregister_functions(self, removed_functions):
|
||||||
|
'''Unregister files handled by these functions.
|
||||||
|
|
||||||
|
:param set removed_functions:
|
||||||
|
Set of functions previously passed to ``.register()`` method.
|
||||||
|
'''
|
||||||
|
with self.lock:
|
||||||
|
for path, functions in list(self.watched.items()):
|
||||||
|
functions -= removed_functions
|
||||||
|
if not functions:
|
||||||
|
self.watched.pop(path)
|
||||||
|
self.loaded.pop(path, None)
|
||||||
|
|
||||||
|
def unregister_missing(self, removed_functions):
|
||||||
|
'''Unregister files handled by these functions.
|
||||||
|
|
||||||
|
:param set removed_functions:
|
||||||
|
Set of pairs (2-tuples) representing ``(condition_function,
|
||||||
|
function)`` function pairs previously passed as an arguments to
|
||||||
|
``.register_missing()`` method.
|
||||||
|
'''
|
||||||
|
with self.lock:
|
||||||
|
for key, functions in list(self.missing.items()):
|
||||||
|
functions -= removed_functions
|
||||||
|
if not functions:
|
||||||
|
self.missing.pop(key)
|
||||||
|
|
||||||
|
def load(self, path):
|
||||||
|
try:
|
||||||
|
# No locks: GIL does what we need
|
||||||
|
return self.loaded[path]
|
||||||
|
except KeyError:
|
||||||
|
r = self._load(path)
|
||||||
|
self.loaded[path] = r
|
||||||
|
return r
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
toload = []
|
||||||
|
with self.lock:
|
||||||
|
for path, functions in self.watched.items():
|
||||||
|
for function in functions:
|
||||||
|
try:
|
||||||
|
modified = self.watcher(path)
|
||||||
|
except OSError as e:
|
||||||
|
modified = True
|
||||||
|
self.exception('Error while running watcher for path {0}: {1}', path, str(e))
|
||||||
|
else:
|
||||||
|
if modified:
|
||||||
|
toload.append(path)
|
||||||
|
if modified:
|
||||||
|
function(path)
|
||||||
|
with self.lock:
|
||||||
|
for key, functions in list(self.missing.items()):
|
||||||
|
for condition_function, function in list(functions):
|
||||||
|
try:
|
||||||
|
path = condition_function(key)
|
||||||
|
except Exception as e:
|
||||||
|
self.exception('Error while running condition function for key {0}: {1}', key, str(e))
|
||||||
|
else:
|
||||||
|
if path:
|
||||||
|
toload.append(path)
|
||||||
|
function(path)
|
||||||
|
functions.remove((condition_function, function))
|
||||||
|
if not functions:
|
||||||
|
self.missing.pop(key)
|
||||||
|
for path in toload:
|
||||||
|
try:
|
||||||
|
self.loaded[path] = self._load(path)
|
||||||
|
except Exception as e:
|
||||||
|
self.exception('Error while loading {0}: {1}', path, str(e))
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.interval is not None and not self.shutdown_event.is_set():
|
||||||
|
self.update()
|
||||||
|
self.shutdown_event.wait(self.interval)
|
||||||
|
|
||||||
|
def exception(self, msg, *args, **kwargs):
|
||||||
|
if self.pl:
|
||||||
|
self.pl.exception(msg, prefix='config_loader', *args, **kwargs)
|
||||||
|
else:
|
||||||
|
raise
|
|
@ -0,0 +1,181 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from time import sleep
|
||||||
|
from threading import RLock
|
||||||
|
|
||||||
|
from powerline.lib.monotonic import monotonic
|
||||||
|
from powerline.lib.inotify import INotify, INotifyError
|
||||||
|
|
||||||
|
|
||||||
|
class INotifyWatch(INotify):
|
||||||
|
is_stat_based = False
|
||||||
|
|
||||||
|
def __init__(self, expire_time=10):
|
||||||
|
super(INotifyWatch, self).__init__()
|
||||||
|
self.watches = {}
|
||||||
|
self.modified = {}
|
||||||
|
self.last_query = {}
|
||||||
|
self.lock = RLock()
|
||||||
|
self.expire_time = expire_time * 60
|
||||||
|
|
||||||
|
def expire_watches(self):
|
||||||
|
now = monotonic()
|
||||||
|
for path, last_query in tuple(self.last_query.items()):
|
||||||
|
if last_query - now > self.expire_time:
|
||||||
|
self.unwatch(path)
|
||||||
|
|
||||||
|
def process_event(self, wd, mask, cookie, name):
|
||||||
|
if wd == -1 and (mask & self.Q_OVERFLOW):
|
||||||
|
# We missed some INOTIFY events, so we dont
|
||||||
|
# know the state of any tracked files.
|
||||||
|
for path in tuple(self.modified):
|
||||||
|
if os.path.exists(path):
|
||||||
|
self.modified[path] = True
|
||||||
|
else:
|
||||||
|
self.watches.pop(path, None)
|
||||||
|
self.modified.pop(path, None)
|
||||||
|
self.last_query.pop(path, None)
|
||||||
|
return
|
||||||
|
|
||||||
|
for path, num in tuple(self.watches.items()):
|
||||||
|
if num == wd:
|
||||||
|
if mask & self.IGNORED:
|
||||||
|
self.watches.pop(path, None)
|
||||||
|
self.modified.pop(path, None)
|
||||||
|
self.last_query.pop(path, None)
|
||||||
|
else:
|
||||||
|
self.modified[path] = True
|
||||||
|
|
||||||
|
def unwatch(self, path):
|
||||||
|
''' Remove the watch for path. Raises an OSError if removing the watch
|
||||||
|
fails for some reason. '''
|
||||||
|
path = self.os.path.abspath(path)
|
||||||
|
with self.lock:
|
||||||
|
self.modified.pop(path, None)
|
||||||
|
self.last_query.pop(path, None)
|
||||||
|
wd = self.watches.pop(path, None)
|
||||||
|
if wd is not None:
|
||||||
|
if self._rm_watch(self._inotify_fd, wd) != 0:
|
||||||
|
self.handle_error()
|
||||||
|
|
||||||
|
def watch(self, path):
|
||||||
|
''' Register a watch for the file named path. Raises an OSError if path
|
||||||
|
does not exist. '''
|
||||||
|
import ctypes
|
||||||
|
path = self.os.path.abspath(path)
|
||||||
|
with self.lock:
|
||||||
|
if path not in self.watches:
|
||||||
|
bpath = path if isinstance(path, bytes) else path.encode(self.fenc)
|
||||||
|
wd = self._add_watch(self._inotify_fd, ctypes.c_char_p(bpath),
|
||||||
|
self.MODIFY | self.ATTRIB | self.MOVE_SELF | self.DELETE_SELF)
|
||||||
|
if wd == -1:
|
||||||
|
self.handle_error()
|
||||||
|
self.watches[path] = wd
|
||||||
|
self.modified[path] = False
|
||||||
|
|
||||||
|
def __call__(self, path):
|
||||||
|
''' Return True if path has been modified since the last call. Can
|
||||||
|
raise OSError if the path does not exist. '''
|
||||||
|
path = self.os.path.abspath(path)
|
||||||
|
with self.lock:
|
||||||
|
self.last_query[path] = monotonic()
|
||||||
|
self.expire_watches()
|
||||||
|
if path not in self.watches:
|
||||||
|
# Try to re-add the watch, it will fail if the file does not
|
||||||
|
# exist/you dont have permission
|
||||||
|
self.watch(path)
|
||||||
|
return True
|
||||||
|
self.read(get_name=False)
|
||||||
|
if path not in self.modified:
|
||||||
|
# An ignored event was received which means the path has been
|
||||||
|
# automatically unwatched
|
||||||
|
return True
|
||||||
|
ans = self.modified[path]
|
||||||
|
if ans:
|
||||||
|
self.modified[path] = False
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
with self.lock:
|
||||||
|
for path in tuple(self.watches):
|
||||||
|
try:
|
||||||
|
self.unwatch(path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
super(INotifyWatch, self).close()
|
||||||
|
|
||||||
|
|
||||||
|
class StatWatch(object):
|
||||||
|
is_stat_based = True
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.watches = {}
|
||||||
|
self.lock = RLock()
|
||||||
|
|
||||||
|
def watch(self, path):
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
with self.lock:
|
||||||
|
self.watches[path] = os.path.getmtime(path)
|
||||||
|
|
||||||
|
def unwatch(self, path):
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
with self.lock:
|
||||||
|
self.watches.pop(path, None)
|
||||||
|
|
||||||
|
def __call__(self, path):
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
with self.lock:
|
||||||
|
if path not in self.watches:
|
||||||
|
self.watches[path] = os.path.getmtime(path)
|
||||||
|
return True
|
||||||
|
mtime = os.path.getmtime(path)
|
||||||
|
if mtime != self.watches[path]:
|
||||||
|
self.watches[path] = mtime
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
with self.lock:
|
||||||
|
self.watches.clear()
|
||||||
|
|
||||||
|
|
||||||
|
def create_file_watcher(use_stat=False, expire_time=10):
|
||||||
|
'''
|
||||||
|
Create an object that can watch for changes to specified files. To use:
|
||||||
|
|
||||||
|
watcher = create_file_watcher()
|
||||||
|
watcher(path1) # Will return True if path1 has changed since the last time this was called. Always returns True the first time.
|
||||||
|
watcher.unwatch(path1)
|
||||||
|
|
||||||
|
Uses inotify if available, otherwise tracks mtimes. expire_time is the
|
||||||
|
number of minutes after the last query for a given path for the inotify
|
||||||
|
watch for that path to be automatically removed. This conserves kernel
|
||||||
|
resources.
|
||||||
|
'''
|
||||||
|
if use_stat:
|
||||||
|
return StatWatch()
|
||||||
|
try:
|
||||||
|
return INotifyWatch(expire_time=expire_time)
|
||||||
|
except INotifyError:
|
||||||
|
pass
|
||||||
|
return StatWatch()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
watcher = create_file_watcher()
|
||||||
|
print ('Using watcher: %s' % watcher.__class__.__name__)
|
||||||
|
print ('Watching %s, press Ctrl-C to quit' % sys.argv[-1])
|
||||||
|
watcher.watch(sys.argv[-1])
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
if watcher(sys.argv[-1]):
|
||||||
|
print ('%s has changed' % sys.argv[-1])
|
||||||
|
sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
watcher.close()
|
|
@ -0,0 +1,22 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from math import log
|
||||||
|
unit_list = tuple(zip(['', 'k', 'M', 'G', 'T', 'P'], [0, 0, 1, 2, 2, 2]))
|
||||||
|
|
||||||
|
|
||||||
|
def humanize_bytes(num, suffix='B', si_prefix=False):
|
||||||
|
'''Return a human friendly byte representation.
|
||||||
|
|
||||||
|
Modified version from http://stackoverflow.com/questions/1094841
|
||||||
|
'''
|
||||||
|
if num == 0:
|
||||||
|
return '0 ' + suffix
|
||||||
|
div = 1000 if si_prefix else 1024
|
||||||
|
exponent = min(int(log(num, div)) if num else 0, len(unit_list) - 1)
|
||||||
|
quotient = float(num) / div ** exponent
|
||||||
|
unit, decimals = unit_list[exponent]
|
||||||
|
if unit and not si_prefix:
|
||||||
|
unit = unit.upper() + 'i'
|
||||||
|
return '{{quotient:.{decimals}f}} {{unit}}{{suffix}}'\
|
||||||
|
.format(decimals=decimals)\
|
||||||
|
.format(quotient=quotient, unit=unit, suffix=suffix)
|
|
@ -0,0 +1,178 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
|
||||||
|
|
||||||
|
class INotifyError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
_inotify = None
|
||||||
|
|
||||||
|
|
||||||
|
def load_inotify():
|
||||||
|
''' Initialize the inotify library '''
|
||||||
|
global _inotify
|
||||||
|
if _inotify is None:
|
||||||
|
if hasattr(sys, 'getwindowsversion'):
|
||||||
|
# On windows abort before loading the C library. Windows has
|
||||||
|
# multiple, incompatible C runtimes, and we have no way of knowing
|
||||||
|
# if the one chosen by ctypes is compatible with the currently
|
||||||
|
# loaded one.
|
||||||
|
raise INotifyError('INotify not available on windows')
|
||||||
|
import ctypes
|
||||||
|
if not hasattr(ctypes, 'c_ssize_t'):
|
||||||
|
raise INotifyError('You need python >= 2.7 to use inotify')
|
||||||
|
from ctypes.util import find_library
|
||||||
|
name = find_library('c')
|
||||||
|
if not name:
|
||||||
|
raise INotifyError('Cannot find C library')
|
||||||
|
libc = ctypes.CDLL(name, use_errno=True)
|
||||||
|
for function in ("inotify_add_watch", "inotify_init1", "inotify_rm_watch"):
|
||||||
|
if not hasattr(libc, function):
|
||||||
|
raise INotifyError('libc is too old')
|
||||||
|
# inotify_init1()
|
||||||
|
prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, use_errno=True)
|
||||||
|
init1 = prototype(('inotify_init1', libc), ((1, "flags", 0),))
|
||||||
|
|
||||||
|
# inotify_add_watch()
|
||||||
|
prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint32, use_errno=True)
|
||||||
|
add_watch = prototype(('inotify_add_watch', libc), (
|
||||||
|
(1, "fd"), (1, "pathname"), (1, "mask")), use_errno=True)
|
||||||
|
|
||||||
|
# inotify_rm_watch()
|
||||||
|
prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int, use_errno=True)
|
||||||
|
rm_watch = prototype(('inotify_rm_watch', libc), (
|
||||||
|
(1, "fd"), (1, "wd")), use_errno=True)
|
||||||
|
|
||||||
|
# read()
|
||||||
|
prototype = ctypes.CFUNCTYPE(ctypes.c_ssize_t, ctypes.c_int, ctypes.c_void_p, ctypes.c_size_t, use_errno=True)
|
||||||
|
read = prototype(('read', libc), (
|
||||||
|
(1, "fd"), (1, "buf"), (1, "count")), use_errno=True)
|
||||||
|
_inotify = (init1, add_watch, rm_watch, read)
|
||||||
|
return _inotify
|
||||||
|
|
||||||
|
|
||||||
|
class INotify(object):
|
||||||
|
# See <sys/inotify.h> for the flags defined below
|
||||||
|
|
||||||
|
# Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.
|
||||||
|
ACCESS = 0x00000001 # File was accessed.
|
||||||
|
MODIFY = 0x00000002 # File was modified.
|
||||||
|
ATTRIB = 0x00000004 # Metadata changed.
|
||||||
|
CLOSE_WRITE = 0x00000008 # Writtable file was closed.
|
||||||
|
CLOSE_NOWRITE = 0x00000010 # Unwrittable file closed.
|
||||||
|
OPEN = 0x00000020 # File was opened.
|
||||||
|
MOVED_FROM = 0x00000040 # File was moved from X.
|
||||||
|
MOVED_TO = 0x00000080 # File was moved to Y.
|
||||||
|
CREATE = 0x00000100 # Subfile was created.
|
||||||
|
DELETE = 0x00000200 # Subfile was deleted.
|
||||||
|
DELETE_SELF = 0x00000400 # Self was deleted.
|
||||||
|
MOVE_SELF = 0x00000800 # Self was moved.
|
||||||
|
|
||||||
|
# Events sent by the kernel.
|
||||||
|
UNMOUNT = 0x00002000 # Backing fs was unmounted.
|
||||||
|
Q_OVERFLOW = 0x00004000 # Event queued overflowed.
|
||||||
|
IGNORED = 0x00008000 # File was ignored.
|
||||||
|
|
||||||
|
# Helper events.
|
||||||
|
CLOSE = (CLOSE_WRITE | CLOSE_NOWRITE) # Close.
|
||||||
|
MOVE = (MOVED_FROM | MOVED_TO) # Moves.
|
||||||
|
|
||||||
|
# Special flags.
|
||||||
|
ONLYDIR = 0x01000000 # Only watch the path if it is a directory.
|
||||||
|
DONT_FOLLOW = 0x02000000 # Do not follow a sym link.
|
||||||
|
EXCL_UNLINK = 0x04000000 # Exclude events on unlinked objects.
|
||||||
|
MASK_ADD = 0x20000000 # Add to the mask of an already existing watch.
|
||||||
|
ISDIR = 0x40000000 # Event occurred against dir.
|
||||||
|
ONESHOT = 0x80000000 # Only send event once.
|
||||||
|
|
||||||
|
# All events which a program can wait on.
|
||||||
|
ALL_EVENTS = (ACCESS | MODIFY | ATTRIB | CLOSE_WRITE | CLOSE_NOWRITE |
|
||||||
|
OPEN | MOVED_FROM | MOVED_TO | CREATE | DELETE |
|
||||||
|
DELETE_SELF | MOVE_SELF)
|
||||||
|
|
||||||
|
# See <bits/inotify.h>
|
||||||
|
CLOEXEC = 0x80000
|
||||||
|
NONBLOCK = 0x800
|
||||||
|
|
||||||
|
def __init__(self, cloexec=True, nonblock=True):
|
||||||
|
import ctypes
|
||||||
|
import struct
|
||||||
|
self._init1, self._add_watch, self._rm_watch, self._read = load_inotify()
|
||||||
|
flags = 0
|
||||||
|
if cloexec:
|
||||||
|
flags |= self.CLOEXEC
|
||||||
|
if nonblock:
|
||||||
|
flags |= self.NONBLOCK
|
||||||
|
self._inotify_fd = self._init1(flags)
|
||||||
|
if self._inotify_fd == -1:
|
||||||
|
raise INotifyError(os.strerror(ctypes.get_errno()))
|
||||||
|
|
||||||
|
self._buf = ctypes.create_string_buffer(5000)
|
||||||
|
self.fenc = sys.getfilesystemencoding() or 'utf-8'
|
||||||
|
self.hdr = struct.Struct(b'iIII')
|
||||||
|
if self.fenc == 'ascii':
|
||||||
|
self.fenc = 'utf-8'
|
||||||
|
# We keep a reference to os to prevent it from being deleted
|
||||||
|
# during interpreter shutdown, which would lead to errors in the
|
||||||
|
# __del__ method
|
||||||
|
self.os = os
|
||||||
|
|
||||||
|
def handle_error(self):
|
||||||
|
import ctypes
|
||||||
|
eno = ctypes.get_errno()
|
||||||
|
raise OSError(eno, self.os.strerror(eno))
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
# This method can be called during interpreter shutdown, which means we
|
||||||
|
# must do the absolute minimum here. Note that there could be running
|
||||||
|
# daemon threads that are trying to call other methods on this object.
|
||||||
|
try:
|
||||||
|
self.os.close(self._inotify_fd)
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if hasattr(self, '_inotify_fd'):
|
||||||
|
self.os.close(self._inotify_fd)
|
||||||
|
del self.os
|
||||||
|
del self._add_watch
|
||||||
|
del self._rm_watch
|
||||||
|
del self._inotify_fd
|
||||||
|
|
||||||
|
def read(self, get_name=True):
|
||||||
|
import ctypes
|
||||||
|
buf = []
|
||||||
|
while True:
|
||||||
|
num = self._read(self._inotify_fd, self._buf, len(self._buf))
|
||||||
|
if num == 0:
|
||||||
|
break
|
||||||
|
if num < 0:
|
||||||
|
en = ctypes.get_errno()
|
||||||
|
if en == errno.EAGAIN:
|
||||||
|
break # No more data
|
||||||
|
if en == errno.EINTR:
|
||||||
|
continue # Interrupted, try again
|
||||||
|
raise OSError(en, self.os.strerror(en))
|
||||||
|
buf.append(self._buf.raw[:num])
|
||||||
|
raw = b''.join(buf)
|
||||||
|
pos = 0
|
||||||
|
lraw = len(raw)
|
||||||
|
while lraw - pos >= self.hdr.size:
|
||||||
|
wd, mask, cookie, name_len = self.hdr.unpack_from(raw, pos)
|
||||||
|
pos += self.hdr.size
|
||||||
|
name = None
|
||||||
|
if get_name:
|
||||||
|
name = raw[pos:pos + name_len].rstrip(b'\0').decode(self.fenc)
|
||||||
|
pos += name_len
|
||||||
|
self.process_event(wd, mask, cookie, name)
|
||||||
|
|
||||||
|
def process_event(self, *args):
|
||||||
|
raise NotImplementedError()
|
|
@ -0,0 +1,40 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
from powerline.lib.monotonic import monotonic
|
||||||
|
|
||||||
|
|
||||||
|
def default_cache_key(**kwargs):
|
||||||
|
return frozenset(kwargs.items())
|
||||||
|
|
||||||
|
|
||||||
|
class memoize(object):
|
||||||
|
'''Memoization decorator with timeout.'''
|
||||||
|
def __init__(self, timeout, cache_key=default_cache_key, cache_reg_func=None):
|
||||||
|
self.timeout = timeout
|
||||||
|
self.cache_key = cache_key
|
||||||
|
self.cache = {}
|
||||||
|
self.cache_reg_func = cache_reg_func
|
||||||
|
|
||||||
|
def __call__(self, func):
|
||||||
|
@wraps(func)
|
||||||
|
def decorated_function(**kwargs):
|
||||||
|
if self.cache_reg_func:
|
||||||
|
self.cache_reg_func(self.cache)
|
||||||
|
self.cache_reg_func = None
|
||||||
|
|
||||||
|
key = self.cache_key(**kwargs)
|
||||||
|
try:
|
||||||
|
cached = self.cache.get(key, None)
|
||||||
|
except TypeError:
|
||||||
|
return func(**kwargs)
|
||||||
|
# Handle case when time() appears to be less then cached['time'] due
|
||||||
|
# to clock updates. Not applicable for monotonic clock, but this
|
||||||
|
# case is currently rare.
|
||||||
|
if cached is None or not (cached['time'] < monotonic() < cached['time'] + self.timeout):
|
||||||
|
cached = self.cache[key] = {
|
||||||
|
'result': func(**kwargs),
|
||||||
|
'time': monotonic(),
|
||||||
|
}
|
||||||
|
return cached['result']
|
||||||
|
return decorated_function
|
|
@ -0,0 +1,103 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import division, absolute_import
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# >=python-3.3, Unix
|
||||||
|
from time import clock_gettime
|
||||||
|
try:
|
||||||
|
# >={kernel}-sources-2.6.28
|
||||||
|
from time import CLOCK_MONOTONIC_RAW as CLOCK_ID
|
||||||
|
except ImportError:
|
||||||
|
from time import CLOCK_MONOTONIC as CLOCK_ID # NOQA
|
||||||
|
|
||||||
|
monotonic = lambda: clock_gettime(CLOCK_ID)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
# >=python-3.3
|
||||||
|
from time import monotonic # NOQA
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
import ctypes
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
# Windows only
|
||||||
|
GetTickCount64 = ctypes.windll.kernel32.GetTickCount64
|
||||||
|
GetTickCount64.restype = ctypes.c_ulonglong
|
||||||
|
|
||||||
|
def monotonic(): # NOQA
|
||||||
|
return GetTickCount64() / 1000
|
||||||
|
|
||||||
|
elif sys.platform == 'darwin':
|
||||||
|
# Mac OS X
|
||||||
|
from ctypes.util import find_library
|
||||||
|
|
||||||
|
libc_name = find_library('c')
|
||||||
|
if not libc_name:
|
||||||
|
raise OSError
|
||||||
|
|
||||||
|
libc = ctypes.CDLL(libc_name, use_errno=True)
|
||||||
|
|
||||||
|
mach_absolute_time = libc.mach_absolute_time
|
||||||
|
mach_absolute_time.argtypes = ()
|
||||||
|
mach_absolute_time.restype = ctypes.c_uint64
|
||||||
|
|
||||||
|
class mach_timebase_info_data_t(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('numer', ctypes.c_uint32),
|
||||||
|
('denom', ctypes.c_uint32),
|
||||||
|
)
|
||||||
|
mach_timebase_info_data_p = ctypes.POINTER(mach_timebase_info_data_t)
|
||||||
|
|
||||||
|
_mach_timebase_info = libc.mach_timebase_info
|
||||||
|
_mach_timebase_info.argtypes = (mach_timebase_info_data_p,)
|
||||||
|
_mach_timebase_info.restype = ctypes.c_int
|
||||||
|
|
||||||
|
def mach_timebase_info():
|
||||||
|
timebase = mach_timebase_info_data_t()
|
||||||
|
_mach_timebase_info(ctypes.byref(timebase))
|
||||||
|
return (timebase.numer, timebase.denom)
|
||||||
|
|
||||||
|
timebase = mach_timebase_info()
|
||||||
|
factor = timebase[0] / timebase[1] * 1e-9
|
||||||
|
|
||||||
|
def monotonic(): # NOQA
|
||||||
|
return mach_absolute_time() * factor
|
||||||
|
else:
|
||||||
|
# linux only (no librt on OS X)
|
||||||
|
import os
|
||||||
|
|
||||||
|
# See <bits/time.h>
|
||||||
|
CLOCK_MONOTONIC = 1
|
||||||
|
CLOCK_MONOTONIC_RAW = 4
|
||||||
|
|
||||||
|
class timespec(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('tv_sec', ctypes.c_long),
|
||||||
|
('tv_nsec', ctypes.c_long)
|
||||||
|
)
|
||||||
|
tspec = timespec()
|
||||||
|
|
||||||
|
librt = ctypes.CDLL('librt.so.1', use_errno=True)
|
||||||
|
clock_gettime = librt.clock_gettime
|
||||||
|
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
|
||||||
|
|
||||||
|
if clock_gettime(CLOCK_MONOTONIC_RAW, ctypes.pointer(tspec)) == 0:
|
||||||
|
# >={kernel}-sources-2.6.28
|
||||||
|
clock_id = CLOCK_MONOTONIC_RAW
|
||||||
|
elif clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(tspec)) == 0:
|
||||||
|
clock_id = CLOCK_MONOTONIC
|
||||||
|
else:
|
||||||
|
raise OSError
|
||||||
|
|
||||||
|
def monotonic(): # NOQA
|
||||||
|
if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(tspec)) != 0:
|
||||||
|
errno_ = ctypes.get_errno()
|
||||||
|
raise OSError(errno_, os.strerror(errno_))
|
||||||
|
return tspec.tv_sec + tspec.tv_nsec / 1e9
|
||||||
|
|
||||||
|
except:
|
||||||
|
from time import time as monotonic # NOQA
|
|
@ -0,0 +1,204 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from powerline.lib.monotonic import monotonic
|
||||||
|
|
||||||
|
from threading import Thread, Lock, Event
|
||||||
|
|
||||||
|
|
||||||
|
class MultiRunnedThread(object):
|
||||||
|
daemon = True
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.thread = None
|
||||||
|
|
||||||
|
def is_alive(self):
|
||||||
|
return self.thread and self.thread.is_alive()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.shutdown_event.clear()
|
||||||
|
self.thread = Thread(target=self.run)
|
||||||
|
self.thread.daemon = self.daemon
|
||||||
|
self.thread.start()
|
||||||
|
|
||||||
|
def join(self, *args, **kwargs):
|
||||||
|
if self.thread:
|
||||||
|
return self.thread.join(*args, **kwargs)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadedSegment(MultiRunnedThread):
|
||||||
|
min_sleep_time = 0.1
|
||||||
|
update_first = True
|
||||||
|
interval = 1
|
||||||
|
daemon = False
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(ThreadedSegment, self).__init__()
|
||||||
|
self.run_once = True
|
||||||
|
self.skip = False
|
||||||
|
self.crashed_value = None
|
||||||
|
self.update_value = None
|
||||||
|
self.updated = False
|
||||||
|
|
||||||
|
def __call__(self, pl, update_first=True, **kwargs):
|
||||||
|
if self.run_once:
|
||||||
|
self.pl = pl
|
||||||
|
self.set_state(**kwargs)
|
||||||
|
update_value = self.get_update_value(True)
|
||||||
|
elif not self.is_alive():
|
||||||
|
# Without this we will not have to wait long until receiving bug “I
|
||||||
|
# opened vim, but branch information is only shown after I move
|
||||||
|
# cursor”.
|
||||||
|
#
|
||||||
|
# If running once .update() is called in __call__.
|
||||||
|
update_value = self.get_update_value(update_first and self.update_first)
|
||||||
|
self.start()
|
||||||
|
elif not self.updated:
|
||||||
|
update_value = self.get_update_value(True)
|
||||||
|
self.updated = True
|
||||||
|
else:
|
||||||
|
update_value = self.update_value
|
||||||
|
|
||||||
|
if self.skip:
|
||||||
|
return self.crashed_value
|
||||||
|
|
||||||
|
return self.render(update_value, update_first=update_first, pl=pl, **kwargs)
|
||||||
|
|
||||||
|
def get_update_value(self, update=False):
|
||||||
|
if update:
|
||||||
|
self.update_value = self.update(self.update_value)
|
||||||
|
return self.update_value
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while not self.shutdown_event.is_set():
|
||||||
|
start_time = monotonic()
|
||||||
|
try:
|
||||||
|
self.update_value = self.update(self.update_value)
|
||||||
|
except Exception as e:
|
||||||
|
self.exception('Exception while updating: {0}', str(e))
|
||||||
|
self.skip = True
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.warn('Caught keyboard interrupt while updating')
|
||||||
|
self.skip = True
|
||||||
|
else:
|
||||||
|
self.skip = False
|
||||||
|
self.shutdown_event.wait(max(self.interval - (monotonic() - start_time), self.min_sleep_time))
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.shutdown_event.set()
|
||||||
|
if self.daemon and self.is_alive():
|
||||||
|
# Give the worker thread a chance to shutdown, but don't block for
|
||||||
|
# too long
|
||||||
|
self.join(0.01)
|
||||||
|
|
||||||
|
def set_interval(self, interval=None):
|
||||||
|
# Allowing “interval” keyword in configuration.
|
||||||
|
# Note: Here **kwargs is needed to support foreign data, in subclasses
|
||||||
|
# it can be seen in a number of places in order to support
|
||||||
|
# .set_interval().
|
||||||
|
interval = interval or getattr(self, 'interval')
|
||||||
|
self.interval = interval
|
||||||
|
|
||||||
|
def set_state(self, interval=None, update_first=True, shutdown_event=None, **kwargs):
|
||||||
|
self.set_interval(interval)
|
||||||
|
self.shutdown_event = shutdown_event or Event()
|
||||||
|
self.updated = self.updated or (not (update_first and self.update_first))
|
||||||
|
|
||||||
|
def startup(self, pl, **kwargs):
|
||||||
|
self.run_once = False
|
||||||
|
self.pl = pl
|
||||||
|
self.daemon = pl.use_daemon_threads
|
||||||
|
|
||||||
|
self.set_state(**kwargs)
|
||||||
|
|
||||||
|
if not self.is_alive():
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def critical(self, *args, **kwargs):
|
||||||
|
self.pl.critical(prefix=self.__class__.__name__, *args, **kwargs)
|
||||||
|
|
||||||
|
def exception(self, *args, **kwargs):
|
||||||
|
self.pl.exception(prefix=self.__class__.__name__, *args, **kwargs)
|
||||||
|
|
||||||
|
def info(self, *args, **kwargs):
|
||||||
|
self.pl.info(prefix=self.__class__.__name__, *args, **kwargs)
|
||||||
|
|
||||||
|
def error(self, *args, **kwargs):
|
||||||
|
self.pl.error(prefix=self.__class__.__name__, *args, **kwargs)
|
||||||
|
|
||||||
|
def warn(self, *args, **kwargs):
|
||||||
|
self.pl.warn(prefix=self.__class__.__name__, *args, **kwargs)
|
||||||
|
|
||||||
|
def debug(self, *args, **kwargs):
|
||||||
|
self.pl.debug(prefix=self.__class__.__name__, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class KwThreadedSegment(ThreadedSegment):
|
||||||
|
drop_interval = 10 * 60
|
||||||
|
update_first = True
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(KwThreadedSegment, self).__init__()
|
||||||
|
self.updated = True
|
||||||
|
self.update_value = ({}, set())
|
||||||
|
self.write_lock = Lock()
|
||||||
|
self.new_queries = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def key(**kwargs):
|
||||||
|
return frozenset(kwargs.items())
|
||||||
|
|
||||||
|
def render(self, update_value, update_first, **kwargs):
|
||||||
|
queries, crashed = update_value
|
||||||
|
key = self.key(**kwargs)
|
||||||
|
if key in crashed:
|
||||||
|
return self.crashed_value
|
||||||
|
|
||||||
|
try:
|
||||||
|
update_state = queries[key][1]
|
||||||
|
except KeyError:
|
||||||
|
# Allow only to forbid to compute missing values: in either user
|
||||||
|
# configuration or in subclasses.
|
||||||
|
update_state = self.compute_state(key) if ((update_first and self.update_first) or self.run_once) else None
|
||||||
|
|
||||||
|
with self.write_lock:
|
||||||
|
self.new_queries[key] = (monotonic(), update_state)
|
||||||
|
return self.render_one(update_state, **kwargs)
|
||||||
|
|
||||||
|
def update(self, old_update_value):
|
||||||
|
updates = {}
|
||||||
|
crashed = set()
|
||||||
|
update_value = (updates, crashed)
|
||||||
|
queries = old_update_value[0]
|
||||||
|
with self.write_lock:
|
||||||
|
if self.new_queries:
|
||||||
|
queries.update(self.new_queries)
|
||||||
|
self.new_queries.clear()
|
||||||
|
|
||||||
|
for key, (last_query_time, state) in queries.items():
|
||||||
|
if last_query_time < monotonic() < last_query_time + self.drop_interval:
|
||||||
|
try:
|
||||||
|
updates[key] = (last_query_time, self.compute_state(key))
|
||||||
|
except Exception as e:
|
||||||
|
self.exception('Exception while computing state for {0!r}: {1}', key, str(e))
|
||||||
|
crashed.add(key)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.warn('Interrupt while computing state for {0!r}', key)
|
||||||
|
crashed.add(key)
|
||||||
|
|
||||||
|
return update_value
|
||||||
|
|
||||||
|
def set_state(self, interval=None, shutdown_event=None, **kwargs):
|
||||||
|
self.set_interval(interval)
|
||||||
|
self.shutdown_event = shutdown_event or Event()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def render_one(update_state, **kwargs):
|
||||||
|
return update_state
|
||||||
|
|
||||||
|
|
||||||
|
def with_docstring(instance, doc):
|
||||||
|
instance.__doc__ = doc
|
||||||
|
return instance
|
|
@ -0,0 +1,199 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import (unicode_literals, absolute_import, print_function)
|
||||||
|
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
from time import sleep
|
||||||
|
from powerline.lib.monotonic import monotonic
|
||||||
|
|
||||||
|
from powerline.lib.inotify import INotify, INotifyError
|
||||||
|
|
||||||
|
|
||||||
|
class NoSuchDir(ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DirTooLarge(ValueError):
|
||||||
|
def __init__(self, bdir):
|
||||||
|
ValueError.__init__(self, 'The directory {0} is too large to monitor. Try increasing the value in /proc/sys/fs/inotify/max_user_watches'.format(bdir))
|
||||||
|
|
||||||
|
|
||||||
|
class INotifyTreeWatcher(INotify):
|
||||||
|
is_dummy = False
|
||||||
|
|
||||||
|
def __init__(self, basedir):
|
||||||
|
super(INotifyTreeWatcher, self).__init__()
|
||||||
|
self.basedir = os.path.abspath(basedir)
|
||||||
|
self.watch_tree()
|
||||||
|
self.modified = True
|
||||||
|
|
||||||
|
def watch_tree(self):
|
||||||
|
self.watched_dirs = {}
|
||||||
|
self.watched_rmap = {}
|
||||||
|
try:
|
||||||
|
self.add_watches(self.basedir)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.ENOSPC:
|
||||||
|
raise DirTooLarge(self.basedir)
|
||||||
|
|
||||||
|
def add_watches(self, base, top_level=True):
|
||||||
|
''' Add watches for this directory and all its descendant directories,
|
||||||
|
recursively. '''
|
||||||
|
base = os.path.abspath(base)
|
||||||
|
try:
|
||||||
|
is_dir = self.add_watch(base)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.ENOENT:
|
||||||
|
# The entry could have been deleted between listdir() and
|
||||||
|
# add_watch().
|
||||||
|
if top_level:
|
||||||
|
raise NoSuchDir('The dir {0} does not exist'.format(base))
|
||||||
|
return
|
||||||
|
if e.errno == errno.EACCES:
|
||||||
|
# We silently ignore entries for which we dont have permission,
|
||||||
|
# unless they are the top level dir
|
||||||
|
if top_level:
|
||||||
|
raise NoSuchDir('You do not have permission to monitor {0}'.format(base))
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
if is_dir:
|
||||||
|
try:
|
||||||
|
files = os.listdir(base)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno in (errno.ENOTDIR, errno.ENOENT):
|
||||||
|
# The dir was deleted/replaced between the add_watch()
|
||||||
|
# and listdir()
|
||||||
|
if top_level:
|
||||||
|
raise NoSuchDir('The dir {0} does not exist'.format(base))
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
for x in files:
|
||||||
|
self.add_watches(os.path.join(base, x), top_level=False)
|
||||||
|
elif top_level:
|
||||||
|
# The top level dir is a file, not good.
|
||||||
|
raise NoSuchDir('The dir {0} does not exist'.format(base))
|
||||||
|
|
||||||
|
def add_watch(self, path):
|
||||||
|
import ctypes
|
||||||
|
bpath = path if isinstance(path, bytes) else path.encode(self.fenc)
|
||||||
|
wd = self._add_watch(self._inotify_fd, ctypes.c_char_p(bpath),
|
||||||
|
# Ignore symlinks and watch only directories
|
||||||
|
self.DONT_FOLLOW | self.ONLYDIR |
|
||||||
|
|
||||||
|
self.MODIFY | self.CREATE | self.DELETE |
|
||||||
|
self.MOVE_SELF | self.MOVED_FROM | self.MOVED_TO |
|
||||||
|
self.ATTRIB | self.MOVE_SELF | self.DELETE_SELF)
|
||||||
|
if wd == -1:
|
||||||
|
eno = ctypes.get_errno()
|
||||||
|
if eno == errno.ENOTDIR:
|
||||||
|
return False
|
||||||
|
raise OSError(eno, 'Failed to add watch for: {0}: {1}'.format(path, self.os.strerror(eno)))
|
||||||
|
self.watched_dirs[path] = wd
|
||||||
|
self.watched_rmap[wd] = path
|
||||||
|
return True
|
||||||
|
|
||||||
|
def process_event(self, wd, mask, cookie, name):
|
||||||
|
if wd == -1 and (mask & self.Q_OVERFLOW):
|
||||||
|
# We missed some INOTIFY events, so we dont
|
||||||
|
# know the state of any tracked dirs.
|
||||||
|
self.watch_tree()
|
||||||
|
self.modified = True
|
||||||
|
return
|
||||||
|
path = self.watched_rmap.get(wd, None)
|
||||||
|
if path is not None:
|
||||||
|
self.modified = True
|
||||||
|
if mask & self.CREATE:
|
||||||
|
# A new sub-directory might have been created, monitor it.
|
||||||
|
try:
|
||||||
|
self.add_watch(os.path.join(path, name))
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.ENOENT:
|
||||||
|
# Deleted before add_watch()
|
||||||
|
pass
|
||||||
|
elif e.errno == errno.ENOSPC:
|
||||||
|
raise DirTooLarge(self.basedir)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
self.read()
|
||||||
|
ret = self.modified
|
||||||
|
self.modified = False
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class DummyTreeWatcher(object):
|
||||||
|
is_dummy = True
|
||||||
|
|
||||||
|
def __init__(self, basedir):
|
||||||
|
self.basedir = os.path.abspath(basedir)
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class TreeWatcher(object):
|
||||||
|
def __init__(self, expire_time=10):
|
||||||
|
self.watches = {}
|
||||||
|
self.last_query_times = {}
|
||||||
|
self.expire_time = expire_time * 60
|
||||||
|
|
||||||
|
def watch(self, path, logger=None):
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
try:
|
||||||
|
w = INotifyTreeWatcher(path)
|
||||||
|
except (INotifyError, DirTooLarge) as e:
|
||||||
|
if logger is not None:
|
||||||
|
logger.warn('Failed to watch path: {0} with error: {1}'.format(path, e))
|
||||||
|
w = DummyTreeWatcher(path)
|
||||||
|
self.watches[path] = w
|
||||||
|
return w
|
||||||
|
|
||||||
|
def is_actually_watched(self, path):
|
||||||
|
w = self.watches.get(path, None)
|
||||||
|
return not getattr(w, 'is_dummy', True)
|
||||||
|
|
||||||
|
def expire_old_queries(self):
|
||||||
|
pop = []
|
||||||
|
now = monotonic()
|
||||||
|
for path, lt in self.last_query_times.items():
|
||||||
|
if now - lt > self.expire_time:
|
||||||
|
pop.append(path)
|
||||||
|
for path in pop:
|
||||||
|
del self.last_query_times[path]
|
||||||
|
|
||||||
|
def __call__(self, path, logger=None):
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
self.expire_old_queries()
|
||||||
|
self.last_query_times[path] = monotonic()
|
||||||
|
w = self.watches.get(path, None)
|
||||||
|
if w is None:
|
||||||
|
try:
|
||||||
|
self.watch(path)
|
||||||
|
except NoSuchDir:
|
||||||
|
pass
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
return w()
|
||||||
|
except DirTooLarge as e:
|
||||||
|
if logger is not None:
|
||||||
|
logger.warn(str(e))
|
||||||
|
self.watches[path] = DummyTreeWatcher(path)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
w = INotifyTreeWatcher(sys.argv[-1])
|
||||||
|
w()
|
||||||
|
print ('Monitoring', sys.argv[-1], 'press Ctrl-C to stop')
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
if w():
|
||||||
|
print (sys.argv[-1], 'changed')
|
||||||
|
sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
raise SystemExit(0)
|
|
@ -0,0 +1,16 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urllib.error import HTTPError
|
||||||
|
from urllib.request import urlopen
|
||||||
|
from urllib.parse import urlencode as urllib_urlencode # NOQA
|
||||||
|
except ImportError:
|
||||||
|
from urllib2 import urlopen, HTTPError # NOQA
|
||||||
|
from urllib import urlencode as urllib_urlencode # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
def urllib_read(url):
|
||||||
|
try:
|
||||||
|
return urlopen(url, timeout=10).read().decode('utf-8')
|
||||||
|
except HTTPError:
|
||||||
|
return
|
|
@ -0,0 +1,33 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
vcs_props = (
|
||||||
|
('git', '.git', os.path.exists),
|
||||||
|
('mercurial', '.hg', os.path.isdir),
|
||||||
|
('bzr', '.bzr', os.path.isdir),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_directories(path):
|
||||||
|
yield path
|
||||||
|
while True:
|
||||||
|
old_path = path
|
||||||
|
path = os.path.dirname(path)
|
||||||
|
if path == old_path or not path:
|
||||||
|
break
|
||||||
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
def guess(path):
|
||||||
|
for directory in generate_directories(path):
|
||||||
|
for vcs, vcs_dir, check in vcs_props:
|
||||||
|
if check(os.path.join(directory, vcs_dir)):
|
||||||
|
try:
|
||||||
|
if vcs not in globals():
|
||||||
|
globals()[vcs] = getattr(__import__('powerline.lib.vcs', fromlist=[vcs]), vcs)
|
||||||
|
return globals()[vcs].Repository(directory)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return None
|
|
@ -0,0 +1,64 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import absolute_import, unicode_literals, division, print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
from bzrlib import (branch, workingtree, status, library_state, trace, ui)
|
||||||
|
|
||||||
|
|
||||||
|
class CoerceIO(StringIO):
|
||||||
|
def write(self, arg):
|
||||||
|
if isinstance(arg, bytes):
|
||||||
|
arg = arg.decode('utf-8', 'replace')
|
||||||
|
return super(CoerceIO, self).write(arg)
|
||||||
|
|
||||||
|
|
||||||
|
class Repository(object):
|
||||||
|
def __init__(self, directory):
|
||||||
|
if isinstance(directory, bytes):
|
||||||
|
directory = directory.decode(sys.getfilesystemencoding() or sys.getdefaultencoding() or 'utf-8')
|
||||||
|
self.directory = directory
|
||||||
|
self.state = library_state.BzrLibraryState(ui=ui.SilentUIFactory, trace=trace.DefaultConfig())
|
||||||
|
|
||||||
|
def status(self, path=None):
|
||||||
|
'''Return status of repository or file.
|
||||||
|
|
||||||
|
Without file argument: returns status of the repository:
|
||||||
|
|
||||||
|
:"D?": dirty (tracked modified files: added, removed, deleted, modified),
|
||||||
|
:"?U": untracked-dirty (added, but not tracked files)
|
||||||
|
:None: clean (status is empty)
|
||||||
|
|
||||||
|
With file argument: returns status of this file: The status codes are
|
||||||
|
those returned by bzr status -S
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
return self._status(path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _status(self, path):
|
||||||
|
buf = CoerceIO()
|
||||||
|
w = workingtree.WorkingTree.open(self.directory)
|
||||||
|
status.show_tree_status(w, specific_files=[path] if path else None, to_file=buf, short=True)
|
||||||
|
raw = buf.getvalue()
|
||||||
|
if not raw.strip():
|
||||||
|
return
|
||||||
|
if path:
|
||||||
|
return raw[:2]
|
||||||
|
dirtied = untracked = ' '
|
||||||
|
for line in raw.splitlines():
|
||||||
|
if len(line) > 1 and line[1] in 'ACDMRIN':
|
||||||
|
dirtied = 'D'
|
||||||
|
elif line and line[0] == '?':
|
||||||
|
untracked = 'U'
|
||||||
|
ans = dirtied + untracked
|
||||||
|
return ans if ans.strip() else None
|
||||||
|
|
||||||
|
def branch(self):
|
||||||
|
try:
|
||||||
|
b = branch.Branch.open(self.directory)
|
||||||
|
return b._get_nick(local=True) or None
|
||||||
|
except:
|
||||||
|
pass
|
|
@ -0,0 +1,143 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
try:
|
||||||
|
import pygit2 as git
|
||||||
|
|
||||||
|
class Repository(object):
|
||||||
|
__slots__ = ('directory')
|
||||||
|
|
||||||
|
def __init__(self, directory):
|
||||||
|
self.directory = directory
|
||||||
|
|
||||||
|
def _repo(self):
|
||||||
|
return git.Repository(self.directory)
|
||||||
|
|
||||||
|
def status(self, path=None):
|
||||||
|
'''Return status of repository or file.
|
||||||
|
|
||||||
|
Without file argument: returns status of the repository:
|
||||||
|
|
||||||
|
:First column: working directory status (D: dirty / space)
|
||||||
|
:Second column: index status (I: index dirty / space)
|
||||||
|
:Third column: presense of untracked files (U: untracked files / space)
|
||||||
|
:None: repository clean
|
||||||
|
|
||||||
|
With file argument: returns status of this file. Output is
|
||||||
|
equivalent to the first two columns of "git status --porcelain"
|
||||||
|
(except for merge statuses as they are not supported by libgit2).
|
||||||
|
'''
|
||||||
|
if path:
|
||||||
|
try:
|
||||||
|
status = self._repo().status_file(path)
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
if status == git.GIT_STATUS_CURRENT:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
if status & git.GIT_STATUS_WT_NEW:
|
||||||
|
return '??'
|
||||||
|
if status & git.GIT_STATUS_IGNORED:
|
||||||
|
return '!!'
|
||||||
|
|
||||||
|
if status & git.GIT_STATUS_INDEX_NEW:
|
||||||
|
index_status = 'A'
|
||||||
|
elif status & git.GIT_STATUS_INDEX_DELETED:
|
||||||
|
index_status = 'D'
|
||||||
|
elif status & git.GIT_STATUS_INDEX_MODIFIED:
|
||||||
|
index_status = 'M'
|
||||||
|
else:
|
||||||
|
index_status = ' '
|
||||||
|
|
||||||
|
if status & git.GIT_STATUS_WT_DELETED:
|
||||||
|
wt_status = 'D'
|
||||||
|
elif status & git.GIT_STATUS_WT_MODIFIED:
|
||||||
|
wt_status = 'M'
|
||||||
|
else:
|
||||||
|
wt_status = ' '
|
||||||
|
|
||||||
|
return index_status + wt_status
|
||||||
|
else:
|
||||||
|
wt_column = ' '
|
||||||
|
index_column = ' '
|
||||||
|
untracked_column = ' '
|
||||||
|
for status in self._repo().status().values():
|
||||||
|
if status & git.GIT_STATUS_WT_NEW:
|
||||||
|
untracked_column = 'U'
|
||||||
|
continue
|
||||||
|
|
||||||
|
if status & (git.GIT_STATUS_WT_DELETED
|
||||||
|
| git.GIT_STATUS_WT_MODIFIED):
|
||||||
|
wt_column = 'D'
|
||||||
|
|
||||||
|
if status & (git.GIT_STATUS_INDEX_NEW
|
||||||
|
| git.GIT_STATUS_INDEX_MODIFIED
|
||||||
|
| git.GIT_STATUS_INDEX_DELETED):
|
||||||
|
index_column = 'I'
|
||||||
|
r = wt_column + index_column + untracked_column
|
||||||
|
return r if r != ' ' else None
|
||||||
|
|
||||||
|
def branch(self):
|
||||||
|
try:
|
||||||
|
ref = self._repo().lookup_reference('HEAD')
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
target = ref.target
|
||||||
|
except ValueError:
|
||||||
|
return '[DETACHED HEAD]'
|
||||||
|
|
||||||
|
if target.startswith('refs/heads/'):
|
||||||
|
return target[11:]
|
||||||
|
else:
|
||||||
|
return '[DETACHED HEAD]'
|
||||||
|
except ImportError:
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
def readlines(cmd, cwd):
|
||||||
|
p = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, cwd=cwd)
|
||||||
|
p.stderr.close()
|
||||||
|
with p.stdout:
|
||||||
|
for line in p.stdout:
|
||||||
|
yield line[:-1].decode('utf-8')
|
||||||
|
|
||||||
|
class Repository(object):
|
||||||
|
__slots__ = ('directory',)
|
||||||
|
|
||||||
|
def __init__(self, directory):
|
||||||
|
self.directory = directory
|
||||||
|
|
||||||
|
def _gitcmd(self, *args):
|
||||||
|
return readlines(('git',) + args, self.directory)
|
||||||
|
|
||||||
|
def status(self, path=None):
|
||||||
|
if path:
|
||||||
|
try:
|
||||||
|
return next(self._gitcmd('status', '--porcelain', '--ignored', '--', path))[:2]
|
||||||
|
except StopIteration:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
wt_column = ' '
|
||||||
|
index_column = ' '
|
||||||
|
untracked_column = ' '
|
||||||
|
for line in self._gitcmd('status', '--porcelain'):
|
||||||
|
if line[0] == '?':
|
||||||
|
untracked_column = 'U'
|
||||||
|
continue
|
||||||
|
elif line[0] == '!':
|
||||||
|
continue
|
||||||
|
|
||||||
|
if line[0] != ' ':
|
||||||
|
index_column = 'I'
|
||||||
|
|
||||||
|
if line[1] != ' ':
|
||||||
|
wt_column = 'D'
|
||||||
|
|
||||||
|
r = wt_column + index_column + untracked_column
|
||||||
|
return r if r != ' ' else None
|
||||||
|
|
||||||
|
def branch(self):
|
||||||
|
for line in self._gitcmd('branch', '-l'):
|
||||||
|
if line[0] == '*':
|
||||||
|
return line[2:]
|
||||||
|
return None
|
|
@ -0,0 +1,51 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from mercurial import hg, ui, match
|
||||||
|
|
||||||
|
|
||||||
|
class Repository(object):
|
||||||
|
__slots__ = ('directory', 'ui')
|
||||||
|
|
||||||
|
statuses = 'MARDUI'
|
||||||
|
repo_statuses = (1, 1, 1, 1, 2)
|
||||||
|
repo_statuses_str = (None, 'D ', ' U', 'DU')
|
||||||
|
|
||||||
|
def __init__(self, directory):
|
||||||
|
self.directory = directory
|
||||||
|
self.ui = ui.ui()
|
||||||
|
|
||||||
|
def _repo(self):
|
||||||
|
# Cannot create this object once and use always: when repository updates
|
||||||
|
# functions emit invalid results
|
||||||
|
return hg.repository(self.ui, self.directory)
|
||||||
|
|
||||||
|
def status(self, path=None):
|
||||||
|
'''Return status of repository or file.
|
||||||
|
|
||||||
|
Without file argument: returns status of the repository:
|
||||||
|
|
||||||
|
:"D?": dirty (tracked modified files: added, removed, deleted, modified),
|
||||||
|
:"?U": untracked-dirty (added, but not tracked files)
|
||||||
|
:None: clean (status is empty)
|
||||||
|
|
||||||
|
With file argument: returns status of this file: "M"odified, "A"dded,
|
||||||
|
"R"emoved, "D"eleted (removed from filesystem, but still tracked),
|
||||||
|
"U"nknown, "I"gnored, (None)Clean.
|
||||||
|
'''
|
||||||
|
repo = self._repo()
|
||||||
|
if path:
|
||||||
|
m = match.match(None, None, [path], exact=True)
|
||||||
|
statuses = repo.status(match=m, unknown=True, ignored=True)
|
||||||
|
for status, paths in zip(self.statuses, statuses):
|
||||||
|
if paths:
|
||||||
|
return status
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
resulting_status = 0
|
||||||
|
for status, paths in zip(self.repo_statuses, repo.status(unknown=True)):
|
||||||
|
if paths:
|
||||||
|
resulting_status |= status
|
||||||
|
return self.repo_statuses_str[resulting_status]
|
||||||
|
|
||||||
|
def branch(self):
|
||||||
|
return self._repo().dirstate.branch()
|
1108
common/.local/lib/python2.7/site-packages/powerline/lint/__init__.py
Normal file
1108
common/.local/lib/python2.7/site-packages/powerline/lint/__init__.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,59 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from inspect import ArgSpec, getargspec
|
||||||
|
from powerline.lib.threaded import ThreadedSegment, KwThreadedSegment
|
||||||
|
from itertools import count
|
||||||
|
|
||||||
|
def getconfigargspec(obj):
|
||||||
|
if isinstance(obj, ThreadedSegment):
|
||||||
|
args = ['interval']
|
||||||
|
defaults = [getattr(obj, 'interval', 1)]
|
||||||
|
if obj.update_first:
|
||||||
|
args.append('update_first')
|
||||||
|
defaults.append(True)
|
||||||
|
methods = ['render', 'set_state']
|
||||||
|
if isinstance(obj, KwThreadedSegment):
|
||||||
|
methods += ['key', 'render_one']
|
||||||
|
|
||||||
|
for method in methods:
|
||||||
|
if hasattr(obj, method):
|
||||||
|
# Note: on <python-2.6 it may return simple tuple, not
|
||||||
|
# ArgSpec instance.
|
||||||
|
argspec = getargspec(getattr(obj, method))
|
||||||
|
for i, arg in zip(count(1), reversed(argspec.args)):
|
||||||
|
if (arg == 'self' or
|
||||||
|
(arg == 'segment_info' and
|
||||||
|
getattr(obj, 'powerline_requires_segment_info', None)) or
|
||||||
|
(arg == 'pl') or
|
||||||
|
(method.startswith('render') and (1 if argspec.args[0] == 'self' else 0) + i == len(argspec.args)) or
|
||||||
|
arg in args):
|
||||||
|
continue
|
||||||
|
if argspec.defaults and len(argspec.defaults) >= i:
|
||||||
|
default = argspec.defaults[-i]
|
||||||
|
defaults.append(default)
|
||||||
|
args.append(arg)
|
||||||
|
else:
|
||||||
|
args.insert(0, arg)
|
||||||
|
argspec = ArgSpec(args=args, varargs=None, keywords=None, defaults=tuple(defaults))
|
||||||
|
else:
|
||||||
|
if hasattr(obj, 'powerline_origin'):
|
||||||
|
obj = obj.powerline_origin
|
||||||
|
else:
|
||||||
|
obj = obj
|
||||||
|
|
||||||
|
argspec = getargspec(obj)
|
||||||
|
args = []
|
||||||
|
defaults = []
|
||||||
|
for i, arg in zip(count(1), reversed(argspec.args)):
|
||||||
|
if ((arg == 'segment_info' and getattr(obj, 'powerline_requires_segment_info', None)) or
|
||||||
|
arg == 'pl'):
|
||||||
|
continue
|
||||||
|
if argspec.defaults and len(argspec.defaults) >= i:
|
||||||
|
default = argspec.defaults[-i]
|
||||||
|
defaults.append(default)
|
||||||
|
args.append(arg)
|
||||||
|
else:
|
||||||
|
args.insert(0, arg)
|
||||||
|
argspec = ArgSpec(args=args, varargs=argspec.varargs, keywords=argspec.keywords, defaults=tuple(defaults))
|
||||||
|
|
||||||
|
return argspec
|
|
@ -0,0 +1,17 @@
|
||||||
|
__version__ = '3.10'
|
||||||
|
|
||||||
|
|
||||||
|
from .loader import Loader
|
||||||
|
|
||||||
|
|
||||||
|
def load(stream, Loader=Loader):
|
||||||
|
"""
|
||||||
|
Parse the first YAML document in a stream
|
||||||
|
and produce the corresponding Python object.
|
||||||
|
"""
|
||||||
|
loader = Loader(stream)
|
||||||
|
try:
|
||||||
|
r = loader.get_single_data()
|
||||||
|
return r, loader.haserrors
|
||||||
|
finally:
|
||||||
|
loader.dispose()
|
|
@ -0,0 +1,117 @@
|
||||||
|
__all__ = ['Composer', 'ComposerError']
|
||||||
|
|
||||||
|
from .error import MarkedError
|
||||||
|
from .events import * # NOQA
|
||||||
|
from .nodes import * # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class ComposerError(MarkedError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Composer:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_node(self):
|
||||||
|
# Drop the STREAM-START event.
|
||||||
|
if self.check_event(StreamStartEvent):
|
||||||
|
self.get_event()
|
||||||
|
|
||||||
|
# If there are more documents available?
|
||||||
|
return not self.check_event(StreamEndEvent)
|
||||||
|
|
||||||
|
def get_node(self):
|
||||||
|
# Get the root node of the next document.
|
||||||
|
if not self.check_event(StreamEndEvent):
|
||||||
|
return self.compose_document()
|
||||||
|
|
||||||
|
def get_single_node(self):
|
||||||
|
# Drop the STREAM-START event.
|
||||||
|
self.get_event()
|
||||||
|
|
||||||
|
# Compose a document if the stream is not empty.
|
||||||
|
document = None
|
||||||
|
if not self.check_event(StreamEndEvent):
|
||||||
|
document = self.compose_document()
|
||||||
|
|
||||||
|
# Ensure that the stream contains no more documents.
|
||||||
|
if not self.check_event(StreamEndEvent):
|
||||||
|
event = self.get_event()
|
||||||
|
raise ComposerError("expected a single document in the stream",
|
||||||
|
document.start_mark, "but found another document",
|
||||||
|
event.start_mark)
|
||||||
|
|
||||||
|
# Drop the STREAM-END event.
|
||||||
|
self.get_event()
|
||||||
|
|
||||||
|
return document
|
||||||
|
|
||||||
|
def compose_document(self):
|
||||||
|
# Drop the DOCUMENT-START event.
|
||||||
|
self.get_event()
|
||||||
|
|
||||||
|
# Compose the root node.
|
||||||
|
node = self.compose_node(None, None)
|
||||||
|
|
||||||
|
# Drop the DOCUMENT-END event.
|
||||||
|
self.get_event()
|
||||||
|
|
||||||
|
return node
|
||||||
|
|
||||||
|
def compose_node(self, parent, index):
|
||||||
|
self.descend_resolver(parent, index)
|
||||||
|
if self.check_event(ScalarEvent):
|
||||||
|
node = self.compose_scalar_node()
|
||||||
|
elif self.check_event(SequenceStartEvent):
|
||||||
|
node = self.compose_sequence_node()
|
||||||
|
elif self.check_event(MappingStartEvent):
|
||||||
|
node = self.compose_mapping_node()
|
||||||
|
self.ascend_resolver()
|
||||||
|
return node
|
||||||
|
|
||||||
|
def compose_scalar_node(self):
|
||||||
|
event = self.get_event()
|
||||||
|
tag = event.tag
|
||||||
|
if tag is None or tag == '!':
|
||||||
|
tag = self.resolve(ScalarNode, event.value, event.implicit, event.start_mark)
|
||||||
|
node = ScalarNode(tag, event.value,
|
||||||
|
event.start_mark, event.end_mark, style=event.style)
|
||||||
|
return node
|
||||||
|
|
||||||
|
def compose_sequence_node(self):
|
||||||
|
start_event = self.get_event()
|
||||||
|
tag = start_event.tag
|
||||||
|
if tag is None or tag == '!':
|
||||||
|
tag = self.resolve(SequenceNode, None, start_event.implicit)
|
||||||
|
node = SequenceNode(tag, [],
|
||||||
|
start_event.start_mark, None,
|
||||||
|
flow_style=start_event.flow_style)
|
||||||
|
index = 0
|
||||||
|
while not self.check_event(SequenceEndEvent):
|
||||||
|
node.value.append(self.compose_node(node, index))
|
||||||
|
index += 1
|
||||||
|
end_event = self.get_event()
|
||||||
|
node.end_mark = end_event.end_mark
|
||||||
|
return node
|
||||||
|
|
||||||
|
def compose_mapping_node(self):
|
||||||
|
start_event = self.get_event()
|
||||||
|
tag = start_event.tag
|
||||||
|
if tag is None or tag == '!':
|
||||||
|
tag = self.resolve(MappingNode, None, start_event.implicit)
|
||||||
|
node = MappingNode(tag, [],
|
||||||
|
start_event.start_mark, None,
|
||||||
|
flow_style=start_event.flow_style)
|
||||||
|
while not self.check_event(MappingEndEvent):
|
||||||
|
#key_event = self.peek_event()
|
||||||
|
item_key = self.compose_node(node, None)
|
||||||
|
#if item_key in node.value:
|
||||||
|
# raise ComposerError("while composing a mapping", start_event.start_mark,
|
||||||
|
# "found duplicate key", key_event.start_mark)
|
||||||
|
item_value = self.compose_node(node, item_key)
|
||||||
|
#node.value[item_key] = item_value
|
||||||
|
node.value.append((item_key, item_value))
|
||||||
|
end_event = self.get_event()
|
||||||
|
node.end_mark = end_event.end_mark
|
||||||
|
return node
|
|
@ -0,0 +1,274 @@
|
||||||
|
__all__ = ['BaseConstructor', 'Constructor', 'ConstructorError']
|
||||||
|
|
||||||
|
from .error import MarkedError
|
||||||
|
from .nodes import * # NOQA
|
||||||
|
from .markedvalue import gen_marked_value
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import types
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __builtin__ import unicode
|
||||||
|
except ImportError:
|
||||||
|
unicode = str # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
def marked(func):
|
||||||
|
@wraps(func)
|
||||||
|
def f(self, node, *args, **kwargs):
|
||||||
|
return gen_marked_value(func(self, node, *args, **kwargs), node.start_mark)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
class ConstructorError(MarkedError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BaseConstructor:
|
||||||
|
yaml_constructors = {}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.constructed_objects = {}
|
||||||
|
self.state_generators = []
|
||||||
|
self.deep_construct = False
|
||||||
|
|
||||||
|
def check_data(self):
|
||||||
|
# If there are more documents available?
|
||||||
|
return self.check_node()
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
# Construct and return the next document.
|
||||||
|
if self.check_node():
|
||||||
|
return self.construct_document(self.get_node())
|
||||||
|
|
||||||
|
def get_single_data(self):
|
||||||
|
# Ensure that the stream contains a single document and construct it.
|
||||||
|
node = self.get_single_node()
|
||||||
|
if node is not None:
|
||||||
|
return self.construct_document(node)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def construct_document(self, node):
|
||||||
|
data = self.construct_object(node)
|
||||||
|
while self.state_generators:
|
||||||
|
state_generators = self.state_generators
|
||||||
|
self.state_generators = []
|
||||||
|
for generator in state_generators:
|
||||||
|
for dummy in generator:
|
||||||
|
pass
|
||||||
|
self.constructed_objects = {}
|
||||||
|
self.deep_construct = False
|
||||||
|
return data
|
||||||
|
|
||||||
|
def construct_object(self, node, deep=False):
|
||||||
|
if node in self.constructed_objects:
|
||||||
|
return self.constructed_objects[node]
|
||||||
|
if deep:
|
||||||
|
old_deep = self.deep_construct
|
||||||
|
self.deep_construct = True
|
||||||
|
constructor = None
|
||||||
|
tag_suffix = None
|
||||||
|
if node.tag in self.yaml_constructors:
|
||||||
|
constructor = self.yaml_constructors[node.tag]
|
||||||
|
else:
|
||||||
|
raise ConstructorError(None, None, 'no constructor for tag %s' % node.tag)
|
||||||
|
if tag_suffix is None:
|
||||||
|
data = constructor(self, node)
|
||||||
|
else:
|
||||||
|
data = constructor(self, tag_suffix, node)
|
||||||
|
if isinstance(data, types.GeneratorType):
|
||||||
|
generator = data
|
||||||
|
data = next(generator)
|
||||||
|
if self.deep_construct:
|
||||||
|
for dummy in generator:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.state_generators.append(generator)
|
||||||
|
self.constructed_objects[node] = data
|
||||||
|
if deep:
|
||||||
|
self.deep_construct = old_deep
|
||||||
|
return data
|
||||||
|
|
||||||
|
@marked
|
||||||
|
def construct_scalar(self, node):
|
||||||
|
if not isinstance(node, ScalarNode):
|
||||||
|
raise ConstructorError(None, None,
|
||||||
|
"expected a scalar node, but found %s" % node.id,
|
||||||
|
node.start_mark)
|
||||||
|
return node.value
|
||||||
|
|
||||||
|
def construct_sequence(self, node, deep=False):
|
||||||
|
if not isinstance(node, SequenceNode):
|
||||||
|
raise ConstructorError(None, None,
|
||||||
|
"expected a sequence node, but found %s" % node.id,
|
||||||
|
node.start_mark)
|
||||||
|
return [self.construct_object(child, deep=deep)
|
||||||
|
for child in node.value]
|
||||||
|
|
||||||
|
@marked
|
||||||
|
def construct_mapping(self, node, deep=False):
|
||||||
|
if not isinstance(node, MappingNode):
|
||||||
|
raise ConstructorError(None, None,
|
||||||
|
"expected a mapping node, but found %s" % node.id,
|
||||||
|
node.start_mark)
|
||||||
|
mapping = {}
|
||||||
|
for key_node, value_node in node.value:
|
||||||
|
key = self.construct_object(key_node, deep=deep)
|
||||||
|
if not isinstance(key, collections.Hashable):
|
||||||
|
self.echoerr('While constructing a mapping', node.start_mark,
|
||||||
|
'found unhashable key', key_node.start_mark)
|
||||||
|
continue
|
||||||
|
elif type(key.value) != unicode:
|
||||||
|
self.echoerr('Error while constructing a mapping', node.start_mark,
|
||||||
|
'found key that is not a string', key_node.start_mark)
|
||||||
|
continue
|
||||||
|
elif key in mapping:
|
||||||
|
self.echoerr('Error while constructing a mapping', node.start_mark,
|
||||||
|
'found duplicate key', key_node.start_mark)
|
||||||
|
continue
|
||||||
|
value = self.construct_object(value_node, deep=deep)
|
||||||
|
mapping[key] = value
|
||||||
|
return mapping
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_constructor(cls, tag, constructor):
|
||||||
|
if not 'yaml_constructors' in cls.__dict__:
|
||||||
|
cls.yaml_constructors = cls.yaml_constructors.copy()
|
||||||
|
cls.yaml_constructors[tag] = constructor
|
||||||
|
|
||||||
|
|
||||||
|
class Constructor(BaseConstructor):
|
||||||
|
def construct_scalar(self, node):
|
||||||
|
if isinstance(node, MappingNode):
|
||||||
|
for key_node, value_node in node.value:
|
||||||
|
if key_node.tag == 'tag:yaml.org,2002:value':
|
||||||
|
return self.construct_scalar(value_node)
|
||||||
|
return BaseConstructor.construct_scalar(self, node)
|
||||||
|
|
||||||
|
def flatten_mapping(self, node):
|
||||||
|
merge = []
|
||||||
|
index = 0
|
||||||
|
while index < len(node.value):
|
||||||
|
key_node, value_node = node.value[index]
|
||||||
|
if key_node.tag == 'tag:yaml.org,2002:merge':
|
||||||
|
del node.value[index]
|
||||||
|
if isinstance(value_node, MappingNode):
|
||||||
|
self.flatten_mapping(value_node)
|
||||||
|
merge.extend(value_node.value)
|
||||||
|
elif isinstance(value_node, SequenceNode):
|
||||||
|
submerge = []
|
||||||
|
for subnode in value_node.value:
|
||||||
|
if not isinstance(subnode, MappingNode):
|
||||||
|
raise ConstructorError("while constructing a mapping",
|
||||||
|
node.start_mark,
|
||||||
|
"expected a mapping for merging, but found %s"
|
||||||
|
% subnode.id, subnode.start_mark)
|
||||||
|
self.flatten_mapping(subnode)
|
||||||
|
submerge.append(subnode.value)
|
||||||
|
submerge.reverse()
|
||||||
|
for value in submerge:
|
||||||
|
merge.extend(value)
|
||||||
|
else:
|
||||||
|
raise ConstructorError("while constructing a mapping", node.start_mark,
|
||||||
|
"expected a mapping or list of mappings for merging, but found %s"
|
||||||
|
% value_node.id, value_node.start_mark)
|
||||||
|
elif key_node.tag == 'tag:yaml.org,2002:value':
|
||||||
|
key_node.tag = 'tag:yaml.org,2002:str'
|
||||||
|
index += 1
|
||||||
|
else:
|
||||||
|
index += 1
|
||||||
|
if merge:
|
||||||
|
node.value = merge + node.value
|
||||||
|
|
||||||
|
def construct_mapping(self, node, deep=False):
|
||||||
|
if isinstance(node, MappingNode):
|
||||||
|
self.flatten_mapping(node)
|
||||||
|
return BaseConstructor.construct_mapping(self, node, deep=deep)
|
||||||
|
|
||||||
|
@marked
|
||||||
|
def construct_yaml_null(self, node):
|
||||||
|
self.construct_scalar(node)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@marked
|
||||||
|
def construct_yaml_bool(self, node):
|
||||||
|
value = self.construct_scalar(node).value
|
||||||
|
return bool(value)
|
||||||
|
|
||||||
|
@marked
|
||||||
|
def construct_yaml_int(self, node):
|
||||||
|
value = self.construct_scalar(node).value
|
||||||
|
sign = +1
|
||||||
|
if value[0] == '-':
|
||||||
|
sign = -1
|
||||||
|
if value[0] in '+-':
|
||||||
|
value = value[1:]
|
||||||
|
if value == '0':
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return sign * int(value)
|
||||||
|
|
||||||
|
@marked
|
||||||
|
def construct_yaml_float(self, node):
|
||||||
|
value = self.construct_scalar(node).value
|
||||||
|
sign = +1
|
||||||
|
if value[0] == '-':
|
||||||
|
sign = -1
|
||||||
|
if value[0] in '+-':
|
||||||
|
value = value[1:]
|
||||||
|
else:
|
||||||
|
return sign * float(value)
|
||||||
|
|
||||||
|
def construct_yaml_str(self, node):
|
||||||
|
return self.construct_scalar(node)
|
||||||
|
|
||||||
|
def construct_yaml_seq(self, node):
|
||||||
|
data = gen_marked_value([], node.start_mark)
|
||||||
|
yield data
|
||||||
|
data.extend(self.construct_sequence(node))
|
||||||
|
|
||||||
|
def construct_yaml_map(self, node):
|
||||||
|
data = gen_marked_value({}, node.start_mark)
|
||||||
|
yield data
|
||||||
|
value = self.construct_mapping(node)
|
||||||
|
data.update(value)
|
||||||
|
|
||||||
|
def construct_undefined(self, node):
|
||||||
|
raise ConstructorError(None, None,
|
||||||
|
"could not determine a constructor for the tag %r" % node.tag,
|
||||||
|
node.start_mark)
|
||||||
|
|
||||||
|
|
||||||
|
Constructor.add_constructor(
|
||||||
|
'tag:yaml.org,2002:null',
|
||||||
|
Constructor.construct_yaml_null)
|
||||||
|
|
||||||
|
Constructor.add_constructor(
|
||||||
|
'tag:yaml.org,2002:bool',
|
||||||
|
Constructor.construct_yaml_bool)
|
||||||
|
|
||||||
|
Constructor.add_constructor(
|
||||||
|
'tag:yaml.org,2002:int',
|
||||||
|
Constructor.construct_yaml_int)
|
||||||
|
|
||||||
|
Constructor.add_constructor(
|
||||||
|
'tag:yaml.org,2002:float',
|
||||||
|
Constructor.construct_yaml_float)
|
||||||
|
|
||||||
|
Constructor.add_constructor(
|
||||||
|
'tag:yaml.org,2002:str',
|
||||||
|
Constructor.construct_yaml_str)
|
||||||
|
|
||||||
|
Constructor.add_constructor(
|
||||||
|
'tag:yaml.org,2002:seq',
|
||||||
|
Constructor.construct_yaml_seq)
|
||||||
|
|
||||||
|
Constructor.add_constructor(
|
||||||
|
'tag:yaml.org,2002:map',
|
||||||
|
Constructor.construct_yaml_map)
|
||||||
|
|
||||||
|
Constructor.add_constructor(None,
|
||||||
|
Constructor.construct_undefined)
|
|
@ -0,0 +1,99 @@
|
||||||
|
__all__ = ['Mark', 'MarkedError', 'echoerr', 'NON_PRINTABLE']
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __builtin__ import unichr
|
||||||
|
except ImportError:
|
||||||
|
unichr = chr # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
NON_PRINTABLE = re.compile('[^\t\n\x20-\x7E' + unichr(0x85) + (unichr(0xA0) + '-' + unichr(0xD7FF)) + (unichr(0xE000) + '-' + unichr(0xFFFD)) + ']')
|
||||||
|
|
||||||
|
|
||||||
|
def repl(s):
|
||||||
|
return '<x%04x>' % ord(s.group())
|
||||||
|
|
||||||
|
|
||||||
|
def strtrans(s):
|
||||||
|
return NON_PRINTABLE.sub(repl, s.replace('\t', '>---'))
|
||||||
|
|
||||||
|
|
||||||
|
class Mark:
|
||||||
|
def __init__(self, name, line, column, buffer, pointer):
|
||||||
|
self.name = name
|
||||||
|
self.line = line
|
||||||
|
self.column = column
|
||||||
|
self.buffer = buffer
|
||||||
|
self.pointer = pointer
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return Mark(self.name, self.line, self.column, self.buffer, self.pointer)
|
||||||
|
|
||||||
|
def get_snippet(self, indent=4, max_length=75):
|
||||||
|
if self.buffer is None:
|
||||||
|
return None
|
||||||
|
head = ''
|
||||||
|
start = self.pointer
|
||||||
|
while start > 0 and self.buffer[start - 1] not in '\0\n':
|
||||||
|
start -= 1
|
||||||
|
if self.pointer - start > max_length / 2 - 1:
|
||||||
|
head = ' ... '
|
||||||
|
start += 5
|
||||||
|
break
|
||||||
|
tail = ''
|
||||||
|
end = self.pointer
|
||||||
|
while end < len(self.buffer) and self.buffer[end] not in '\0\n':
|
||||||
|
end += 1
|
||||||
|
if end - self.pointer > max_length / 2 - 1:
|
||||||
|
tail = ' ... '
|
||||||
|
end -= 5
|
||||||
|
break
|
||||||
|
snippet = [self.buffer[start:self.pointer], self.buffer[self.pointer], self.buffer[self.pointer + 1:end]]
|
||||||
|
snippet = [strtrans(s) for s in snippet]
|
||||||
|
return ' ' * indent + head + ''.join(snippet) + tail + '\n' \
|
||||||
|
+ ' ' * (indent + len(head) + len(snippet[0])) + '^'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
snippet = self.get_snippet()
|
||||||
|
where = " in \"%s\", line %d, column %d" \
|
||||||
|
% (self.name, self.line + 1, self.column + 1)
|
||||||
|
if snippet is not None:
|
||||||
|
where += ":\n" + snippet
|
||||||
|
if type(where) is str:
|
||||||
|
return where
|
||||||
|
else:
|
||||||
|
return where.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def echoerr(*args, **kwargs):
|
||||||
|
sys.stderr.write('\n')
|
||||||
|
sys.stderr.write(format_error(*args, **kwargs) + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
def format_error(context=None, context_mark=None, problem=None, problem_mark=None, note=None):
|
||||||
|
lines = []
|
||||||
|
if context is not None:
|
||||||
|
lines.append(context)
|
||||||
|
if context_mark is not None \
|
||||||
|
and (problem is None or problem_mark is None
|
||||||
|
or context_mark.name != problem_mark.name
|
||||||
|
or context_mark.line != problem_mark.line
|
||||||
|
or context_mark.column != problem_mark.column):
|
||||||
|
lines.append(str(context_mark))
|
||||||
|
if problem is not None:
|
||||||
|
lines.append(problem)
|
||||||
|
if problem_mark is not None:
|
||||||
|
lines.append(str(problem_mark))
|
||||||
|
if note is not None:
|
||||||
|
lines.append(note)
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
class MarkedError(Exception):
|
||||||
|
def __init__(self, context=None, context_mark=None,
|
||||||
|
problem=None, problem_mark=None, note=None):
|
||||||
|
Exception.__init__(self, format_error(context, context_mark, problem,
|
||||||
|
problem_mark, note))
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Abstract classes.
|
||||||
|
|
||||||
|
|
||||||
|
class Event(object):
|
||||||
|
def __init__(self, start_mark=None, end_mark=None):
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
attributes = [key for key in ['implicit', 'value']
|
||||||
|
if hasattr(self, key)]
|
||||||
|
arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
|
||||||
|
for key in attributes])
|
||||||
|
return '%s(%s)' % (self.__class__.__name__, arguments)
|
||||||
|
|
||||||
|
|
||||||
|
class NodeEvent(Event):
|
||||||
|
def __init__(self, start_mark=None, end_mark=None):
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionStartEvent(NodeEvent):
|
||||||
|
def __init__(self, implicit, start_mark=None, end_mark=None,
|
||||||
|
flow_style=None):
|
||||||
|
self.tag = None
|
||||||
|
self.implicit = implicit
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.flow_style = flow_style
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionEndEvent(Event):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Implementations.
|
||||||
|
|
||||||
|
|
||||||
|
class StreamStartEvent(Event):
|
||||||
|
def __init__(self, start_mark=None, end_mark=None, encoding=None):
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.encoding = encoding
|
||||||
|
|
||||||
|
|
||||||
|
class StreamEndEvent(Event):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentStartEvent(Event):
|
||||||
|
def __init__(self, start_mark=None, end_mark=None,
|
||||||
|
explicit=None, version=None, tags=None):
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.explicit = explicit
|
||||||
|
self.version = version
|
||||||
|
self.tags = tags
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentEndEvent(Event):
|
||||||
|
def __init__(self, start_mark=None, end_mark=None,
|
||||||
|
explicit=None):
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.explicit = explicit
|
||||||
|
|
||||||
|
|
||||||
|
class AliasEvent(NodeEvent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ScalarEvent(NodeEvent):
|
||||||
|
def __init__(self, implicit, value,
|
||||||
|
start_mark=None, end_mark=None, style=None):
|
||||||
|
self.tag = None
|
||||||
|
self.implicit = implicit
|
||||||
|
self.value = value
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.style = style
|
||||||
|
|
||||||
|
|
||||||
|
class SequenceStartEvent(CollectionStartEvent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SequenceEndEvent(CollectionEndEvent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MappingStartEvent(CollectionStartEvent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MappingEndEvent(CollectionEndEvent):
|
||||||
|
pass
|
|
@ -0,0 +1,24 @@
|
||||||
|
__all__ = ['Loader']
|
||||||
|
|
||||||
|
from .reader import Reader
|
||||||
|
from .scanner import Scanner
|
||||||
|
from .parser import Parser
|
||||||
|
from .composer import Composer
|
||||||
|
from .constructor import Constructor
|
||||||
|
from .resolver import Resolver
|
||||||
|
from .error import echoerr
|
||||||
|
|
||||||
|
|
||||||
|
class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
|
||||||
|
def __init__(self, stream):
|
||||||
|
Reader.__init__(self, stream)
|
||||||
|
Scanner.__init__(self)
|
||||||
|
Parser.__init__(self)
|
||||||
|
Composer.__init__(self)
|
||||||
|
Constructor.__init__(self)
|
||||||
|
Resolver.__init__(self)
|
||||||
|
self.haserrors = False
|
||||||
|
|
||||||
|
def echoerr(self, *args, **kwargs):
|
||||||
|
echoerr(*args, **kwargs)
|
||||||
|
self.haserrors = True
|
|
@ -0,0 +1,83 @@
|
||||||
|
__all__ = ['gen_marked_value', 'MarkedValue']
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __builtin__ import unicode
|
||||||
|
except ImportError:
|
||||||
|
unicode = str
|
||||||
|
|
||||||
|
|
||||||
|
def gen_new(cls):
|
||||||
|
def __new__(arg_cls, value, mark):
|
||||||
|
r = super(arg_cls, arg_cls).__new__(arg_cls, value)
|
||||||
|
r.mark = mark
|
||||||
|
r.value = value
|
||||||
|
return r
|
||||||
|
return __new__
|
||||||
|
|
||||||
|
|
||||||
|
class MarkedUnicode(unicode):
|
||||||
|
__new__ = gen_new(unicode)
|
||||||
|
|
||||||
|
def _proc_partition(self, part_result):
|
||||||
|
pointdiff = 1
|
||||||
|
r = []
|
||||||
|
for s in part_result:
|
||||||
|
mark = self.mark.copy()
|
||||||
|
# XXX Does not work properly with escaped strings, but this requires
|
||||||
|
# saving much more information in mark.
|
||||||
|
mark.column += pointdiff
|
||||||
|
mark.pointer += pointdiff
|
||||||
|
r.append(MarkedUnicode(s, mark))
|
||||||
|
pointdiff += len(s)
|
||||||
|
return tuple(r)
|
||||||
|
|
||||||
|
def rpartition(self, sep):
|
||||||
|
return self._proc_partition(super(MarkedUnicode, self).rpartition(sep))
|
||||||
|
|
||||||
|
def partition(self, sep):
|
||||||
|
return self._proc_partition(super(MarkedUnicode, self).partition(sep))
|
||||||
|
|
||||||
|
|
||||||
|
class MarkedInt(int):
|
||||||
|
__new__ = gen_new(int)
|
||||||
|
|
||||||
|
|
||||||
|
class MarkedFloat(float):
|
||||||
|
__new__ = gen_new(float)
|
||||||
|
|
||||||
|
|
||||||
|
class MarkedValue:
|
||||||
|
def __init__(self, value, mark):
|
||||||
|
self.mark = mark
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
specialclasses = {
|
||||||
|
unicode: MarkedUnicode,
|
||||||
|
int: MarkedInt,
|
||||||
|
float: MarkedFloat,
|
||||||
|
}
|
||||||
|
|
||||||
|
classcache = {}
|
||||||
|
|
||||||
|
|
||||||
|
def gen_marked_value(value, mark, use_special_classes=True):
|
||||||
|
if use_special_classes and value.__class__ in specialclasses:
|
||||||
|
Marked = specialclasses[value.__class__]
|
||||||
|
elif value.__class__ in classcache:
|
||||||
|
Marked = classcache[value.__class__]
|
||||||
|
else:
|
||||||
|
class Marked(MarkedValue):
|
||||||
|
for func in value.__class__.__dict__:
|
||||||
|
if func not in set(('__init__', '__new__', '__getattribute__')):
|
||||||
|
if func in set(('__eq__',)):
|
||||||
|
# HACK to make marked dictionaries always work
|
||||||
|
exec (('def {0}(self, *args):\n'
|
||||||
|
' return self.value.{0}(*[arg.value if isinstance(arg, MarkedValue) else arg for arg in args])').format(func))
|
||||||
|
else:
|
||||||
|
exec (('def {0}(self, *args, **kwargs):\n'
|
||||||
|
' return self.value.{0}(*args, **kwargs)\n').format(func))
|
||||||
|
classcache[value.__class__] = Marked
|
||||||
|
|
||||||
|
return Marked(value, mark)
|
|
@ -0,0 +1,53 @@
|
||||||
|
class Node(object):
|
||||||
|
def __init__(self, tag, value, start_mark, end_mark):
|
||||||
|
self.tag = tag
|
||||||
|
self.value = value
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
value = self.value
|
||||||
|
#if isinstance(value, list):
|
||||||
|
# if len(value) == 0:
|
||||||
|
# value = '<empty>'
|
||||||
|
# elif len(value) == 1:
|
||||||
|
# value = '<1 item>'
|
||||||
|
# else:
|
||||||
|
# value = '<%d items>' % len(value)
|
||||||
|
#else:
|
||||||
|
# if len(value) > 75:
|
||||||
|
# value = repr(value[:70]+u' ... ')
|
||||||
|
# else:
|
||||||
|
# value = repr(value)
|
||||||
|
value = repr(value)
|
||||||
|
return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalarNode(Node):
|
||||||
|
id = 'scalar'
|
||||||
|
|
||||||
|
def __init__(self, tag, value,
|
||||||
|
start_mark=None, end_mark=None, style=None):
|
||||||
|
self.tag = tag
|
||||||
|
self.value = value
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.style = style
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionNode(Node):
|
||||||
|
def __init__(self, tag, value,
|
||||||
|
start_mark=None, end_mark=None, flow_style=None):
|
||||||
|
self.tag = tag
|
||||||
|
self.value = value
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.flow_style = flow_style
|
||||||
|
|
||||||
|
|
||||||
|
class SequenceNode(CollectionNode):
|
||||||
|
id = 'sequence'
|
||||||
|
|
||||||
|
|
||||||
|
class MappingNode(CollectionNode):
|
||||||
|
id = 'mapping'
|
|
@ -0,0 +1,240 @@
|
||||||
|
__all__ = ['Parser', 'ParserError']
|
||||||
|
|
||||||
|
from .error import MarkedError
|
||||||
|
from .tokens import * # NOQA
|
||||||
|
from .events import * # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class ParserError(MarkedError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Parser:
|
||||||
|
def __init__(self):
|
||||||
|
self.current_event = None
|
||||||
|
self.yaml_version = None
|
||||||
|
self.states = []
|
||||||
|
self.marks = []
|
||||||
|
self.state = self.parse_stream_start
|
||||||
|
|
||||||
|
def dispose(self):
|
||||||
|
# Reset the state attributes (to clear self-references)
|
||||||
|
self.states = []
|
||||||
|
self.state = None
|
||||||
|
|
||||||
|
def check_event(self, *choices):
|
||||||
|
# Check the type of the next event.
|
||||||
|
if self.current_event is None:
|
||||||
|
if self.state:
|
||||||
|
self.current_event = self.state()
|
||||||
|
if self.current_event is not None:
|
||||||
|
if not choices:
|
||||||
|
return True
|
||||||
|
for choice in choices:
|
||||||
|
if isinstance(self.current_event, choice):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def peek_event(self):
|
||||||
|
# Get the next event.
|
||||||
|
if self.current_event is None:
|
||||||
|
if self.state:
|
||||||
|
self.current_event = self.state()
|
||||||
|
return self.current_event
|
||||||
|
|
||||||
|
def get_event(self):
|
||||||
|
# Get the next event and proceed further.
|
||||||
|
if self.current_event is None:
|
||||||
|
if self.state:
|
||||||
|
self.current_event = self.state()
|
||||||
|
value = self.current_event
|
||||||
|
self.current_event = None
|
||||||
|
return value
|
||||||
|
|
||||||
|
# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
|
||||||
|
# implicit_document ::= block_node DOCUMENT-END*
|
||||||
|
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||||
|
|
||||||
|
def parse_stream_start(self):
|
||||||
|
# Parse the stream start.
|
||||||
|
token = self.get_token()
|
||||||
|
event = StreamStartEvent(token.start_mark, token.end_mark,
|
||||||
|
encoding=token.encoding)
|
||||||
|
|
||||||
|
# Prepare the next state.
|
||||||
|
self.state = self.parse_implicit_document_start
|
||||||
|
|
||||||
|
return event
|
||||||
|
|
||||||
|
def parse_implicit_document_start(self):
|
||||||
|
# Parse an implicit document.
|
||||||
|
if not self.check_token(StreamEndToken):
|
||||||
|
token = self.peek_token()
|
||||||
|
start_mark = end_mark = token.start_mark
|
||||||
|
event = DocumentStartEvent(start_mark, end_mark, explicit=False)
|
||||||
|
|
||||||
|
# Prepare the next state.
|
||||||
|
self.states.append(self.parse_document_end)
|
||||||
|
self.state = self.parse_node
|
||||||
|
|
||||||
|
return event
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.parse_document_start()
|
||||||
|
|
||||||
|
def parse_document_start(self):
|
||||||
|
# Parse an explicit document.
|
||||||
|
if not self.check_token(StreamEndToken):
|
||||||
|
token = self.peek_token()
|
||||||
|
self.echoerr(None, None,
|
||||||
|
"expected '<stream end>', but found %r" % token.id,
|
||||||
|
token.start_mark)
|
||||||
|
return StreamEndEvent(token.start_mark, token.end_mark)
|
||||||
|
else:
|
||||||
|
# Parse the end of the stream.
|
||||||
|
token = self.get_token()
|
||||||
|
event = StreamEndEvent(token.start_mark, token.end_mark)
|
||||||
|
assert not self.states
|
||||||
|
assert not self.marks
|
||||||
|
self.state = None
|
||||||
|
return event
|
||||||
|
|
||||||
|
def parse_document_end(self):
|
||||||
|
# Parse the document end.
|
||||||
|
token = self.peek_token()
|
||||||
|
start_mark = end_mark = token.start_mark
|
||||||
|
explicit = False
|
||||||
|
event = DocumentEndEvent(start_mark, end_mark, explicit=explicit)
|
||||||
|
|
||||||
|
# Prepare the next state.
|
||||||
|
self.state = self.parse_document_start
|
||||||
|
|
||||||
|
return event
|
||||||
|
|
||||||
|
def parse_document_content(self):
|
||||||
|
return self.parse_node()
|
||||||
|
|
||||||
|
def parse_node(self, indentless_sequence=False):
|
||||||
|
start_mark = end_mark = None
|
||||||
|
if start_mark is None:
|
||||||
|
start_mark = end_mark = self.peek_token().start_mark
|
||||||
|
event = None
|
||||||
|
implicit = True
|
||||||
|
if self.check_token(ScalarToken):
|
||||||
|
token = self.get_token()
|
||||||
|
end_mark = token.end_mark
|
||||||
|
if token.plain:
|
||||||
|
implicit = (True, False)
|
||||||
|
else:
|
||||||
|
implicit = (False, True)
|
||||||
|
event = ScalarEvent(implicit, token.value,
|
||||||
|
start_mark, end_mark, style=token.style)
|
||||||
|
self.state = self.states.pop()
|
||||||
|
elif self.check_token(FlowSequenceStartToken):
|
||||||
|
end_mark = self.peek_token().end_mark
|
||||||
|
event = SequenceStartEvent(implicit,
|
||||||
|
start_mark, end_mark, flow_style=True)
|
||||||
|
self.state = self.parse_flow_sequence_first_entry
|
||||||
|
elif self.check_token(FlowMappingStartToken):
|
||||||
|
end_mark = self.peek_token().end_mark
|
||||||
|
event = MappingStartEvent(implicit,
|
||||||
|
start_mark, end_mark, flow_style=True)
|
||||||
|
self.state = self.parse_flow_mapping_first_key
|
||||||
|
else:
|
||||||
|
token = self.peek_token()
|
||||||
|
raise ParserError("while parsing a flow node", start_mark,
|
||||||
|
"expected the node content, but found %r" % token.id,
|
||||||
|
token.start_mark)
|
||||||
|
return event
|
||||||
|
|
||||||
|
def parse_flow_sequence_first_entry(self):
|
||||||
|
token = self.get_token()
|
||||||
|
self.marks.append(token.start_mark)
|
||||||
|
return self.parse_flow_sequence_entry(first=True)
|
||||||
|
|
||||||
|
def parse_flow_sequence_entry(self, first=False):
|
||||||
|
if not self.check_token(FlowSequenceEndToken):
|
||||||
|
if not first:
|
||||||
|
if self.check_token(FlowEntryToken):
|
||||||
|
self.get_token()
|
||||||
|
if self.check_token(FlowSequenceEndToken):
|
||||||
|
token = self.peek_token()
|
||||||
|
self.echoerr("While parsing a flow sequence", self.marks[-1],
|
||||||
|
"expected sequence value, but got %r" % token.id, token.start_mark)
|
||||||
|
else:
|
||||||
|
token = self.peek_token()
|
||||||
|
raise ParserError("while parsing a flow sequence", self.marks[-1],
|
||||||
|
"expected ',' or ']', but got %r" % token.id, token.start_mark)
|
||||||
|
|
||||||
|
if not self.check_token(FlowSequenceEndToken):
|
||||||
|
self.states.append(self.parse_flow_sequence_entry)
|
||||||
|
return self.parse_node()
|
||||||
|
token = self.get_token()
|
||||||
|
event = SequenceEndEvent(token.start_mark, token.end_mark)
|
||||||
|
self.state = self.states.pop()
|
||||||
|
self.marks.pop()
|
||||||
|
return event
|
||||||
|
|
||||||
|
def parse_flow_sequence_entry_mapping_end(self):
|
||||||
|
self.state = self.parse_flow_sequence_entry
|
||||||
|
token = self.peek_token()
|
||||||
|
return MappingEndEvent(token.start_mark, token.start_mark)
|
||||||
|
|
||||||
|
def parse_flow_mapping_first_key(self):
|
||||||
|
token = self.get_token()
|
||||||
|
self.marks.append(token.start_mark)
|
||||||
|
return self.parse_flow_mapping_key(first=True)
|
||||||
|
|
||||||
|
def parse_flow_mapping_key(self, first=False):
|
||||||
|
if not self.check_token(FlowMappingEndToken):
|
||||||
|
if not first:
|
||||||
|
if self.check_token(FlowEntryToken):
|
||||||
|
self.get_token()
|
||||||
|
if self.check_token(FlowMappingEndToken):
|
||||||
|
token = self.peek_token()
|
||||||
|
self.echoerr("While parsing a flow mapping", self.marks[-1],
|
||||||
|
"expected mapping key, but got %r" % token.id, token.start_mark)
|
||||||
|
else:
|
||||||
|
token = self.peek_token()
|
||||||
|
raise ParserError("while parsing a flow mapping", self.marks[-1],
|
||||||
|
"expected ',' or '}', but got %r" % token.id, token.start_mark)
|
||||||
|
if self.check_token(KeyToken):
|
||||||
|
token = self.get_token()
|
||||||
|
if not self.check_token(ValueToken,
|
||||||
|
FlowEntryToken, FlowMappingEndToken):
|
||||||
|
self.states.append(self.parse_flow_mapping_value)
|
||||||
|
return self.parse_node()
|
||||||
|
else:
|
||||||
|
token = self.peek_token()
|
||||||
|
raise ParserError("while parsing a flow mapping", self.marks[-1],
|
||||||
|
"expected value, but got %r" % token.id, token.start_mark)
|
||||||
|
elif not self.check_token(FlowMappingEndToken):
|
||||||
|
token = self.peek_token()
|
||||||
|
expect_key = self.check_token(ValueToken, FlowEntryToken)
|
||||||
|
if not expect_key:
|
||||||
|
self.get_token()
|
||||||
|
expect_key = self.check_token(ValueToken)
|
||||||
|
|
||||||
|
if expect_key:
|
||||||
|
raise ParserError("while parsing a flow mapping", self.marks[-1],
|
||||||
|
"expected string key, but got %r" % token.id, token.start_mark)
|
||||||
|
else:
|
||||||
|
token = self.peek_token()
|
||||||
|
raise ParserError("while parsing a flow mapping", self.marks[-1],
|
||||||
|
"expected ':', but got %r" % token.id, token.start_mark)
|
||||||
|
token = self.get_token()
|
||||||
|
event = MappingEndEvent(token.start_mark, token.end_mark)
|
||||||
|
self.state = self.states.pop()
|
||||||
|
self.marks.pop()
|
||||||
|
return event
|
||||||
|
|
||||||
|
def parse_flow_mapping_value(self):
|
||||||
|
if self.check_token(ValueToken):
|
||||||
|
token = self.get_token()
|
||||||
|
if not self.check_token(FlowEntryToken, FlowMappingEndToken):
|
||||||
|
self.states.append(self.parse_flow_mapping_key)
|
||||||
|
return self.parse_node()
|
||||||
|
|
||||||
|
token = self.peek_token()
|
||||||
|
raise ParserError("while parsing a flow mapping", self.marks[-1],
|
||||||
|
"expected mapping value, but got %r" % token.id, token.start_mark)
|
|
@ -0,0 +1,135 @@
|
||||||
|
# This module contains abstractions for the input stream. You don't have to
|
||||||
|
# looks further, there are no pretty code.
|
||||||
|
|
||||||
|
__all__ = ['Reader', 'ReaderError']
|
||||||
|
|
||||||
|
from .error import MarkedError, Mark, NON_PRINTABLE
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __builtin__ import unicode
|
||||||
|
except ImportError:
|
||||||
|
unicode = str # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class ReaderError(MarkedError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Reader(object):
|
||||||
|
# Reader:
|
||||||
|
# - determines the data encoding and converts it to a unicode string,
|
||||||
|
# - checks if characters are in allowed range,
|
||||||
|
# - adds '\0' to the end.
|
||||||
|
|
||||||
|
# Reader accepts
|
||||||
|
# - a file-like object with its `read` method returning `str`,
|
||||||
|
|
||||||
|
# Yeah, it's ugly and slow.
|
||||||
|
def __init__(self, stream):
|
||||||
|
self.name = None
|
||||||
|
self.stream = None
|
||||||
|
self.stream_pointer = 0
|
||||||
|
self.eof = True
|
||||||
|
self.buffer = ''
|
||||||
|
self.pointer = 0
|
||||||
|
self.full_buffer = unicode('')
|
||||||
|
self.full_pointer = 0
|
||||||
|
self.raw_buffer = None
|
||||||
|
self.raw_decode = codecs.utf_8_decode
|
||||||
|
self.encoding = 'utf-8'
|
||||||
|
self.index = 0
|
||||||
|
self.line = 0
|
||||||
|
self.column = 0
|
||||||
|
|
||||||
|
self.stream = stream
|
||||||
|
self.name = getattr(stream, 'name', "<file>")
|
||||||
|
self.eof = False
|
||||||
|
self.raw_buffer = None
|
||||||
|
|
||||||
|
while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2):
|
||||||
|
self.update_raw()
|
||||||
|
self.update(1)
|
||||||
|
|
||||||
|
def peek(self, index=0):
|
||||||
|
try:
|
||||||
|
return self.buffer[self.pointer + index]
|
||||||
|
except IndexError:
|
||||||
|
self.update(index + 1)
|
||||||
|
return self.buffer[self.pointer + index]
|
||||||
|
|
||||||
|
def prefix(self, length=1):
|
||||||
|
if self.pointer + length >= len(self.buffer):
|
||||||
|
self.update(length)
|
||||||
|
return self.buffer[self.pointer:self.pointer + length]
|
||||||
|
|
||||||
|
def update_pointer(self, length):
|
||||||
|
while length:
|
||||||
|
ch = self.buffer[self.pointer]
|
||||||
|
self.pointer += 1
|
||||||
|
self.full_pointer += 1
|
||||||
|
self.index += 1
|
||||||
|
if ch == '\n':
|
||||||
|
self.line += 1
|
||||||
|
self.column = 0
|
||||||
|
else:
|
||||||
|
self.column += 1
|
||||||
|
length -= 1
|
||||||
|
|
||||||
|
def forward(self, length=1):
|
||||||
|
if self.pointer + length + 1 >= len(self.buffer):
|
||||||
|
self.update(length + 1)
|
||||||
|
self.update_pointer(length)
|
||||||
|
|
||||||
|
def get_mark(self):
|
||||||
|
return Mark(self.name, self.line, self.column, self.full_buffer, self.full_pointer)
|
||||||
|
|
||||||
|
def check_printable(self, data):
|
||||||
|
match = NON_PRINTABLE.search(data)
|
||||||
|
if match:
|
||||||
|
self.update_pointer(match.start())
|
||||||
|
raise ReaderError('while reading from stream', None,
|
||||||
|
'found special characters which are not allowed',
|
||||||
|
Mark(self.name, self.line, self.column, self.full_buffer, self.full_pointer))
|
||||||
|
|
||||||
|
def update(self, length):
|
||||||
|
if self.raw_buffer is None:
|
||||||
|
return
|
||||||
|
self.buffer = self.buffer[self.pointer:]
|
||||||
|
self.pointer = 0
|
||||||
|
while len(self.buffer) < length:
|
||||||
|
if not self.eof:
|
||||||
|
self.update_raw()
|
||||||
|
try:
|
||||||
|
data, converted = self.raw_decode(self.raw_buffer,
|
||||||
|
'strict', self.eof)
|
||||||
|
except UnicodeDecodeError as exc:
|
||||||
|
character = self.raw_buffer[exc.start]
|
||||||
|
position = self.stream_pointer - len(self.raw_buffer) + exc.start
|
||||||
|
data, converted = self.raw_decode(self.raw_buffer[:exc.start], 'strict', self.eof)
|
||||||
|
self.buffer += data
|
||||||
|
self.full_buffer += data + '<' + str(ord(character)) + '>'
|
||||||
|
self.raw_buffer = self.raw_buffer[converted:]
|
||||||
|
self.update_pointer(exc.start - 1)
|
||||||
|
raise ReaderError('while reading from stream', None,
|
||||||
|
'found character #x%04x that cannot be decoded by UTF-8 codec' % ord(character),
|
||||||
|
Mark(self.name, self.line, self.column, self.full_buffer, position))
|
||||||
|
self.buffer += data
|
||||||
|
self.full_buffer += data
|
||||||
|
self.raw_buffer = self.raw_buffer[converted:]
|
||||||
|
self.check_printable(data)
|
||||||
|
if self.eof:
|
||||||
|
self.buffer += '\0'
|
||||||
|
self.raw_buffer = None
|
||||||
|
break
|
||||||
|
|
||||||
|
def update_raw(self, size=4096):
|
||||||
|
data = self.stream.read(size)
|
||||||
|
if self.raw_buffer is None:
|
||||||
|
self.raw_buffer = data
|
||||||
|
else:
|
||||||
|
self.raw_buffer += data
|
||||||
|
self.stream_pointer += len(data)
|
||||||
|
if not data:
|
||||||
|
self.eof = True
|
|
@ -0,0 +1,131 @@
|
||||||
|
__all__ = ['BaseResolver', 'Resolver']
|
||||||
|
|
||||||
|
from .error import MarkedError
|
||||||
|
from .nodes import * # NOQA
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class ResolverError(MarkedError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BaseResolver:
|
||||||
|
DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str'
|
||||||
|
DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq'
|
||||||
|
DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map'
|
||||||
|
|
||||||
|
yaml_implicit_resolvers = {}
|
||||||
|
yaml_path_resolvers = {}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.resolver_exact_paths = []
|
||||||
|
self.resolver_prefix_paths = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_implicit_resolver(cls, tag, regexp, first):
|
||||||
|
if not 'yaml_implicit_resolvers' in cls.__dict__:
|
||||||
|
cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy()
|
||||||
|
if first is None:
|
||||||
|
first = [None]
|
||||||
|
for ch in first:
|
||||||
|
cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))
|
||||||
|
|
||||||
|
def descend_resolver(self, current_node, current_index):
|
||||||
|
if not self.yaml_path_resolvers:
|
||||||
|
return
|
||||||
|
exact_paths = {}
|
||||||
|
prefix_paths = []
|
||||||
|
if current_node:
|
||||||
|
depth = len(self.resolver_prefix_paths)
|
||||||
|
for path, kind in self.resolver_prefix_paths[-1]:
|
||||||
|
if self.check_resolver_prefix(depth, path, kind,
|
||||||
|
current_node, current_index):
|
||||||
|
if len(path) > depth:
|
||||||
|
prefix_paths.append((path, kind))
|
||||||
|
else:
|
||||||
|
exact_paths[kind] = self.yaml_path_resolvers[path, kind]
|
||||||
|
else:
|
||||||
|
for path, kind in self.yaml_path_resolvers:
|
||||||
|
if not path:
|
||||||
|
exact_paths[kind] = self.yaml_path_resolvers[path, kind]
|
||||||
|
else:
|
||||||
|
prefix_paths.append((path, kind))
|
||||||
|
self.resolver_exact_paths.append(exact_paths)
|
||||||
|
self.resolver_prefix_paths.append(prefix_paths)
|
||||||
|
|
||||||
|
def ascend_resolver(self):
|
||||||
|
if not self.yaml_path_resolvers:
|
||||||
|
return
|
||||||
|
self.resolver_exact_paths.pop()
|
||||||
|
self.resolver_prefix_paths.pop()
|
||||||
|
|
||||||
|
def check_resolver_prefix(self, depth, path, kind,
|
||||||
|
current_node, current_index):
|
||||||
|
node_check, index_check = path[depth - 1]
|
||||||
|
if isinstance(node_check, str):
|
||||||
|
if current_node.tag != node_check:
|
||||||
|
return
|
||||||
|
elif node_check is not None:
|
||||||
|
if not isinstance(current_node, node_check):
|
||||||
|
return
|
||||||
|
if index_check is True and current_index is not None:
|
||||||
|
return
|
||||||
|
if (index_check is False or index_check is None) \
|
||||||
|
and current_index is None:
|
||||||
|
return
|
||||||
|
if isinstance(index_check, str):
|
||||||
|
if not (isinstance(current_index, ScalarNode)
|
||||||
|
and index_check == current_index.value):
|
||||||
|
return
|
||||||
|
elif isinstance(index_check, int) and not isinstance(index_check, bool):
|
||||||
|
if index_check != current_index:
|
||||||
|
return
|
||||||
|
return True
|
||||||
|
|
||||||
|
def resolve(self, kind, value, implicit, mark=None):
|
||||||
|
if kind is ScalarNode and implicit[0]:
|
||||||
|
if value == '':
|
||||||
|
resolvers = self.yaml_implicit_resolvers.get('', [])
|
||||||
|
else:
|
||||||
|
resolvers = self.yaml_implicit_resolvers.get(value[0], [])
|
||||||
|
resolvers += self.yaml_implicit_resolvers.get(None, [])
|
||||||
|
for tag, regexp in resolvers:
|
||||||
|
if regexp.match(value):
|
||||||
|
return tag
|
||||||
|
else:
|
||||||
|
self.echoerr('While resolving plain scalar', None,
|
||||||
|
'expected floating-point value, integer, null or boolean, but got %r' % value,
|
||||||
|
mark)
|
||||||
|
return self.DEFAULT_SCALAR_TAG
|
||||||
|
if kind is ScalarNode:
|
||||||
|
return self.DEFAULT_SCALAR_TAG
|
||||||
|
elif kind is SequenceNode:
|
||||||
|
return self.DEFAULT_SEQUENCE_TAG
|
||||||
|
elif kind is MappingNode:
|
||||||
|
return self.DEFAULT_MAPPING_TAG
|
||||||
|
|
||||||
|
|
||||||
|
class Resolver(BaseResolver):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
Resolver.add_implicit_resolver(
|
||||||
|
'tag:yaml.org,2002:bool',
|
||||||
|
re.compile(r'''^(?:true|false)$''', re.X),
|
||||||
|
list('yYnNtTfFoO'))
|
||||||
|
|
||||||
|
Resolver.add_implicit_resolver(
|
||||||
|
'tag:yaml.org,2002:float',
|
||||||
|
re.compile(r'^-?(?:0|[1-9]\d*)(?=[.eE])(?:\.\d+)?(?:[eE][-+]?\d+)?$', re.X),
|
||||||
|
list('-0123456789'))
|
||||||
|
|
||||||
|
Resolver.add_implicit_resolver(
|
||||||
|
'tag:yaml.org,2002:int',
|
||||||
|
re.compile(r'^(?:0|-?[1-9]\d*)$', re.X),
|
||||||
|
list('-0123456789'))
|
||||||
|
|
||||||
|
Resolver.add_implicit_resolver(
|
||||||
|
'tag:yaml.org,2002:null',
|
||||||
|
re.compile(r'^null$', re.X),
|
||||||
|
['n'])
|
|
@ -0,0 +1,474 @@
|
||||||
|
# Scanner produces tokens of the following types:
|
||||||
|
# STREAM-START
|
||||||
|
# STREAM-END
|
||||||
|
# DOCUMENT-START
|
||||||
|
# DOCUMENT-END
|
||||||
|
# FLOW-SEQUENCE-START
|
||||||
|
# FLOW-MAPPING-START
|
||||||
|
# FLOW-SEQUENCE-END
|
||||||
|
# FLOW-MAPPING-END
|
||||||
|
# FLOW-ENTRY
|
||||||
|
# KEY
|
||||||
|
# VALUE
|
||||||
|
# SCALAR(value, plain, style)
|
||||||
|
#
|
||||||
|
# Read comments in the Scanner code for more details.
|
||||||
|
|
||||||
|
__all__ = ['Scanner', 'ScannerError']
|
||||||
|
|
||||||
|
from .error import MarkedError
|
||||||
|
from .tokens import * # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class ScannerError(MarkedError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __builtin__ import unicode
|
||||||
|
except ImportError:
|
||||||
|
unicode = str # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleKey:
|
||||||
|
# See below simple keys treatment.
|
||||||
|
def __init__(self, token_number, index, line, column, mark):
|
||||||
|
self.token_number = token_number
|
||||||
|
self.index = index
|
||||||
|
self.line = line
|
||||||
|
self.column = column
|
||||||
|
self.mark = mark
|
||||||
|
|
||||||
|
|
||||||
|
class Scanner:
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the scanner."""
|
||||||
|
# It is assumed that Scanner and Reader will have a common descendant.
|
||||||
|
# Reader do the dirty work of checking for BOM and converting the
|
||||||
|
# input data to Unicode. It also adds NUL to the end.
|
||||||
|
#
|
||||||
|
# Reader supports the following methods
|
||||||
|
# self.peek(i=0) # peek the next i-th character
|
||||||
|
# self.prefix(l=1) # peek the next l characters
|
||||||
|
# self.forward(l=1) # read the next l characters and move the pointer.
|
||||||
|
|
||||||
|
# Had we reached the end of the stream?
|
||||||
|
self.done = False
|
||||||
|
|
||||||
|
# The number of unclosed '{' and '['. `flow_level == 0` means block
|
||||||
|
# context.
|
||||||
|
self.flow_level = 0
|
||||||
|
|
||||||
|
# List of processed tokens that are not yet emitted.
|
||||||
|
self.tokens = []
|
||||||
|
|
||||||
|
# Add the STREAM-START token.
|
||||||
|
self.fetch_stream_start()
|
||||||
|
|
||||||
|
# Number of tokens that were emitted through the `get_token` method.
|
||||||
|
self.tokens_taken = 0
|
||||||
|
|
||||||
|
# Variables related to simple keys treatment.
|
||||||
|
|
||||||
|
# A simple key is a key that is not denoted by the '?' indicator.
|
||||||
|
# We emit the KEY token before all keys, so when we find a potential
|
||||||
|
# simple key, we try to locate the corresponding ':' indicator.
|
||||||
|
# Simple keys should be limited to a single line.
|
||||||
|
|
||||||
|
# Can a simple key start at the current position? A simple key may
|
||||||
|
# start:
|
||||||
|
# - after '{', '[', ',' (in the flow context),
|
||||||
|
self.allow_simple_key = False
|
||||||
|
|
||||||
|
# Keep track of possible simple keys. This is a dictionary. The key
|
||||||
|
# is `flow_level`; there can be no more that one possible simple key
|
||||||
|
# for each level. The value is a SimpleKey record:
|
||||||
|
# (token_number, index, line, column, mark)
|
||||||
|
# A simple key may start with SCALAR(flow), '[', or '{' tokens.
|
||||||
|
self.possible_simple_keys = {}
|
||||||
|
|
||||||
|
# Public methods.
|
||||||
|
|
||||||
|
def check_token(self, *choices):
|
||||||
|
# Check if the next token is one of the given types.
|
||||||
|
while self.need_more_tokens():
|
||||||
|
self.fetch_more_tokens()
|
||||||
|
if self.tokens:
|
||||||
|
if not choices:
|
||||||
|
return True
|
||||||
|
for choice in choices:
|
||||||
|
if isinstance(self.tokens[0], choice):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def peek_token(self):
|
||||||
|
# Return the next token, but do not delete if from the queue.
|
||||||
|
while self.need_more_tokens():
|
||||||
|
self.fetch_more_tokens()
|
||||||
|
if self.tokens:
|
||||||
|
return self.tokens[0]
|
||||||
|
|
||||||
|
def get_token(self):
|
||||||
|
# Return the next token.
|
||||||
|
while self.need_more_tokens():
|
||||||
|
self.fetch_more_tokens()
|
||||||
|
if self.tokens:
|
||||||
|
self.tokens_taken += 1
|
||||||
|
return self.tokens.pop(0)
|
||||||
|
|
||||||
|
# Private methods.
|
||||||
|
|
||||||
|
def need_more_tokens(self):
|
||||||
|
if self.done:
|
||||||
|
return False
|
||||||
|
if not self.tokens:
|
||||||
|
return True
|
||||||
|
# The current token may be a potential simple key, so we
|
||||||
|
# need to look further.
|
||||||
|
self.stale_possible_simple_keys()
|
||||||
|
if self.next_possible_simple_key() == self.tokens_taken:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def fetch_more_tokens(self):
|
||||||
|
|
||||||
|
# Eat whitespaces and comments until we reach the next token.
|
||||||
|
self.scan_to_next_token()
|
||||||
|
|
||||||
|
# Remove obsolete possible simple keys.
|
||||||
|
self.stale_possible_simple_keys()
|
||||||
|
|
||||||
|
# Peek the next character.
|
||||||
|
ch = self.peek()
|
||||||
|
|
||||||
|
# Is it the end of stream?
|
||||||
|
if ch == '\0':
|
||||||
|
return self.fetch_stream_end()
|
||||||
|
|
||||||
|
# Note: the order of the following checks is NOT significant.
|
||||||
|
|
||||||
|
# Is it the flow sequence start indicator?
|
||||||
|
if ch == '[':
|
||||||
|
return self.fetch_flow_sequence_start()
|
||||||
|
|
||||||
|
# Is it the flow mapping start indicator?
|
||||||
|
if ch == '{':
|
||||||
|
return self.fetch_flow_mapping_start()
|
||||||
|
|
||||||
|
# Is it the flow sequence end indicator?
|
||||||
|
if ch == ']':
|
||||||
|
return self.fetch_flow_sequence_end()
|
||||||
|
|
||||||
|
# Is it the flow mapping end indicator?
|
||||||
|
if ch == '}':
|
||||||
|
return self.fetch_flow_mapping_end()
|
||||||
|
|
||||||
|
# Is it the flow entry indicator?
|
||||||
|
if ch == ',':
|
||||||
|
return self.fetch_flow_entry()
|
||||||
|
|
||||||
|
# Is it the value indicator?
|
||||||
|
if ch == ':' and self.flow_level:
|
||||||
|
return self.fetch_value()
|
||||||
|
|
||||||
|
# Is it a double quoted scalar?
|
||||||
|
if ch == '\"':
|
||||||
|
return self.fetch_double()
|
||||||
|
|
||||||
|
# It must be a plain scalar then.
|
||||||
|
if self.check_plain():
|
||||||
|
return self.fetch_plain()
|
||||||
|
|
||||||
|
# No? It's an error. Let's produce a nice error message.
|
||||||
|
raise ScannerError("while scanning for the next token", None,
|
||||||
|
"found character %r that cannot start any token" % ch,
|
||||||
|
self.get_mark())
|
||||||
|
|
||||||
|
# Simple keys treatment.
|
||||||
|
|
||||||
|
def next_possible_simple_key(self):
|
||||||
|
# Return the number of the nearest possible simple key. Actually we
|
||||||
|
# don't need to loop through the whole dictionary. We may replace it
|
||||||
|
# with the following code:
|
||||||
|
# if not self.possible_simple_keys:
|
||||||
|
# return None
|
||||||
|
# return self.possible_simple_keys[
|
||||||
|
# min(self.possible_simple_keys.keys())].token_number
|
||||||
|
min_token_number = None
|
||||||
|
for level in self.possible_simple_keys:
|
||||||
|
key = self.possible_simple_keys[level]
|
||||||
|
if min_token_number is None or key.token_number < min_token_number:
|
||||||
|
min_token_number = key.token_number
|
||||||
|
return min_token_number
|
||||||
|
|
||||||
|
def stale_possible_simple_keys(self):
|
||||||
|
# Remove entries that are no longer possible simple keys. According to
|
||||||
|
# the YAML specification, simple keys
|
||||||
|
# - should be limited to a single line,
|
||||||
|
# Disabling this procedure will allow simple keys of any length and
|
||||||
|
# height (may cause problems if indentation is broken though).
|
||||||
|
for level in list(self.possible_simple_keys):
|
||||||
|
key = self.possible_simple_keys[level]
|
||||||
|
if key.line != self.line:
|
||||||
|
del self.possible_simple_keys[level]
|
||||||
|
|
||||||
|
def save_possible_simple_key(self):
|
||||||
|
# The next token may start a simple key. We check if it's possible
|
||||||
|
# and save its position. This function is called for
|
||||||
|
# SCALAR(flow), '[', and '{'.
|
||||||
|
|
||||||
|
# The next token might be a simple key. Let's save it's number and
|
||||||
|
# position.
|
||||||
|
if self.allow_simple_key:
|
||||||
|
self.remove_possible_simple_key()
|
||||||
|
token_number = self.tokens_taken + len(self.tokens)
|
||||||
|
key = SimpleKey(token_number,
|
||||||
|
self.index, self.line, self.column, self.get_mark())
|
||||||
|
self.possible_simple_keys[self.flow_level] = key
|
||||||
|
|
||||||
|
def remove_possible_simple_key(self):
|
||||||
|
# Remove the saved possible key position at the current flow level.
|
||||||
|
if self.flow_level in self.possible_simple_keys:
|
||||||
|
del self.possible_simple_keys[self.flow_level]
|
||||||
|
|
||||||
|
# Fetchers.
|
||||||
|
|
||||||
|
def fetch_stream_start(self):
|
||||||
|
# We always add STREAM-START as the first token and STREAM-END as the
|
||||||
|
# last token.
|
||||||
|
|
||||||
|
# Read the token.
|
||||||
|
mark = self.get_mark()
|
||||||
|
|
||||||
|
# Add STREAM-START.
|
||||||
|
self.tokens.append(StreamStartToken(mark, mark,
|
||||||
|
encoding=self.encoding))
|
||||||
|
|
||||||
|
def fetch_stream_end(self):
|
||||||
|
# Reset simple keys.
|
||||||
|
self.remove_possible_simple_key()
|
||||||
|
self.allow_simple_key = False
|
||||||
|
self.possible_simple_keys = {}
|
||||||
|
|
||||||
|
# Read the token.
|
||||||
|
mark = self.get_mark()
|
||||||
|
|
||||||
|
# Add STREAM-END.
|
||||||
|
self.tokens.append(StreamEndToken(mark, mark))
|
||||||
|
|
||||||
|
# The steam is finished.
|
||||||
|
self.done = True
|
||||||
|
|
||||||
|
def fetch_flow_sequence_start(self):
|
||||||
|
self.fetch_flow_collection_start(FlowSequenceStartToken)
|
||||||
|
|
||||||
|
def fetch_flow_mapping_start(self):
|
||||||
|
self.fetch_flow_collection_start(FlowMappingStartToken)
|
||||||
|
|
||||||
|
def fetch_flow_collection_start(self, TokenClass):
|
||||||
|
|
||||||
|
# '[' and '{' may start a simple key.
|
||||||
|
self.save_possible_simple_key()
|
||||||
|
|
||||||
|
# Increase the flow level.
|
||||||
|
self.flow_level += 1
|
||||||
|
|
||||||
|
# Simple keys are allowed after '[' and '{'.
|
||||||
|
self.allow_simple_key = True
|
||||||
|
|
||||||
|
# Add FLOW-SEQUENCE-START or FLOW-MAPPING-START.
|
||||||
|
start_mark = self.get_mark()
|
||||||
|
self.forward()
|
||||||
|
end_mark = self.get_mark()
|
||||||
|
self.tokens.append(TokenClass(start_mark, end_mark))
|
||||||
|
|
||||||
|
def fetch_flow_sequence_end(self):
|
||||||
|
self.fetch_flow_collection_end(FlowSequenceEndToken)
|
||||||
|
|
||||||
|
def fetch_flow_mapping_end(self):
|
||||||
|
self.fetch_flow_collection_end(FlowMappingEndToken)
|
||||||
|
|
||||||
|
def fetch_flow_collection_end(self, TokenClass):
|
||||||
|
|
||||||
|
# Reset possible simple key on the current level.
|
||||||
|
self.remove_possible_simple_key()
|
||||||
|
|
||||||
|
# Decrease the flow level.
|
||||||
|
self.flow_level -= 1
|
||||||
|
|
||||||
|
# No simple keys after ']' or '}'.
|
||||||
|
self.allow_simple_key = False
|
||||||
|
|
||||||
|
# Add FLOW-SEQUENCE-END or FLOW-MAPPING-END.
|
||||||
|
start_mark = self.get_mark()
|
||||||
|
self.forward()
|
||||||
|
end_mark = self.get_mark()
|
||||||
|
self.tokens.append(TokenClass(start_mark, end_mark))
|
||||||
|
|
||||||
|
def fetch_value(self):
|
||||||
|
# Do we determine a simple key?
|
||||||
|
if self.flow_level in self.possible_simple_keys:
|
||||||
|
|
||||||
|
# Add KEY.
|
||||||
|
key = self.possible_simple_keys[self.flow_level]
|
||||||
|
del self.possible_simple_keys[self.flow_level]
|
||||||
|
self.tokens.insert(key.token_number - self.tokens_taken,
|
||||||
|
KeyToken(key.mark, key.mark))
|
||||||
|
|
||||||
|
# There cannot be two simple keys one after another.
|
||||||
|
self.allow_simple_key = False
|
||||||
|
|
||||||
|
# Add VALUE.
|
||||||
|
start_mark = self.get_mark()
|
||||||
|
self.forward()
|
||||||
|
end_mark = self.get_mark()
|
||||||
|
self.tokens.append(ValueToken(start_mark, end_mark))
|
||||||
|
|
||||||
|
def fetch_flow_entry(self):
|
||||||
|
|
||||||
|
# Simple keys are allowed after ','.
|
||||||
|
self.allow_simple_key = True
|
||||||
|
|
||||||
|
# Reset possible simple key on the current level.
|
||||||
|
self.remove_possible_simple_key()
|
||||||
|
|
||||||
|
# Add FLOW-ENTRY.
|
||||||
|
start_mark = self.get_mark()
|
||||||
|
self.forward()
|
||||||
|
end_mark = self.get_mark()
|
||||||
|
self.tokens.append(FlowEntryToken(start_mark, end_mark))
|
||||||
|
|
||||||
|
def fetch_double(self):
|
||||||
|
# A flow scalar could be a simple key.
|
||||||
|
self.save_possible_simple_key()
|
||||||
|
|
||||||
|
# No simple keys after flow scalars.
|
||||||
|
self.allow_simple_key = False
|
||||||
|
|
||||||
|
# Scan and add SCALAR.
|
||||||
|
self.tokens.append(self.scan_flow_scalar())
|
||||||
|
|
||||||
|
def fetch_plain(self):
|
||||||
|
|
||||||
|
self.save_possible_simple_key()
|
||||||
|
|
||||||
|
# No simple keys after plain scalars.
|
||||||
|
self.allow_simple_key = False
|
||||||
|
|
||||||
|
# Scan and add SCALAR. May change `allow_simple_key`.
|
||||||
|
self.tokens.append(self.scan_plain())
|
||||||
|
|
||||||
|
# Checkers.
|
||||||
|
|
||||||
|
def check_plain(self):
|
||||||
|
return self.peek() in '0123456789-ntf'
|
||||||
|
|
||||||
|
# Scanners.
|
||||||
|
|
||||||
|
def scan_to_next_token(self):
|
||||||
|
while self.peek() in ' \t\n':
|
||||||
|
self.forward()
|
||||||
|
|
||||||
|
def scan_flow_scalar(self):
|
||||||
|
# See the specification for details.
|
||||||
|
# Note that we loose indentation rules for quoted scalars. Quoted
|
||||||
|
# scalars don't need to adhere indentation because " and ' clearly
|
||||||
|
# mark the beginning and the end of them. Therefore we are less
|
||||||
|
# restrictive then the specification requires. We only need to check
|
||||||
|
# that document separators are not included in scalars.
|
||||||
|
chunks = []
|
||||||
|
start_mark = self.get_mark()
|
||||||
|
quote = self.peek()
|
||||||
|
self.forward()
|
||||||
|
chunks.extend(self.scan_flow_scalar_non_spaces(start_mark))
|
||||||
|
while self.peek() != quote:
|
||||||
|
chunks.extend(self.scan_flow_scalar_spaces(start_mark))
|
||||||
|
chunks.extend(self.scan_flow_scalar_non_spaces(start_mark))
|
||||||
|
self.forward()
|
||||||
|
end_mark = self.get_mark()
|
||||||
|
return ScalarToken(unicode().join(chunks), False, start_mark, end_mark, '"')
|
||||||
|
|
||||||
|
ESCAPE_REPLACEMENTS = {
|
||||||
|
'b': '\x08',
|
||||||
|
't': '\x09',
|
||||||
|
'n': '\x0A',
|
||||||
|
'f': '\x0C',
|
||||||
|
'r': '\x0D',
|
||||||
|
'\"': '\"',
|
||||||
|
'\\': '\\',
|
||||||
|
}
|
||||||
|
|
||||||
|
ESCAPE_CODES = {
|
||||||
|
'u': 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
def scan_flow_scalar_non_spaces(self, start_mark):
|
||||||
|
# See the specification for details.
|
||||||
|
chunks = []
|
||||||
|
while True:
|
||||||
|
length = 0
|
||||||
|
while self.peek(length) not in '\"\\\0 \t\n':
|
||||||
|
length += 1
|
||||||
|
if length:
|
||||||
|
chunks.append(self.prefix(length))
|
||||||
|
self.forward(length)
|
||||||
|
ch = self.peek()
|
||||||
|
if ch == '\\':
|
||||||
|
self.forward()
|
||||||
|
ch = self.peek()
|
||||||
|
if ch in self.ESCAPE_REPLACEMENTS:
|
||||||
|
chunks.append(self.ESCAPE_REPLACEMENTS[ch])
|
||||||
|
self.forward()
|
||||||
|
elif ch in self.ESCAPE_CODES:
|
||||||
|
length = self.ESCAPE_CODES[ch]
|
||||||
|
self.forward()
|
||||||
|
for k in range(length):
|
||||||
|
if self.peek(k) not in '0123456789ABCDEFabcdef':
|
||||||
|
raise ScannerError("while scanning a double-quoted scalar", start_mark,
|
||||||
|
"expected escape sequence of %d hexdecimal numbers, but found %r" %
|
||||||
|
(length, self.peek(k)), self.get_mark())
|
||||||
|
code = int(self.prefix(length), 16)
|
||||||
|
chunks.append(chr(code))
|
||||||
|
self.forward(length)
|
||||||
|
else:
|
||||||
|
raise ScannerError("while scanning a double-quoted scalar", start_mark,
|
||||||
|
"found unknown escape character %r" % ch, self.get_mark())
|
||||||
|
else:
|
||||||
|
return chunks
|
||||||
|
|
||||||
|
def scan_flow_scalar_spaces(self, start_mark):
|
||||||
|
# See the specification for details.
|
||||||
|
chunks = []
|
||||||
|
length = 0
|
||||||
|
while self.peek(length) in ' \t':
|
||||||
|
length += 1
|
||||||
|
whitespaces = self.prefix(length)
|
||||||
|
self.forward(length)
|
||||||
|
ch = self.peek()
|
||||||
|
if ch == '\0':
|
||||||
|
raise ScannerError("while scanning a quoted scalar", start_mark,
|
||||||
|
"found unexpected end of stream", self.get_mark())
|
||||||
|
elif ch == '\n':
|
||||||
|
raise ScannerError("while scanning a quoted scalar", start_mark,
|
||||||
|
"found unexpected line end", self.get_mark())
|
||||||
|
else:
|
||||||
|
chunks.append(whitespaces)
|
||||||
|
return chunks
|
||||||
|
|
||||||
|
def scan_plain(self):
|
||||||
|
chunks = []
|
||||||
|
start_mark = self.get_mark()
|
||||||
|
spaces = []
|
||||||
|
while True:
|
||||||
|
length = 0
|
||||||
|
while True:
|
||||||
|
if self.peek(length) not in 'eE.0123456789nul-tr+fas':
|
||||||
|
break
|
||||||
|
length += 1
|
||||||
|
if length == 0:
|
||||||
|
break
|
||||||
|
self.allow_simple_key = False
|
||||||
|
chunks.extend(spaces)
|
||||||
|
chunks.append(self.prefix(length))
|
||||||
|
self.forward(length)
|
||||||
|
end_mark = self.get_mark()
|
||||||
|
return ScalarToken(''.join(chunks), True, start_mark, end_mark)
|
|
@ -0,0 +1,65 @@
|
||||||
|
class Token(object):
|
||||||
|
def __init__(self, start_mark, end_mark):
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
attributes = [key for key in self.__dict__
|
||||||
|
if not key.endswith('_mark')]
|
||||||
|
attributes.sort()
|
||||||
|
arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
|
||||||
|
for key in attributes])
|
||||||
|
return '%s(%s)' % (self.__class__.__name__, arguments)
|
||||||
|
|
||||||
|
|
||||||
|
class StreamStartToken(Token):
|
||||||
|
id = '<stream start>'
|
||||||
|
|
||||||
|
def __init__(self, start_mark=None, end_mark=None,
|
||||||
|
encoding=None):
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.encoding = encoding
|
||||||
|
|
||||||
|
|
||||||
|
class StreamEndToken(Token):
|
||||||
|
id = '<stream end>'
|
||||||
|
|
||||||
|
|
||||||
|
class FlowSequenceStartToken(Token):
|
||||||
|
id = '['
|
||||||
|
|
||||||
|
|
||||||
|
class FlowMappingStartToken(Token):
|
||||||
|
id = '{'
|
||||||
|
|
||||||
|
|
||||||
|
class FlowSequenceEndToken(Token):
|
||||||
|
id = ']'
|
||||||
|
|
||||||
|
|
||||||
|
class FlowMappingEndToken(Token):
|
||||||
|
id = '}'
|
||||||
|
|
||||||
|
|
||||||
|
class KeyToken(Token):
|
||||||
|
id = '?'
|
||||||
|
|
||||||
|
|
||||||
|
class ValueToken(Token):
|
||||||
|
id = ':'
|
||||||
|
|
||||||
|
|
||||||
|
class FlowEntryToken(Token):
|
||||||
|
id = ','
|
||||||
|
|
||||||
|
|
||||||
|
class ScalarToken(Token):
|
||||||
|
id = '<scalar>'
|
||||||
|
|
||||||
|
def __init__(self, value, plain, start_mark, end_mark, style=None):
|
||||||
|
self.value = value
|
||||||
|
self.plain = plain
|
||||||
|
self.start_mark = start_mark
|
||||||
|
self.end_mark = end_mark
|
||||||
|
self.style = style
|
|
@ -0,0 +1,19 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def gen_matcher_getter(ext, import_paths):
|
||||||
|
def get(match_name):
|
||||||
|
match_module, separator, match_function = match_name.rpartition('.')
|
||||||
|
if not separator:
|
||||||
|
match_module = 'powerline.matchers.{0}'.format(ext)
|
||||||
|
match_function = match_name
|
||||||
|
oldpath = sys.path
|
||||||
|
sys.path = import_paths + sys.path
|
||||||
|
try:
|
||||||
|
return getattr(__import__(match_module, fromlist=[match_function]), match_function)
|
||||||
|
finally:
|
||||||
|
sys.path = oldpath
|
||||||
|
return get
|
|
@ -0,0 +1,19 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import os
|
||||||
|
from powerline.bindings.vim import getbufvar
|
||||||
|
|
||||||
|
|
||||||
|
def help(matcher_info):
|
||||||
|
return str(getbufvar(matcher_info['bufnr'], '&buftype')) == 'help'
|
||||||
|
|
||||||
|
|
||||||
|
def cmdwin(matcher_info):
|
||||||
|
name = matcher_info['buffer'].name
|
||||||
|
return name and os.path.basename(name) == '[Command Line]'
|
||||||
|
|
||||||
|
|
||||||
|
def quickfix(matcher_info):
|
||||||
|
return str(getbufvar(matcher_info['bufnr'], '&buftype')) == 'quickfix'
|
319
common/.local/lib/python2.7/site-packages/powerline/renderer.py
Normal file
319
common/.local/lib/python2.7/site-packages/powerline/renderer.py
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.theme import Theme
|
||||||
|
from unicodedata import east_asian_width, combining
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
NBSP = unicode(' ', 'utf-8')
|
||||||
|
except NameError:
|
||||||
|
NBSP = ' '
|
||||||
|
|
||||||
|
|
||||||
|
def construct_returned_value(rendered_highlighted, segments, output_raw):
|
||||||
|
if output_raw:
|
||||||
|
return rendered_highlighted, ''.join((segment['_rendered_raw'] for segment in segments))
|
||||||
|
else:
|
||||||
|
return rendered_highlighted
|
||||||
|
|
||||||
|
|
||||||
|
class Renderer(object):
|
||||||
|
'''Object that is responsible for generating the highlighted string.
|
||||||
|
|
||||||
|
:param dict theme_config:
|
||||||
|
Main theme configuration.
|
||||||
|
:param local_themes:
|
||||||
|
Local themes. Is to be used by subclasses from ``.get_theme()`` method,
|
||||||
|
base class only records this parameter to a ``.local_themes`` attribute.
|
||||||
|
:param dict theme_kwargs:
|
||||||
|
Keyword arguments for ``Theme`` class constructor.
|
||||||
|
:param Colorscheme colorscheme:
|
||||||
|
Colorscheme object that holds colors configuration.
|
||||||
|
:param PowerlineLogger pl:
|
||||||
|
Object used for logging.
|
||||||
|
:param int ambiwidth:
|
||||||
|
Width of the characters with east asian width unicode attribute equal to
|
||||||
|
``A`` (Ambigious).
|
||||||
|
:param dict options:
|
||||||
|
Various options. Are normally not used by base renderer, but all options
|
||||||
|
are recorded as attributes.
|
||||||
|
'''
|
||||||
|
|
||||||
|
segment_info = {
|
||||||
|
'environ': os.environ,
|
||||||
|
'getcwd': getattr(os, 'getcwdu', os.getcwd),
|
||||||
|
'home': os.environ.get('HOME'),
|
||||||
|
}
|
||||||
|
'''Basic segment info. Is merged with local segment information by
|
||||||
|
``.get_segment_info()`` method. Keys:
|
||||||
|
|
||||||
|
``environ``
|
||||||
|
Object containing environment variables. Must define at least the
|
||||||
|
following methods: ``.__getitem__(var)`` that raises ``KeyError`` in
|
||||||
|
case requested environment variable is not present, ``.get(var,
|
||||||
|
default=None)`` that works like ``dict.get`` and be able to be passed to
|
||||||
|
``Popen``.
|
||||||
|
|
||||||
|
``getcwd``
|
||||||
|
Function that returns current working directory. Will be called without
|
||||||
|
any arguments, should return ``unicode`` or (in python-2) regular
|
||||||
|
string.
|
||||||
|
|
||||||
|
``home``
|
||||||
|
String containing path to home directory. Should be ``unicode`` or (in
|
||||||
|
python-2) regular string or ``None``.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
theme_config,
|
||||||
|
local_themes,
|
||||||
|
theme_kwargs,
|
||||||
|
colorscheme,
|
||||||
|
pl,
|
||||||
|
ambiwidth=1,
|
||||||
|
**options):
|
||||||
|
self.__dict__.update(options)
|
||||||
|
self.theme_config = theme_config
|
||||||
|
theme_kwargs['pl'] = pl
|
||||||
|
self.pl = pl
|
||||||
|
self.theme = Theme(theme_config=theme_config, **theme_kwargs)
|
||||||
|
self.local_themes = local_themes
|
||||||
|
self.theme_kwargs = theme_kwargs
|
||||||
|
self.colorscheme = colorscheme
|
||||||
|
self.width_data = {
|
||||||
|
'N': 1, # Neutral
|
||||||
|
'Na': 1, # Narrow
|
||||||
|
'A': ambiwidth, # Ambigious
|
||||||
|
'H': 1, # Half-width
|
||||||
|
'W': 2, # Wide
|
||||||
|
'F': 2, # Fullwidth
|
||||||
|
}
|
||||||
|
|
||||||
|
def strwidth(self, string):
|
||||||
|
'''Function that returns string width.
|
||||||
|
|
||||||
|
Is used to calculate the place given string occupies when handling
|
||||||
|
``width`` argument to ``.render()`` method. Must take east asian width
|
||||||
|
into account.
|
||||||
|
|
||||||
|
:param unicode string:
|
||||||
|
String whose width will be calculated.
|
||||||
|
|
||||||
|
:return: unsigned integer.
|
||||||
|
'''
|
||||||
|
return sum((0 if combining(symbol) else self.width_data[east_asian_width(symbol)] for symbol in string))
|
||||||
|
|
||||||
|
def get_theme(self, matcher_info):
|
||||||
|
'''Get Theme object.
|
||||||
|
|
||||||
|
Is to be overridden by subclasses to support local themes, this variant
|
||||||
|
only returns ``.theme`` attribute.
|
||||||
|
|
||||||
|
:param matcher_info:
|
||||||
|
Parameter ``matcher_info`` that ``.render()`` method received.
|
||||||
|
Unused.
|
||||||
|
'''
|
||||||
|
return self.theme
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
'''Prepare for interpreter shutdown. The only job it is supposed to do
|
||||||
|
is calling ``.shutdown()`` method for all theme objects. Should be
|
||||||
|
overridden by subclasses in case they support local themes.
|
||||||
|
'''
|
||||||
|
self.theme.shutdown()
|
||||||
|
|
||||||
|
def _get_highlighting(self, segment, mode):
|
||||||
|
segment['highlight'] = self.colorscheme.get_highlighting(segment['highlight_group'], mode, segment.get('gradient_level'))
|
||||||
|
if segment['divider_highlight_group']:
|
||||||
|
segment['divider_highlight'] = self.colorscheme.get_highlighting(segment['divider_highlight_group'], mode)
|
||||||
|
else:
|
||||||
|
segment['divider_highlight'] = None
|
||||||
|
return segment
|
||||||
|
|
||||||
|
def get_segment_info(self, segment_info):
|
||||||
|
'''Get segment information.
|
||||||
|
|
||||||
|
Must return a dictionary containing at least ``home``, ``environ`` and
|
||||||
|
``getcwd`` keys (see documentation for ``segment_info`` attribute). This
|
||||||
|
implementation merges ``segment_info`` dictionary passed to
|
||||||
|
``.render()`` method with ``.segment_info`` attribute, preferring keys
|
||||||
|
from the former. It also replaces ``getcwd`` key with function returning
|
||||||
|
``segment_info['environ']['PWD']`` in case ``PWD`` variable is
|
||||||
|
available.
|
||||||
|
|
||||||
|
:param dict segment_info:
|
||||||
|
Segment information that was passed to ``.render()`` method.
|
||||||
|
|
||||||
|
:return: dict with segment information.
|
||||||
|
'''
|
||||||
|
r = self.segment_info.copy()
|
||||||
|
if segment_info:
|
||||||
|
r.update(segment_info)
|
||||||
|
if 'PWD' in r['environ']:
|
||||||
|
r['getcwd'] = lambda: r['environ']['PWD']
|
||||||
|
return r
|
||||||
|
|
||||||
|
def render(self, mode=None, width=None, side=None, output_raw=False, segment_info=None, matcher_info=None):
|
||||||
|
'''Render all segments.
|
||||||
|
|
||||||
|
When a width is provided, low-priority segments are dropped one at
|
||||||
|
a time until the line is shorter than the width, or only segments
|
||||||
|
with a negative priority are left. If one or more filler segments are
|
||||||
|
provided they will fill the remaining space until the desired width is
|
||||||
|
reached.
|
||||||
|
|
||||||
|
:param str mode:
|
||||||
|
Mode string. Affects contents (colors and the set of segments) of
|
||||||
|
rendered string.
|
||||||
|
:param int width:
|
||||||
|
Maximum width text can occupy. May be exceeded if there are too much
|
||||||
|
non-removable segments.
|
||||||
|
:param str side:
|
||||||
|
One of ``left``, ``right``. Determines which side will be rendered.
|
||||||
|
If not present all sides are rendered.
|
||||||
|
:param bool output_raw:
|
||||||
|
Changes the output: if this parameter is ``True`` then in place of
|
||||||
|
one string this method outputs a pair ``(colored_string,
|
||||||
|
colorless_string)``.
|
||||||
|
:param dict segment_info:
|
||||||
|
Segment information. See also ``.get_segment_info()`` method.
|
||||||
|
:param matcher_info:
|
||||||
|
Matcher information. Is processed in ``.get_theme()`` method.
|
||||||
|
'''
|
||||||
|
theme = self.get_theme(matcher_info)
|
||||||
|
segments = theme.get_segments(side, self.get_segment_info(segment_info))
|
||||||
|
|
||||||
|
# Handle excluded/included segments for the current mode
|
||||||
|
segments = [self._get_highlighting(segment, mode) for segment in segments
|
||||||
|
if mode not in segment['exclude_modes'] or (segment['include_modes'] and segment in segment['include_modes'])]
|
||||||
|
|
||||||
|
segments = [segment for segment in self._render_segments(theme, segments)]
|
||||||
|
|
||||||
|
if not width:
|
||||||
|
# No width specified, so we don't need to crop or pad anything
|
||||||
|
return construct_returned_value(''.join([segment['_rendered_hl'] for segment in segments]) + self.hlstyle(), segments, output_raw)
|
||||||
|
|
||||||
|
# Create an ordered list of segments that can be dropped
|
||||||
|
segments_priority = sorted((segment for segment in segments if segment['priority'] is not None), key=lambda segment: segment['priority'], reverse=True)
|
||||||
|
while sum([segment['_len'] for segment in segments]) > width and len(segments_priority):
|
||||||
|
segments.remove(segments_priority[0])
|
||||||
|
segments_priority.pop(0)
|
||||||
|
|
||||||
|
# Distribute the remaining space on spacer segments
|
||||||
|
segments_spacers = [segment for segment in segments if segment['width'] == 'auto']
|
||||||
|
if segments_spacers:
|
||||||
|
distribute_len, distribute_len_remainder = divmod(width - sum([segment['_len'] for segment in segments]), len(segments_spacers))
|
||||||
|
for segment in segments_spacers:
|
||||||
|
if segment['align'] == 'l':
|
||||||
|
segment['_space_right'] += distribute_len
|
||||||
|
elif segment['align'] == 'r':
|
||||||
|
segment['_space_left'] += distribute_len
|
||||||
|
elif segment['align'] == 'c':
|
||||||
|
space_side, space_side_remainder = divmod(distribute_len, 2)
|
||||||
|
segment['_space_left'] += space_side + space_side_remainder
|
||||||
|
segment['_space_right'] += space_side
|
||||||
|
segments_spacers[0]['_space_right'] += distribute_len_remainder
|
||||||
|
|
||||||
|
rendered_highlighted = ''.join([segment['_rendered_hl'] for segment in self._render_segments(theme, segments)]) + self.hlstyle()
|
||||||
|
|
||||||
|
return construct_returned_value(rendered_highlighted, segments, output_raw)
|
||||||
|
|
||||||
|
def _render_segments(self, theme, segments, render_highlighted=True):
|
||||||
|
'''Internal segment rendering method.
|
||||||
|
|
||||||
|
This method loops through the segment array and compares the
|
||||||
|
foreground/background colors and divider properties and returns the
|
||||||
|
rendered statusline as a string.
|
||||||
|
|
||||||
|
The method always renders the raw segment contents (i.e. without
|
||||||
|
highlighting strings added), and only renders the highlighted
|
||||||
|
statusline if render_highlighted is True.
|
||||||
|
'''
|
||||||
|
segments_len = len(segments)
|
||||||
|
|
||||||
|
for index, segment in enumerate(segments):
|
||||||
|
segment['_rendered_raw'] = ''
|
||||||
|
segment['_rendered_hl'] = ''
|
||||||
|
|
||||||
|
prev_segment = segments[index - 1] if index > 0 else theme.EMPTY_SEGMENT
|
||||||
|
next_segment = segments[index + 1] if index < segments_len - 1 else theme.EMPTY_SEGMENT
|
||||||
|
compare_segment = next_segment if segment['side'] == 'left' else prev_segment
|
||||||
|
outer_padding = ' ' if (index == 0 and segment['side'] == 'left') or (index == segments_len - 1 and segment['side'] == 'right') else ''
|
||||||
|
divider_type = 'soft' if compare_segment['highlight']['bg'] == segment['highlight']['bg'] else 'hard'
|
||||||
|
|
||||||
|
divider_raw = theme.get_divider(segment['side'], divider_type)
|
||||||
|
divider_spaces = theme.get_spaces()
|
||||||
|
divider_highlighted = ''
|
||||||
|
contents_raw = segment['contents']
|
||||||
|
contents_highlighted = ''
|
||||||
|
draw_divider = segment['draw_' + divider_type + '_divider']
|
||||||
|
|
||||||
|
# Pad segments first
|
||||||
|
if draw_divider:
|
||||||
|
if segment['side'] == 'left':
|
||||||
|
contents_raw = outer_padding + (segment['_space_left'] * ' ') + contents_raw + ((divider_spaces + segment['_space_right']) * ' ')
|
||||||
|
else:
|
||||||
|
contents_raw = ((divider_spaces + segment['_space_left']) * ' ') + contents_raw + (segment['_space_right'] * ' ') + outer_padding
|
||||||
|
else:
|
||||||
|
if segment['side'] == 'left':
|
||||||
|
contents_raw = outer_padding + (segment['_space_left'] * ' ') + contents_raw + (segment['_space_right'] * ' ')
|
||||||
|
else:
|
||||||
|
contents_raw = (segment['_space_left'] * ' ') + contents_raw + (segment['_space_right'] * ' ') + outer_padding
|
||||||
|
|
||||||
|
# Replace spaces with no-break spaces
|
||||||
|
contents_raw = contents_raw.replace(' ', NBSP)
|
||||||
|
divider_raw = divider_raw.replace(' ', NBSP)
|
||||||
|
|
||||||
|
# Apply highlighting to padded dividers and contents
|
||||||
|
if render_highlighted:
|
||||||
|
if divider_type == 'soft':
|
||||||
|
divider_highlight_group_key = 'highlight' if segment['divider_highlight_group'] is None else 'divider_highlight'
|
||||||
|
divider_fg = segment[divider_highlight_group_key]['fg']
|
||||||
|
divider_bg = segment[divider_highlight_group_key]['bg']
|
||||||
|
else:
|
||||||
|
divider_fg = segment['highlight']['bg']
|
||||||
|
divider_bg = compare_segment['highlight']['bg']
|
||||||
|
divider_highlighted = self.hl(divider_raw, divider_fg, divider_bg, False)
|
||||||
|
contents_highlighted = self.hl(self.escape(contents_raw), **segment['highlight'])
|
||||||
|
|
||||||
|
# Append padded raw and highlighted segments to the rendered segment variables
|
||||||
|
if draw_divider:
|
||||||
|
if segment['side'] == 'left':
|
||||||
|
segment['_rendered_raw'] += contents_raw + divider_raw
|
||||||
|
segment['_rendered_hl'] += contents_highlighted + divider_highlighted
|
||||||
|
else:
|
||||||
|
segment['_rendered_raw'] += divider_raw + contents_raw
|
||||||
|
segment['_rendered_hl'] += divider_highlighted + contents_highlighted
|
||||||
|
else:
|
||||||
|
if segment['side'] == 'left':
|
||||||
|
segment['_rendered_raw'] += contents_raw
|
||||||
|
segment['_rendered_hl'] += contents_highlighted
|
||||||
|
else:
|
||||||
|
segment['_rendered_raw'] += contents_raw
|
||||||
|
segment['_rendered_hl'] += contents_highlighted
|
||||||
|
segment['_len'] = self.strwidth(segment['_rendered_raw'])
|
||||||
|
yield segment
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def escape(string):
|
||||||
|
'''Method that escapes segment contents.
|
||||||
|
'''
|
||||||
|
return string
|
||||||
|
|
||||||
|
def hlstyle(fg=None, bg=None, attr=None):
|
||||||
|
'''Output highlight style string.
|
||||||
|
|
||||||
|
Assuming highlighted string looks like ``{style}{contents}`` this method
|
||||||
|
should output ``{style}``. If it is called without arguments this method
|
||||||
|
is supposed to reset style to its default.
|
||||||
|
'''
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def hl(self, contents, fg=None, bg=None, attr=None):
|
||||||
|
'''Output highlighted chunk.
|
||||||
|
|
||||||
|
This implementation just outputs ``.hlstyle()`` joined with
|
||||||
|
``contents``.
|
||||||
|
'''
|
||||||
|
return self.hlstyle(fg, bg, attr) + (contents or '')
|
|
@ -0,0 +1,16 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.renderers.shell import ShellRenderer
|
||||||
|
|
||||||
|
|
||||||
|
class BashPromptRenderer(ShellRenderer):
|
||||||
|
'''Powerline bash prompt segment renderer.'''
|
||||||
|
escape_hl_start = '\['
|
||||||
|
escape_hl_end = '\]'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def escape(string):
|
||||||
|
return string.replace('\\', '\\\\').replace('$', '\\$').replace('`', '\\`')
|
||||||
|
|
||||||
|
|
||||||
|
renderer = BashPromptRenderer
|
|
@ -0,0 +1,35 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.renderers.shell import ShellRenderer
|
||||||
|
from powerline.theme import Theme
|
||||||
|
|
||||||
|
|
||||||
|
class IpythonRenderer(ShellRenderer):
|
||||||
|
'''Powerline ipython segment renderer.'''
|
||||||
|
escape_hl_start = '\x01'
|
||||||
|
escape_hl_end = '\x02'
|
||||||
|
|
||||||
|
def get_segment_info(self, segment_info):
|
||||||
|
r = self.segment_info.copy()
|
||||||
|
r['ipython'] = segment_info
|
||||||
|
return r
|
||||||
|
|
||||||
|
def get_theme(self, matcher_info):
|
||||||
|
if matcher_info == 'in':
|
||||||
|
return self.theme
|
||||||
|
else:
|
||||||
|
match = self.local_themes[matcher_info]
|
||||||
|
try:
|
||||||
|
return match['theme']
|
||||||
|
except KeyError:
|
||||||
|
match['theme'] = Theme(theme_config=match['config'], top_theme_config=self.theme_config, **self.theme_kwargs)
|
||||||
|
return match['theme']
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.theme.shutdown()
|
||||||
|
for match in self.local_themes.values():
|
||||||
|
if 'theme' in match:
|
||||||
|
match['theme'].shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
renderer = IpythonRenderer
|
|
@ -0,0 +1,38 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.renderer import Renderer
|
||||||
|
from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
|
||||||
|
|
||||||
|
from xml.sax.saxutils import escape as _escape
|
||||||
|
|
||||||
|
|
||||||
|
class PangoMarkupRenderer(Renderer):
|
||||||
|
'''Powerline Pango markup segment renderer.'''
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hlstyle(*args, **kwargs):
|
||||||
|
# We don't need to explicitly reset attributes, so skip those calls
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def hl(self, contents, fg=None, bg=None, attr=None):
|
||||||
|
'''Highlight a segment.'''
|
||||||
|
awesome_attr = []
|
||||||
|
if fg is not None:
|
||||||
|
if fg is not False and fg[1] is not False:
|
||||||
|
awesome_attr += ['foreground="#{0:06x}"'.format(fg[1])]
|
||||||
|
if bg is not None:
|
||||||
|
if bg is not False and bg[1] is not False:
|
||||||
|
awesome_attr += ['background="#{0:06x}"'.format(bg[1])]
|
||||||
|
if attr is not None and attr is not False:
|
||||||
|
if attr & ATTR_BOLD:
|
||||||
|
awesome_attr += ['font_weight="bold"']
|
||||||
|
if attr & ATTR_ITALIC:
|
||||||
|
awesome_attr += ['font_style="italic"']
|
||||||
|
if attr & ATTR_UNDERLINE:
|
||||||
|
awesome_attr += ['underline="single"']
|
||||||
|
return '<span ' + ' '.join(awesome_attr) + '>' + contents + '</span>'
|
||||||
|
|
||||||
|
escape = staticmethod(_escape)
|
||||||
|
|
||||||
|
|
||||||
|
renderer = PangoMarkupRenderer
|
|
@ -0,0 +1,70 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.renderer import Renderer
|
||||||
|
from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
|
||||||
|
|
||||||
|
|
||||||
|
def int_to_rgb(num):
|
||||||
|
r = (num >> 16) & 0xff
|
||||||
|
g = (num >> 8) & 0xff
|
||||||
|
b = num & 0xff
|
||||||
|
return r, g, b
|
||||||
|
|
||||||
|
|
||||||
|
class ShellRenderer(Renderer):
|
||||||
|
'''Powerline shell segment renderer.'''
|
||||||
|
escape_hl_start = ''
|
||||||
|
escape_hl_end = ''
|
||||||
|
term_truecolor = False
|
||||||
|
tmux_escape = False
|
||||||
|
screen_escape = False
|
||||||
|
|
||||||
|
def hlstyle(self, fg=None, bg=None, attr=None):
|
||||||
|
'''Highlight a segment.
|
||||||
|
|
||||||
|
If an argument is None, the argument is ignored. If an argument is
|
||||||
|
False, the argument is reset to the terminal defaults. If an argument
|
||||||
|
is a valid color or attribute, it's added to the ANSI escape code.
|
||||||
|
'''
|
||||||
|
ansi = [0]
|
||||||
|
if fg is not None:
|
||||||
|
if fg is False or fg[0] is False:
|
||||||
|
ansi += [39]
|
||||||
|
else:
|
||||||
|
if self.term_truecolor:
|
||||||
|
ansi += [38, 2] + list(int_to_rgb(fg[1]))
|
||||||
|
else:
|
||||||
|
ansi += [38, 5, fg[0]]
|
||||||
|
if bg is not None:
|
||||||
|
if bg is False or bg[0] is False:
|
||||||
|
ansi += [49]
|
||||||
|
else:
|
||||||
|
if self.term_truecolor:
|
||||||
|
ansi += [48, 2] + list(int_to_rgb(bg[1]))
|
||||||
|
else:
|
||||||
|
ansi += [48, 5, bg[0]]
|
||||||
|
if attr is not None:
|
||||||
|
if attr is False:
|
||||||
|
ansi += [22]
|
||||||
|
else:
|
||||||
|
if attr & ATTR_BOLD:
|
||||||
|
ansi += [1]
|
||||||
|
elif attr & ATTR_ITALIC:
|
||||||
|
# Note: is likely not to work or even be inverse in place of
|
||||||
|
# italic. Omit using this in colorschemes.
|
||||||
|
ansi += [3]
|
||||||
|
elif attr & ATTR_UNDERLINE:
|
||||||
|
ansi += [4]
|
||||||
|
r = '\033[{0}m'.format(';'.join(str(attr) for attr in ansi))
|
||||||
|
if self.tmux_escape:
|
||||||
|
r = '\033Ptmux;' + r.replace('\033', '\033\033') + '\033\\'
|
||||||
|
elif self.screen_escape:
|
||||||
|
r = '\033P' + r.replace('\033', '\033\033') + '\033\\'
|
||||||
|
return self.escape_hl_start + r + self.escape_hl_end
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def escape(string):
|
||||||
|
return string.replace('\\', '\\\\')
|
||||||
|
|
||||||
|
|
||||||
|
renderer = ShellRenderer
|
|
@ -0,0 +1,44 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.renderer import Renderer
|
||||||
|
from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
|
||||||
|
|
||||||
|
|
||||||
|
class TmuxRenderer(Renderer):
|
||||||
|
'''Powerline tmux segment renderer.'''
|
||||||
|
def hlstyle(self, fg=None, bg=None, attr=None):
|
||||||
|
'''Highlight a segment.'''
|
||||||
|
# We don't need to explicitly reset attributes, so skip those calls
|
||||||
|
if not attr and not bg and not fg:
|
||||||
|
return ''
|
||||||
|
tmux_attr = []
|
||||||
|
if fg is not None:
|
||||||
|
if fg is False or fg[0] is False:
|
||||||
|
tmux_attr += ['fg=default']
|
||||||
|
else:
|
||||||
|
tmux_attr += ['fg=colour' + str(fg[0])]
|
||||||
|
if bg is not None:
|
||||||
|
if bg is False or bg[0] is False:
|
||||||
|
tmux_attr += ['bg=default']
|
||||||
|
else:
|
||||||
|
tmux_attr += ['bg=colour' + str(bg[0])]
|
||||||
|
if attr is not None:
|
||||||
|
if attr is False:
|
||||||
|
tmux_attr += ['nobold', 'noitalics', 'nounderscore']
|
||||||
|
else:
|
||||||
|
if attr & ATTR_BOLD:
|
||||||
|
tmux_attr += ['bold']
|
||||||
|
else:
|
||||||
|
tmux_attr += ['nobold']
|
||||||
|
if attr & ATTR_ITALIC:
|
||||||
|
tmux_attr += ['italics']
|
||||||
|
else:
|
||||||
|
tmux_attr += ['noitalics']
|
||||||
|
if attr & ATTR_UNDERLINE:
|
||||||
|
tmux_attr += ['underscore']
|
||||||
|
else:
|
||||||
|
tmux_attr += ['nounderscore']
|
||||||
|
return '#[' + ','.join(tmux_attr) + ']'
|
||||||
|
|
||||||
|
|
||||||
|
renderer = TmuxRenderer
|
|
@ -0,0 +1,154 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from powerline.bindings.vim import vim_get_func
|
||||||
|
from powerline.renderer import Renderer
|
||||||
|
from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
|
||||||
|
from powerline.theme import Theme
|
||||||
|
|
||||||
|
import vim
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
vim_mode = vim_get_func('mode', rettype=str)
|
||||||
|
mode_translations = {
|
||||||
|
chr(ord('V') - 0x40): '^V',
|
||||||
|
chr(ord('S') - 0x40): '^S',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VimRenderer(Renderer):
|
||||||
|
'''Powerline vim segment renderer.'''
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
if not hasattr(vim, 'strwidth'):
|
||||||
|
# Hope nobody want to change this at runtime
|
||||||
|
if vim.eval('&ambiwidth') == 'double':
|
||||||
|
kwargs = dict(**kwargs)
|
||||||
|
kwargs['ambigious'] = 2
|
||||||
|
super(VimRenderer, self).__init__(*args, **kwargs)
|
||||||
|
self.hl_groups = {}
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.theme.shutdown()
|
||||||
|
for match in self.local_themes.values():
|
||||||
|
if 'theme' in match:
|
||||||
|
match['theme'].shutdown()
|
||||||
|
|
||||||
|
def add_local_theme(self, matcher, theme):
|
||||||
|
if matcher in self.local_themes:
|
||||||
|
raise KeyError('There is already a local theme with given matcher')
|
||||||
|
self.local_themes[matcher] = theme
|
||||||
|
|
||||||
|
def get_theme(self, matcher_info):
|
||||||
|
for matcher in self.local_themes.keys():
|
||||||
|
if matcher(matcher_info):
|
||||||
|
match = self.local_themes[matcher]
|
||||||
|
try:
|
||||||
|
return match['theme']
|
||||||
|
except KeyError:
|
||||||
|
match['theme'] = Theme(theme_config=match['config'], top_theme_config=self.theme_config, **self.theme_kwargs)
|
||||||
|
return match['theme']
|
||||||
|
else:
|
||||||
|
return self.theme
|
||||||
|
|
||||||
|
if hasattr(vim, 'strwidth'):
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
@staticmethod
|
||||||
|
def strwidth(string):
|
||||||
|
# Does not work with tabs, but neither is strwidth from default
|
||||||
|
# renderer
|
||||||
|
return vim.strwidth(string.encode('utf-8'))
|
||||||
|
else:
|
||||||
|
@staticmethod # NOQA
|
||||||
|
def strwidth(string):
|
||||||
|
return vim.strwidth(string)
|
||||||
|
|
||||||
|
def get_segment_info(self, segment_info):
|
||||||
|
return segment_info or self.segment_info
|
||||||
|
|
||||||
|
def render(self, window_id, winidx, current):
|
||||||
|
'''Render all segments.'''
|
||||||
|
if current:
|
||||||
|
mode = vim_mode(1)
|
||||||
|
mode = mode_translations.get(mode, mode)
|
||||||
|
else:
|
||||||
|
mode = 'nc'
|
||||||
|
segment_info = {
|
||||||
|
'window': vim.windows[winidx],
|
||||||
|
'mode': mode,
|
||||||
|
'window_id': window_id,
|
||||||
|
}
|
||||||
|
segment_info['buffer'] = segment_info['window'].buffer
|
||||||
|
segment_info['bufnr'] = segment_info['buffer'].number
|
||||||
|
segment_info.update(self.segment_info)
|
||||||
|
winwidth = segment_info['window'].width
|
||||||
|
statusline = super(VimRenderer, self).render(
|
||||||
|
mode=mode,
|
||||||
|
width=winwidth,
|
||||||
|
segment_info=segment_info,
|
||||||
|
matcher_info=segment_info,
|
||||||
|
)
|
||||||
|
return statusline
|
||||||
|
|
||||||
|
def reset_highlight(self):
|
||||||
|
self.hl_groups.clear()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def escape(string):
|
||||||
|
return string.replace('%', '%%')
|
||||||
|
|
||||||
|
def hlstyle(self, fg=None, bg=None, attr=None):
|
||||||
|
'''Highlight a segment.
|
||||||
|
|
||||||
|
If an argument is None, the argument is ignored. If an argument is
|
||||||
|
False, the argument is reset to the terminal defaults. If an argument
|
||||||
|
is a valid color or attribute, it's added to the vim highlight group.
|
||||||
|
'''
|
||||||
|
# We don't need to explicitly reset attributes in vim, so skip those calls
|
||||||
|
if not attr and not bg and not fg:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
if not (fg, bg, attr) in self.hl_groups:
|
||||||
|
hl_group = {
|
||||||
|
'ctermfg': 'NONE',
|
||||||
|
'guifg': None,
|
||||||
|
'ctermbg': 'NONE',
|
||||||
|
'guibg': None,
|
||||||
|
'attr': ['NONE'],
|
||||||
|
'name': '',
|
||||||
|
}
|
||||||
|
if fg is not None and fg is not False:
|
||||||
|
hl_group['ctermfg'] = fg[0]
|
||||||
|
hl_group['guifg'] = fg[1]
|
||||||
|
if bg is not None and bg is not False:
|
||||||
|
hl_group['ctermbg'] = bg[0]
|
||||||
|
hl_group['guibg'] = bg[1]
|
||||||
|
if attr:
|
||||||
|
hl_group['attr'] = []
|
||||||
|
if attr & ATTR_BOLD:
|
||||||
|
hl_group['attr'].append('bold')
|
||||||
|
if attr & ATTR_ITALIC:
|
||||||
|
hl_group['attr'].append('italic')
|
||||||
|
if attr & ATTR_UNDERLINE:
|
||||||
|
hl_group['attr'].append('underline')
|
||||||
|
hl_group['name'] = 'Pl_' + \
|
||||||
|
str(hl_group['ctermfg']) + '_' + \
|
||||||
|
str(hl_group['guifg']) + '_' + \
|
||||||
|
str(hl_group['ctermbg']) + '_' + \
|
||||||
|
str(hl_group['guibg']) + '_' + \
|
||||||
|
''.join(hl_group['attr'])
|
||||||
|
self.hl_groups[(fg, bg, attr)] = hl_group
|
||||||
|
vim.command('hi {group} ctermfg={ctermfg} guifg={guifg} guibg={guibg} ctermbg={ctermbg} cterm={attr} gui={attr}'.format(
|
||||||
|
group=hl_group['name'],
|
||||||
|
ctermfg=hl_group['ctermfg'],
|
||||||
|
guifg='#{0:06x}'.format(hl_group['guifg']) if hl_group['guifg'] is not None else 'NONE',
|
||||||
|
ctermbg=hl_group['ctermbg'],
|
||||||
|
guibg='#{0:06x}'.format(hl_group['guibg']) if hl_group['guibg'] is not None else 'NONE',
|
||||||
|
attr=','.join(hl_group['attr']),
|
||||||
|
))
|
||||||
|
return '%#' + self.hl_groups[(fg, bg, attr)]['name'] + '#'
|
||||||
|
|
||||||
|
|
||||||
|
renderer = VimRenderer
|
|
@ -0,0 +1,16 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.renderers.shell import ShellRenderer
|
||||||
|
|
||||||
|
|
||||||
|
class ZshPromptRenderer(ShellRenderer):
|
||||||
|
'''Powerline zsh prompt segment renderer.'''
|
||||||
|
escape_hl_start = '%{'
|
||||||
|
escape_hl_end = '%}'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def escape(string):
|
||||||
|
return string.replace('%', '%%').replace('\\', '\\\\')
|
||||||
|
|
||||||
|
|
||||||
|
renderer = ZshPromptRenderer
|
104
common/.local/lib/python2.7/site-packages/powerline/segment.py
Normal file
104
common/.local/lib/python2.7/site-packages/powerline/segment.py
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def get_segment_key(segment, theme_configs, key, module=None, default=None):
|
||||||
|
try:
|
||||||
|
return segment[key]
|
||||||
|
except KeyError:
|
||||||
|
if 'name' in segment:
|
||||||
|
name = segment['name']
|
||||||
|
for theme_config in theme_configs:
|
||||||
|
if 'segment_data' in theme_config:
|
||||||
|
for segment_key in ((module + '.' + name, name) if module else (name,)):
|
||||||
|
try:
|
||||||
|
return theme_config['segment_data'][segment_key][key]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def get_function(data, segment):
|
||||||
|
oldpath = sys.path
|
||||||
|
sys.path = data['path'] + sys.path
|
||||||
|
segment_module = str(segment.get('module', data['default_module']))
|
||||||
|
try:
|
||||||
|
return None, getattr(__import__(segment_module, fromlist=[segment['name']]), segment['name']), segment_module
|
||||||
|
finally:
|
||||||
|
sys.path = oldpath
|
||||||
|
|
||||||
|
|
||||||
|
def get_string(data, segment):
|
||||||
|
return data['get_key'](segment, None, 'contents'), None, None
|
||||||
|
|
||||||
|
|
||||||
|
def get_filler(data, segment):
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
|
|
||||||
|
segment_getters = {
|
||||||
|
"function": get_function,
|
||||||
|
"string": get_string,
|
||||||
|
"filler": get_filler,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def gen_segment_getter(pl, ext, path, theme_configs, default_module=None):
|
||||||
|
data = {
|
||||||
|
'default_module': default_module or 'powerline.segments.' + ext,
|
||||||
|
'path': path,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_key(segment, module, key, default=None):
|
||||||
|
return get_segment_key(segment, theme_configs, key, module, default)
|
||||||
|
data['get_key'] = get_key
|
||||||
|
|
||||||
|
def get(segment, side):
|
||||||
|
segment_type = segment.get('type', 'function')
|
||||||
|
try:
|
||||||
|
get_segment_info = segment_getters[segment_type]
|
||||||
|
except KeyError:
|
||||||
|
raise TypeError('Unknown segment type: {0}'.format(segment_type))
|
||||||
|
|
||||||
|
try:
|
||||||
|
contents, contents_func, module = get_segment_info(data, segment)
|
||||||
|
except Exception as e:
|
||||||
|
pl.exception('Failed to generate segment from {0!r}: {1}', segment, str(e), prefix='segment_generator')
|
||||||
|
return None
|
||||||
|
|
||||||
|
if segment_type == 'function':
|
||||||
|
highlight_group = [module + '.' + segment['name'], segment['name']]
|
||||||
|
else:
|
||||||
|
highlight_group = segment.get('highlight_group') or segment.get('name')
|
||||||
|
|
||||||
|
return {
|
||||||
|
'name': segment.get('name'),
|
||||||
|
'type': segment_type,
|
||||||
|
'highlight_group': highlight_group,
|
||||||
|
'divider_highlight_group': None,
|
||||||
|
'before': get_key(segment, module, 'before', ''),
|
||||||
|
'after': get_key(segment, module, 'after', ''),
|
||||||
|
'contents_func': contents_func,
|
||||||
|
'contents': contents,
|
||||||
|
'args': get_key(segment, module, 'args', {}) if segment_type == 'function' else {},
|
||||||
|
'priority': segment.get('priority', None),
|
||||||
|
'draw_hard_divider': segment.get('draw_hard_divider', True),
|
||||||
|
'draw_soft_divider': segment.get('draw_soft_divider', True),
|
||||||
|
'draw_inner_divider': segment.get('draw_inner_divider', False),
|
||||||
|
'side': side,
|
||||||
|
'exclude_modes': segment.get('exclude_modes', []),
|
||||||
|
'include_modes': segment.get('include_modes', []),
|
||||||
|
'width': segment.get('width'),
|
||||||
|
'align': segment.get('align', 'l'),
|
||||||
|
'shutdown': getattr(contents_func, 'shutdown', None),
|
||||||
|
'startup': getattr(contents_func, 'startup', None),
|
||||||
|
'_rendered_raw': '',
|
||||||
|
'_rendered_hl': '',
|
||||||
|
'_len': 0,
|
||||||
|
'_space_left': 0,
|
||||||
|
'_space_right': 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
return get
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,8 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.theme import requires_segment_info
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def prompt_count(pl, segment_info):
|
||||||
|
return str(segment_info['ipython'].prompt_count)
|
|
@ -0,0 +1,28 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline.theme import requires_segment_info
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def last_status(pl, segment_info):
|
||||||
|
'''Return last exit code.
|
||||||
|
|
||||||
|
Highlight groups used: ``exit_fail``
|
||||||
|
'''
|
||||||
|
if not segment_info['args'].last_exit_code:
|
||||||
|
return None
|
||||||
|
return [{'contents': str(segment_info['args'].last_exit_code), 'highlight_group': 'exit_fail'}]
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def last_pipe_status(pl, segment_info):
|
||||||
|
'''Return last pipe status.
|
||||||
|
|
||||||
|
Highlight groups used: ``exit_fail``, ``exit_success``
|
||||||
|
'''
|
||||||
|
last_pipe_status = segment_info['args'].last_pipe_status
|
||||||
|
if any(last_pipe_status):
|
||||||
|
return [{'contents': str(status), 'highlight_group': 'exit_fail' if status else 'exit_success', 'draw_inner_divider': True}
|
||||||
|
for status in last_pipe_status]
|
||||||
|
else:
|
||||||
|
return None
|
|
@ -0,0 +1,443 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division
|
||||||
|
|
||||||
|
import os
|
||||||
|
try:
|
||||||
|
import vim
|
||||||
|
except ImportError:
|
||||||
|
vim = {} # NOQA
|
||||||
|
|
||||||
|
from powerline.bindings.vim import vim_get_func, getbufvar
|
||||||
|
from powerline.theme import requires_segment_info
|
||||||
|
from powerline.lib import add_divider_highlight_group
|
||||||
|
from powerline.lib.vcs import guess
|
||||||
|
from powerline.lib.humanize_bytes import humanize_bytes
|
||||||
|
from powerline.lib.threaded import KwThreadedSegment, with_docstring
|
||||||
|
from powerline.lib import wraps_saveargs as wraps
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
vim_funcs = {
|
||||||
|
'virtcol': vim_get_func('virtcol', rettype=int),
|
||||||
|
'fnamemodify': vim_get_func('fnamemodify', rettype=str),
|
||||||
|
'expand': vim_get_func('expand', rettype=str),
|
||||||
|
'bufnr': vim_get_func('bufnr', rettype=int),
|
||||||
|
'line2byte': vim_get_func('line2byte', rettype=int),
|
||||||
|
}
|
||||||
|
|
||||||
|
vim_modes = {
|
||||||
|
'n': 'NORMAL',
|
||||||
|
'no': 'N·OPER',
|
||||||
|
'v': 'VISUAL',
|
||||||
|
'V': 'V·LINE',
|
||||||
|
'^V': 'V·BLCK',
|
||||||
|
's': 'SELECT',
|
||||||
|
'S': 'S·LINE',
|
||||||
|
'^S': 'S·BLCK',
|
||||||
|
'i': 'INSERT',
|
||||||
|
'R': 'REPLACE',
|
||||||
|
'Rv': 'V·RPLCE',
|
||||||
|
'c': 'COMMND',
|
||||||
|
'cv': 'VIM EX',
|
||||||
|
'ce': 'EX',
|
||||||
|
'r': 'PROMPT',
|
||||||
|
'rm': 'MORE',
|
||||||
|
'r?': 'CONFIRM',
|
||||||
|
'!': 'SHELL',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
eventfuncs = defaultdict(lambda: [])
|
||||||
|
bufeventfuncs = defaultdict(lambda: [])
|
||||||
|
defined_events = set()
|
||||||
|
|
||||||
|
|
||||||
|
def purgeonevents_reg(func, events, is_buffer_event=False):
|
||||||
|
if is_buffer_event:
|
||||||
|
cureventfuncs = bufeventfuncs
|
||||||
|
else:
|
||||||
|
cureventfuncs = eventfuncs
|
||||||
|
for event in events:
|
||||||
|
if event not in defined_events:
|
||||||
|
vim.eval('PowerlineRegisterCachePurgerEvent("' + event + '")')
|
||||||
|
defined_events.add(event)
|
||||||
|
cureventfuncs[event].append(func)
|
||||||
|
|
||||||
|
|
||||||
|
def launchevent(event):
|
||||||
|
global eventfuncs
|
||||||
|
global bufeventfuncs
|
||||||
|
for func in eventfuncs[event]:
|
||||||
|
func()
|
||||||
|
if bufeventfuncs[event]:
|
||||||
|
buffer = vim.buffers[int(vim_funcs['expand']('<abuf>')) - 1]
|
||||||
|
for func in bufeventfuncs[event]:
|
||||||
|
func(buffer)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Remove cache when needed
|
||||||
|
def window_cached(func):
|
||||||
|
cache = {}
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
@wraps(func)
|
||||||
|
def ret(segment_info, **kwargs):
|
||||||
|
window_id = segment_info['window_id']
|
||||||
|
if segment_info['mode'] == 'nc':
|
||||||
|
return cache.get(window_id)
|
||||||
|
else:
|
||||||
|
r = func(**kwargs)
|
||||||
|
cache[window_id] = r
|
||||||
|
return r
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def mode(pl, segment_info, override=None):
|
||||||
|
'''Return the current vim mode.
|
||||||
|
|
||||||
|
:param dict override:
|
||||||
|
dict for overriding default mode strings, e.g. ``{ 'n': 'NORM' }``
|
||||||
|
'''
|
||||||
|
mode = segment_info['mode']
|
||||||
|
if mode == 'nc':
|
||||||
|
return None
|
||||||
|
if not override:
|
||||||
|
return vim_modes[mode]
|
||||||
|
try:
|
||||||
|
return override[mode]
|
||||||
|
except KeyError:
|
||||||
|
return vim_modes[mode]
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def modified_indicator(pl, segment_info, text='+'):
|
||||||
|
'''Return a file modified indicator.
|
||||||
|
|
||||||
|
:param string text:
|
||||||
|
text to display if the current buffer is modified
|
||||||
|
'''
|
||||||
|
return text if int(getbufvar(segment_info['bufnr'], '&modified')) else None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def paste_indicator(pl, segment_info, text='PASTE'):
|
||||||
|
'''Return a paste mode indicator.
|
||||||
|
|
||||||
|
:param string text:
|
||||||
|
text to display if paste mode is enabled
|
||||||
|
'''
|
||||||
|
return text if int(vim.eval('&paste')) else None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def readonly_indicator(pl, segment_info, text=''):
|
||||||
|
'''Return a read-only indicator.
|
||||||
|
|
||||||
|
:param string text:
|
||||||
|
text to display if the current buffer is read-only
|
||||||
|
'''
|
||||||
|
return text if int(getbufvar(segment_info['bufnr'], '&readonly')) else None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def file_directory(pl, segment_info, shorten_user=True, shorten_cwd=True, shorten_home=False):
|
||||||
|
'''Return file directory (head component of the file path).
|
||||||
|
|
||||||
|
:param bool shorten_user:
|
||||||
|
shorten ``$HOME`` directory to :file:`~/`
|
||||||
|
|
||||||
|
:param bool shorten_cwd:
|
||||||
|
shorten current directory to :file:`./`
|
||||||
|
|
||||||
|
:param bool shorten_home:
|
||||||
|
shorten all directories in :file:`/home/` to :file:`~user/` instead of :file:`/home/user/`.
|
||||||
|
'''
|
||||||
|
name = segment_info['buffer'].name
|
||||||
|
if not name:
|
||||||
|
return None
|
||||||
|
file_directory = vim_funcs['fnamemodify'](name, (':~' if shorten_user else '')
|
||||||
|
+ (':.' if shorten_cwd else '') + ':h')
|
||||||
|
if shorten_home and file_directory.startswith('/home/'):
|
||||||
|
file_directory = '~' + file_directory[6:]
|
||||||
|
return file_directory + os.sep if file_directory else None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def file_name(pl, segment_info, display_no_file=False, no_file_text='[No file]'):
|
||||||
|
'''Return file name (tail component of the file path).
|
||||||
|
|
||||||
|
:param bool display_no_file:
|
||||||
|
display a string if the buffer is missing a file name
|
||||||
|
:param str no_file_text:
|
||||||
|
the string to display if the buffer is missing a file name
|
||||||
|
|
||||||
|
Highlight groups used: ``file_name_no_file`` or ``file_name``, ``file_name``.
|
||||||
|
'''
|
||||||
|
name = segment_info['buffer'].name
|
||||||
|
if not name:
|
||||||
|
if display_no_file:
|
||||||
|
return [{
|
||||||
|
'contents': no_file_text,
|
||||||
|
'highlight_group': ['file_name_no_file', 'file_name'],
|
||||||
|
}]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
file_name = vim_funcs['fnamemodify'](name, ':~:.:t')
|
||||||
|
return file_name
|
||||||
|
|
||||||
|
|
||||||
|
@window_cached
|
||||||
|
def file_size(pl, suffix='B', si_prefix=False):
|
||||||
|
'''Return file size in &encoding.
|
||||||
|
|
||||||
|
:param str suffix:
|
||||||
|
string appended to the file size
|
||||||
|
:param bool si_prefix:
|
||||||
|
use SI prefix, e.g. MB instead of MiB
|
||||||
|
:return: file size or None if the file isn't saved or if the size is too big to fit in a number
|
||||||
|
'''
|
||||||
|
# Note: returns file size in &encoding, not in &fileencoding. But returned
|
||||||
|
# size is updated immediately; and it is valid for any buffer
|
||||||
|
file_size = vim_funcs['line2byte'](len(vim.current.buffer) + 1) - 1
|
||||||
|
return humanize_bytes(file_size, suffix, si_prefix)
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
@add_divider_highlight_group('background:divider')
|
||||||
|
def file_format(pl, segment_info):
|
||||||
|
'''Return file format (i.e. line ending type).
|
||||||
|
|
||||||
|
:return: file format or None if unknown or missing file format
|
||||||
|
|
||||||
|
Divider highlight group used: ``background:divider``.
|
||||||
|
'''
|
||||||
|
return getbufvar(segment_info['bufnr'], '&fileformat') or None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
@add_divider_highlight_group('background:divider')
|
||||||
|
def file_encoding(pl, segment_info):
|
||||||
|
'''Return file encoding/character set.
|
||||||
|
|
||||||
|
:return: file encoding/character set or None if unknown or missing file encoding
|
||||||
|
|
||||||
|
Divider highlight group used: ``background:divider``.
|
||||||
|
'''
|
||||||
|
return getbufvar(segment_info['bufnr'], '&fileencoding') or None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
@add_divider_highlight_group('background:divider')
|
||||||
|
def file_type(pl, segment_info):
|
||||||
|
'''Return file type.
|
||||||
|
|
||||||
|
:return: file type or None if unknown file type
|
||||||
|
|
||||||
|
Divider highlight group used: ``background:divider``.
|
||||||
|
'''
|
||||||
|
return getbufvar(segment_info['bufnr'], '&filetype') or None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def line_percent(pl, segment_info, gradient=False):
|
||||||
|
'''Return the cursor position in the file as a percentage.
|
||||||
|
|
||||||
|
:param bool gradient:
|
||||||
|
highlight the percentage with a color gradient (by default a green to red gradient)
|
||||||
|
|
||||||
|
Highlight groups used: ``line_percent_gradient`` (gradient), ``line_percent``.
|
||||||
|
'''
|
||||||
|
line_current = segment_info['window'].cursor[0]
|
||||||
|
line_last = len(segment_info['buffer'])
|
||||||
|
percentage = line_current * 100.0 / line_last
|
||||||
|
if not gradient:
|
||||||
|
return str(int(round(percentage)))
|
||||||
|
return [{
|
||||||
|
'contents': str(int(round(percentage))),
|
||||||
|
'highlight_group': ['line_percent_gradient', 'line_percent'],
|
||||||
|
'gradient_level': percentage,
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def line_current(pl, segment_info):
|
||||||
|
'''Return the current cursor line.'''
|
||||||
|
return str(segment_info['window'].cursor[0])
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def col_current(pl, segment_info):
|
||||||
|
'''Return the current cursor column.
|
||||||
|
'''
|
||||||
|
return str(segment_info['window'].cursor[1] + 1)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Add &textwidth-based gradient
|
||||||
|
@window_cached
|
||||||
|
def virtcol_current(pl, gradient=True):
|
||||||
|
'''Return current visual column with concealed characters ingored
|
||||||
|
|
||||||
|
:param bool gradient:
|
||||||
|
Determines whether it should show textwidth-based gradient (gradient level is ``virtcol * 100 / textwidth``).
|
||||||
|
|
||||||
|
Highlight groups used: ``virtcol_current_gradient`` (gradient), ``virtcol_current`` or ``col_current``.
|
||||||
|
'''
|
||||||
|
col = vim_funcs['virtcol']('.')
|
||||||
|
r = [{'contents': str(col), 'highlight_group': ['virtcol_current', 'col_current']}]
|
||||||
|
if gradient:
|
||||||
|
textwidth = int(getbufvar('%', '&textwidth'))
|
||||||
|
r[-1]['gradient_level'] = min(col * 100 / textwidth, 100) if textwidth else 0
|
||||||
|
r[-1]['highlight_group'].insert(0, 'virtcol_current_gradient')
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def modified_buffers(pl, text='+ ', join_str=','):
|
||||||
|
'''Return a comma-separated list of modified buffers.
|
||||||
|
|
||||||
|
:param str text:
|
||||||
|
text to display before the modified buffer list
|
||||||
|
:param str join_str:
|
||||||
|
string to use for joining the modified buffer list
|
||||||
|
'''
|
||||||
|
buffer_len = vim_funcs['bufnr']('$')
|
||||||
|
buffer_mod = [str(bufnr) for bufnr in range(1, buffer_len + 1) if int(getbufvar(bufnr, '&modified') or 0)]
|
||||||
|
if buffer_mod:
|
||||||
|
return text + join_str.join(buffer_mod)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class KwWindowThreadedSegment(KwThreadedSegment):
|
||||||
|
def set_state(self, **kwargs):
|
||||||
|
kwargs = kwargs.copy()
|
||||||
|
for window in vim.windows:
|
||||||
|
buffer = window.buffer
|
||||||
|
kwargs['segment_info'] = {'bufnr': buffer.number, 'buffer': buffer}
|
||||||
|
super(KwWindowThreadedSegment, self).set_state(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class RepositorySegment(KwWindowThreadedSegment):
|
||||||
|
def __init__(self):
|
||||||
|
super(RepositorySegment, self).__init__()
|
||||||
|
self.directories = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def key(segment_info, **kwargs):
|
||||||
|
# FIXME os.getcwd() is not a proper variant for non-current buffers
|
||||||
|
return segment_info['buffer'].name or os.getcwd()
|
||||||
|
|
||||||
|
def update(self, *args):
|
||||||
|
# .compute_state() is running only in this method, and only in one
|
||||||
|
# thread, thus operations with .directories do not need write locks
|
||||||
|
# (.render() method is not using .directories). If this is changed
|
||||||
|
# .directories needs redesigning
|
||||||
|
self.directories.clear()
|
||||||
|
return super(RepositorySegment, self).update(*args)
|
||||||
|
|
||||||
|
def compute_state(self, path):
|
||||||
|
repo = guess(path=path)
|
||||||
|
if repo:
|
||||||
|
if repo.directory in self.directories:
|
||||||
|
return self.directories[repo.directory]
|
||||||
|
else:
|
||||||
|
r = self.process_repo(repo)
|
||||||
|
self.directories[repo.directory] = r
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
class RepositoryStatusSegment(RepositorySegment):
|
||||||
|
interval = 2
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process_repo(repo):
|
||||||
|
return repo.status()
|
||||||
|
|
||||||
|
|
||||||
|
repository_status = with_docstring(RepositoryStatusSegment(),
|
||||||
|
'''Return the status for the current repo.''')
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
class BranchSegment(RepositorySegment):
|
||||||
|
interval = 0.2
|
||||||
|
started_repository_status = False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process_repo(repo):
|
||||||
|
return repo.branch()
|
||||||
|
|
||||||
|
def render_one(self, branch, segment_info, status_colors=False, **kwargs):
|
||||||
|
if not branch:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if status_colors:
|
||||||
|
self.started_repository_status = True
|
||||||
|
|
||||||
|
return [{
|
||||||
|
'contents': branch,
|
||||||
|
'highlight_group': (['branch_dirty' if repository_status(segment_info=segment_info, **kwargs) else 'branch_clean']
|
||||||
|
if status_colors else []) + ['branch'],
|
||||||
|
'divider_highlight_group': 'branch:divider',
|
||||||
|
}]
|
||||||
|
|
||||||
|
def startup(self, status_colors=False, **kwargs):
|
||||||
|
super(BranchSegment, self).startup(**kwargs)
|
||||||
|
if status_colors:
|
||||||
|
self.started_repository_status = True
|
||||||
|
repository_status.startup(**kwargs)
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
if self.started_repository_status:
|
||||||
|
repository_status.shutdown()
|
||||||
|
super(BranchSegment, self).shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
branch = with_docstring(BranchSegment(),
|
||||||
|
'''Return the current working branch.
|
||||||
|
|
||||||
|
:param bool status_colors:
|
||||||
|
determines whether repository status will be used to determine highlighting. Default: False.
|
||||||
|
|
||||||
|
Highlight groups used: ``branch_clean``, ``branch_dirty``, ``branch``.
|
||||||
|
|
||||||
|
Divider highlight group used: ``branch:divider``.
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
class FileVCSStatusSegment(KwWindowThreadedSegment):
|
||||||
|
interval = 0.2
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def key(segment_info, **kwargs):
|
||||||
|
name = segment_info['buffer'].name
|
||||||
|
skip = not (name and (not getbufvar(segment_info['bufnr'], '&buftype')))
|
||||||
|
return name, skip
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def compute_state(key):
|
||||||
|
name, skip = key
|
||||||
|
if not skip:
|
||||||
|
repo = guess(path=name)
|
||||||
|
if repo:
|
||||||
|
status = repo.status(os.path.relpath(name, repo.directory))
|
||||||
|
if not status:
|
||||||
|
return None
|
||||||
|
status = status.strip()
|
||||||
|
ret = []
|
||||||
|
for status in status:
|
||||||
|
ret.append({
|
||||||
|
'contents': status,
|
||||||
|
'highlight_group': ['file_vcs_status_' + status, 'file_vcs_status'],
|
||||||
|
})
|
||||||
|
return ret
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
file_vcs_status = with_docstring(FileVCSStatusSegment(),
|
||||||
|
'''Return the VCS status for this buffer.
|
||||||
|
|
||||||
|
Highlight groups used: ``file_vcs_status``.
|
||||||
|
''')
|
55
common/.local/lib/python2.7/site-packages/powerline/shell.py
Normal file
55
common/.local/lib/python2.7/site-packages/powerline/shell.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from powerline import Powerline
|
||||||
|
from powerline.lib import mergedicts, parsedotval
|
||||||
|
|
||||||
|
|
||||||
|
def mergeargs(argvalue):
|
||||||
|
if not argvalue:
|
||||||
|
return None
|
||||||
|
r = dict([argvalue[0]])
|
||||||
|
for subval in argvalue[1:]:
|
||||||
|
mergedicts(r, dict([subval]))
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
class ShellPowerline(Powerline):
|
||||||
|
def __init__(self, args, **kwargs):
|
||||||
|
self.args = args
|
||||||
|
self.theme_option = mergeargs(args.theme_option) or {}
|
||||||
|
super(ShellPowerline, self).__init__(args.ext[0], args.renderer_module, **kwargs)
|
||||||
|
|
||||||
|
def load_main_config(self):
|
||||||
|
r = super(ShellPowerline, self).load_main_config()
|
||||||
|
if self.args.config:
|
||||||
|
mergedicts(r, mergeargs(self.args.config))
|
||||||
|
return r
|
||||||
|
|
||||||
|
def load_theme_config(self, name):
|
||||||
|
r = super(ShellPowerline, self).load_theme_config(name)
|
||||||
|
if name in self.theme_option:
|
||||||
|
mergedicts(r, self.theme_option[name])
|
||||||
|
return r
|
||||||
|
|
||||||
|
def get_config_paths(self):
|
||||||
|
if self.args.config_path:
|
||||||
|
return [self.args.config_path]
|
||||||
|
else:
|
||||||
|
return super(ShellPowerline, self).get_config_paths()
|
||||||
|
|
||||||
|
|
||||||
|
def get_argparser(parser=None, *args, **kwargs):
|
||||||
|
if not parser:
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser
|
||||||
|
p = parser(*args, **kwargs)
|
||||||
|
p.add_argument('ext', nargs=1)
|
||||||
|
p.add_argument('side', nargs='?', choices=('left', 'right'))
|
||||||
|
p.add_argument('-r', '--renderer_module', metavar='MODULE', type=str)
|
||||||
|
p.add_argument('-w', '--width', type=int)
|
||||||
|
p.add_argument('--last_exit_code', metavar='INT', type=int)
|
||||||
|
p.add_argument('--last_pipe_status', metavar='LIST', default='', type=lambda s: [int(status) for status in s.split()])
|
||||||
|
p.add_argument('-c', '--config', metavar='KEY.KEY=VALUE', type=parsedotval, action='append')
|
||||||
|
p.add_argument('-t', '--theme_option', metavar='THEME.KEY.KEY=VALUE', type=parsedotval, action='append')
|
||||||
|
p.add_argument('-p', '--config_path', metavar='PATH')
|
||||||
|
return p
|
148
common/.local/lib/python2.7/site-packages/powerline/theme.py
Normal file
148
common/.local/lib/python2.7/site-packages/powerline/theme.py
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from .segment import gen_segment_getter
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __builtin__ import unicode
|
||||||
|
except ImportError:
|
||||||
|
unicode = str # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
def u(s):
|
||||||
|
if type(s) is unicode:
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return unicode(s, 'utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def requires_segment_info(func):
|
||||||
|
func.powerline_requires_segment_info = True
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
class Theme(object):
|
||||||
|
def __init__(self,
|
||||||
|
ext,
|
||||||
|
theme_config,
|
||||||
|
common_config,
|
||||||
|
pl,
|
||||||
|
top_theme_config=None,
|
||||||
|
run_once=False,
|
||||||
|
shutdown_event=None):
|
||||||
|
self.dividers = theme_config.get('dividers', common_config['dividers'])
|
||||||
|
self.spaces = theme_config.get('spaces', common_config['spaces'])
|
||||||
|
self.segments = {
|
||||||
|
'left': [],
|
||||||
|
'right': [],
|
||||||
|
}
|
||||||
|
self.EMPTY_SEGMENT = {
|
||||||
|
'contents': None,
|
||||||
|
'highlight': {'fg': False, 'bg': False, 'attr': 0}
|
||||||
|
}
|
||||||
|
self.pl = pl
|
||||||
|
theme_configs = [theme_config]
|
||||||
|
if top_theme_config:
|
||||||
|
theme_configs.append(top_theme_config)
|
||||||
|
get_segment = gen_segment_getter(pl, ext, common_config['paths'], theme_configs, theme_config.get('default_module'))
|
||||||
|
for side in ['left', 'right']:
|
||||||
|
for segment in theme_config['segments'].get(side, []):
|
||||||
|
segment = get_segment(segment, side)
|
||||||
|
if not run_once:
|
||||||
|
if segment['startup']:
|
||||||
|
try:
|
||||||
|
segment['startup'](pl=pl, shutdown_event=shutdown_event, **segment['args'])
|
||||||
|
except Exception as e:
|
||||||
|
pl.error('Exception during {0} startup: {1}', segment['name'], str(e))
|
||||||
|
continue
|
||||||
|
self.segments[side].append(segment)
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
for segments in self.segments.values():
|
||||||
|
for segment in segments:
|
||||||
|
try:
|
||||||
|
segment['shutdown']()
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_divider(self, side='left', type='soft'):
|
||||||
|
'''Return segment divider.'''
|
||||||
|
return self.dividers[side][type]
|
||||||
|
|
||||||
|
def get_spaces(self):
|
||||||
|
return self.spaces
|
||||||
|
|
||||||
|
def get_segments(self, side=None, segment_info=None):
|
||||||
|
'''Return all segments.
|
||||||
|
|
||||||
|
Function segments are called, and all segments get their before/after
|
||||||
|
and ljust/rjust properties applied.
|
||||||
|
'''
|
||||||
|
for side in [side] if side else ['left', 'right']:
|
||||||
|
parsed_segments = []
|
||||||
|
for segment in self.segments[side]:
|
||||||
|
if segment['type'] == 'function':
|
||||||
|
self.pl.prefix = segment['name']
|
||||||
|
try:
|
||||||
|
if (hasattr(segment['contents_func'], 'powerline_requires_segment_info')
|
||||||
|
and segment['contents_func'].powerline_requires_segment_info):
|
||||||
|
contents = segment['contents_func'](pl=self.pl, segment_info=segment_info, **segment['args'])
|
||||||
|
else:
|
||||||
|
contents = segment['contents_func'](pl=self.pl, **segment['args'])
|
||||||
|
except Exception as e:
|
||||||
|
self.pl.exception('Exception while computing segment: {0}', str(e))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if contents is None:
|
||||||
|
continue
|
||||||
|
if isinstance(contents, list):
|
||||||
|
segment_base = segment.copy()
|
||||||
|
if contents:
|
||||||
|
draw_divider_position = -1 if side == 'left' else 0
|
||||||
|
for key, i, newval in (
|
||||||
|
('before', 0, ''),
|
||||||
|
('after', -1, ''),
|
||||||
|
('draw_soft_divider', draw_divider_position, True),
|
||||||
|
('draw_hard_divider', draw_divider_position, True),
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
contents[i][key] = segment_base.pop(key)
|
||||||
|
segment_base[key] = newval
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
draw_inner_divider = None
|
||||||
|
if side == 'right':
|
||||||
|
append = parsed_segments.append
|
||||||
|
else:
|
||||||
|
pslen = len(parsed_segments)
|
||||||
|
append = lambda item: parsed_segments.insert(pslen, item)
|
||||||
|
|
||||||
|
for subsegment in (contents if side == 'right' else reversed(contents)):
|
||||||
|
segment_copy = segment_base.copy()
|
||||||
|
segment_copy.update(subsegment)
|
||||||
|
if draw_inner_divider is not None:
|
||||||
|
segment_copy['draw_soft_divider'] = draw_inner_divider
|
||||||
|
draw_inner_divider = segment_copy.pop('draw_inner_divider', None)
|
||||||
|
append(segment_copy)
|
||||||
|
else:
|
||||||
|
segment['contents'] = contents
|
||||||
|
parsed_segments.append(segment)
|
||||||
|
elif segment['width'] == 'auto' or (segment['type'] == 'string' and segment['contents'] is not None):
|
||||||
|
parsed_segments.append(segment)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
for segment in parsed_segments:
|
||||||
|
segment['contents'] = segment['before'] + u(segment['contents'] if segment['contents'] is not None else '') + segment['after']
|
||||||
|
# Align segment contents
|
||||||
|
if segment['width'] and segment['width'] != 'auto':
|
||||||
|
if segment['align'] == 'l':
|
||||||
|
segment['contents'] = segment['contents'].ljust(segment['width'])
|
||||||
|
elif segment['align'] == 'r':
|
||||||
|
segment['contents'] = segment['contents'].rjust(segment['width'])
|
||||||
|
elif segment['align'] == 'c':
|
||||||
|
segment['contents'] = segment['contents'].center(segment['width'])
|
||||||
|
# We need to yield a copy of the segment, or else mode-dependent
|
||||||
|
# segment contents can't be cached correctly e.g. when caching
|
||||||
|
# non-current window contents for vim statuslines
|
||||||
|
yield segment.copy()
|
95
common/.local/lib/python2.7/site-packages/powerline/vim.py
Normal file
95
common/.local/lib/python2.7/site-packages/powerline/vim.py
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from powerline.bindings.vim import vim_get_func
|
||||||
|
from powerline import Powerline
|
||||||
|
from powerline.lib import mergedicts
|
||||||
|
from powerline.matcher import gen_matcher_getter
|
||||||
|
import vim
|
||||||
|
|
||||||
|
|
||||||
|
vim_exists = vim_get_func('exists', rettype=int)
|
||||||
|
|
||||||
|
|
||||||
|
def _override_from(config, override_varname):
|
||||||
|
if vim_exists(override_varname):
|
||||||
|
# FIXME vim.eval has problem with numeric types, vim.bindeval may be
|
||||||
|
# absent (and requires converting values to python built-in types),
|
||||||
|
# vim.eval with typed call like the one I implemented in frawor is slow.
|
||||||
|
# Maybe eval(vime.eval('string({0})'.format(override_varname)))?
|
||||||
|
overrides = vim.eval(override_varname)
|
||||||
|
mergedicts(config, overrides)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
class VimPowerline(Powerline):
|
||||||
|
def __init__(self):
|
||||||
|
super(VimPowerline, self).__init__('vim')
|
||||||
|
|
||||||
|
def add_local_theme(self, key, config):
|
||||||
|
'''Add local themes at runtime (during vim session).
|
||||||
|
|
||||||
|
:param str key:
|
||||||
|
Matcher name (in format ``{matcher_module}.{module_attribute}`` or
|
||||||
|
``{module_attribute}`` if ``{matcher_module}`` is
|
||||||
|
``powerline.matchers.vim``). Function pointed by
|
||||||
|
``{module_attribute}`` should be hashable and accept a dictionary
|
||||||
|
with information about current buffer and return boolean value
|
||||||
|
indicating whether current window matched conditions. See also
|
||||||
|
:ref:`local_themes key description <config-ext-local_themes>`.
|
||||||
|
|
||||||
|
:param dict config:
|
||||||
|
:ref:`Theme <config-themes>` dictionary.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
``True`` if theme was added successfully and ``False`` if theme with
|
||||||
|
the same matcher already exists.
|
||||||
|
'''
|
||||||
|
self.update_renderer()
|
||||||
|
key = self.get_matcher(key)
|
||||||
|
try:
|
||||||
|
self.renderer.add_local_theme(key, {'config': config})
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def load_main_config(self):
|
||||||
|
return _override_from(super(VimPowerline, self).load_main_config(), 'g:powerline_config_overrides')
|
||||||
|
|
||||||
|
def load_theme_config(self, name):
|
||||||
|
# Note: themes with non-[a-zA-Z0-9_] names are impossible to override
|
||||||
|
# (though as far as I know exists() won’t throw). Won’t fix, use proper
|
||||||
|
# theme names.
|
||||||
|
return _override_from(super(VimPowerline, self).load_theme_config(name),
|
||||||
|
'g:powerline_theme_overrides__' + name)
|
||||||
|
|
||||||
|
def get_local_themes(self, local_themes):
|
||||||
|
if not local_themes:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
self.get_matcher = gen_matcher_getter(self.ext, self.import_paths)
|
||||||
|
return dict(((self.get_matcher(key), {'config': self.load_theme_config(val)})
|
||||||
|
for key, val in local_themes.items()))
|
||||||
|
|
||||||
|
def get_config_paths(self):
|
||||||
|
if vim_exists('g:powerline_config_path'):
|
||||||
|
return [vim.eval('g:powerline_config_path')]
|
||||||
|
else:
|
||||||
|
return super(VimPowerline, self).get_config_paths()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_segment_info():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def reset_highlight(self):
|
||||||
|
try:
|
||||||
|
self.renderer.reset_highlight()
|
||||||
|
except AttributeError:
|
||||||
|
# Renderer object appears only after first `.render()` call. Thus if
|
||||||
|
# ColorScheme event happens before statusline is drawn for the first
|
||||||
|
# time AttributeError will be thrown for the self.renderer. It is
|
||||||
|
# fine to ignore it: no renderer == no colors to reset == no need to
|
||||||
|
# do anything.
|
||||||
|
pass
|
|
@ -1,11 +1,13 @@
|
||||||
# Path to your oh-my-zsh configuration.
|
# Path to your oh-my-zsh configuration.
|
||||||
ZSH=$HOME/.oh-my-zsh
|
ZSH=$HOME/.oh-my-zsh
|
||||||
|
|
||||||
|
export TERM="xterm-256color"
|
||||||
|
|
||||||
# Set name of the theme to load.
|
# Set name of the theme to load.
|
||||||
# Look in ~/.oh-my-zsh/themes/
|
# Look in ~/.oh-my-zsh/themes/
|
||||||
# Optionally, if you set this to "random", it'll load a random theme each
|
# Optionally, if you set this to "random", it'll load a random theme each
|
||||||
# time that oh-my-zsh is loaded.
|
# time that oh-my-zsh is loaded.
|
||||||
ZSH_THEME="robbyrussell"
|
#ZSH_THEME="robbyrussell"
|
||||||
|
|
||||||
# Example aliases
|
# Example aliases
|
||||||
# alias zshconfig="mate ~/.zshrc"
|
# alias zshconfig="mate ~/.zshrc"
|
||||||
|
@ -24,23 +26,37 @@ ZSH_THEME="robbyrussell"
|
||||||
# DISABLE_AUTO_TITLE="true"
|
# DISABLE_AUTO_TITLE="true"
|
||||||
|
|
||||||
# Uncomment following line if you want red dots to be displayed while waiting for completion
|
# Uncomment following line if you want red dots to be displayed while waiting for completion
|
||||||
# COMPLETION_WAITING_DOTS="true"
|
COMPLETION_WAITING_DOTS="true"
|
||||||
|
|
||||||
# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
|
# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
|
||||||
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
|
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
|
||||||
# Example format: plugins=(rails git textmate ruby lighthouse)
|
# Example format: plugins=(rails git textmate ruby lighthouse)
|
||||||
plugins=(git)
|
plugins=(git mercurial battery colorize debian django go pip python svn tmux vi-mode command-not-found)
|
||||||
|
|
||||||
|
bindkey "^[[A" history-search-backward
|
||||||
|
bindkey "^[[B" history-search-forward
|
||||||
|
|
||||||
source $ZSH/oh-my-zsh.sh
|
source $ZSH/oh-my-zsh.sh
|
||||||
|
source ~/.zshrc-local
|
||||||
|
source ~/.zshrc-local-theme
|
||||||
|
|
||||||
autoload -Uz promptinit
|
autoload -Uz promptinit
|
||||||
promptinit
|
promptinit
|
||||||
prompt fire
|
|
||||||
|
|
||||||
autoload -U zsh-mime-setup
|
autoload -U zsh-mime-setup
|
||||||
autoload -U zsh-mime-handler
|
autoload -U zsh-mime-handler
|
||||||
zsh-mime-setup
|
zsh-mime-setup
|
||||||
|
|
||||||
|
autoload -Uz vcs_info
|
||||||
|
zstyle ':vcs_info:*' enable git svn hg bzr mtn
|
||||||
|
precmd() {
|
||||||
|
vcs_info
|
||||||
|
}
|
||||||
|
|
||||||
|
zstyle ':vcs_info:*' actionformats
|
||||||
|
zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat '%b%F{1}:%F{3}%r'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
alias make='colormake'
|
alias make='colormake'
|
||||||
alias gcc='colorgcc'
|
alias gcc='colorgcc'
|
||||||
|
@ -70,15 +86,17 @@ function cd() {
|
||||||
# Customize to your needs...
|
# Customize to your needs...
|
||||||
export PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/games
|
export PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/games
|
||||||
|
|
||||||
ssc() { ssh -XC -p ${3:-"22"} -t ${2:-`whoami`}@$1 tmux ${argv[4,-1]:-"attach-session"}; }
|
ssc() { ssh -XC -p ${3:-"22"} -t ${2:-`whoami`}@$1 "tmux ${argv[4,-1]:-"attach-session"} || tmux ${argv[4,-1]} ;" }
|
||||||
|
|
||||||
senritsu() { ssc senritsu.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
senritsu() { ssc senritsu.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
gon() { ssc gon.kujiu.org ${argv[-1]:-`whoami`} 2208 $argv[1,-2]; }
|
gon() { ssc gon.kujiu.org ${argv[-1]:-`whoami`} 2208 $argv[1,-2]; }
|
||||||
kirua() { ssc kirua.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
kirua() { ssc kirua.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
kurapika() { ssc kurapika.kujiu.org ${argv[-1]:-`whoami`} 2242 $argv[1,-2]; }
|
kurapika() { ssc kurapika.kujiu.org ${argv[-1]:-`whoami`} 2242 $argv[1,-2]; }
|
||||||
leorio() { ssc leorio.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
leorio() { ssc leorio.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
ellcrys() { ssc ellcrys.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
ellcrys() { ssc ellcrys.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
|
bisuke() { ssc bisuke.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
|
goreinu() { ssc goreinu.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
|
pakunoda() { ssc pakunoda.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
|
hisoka() { ssc hisoka.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
|
||||||
|
|
||||||
DEBEMAIL="christophe@buffenoir.org"
|
hl() { highlight --out-format=xterm256 -l ${argv} | less -R; }
|
||||||
DEBFULLNAME="Christophe Buffenoir"
|
|
||||||
export DEBEMAIL DEBFULLNAME
|
|
8
common/.zshrc-local
Normal file
8
common/.zshrc-local
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
DEBEMAIL="christophe@buffenoir.org"
|
||||||
|
DEBFULLNAME="Christophe Buffenoir"
|
||||||
|
|
||||||
|
export DEBEMAIL DEBFULLNAME
|
||||||
|
|
||||||
|
POWERLINE_DETECT_SSH="true"
|
||||||
|
#POWERLINE_FULL_CURRENT_PATH="true"
|
||||||
|
|
129
common/.zshrc-local-theme
Normal file
129
common/.zshrc-local-theme
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
# FreeAgent puts the powerline style in zsh !
|
||||||
|
|
||||||
|
if [ "$POWERLINE_DATE_FORMAT" = "" ]; then
|
||||||
|
POWERLINE_DATE_FORMAT=%D{%Y-%m-%d}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_RIGHT_B" = "" ]; then
|
||||||
|
POWERLINE_RIGHT_B=%D{%H:%M:%S}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_RIGHT_A" = "mixed" ]; then
|
||||||
|
POWERLINE_RIGHT_A=%(?."$POWERLINE_DATE_FORMAT".%F{red}✘ %?)
|
||||||
|
elif [ "$POWERLINE_RIGHT_A" = "exit-status" ]; then
|
||||||
|
POWERLINE_RIGHT_A=%(?.%F{green}✔ %?.%F{red}✘ %?)
|
||||||
|
elif [ "$POWERLINE_RIGHT_A" = "date" ]; then
|
||||||
|
POWERLINE_RIGHT_A="$POWERLINE_DATE_FORMAT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_HIDE_USER_NAME" = "" ] && [ "$POWERLINE_HIDE_HOST_NAME" = "" ]; then
|
||||||
|
POWERLINE_USER_NAME="%n@%M"
|
||||||
|
elif [ "$POWERLINE_HIDE_USER_NAME" != "" ] && [ "$POWERLINE_HIDE_HOST_NAME" = "" ]; then
|
||||||
|
POWERLINE_USER_NAME="@%M"
|
||||||
|
elif [ "$POWERLINE_HIDE_USER_NAME" = "" ] && [ "$POWERLINE_HIDE_HOST_NAME" != "" ]; then
|
||||||
|
POWERLINE_USER_NAME="%n"
|
||||||
|
else
|
||||||
|
POWERLINE_USER_NAME=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
POWERLINE_CURRENT_PATH="%d"
|
||||||
|
|
||||||
|
if [ "$POWERLINE_FULL_CURRENT_PATH" = "" ]; then
|
||||||
|
POWERLINE_CURRENT_PATH="%1~"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_CLEAN" = "" ]; then
|
||||||
|
POWERLINE_GIT_CLEAN="✔"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_DIRTY" = "" ]; then
|
||||||
|
POWERLINE_GIT_DIRTY="✘"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_ADDED" = "" ]; then
|
||||||
|
POWERLINE_GIT_ADDED="%F{green}✚%F{black}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_MODIFIED" = "" ]; then
|
||||||
|
POWERLINE_GIT_MODIFIED="%F{blue}✹%F{black}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_DELETED" = "" ]; then
|
||||||
|
POWERLINE_GIT_DELETED="%F{red}✖%F{black}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_UNTRACKED" = "" ]; then
|
||||||
|
POWERLINE_GIT_UNTRACKED="%F{yellow}✭%F{black}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_RENAMED" = "" ]; then
|
||||||
|
POWERLINE_GIT_RENAMED="➜"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_GIT_UNMERGED" = "" ]; then
|
||||||
|
POWERLINE_GIT_UNMERGED="═"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ZSH_THEME_GIT_PROMPT_PREFIX=" \ue0a0 "
|
||||||
|
ZSH_THEME_GIT_PROMPT_SUFFIX=""
|
||||||
|
ZSH_THEME_GIT_PROMPT_DIRTY=" $POWERLINE_GIT_DIRTY"
|
||||||
|
ZSH_THEME_GIT_PROMPT_CLEAN=" $POWERLINE_GIT_CLEAN"
|
||||||
|
|
||||||
|
ZSH_THEME_GIT_PROMPT_ADDED=" $POWERLINE_GIT_ADDED"
|
||||||
|
ZSH_THEME_GIT_PROMPT_MODIFIED=" $POWERLINE_GIT_MODIFIED"
|
||||||
|
ZSH_THEME_GIT_PROMPT_DELETED=" $POWERLINE_GIT_DELETED"
|
||||||
|
ZSH_THEME_GIT_PROMPT_UNTRACKED=" $POWERLINE_GIT_UNTRACKED"
|
||||||
|
ZSH_THEME_GIT_PROMPT_RENAMED=" $POWERLINE_GIT_RENAMED"
|
||||||
|
ZSH_THEME_GIT_PROMPT_UNMERGED=" $POWERLINE_GIT_UNMERGED"
|
||||||
|
ZSH_THEME_GIT_PROMPT_AHEAD=" ⬆"
|
||||||
|
ZSH_THEME_GIT_PROMPT_BEHIND=" ⬇"
|
||||||
|
ZSH_THEME_GIT_PROMPT_DIVERGED=" ⬍"
|
||||||
|
|
||||||
|
# if [ "${vcs_info_msg_0_}" = "" ]; then
|
||||||
|
# POWERLINE_GIT_INFO_LEFT=""
|
||||||
|
# POWERLINE_GIT_INFO_RIGHT=""
|
||||||
|
# else
|
||||||
|
if [ "$POWERLINE_SHOW_GIT_ON_RIGHT" = "" ]; then
|
||||||
|
if [ "$POWERLINE_HIDE_GIT_PROMPT_STATUS" = "" ]; then
|
||||||
|
POWERLINE_GIT_INFO_LEFT=" %F{blue}%K{white}"$'\ue0b0'"%F{white}%F{black}%K{white}"$'${vcs_info_msg_0_}$(git_prompt_status)%F{white}'
|
||||||
|
else
|
||||||
|
POWERLINE_GIT_INFO_LEFT=" %F{blue}%K{white}"$'\ue0b0'"%F{white}%F{black}%K{white}"$'${vcs_info_msg_0_}%F{white}'
|
||||||
|
fi
|
||||||
|
POWERLINE_GIT_INFO_RIGHT=""
|
||||||
|
else
|
||||||
|
POWERLINE_GIT_INFO_LEFT=""
|
||||||
|
POWERLINE_GIT_INFO_RIGHT="%F{white}"$'\ue0b2'"%F{black}%K{white}"$'${vcs_info_msg_0_}'" %K{white}"
|
||||||
|
fi
|
||||||
|
# fi
|
||||||
|
|
||||||
|
if [ $(id -u) -eq 0 ]; then
|
||||||
|
POWERLINE_SEC1_BG=%K{red}
|
||||||
|
POWERLINE_SEC1_FG=%F{red}
|
||||||
|
else
|
||||||
|
POWERLINE_SEC1_BG=%K{green}
|
||||||
|
POWERLINE_SEC1_FG=%F{green}
|
||||||
|
fi
|
||||||
|
POWERLINE_SEC1_TXT=%F{black}
|
||||||
|
if [ "$POWERLINE_DETECT_SSH" != "" ]; then
|
||||||
|
if [ -n "$SSH_CLIENT" ]; then
|
||||||
|
POWERLINE_SEC1_BG=%K{red}
|
||||||
|
POWERLINE_SEC1_FG=%F{red}
|
||||||
|
POWERLINE_SEC1_TXT=%F{white}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
PROMPT="$POWERLINE_SEC1_BG$POWERLINE_SEC1_TXT $POWERLINE_USER_NAME %k%f$POWERLINE_SEC1_FG%K{blue}"$'\ue0b0'"%k%f%F{white}%K{blue} "$POWERLINE_CURRENT_PATH"%F{blue}"$POWERLINE_GIT_INFO_LEFT" %k"$'\ue0b0'"%f "
|
||||||
|
|
||||||
|
if [ "$POWERLINE_NO_BLANK_LINE" = "" ]; then
|
||||||
|
PROMPT="
|
||||||
|
"$PROMPT
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POWERLINE_DISABLE_RPROMPT" = "" ]; then
|
||||||
|
if [ "$POWERLINE_RIGHT_A" = "" ]; then
|
||||||
|
RPROMPT="$POWERLINE_GIT_INFO_RIGHT%F{white}"$'\ue0b2'"%k%F{black}%K{white} $POWERLINE_RIGHT_B %f%k"
|
||||||
|
else
|
||||||
|
RPROMPT="$POWERLINE_GIT_INFO_RIGHT%F{white}"$'\ue0b2'"%k%F{black}%K{white} $POWERLINE_RIGHT_B %f%F{240}"$'\ue0b2'"%f%k%K{240}%F{255} $POWERLINE_RIGHT_A %f%k"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
zstyle ':vcs_info:*' formats "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}%s %r/%S %b %m%u%c$ZSH_THEME_GIT_PROMPT_SUFFIX"
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue