New conf for zsh (powerline)

This commit is contained in:
Christophe Buffenoir 2013-05-02 18:11:33 +02:00
parent 16b4350cdb
commit c98bf2e7a6
102 changed files with 9836 additions and 98 deletions

25
common/.local/bin/powerline Executable file
View 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'))

View 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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,4 @@
[docs]
Sphinx

View 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. Wont 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()

View File

@ -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))

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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]"

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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
)

View File

@ -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"]
]
}
}

View File

@ -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" }
}
}

View File

@ -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" }
}
}

View File

@ -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" }
}
}

View File

@ -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" }
}
}

View File

@ -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"] }
}
}
}
}

View File

@ -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"] }
}
}
}
}

View File

@ -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" }
}
}

View File

@ -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"
}
}
}

View File

@ -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"]
}
]
}
}

View File

@ -0,0 +1,13 @@
{
"default_module": "powerline.segments.common",
"segments": {
"left": [
{
"type": "string",
"contents": "",
"width": "auto",
"highlight_group": ["prompt"]
}
]
}
}

View File

@ -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"]
}
]
}
}

View File

@ -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"]
}
]
}
}

View File

@ -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"
}
]
}
}

View File

@ -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"
}
]
}
}

View File

@ -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"
}
]
}
}

View File

@ -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"
}
]
}
}

View File

@ -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"
}
]
}
}

View File

@ -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"
}
]
}
}

View File

@ -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"
}
]
}
}

View File

@ -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": ""
}
}
]
}
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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'

View File

@ -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)

View File

@ -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

View File

@ -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'])

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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'

View 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 '')

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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)

View File

@ -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

View File

@ -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``.
''')

View 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

View 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()

View 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() wont throw). Wont 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

View File

@ -1,11 +1,13 @@
# Path to your oh-my-zsh configuration.
ZSH=$HOME/.oh-my-zsh
export TERM="xterm-256color"
# Set name of the theme to load.
# Look in ~/.oh-my-zsh/themes/
# Optionally, if you set this to "random", it'll load a random theme each
# time that oh-my-zsh is loaded.
ZSH_THEME="robbyrussell"
#ZSH_THEME="robbyrussell"
# Example aliases
# alias zshconfig="mate ~/.zshrc"
@ -24,23 +26,37 @@ ZSH_THEME="robbyrussell"
# DISABLE_AUTO_TITLE="true"
# 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/*)
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# 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 ~/.zshrc-local
source ~/.zshrc-local-theme
autoload -Uz promptinit
promptinit
prompt fire
autoload -U zsh-mime-setup
autoload -U zsh-mime-handler
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 gcc='colorgcc'
@ -70,15 +86,17 @@ function cd() {
# Customize to your needs...
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]; }
gon() { ssc gon.kujiu.org ${argv[-1]:-`whoami`} 2208 $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]; }
leorio() { ssc leorio.kujiu.org ${argv[-1]:-`whoami`} 22 $argv[1,-2]; }
ellcrys() { ssc ellcrys.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]; }
kirua() { ssc kirua.kujiu.org ${argv[-1]:-`whoami`} 22 $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]; }
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"
DEBFULLNAME="Christophe Buffenoir"
export DEBEMAIL DEBFULLNAME
hl() { highlight --out-format=xterm256 -l ${argv} | less -R; }

8
common/.zshrc-local Normal file
View 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
View 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