diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:40:16 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:40:16 +0000 |
commit | 3f25952c13d5847d510c0cae22a8ba876638d570 (patch) | |
tree | 02f505f016ed5a1029277dcae520d5e2a75906fb | |
parent | Initial commit. (diff) | |
download | powerline-3f25952c13d5847d510c0cae22a8ba876638d570.tar.xz powerline-3f25952c13d5847d510c0cae22a8ba876638d570.zip |
Adding upstream version 2.8.3.upstream/2.8.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
381 files changed, 40787 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..94eab89 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# editorconfig ini file +# Check out http://editorconfig.org for a list of plugins for different +# IDEs/text editors that support this file. Vim plugin to support this: +# +# http://www.vim.org/scripts/script.php?script_id=3934 +# https://github.com/editorconfig/editorconfig-vim +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = tab +# Despite promise somewhere alignment is done only using tabs. Thus setting +# indent_size and tab_width is a requirement. +indent_size = 4 +tab_width = 4 +charset = utf-8 + +[*.rst] +indent_style = space diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e307485 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.rst whitespace=-blank-at-eol diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 0000000..ea7f7f9 --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,46 @@ +name: Build and Publish to PyPI + +on: + push: + branches: + - master + - develop + - feature/actions + pull_request: + branches: + - develop + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + - name: Build + run: | + python setup.py sdist bdist_wheel + + - name: Publish + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} + packages_dir: dist/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6491a77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +tags + +*.py[co] +__pycache__ + +*.egg +*.egg-info +dist +build + +message.fail + +/client/powerline + +/tests/tmp +/tests/status diff --git a/.local.vimrc b/.local.vimrc new file mode 100644 index 0000000..c8e1ef3 --- /dev/null +++ b/.local.vimrc @@ -0,0 +1,11 @@ +" Project vimrc file. To be sourced each time you open any file in this +" repository. You may use [vimscript #3393][1] [(homepage)][2] to do this +" automatically. +" +" [1]: http://www.vim.org/scripts/script.php?script_id=3393 +" [2]: https://github.com/thinca/vim-localrc +let g:syntastic_python_flake8_args = '--ignore=W191,E501,E128,W291,E126,E101' +let b:syntastic_checkers = ['flake8'] +unlet! g:python_space_error_highlight +let g:pymode_syntax_indent_errors = 0 +let g:pymode_syntax_space_errors = 0 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..57ef8e2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,32 @@ +sudo: false +dist: trusty +cache: + directories: + - $HOME/.cache/pip + - tests/bot-ci +addons: + apt: + packages: + - libssl1.0.0 + - zsh + - tcsh + - mksh + - busybox + # - rc + - socat + - bc +language: python +install: tests/install.sh +script: tests/test.sh +jobs: + include: + - stage: PyPy + python: "pypy" + - python: "pypy3" + - stage: Latest Python + python: "3.6" + - stage: Intermediate versions + python: "3.5" + - python: "3.4" + +# vim: et diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..3792b70 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,138 @@ +***************** +How to contribute +***************** + +So you want to contribute to the Powerline project? Awesome! This document +describes the guidelines you should follow when making contributions to the +project. + +**Please note that these guidelines aren't mandatory in any way, but your +pull request will be merged a lot faster if you follow them.** + +Getting started +=============== + +* Make sure you have a `GitHub account <https://github.com/signup/free>`_. +* Submit an `issue on GitHub <https://github.com/powerline/powerline/issues>`_, + assuming one does not already exist. + + * Clearly describe the issue. + * If the issue is a bug: make sure you include steps to reproduce, and + include the earliest revision that you know has the issue. + +* Fork the repository on GitHub. + +Making changes +============== + +* Create a topic branch from where you want to base your work. + + * Powerline uses the `Git Flow + <http://nvie.com/posts/a-successful-git-branching-model/>`_ branching + model. + * Most contributions should be based off the ``develop`` branch. + * Prefix your branch with ``feature/`` if you're working on a new feature. + * Include the issue number in your topic branch, e.g. + ``321-fix-some-error`` or ``feature/123-a-cool-feature``. + +* Make commits of logical units. +* Run your code through ``flake8`` and fix any programming style errors. Use + common sense regarding whitespace warnings, not all warnings need to be + fixed. +* Make sure your commit messages are in the `proper format + <http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html>`_. + The summary must be no longer than 70 characters. Refer to any related + issues with e.g. ``Ref #123`` or ``Fixes #234`` at the bottom of the + commit message. Commit messages can use Markdown with the following + exceptions: + + * No HTML extensions. + * Only indented code blocks (no ``````` blocks). + * Long links should be moved to the bottom if they make the text wrap or + extend past 72 columns. + +* Make sure you have added the necessary tests for your changes. +* Run *all* the tests to assure nothing else was accidentally broken. + +Programming style +----------------- + +* The project uses *tabs for indentation* and *spaces for alignment*, this + is also included in a vim modeline on top of every script file. +* Run your code through ``flake8 --ignore=W191,E501,E128,W291,E126,E101`` to fix + any style errors. Use common sense regarding whitespace warnings, not all + ``flake8`` warnings need to be fixed. +* Trailing whitespace to indicate a continuing paragraph is OK in comments, + documentation and commit messages. +* It is allowed to have too long lines. It is advised though to avoid lines + wider then a hundred of characters. +* Imports have the following structure: + + 1. Shebang and modeline in a form + + .. code-block:: python + + #!/usr/bin/env python + # vim:fileencoding=utf-8:noet + + . Modeline is required, shebang is not. If shebang is present file must end + with + + .. code-block:: python + + if __name__ == '__main__': + # Actual script here + + 2. Module docstring. + 3. ``__future__`` import exactly in a form + + .. code-block:: python + + from __future__ import (unicode_literals, division, absolute_import, print_function) + + (powerline.shell is the only exception due to problems with argparse). It + is not separated by newline with shebang and modeline, but is with + docstring. + 4. Standard python library imports in a form ``import X``. + 5. Standard python library imports in a form ``from X import Y``. + 6. Third-party (non-python and non-powerline) library imports in a form + ``import X``. + 7. Third-party library imports in a form ``from X import Y``. + 8. Powerline non-test imports in a form ``from powerline.X import Y``. + 9. Powerline test imports in a form ``import tests.vim as vim_module``. + 10. Powerline test imports in a form ``from tests.X import Y``. + + Each entry is separated by newline from another entry. Any entry except for + the first and third ones is optional. Example with all entries: + + .. code-block:: python + + #!/usr/bin/env python + # vim:fileencoding=utf-8:noet + + '''Powerline super module''' + + from __future__ import (unicode_literals, division, absolute_import, print_function) + + import sys + + from argparse import ArgumentParser + + import psutil + + from colormath.color_diff import delta_e_cie2000 + + from powerline.lib.unicode import u + + import tests.vim as vim_module + + from tests import TestCase + +Submitting changes +================== + +* Push your changes to a topic branch in your fork of the repository. +* If necessary, use ``git rebase -i <revision>`` to squash or reword commits + before submitting a pull request. +* Submit a pull request to `powerline repository + <https://github.com/powerline/powerline>`_. @@ -0,0 +1,21 @@ +Copyright 2013 Kim Silkebækken and other contributors +https://github.com/powerline/powerline + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..1ebcf9c --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,8 @@ +recursive-include powerline *.json *.vim +recursive-include powerline/bindings *.* +recursive-exclude powerline/bindings *.pyc *.pyo +recursive-include powerline/dist *.* +recursive-include client *.* +recursive-include docs/source *.rst *.py +include docs/Makefile +include LICENSE diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..0c37ac2 --- /dev/null +++ b/README.rst @@ -0,0 +1,120 @@ +Powerline +========= + +.. image:: https://api.travis-ci.org/powerline/powerline.svg?branch=develop + :target: `travis-build-status`_ + :alt: Build status +.. _travis-build-status: https://travis-ci.org/powerline/powerline + +**Powerline is a statusline plugin for vim, and provides statuslines and +prompts for several other applications, including zsh, bash, fish, tmux, +IPython, Awesome, i3 and Qtile.** + ++---------+---------------------------------------------------+ +| Author | Kim Silkebækken (kim.silkebaekken+vim@gmail.com) | ++---------+---------------------------------------------------+ +| Source | https://github.com/powerline/powerline | ++---------+---------------------------------------------------+ +| Version | beta | ++---------+---------------------------------------------------+ + +**Powerline does not support python2 anymore and powerline will stop working with python2 in the near future.** + +Features +-------- + +* **Extensible and feature rich, written in Python.** Powerline was + completely rewritten in Python to get rid of as much vimscript as + possible. This has allowed much better extensibility, leaner and better + config files, and a structured, object-oriented codebase with no mandatory + third-party dependencies other than a Python interpreter. +* **Stable and testable code base.** Using Python has allowed unit testing + of all the project code. The code is tested to work in Python 3.6+. +* **Support for prompts and statuslines in many applications.** Originally + created exclusively for vim statuslines, the project has evolved to + provide statuslines in tmux and several WMs, and prompts for shells like + bash/zsh and other applications. It’s simple to write renderers for any + other applications that Powerline doesn’t yet support. +* **Configuration and colorschemes written in JSON.** JSON is + a standardized, simple and easy to use file format that allows for easy + user configuration across all of Powerline’s supported applications. +* **Fast and lightweight, with daemon support for even better performance.** + Although the code base spans a couple of thousand lines of code with no + goal of “less than X lines of code”, the main focus is on good performance + and as little code as possible while still providing a rich set of + features. The new daemon also ensures that only one Python instance is + launched for prompts and statuslines, which provides excellent + performance. + +*But I hate Python / I don’t need shell prompts / this is just too much +hassle for me / what happened to the original vim-powerline project / …* + +You should check out some of the Powerline derivatives. The most lightweight +and feature-rich alternative is currently the `vim-airline +<https://github.com/vim-airline/vim-airline>`_ project. + +Configuration +------------- + +Basic powerline configuration is done via `JSON` files located at `.config/powerline/`. It is a good idea to start by copying the default configuration located at `powerline_root/powerline/config_files/` to `.config/powerline/`. +If you installed the powerline from the AUR or via pip, `powerline_root` should be `/usr/lib/python3.6/site-packages/` or something similar, depending on your python version. + +If you installed powerline via apt-get 'powerline_root' should be '/usr/share/powerline/'. + +This should yield you the following directory structure: + + :: + + .config/powerline/ + ├── colorschemes + │ ├── ... + │ └── wm + | └── default.json // Your configuration goes here + ├── colors.json + ├── config.json + └── themes + ├── ... + └── wm + └── default.json // Your configuration goes here + + + +The files in the subdirectories of `themes` are used to specify which segments shall be shown; the files in subdirectories of `colorschemes` are used to specify which colors (as defined in `colors.json`) shall be used to display a segment. + +Note that your local configuration only overrides the global configuration, it does not replace it, i.e. if you don't configure something locally, the global default will be used instead. + +* Consult the `documentation <https://powerline.readthedocs.org/en/latest/configuration.html#quick-setup-guide>`_ for more details. See also the `segment reference <https://powerline.readthedocs.org/en/latest/configuration/segments.html>`_ for available segments and their configuration. +* Check out `powerline-fonts <https://github.com/powerline/fonts>`_ for + pre-patched versions of popular, open source coding fonts. + +Screenshots +----------- + +Vim statusline +^^^^^^^^^^^^^^ + +**Mode-dependent highlighting** + +* .. image:: https://raw.github.com/powerline/powerline/develop/docs/source/_static/img/pl-mode-normal.png + :alt: Normal mode +* .. image:: https://raw.github.com/powerline/powerline/develop/docs/source/_static/img/pl-mode-insert.png + :alt: Insert mode +* .. image:: https://raw.github.com/powerline/powerline/develop/docs/source/_static/img/pl-mode-visual.png + :alt: Visual mode +* .. image:: https://raw.github.com/powerline/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/powerline/powerline/develop/docs/source/_static/img/pl-truncate1.png + :alt: Truncation illustration +* .. image:: https://raw.github.com/powerline/powerline/develop/docs/source/_static/img/pl-truncate2.png + :alt: Truncation illustration +* .. image:: https://raw.github.com/powerline/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/shop/fonts/pragmatapro diff --git a/client/powerline.c b/client/powerline.c new file mode 100644 index 0000000..ff107ec --- /dev/null +++ b/client/powerline.c @@ -0,0 +1,164 @@ +/* vim:fileencoding=utf-8:noet + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <sys/un.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#define HANDLE_ERROR(msg) \ + do { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define TEMP_FAILURE_RETRY(var, expression) \ + do { \ + ptrdiff_t __result; \ + do { \ + __result = (expression); \ + } while (__result == -1L && errno == EINTR); \ + var = __result; \ + } while (0) + +extern char **environ; + +void do_write(int sd, const char *raw, size_t len) { + size_t written = 0; + ptrdiff_t n = -1; + + while (written < len) { + TEMP_FAILURE_RETRY(n, write(sd, raw + written, len - written)); + if (n == -1) { + close(sd); + HANDLE_ERROR("write() failed"); + } + written += (size_t) n; + } +} + +static inline size_t true_sun_len(const struct sockaddr_un *ptr) { +#ifdef __linux__ + /* Because SUN_LEN uses strlen and abstract namespace paths begin + * with a null byte, SUN_LEN is broken for these. Passing the full + * struct size also fails on Linux, so compute manually. The + * abstract namespace is Linux-only. */ + if (ptr->sun_path[0] == '\0') { + return sizeof(ptr->sun_family) + strlen(ptr->sun_path + 1) + 1; + } +#endif +#ifdef SUN_LEN + /* If the vendor provided SUN_LEN, we may as well use it. */ + return SUN_LEN(ptr); +#else + /* SUN_LEN is not POSIX, so if it was not provided, use the struct + * size as a fallback. */ + return sizeof(struct sockaddr_un); +#endif +} + +#ifdef __linux__ +# define ADDRESS_TEMPLATE "powerline-ipc-%d" +# define A +1 +#else +# define ADDRESS_TEMPLATE "/tmp/powerline-ipc-%d" +# define A +#endif + +#define ADDRESS_SIZE sizeof(ADDRESS_TEMPLATE) + (sizeof(uid_t) * 4) +#define NUM_ARGS_SIZE (sizeof(int) * 2 + 1) +#define BUF_SIZE 4096 +#define NEW_ARGV_SIZE 200 + +int main(int argc, char *argv[]) { + int sd = -1; + int i; + ptrdiff_t read_size; + struct sockaddr_un server; + char address_buf[ADDRESS_SIZE]; + const char eof[2] = "\0\0"; + char num_args[NUM_ARGS_SIZE]; + char buf[BUF_SIZE]; + char *newargv[NEW_ARGV_SIZE]; + char *wd = NULL; + char **envp; + const char *address; + int len; + + if (argc < 2) { + printf("Must provide at least one argument.\n"); + return EXIT_FAILURE; + } + + if (argc > 3 && strcmp(argv[1], "--socket") == 0) { + address = argv[2]; + argv += 2; + argc -= 2; + } else { + snprintf(address_buf, ADDRESS_SIZE, ADDRESS_TEMPLATE, getuid()); + address = &(address_buf[0]); + } + + sd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sd == -1) + HANDLE_ERROR("socket() failed"); + + memset(&server, 0, sizeof(struct sockaddr_un)); + server.sun_family = AF_UNIX; + strncpy(server.sun_path A, address, strlen(address)); + + if (connect(sd, (struct sockaddr *) &server, true_sun_len(&server)) < 0) { + close(sd); + /* We failed to connect to the daemon, execute powerline instead */ + argc = (argc < NEW_ARGV_SIZE - 1) ? argc : NEW_ARGV_SIZE - 1; + for (i = 1; i < argc; i++) + newargv[i] = argv[i]; + newargv[0] = "powerline-render"; + newargv[argc] = NULL; + execvp("powerline-render", newargv); + } + + len = snprintf(num_args, NUM_ARGS_SIZE, "%x", argc - 1); + do_write(sd, num_args, len); + do_write(sd, eof, 1); + + for (i = 1; i < argc; i++) { + do_write(sd, argv[i], strlen(argv[i])); + do_write(sd, eof, 1); + } + + wd = getcwd(NULL, 0); + if (wd != NULL) { + do_write(sd, wd, strlen(wd)); + free(wd); + wd = NULL; + } + do_write(sd, eof, 1); + + for(envp=environ; *envp; envp++) { + do_write(sd, *envp, strlen(*envp)); + do_write(sd, eof, 1); + } + + do_write(sd, eof, 2); + + read_size = -1; + while (read_size != 0) { + TEMP_FAILURE_RETRY(read_size, read(sd, buf, BUF_SIZE)); + if (read_size == -1) { + close(sd); + HANDLE_ERROR("read() failed"); + } else if (read_size > 0) { + do_write(STDOUT_FILENO, buf, (size_t) read_size); + } + } + + close(sd); + + return 0; +} diff --git a/client/powerline.py b/client/powerline.py new file mode 100755 index 0000000..28492c1 --- /dev/null +++ b/client/powerline.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import socket +import errno +import os + +try: + from posix import environ +except ImportError: + from os import environ + +# XXX Hack for importing powerline modules to work. +sys.path.pop(0) + +try: + from powerline.lib.encoding import get_preferred_output_encoding +except ImportError: + sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__))))) + from powerline.lib.encoding import get_preferred_output_encoding + + +if len(sys.argv) < 2: + print('Must provide at least one argument.', file=sys.stderr) + raise SystemExit(1) + +use_filesystem = not sys.platform.lower().startswith('linux') + +if sys.argv[1] == '--socket': + address = sys.argv[2] + if not use_filesystem: + address = '\0' + address + del sys.argv[1:3] +else: + address = ('/tmp/powerline-ipc-%d' if use_filesystem else '\0powerline-ipc-%d') % os.getuid() + +sock = socket.socket(family=socket.AF_UNIX) + + +def eintr_retry_call(func, *args, **kwargs): + while True: + try: + return func(*args, **kwargs) + except EnvironmentError as e: + if getattr(e, 'errno', None) == errno.EINTR: + continue + raise + + +try: + eintr_retry_call(sock.connect, address) +except Exception: + # Run the powerline renderer + args = ['powerline-render'] + sys.argv[1:] + os.execvp('powerline-render', args) + +fenc = get_preferred_output_encoding() + + +def tobytes(s): + if isinstance(s, bytes): + return s + else: + return s.encode(fenc) + + +args = [tobytes('%x' % (len(sys.argv) - 1))] +args.extend((tobytes(s) for s in sys.argv[1:])) + + +try: + cwd = os.getcwd() +except EnvironmentError: + pass +else: + if not isinstance(cwd, bytes): + cwd = cwd.encode(fenc) + args.append(cwd) + + +args.extend((tobytes(k) + b'=' + tobytes(v) for k, v in environ.items())) + +EOF = b'\0\0' + +for a in args: + eintr_retry_call(sock.sendall, a + b'\0') + +eintr_retry_call(sock.sendall, EOF) + +received = [] +while True: + r = sock.recv(4096) + if not r: + break + received.append(r) + +sock.close() + +if sys.version_info < (3,): + sys.stdout.write(b''.join(received)) +else: + sys.stdout.buffer.write(b''.join(received)) diff --git a/client/powerline.sh b/client/powerline.sh new file mode 100755 index 0000000..ad278c2 --- /dev/null +++ b/client/powerline.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +use_filesystem=1 +darwin= +if test -n "$OSTYPE" ; then + # OSTYPE variable is a shell feature. supported by bash and zsh, but not + # dash, busybox or (m)ksh. + if test "${OSTYPE#linux}" '!=' "${OSTYPE}" ; then + use_filesystem= + elif test "${OSTYPE#darwin}" ; then + darwin=1 + fi +elif command -v uname >/dev/null ; then + if uname -o | grep -iqF linux ; then + use_filesystem= + elif uname -o | grep -iqF darwin ; then + darwin=1 + fi +fi + +if test "$1" = "--socket" ; then + shift + ADDRESS="$1" + shift +else + ADDRESS="powerline-ipc-${UID:-`id -u`}" + test -n "$use_filesystem" && ADDRESS="/tmp/$ADDRESS" +fi + +if test -n "$darwin" ; then + ENV=genv +else + ENV=env +fi + +if test -z "$use_filesystem" ; then + ADDRESS="abstract-client:$ADDRESS" +fi + +# Warning: env -0 does not work in busybox. Consider switching to parsing +# `set` output in this case +( + printf '%x\0' "$#" + for argv in "$@" ; do + printf '%s\0' "$argv" + done + printf '%s\0' "$PWD" + $ENV -0 +) 2>/dev/null | socat -lf/dev/null -t 10 - "$ADDRESS" + +if test $? -ne 0 ; then + powerline-render "$@" +fi diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..3b41221 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,39 @@ +# Makefile for Sphinx documentation +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -T -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +GH_PAGES_SOURCES = source Makefile +GH_SOURCE_BRANCH = develop + +.PHONY: html clean html latexpdf + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + +clean: + -rm -rf $(BUILDDIR)/* + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." diff --git a/docs/source/_static/css/theme_overrides.css b/docs/source/_static/css/theme_overrides.css new file mode 100644 index 0000000..7e39e34 --- /dev/null +++ b/docs/source/_static/css/theme_overrides.css @@ -0,0 +1,6 @@ +.wy-table-responsive > table > tbody > tr > td { + white-space: unset; +} +.wy-table-responsive > table > tbody > tr > td:first-child { + vertical-align: top; +} diff --git a/docs/source/_static/img/icons/cross.png b/docs/source/_static/img/icons/cross.png Binary files differnew file mode 100644 index 0000000..33a3837 --- /dev/null +++ b/docs/source/_static/img/icons/cross.png diff --git a/docs/source/_static/img/icons/error.png b/docs/source/_static/img/icons/error.png Binary files differnew file mode 100644 index 0000000..dbfda22 --- /dev/null +++ b/docs/source/_static/img/icons/error.png diff --git a/docs/source/_static/img/icons/tick.png b/docs/source/_static/img/icons/tick.png Binary files differnew file mode 100644 index 0000000..c277e6b --- /dev/null +++ b/docs/source/_static/img/icons/tick.png diff --git a/docs/source/_static/img/pl-mode-insert.png b/docs/source/_static/img/pl-mode-insert.png Binary files differnew file mode 100644 index 0000000..9b09e18 --- /dev/null +++ b/docs/source/_static/img/pl-mode-insert.png diff --git a/docs/source/_static/img/pl-mode-normal.png b/docs/source/_static/img/pl-mode-normal.png Binary files differnew file mode 100644 index 0000000..29d3716 --- /dev/null +++ b/docs/source/_static/img/pl-mode-normal.png diff --git a/docs/source/_static/img/pl-mode-replace.png b/docs/source/_static/img/pl-mode-replace.png Binary files differnew file mode 100644 index 0000000..d7c89a4 --- /dev/null +++ b/docs/source/_static/img/pl-mode-replace.png diff --git a/docs/source/_static/img/pl-mode-visual.png b/docs/source/_static/img/pl-mode-visual.png Binary files differnew file mode 100644 index 0000000..d654763 --- /dev/null +++ b/docs/source/_static/img/pl-mode-visual.png diff --git a/docs/source/_static/img/pl-truncate1.png b/docs/source/_static/img/pl-truncate1.png Binary files differnew file mode 100644 index 0000000..c687502 --- /dev/null +++ b/docs/source/_static/img/pl-truncate1.png diff --git a/docs/source/_static/img/pl-truncate2.png b/docs/source/_static/img/pl-truncate2.png Binary files differnew file mode 100644 index 0000000..1630f1d --- /dev/null +++ b/docs/source/_static/img/pl-truncate2.png diff --git a/docs/source/_static/img/pl-truncate3.png b/docs/source/_static/img/pl-truncate3.png Binary files differnew file mode 100644 index 0000000..83e5b21 --- /dev/null +++ b/docs/source/_static/img/pl-truncate3.png diff --git a/docs/source/commands.rst b/docs/source/commands.rst new file mode 100644 index 0000000..a35d05f --- /dev/null +++ b/docs/source/commands.rst @@ -0,0 +1,9 @@ +************************************** +Powerline shell commands’ manual pages +************************************** + +.. toctree:: + :maxdepth: 1 + :glob: + + commands/* diff --git a/docs/source/commands/config.rst b/docs/source/commands/config.rst new file mode 100644 index 0000000..3fc25aa --- /dev/null +++ b/docs/source/commands/config.rst @@ -0,0 +1,12 @@ +:orphan: + +powerline-config manual page +============================ + +.. automan:: powerline.commands.config + :prog: powerline-config + +See also +-------- + +:manpage:`powerline(1)` diff --git a/docs/source/commands/daemon.rst b/docs/source/commands/daemon.rst new file mode 100644 index 0000000..d899c73 --- /dev/null +++ b/docs/source/commands/daemon.rst @@ -0,0 +1,12 @@ +:orphan: + +powerline-daemon manual page +============================ + +.. automan:: powerline.commands.daemon + :prog: powerline-daemon + +See also +-------- + +:manpage:`powerline(1)` diff --git a/docs/source/commands/lint.rst b/docs/source/commands/lint.rst new file mode 100644 index 0000000..92d676d --- /dev/null +++ b/docs/source/commands/lint.rst @@ -0,0 +1,14 @@ +:orphan: + +.. _command-powerline-lint: + +powerline-lint manual page +========================== + +.. automan:: powerline.commands.lint + :prog: powerline-lint + +See also +-------- + +:manpage:`powerline(1)`, :manpage:`powerline-config(1)` diff --git a/docs/source/commands/main.rst b/docs/source/commands/main.rst new file mode 100644 index 0000000..178bcb9 --- /dev/null +++ b/docs/source/commands/main.rst @@ -0,0 +1,12 @@ +:orphan: + +powerline manual page +===================== + +.. automan:: powerline.commands.main + :prog: powerline + +See also +-------- + +:manpage:`powerline-daemon(1)`, :manpage:`powerline-config(1)` diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..5577ef6 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,70 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import sys + + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(os.getcwd())))) +sys.path.insert(0, os.path.abspath(os.getcwd())) + +extensions = [ + 'powerline_autodoc', 'powerline_automan', + 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', +] +source_suffix = '.rst' +master_doc = 'index' +project = 'Powerline' +version = 'beta' +release = 'beta' +exclude_patterns = ['_build'] +pygments_style = 'sphinx' + +html_theme = 'default' +html_static_path = ['_static'] +html_show_copyright = False + +latex_show_urls = 'footnote' +latex_elements = { + 'preamble': ''' + \\DeclareUnicodeCharacter{22EF}{$\\cdots$} % Dots + \\DeclareUnicodeCharacter{2665}{\\ding{170}} % Heart + \\DeclareUnicodeCharacter{2746}{\\ding{105}} % Snow + \\usepackage{pifont} + ''', +} + +man_pages = [] +for doc in os.listdir(os.path.join(os.path.dirname(__file__), 'commands')): + if doc.endswith('.rst'): + name = doc[:-4] + module = 'powerline.commands.{0}'.format(name) + get_argparser = __import__(str(module), fromlist=[str('get_argparser')]).get_argparser + parser = get_argparser() + description = parser.description + man_pages.append([ + 'commands/' + name, + 'powerline' if name == 'main' else 'powerline-' + name, + description, + '', + 1 + ]) + +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we’re building docs locally + try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + except ImportError: + pass + +if on_rtd or html_theme == 'sphinx_rtd_theme': + html_context = { + 'css_files': [ + 'https://media.readthedocs.org/css/sphinx_rtd_theme.css', + 'https://media.readthedocs.org/css/readthedocs-doc-embed.css', + '_static/css/theme_overrides.css', + ], + } diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst new file mode 100644 index 0000000..a2be2d5 --- /dev/null +++ b/docs/source/configuration.rst @@ -0,0 +1,151 @@ +******************************* +Configuration and customization +******************************* + +.. note:: + **Forking the main GitHub repo is not needed to personalize Powerline + configuration!** Please read through the :ref:`quick-guide` for a quick + introduction to user configuration. + +Powerline is configured with one main configuration file, and with separate +configuration files for themes and colorschemes. All configuration files are +written in JSON, with the exception of segment definitions, which are +written in Python. + +Powerline provides default configurations in the following locations: + +:ref:`Main configuration <config-main>` + :file:`{powerline}/config.json` +:ref:`Colorschemes <config-colorschemes>` + :file:`{powerline}/colorschemes/{name}.json`, + :file:`{powerline}/colorschemes/{extension}/__main__.json`, + :file:`{powerline}/colorschemes/{extension}/{name}.json` +:ref:`Themes <config-themes>` + :file:`{powerline}/themes/{top_theme}.json`, + :file:`{powerline}/themes/{extension}/__main__.json`, + :file:`{powerline}/themes/{extension}/default.json` + +Here `{powerline}` is one of the following: + +#. The default configuration directory located in the main package: + :file:`{powerline_root}/powerline/config_files`. May be absent in some + packages (e.g. when installing via Gentoo ebuilds). +#. If variable ``$XDG_CONFIG_DIRS`` is set and non-empty then to any + :file:`{directory}/powerline` where `{directory}` is a directory listed in + a colon-separated ``$XDG_CONFIG_DIRS`` list. Directories are checked in + reverse order. +#. User configuration directory located in :file:`$XDG_CONFIG_HOME/powerline`. + This usually corresponds to :file:`~/.config/powerline` on all platforms. + +If per-instance configuration is needed please refer to :ref:`Local +configuration overrides <local-configuration-overrides>`. + +.. _configuration-merging: + +.. note:: + Existing multiple configuration files that have the same name, but are placed + in different directories, will be merged. Merging happens in the order given + in the above list of possible `{powerline}` meanings. + + When merging configuration only dictionaries are merged and they are merged + recursively: keys from next file overrule those from the previous unless + corresponding values are both dictionaries in which case these dictionaries + are merged and key is assigned the result of the merge. + +.. note:: Some configuration files (i.e. themes and colorschemes) have two level + of merging: first happens merging described above, second theme- or + colorscheme-specific merging happens. + +.. _quick-guide: + +Quick setup guide +================= + +This guide will help you with the initial configuration of Powerline. + +Look at configuration in :file:`{powerline_root}/powerline/config_files`. If you +want to modify some file you can create :file:`~/.config/powerline` directory +and put modifications there: all configuration files are :ref:`merged +<configuration-merging>` with each other. + +Each extension (vim, tmux, etc.) has its own theme, and they are located in +:file:`{config directory}/themes/{extension}/default.json`. Best way to modify +it is to copy this theme as a whole, remove ``segment_data`` key with +corresponding value if present (unless you need to modify it, in which case only +modifications must be left) and do necessary modifications in the list of +segments (lists are not subject to merging: this is why you need a copy). + +If you want to move, remove or customize any of the provided segments in the +copy, you can do that by updating the segment dictionary in the theme you want +to customize. A segment dictionary looks like this: + +.. code-block:: javascript + + { + "name": "segment_name" + ... + } + +You can move the segment dictionaries around to change the segment +positions, or remove the entire dictionary to remove the segment from the +prompt or statusline. + +.. note:: It’s essential that the contents of all your configuration files + is valid JSON! It’s strongly recommended that you run your configuration + files through ``jsonlint`` after changing them. + +.. note:: + If your modifications appear not to work, run :ref:`powerline-lint script + <command-powerline-lint>`. This script should show you the location of the + error. + +Some segments need a user configuration to work properly. Here’s a couple of +segments that you may want to customize right away: + +**E-mail alert segment** + You have to set your username and password (and possibly server/port) + for the e-mail alert segment. If you’re using GMail it’s recommended + that you `generate an application-specific password + <https://accounts.google.com/IssuedAuthSubTokens>`_ for this purpose. + + Open a theme file, scroll down to the ``email_imap_alert`` segment and + set your ``username`` and ``password``. The server defaults to GMail’s + IMAP server, but you can set the server/port by adding a ``server`` and + a ``port`` argument. +**Weather segment** + The weather segment will try to find your location using a GeoIP lookup, + so unless you’re on a VPN you probably won’t have to change the location + query. + + It is using OpenWeatherMap as a provider, which can be configured with a + personal API key. These can be generated `here + <https://home.openweathermap.org/api_keys>`_ + + If you want to change the location query or the temperature unit you’ll + have to update the segment arguments. Open a theme file, scroll down to + the weather segment and update it to include unit, location query or + api key arguments: + + .. code-block:: javascript + + { + "name": "weather", + "priority": 50, + "args": { + "unit": "F", + "location_query": "oslo, norway", + "weather_api_key": "your_api_key" + } + }, + +References +========== + +.. toctree:: + :glob: + + configuration/reference + configuration/segments + configuration/listers + configuration/selectors + configuration/local diff --git a/docs/source/configuration/listers.rst b/docs/source/configuration/listers.rst new file mode 100644 index 0000000..7aaaabc --- /dev/null +++ b/docs/source/configuration/listers.rst @@ -0,0 +1,35 @@ +.. _config-listers: + +**************** +Lister reference +**************** + +Listers are special segment collections which allow to show some list of +segments for each entity in the list of entities (multiply their segments list +by a list of entities). E.g. ``powerline.listers.vim.tablister`` presented with +``powerline.segments.vim.tabnr`` and ``….file_name`` as segments will emit +segments with buffer names and tabpage numbers for each tabpage shown by vim. + +Listers appear in configuration as irregular segments having ``segment_list`` as +their type and ``segments`` key with a list of segments (a bit more details in +:ref:`Themes section of configuration reference <config-themes-segments>`). + +More information in :ref:`Writing listers <dev-listers>` section. + +Vim listers +----------- + +.. automodule:: powerline.listers.vim + :members: + +Pdb listers +----------- + +.. automodule:: powerline.listers.pdb + :members: + +i3wm listers +------------ + +.. automodule:: powerline.listers.i3wm + :members: diff --git a/docs/source/configuration/local.rst b/docs/source/configuration/local.rst new file mode 100644 index 0000000..0f3d110 --- /dev/null +++ b/docs/source/configuration/local.rst @@ -0,0 +1,260 @@ +.. _local-configuration-overrides: + +***************************** +Local configuration overrides +***************************** + +Depending on the application used it is possible to override configuration. Here +is the list: + +Vim overrides +============= + +Vim configuration can be overridden using the following options: + +.. _local-configuration-overrides-vim-config: + +``g:powerline_config_overrides`` + Dictionary, recursively merged with contents of + :file:`powerline/config.json`. + +``g:powerline_theme_overrides`` + Dictionary mapping theme names to theme overrides, recursively merged with + contents of :file:`powerline/themes/vim/{key}.json`. Note that this way some + value (e.g. segment) in a list cannot be redefined, only the whole list + itself: only dictionaries are merged recursively. + +``g:powerline_config_paths`` + Paths list (each path must be expanded, ``~`` shortcut is not supported). + Points to the list of directories which will be searched for configuration. + When this option is present, none of the other locations are searched. + +``g:powerline_no_python_error`` + If this variable is set to a true value it will prevent Powerline from reporting + an error when loaded in a copy of vim without the necessary Python support. + +``g:powerline_use_var_handler`` + This variable may be set to either 0 or 1. If it is set to 1 then Vim will + save log in ``g:powerline_log_messages`` variable in addition to whatever + was configured in :ref:`log_* options <config-common-log>`. Level is always + :ref:`log_level <config-common-log_level>`, same for format. + + .. warning:: + This variable is deprecated. Use :ref:`log_file option + <config-common-log>` in conjunction with + :py:class:`powerline.vim.VimVarHandler` class and :ref:`Vim config + overrides variable <local-configuration-overrides-vim-config>`. Using + this is also the only variant to make saving into the environment + variable the *only* place where log is saved or save into different + variable. + + .. autoclass:: powerline.vim.VimVarHandler + +.. _local-configuration-overrides-script: + +Powerline script overrides +========================== + +Powerline script has a number of options controlling powerline behavior. Here +``VALUE`` always means “some JSON object”. + +``-c KEY.NESTED_KEY=VALUE`` or ``--config-override=KEY.NESTED_KEY=VALUE`` + Overrides options from :file:`powerline/config.json`. + ``KEY.KEY2.KEY3=VALUE`` is a shortcut for ``KEY={"KEY2": {"KEY3": VALUE}}``. + Multiple options (i.e. ``-c K1=V1 -c K2=V2``) are allowed, result (in the + example: ``{"K1": V1, "K2": V2}``) is recursively merged with the contents + of the file. + + If ``VALUE`` is omitted then corresponding key will be removed from the + configuration (if it was present). + +``-t THEME_NAME.KEY.NESTED_KEY=VALUE`` or ``--theme-override=THEME_NAME.KEY.NESTED_KEY=VALUE`` + Overrides options from :file:`powerline/themes/{ext}/{THEME_NAME}.json`. + ``KEY.NESTED_KEY=VALUE`` is processed like described above, ``{ext}`` is the + first argument to powerline script. May be passed multiple times. + + If ``VALUE`` is omitted then corresponding key will be removed from the + configuration (if it was present). + +``-p PATH`` or ``--config-path=PATH`` + Sets directory where configuration should be read from. If present, no + default locations are searched for configuration. No expansions are + performed by powerline script itself, but ``-p ~/.powerline`` will likely be + expanded by the shell to something like ``-p /home/user/.powerline``. + +.. warning:: + Such overrides are suggested for testing purposes only. Use + :ref:`Environment variables overrides <local-configuration-overrides-env>` + for other purposes. + +.. _local-configuration-overrides-env: + +Environment variables overrides +=============================== + +All bindings that use ``POWERLINE_COMMAND`` environment variable support taking +overrides from environment variables. In this case overrides should look like +the following:: + + OVERRIDE='key1.key2.key3=value;key4.key5={"value":1};key6=true;key1.key7=10' + +. This will be parsed into + +.. code-block:: Python + + { + "key1": { + "key2": { + "key3": "value" + }, + "key7": 10, + }, + "key4": { + "key5": { + "value": 1, + }, + }, + "key6": True, + } + +. Rules: + +#. Environment variable must form a semicolon-separated list of key-value pairs: + ``key=value;key2=value2``. +#. Keys are always dot-separated strings that must not contain equals sign (as + well as semicolon) or start with an underscore. They are interpreted + literally and create a nested set of dictionaries: ``k1.k2.k3`` creates + ``{"k1":{"k2":{}}}`` and inside the innermost dictionary last key (``k3`` in + the example) is contained with its value. +#. Value may be empty in which case they are interpreted as an order to remove + some value: ``k1.k2=`` will form ``{"k1":{"k2":REMOVE_THIS_KEY}}`` nested + dictionary where ``k2`` value is a special value that tells + dictionary-merging function to remove ``k2`` rather then replace it with + something. +#. Value may be a JSON strings like ``{"a":1}`` (JSON dictionary), ``["a",1]`` + (JSON list), ``1`` or ``-1`` (JSON number), ``"abc"`` (JSON string) or + ``true``, ``false`` and ``null`` (JSON boolean objects and ``Null`` object + from JSON). General rule is that anything starting with a digit (U+0030 till + U+0039, inclusive), a hyphenminus (U+002D), a quotation mark (U+0022), a left + curly bracket (U+007B) or a left square bracket (U+005B) is considered to be + some JSON object, same for *exact* values ``true``, ``false`` and ``null``. +#. Any other value is considered to be literal string: ``k1=foo:bar`` parses to + ``{"k1": "foo:bar"}``. + +The following environment variables may be used for overrides according to the +above rules: + +``POWERLINE_CONFIG_OVERRIDES`` + Overrides values from :file:`powerline/config.json`. + +``POWERLINE_THEME_OVERRIDES`` + Overrides values from :file:`powerline/themes/{ext}/{key}.json`. Top-level + key is treated as a name of the theme for which overrides are used: e.g. to + disable cwd segment defined in :file:`powerline/themes/shell/default.json` + one needs to use:: + + POWERLINE_THEME_OVERRIDES=default.segment_data.cwd.display=false + +Additionally one environment variable is a usual *colon*-separated list of +directories: ``POWERLINE_CONFIG_PATHS``. This one defines paths which will be +searched for configuration. Empty paths in ``POWERLINE_CONFIG_PATHS`` are +ignored. + +.. note:: + Overrides from environment variables have lower priority then + :ref:`Powerline script overrides <local-configuration-overrides-script>`. + Latter are suggested for tests only. + +Zsh/zpython overrides +===================== + +Here overrides are controlled by similarly to the powerline script, but values +are taken from zsh variables. :ref:`Environment variable overrides +<local-configuration-overrides-env>` are also supported: if variable is a string +this variant is used. + +``POWERLINE_CONFIG_OVERRIDES`` + Overrides options from :file:`powerline/config.json`. Should be a zsh + associative array with keys equal to ``KEY.NESTED_KEY`` and values being + JSON strings. Pair ``KEY.KEY1 VALUE`` is equivalent to ``{"KEY": {"KEY1": + VALUE}}``. All pairs are then recursively merged into one dictionary and + this dictionary is recursively merged with the contents of the file. + +``POWERLINE_THEME_OVERRIDES`` + Overrides options from :file:`powerline/themes/shell/*.json`. Should be + a zsh associative array with keys equal to ``THEME_NAME.KEY.NESTED_KEY`` and + values being JSON strings. Is processed like the above + ``POWERLINE_CONFIG_OVERRIDES``, but only subdictionaries for ``THEME_NAME`` + key are merged with theme configuration when theme with given name is + requested. + +``POWERLINE_CONFIG_PATHS`` + Sets directories where configuration should be read from. If present, no + default locations are searched for configuration. No expansions are + performed by powerline script itself, but zsh usually performs them on its + own if variable without is set without quotes: ``POWERLINE_CONFIG_PATHS=( + ~/example )``. In addition to arrays usual colon-separated “array” string + can be used: ``POWERLINE_CONFIG_PATHS=$HOME/path1:$HOME/path2``. + +Ipython overrides +================= + +Ipython overrides depend on ipython version. Before ipython-0.11 additional +keyword arguments should be passed to setup() function. After ipython-0.11 +``c.Powerline.KEY`` should be used. Supported ``KEY`` strings or keyword +argument names: + +``config_overrides`` + Overrides options from :file:`powerline/config.json`. Should be a dictionary + that will be recursively merged with the contents of the file. + +``theme_overrides`` + Overrides options from :file:`powerline/themes/ipython/*.json`. Should be + a dictionary where keys are theme names and values are dictionaries which + will be recursively merged with the contents of the given theme. + +``config_paths`` + Sets directories where configuration should be read from. If present, no + default locations are searched for configuration. No expansions are + performed thus paths starting with ``~/`` cannot be used: use + :py:func:`os.path.expanduser`. + +Prompt command +============== + +In addition to the above configuration options ``$POWERLINE_COMMAND`` +environment variable can be used to tell shell or tmux to use specific powerline +implementation and ``$POWERLINE_CONFIG_COMMAND`` to tell zsh or tmux where +``powerline-config`` script is located. This is mostly useful for putting +powerline into different directory. + +.. note:: + + ``$POWERLINE_COMMAND`` is always treated as one path in shell bindings, so + path with spaces in it may be used. To specify additional arguments one may + use ``$POWERLINE_COMMAND_ARGS``, but note that this variable exists for + testing purposes only and may be removed. One should use :ref:`Environment + variable overrides <local-configuration-overrides-env>` instead. + +To disable prompt in shell, but still have tmux support or to disable tmux +support environment variables ``$POWERLINE_NO_{SHELL}_PROMPT`` and +``$POWERLINE_NO_{SHELL}_TMUX_SUPPORT`` can be used (substitute ``{SHELL}`` with +the name of the shell (all-caps) that should be affected (e.g. ``BASH``) or use +all-inclusive ``SHELL`` that will disable support for all shells). These +variables have no effect after configuration script was sourced (in fish case: +after ``powerline-setup`` function was run). To disable specific feature support +set one of these variables to some non-empty value. + +In order to keep shell prompt, but avoid launching Python twice to get unused +:ref:`above <config-themes-above>` lines in tcsh ``$POWERLINE_NO_TCSH_ABOVE`` or +``$POWERLINE_NO_SHELL_ABOVE`` variable should be set. + +In order to remove additional space from the end of the right prompt in fish +that was added in order to support multiline prompt ``$POWERLINE_NO_FISH_ABOVE`` +or ``$POWERLINE_NO_SHELL_ABOVE`` variable should be set. + +PDB overrides +============= + +Like shell bindings :ref:`PDB bindings <pdb-prompt>` take overrides from +:ref:`environment variables <local-configuration-overrides-env>`. diff --git a/docs/source/configuration/reference.rst b/docs/source/configuration/reference.rst new file mode 100644 index 0000000..d4fd4ab --- /dev/null +++ b/docs/source/configuration/reference.rst @@ -0,0 +1,602 @@ +*********************** +Configuration reference +*********************** + +.. _config-main: + +Main configuration +================== + +:Location: :file:`powerline/config.json` + +The main configuration file defines some common options that applies to all +extensions, as well as some extension-specific options like themes and +colorschemes. + +Common configuration +-------------------- + +Common configuration is a subdictionary that is a value of ``common`` key in +:file:`powerline/config.json` file. + +.. _config-common-term_truecolor: + +``term_truecolor`` + Defines whether to output cterm indices (8-bit) or RGB colors (24-bit) + to the terminal emulator. See the :ref:`term-feature-support-matrix` for + information on whether used terminal emulator supports 24-bit colors. + + This variable is forced to be ``false`` if :ref:`term_escape_style + <config-common-term_escape_style>` option is set to ``"fbterm"`` or if it is + set to ``"auto"`` and powerline detected fbterm. + +.. _config-common-term_escape_style: + +``term_escape_style`` + Defines what escapes sequences should be used. Accepts three variants: + + ======= =================================================================== + Variant Description + ======= =================================================================== + auto ``xterm`` or ``fbterm`` depending on ``$TERM`` variable value: + ``TERM=fbterm`` implies ``fbterm`` escaping style, all other values + select ``xterm`` escaping. + xterm Uses ``\e[{fb};5;{color}m`` for colors (``{fb}`` is either ``38`` + (foreground) or ``48`` (background)). Should be used for most + terminals. + fbterm Uses ``\e[{fb};{color}}`` for colors (``{fb}`` is either ``1`` + (foreground) or ``2`` (background)). Should be used for fbterm: + framebuffer terminal. + ======= =================================================================== + +.. _config-common-ambiwidth: + +``ambiwidth`` + Tells powerline what to do with characters with East Asian Width Class + Ambiguous (such as Euro, Registered Sign, Copyright Sign, Greek + letters, Cyrillic letters). Valid values: any positive integer; it is + suggested that this option is only set it to 1 (default) or 2. + +.. _config-common-watcher: + +``watcher`` + Select filesystem watcher. Variants are + + ======= =================================== + Variant Description + ======= =================================== + auto Selects most performant watcher. + inotify Select inotify watcher. Linux only. + stat Select stat-based polling watcher. + uv Select libuv-based watcher. + ======= =================================== + + Default is ``auto``. + +.. _config-common-additional_escapes: + +``additional_escapes`` + Valid for shell extensions, makes sense only if :ref:`term_truecolor + <config-common-term_truecolor>` is enabled. Is to be set from command-line. + Controls additional escaping that is needed for tmux/screen to work with + terminal true color escape codes: normally tmux/screen prevent terminal + emulator from receiving these control codes thus rendering powerline prompt + colorless. Valid values: ``"tmux"``, ``"screen"``, ``null`` (default). + +.. _config-common-paths: + +``paths`` + Defines additional paths which will be searched for modules when using + :ref:`function segment option <config-themes-seg-function>` or :ref:`Vim + local_themes option <config-ext-local_themes>`. Paths defined here have + priority when searching for modules. + +.. _config-common-log: + +``log_file`` + Defines how logs will be handled. There are three variants here: + + #. Absent. In this case logging will be done to stderr: equivalent to + ``[["logging.StreamHandler", []]]`` or ``[null]``. + #. Plain string. In this case logging will be done to the given file: + ``"/file/name"`` is equivalent to ``[["logging.FileHandler", + [["/file/name"]]]]`` or ``["/file/name"]``. Leading ``~/`` is expanded in + the file name, so using ``"~/.log/foo"`` is permitted. If directory + pointed by the option is absent, it will be created, but not its parent. + #. List of handler definitions. Handler definition may either be ``null``, + a string or a list with two or three elements: + + #. Logging class name and module. If module name is absent, it is + equivalent to ``logging.handlers``. + #. Class constructor arguments in a form ``[[args[, kwargs]]]``: accepted + variants are ``[]`` (no arguments), ``[args]`` (e.g. + ``[["/file/name"]]``: only positional arguments) or ``[args, kwargs]`` + (e.g. ``[[], {"host": "localhost", "port": 6666}]``: positional and + keyword arguments, but no positional arguments in the example). + #. Optional logging level. Overrides :ref:`log_level key + <config-common-log_level>` and has the same format. + #. Optional format string. Partially overrides :ref:`log_format key + <config-common-log_format>` and has the same format. “Partially” here + means that it may only specify more critical level. + +.. _config-common-log_level: + +``log_level`` + String, determines logging level. Defaults to ``WARNING``. + +.. _config-common-log_format: + +``log_format`` + String, determines format of the log messages. Defaults to + ``'%(asctime)s:%(level)s:%(message)s'``. + +``interval`` + Number, determines time (in seconds) between checks for changed + configuration. Checks are done in a separate thread. Use ``null`` to check + for configuration changes on ``.render()`` call in main thread. + Defaults to ``None``. + +``reload_config`` + Boolean, determines whether configuration should be reloaded at all. + Defaults to ``True``. + +.. _config-common-default_top_theme: + +``default_top_theme`` + String, determines which top-level theme will be used as the default. + Defaults to ``powerline_terminus`` in unicode locales and ``ascii`` in + non-unicode locales. See `Themes`_ section for more details. + +Extension-specific configuration +-------------------------------- + +Common configuration is a subdictionary that is a value of ``ext`` key in +:file:`powerline/config.json` file. + +``colorscheme`` + Defines the colorscheme used for this extension. + +.. _config-ext-theme: + +``theme`` + Defines the theme used for this extension. + +.. _config-ext-top_theme: + +``top_theme`` + Defines the top-level theme used for this extension. See `Themes`_ section + for more details. + +.. _config-ext-local_themes: + +``local_themes`` + Defines themes used when certain conditions are met, e.g. for + buffer-specific statuslines in vim. Value depends on extension used. For vim + it is a dictionary ``{matcher_name : theme_name}``, where ``matcher_name`` + is either ``matcher_module.module_attribute`` or ``module_attribute`` + (``matcher_module`` defaults to ``powerline.matchers.vim``) and + ``module_attribute`` should point to a function that returns boolean value + indicating that current buffer has (not) matched conditions. There is an + exception for ``matcher_name`` though: if it is ``__tabline__`` no functions + are loaded. This special theme is used for ``tabline`` Vim option. + + For shell and ipython it is a simple ``{prompt_type : theme_name}``, where + ``prompt_type`` is a string with no special meaning (specifically it does + not refer to any Python function). Shell has ``continuation``, and + ``select`` prompts with rather self-explanatory names, IPython has ``in2``, + ``out`` and ``rewrite`` prompts (refer to IPython documentation for more + details) while ``in`` prompt is the default. + + For wm (:ref:`lemonbar <lemonbar-usage>` only) it is a dictionary + ``{output : theme_name}`` that maps the ``xrandr`` output names to the + local themes to use on that output. + +.. _config-ext-components: + +``components`` + Determines which extension components should be enabled. This key is highly + extension-specific, here is the table of extensions and corresponding + components: + + +---------+----------+-----------------------------------------------------+ + |Extension|Component |Description | + +---------+----------+-----------------------------------------------------+ + |vim |statusline|Makes Vim use powerline statusline. | + | +----------+-----------------------------------------------------+ + | |tabline |Makes Vim use powerline tabline. | + +---------+----------+-----------------------------------------------------+ + |shell |prompt |Makes shell display powerline prompt. | + | +----------+-----------------------------------------------------+ + | |tmux |Makes shell report its current working directory | + | | |and screen width to tmux for tmux powerline | + | | |bindings. | + | | | | + +---------+----------+-----------------------------------------------------+ + + All components are enabled by default. + +.. _config-ext-update_interval: + +``update_interval`` + Determines how often WM status bars need to be updated, in seconds. Only + valid for WM extensions which use ``powerline-daemon``. Defaults to + 2 seconds. + +.. _config-colors: + +Color definitions +================= + +:Location: :file:`powerline/colors.json` + +.. _config-colors-colors: + +``colors`` + Color definitions, consisting of a dict where the key is the name of the + color, and the value is one of the following: + + * A cterm color index. + * A list with a cterm color index and a hex color string (e.g. ``[123, + "aabbcc"]``). This is useful for colorschemes that use colors that + aren’t available in color terminals. + +``gradients`` + Gradient definitions, consisting of a dict where the key is the name of the + gradient, and the value is a list containing one or two items, second item + is optional: + + * A list of cterm color indices. + * A list of hex color strings. + + It is expected that gradients are defined from least alert color to most + alert or non-alert colors are used. + +.. _config-colorschemes: + +Colorschemes +============ + +:Location: :file:`powerline/colorschemes/{name}.json`, + :file:`powerline/colorschemes/__main__.json`, + :file:`powerline/colorschemes/{extension}/{name}.json` + +Colorscheme files are processed in order given: definitions from each next file +override those from each previous file. It is required that either +:file:`powerline/colorschemes/{name}.json`, or +:file:`powerline/colorschemes/{extension}/{name}.json` exists. + +``name`` + Name of the colorscheme. + +.. _config-colorschemes-groups: + +``groups`` + Segment highlighting groups, consisting of a dict where the key is the + name of the highlighting group (usually the function name for function + segments), and the value is either + + #) a dict that defines the foreground color, background color and + attributes: + + ``fg`` + Foreground color. Must be defined in :ref:`colors + <config-colors-colors>`. + + ``bg`` + Background color. Must be defined in :ref:`colors + <config-colors-colors>`. + + ``attrs`` + List of attributes. Valid values are one or more of ``bold``, + ``italic`` and ``underline``. Note that some attributes may be + unavailable in some applications or terminal emulators. If no + attributes are needed this list should be left empty. + + #) a string (an alias): a name of existing group. This group’s definition + will be used when this color is requested. + +``mode_translations`` + Mode-specific highlighting for extensions that support it (e.g. the vim + extension). It’s an easy way of changing a color in a specific mode. + Consists of a dict where the key is the mode and the value is a dict + with the following options: + + ``colors`` + A dict where the key is the color to be translated in this mode, and + the value is the new color. Both the key and the value must be defined + in :ref:`colors <config-colors-colors>`. + + ``groups`` + Segment highlighting groups for this mode. Same syntax as the main + :ref:`groups <config-colorschemes-groups>` option. + +.. _config-themes: + +Themes +====== + +:Location: :file:`powerline/themes/{top_theme}.json`, + :file:`powerline/themes/{extension}/__main__.json`, + :file:`powerline/themes/{extension}/{name}.json` + +Theme files are processed in order given: definitions from each next file +override those from each previous file. It is required that file +:file:`powerline/themes/{extension}/{name}.json` exists. + +`{top_theme}` component of the file name is obtained either from :ref:`top_theme +extension-specific key <config-ext-top_theme>` or from :ref:`default_top_theme +common configuration key <config-common-default_top_theme>`. Powerline ships +with the following top themes: + +.. _config-top_themes-list: + +========================== ==================================================== +Theme Description +========================== ==================================================== +powerline Default powerline theme with fancy powerline symbols +powerline_unicode7 Theme with powerline dividers and unicode-7 symbols +unicode Theme without any symbols from private use area +unicode_terminus Theme containing only symbols from terminus PCF font +unicode_terminus_condensed Like above, but occupies as less space as possible +powerline_terminus Like unicode_terminus, but with powerline symbols +ascii Theme without any unicode characters at all +========================== ==================================================== + +``name`` + Name of the theme. + +.. _config-themes-default_module: + +``default_module`` + Python module where segments will be looked by default. Defaults to + ``powerline.segments.{ext}``. + +``spaces`` + Defines number of spaces just before the divider (on the right side) or just + after it (on the left side). These spaces will not be added if divider is + not drawn. + +``use_non_breaking_spaces`` + Determines whether non-breaking spaces should be used in place of the + regular ones. This option is needed because regular spaces are not displayed + properly when using powerline with some font configuration. Defaults to + ``True``. + + .. note:: + Unlike all other options this one is only checked once at startup using + whatever theme is :ref:`the default <config-ext-theme>`. If this option + is set in the local themes it will be ignored. This option may also be + ignored in some bindings. + +``outer_padding`` + Defines number of spaces at the end of output (on the right side) or at + the start of output (on the left side). Defaults to ``1``. + + +``dividers`` + Defines the dividers used in all Powerline extensions. + + The ``hard`` dividers are used to divide segments with different + background colors, while the ``soft`` dividers are used to divide + segments with the same background color. + +.. _config-themes-cursor_space: + +``cursor_space`` + Space reserved for user input in shell bindings. It is measured in per + cents. + +``cursor_columns`` + Space reserved for user input in shell bindings. Unlike :ref:`cursor_space + <config-themes-cursor_space>` it is measured in absolute amount of columns. + +.. _config-themes-segment_data: + +``segment_data`` + A dict where keys are segment names or strings ``{module}.{function}``. Used + to specify default values for various keys: + :ref:`after <config-themes-seg-after>`, + :ref:`before <config-themes-seg-before>`, + :ref:`contents <config-themes-seg-contents>` (only for string segments + if :ref:`name <config-themes-seg-name>` is defined), + :ref:`display <config-themes-seg-display>`. + + Key :ref:`args <config-themes-seg-args>` (only for function and + segment_list segments) is handled specially: unlike other values it is + merged with all other values, except that a single ``{module}.{function}`` + key if found prevents merging all ``{function}`` values. + + When using :ref:`local themes <config-ext-local_themes>` values of these + keys are first searched in the segment description, then in ``segment_data`` + key of a local theme, then in ``segment_data`` key of a :ref:`default theme + <config-ext-theme>`. For the :ref:`default theme <config-ext-theme>` itself + step 2 is obviously avoided. + + .. note:: Top-level themes are out of equation here: they are merged + before the above merging process happens. + +.. _config-themes-segments: + +``segments`` + A dict with a ``left`` and a ``right`` lists, consisting of segment + dictionaries. Shell themes may also contain ``above`` list of dictionaries. + Each item in ``above`` list may have ``left`` and ``right`` keys like this + dictionary, but no ``above`` key. + + .. _config-themes-above: + + ``above`` list is used for multiline shell configurations. + + ``left`` and ``right`` lists are used for segments that should be put on the + left or right side in the output. Actual mechanizm of putting segments on + the left or the right depends on used renderer, but most renderers require + one to specify segment with :ref:`width <config-themes-seg-width>` ``auto`` + on either side to make generated line fill all of the available width. + + Each segment dictionary has the following options: + + .. _config-themes-seg-type: + + ``type`` + The segment type. Can be one of ``function`` (default), ``string`` or + ``segment_list``: + + ``function`` + The segment contents is the return value of the function defined in + the :ref:`function option <config-themes-seg-function>`. + + List of function segments is available in :ref:`Segment reference + <config-segments>` section. + + ``string`` + A static string segment where the contents is defined in the + :ref:`contents option <config-themes-seg-contents>`, and the + highlighting group is defined in the :ref:`highlight_groups option + <config-themes-seg-highlight_groups>`. + + ``segment_list`` + Sub-list of segments. This list only allows :ref:`function + <config-themes-seg-function>`, :ref:`segments + <config-themes-seg-segments>` and :ref:`args + <config-themes-seg-args>` options. + + List of lister segments is available in :ref:`Lister reference + <config-listers>` section. + + .. _config-themes-seg-name: + + ``name`` + Segment name. If present allows referring to this segment in + :ref:`segment_data <config-themes-segment_data>` dictionary by this + name. If not ``string`` segments may not be referred there at all and + ``function`` and ``segment_list`` segments may be referred there using + either ``{module}.{function_name}`` or ``{function_name}``, whichever + will be found first. Function name is taken from :ref:`function key + <config-themes-seg-function>`. + + .. note:: + If present prevents ``function`` key from acting as a segment name. + + .. _config-themes-seg-function: + + ``function`` + Function used to get segment contents, in format ``{module}.{function}`` + or ``{function}``. If ``{module}`` is omitted :ref:`default_module + option <config-themes-default_module>` is used. + + .. _config-themes-seg-highlight_groups: + + ``highlight_groups`` + Highlighting group for this segment. Consists of a prioritized list of + highlighting groups, where the first highlighting group that is + available in the colorscheme is used. + + Ignored for segments that have ``function`` type. + + .. _config-themes-seg-before: + + ``before`` + A string which will be prepended to the segment contents. + + .. _config-themes-seg-after: + + ``after`` + A string which will be appended to the segment contents. + + .. _config-themes-seg-contents: + + ``contents`` + Segment contents, only required for ``string`` segments. + + .. _config-themes-seg-args: + + ``args`` + A dict of arguments to be passed to a ``function`` segment. + + .. _config-themes-seg-align: + + ``align`` + Aligns the segments contents to the left (``l``), center (``c``) or + right (``r``). Has no sense if ``width`` key was not specified or if + segment provides its own function for ``auto`` ``width`` handling and + does not care about this option. + + .. _config-themes-seg-width: + + ``width`` + Enforces a specific width for this segment. + + This segment will work as a spacer if the width is set to ``auto``. + Several spacers may be used, and the space will be distributed + equally among all the spacer segments. Spacers may have contents, + either returned by a function or a static string, and the contents + can be aligned with the ``align`` property. + + .. _config-themes-seg-priority: + + ``priority`` + Optional segment priority. Segments with priority ``None`` (the default + priority, represented by ``null`` in json) will always be included, + regardless of the width of the prompt/statusline. + + If the priority is any number, the segment may be removed if the + prompt/statusline width is too small for all the segments to be + rendered. A lower number means that the segment has a higher priority. + + Segments are removed according to their priority, with low priority + segments (i.e. with a greater priority number) being removed first. + + .. _config-themes-seg-draw_divider: + + ``draw_hard_divider``, ``draw_soft_divider`` + Whether to draw a divider between this and the adjacent segment. The + adjacent segment is to the *right* for segments on the *left* side, and + vice versa. Hard dividers are used between segments with different + background colors, soft ones are used between segments with same + background. Both options default to ``True``. + + .. _config-themes-seg-draw_inner_divider: + + ``draw_inner_divider`` + Determines whether inner soft dividers are to be drawn for function + segments. Only applicable for functions returning multiple segments. + Defaults to ``False``. + + .. _config-themes-seg-exclude_modes: + + ``exclude_modes``, ``include_modes`` + A list of modes where this segment will be excluded: the segment is not + included or is included in all modes, *except* for the modes in one of + these lists respectively. If ``exclude_modes`` is not present then it + acts like an empty list (segment is not excluded from any modes). + Without ``include_modes`` it acts like a list with all possible modes + (segment is included in all modes). When there are both + ``exclude_modes`` overrides ``include_modes``. + + .. _config-themes-seg-exclude_function: + + ``exclude_function``, ``include_function`` + Function name in a form ``{name}`` or ``{module}.{name}`` (in the first + form ``{module}`` defaults to ``powerline.selectors.{ext}``). Determines + under which condition specific segment will be included or excluded. By + default segment is always included and never excluded. + ``exclude_function`` overrides ``include_function``. + + .. note:: + Options :ref:`exclude_/include_modes + <config-themes-seg-exclude_modes>` complement + ``exclude_/include_functions``: segment will be included if it is + included by either ``include_mode`` or ``include_function`` and will + be excluded if it is excluded by either ``exclude_mode`` or + ``exclude_function``. + + .. _config-themes-seg-display: + + ``display`` + Boolean. If false disables displaying of the segment. + Defaults to ``True``. + + .. _config-themes-seg-segments: + + ``segments`` + A list of subsegments. diff --git a/docs/source/configuration/segments.rst b/docs/source/configuration/segments.rst new file mode 100644 index 0000000..63b4975 --- /dev/null +++ b/docs/source/configuration/segments.rst @@ -0,0 +1,28 @@ +.. _config-segments: + +***************** +Segment reference +***************** + +Segments +======== + +Segments are written in Python, and the default segments provided with +Powerline are located in :file:`powerline/segments/{extension}.py`. +User-defined segments can be defined in any module in ``sys.path`` or +:ref:`paths common configuration option <config-common-paths>`, import is +always absolute. + +Segments are regular Python functions, and they may accept arguments. All +arguments should have a default value which will be used for themes that +don’t provide an ``args`` dict. + +More information is available in :ref:`Writing segments <dev-segments>` section. + +Available segments +================== + +.. toctree:: + :glob: + + segments/* diff --git a/docs/source/configuration/segments/common.rst b/docs/source/configuration/segments/common.rst new file mode 100644 index 0000000..5d52d69 --- /dev/null +++ b/docs/source/configuration/segments/common.rst @@ -0,0 +1,57 @@ +*************** +Common segments +*************** + +VCS submodule +============= + +.. automodule:: powerline.segments.common.vcs + :members: + +System properties +================= + +.. automodule:: powerline.segments.common.sys + :members: + +Network +======= + +.. automodule:: powerline.segments.common.net + :members: + +Current environment +=================== + +.. automodule:: powerline.segments.common.env + :members: + +Battery +======= + +.. automodule:: powerline.segments.common.bat + :members: + +Weather +======= + +.. automodule:: powerline.segments.common.wthr + :members: + +Date and time +============= + +.. automodule:: powerline.segments.common.time + :members: + +Mail +==== + +.. automodule:: powerline.segments.common.mail + :members: + +Media players +============= + +.. automodule:: powerline.segments.common.players + :members: diff --git a/docs/source/configuration/segments/i3wm.rst b/docs/source/configuration/segments/i3wm.rst new file mode 100644 index 0000000..d103374 --- /dev/null +++ b/docs/source/configuration/segments/i3wm.rst @@ -0,0 +1,6 @@ +************* +i3wm segments +************* + +.. automodule:: powerline.segments.i3wm + :members: diff --git a/docs/source/configuration/segments/pdb.rst b/docs/source/configuration/segments/pdb.rst new file mode 100644 index 0000000..b9a104b --- /dev/null +++ b/docs/source/configuration/segments/pdb.rst @@ -0,0 +1,7 @@ +************ +PDB segments +************ + +.. automodule:: powerline.segments.pdb + :members: + diff --git a/docs/source/configuration/segments/shell.rst b/docs/source/configuration/segments/shell.rst new file mode 100644 index 0000000..fb3c804 --- /dev/null +++ b/docs/source/configuration/segments/shell.rst @@ -0,0 +1,6 @@ +************** +Shell segments +************** + +.. automodule:: powerline.segments.shell + :members: diff --git a/docs/source/configuration/segments/tmux.rst b/docs/source/configuration/segments/tmux.rst new file mode 100644 index 0000000..1a4a78f --- /dev/null +++ b/docs/source/configuration/segments/tmux.rst @@ -0,0 +1,6 @@ +************* +Tmux segments +************* + +.. automodule:: powerline.segments.tmux + :members: diff --git a/docs/source/configuration/segments/vim.rst b/docs/source/configuration/segments/vim.rst new file mode 100644 index 0000000..5df70d6 --- /dev/null +++ b/docs/source/configuration/segments/vim.rst @@ -0,0 +1,46 @@ +************ +Vim segments +************ + +.. automodule:: powerline.segments.vim + :members: + + +Plugin-specific segments +======================== + +Asynchronous Linter Engine (ALE) segments +----------------------------------------- + +.. automodule:: powerline.segments.vim.plugin.ale + :members: + +Syntastic segments +------------------ + +.. automodule:: powerline.segments.vim.plugin.syntastic + :members: + +Command-T segments +------------------ + +.. automodule:: powerline.segments.vim.plugin.commandt + :members: + +Tagbar segments +--------------- + +.. automodule:: powerline.segments.vim.plugin.tagbar + :members: + +NERDTree segments +----------------- + +.. automodule:: powerline.segments.vim.plugin.nerdtree + :members: + +Capslock segments +----------------- + +.. automodule:: powerline.segments.vim.plugin.capslock + :members: diff --git a/docs/source/configuration/selectors.rst b/docs/source/configuration/selectors.rst new file mode 100644 index 0000000..f9367b2 --- /dev/null +++ b/docs/source/configuration/selectors.rst @@ -0,0 +1,17 @@ +.. _config-selectors: + +****************** +Selector functions +****************** + +Selector functions are functions that return ``True`` or ``False`` depending on +application state. They are used for :ref:`exclude_function and include_function +segment options <config-themes-seg-exclude_function>`. + +Available selectors +=================== + +.. toctree:: + :glob: + + selectors/* diff --git a/docs/source/configuration/selectors/vim.rst b/docs/source/configuration/selectors/vim.rst new file mode 100644 index 0000000..5097320 --- /dev/null +++ b/docs/source/configuration/selectors/vim.rst @@ -0,0 +1,6 @@ +************* +Vim selectors +************* + +.. automodule:: powerline.selectors.vim + :members: diff --git a/docs/source/develop.rst b/docs/source/develop.rst new file mode 100644 index 0000000..bf45498 --- /dev/null +++ b/docs/source/develop.rst @@ -0,0 +1,13 @@ +*************** +Developer guide +*************** + +.. toctree:: + :maxdepth: 2 + :glob: + + develop/segments + develop/listers + develop/local-themes + develop/extensions + develop/tips-and-tricks diff --git a/docs/source/develop/extensions.rst b/docs/source/develop/extensions.rst new file mode 100644 index 0000000..2ddf223 --- /dev/null +++ b/docs/source/develop/extensions.rst @@ -0,0 +1,47 @@ +******************************** +Creating new powerline extension +******************************** + +Powerline extension is a code that tells powerline how to highlight and display +segments in some set of applications. Specifically this means + +#. Creating a :py:class:`powerline.Powerline` subclass that knows how to obtain + :ref:`local configuration overrides <local-configuration-overrides>`. It also + knows how to load local themes, but not when to apply them. + + Instance of this class is the only instance that interacts directly with + bindings code, so it has a proxy :py:meth:`powerline.Powerline.render` and + :py:meth:`powerline.Powerline.shutdown` methods and other methods which may + be useful for bindings. + + This subclass must be placed directly in :file:`powerline` directory (e.g. in + :file:`powerline/vim.py`) and named like ``VimPowerline`` (version of the + file name without directory and extension and first capital letter + + ``Powerline``). There is no technical reason for naming classes like this. +#. Creating a :py:class:`powerline.renderer.Renderer` subclass that knows how to + highlight a segment or reset highlighting to the default value (only makes + sense in prompts). It is also responsible for selecting local themes and + computing text width. + + This subclass must be placed directly in :file:`powerline/renderers` + directory (for powerline extensions developed for a set of applications use + :file:`powerline/renderers/{ext}/*.py`) and named like ``ExtRenderer`` or + ``AppPromptRenderer``. For technical reasons the class itself must be + referenced in ``renderer`` module attribute thus allowing only one renderer + per one module. +#. Creating an extension bindings. These are to be placed in + :file:`powerline/bindings/{ext}` and may contain virtually anything which may + be required for powerline to work inside given applications, assuming it does + not fit in other places. + +Powerline class +=============== + +.. autoclass:: powerline.Powerline + :members: + +Renderer class +============== + +.. autoclass:: powerline.renderer.Renderer + :members: diff --git a/docs/source/develop/listers.rst b/docs/source/develop/listers.rst new file mode 100644 index 0000000..e779704 --- /dev/null +++ b/docs/source/develop/listers.rst @@ -0,0 +1,49 @@ +.. _dev-listers: + +*************** +Writing listers +*************** + +Listers provide a way to show some segments multiple times: once per each entity +(buffer, tabpage, etc) lister knows. They are functions which receive the +following arguments: + +``pl`` + A :py:class:`powerline.PowerlineLogger` class instance. It must be used for + logging. + +``segment_info`` + Base segment info dictionary. Lister function or class must have + ``powerline_requires_segment_info`` to receive this argument. + + .. warning:: + Listers are close to useless if they do not have access to this + argument. + + Refer to :ref:`segment_info detailed description <dev-segments-info>` for + further details. + +``draw_inner_divider`` + If False (default) soft dividers between segments in the listed group will + not be drawn regardless of actual segment settings. If True they will be + drawn, again regardless of actual segment settings. Set it to ``None`` in + order to respect segment settings. + +And also any other argument(s) specified by user in :ref:`args key +<config-themes-seg-args>` (no additional arguments by default). + +Listers must return a sequence of pairs. First item in the pair must contain +a ``segment_info`` dictionary specific to one of the listed entities. + +Second item must contain another dictionary: it will be used to modify the +resulting segment. In addition to :ref:`usual keys that describe segment +<dev-segments-segment>` the following keys may be present (it is advised that +*only* the following keys will be used): + +``priority_multiplier`` + Value (usually a ``float``) used to multiply segment priority. It is useful + for finer-grained controlling which segments disappear first: e.g. when + listing tab pages make first disappear directory names of the tabpages which + are most far away from current tabpage, then (when all directory names + disappeared) buffer names. Check out existing listers implementation in + :file:`powerline/listers/vim.py`. diff --git a/docs/source/develop/local-themes.rst b/docs/source/develop/local-themes.rst new file mode 100644 index 0000000..959e1c4 --- /dev/null +++ b/docs/source/develop/local-themes.rst @@ -0,0 +1,59 @@ +************ +Local themes +************ + +From the user point of view local themes are the regular themes with a specific +scope where they are applied (i.e. specific vim window or specific kind of +prompt). Used themes are defined in :ref:`local_themes key +<config-ext-local_themes>`. + +Vim local themes +================ + +Vim is the only available extension that has a wide variaty of options for local +themes. It is the only extension where local theme key refers to a function as +described in :ref:`local_themes value documentation <config-ext-local_themes>`. + +This function always takes a single value named ``matcher_info`` which is the +same dictionary as :ref:`segment_info dictionary <dev-segment_info-vim>`. Unlike +segments it takes this single argument as a *positional* argument, not as +a keyword one. + +Matcher function should return a boolean value: ``True`` if theme applies for +the given ``matcher_info`` dictionary or ``False`` if it is not. When one of the +matcher functions returns ``True`` powerline takes the corresponding theme at +uses it for the given window. Matchers are not tested in any particular order. + +In addition to :ref:`local_themes configuration key <config-ext-local_themes>` +developer of some plugin which wishes to support powerline without including his +code in powerline tree may use +:py:meth:`powerline.vim.VimPowerline.add_local_theme` method. It accepts two +arguments: matcher name (same as in :ref:`local_themes +<config-ext-local_themes>`) and dictionary with theme. This dictionary is merged +with :ref:`top theme <config-ext-top_theme>` and +:file:`powerline/themes/vim/__main__.json`. Note that if user already specified +the matcher in his configuration file ``KeyError`` is raised. + +Other local themes +================== + +Except for Vim only IPython and shells have local themes. Unlike Vim these +themes are names with no special meaning (they do not refer to or cause loading +of any Python functions): + ++---------+------------+-------------------------------------------------------+ +|Extension|Theme name |Description | ++---------+------------+-------------------------------------------------------+ +|Shell |continuation|Shown for unfinished command (unclosed quote, | +| | |unfinished cycle). | +| +------------+-------------------------------------------------------+ +| |select |Shown for ``select`` command available in some shells. | ++---------+------------+-------------------------------------------------------+ +|IPython |in2 |Continuation prompt: shown for unfinished (multiline) | +| | |expression, unfinished class or function definition. | +| +------------+-------------------------------------------------------+ +| |out |Displayed before the result. | +| +------------+-------------------------------------------------------+ +| |rewrite |Displayed before the actually executed code when | +| | |``autorewrite`` IPython feature is enabled. | ++---------+------------+-------------------------------------------------------+ diff --git a/docs/source/develop/segments.rst b/docs/source/develop/segments.rst new file mode 100644 index 0000000..59549f6 --- /dev/null +++ b/docs/source/develop/segments.rst @@ -0,0 +1,547 @@ +.. _dev-segments: + +**************** +Writing segments +**************** + +Each powerline segment is a callable object. It is supposed to be either +a Python function or :py:class:`powerline.segments.Segment` class. As a callable +object it should receive the following arguments: + +.. note:: All received arguments are keyword arguments. + +``pl`` + A :py:class:`powerline.PowerlineLogger` instance. It must be used every time + something needs to be logged. + +``segment_info`` + A dictionary. It is only received if callable has + ``powerline_requires_segment_info`` attribute. + + Refer to :ref:`segment_info detailed description <dev-segments-info>` for + further details. + +``create_watcher`` + Function that will create filesystem watcher once called. Which watcher will + be created exactly is controlled by :ref:`watcher configuration option + <config-common-watcher>`. + +And also any other argument(s) specified by user in :ref:`args key +<config-themes-seg-args>` (no additional arguments by default). + +.. note:: + For powerline-lint to work properly the following things may be needed: + + #. If segment is a :py:class:`powerline.segments.Segment` instance and used + arguments are scattered over multiple methods + :py:meth:`powerline.segments.Segment.argspecobjs` should be overridden in + subclass to tell powerline-lint which objects should be inspected for + arguments. + #. If segment takes some arguments that are never listed, but accessed via + ``kwargs.get()`` or previous function cannot be used for whatever reason + :py:meth:`powerline.segments.Segment.additional_args` should be + overridden in subclass. + #. If user is expected to use one :ref:`name <config-themes-seg-name>` for + multiple segments which cannot be linked to the segment function + automatically by powerline-lint (e.g. because there are no instances of + the segments in question in the default configuration) + :py:func:`powerline.lint.checks.register_common_name` function should be + used. + +Object representing segment may have the following attributes used by +powerline: + +``powerline_requires_segment_info`` + This attribute controls whether segment will receive ``segment_info`` + argument: if it is present argument will be received. + +``powerline_requires_filesystem_watcher`` + This attribute controls whether segment will receive ``create_watcher`` + argument: if it is present argument will be received. + +``powerline_segment_datas`` + This attribute must be a dictionary containing ``top_theme: segment_data`` + mapping where ``top_theme`` is any theme name (it is expected that all of + the names from :ref:`top-level themes list <config-top_themes-list>` are + present) and ``segment_data`` is a dictionary like the one that is contained + inside :ref:`segment_data dictionary in configuration + <config-themes-segment_data>`. This attribute should be used to specify + default theme-specific values for *third-party* segments: powerline + theme-specific values go directly to :ref:`top-level themes + <config-themes>`. + +.. _dev-segments-startup: + +``startup`` + This attribute must be a callable which accepts the following keyword + arguments: + + * ``pl``: :py:class:`powerline.PowerlineLogger` instance which is to be used + for logging. + * ``shutdown_event``: :py:class:`Event` object which will be set when + powerline will be shut down. + * Any arguments found in user configuration for the given segment (i.e. + :ref:`args key <config-themes-seg-args>`). + + This function is called at powerline startup when using long-running + processes (e.g. powerline in vim, in zsh with libzpython, in ipython or in + powerline daemon) and not called when ``powerline-render`` executable is + used (more specific: when :py:class:`powerline.Powerline` constructor + received true ``run_once`` argument). + +.. _dev-segments-shutdown: + +``shutdown`` + This attribute must be a callable that accepts no arguments and shuts down + threads and frees any other resources allocated in ``startup`` method of the + segment in question. + + This function is not called when ``startup`` method is not called. + +.. _dev-segments-expand: + +``expand`` + This attribute must be a callable that accepts the following keyword + arguments: + + * ``pl``: :py:class:`powerline.PowerlineLogger` instance which is to be used + for logging. + * ``amount``: integer number representing amount of display cells result + must occupy. + + .. warning:: + “Amount of display cells” is *not* number of Unicode codepoints, string + length, or byte count. It is suggested that this function should look + something like ``return (' ' * amount) + segment['contents']`` where + ``' '`` may be replaced with anything that is known to occupy exactly + one display cell. + * ``segment``: :ref:`segment dictionary <dev-segments-segment>`. + * Any arguments found in user configuration for the given segment (i.e. + :ref:`args key <config-themes-seg-args>`). + + It must return new value of :ref:`contents <dev-segments-seg-contents>` key. + +.. _dev-segments-truncate: + +``truncate`` + Like :ref:`expand function <dev-segments-expand>`, but for truncating + segments. Here ``amount`` means the number of display cells which must be + freed. + + This function is called for all segments before powerline starts purging + them to free space. + +This callable object should may return either a string (``unicode`` in Python2 +or ``str`` in Python3, *not* ``str`` in Python2 or ``bytes`` in Python3) object +or a list of dictionaries. String object is a short form of the following return +value: + +.. code-block:: python + + [{ + 'contents': original_return, + 'highlight_groups': [segment_name], + }] + +.. _dev-segments-return: + +Returned list is a list of segments treated independently, except for +:ref:`draw_inner_divider key <dev-segments-draw_inner_divider>`. + +All keys in segments returned by the function override those obtained from +:ref:`configuration <config-themes-segments>` and have the same meaning. + +Detailed description of used dictionary keys: + +.. _dev-segments-contents: + +``contents`` + Text displayed by segment. Should be a ``unicode`` (Python2) or ``str`` + (Python3) instance. + +``literal_contents`` + Text that needs to be output literally (i.e. without passing through + :py:meth:`powerline.renderer.strwidth` to determine length, through + :py:meth:`powerline.renderer.escape` to escape special characters and + through :py:meth:`powerline.renderer.hl` to highlight it). Should be a tuple + ``(contents_length, contents)`` where ``contents_length`` is an integer and + ``contents`` is a ``unicode`` (Python2) or ``str`` (Python3) instance. + + If this key is present and its second value is true then other contents keys + (:ref:`contents <dev-segments-contents>`, :ref:`after + <config-themes-seg-after>`, :ref:`before <config-themes-seg-before>`) will + be ignored. + + .. note:: + If target is inclusion of the segment in powerline upstream all segment + functions that output *only* subsegments with ``literal_contents`` key + must contain the following string in documentation:: + + No highlight groups are used (literal segment). + + String must be present on the separate line. + +.. _dev-segments-draw_inner_divider: + +``draw_hard_divider``, ``draw_soft_divider``, ``draw_inner_divider`` + Determines whether given divider should be drawn. All have the same meaning + as :ref:`the similar keys in configuration <config-themes-seg-draw_divider>` + (:ref:`draw_inner_divider <config-themes-seg-draw_inner_divider>`). + +.. _dev-segments-highlight_groups: + +``highlight_groups`` + Determines segment highlighting. Refer to :ref:`themes documentation + <config-themes-seg-highlight_groups>` for more details. + + Defaults to the name of the segment. + + .. note:: + If target is inclusion of the segment in powerline upstream all used + highlighting groups must be specified in the segment documentation in the + form:: + + Highlight groups used: ``g1``[ or ``g2``]*[, ``g3`` (gradient)[ or ``g4``]*]*. + + I.e. use:: + + Highlight groups used: ``foo_gradient`` (gradient) or ``foo``, ``bar``. + + to specify that the segment uses *either* ``foo_gradient`` group or + ``foo`` group *and* ``bar`` group meaning that ``powerline-lint`` will + check that at least one of the first two groups is defined (and if + ``foo_gradient`` is defined it must use at least one gradient color) and + third group is defined as well. + + All groups must be specified on one line. + +``divider_highlight_group`` + Determines segment divider highlight group. Only applicable for soft + dividers: colors for hard dividers are determined by colors of adjacent + segments. + + .. note:: + If target is inclusion of the segment in powerline upstream used divider + highlight group must be specified in the segment documentation in the + form:: + + Divider highlight group used: ``group``. + + This text must not wrap and all divider highlight group names are + supposed to end with ``:divider``: e.g. ``cwd:divider``. + +``gradient_level`` + First and the only key that may not be specified in user configuration. It + determines which color should be used for this segment when one of the + highlighting groups specified by :ref:`highlight_groups + <dev-segments-highlight_groups>` was defined to use the color gradient. + + This key may have any value from 0 to 100 inclusive, value is supposed to be + an ``int`` or ``float`` instance. + + No error occurs if segment has this key, but no used highlight groups use + gradient color. + +``_*`` + Keys starting with underscore are reserved for powerline and must not be + returned. + +``__*`` + Keys starting with two underscores are reserved for the segment functions, + specifically for :ref:`expand function <dev-segments-expand>`. + +.. _dev-segments-segment: + +Segment dictionary +================== + +Segment dictionary contains the following keys: + +* All keys returned by segment function (if it was used). + +* All of the following keys: + + ``name`` + Segment name: value of the :ref:`name key <config-themes-seg-name>` or + function name (last component of the :ref:`function key + <config-themes-seg-function>`). May be ``None``. + + ``type`` + :ref:`Segment type <config-themes-seg-type>`. Always represents actual type + and is never ``None``. + + ``highlight_groups``, ``divider_highlight_group`` + Used highlight groups. May be ``None``. + + ``highlight_group_prefix`` + If this key is present then given prefix will be prepended to each highlight + group (both regular and divider) used by this segment in a form + ``{prefix}:{group}`` (note the colon). This key is mostly useful for + :ref:`segment listers <dev-listers>`. + + .. _dev-segments-seg-around: + + ``before``, ``after`` + Value of :ref:`before <config-themes-seg-before>` or :ref:`after + <config-themes-seg-after>` configuration options. May be ``None`` as well as + an empty string. + + ``contents_func`` + Function used to get segment contents. May be ``None``. + + .. _dev-segments-seg-contents: + + ``contents`` + Actual segment contents, excluding dividers and :ref:`before/after + <dev-segments-seg-around>`. May be ``None``. + + ``priority`` + :ref:`Segment priority <config-themes-seg-priority>`. May be ``None`` for no + priority (such segments are always shown). + + ``draw_soft_divider``, ``draw_hard_divider``, ``draw_inner_divider`` + :ref:`Divider control flags <dev-segments-draw_inner_divider>`. + + ``side`` + Segment side: ``right`` or ``left``. + + ``display_condition`` + Contains function that takes three position parameters: + :py:class:`powerline.PowerlineLogger` instance, :ref:`segment_info + <dev-segments-info>` dictionary and current mode and returns either ``True`` + or ``False`` to indicate whether particular segment should be processed. + + This key is constructed based on :ref:`exclude_/include_modes keys + <config-themes-seg-exclude_modes>` and :ref:`exclude_/include_function keys + <config-themes-seg-exclude_function>`. + + ``width``, ``align`` + :ref:`Width and align options <config-themes-seg-align>`. May be ``None``. + + ``expand``, ``truncate`` + Partially applied :ref:`expand <dev-segments-expand>` or :ref:`truncate + <dev-segments-truncate>` function. Accepts ``pl``, ``amount`` and + ``segment`` positional parameters, keyword parameters from :ref:`args + <config-themes-seg-args>` key were applied. + + ``startup`` + Partially applied :ref:`startup function <dev-segments-startup>`. Accepts + ``pl`` and ``shutdown_event`` positional parameters, keyword parameters from + :ref:`args <config-themes-seg-args>` key were applied. + + ``shutdown`` + :ref:`Shutdown function <dev-segments-shutdown>`. Accepts no argument. + +Segments layout +=============== + +Powerline segments are all located in one of the ``powerline.segments`` +submodules. For extension-specific segments ``powerline.segments.{ext}`` module +should be used (e.g. ``powerline.segments.shell``), for extension-agnostic there +is ``powerline.segments.common``. + +Plugin-specific segments (currently only those that are specific to vim plugins) +should live in ``powerline.segments.{ext}.plugin.{plugin_name}``: e.g. +``powerline.segments.vim.plugin.gundo``. + +.. _dev-segments-info: + +Segment information used in various extensions +============================================== + +Each ``segment_info`` value should be a dictionary with at least the following +keys: + +``environ`` + Current environment, may be an alias to ``os.environ``. Is guaranteed to + have ``__getitem__`` and ``get`` methods and nothing more. + + .. warning:: + ``os.environ`` must not ever be used: + + * If segment is run in the daemon this way it will get daemon’s + environment which is not correct. + * If segment is run in Vim or in zsh with libzpython ``os.environ`` will + contain Vim or zsh environ *at the moment Python interpreter was + loaded*. + +``getcwd`` + Function that returns current working directory being called with no + arguments. ``os.getcwd`` must not be used for the same reasons the use of + ``os.environ`` is forbidden, except that current working directory is valid + in Vim and zsh (but not in daemon). + +``home`` + Current home directory. May be false. + +.. _dev-segment_info-vim: + +Vim +--- + +Vim ``segment_info`` argument is a dictionary with the following keys: + +``window`` + ``vim.Window`` object. ``vim.current.window`` or ``vim.windows[number - 1]`` + may be used to obtain such object. May be a false object, in which case any + of this object’s properties must not be used. + +``winnr`` + Window number. Same as ``segment_info['window'].number`` *assuming* Vim is + new enough for ``vim.Window`` object to have ``number`` attribute. + +``window_id`` + Internal powerline window id, unique for each newly created window. It is + safe to assume that this ID is hashable and supports equality comparison, + but no other assumptions about it should be used. Currently uses integer + numbers incremented each time window is created. + +``buffer`` + ``vim.Buffer`` object. One may be obtained using ``vim.current.buffer``, + ``segment_info['window'].buffer`` or ``vim.buffers[some_number]``. Note that + in the latter case depending on vim version ``some_number`` may be ``bufnr`` + or the internal Vim buffer index which is *not* buffer number. For this + reason to get ``vim.Buffer`` object other then stored in ``segment_info`` + dictionary iteration over ``vim.buffers`` and checking their ``number`` + attributes should be performed. + +``bufnr`` + Buffer number. + +``tabpage`` + ``vim.Tabpage`` object. One may be obtained using ``vim.current.tabpage`` or + ``vim.tabpages[number - 1]``. May be a false object, in which case no + object’s properties can be used. + +``tabnr`` + Tabpage number. + +``mode`` + Current mode. + +``encoding`` + Value of ``&encoding`` from the time when powerline was initialized. It + should be used to convert return values. + +.. note:: + Segment generally should not assume that it is run for the current window, + current buffer or current tabpage. “Current window” and “current buffer” + restrictions may be ignored if ``window_cached`` decorator is used, “current + tabpage” restriction may be safely ignored if segment is not supposed to be + used in tabline. + +.. warning:: + Powerline is being tested with vim-7.0.112 (some minor sanity check) and + latest Vim. This means that most of the functionality like + ``vim.Window.number``, ``vim.*.vars``, ``vim.*.options`` or even ``dir(vim + object)`` should be avoided in segments that want to be included in the + upstream. + +Shell +----- + +``args`` + Parsed shell arguments: a ``argparse.Namespace`` object. Check out + ``powerline-render --help`` for the list of all available arguments. + Currently it is expected to contain at least the following attributes: + + ``last_exit_code`` + Exit code returned by last shell command. Is either one integer, + ``sig{name}`` or ``sig{name}+core`` (latter two are only seen in ``rc`` + shell). + + ``last_pipe_status`` + List of exit codes returned by last programs in the pipe or some false + object. Only available in ``zsh`` and ``rc``. Is a list of either + integers, ``sig{name}`` or ``sig{name}+core`` (latter two are only seen + in ``rc`` shell). + + ``jobnum`` + Number of background jobs. + + ``renderer_arg`` + Dictionary containing some keys that are additional arguments used by + shell bindings. *This attribute must not be used directly*: all + arguments from this dictionary are merged with ``segment_info`` + dictionary. Known to have at least the following keys: + + ``client_id`` + Identifier unique to one shell instance. Is used to record instance + state by powerline daemon. In tmux this is the same as :ref:`pane_id + <dev-seginfo-shell-renarg-pane_id>`. + + It is not guaranteed that existing client ID will not be retaken + when old shell with this ID quit: usually process PID is used as + a client ID. + + It is also not guaranteed that client ID will be process PID, number + or something else at all. It is guaranteed though that client ID + will be some hashable object which supports equality comparison. + + ``local_theme`` + Local theme that will be used by shell. One should not rely on the + existence of this key. + + .. _dev-seginfo-shell-renarg-pane_id: + + ``pane_id`` + Identifier unique to each tmux pane. Is always an integer, optional. + Obtained by using ``tmux display -p '#D'``, then all leading spaces + and per cent signs are stripped and the result is converted into an + integer. + + Other keys, if any, are specific to segments. + +Ipython +------- + +``ipython`` + Some object which has ``prompt_count`` attribute. Currently it is guaranteed + to have only this attribute. + + Attribute ``prompt_count`` contains the so-called “history count” + (equivalent to ``\N`` in ``in_template``). + +Pdb +--- + +``pdb`` + Currently active :py:class:`pdb.Pdb` instance. + +``curframe`` + Frame which will be run next. Note: due to the existence of + :py:func:`powerline.listers.pdb.frame_lister` one must not use + ``segment_info['pdb'].curframe``. + +``initial_stack_length`` + Equal to the length of :py:attr:`pdb.Pdb.stack` at the first invocation of + the prompt decremented by one. + +i3wm +---- + +``mode`` + Currently active i3 mode (as a string). + +``output`` + ``xrandr`` output name currently drawing to. Currently only available + in lemonbar bindings. + +``workspace`` + the `i3-ipc` workspace object corresponding to this workspace. + Contains string attributes ``name`` and ``output``, as well as boolean + attributes for ``visible``, ``urgent`` and ``focused``. Currently only + provided by the :py:func:`powerline.listers.i3wm.workspace_lister` lister. + +Segment class +============= + +.. autoclass:: powerline.segments.Segment + :members: + +PowerlineLogger class +===================== + +.. autoclass:: powerline.PowerlineLogger + :members: + :undoc-members: diff --git a/docs/source/develop/tips-and-tricks.rst b/docs/source/develop/tips-and-tricks.rst new file mode 100644 index 0000000..c850659 --- /dev/null +++ b/docs/source/develop/tips-and-tricks.rst @@ -0,0 +1,21 @@ +**************************************** +Tips and tricks for powerline developers +**************************************** + +Profiling powerline in Vim +========================== + +Given that current directory is the root of the powerline repository the +following command may be used: + +.. code-block:: sh + + vim --cmd 'let g:powerline_pyeval="powerline#debug#profile_pyeval"' \ + --cmd 'set rtp=powerline/bindings/vim' \ + -c 'runtime! plugin/powerline.vim' \ + {other arguments if needed} + +After some time run ``:WriteProfiling {filename}`` Vim command. Currently this +only works with recent Vim and python-2*. It should be easy to modify +:file:`powerline/bindings/vim/autoload/powerline/debug.vim` to suit other +needs. diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..9a4d84b --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,28 @@ +********* +Powerline +********* + +.. toctree:: + :maxdepth: 3 + :glob: + + overview + installation + usage + configuration + develop + troubleshooting + tips-and-tricks + license-and-credits + +.. toctree:: + :maxdepth: 2 + + commands + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/installation.rst b/docs/source/installation.rst new file mode 100644 index 0000000..8dc4236 --- /dev/null +++ b/docs/source/installation.rst @@ -0,0 +1,131 @@ +************ +Installation +************ + +Generic requirements +==================== + +* Python 2.6 or later, 3.2 or later, PyPy 2.0 or later, PyPy3 2.3 or later. It + is the only non-optional requirement. + + .. warning: + It is highly advised to use UCS-4 version of Python because UCS-2 version + uses significantly slower text processing (length determination and + non-printable character replacement) functions due to the need of + supporting unicode characters above U+FFFF which are represented as + surrogate pairs. This price will be paid even if configuration has no such + characters. + +* C compiler. Required to build powerline client on linux. If it is not present + then powerline will fall back to shell script or python client. +* ``socat`` program. Required for shell variant of client which runs a bit + faster than python version of the client, but still slower than C version. +* ``psutil`` python package. Required for some segments like cpu_percent. Some + segments have linux-only fallbacks for ``psutil`` functionality. +* ``hglib`` python package *and* mercurial executable. Required to work with + mercurial repositories. +* ``pygit2`` python package or ``git`` executable. Required to work with ``git`` + repositories. +* ``bzr`` python package (note: *not* standalone executable). Required to work + with bazaar repositories. +* ``pyuv`` python package. Required for :ref:`libuv-based watcher + <config-common-watcher>` to work. +* ``i3ipc`` python package. Required for i3wm bindings and segments. +* ``xrandr`` program. Required for the multi-monitor lemonbar binding and the + :py:func:`powerline.listers.i3wm.output_lister`. + +.. note:: + Until bazaar supports Python-3 or PyPy powerline will not support + repository information when running in these interpreters. + +.. _repository-root: + +.. note:: + When using ``pip``, the ``{repository_root}`` directory referenced in + documentation may be found using ``pip show powerline-status``. In the output + of ``pip show`` there is a line like ``Location: {path}``, that ``{path}`` is + ``{repository_root}``. Unless it is ``--editable`` installation this is only + applicable for ``{repository_root}/powerline/…`` paths: something like + ``{repository_root}/scripts/powerline-render`` is not present. + + When using other packages referenced paths may not exist, in this case refer + to package documentation. + +Pip installation +================ + +Due to a naming conflict with an unrelated project, powerline is available on +PyPI under the ``powerline-status`` name: + +.. code-block:: sh + + pip install powerline-status + +is the preferred method because this will get the latest release. To get current +development version + +.. code-block:: sh + + pip install --user git+https://github.com/powerline/powerline + +may be used. If powerline was already checked out into some directory + +.. code-block:: sh + + pip install --user --editable={path_to_powerline} + +is useful, but note that in this case ``pip`` will not install ``powerline`` +executable and something like + +.. code-block:: sh + + ln -s {path_to_powerline}/scripts/powerline ~/.local/bin + +will have to be done (:file:`~/.local/bin` should be replaced with some path +present in ``$PATH``). + +.. note:: + We can use either ``https``(``git+ssh://git@github.com/powerline/powerline``) + or ``https``(``git+https://github.com/powerline/powerline``) protocols. + ``git`` protocol is deprecated by Github. + +Fonts installation +================== + +Powerline uses several special glyphs to get the arrow effect and some custom +symbols for developers. This requires having either a symbol font or a patched +font installed in the system. The used application (e.g. terminal emulator) must +also either be configured to use patched fonts (in some cases even support it +because custom glyphs live in private use area which some applications reserve +for themselves) or support fontconfig for powerline to work properly with +powerline-specific glyphs. + +:ref:`24-bit color support <config-common-term_truecolor>` may be enabled if +used terminal emulator supports it (see :ref:`the terminal emulator support +matrix <usage-terminal-emulators>`). + +There are basically two ways to get powerline glyphs displayed: use +:file:`PowerlineSymbols.otf` font as a fallback for one of the existing fonts or +install a patched font. + +.. _installation-patched-fonts: + +Patched fonts +------------- + +This method is the fallback method and works for every terminal. + +Download the font from `powerline-fonts`_. If preferred font can’t be found in +the `powerline-fonts`_ repo, then patching the preferred font is needed instead. + +.. _powerline-fonts: https://github.com/powerline/fonts + +After downloading this font refer to platform-specific instructions. + +Installation on various platforms +================================= + +.. toctree:: + + Linux <installation/linux> + OS X <installation/osx> diff --git a/docs/source/installation/linux.rst b/docs/source/installation/linux.rst new file mode 100644 index 0000000..e134707 --- /dev/null +++ b/docs/source/installation/linux.rst @@ -0,0 +1,110 @@ +********************* +Installation on Linux +********************* + +The following distribution-specific packages are officially supported, and they +provide an easy way of installing and upgrading Powerline. The packages will +automatically do most of the configuration. + +* `Arch Linux (AUR), Python 2 version <https://aur.archlinux.org/packages/python2-powerline-git/>`_ +* `Arch Linux (AUR), Python 3 version <https://aur.archlinux.org/packages/python-powerline-git/>`_ +* Gentoo Live ebuild in `raiagent <https://github.com/leycec/raiagent>`_ overlay +* Powerline package is available for Debian starting from Wheezy (via `backports + <https://packages.debian.org/wheezy-backports/powerline>`_). Use `search + <https://packages.debian.org/search?keywords=powerline&searchon=names&suite=all§ion=all>`_ + to get more information. + +If used distribution does not have an official package installation guide below +should be followed: + +1. Install Python 3.2+, Python 2.6+ or PyPy and ``pip`` with ``setuptools``. + This step is distribution-specific, so no commands provided. +2. Install Powerline using one of the following commands: + + .. code-block:: sh + + pip install --user powerline-status + + will get the latest release version and + + .. code-block:: sh + + pip install --user git+https://github.com/powerline/powerline + + will get the latest development version. + + .. note:: Due to the naming conflict with an unrelated project powerline is + named ``powerline-status`` in PyPI. + + .. note:: + Powerline developers should be aware that``pip install --editable`` does + not currently fully work. Installation performed this way are missing + ``powerline`` executable that needs to be symlinked. It will be located in + ``scripts/powerline``. + +Fonts installation +================== + +Fontconfig +---------- + +This method only works on Linux. It’s the second recommended method if terminal +emulator supports it as patching fonts is not needed, and it generally works +with any coding font. + +#. Download the latest version of the symbol font and fontconfig file:: + + wget https://github.com/powerline/powerline/raw/develop/font/PowerlineSymbols.otf + wget https://github.com/powerline/powerline/raw/develop/font/10-powerline-symbols.conf + +#. Move the symbol font to a valid X font path. Valid font paths can be + listed with ``xset q``:: + + mv PowerlineSymbols.otf ~/.local/share/fonts/ + +#. Update font cache for the path the font was moved to (root privileges may be + needed to update cache for the system-wide paths):: + + fc-cache -vf ~/.local/share/fonts/ + +#. Install the fontconfig file. For newer versions of fontconfig the config + path is ``~/.config/fontconfig/conf.d/``, for older versions it’s + ``~/.fonts.conf.d/``:: + + mv 10-powerline-symbols.conf ~/.config/fontconfig/conf.d/ + +If custom symbols still cannot be seen then try closing all instances of the +terminal emulator. Restarting X may be needed for the changes to take effect. + +If custom symbols *still* can’t be seen, double-check that the font have been +installed to a valid X font path, and that the fontconfig file was installed to +a valid fontconfig path. Alternatively try to install a :ref:`patched font +<installation-patched-fonts>`. + +Patched font installation +------------------------- + +This is the preferred method, but it is not always available because not all +fonts were patched and not all fonts *can* be patched due to licensing issues. + +After downloading font the following should be done: + +#. Move the patched font to a valid X font path. Valid font paths can be + listed with ``xset q``:: + + mv 'SomeFont for Powerline.otf' ~/.local/share/fonts/ + +#. Update font cache for the path the font was moved to (root privileges may be + needed for updating font cache for some paths):: + + fc-cache -vf ~/.local/share/fonts/ + +After installing patched font terminal emulator, GVim or whatever application +powerline should work with must be configured to use the patched font. The +correct font usually ends with *for Powerline*. + +If custom symbols cannot be seen then try closing all instances of the terminal +emulator. X server may need to be restarted for the changes to take effect. + +If custom symbols *still* can’t be seen then double-check that the font have +been installed to a valid X font path. diff --git a/docs/source/installation/osx.rst b/docs/source/installation/osx.rst new file mode 100644 index 0000000..1d6fafc --- /dev/null +++ b/docs/source/installation/osx.rst @@ -0,0 +1,71 @@ +******************** +Installation on OS X +******************** + +Python package +============== + +1. Install a proper Python version (see `issue #39 + <https://github.com/powerline/powerline/issues/39>`_ for a discussion + regarding the required Python version on OS X):: + + sudo port select python python27-apple + + Homebrew may be used here:: + + brew install python + + .. note:: + There are three variants of the powerline client. The fastest is + written in C and will be compiled if the compiler and libraries are + detected during installation. The second fastest option is + :file:`powerline.sh` which requires ``socat`` and ``coreutils``. + ``coreutils`` may be installed using ``brew install + coreutils``. If neither of these are viable, then Powerline will + utilize a fallback client written in Python. + +2. Install Powerline using one of the following commands: + + .. code-block:: sh + + pip install --user powerline-status + + will get current release version and + + .. code-block:: sh + + pip install --user git+https://github.com/powerline/powerline + + will get latest development version. + + .. warning:: + When using ``brew install`` to install Python one must not supply + ``--user`` flag to ``pip``. + + .. note:: + Due to the naming conflict with an unrelated project powerline is named + ``powerline-status`` in PyPI. + + .. note:: + Powerline developers should be aware that ``pip install --editable`` does + not currently fully work. Installation performed this way are missing + ``powerline`` executable that needs to be symlinked. It will be located in + ``scripts/powerline``. + +Vim installation +================ + +Any terminal vim version with Python 3.2+ or Python 2.6+ support should work, +but MacVim users need to install it using the following command:: + + brew install macvim --env-std --with-override-system-vim + +Fonts installation +================== + +To install patched font double-click the font file in Finder, then click +:guilabel:`Install this font` in the preview window. + +After installing the patched font MacVim or terminal emulator (whatever +application powerline should work with) need to be configured to use the patched +font. The correct font usually ends with *for Powerline*. diff --git a/docs/source/license-and-credits.rst b/docs/source/license-and-credits.rst new file mode 100644 index 0000000..5226669 --- /dev/null +++ b/docs/source/license-and-credits.rst @@ -0,0 +1,31 @@ +******************* +License and credits +******************* + +Powerline is licensed under the `MIT license +<https://raw.github.com/powerline/powerline/develop/LICENSE>`_. + +.. + This document is parsed by powerline_automan.py module. Do not forget to + check that file before altering this one. Specifically it expects + ``Authors`` and ``Contributors`` sections underlined by ``---``, a list of + authors in format ``* `{name} <`` in the “Authors” section and fonts + contributor name in format ``The glyphs in the font patcher are created by + {name},`` in the “Contributors” section. + +Authors +------- + +* `Kim Silkebækken <https://github.com/Lokaltog>`_ +* `Nikolay Pavlov <https://github.com/ZyX-I>`_ +* `Kovid Goyal <https://github.com/kovidgoyal>`_ + +Contributors +------------ + +* `List of contributors + <https://github.com/powerline/powerline/contributors>`_ +* The glyphs in the font patcher are created by Fabrizio Schiavi, creator of + the excellent coding font `Pragmata Pro`_. + +.. _`Pragmata Pro`: http://www.fsd.it/fonts/pragmatapro.htm diff --git a/docs/source/overview.rst b/docs/source/overview.rst new file mode 100644 index 0000000..13b6be3 --- /dev/null +++ b/docs/source/overview.rst @@ -0,0 +1,67 @@ +******** +Overview +******** + +**Powerline is a statusline plugin for vim, and provides statuslines and +prompts for several other applications, including zsh, bash, tmux, IPython, +Awesome, i3 and Qtile.** + +Features +-------- + +* **Extensible and feature rich, written in Python.** Powerline was + completely rewritten in Python to get rid of as much vimscript as + possible. This has allowed much better extensibility, leaner and better + config files, and a structured, object-oriented codebase with no mandatory + third-party dependencies other than a Python interpreter. +* **Stable and testable code base.** Using Python has allowed unit testing + of all the project code. The code is tested to work in Python 2.6+ and + Python 3. +* **Support for prompts and statuslines in many applications.** Originally + created exclusively for vim statuslines, the project has evolved to + provide statuslines in tmux and several WMs, and prompts for shells like + bash/zsh and other applications. It’s simple to write renderers for any + other applications that Powerline doesn’t yet support. +* **Configuration and colorschemes written in JSON.** JSON is + a standardized, simple and easy to use file format that allows for easy + user configuration across all of Powerline’s supported applications. +* **Fast and lightweight, with daemon support for even better performance.** + Although the code base spans a couple of thousand lines of code with no + goal of “less than X lines of code”, the main focus is on good performance + and as little code as possible while still providing a rich set of + features. The new daemon also ensures that only one Python instance is + launched for prompts and statuslines, which provides excellent + performance. + +*But I hate Python / I don’t need shell prompts / this is just too much +hassle for me / what happened to the original vim-powerline project / …* + +You should check out some of the Powerline derivatives. The most lightweight +and feature-rich alternative is currently the `vim-airline +<https://github.com/vim-airline/vim-airline>`_ project. + +Screenshots +----------- + +Vim statusline +^^^^^^^^^^^^^^ + +**Mode-dependent highlighting** + +* .. image:: _static/img/pl-mode-normal.png + :alt: Normal mode +* .. image:: _static/img/pl-mode-insert.png + :alt: Insert mode +* .. image:: _static/img/pl-mode-visual.png + :alt: Visual mode +* .. image:: _static/img/pl-mode-replace.png + :alt: Replace mode + +**Automatic truncation of segments in small windows** + +* .. image:: _static/img/pl-truncate1.png + :alt: Truncation illustration +* .. image:: _static/img/pl-truncate2.png + :alt: Truncation illustration +* .. image:: _static/img/pl-truncate3.png + :alt: Truncation illustration diff --git a/docs/source/powerline_autodoc.py b/docs/source/powerline_autodoc.py new file mode 100644 index 0000000..eba42ed --- /dev/null +++ b/docs/source/powerline_autodoc.py @@ -0,0 +1,64 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os + +from inspect import formatargspec + +from sphinx.ext import autodoc + +from powerline.lint.inspect import getconfigargspec +from powerline.segments import Segment +from powerline.lib.unicode import unicode + + +def formatvalue(val): + if type(val) is str: + return '="' + unicode(val, 'utf-8').replace('"', '\\"').replace('\\', '\\\\') + '"' + else: + return '=' + repr(val) + + +class ThreadedDocumenter(autodoc.FunctionDocumenter): + '''Specialized documenter subclass for ThreadedSegment subclasses.''' + @classmethod + def can_document_member(cls, member, membername, isattr, parent): + return (isinstance(member, Segment) or + super(ThreadedDocumenter, cls).can_document_member(member, membername, isattr, parent)) + + def format_args(self): + argspec = getconfigargspec(self.object) + return formatargspec(*argspec, formatvalue=formatvalue).replace('\\', '\\\\') + + +class Repr(object): + def __init__(self, repr_contents): + self.repr_contents = repr_contents + + def __repr__(self): + return '<{0}>'.format(self.repr_contents) + + +class EnvironDocumenter(autodoc.AttributeDocumenter): + @classmethod + def can_document_member(cls, member, membername, isattr, parent): + if type(member) is dict and member.get('environ') is os.environ: + return True + else: + return False + + def import_object(self, *args, **kwargs): + ret = super(EnvironDocumenter, self).import_object(*args, **kwargs) + if not ret: + return ret + self.object = self.object.copy() + if 'home' in self.object: + self.object.update(home=Repr('home directory')) + self.object.update(environ=Repr('environ dictionary')) + return True + + +def setup(app): + autodoc.setup(app) + app.add_autodocumenter(ThreadedDocumenter) + app.add_autodocumenter(EnvironDocumenter) diff --git a/docs/source/powerline_automan.py b/docs/source/powerline_automan.py new file mode 100644 index 0000000..85d241c --- /dev/null +++ b/docs/source/powerline_automan.py @@ -0,0 +1,408 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import re +import codecs + +from collections import namedtuple +from argparse import REMAINDER + +from functools import reduce + +from docutils.parsers.rst import Directive +from docutils.parsers.rst.directives import unchanged_required +from docutils import nodes + +from powerline.lib.unicode import u + + +AUTHOR_LINE_START = '* `' +GLYPHS_AUTHOR_LINE_START = '* The glyphs in the font patcher are created by ' + + +def get_authors(): + credits_file = os.path.join(os.path.dirname(__file__), 'license-and-credits.rst') + authors = [] + glyphs_author = None + with codecs.open(credits_file, encoding='utf-8') as CF: + section = None + prev_line = None + for line in CF: + line = line[:-1] + if line and not line.replace('-', ''): + section = prev_line + elif section == 'Authors': + if line.startswith(AUTHOR_LINE_START): + authors.append(line[len(AUTHOR_LINE_START):line.index('<')].strip()) + elif section == 'Contributors': + if line.startswith(GLYPHS_AUTHOR_LINE_START): + assert(not glyphs_author) + glyphs_author = line[len(GLYPHS_AUTHOR_LINE_START):line.index(',')].strip() + prev_line = line + return { + 'authors': ', '.join(authors), + 'glyphs_author': glyphs_author, + } + + +class AutoManSubparsers(object): + def __init__(self): + self.parsers = [] + + def add_parser(self, command, *args, **kwargs): + self.parsers.append((command, AutoManParser(*args, **kwargs))) + return self.parsers[-1][1] + + +Argument = namedtuple('Argument', ('names', 'help', 'choices', 'metavar', 'required', 'nargs', 'is_option', 'is_long_option', 'is_short_option', 'multi', 'can_be_joined')) + + +def parse_argument(*args, **kwargs): + is_option = args[0].startswith('-') + is_long_option = args[0].startswith('--') + is_short_option = is_option and not is_long_option + action = kwargs.get('action', 'store') + multi = kwargs.get('action') in ('append',) or kwargs.get('nargs') is REMAINDER + nargs = kwargs.get('nargs', (1 if action in ('append', 'store') else 0)) + return Argument( + names=args, + help=u(kwargs.get('help', '')), + choices=[str(choice) for choice in kwargs.get('choices', [])], + metavar=kwargs.get('metavar') or args[-1].lstrip('-').replace('-', '_').upper(), + required=kwargs.get('required', False) if is_option else ( + kwargs.get('nargs') not in ('?',)), + nargs=nargs, + multi=multi, + is_option=is_option, + is_long_option=is_long_option, + is_short_option=is_short_option, + can_be_joined=(is_short_option and not multi and not nargs) + ) + + +class AutoManGroup(object): + is_short_option = False + is_option = False + is_long_option = False + can_be_joined = False + + def __init__(self): + self.arguments = [] + self.required = False + + def add_argument(self, *args, **kwargs): + self.arguments.append(parse_argument(*args, **kwargs)) + + def add_argument_group(self, *args, **kwargs): + self.arguments.append(AutoManGroup()) + return self.arguments[-1] + + +class SurroundWith(): + def __init__(self, ret, condition, start='[', end=']'): + self.ret = ret + self.condition = condition + self.start = start + self.end = end + + def __enter__(self, *args): + if self.condition: + self.ret.append(nodes.Text(self.start)) + + def __exit__(self, *args): + if self.condition: + self.ret.append(nodes.Text(self.end)) + + +def insert_separators(ret, sep): + for i in range(len(ret) - 1, 0, -1): + ret.insert(i, nodes.Text(sep)) + return ret + + +def format_usage_arguments(arguments, base_length=None): + line = [] + prev_argument = None + arg_indexes = [0] + arguments = arguments[:] + while arguments: + argument = arguments.pop(0) + if isinstance(argument, nodes.Text): + line += [argument] + continue + can_join_arguments = ( + argument.is_short_option + and prev_argument + and prev_argument.can_be_joined + and prev_argument.required == argument.required + ) + if ( + prev_argument + and not prev_argument.required + and prev_argument.can_be_joined + and not can_join_arguments + ): + line.append(nodes.Text(']')) + arg_indexes.append(len(line)) + if isinstance(argument, AutoManGroup): + arguments = ( + [nodes.Text(' (')] + + insert_separators(argument.arguments[:], nodes.Text(' |')) + + [nodes.Text(' )')] + + arguments + ) + else: + if not can_join_arguments: + line.append(nodes.Text(' ')) + with SurroundWith(line, not argument.required and not argument.can_be_joined): + if argument.can_be_joined and not can_join_arguments and not argument.required: + line.append(nodes.Text('[')) + if argument.is_option: + line.append(nodes.strong()) + name = argument.names[0] + if can_join_arguments: + name = name[1:] + # `--` is automatically transformed into – (EN DASH) + # when parsing into HTML. We do not need this. + line[-1] += [nodes.Text(char) for char in name] + elif argument.nargs is REMAINDER: + line.append(nodes.Text('[')) + line.append(nodes.strong()) + line[-1] += [nodes.Text(char) for char in '--'] + line.append(nodes.Text('] ')) + if argument.nargs: + assert(argument.nargs in (1, '?', REMAINDER)) + with SurroundWith( + line, ( + True + if argument.nargs is REMAINDER + else (argument.nargs == '?' and argument.is_option) + ) + ): + if argument.is_long_option: + line.append(nodes.Text('=')) + line.append(nodes.emphasis(text=argument.metavar)) + elif not argument.is_option: + line.append(nodes.strong(text=argument.metavar)) + if argument.multi: + line.append(nodes.Text('…')) + prev_argument = argument + if ( + prev_argument + and prev_argument.can_be_joined + and not prev_argument.required + ): + line.append(nodes.Text(']')) + arg_indexes.append(len(line)) + ret = [] + if base_length is None: + ret = line + else: + length = base_length + prev_arg_idx = arg_indexes.pop(0) + while arg_indexes: + next_arg_idx = arg_indexes.pop(0) + arg_length = sum((len(element.astext()) for element in line[prev_arg_idx:next_arg_idx])) + if length + arg_length > 68: + ret.append(nodes.Text('\n' + (' ' * base_length))) + length = base_length + ret += line[prev_arg_idx:next_arg_idx] + length += arg_length + prev_arg_idx = next_arg_idx + return ret + + +LITERAL_RE = re.compile(r"`(.*?)'") + + +def parse_argparse_text(text): + rst_text = LITERAL_RE.subn(r'``\1``', text)[0] + ret = [] + for i, text in enumerate(rst_text.split('``')): + if i % 2 == 0: + ret.append(nodes.Text(text)) + else: + ret.append(nodes.literal(text=text)) + return ret + + +def flatten_groups(arguments): + for argument in arguments: + if isinstance(argument, AutoManGroup): + for group_argument in flatten_groups(argument.arguments): + yield group_argument + else: + yield argument + + +def format_arguments(arguments): + return [nodes.definition_list( + '', *[ + nodes.definition_list_item( + '', + nodes.term( + # node.Text('') is required because otherwise for some + # reason first name node is seen in HTML output as + # `<strong>abc</strong>`. + '', *([nodes.Text('')] + ( + insert_separators([ + nodes.strong('', '', *[nodes.Text(ch) for ch in name]) + for name in argument.names + ], ', ') + if argument.is_option else + # Unless node.Text('') is here metavar is written in + # bold in the man page. + [nodes.Text(''), nodes.emphasis(text=argument.metavar)] + ) + ( + [] if not argument.is_option or not argument.nargs else + [nodes.Text(' '), nodes.emphasis('', argument.metavar)] + )) + ), + nodes.definition('', nodes.paragraph('', *parse_argparse_text(argument.help or ''))), + ) + for argument in flatten_groups(arguments) + ] + [ + nodes.definition_list_item( + '', + nodes.term( + '', nodes.Text(''), + nodes.strong(text='-h'), + nodes.Text(', '), + nodes.strong('', '', nodes.Text('-'), nodes.Text('-help')), + ), + nodes.definition('', nodes.paragraph('', nodes.Text('Display help and exit.'))) + ) + ] + )] + + +def format_subcommand_usage(arguments, subcommands, progname, base_length): + return reduce((lambda a, b: a + reduce((lambda c, d: c + d), b, [])), [ + [ + [progname] + + format_usage_arguments(arguments) + + [nodes.Text(' '), nodes.strong(text=subcmd)] + + format_usage_arguments(subparser.arguments) + + [nodes.Text('\n')] + for subcmd, subparser in subparsers.parsers + ] + for subparsers in subcommands + ], []) + + +def format_subcommands(subcommands): + return reduce((lambda a, b: a + reduce((lambda c, d: c + d), b, [])), [ + [ + [ + nodes.section( + '', + nodes.title(text='Arguments specific to ' + subcmd + ' subcommand'), + *format_arguments(subparser.arguments), + ids=['subcmd-' + subcmd] + ) + ] + for subcmd, subparser in subparsers.parsers + ] + for subparsers in subcommands + ], []) + + +class AutoManParser(object): + def __init__(self, description=None, help=None): + self.description = description + self.help = help + self.arguments = [] + self.subcommands = [] + + def add_argument(self, *args, **kwargs): + self.arguments.append(parse_argument(*args, **kwargs)) + + def add_subparsers(self): + self.subcommands.append(AutoManSubparsers()) + return self.subcommands[-1] + + def add_mutually_exclusive_group(self): + self.arguments.append(AutoManGroup()) + return self.arguments[-1] + + def automan_usage(self, prog): + block = nodes.literal_block() + progname = nodes.strong() + progname += [nodes.Text(prog)] + base_length = len(prog) + if self.subcommands: + block += format_subcommand_usage(self.arguments, self.subcommands, progname, base_length) + else: + block += [progname] + block += format_usage_arguments(self.arguments, base_length) + return [block] + + def automan_description(self): + ret = [] + if self.help: + ret += parse_argparse_text(self.help) + ret += format_arguments(self.arguments) + format_subcommands(self.subcommands) + return ret + + +class AutoMan(Directive): + required_arguments = 1 + optional_arguments = 0 + option_spec = dict(prog=unchanged_required, minimal=bool) + has_content = False + + def run(self): + minimal = self.options.get('minimal') + module = self.arguments[0] + template_args = {} + template_args.update(get_authors()) + get_argparser = __import__(str(module), fromlist=[str('get_argparser')]).get_argparser + parser = get_argparser(AutoManParser) + if minimal: + container = nodes.container() + container += parser.automan_usage(self.options['prog']) + container += parser.automan_description() + return [container] + synopsis_section = nodes.section( + '', + nodes.title(text='Synopsis'), + ids=['synopsis-section'], + ) + synopsis_section += parser.automan_usage(self.options['prog']) + description_section = nodes.section( + '', nodes.title(text='Description'), + ids=['description-section'], + ) + description_section += parser.automan_description() + author_section = nodes.section( + '', nodes.title(text='Author'), + nodes.paragraph( + '', + nodes.Text('Written by {authors} and contributors. The glyphs in the font patcher are created by {glyphs_author}.'.format( + **get_authors() + )) + ), + ids=['author-section'] + ) + issues_url = 'https://github.com/powerline/powerline/issues' + reporting_bugs_section = nodes.section( + '', nodes.title(text='Reporting bugs'), + nodes.paragraph( + '', + nodes.Text('Report {prog} bugs to '.format( + prog=self.options['prog'])), + nodes.reference( + issues_url, issues_url, + refuri=issues_url, + internal=False, + ), + nodes.Text('.'), + ), + ids=['reporting-bugs-section'] + ) + return [synopsis_section, description_section, author_section, reporting_bugs_section] + + +def setup(app): + app.add_directive('automan', AutoMan) diff --git a/docs/source/tips-and-tricks.rst b/docs/source/tips-and-tricks.rst new file mode 100644 index 0000000..0af780e --- /dev/null +++ b/docs/source/tips-and-tricks.rst @@ -0,0 +1,110 @@ +*************** +Tips and tricks +*************** + +Vim +=== + +Useful settings +--------------- + +You may find the following vim settings useful when using the Powerline +statusline: + +.. code-block:: vim + + set laststatus=2 " Always display the statusline in all windows + set showtabline=2 " Always display the tabline, even if there is only one tab + set noshowmode " Hide the default mode text (e.g. -- INSERT -- below the statusline) + +.. _tips-and-tricks-vscode: + +VS-Code +======= + +Useful settings +--------------- + +To make powerline work in the internal terminal, add the following settings; +where the shell command needs to be adjusted according to your preferred shell. + +.. code-block:: json + + "terminal.integrated.shell.linux": "/bin/bash" + "terminal.integrated.inheritEnv": true + +.. _tips-and-tricks-urxvt: + +Rxvt-unicode +============ + +Terminus font and urxvt +----------------------- + +The Terminus fonts does not have the powerline glyphs and unless someone submits +a patch to the font author, it is unlikely to happen. However, Andre Klärner +came up with this work around: In your ``~/.Xdefault`` file add the following:: + + urxvt*font: xft:Terminus:pixelsize=12,xft:Inconsolata\ for\ Powerline:pixelsize=12 + +This will allow urxvt to fallback onto the Inconsolata fonts in case it does not +find the right glyphs within the terminus font. + +Source Code Pro font and urxvt +------------------------------ + +Much like the terminus font that was mentioned above, a similar fix can be +applied to the Source Code Pro fonts. + +In the ``~/.Xdefaults`` add the following:: + + URxvt*font: xft:Source\ Code\ Pro\ Medium:pixelsize=13:antialias=true:hinting=true,xft:Source\ Code\ Pro\ Medium:pixelsize=13:antialias=true:hinting=true + +I noticed that Source Code Pro has the glyphs there already, but the pixel size +of the fonts play a role in whether or not the > or the < separators showing up +or not. Using font size 12, glyphs on the right hand side of the powerline are +present, but the ones on the left don’t. Pixel size 14, brings the reverse +problem. Font size 13 seems to work just fine. + +Reloading powerline after update +================================ + +Once you have updated powerline you generally have the following options: + +#. Restart the application you are using it in. This is the safest one. Will not + work if the application uses ``powerline-daemon``. +#. For shell and tmux bindings (except for zsh with libzpython): do not do + anything if you do not use ``powerline-daemon``, run ``powerline-daemon + --replace`` if you do. +#. Use powerline reloading feature. + + .. warning:: + This feature is an unsafe one. It is not guaranteed to work always, it may + render your Python constantly error out in place of displaying powerline + and sometimes may render your application useless, forcing you to + restart. + + *Do not report any bugs occurred when using this feature unless you know + both what caused it and how this can be fixed.* + + * When using zsh with libzpython use + + .. code-block:: bash + + powerline-reload + + .. note:: This shell function is only defined when using libzpython. + + * When using IPython use + + :: + + %powerline reload + + * When using Vim use + + .. code-block:: Vim + + py powerline.reload() + " or (depending on Python version you are using) + py3 powerline.reload() diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst new file mode 100644 index 0000000..2b91747 --- /dev/null +++ b/docs/source/troubleshooting.rst @@ -0,0 +1,333 @@ +*************** +Troubleshooting +*************** + +System-specific issues +====================== + +.. toctree:: + + Linux <troubleshooting/linux> + OS X <troubleshooting/osx> + +Common issues +============= + +After an update something stopped working +----------------------------------------- + +Assuming powerline was working before update and stopped only after there are +two possible explanations: + +* You have more then one powerline installation (e.g. ``pip`` and ``Vundle`` + installations) and you have updated only one. +* Update brought some bug to powerline. + +In the second case you, of course, should report the bug to `powerline bug +tracker <https://github.com/powerline/powerline>`_. In the first you should +make sure you either have only one powerline installation or you update all of +them simultaneously (beware that in the second case you are not supported). To +diagnose this problem you may do the following: + +#) If this problem is observed within the shell make sure that + + .. code-block:: sh + + python -c 'import powerline; print (powerline.__file__)' + + which should report something like + :file:`/usr/lib64/python2.7/site-packages/powerline/__init__.pyc` (if + powerline is installed system-wide) or + :file:`/home/USER/.../powerline/__init__.pyc` (if powerline was cloned + somewhere, e.g. in :file:`/home/USER/.vim/bundle/powerline`) reports the same + location you use to source in your shell configuration: in first case it + should be some location in :file:`/usr` (e.g. + :file:`/usr/share/zsh/site-contrib/powerline.zsh`), in the second it should + be something like + :file:`/home/USER/.../powerline/bindings/zsh/powerline.zsh`. If this is true + it may be a powerline bug, but if locations do not match you should not + report the bug until you observe it on configuration where locations do + match. +#) If this problem is observed specifically within bash make sure that you clean + ``$POWERLINE_COMMAND`` and ``$PROMPT_COMMAND`` environment variables on + startup or, at least, that it was cleaned after update. While different + ``$POWERLINE_COMMAND`` variable should not cause any troubles most of time + (and when it will cause troubles are rather trivial) spoiled + ``$PROMPT_COMMAND`` may lead to strange error messages or absence of exit + code reporting. + + These are the sources which may keep outdated environment variables: + + * Any command launched from any application inherits its environment unless + callee explicitly requests to use specific environment. So if you did + ``exec bash`` after update it is rather unlikely to fix the problem. + * More interesting: `tmux` is a client-server application, it keeps one + server instance per one user. You probably already knew that, but there is + an interesting consequence: once `tmux` server was started it inherits its + environment from the callee and keeps it *forever* (i.e. until server is + killed). This environment is then inherited by applications you start with + ``tmux new-session``. Easiest solution is to kill tmux with ``tmux + kill-server``, but you may also use ``tmux set-environment -u`` to unset + offending variables. + * Also check `When using z powerline shows wrong number of jobs`_: though + this problem should not be seen after update only, it contains another + example of ``$PROMPT_COMMAND`` spoiling results. + +#) If this problem is observed within the vim instance you should check out the + output of the following Ex mode commands + + .. code-block:: vim + + python import powerline as pl ; print (pl.__file__) + python3 import powerline as pl ; print (pl.__file__) + + One (but not both) of them will most likely error out, this is OK. The same + rules apply as in the 1), but in place of sourcing you should seek for the + place where you modify `runtimepath` vim option. If you install powerline + using `VAM <https://github.com/MarcWeber/vim-addon-manager>`_ then no + explicit modifications of runtimpath were performed in your vimrc + (runtimepath is modified by VAM in this case), but powerline will be placed + in :file:`{plugin_root_dir}/powerline` where `{plugin_root_dir}` is stored in + VAM settings dictionary: do `echo g:vim_addon_manager.plugin_root_dir`. + +There is a hint if you want to place powerline repository somewhere, but still +make powerline package importable anywhere: use + + .. code-block:: sh + + pip install --user --editable path/to/powerline + +Tmux/screen-related issues +========================== + +I’m using tmux and Powerline looks like crap, what’s wrong? +----------------------------------------------------------- + +* You need to tell tmux that it has 256-color capabilities. Add this to your + :file:`.tmux.conf` to solve this issue:: + + set -g default-terminal "screen-256color" +* If you’re using iTerm2, make sure that you have enabled the setting + :guilabel:`Set locale variables automatically` in :menuselection:`Profiles --> + Terminal --> Environment`. +* Make sure tmux knows that terminal it is running in support 256 colors. You + may tell it tmux by using ``-2`` option when launching it. + +I’m using tmux/screen and Powerline is colorless +------------------------------------------------ + +* If the above advices do not help, then you need to disable + :ref:`term_truecolor <config-common-term_truecolor>`. +* Alternative: set :ref:`additional_escapes <config-common-additional_escapes>` + to ``"tmux"`` or ``"screen"``. Note that it is known to work perfectly in + screen, but in tmux it may produce ugly spaces. + + .. warning:: + Both tmux and screen are not resending sequences escaped in such a way. Thus + even though additional escaping will work for the last shown prompt, + highlighting will eventually go away when tmux or screen will redraw screen + for some reason. + + E.g. in screen it will go away when you used copy mode and prompt got out of + screen and in tmux it will go away immediately after you press ``<Enter>``. + +In tmux there is a green bar in place of powerline +-------------------------------------------------- + +In order for tmux bindings to work ``powerline-config`` script is required to be +present in ``$PATH``. Alternatively one may define ``$POWERLINE_CONFIG_COMMAND`` +environment variable pointing to the location of the script. *This variable must +be defined prior to launching tmux server and in the environment where server is +started from.* + +Shell issues +============ + +Pipe status segment displays only last value in bash +---------------------------------------------------- + +Make sure that powerline command that sets prompt appears the very first in +``$PROMPT_COMMAND``. To do this ``powerline.sh`` needs to be sourced the very +last, after all other users of ``$PROMPT_COMMAND``. + +Bash prompt stopped updating +---------------------------- + +Make sure that powerline commands appear in ``$PROMPT_COMMAND``: some users of +``$PROMPT_COMMAND`` have a habit of overwriting the value instead of +prepending/appending to it. All powerline commands start with ``_powerline`` or +``powerline``, e.g. ``_powerline_set_prompt``. + +Bash prompt does not show last exit code +---------------------------------------- + +There are two possibilities here: + +* You are using ``default`` theme in place of ``default_leftonly``. Unlike + ``default_leftonly`` ``default`` theme was designed for shells with right + prompt support (e.g. zsh, tcsh, fish) and status in question is supposed to be + shown on the right side which bash cannot display. + +* There is some other user of ``$PROMPT_COMMAND`` which prepended to this + variable, but did not bother keeping the exit code. For the best experience + powerline must appear first in ``$PROMPT_COMMAND`` which may be achieved by + sourcing powerline bindings the last. + + .. note:: + Resourcing bash bindings will not resolve the problem unless you clear + powerline commands from ``$PROMPT_COMMAND`` first. + +When sourcing shell bindings it complains about missing command or file +----------------------------------------------------------------------- + +If you are using ``pip`` based installation do not forget to add pip-specific +executable path to ``$PATH`` environment variable. This path usually looks +something like ``$HOME/.local/bin`` (linux) or +``$HOME/Library/Python/{python_version}/bin`` (OS X). One may check out where +``powerline-config`` script was installed by using ``pip show -f +powerline-status | grep powerline-config`` (does not always work). + +I am suffering bad lags before displaying shell prompt +------------------------------------------------------ + +To get rid of these lags there currently are two options: + +* Run ``powerline-daemon``. Powerline does not automatically start it for you. + See installation instructions for more details. +* Compile and install ``libzpython`` module that lives in + https://bitbucket.org/ZyX_I/zpython. This variant is zsh-specific. +* If you are a python package manager, be sure to set ``POWERLINE_COMMAND`` + to your Powerline command. See installation instructions for details. + + +Prompt is spoiled after completing files in ksh +----------------------------------------------- + +This is exactly why powerline has official mksh support, but not official ksh +support. If you know the solution feel free to share it in `powerline bug +tracker`_. + +When using z powerline shows wrong number of jobs +------------------------------------------------- + +This happens because `z <https://github.com/rupa/z>`_ is launching some jobs in +the background from ``$POWERLINE_COMMAND`` and these jobs fail to finish before +powerline prompt is run. + +Solution to this problem is simple: be sure that :file:`z.sh` is sourced +strictly after :file:`powerline/bindings/bash/powerline.sh`. This way background +jobs are spawned by `z <https://github.com/rupa/z>`_ after powerline has done +its job. + +When using shell I do not see powerline fancy characters +-------------------------------------------------------- + +If your locale encoding is not unicode (any encoding that starts with “utf” or +“ucs” will work, case is ignored) powerline falls back to ascii-only theme. You +should set up your system to use unicode locale or forget about powerline fancy +characters. + +Urxvt unicode3 and frills +------------------------- + +Make sure that, whatever urxvt package you're installing, both the `unicode3` +and `frills` features are enabled at compile time. Run +``urxvt --help 2>&1 | grep options:`` to get a list of enabled options. +This should contain at least `frills`, `unicode3` and optionally `iso14755` +if you want to input Unicode characters as well. + +Compiler flags example: + + --enable-frills \ + --enable-unicode3 + +As long as your terminal emulator is compiled without unicode rendering, +no amount of configuration will make it display unicode characters. +They're being considered 'unnecessary features', but they add negligible +overhead to the size of the installed package (~100KB). + +Vim issues +========== + +My vim statusline has strange characters like ``^B`` in it! +----------------------------------------------------------- + +* Please add ``set encoding=utf-8`` to your :file:`vimrc`. + +My vim statusline has a lot of ``^`` or underline characters in it! +------------------------------------------------------------------- + +* You need to configure the ``fillchars`` setting to disable statusline + fillchars (see ``:h 'fillchars'`` for details). Add this to your :file:`vimrc` + to solve this issue: + + .. code-block:: vim + + set fillchars+=stl:\ ,stlnc:\ + +My vim statusline is hidden/only appears in split windows! +---------------------------------------------------------- + +* Make sure that you have ``set laststatus=2`` in your :file:`vimrc`. + +My vim statusline is not displayed completely and has too much spaces +--------------------------------------------------------------------- + +* Be sure you have ``ambiwidth`` option set to ``single``. +* Alternative: set :ref:`ambiwidth <config-common-ambiwidth>` to 2, remove fancy + dividers (they suck when ``ambiwidth`` is set to double). + +Powerline loses color after editing vimrc +----------------------------------------- + +If your vimrc has something like + +.. code-block:: vim + + autocmd! BufWritePost ~/.vimrc :source ~/.vimrc + +used to automatically source vimrc after saving it then you must add ``nested`` +after pattern (``vimrc`` in this case): + +.. code-block:: vim + + autocmd! BufWritePost ~/.vimrc nested :source ~/.vimrc + +. Alternatively move ``:colorscheme`` command out of the vimrc to the file which +will not be automatically resourced. + +Observed problem is that when you use ``:colorscheme`` command existing +highlighting groups are usually cleared, including those defined by powerline. +To workaround this issue powerline hooks ``Colorscheme`` event, but when you +source vimrc with ``BufWritePost`` (or any other) event, but without ``nested`` +this event is not launched. See also `autocmd-nested +<http://vimcommunity.bitbucket.org/doc/autocmd.txt.html#autocmd-nested>`_ Vim +documentation. + +Powerline loses color after saving any file +------------------------------------------- + +It may be one of the incarnations of the above issue: specifically minibufexpl +is known to trigger it. If you are using minibufexplorer you should set + +.. code-block:: vim + + let g:miniBufExplForceSyntaxEnable = 1 + +variable so that this issue is not triggered. Complete explanation: + +#. When MBE autocommand is executed it launches ``:syntax enable`` Vim command… +#. … which makes Vim source :file:`syntax/syntax.vim` file … +#. … which in turn sources :file:`syntax/synload.vim` … +#. … which executes ``:colorscheme`` command. Normally this command triggers + ``Colorscheme`` event, but in the first point minibufexplorer did set up + autocommands that miss ``nested`` attribute meaning that no events will be + triggered when processing MBE events. + +.. note:: + This setting was introduced in version 6.3.1 of `minibufexpl + <http://www.vim.org/scripts/script.php?script_id=159>`_ and removed in + version 6.5.0 of its successor `minibufexplorer + <http://www.vim.org/scripts/script.php?script_id=3239>`_. It is highly + advised to use the latter because `minibufexpl`_ was last updated late in + 2004. diff --git a/docs/source/troubleshooting/linux.rst b/docs/source/troubleshooting/linux.rst new file mode 100644 index 0000000..e0493c6 --- /dev/null +++ b/docs/source/troubleshooting/linux.rst @@ -0,0 +1,78 @@ +************************ +Troubleshooting on Linux +************************ + +I can’t see any fancy symbols, what’s wrong? +-------------------------------------------- + +* Make sure that you’ve configured gvim or your terminal emulator to use + a patched font. +* You need to set your ``LANG`` and ``LC_*`` environment variables to + a UTF-8 locale (e.g. ``LANG=en_US.utf8``). Consult your Linux distro’s + documentation for information about setting these variables correctly. +* Make sure that vim is compiled with the ``--with-features=big`` flag. +* If you’re using rxvt-unicode make sure that it’s compiled with the + ``--enable-unicode3`` flag. +* If you’re using xterm make sure you have told it to work with unicode. You may + need ``-u8`` command-line argument, ``uxterm`` shell wrapper that is usually + shipped with xterm for this or ``xterm*utf8`` property set to ``1`` or ``2`` + in ``~/.Xresources`` (applied with ``xrdb``). Note that in case ``uxterm`` is + used configuration is done via ``uxterm*…`` properties and not ``xterm*…``. + + In any case the only absolute requirement is launching xterm with UTF-8 + locale. +* If you are using bitmap font make sure that + :file:`/etc/fonts/conf.d/70-no-bitmaps.conf` does not exist. If it does check + out your distribution documentation to find a proper way to remove it (so that + it won’t reappear after update). E.g. in Gentoo this is:: + + eselect fontconfig disable 70-no-bitmaps.conf + + (currently this only removes the symlink from :file:`/etc/fonts/conf.d`). Also + check out that no other fontconfig file does not have ``rejectfont`` tag that + tells fontconfig to disable bitmap fonts (they are referenced as not + scalable). + +The fancy symbols look a bit blurry or “off”! +--------------------------------------------- + +* Make sure that you have patched all variants of your font (i.e. both the + regular and the bold font files). + +I am seeing strange blocks in place of playing/paused/stopped signs +------------------------------------------------------------------- + +If you are using ``powerline_unicode7`` :ref:`top-level theme +<config-common-default_top_theme>` then symbols for player segments are taken +from U+23F4–U+23FA range which is missing from most fonts. You may fix the issue +by using `Symbola <http://users.teilar.gr/~g1951d/>`_ font (or any other font +which contains these glyphs). + +If your terminal emulator is using fontconfig library then you can create +a fontconfig configuration file with the following contents: + +.. code-block:: xml + + <?xml version="1.0"?> + <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> + + <fontconfig> + <alias> + <family>Terminus</family> + <prefer><family>Symbola</family></prefer> + </alias> + </fontconfig> + +(replace ``Terminus`` with the name of the font you are using). Exact sequence +of actions you need to perform is different across distributions, most likely it +will work if you put the above xml into +:file:`/etc/fonts/conf.d/99-prefer-symbola.conf`. On Gentoo you need to put it +into :file:`/etc/fonts/conf.d/99-prefer-symbola.conf` and run:: + + eselect fontconfig enable 99-prefer-symbola + +. + +.. warning:: + This answer is only applicable if you use ``powerline_unicode7`` theme or if + you configured powerline to use the same characters yourself. diff --git a/docs/source/troubleshooting/osx.rst b/docs/source/troubleshooting/osx.rst new file mode 100644 index 0000000..b61063e --- /dev/null +++ b/docs/source/troubleshooting/osx.rst @@ -0,0 +1,71 @@ +*********************** +Troubleshooting on OS X +*********************** + +I can’t see any fancy symbols, what’s wrong? +-------------------------------------------- + +* If you’re using iTerm2, please update to `this revision + <https://github.com/gnachman/iTerm2/commit/8e3ad6dabf83c60b8cf4a3e3327c596401744af6>`_ + or newer. Also make sure that Preferences>Profiles>Text>Non-ASCII Font is the same as + your main Font. +* You need to set your ``LANG`` and ``LC_*`` environment variables to + a UTF-8 locale (e.g. ``LANG=en_US.utf8``). Consult your Linux distro’s + documentation for information about setting these variables correctly. + +The colors look weird in the default OS X Terminal app! +------------------------------------------------------- + +* The arrows may have the wrong colors if you have changed the “minimum + contrast” slider in the color tab of your OS X settings. +* The default OS X Terminal app is known to have some issues with the + Powerline colors. Please use another terminal emulator. iTerm2 should work + fine. + +The colors look weird in iTerm2! +-------------------------------- + +* The arrows may have the wrong colors if you have changed the “minimum + contrast” slider in the color tab of your OS X settings. +* If you're using transparency, check “Keep background colors opaque”. + +Statusline is getting wrapped to the next line in iTerm2 +-------------------------------------------------------- + +* Turn off “Treat ambigious-width characters as double width” in `Preferences + --> Text`. +* Alternative: remove fancy dividers (they suck in this case), set + :ref:`ambiwidth <config-common-ambiwidth>` to 2. + +I receive a ``NameError`` when trying to use Powerline with MacVim! +------------------------------------------------------------------- + +* Please install MacVim using this command:: + + brew install macvim --env-std --override-system-vim + + Then install Powerline locally with ``pip install --user``, or by + running these commands in the ``powerline`` directory:: + + ./setup.py build + ./setup.py install --user + +I receive an ``ImportError`` when trying to use Powerline on OS X! +------------------------------------------------------------------ + +* This is caused by an invalid ``sys.path`` when using system vim and system + Python. Please try to select another Python distribution:: + + sudo port select python python27-apple + +* See `issue #39 <https://github.com/powerline/powerline/issues/39>`_ for + a discussion and other possible solutions for this issue. + +I receive “FSEventStreamStart: register_with_server: ERROR” with status_colors +------------------------------------------------------------------------------ + +This is `a known <https://github.com/joyent/node/issues/5463>`_ libuv issue that +happens if one is trying to watch too many files. It should be fixed in +libuv-0.12. Until then it is suggested to either disable ``status_colors`` (from +:py:func:`powerline.segments.common.vcs.branch`) or choose stat-based watcher +(will have effectively the same effect as disabling ``status_colors``). diff --git a/docs/source/usage.rst b/docs/source/usage.rst new file mode 100644 index 0000000..5bfd304 --- /dev/null +++ b/docs/source/usage.rst @@ -0,0 +1,88 @@ +***** +Usage +***** + +Application-specific requirements +--------------------------------- + +Vim plugin requirements +^^^^^^^^^^^^^^^^^^^^^^^ + +The vim plugin requires a vim version with Python support compiled in. Presence +of Python support in Vim can be checked by running ``vim --version | grep ++python``. + +If Python support is absent then Vim needs to be compiled with it. To do this +use ``--enable-pythoninterp`` :file:`./configure` flag (Python 3 uses +``--enable-python3interp`` flag instead). Note that this also requires the +related Python headers to be installed. Please consult distribution’s +documentation for details on how to compile and install packages. + +Vim version 7.4 or newer is recommended for performance reasons, but Powerline +supports Vim 7.0.112 and higher. + +Shell prompts requirements +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Due to fish having incorrect code for prompt width calculations up to version +2.1 and no way to tell that certain sequence of characters has no width +(``%{…%}`` in zsh and ``\[…\]`` in bash prompts serve exactly this purpose) +users that have fish versions below 2.1 are not supported.. + + +WM widgets requirements +^^^^^^^^^^^^^^^^^^^^^^^ + +Awesome is supported starting from version 3.5.1, inclusive. QTile is supported +from version 0.6, inclusive. + +.. _usage-terminal-emulators: + +Terminal emulator requirements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Powerline uses several special glyphs to get the arrow effect and some custom +symbols for developers. This requires either a symbol font or a patched font +installed. Used terminal emulator must also support either patched fonts or +fontconfig for Powerline to work properly. + +:ref:`24-bit color support <config-common-term_truecolor>` can also be enabled +if terminal emulator supports it. + +.. table:: Application/terminal emulator feature support matrix + :name: term-feature-support-matrix + + ===================== ======= ===================== ===================== ===================== + Name OS Patched font support Fontconfig support 24-bit color support + ===================== ======= ===================== ===================== ===================== + Gvim Linux |i_yes| |i_no| |i_yes| + iTerm2 OS X |i_yes| |i_no| |i_no| + Konsole Linux |i_yes| |i_yes| |i_yes| + lxterminal Linux |i_yes| |i_yes| |i_no| + MacVim OS X |i_yes| |i_no| |i_yes| + rxvt-unicode Linux |i_partial| [#]_ |i_no| |i_no| + st Linux |i_yes| |i_yes| |i_yes| [#]_ + Terminal.app OS X |i_yes| |i_no| |i_no| + libvte-based [#]_ Linux |i_yes| |i_yes| |i_yes| [#]_ + xterm Linux |i_yes| |i_no| |i_partial| [#]_ + fbterm Linux |i_yes| |i_yes| |i_no| + ===================== ======= ===================== ===================== ===================== + +.. |i_yes| image:: _static/img/icons/tick.png +.. |i_no| image:: _static/img/icons/cross.png +.. |i_partial| image:: _static/img/icons/error.png + +.. [#] Must be compiled with ``--enable-unicode3`` for the patched font to work. +.. [#] Since version 0.5. +.. [#] Including XFCE terminal and GNOME terminal. +.. [#] Since version 0.36. +.. [#] Uses nearest color from 8-bit palette. + +Plugins +------- + +.. toctree:: + + usage/shell-prompts + usage/wm-widgets + usage/other diff --git a/docs/source/usage/other.rst b/docs/source/usage/other.rst new file mode 100644 index 0000000..ff0ccae --- /dev/null +++ b/docs/source/usage/other.rst @@ -0,0 +1,224 @@ +************* +Other plugins +************* + +.. _vim-vimrc: + +Vim statusline +============== + +If installed using pip just add + +.. code-block:: vim + + python from powerline.vim import setup as powerline_setup + python powerline_setup() + python del powerline_setup + +(replace ``python`` with ``python3`` if appropriate) to the :file:`vimrc`. + +.. note:: + Status line will not appear by default when there is only a single window + displayed. Run ``:h 'laststatus'`` in Vim for more information. + +If the repository was just cloned the following line needs to be added to the +:file:`vimrc`: + +.. code-block:: vim + + set rtp+={repository_root}/powerline/bindings/vim + +where ``{repository_root}`` is the absolute path to the Powerline installation +directory (see :ref:`repository root <repository-root>`). + +If pathogen is used and Powerline functionality is not needed outside of Vim +then it is possible to simply add Powerline as a bundle and point the path above +to the Powerline bundle directory, e.g. +:file:`~/.vim/bundle/powerline/powerline/bindings/vim`. + +Vundle and NeoBundle users may instead use + +.. code-block:: vim + + Bundle 'powerline/powerline', {'rtp': 'powerline/bindings/vim/'} + +(NeoBundle users need ``NeoBundle`` in place of ``Bundle``, otherwise setup is +the same). + +Vim-addon-manager setup is even easier because it is not needed to write this +big path or install anything by hand: ``powerline`` can be installed and +activated just like any other plugin using + +.. code-block:: vim + + call vam#ActivateAddons(['powerline']) + +.. warning:: + *Never* install powerline with pathogen/VAM/Vundle/NeoBundle *and* with pip. + If powerline functionality is needed in applications other then Vim then + system-wide installation (in case used OS distribution has powerline + package), pip-only or ``pip install --editable`` kind of installation + performed on the repository installed by Vim plugin manager should be used. + + No issues are accepted in powerline issue tracker for double pip/non-pip + installations, especially if these issues occur after update. + +.. note:: + If supplied :file:`powerline.vim` file is used to load powerline there are + additional configuration variables available: ``g:powerline_pycmd`` and + ``g:powerline_pyeval``. First sets command used to load powerline: expected + values are ``"py"`` and ``"py3"``. Second sets function used in statusline, + expected values are ``"pyeval"`` and ``"py3eval"``. + + If ``g:powerline_pycmd`` is set to the one of the expected values then + ``g:powerline_pyeval`` will be set accordingly. If it is set to some other + value then ``g:powerline_pyeval`` must also be set. Powerline will not check + that Vim is compiled with Python support if ``g:powerline_pycmd`` is set to + an unexpected value. + + These values are to be used to specify the only Python that is to be loaded + if both versions are present: Vim may disable loading one python version if + other was already loaded. They should also be used if two python versions + are able to load simultaneously, but powerline was installed only for + python-3 version. + +Tmux statusline +=============== + +Add the following lines to :file:`.tmux.conf`, where ``{repository_root}`` is +the absolute path to the Powerline installation directory (see :ref:`repository +root <repository-root>`):: + + source "{repository_root}/powerline/bindings/tmux/powerline.conf" + +.. note:: + The availability of the ``powerline-config`` command is required for + powerline support. The location of this script may be specified via + the ``$POWERLINE_CONFIG_COMMAND`` environment variable. + +.. note:: + It is advised to run ``powerline-daemon`` before adding the above line to + tmux.conf. To do so add:: + + run-shell "powerline-daemon -q" + + to :file:`.tmux.conf`. + +.. warning:: + Segments which depend on current working directory (e.g. + :py:func:`powerline.segments.common.vcs.branch`) require also setting up + :ref:`shell bindings <usage-shell>`. It is not required to use powerline + shell prompt, :ref:`components setting <config-ext-components>` allows to + set up only powerline bindings for tmux without altering your prompt. + Without setting up shell bindings powerline will use current working + directory of *tmux server* which is probably not what you need. + + Segments which depend on environment like + :py:func:`powerline.segments.common.env.virtualenv` will not work at all + (i.e. they will use environment of the tmux server), tracking environment + changes is going to slow down shell a lot. + + In any case it is suggested to avoid both kinds of segments in tmux + :ref:`themes <config-themes>` because even support for tracking current + directory is very limited: + + #. It works only in shell. Should you e.g. run Vim and run ``:cd`` there you + will get current working directory from shell. + #. It works only in local shell and requires configuring it. + #. Some shells are not supported at all. + +IPython prompt +============== + +For IPython>=7.0, add the following line to +:file:`~/.ipython/profile_default/ipython_config.py` file in the used profile: + + +.. code-block:: Python + + from powerline.bindings.ipython.since_7 import PowerlinePrompts + c.TerminalInteractiveShell.prompts_class = PowerlinePrompts + +.. note:: + If certain graphical/colored elements are not showing, make sure `c.TerminalInteractiveShell.simple_prompt` + is set to `False` in your config. + Setting ``simple_prompt`` to False after IPython-5.0 is required regardless + of whether you use ``c.InteractiveShellApp.extensions`` setting or + ``c.TerminalInteractiveShell.prompts_class``. But you probably already have + this line because ``simple_prompt`` is set to ``False`` by default and IPython + is not very useful without it. + +For IPython>=5.0 and <7.0 it is suggested to use + +.. code-block:: Python + + from powerline.bindings.ipython.since_5 import PowerlinePrompts + c = get_config() + c.TerminalInteractiveShell.simple_prompt = False + c.TerminalInteractiveShell.prompts_class = PowerlinePrompts + + + +For IPython>=5.0 and <7.0 you may use the below set up, but it is deprecated. +For IPython>=0.11 add the following line to +:file:`~/.ipython/profile_default/ipython_config.py` file in the used profile: + +.. code-block:: Python + + c = get_config() + c.InteractiveShellApp.extensions = [ + 'powerline.bindings.ipython.post_0_11' + ] + +For IPython<0.11 add the following lines to :file:`.ipython/ipy_user_conf.py`: + +.. code-block:: Python + + # top + from powerline.bindings.ipython.pre_0_11 import setup as powerline_setup + + # main() function (assuming ipython was launched without configuration to + # create skeleton ipy_user_conf.py file): + powerline_setup() + + +IPython=0.11* is not supported and does not work. IPython<0.10 was not +tested (not installable by pip). + +.. _pdb-prompt: + +PDB prompt +========== + +To use Powerline with PDB prompt you need to use custom class. Inherit your +class from :py:class:`pdb.Pdb` and decorate it with +:py:func:`powerline.bindings.pdb.use_powerline_prompt`: + +.. code-block:: Python + + import pdb + + from powerline.bindings.pdb import use_powerline_prompt + + @use_powerline_prompt + class MyPdb(pdb.Pdb): + pass + + MyPdb.run('some.code.to.debug()') + +. Alternatively you may use + +.. code-block:: bash + + python -mpowerline.bindings.pdb path/to/script.py + +just like you used ``python -m pdb``. + +.. note: + If you are using Python-2.6 you need to use ``python + -mpowerline.bindings.pdb.__main__``, not what is shown above. + +.. warning: + Using PyPy (not PyPy3) forces ASCII-only prompts. In other cases unicode + characters are allowed, even if you use `pdbpp + <https://pypi.python.org/pypi/pdbpp>`_. diff --git a/docs/source/usage/shell-prompts.rst b/docs/source/usage/shell-prompts.rst new file mode 100644 index 0000000..17774da --- /dev/null +++ b/docs/source/usage/shell-prompts.rst @@ -0,0 +1,161 @@ +.. _usage-shell: + +************* +Shell prompts +************* + +.. note:: + Powerline can operate without a background daemon, but the shell performance + can be very slow. The Powerline daemon improves this performance + significantly, but must be started separately. It is advised to add + + .. code-block:: bash + + powerline-daemon -q + + before any other powerline-related code in the shell configuration file. + +Bash prompt +=========== + +Add the following line to the :file:`bashrc`, where ``{repository_root}`` is the +absolute path to the Powerline installation directory (see :ref:`repository root +<repository-root>`): + +.. code-block:: bash + + . {repository_root}/powerline/bindings/bash/powerline.sh + +.. note:: + Since without powerline daemon bash bindings are very slow PS2 + (continuation) and PS3 (select) prompts are not set up. Thus it is advised + to use + + .. code-block:: bash + + powerline-daemon -q + POWERLINE_BASH_CONTINUATION=1 + POWERLINE_BASH_SELECT=1 + . {repository_root}/powerline/bindings/bash/powerline.sh + + in the bash configuration file. Without ``POWERLINE_BASH_*`` variables PS2 + and PS3 prompts are computed exactly once at bash startup. + +.. warning:: + At maximum bash continuation PS2 and select PS3 prompts are computed each + time main PS1 prompt is computed. Thus putting e.g. current time into PS2 or + PS3 prompt will not work as expected. + + At minimum they are computed once on startup. + +Zsh prompt +========== + +Add the following line to the :file:`zshrc`, where ``{repository_root}`` is the +absolute path to the Powerline installation directory (see :ref:`repository root +<repository-root>`): + +.. code-block:: bash + + . {repository_root}/powerline/bindings/zsh/powerline.zsh + +Fish prompt +=========== + +Add the following line to :file:`config.fish`, where ``{repository_root}`` is +the absolute path to the Powerline installation directory (see :ref:`repository +root <repository-root>`): + +.. code-block:: bash + + set fish_function_path $fish_function_path "{repository_root}/powerline/bindings/fish" + powerline-setup + +.. warning:: Fish is supported only starting from version 2.1. + +Rcsh prompt +=========== + +Powerline supports Plan9 rc reimplementation *by Byron Rakitzis* packaged by +many \*nix distributions. To use it add + +.. code-block:: bash + + . {repository_root}/powerline/bindings/rc/powerline.rc + +(``{repository_root}`` is the absolute path to the Powerline installation +directory, see :ref:`repository root <repository-root>`) to :file:`rcrc` file +(usually :file:`~/.rcrc`) and make sure ``rc`` is started as a login shell (with +``-l`` argument): otherwise this configuration file is not read. + +.. warning:: + Original Plan9 shell and its \*nix port are not supported because they are + missing ``prompt`` special function (it is being called once before each + non-continuation prompt). Since powerline could not support shell without + this or equivalent feature some other not-so-critical features of that port + were used. + +Busybox (ash), mksh and dash prompt +===================================== + +After launching busybox run the following command: + +.. code-block:: bash + + . {repository_root}/powerline/bindings/shell/powerline.sh + +where ``{repository_root}`` is the absolute path to the Powerline installation +directory (see :ref:`repository root <repository-root>`). + +Mksh users may put this line into ``~/.mkshrc`` file. Dash users may use the +following in ``~/.profile``: + +.. code-block:: bash + + if test "$0" != "${0#dash}" ; then + export ENV={repository_root}/powerline/bindings/shell/powerline.sh + fi + +.. note:: + Dash users that already have ``$ENV`` defined should either put the ``. + …/shell/powerline.sh`` line in the ``$ENV`` file or create a new file which + will source (using ``.`` command) both former ``$ENV`` file and + :file:`powerline.sh` files and set ``$ENV`` to the path of this new file. + +.. warning:: + Mksh users have to set ``$POWERLINE_SHELL_CONTINUATION`` and + ``$POWERLINE_SHELL_SELECT`` to 1 to get PS2 and PS3 (continuation and + select) prompts support respectively: as command substitution is not + performed in these shells for these prompts they are updated once each time + PS1 prompt is displayed which may be slow. + + It is also known that while PS2 and PS3 update is triggered at PS1 update it + is *actually performed* only *next* time PS1 is displayed which means that + PS2 and PS3 prompts will be outdated and may be incorrect for this reason. + + Without these variables PS2 and PS3 prompts will be set once at startup. + This only touches mksh users: busybox and dash both have no such problem. + +.. warning:: + Job count is using some weird hack that uses signals and temporary files for + interprocess communication. It may be wrong sometimes. Not the case in mksh. + +.. warning:: + Busybox has two shells: ``ash`` and ``hush``. Second is known to segfault in + busybox 1.22.1 when using :file:`powerline.sh` script. + +Python Virtual Environments (conda, pyenv) +========================================== + +If your system uses virtual environments to manage different Python versions, +such as pyenv or anaconda, these tools will add a performance delay to every +shell prompt. This delay can be bypassed by explicitly specifying your command +path. + + .. code-block:: bash + + export POWERLINE_COMMAND={path_to_powerline} + +where ``{path_to_powerline}`` is the full filepath for powerline. If you +installed Powerline within an environment, you can find this path for pyenv +with ``pyenv which powerline`` or for conda with ``which powerline``. diff --git a/docs/source/usage/wm-widgets.rst b/docs/source/usage/wm-widgets.rst new file mode 100644 index 0000000..bc63da6 --- /dev/null +++ b/docs/source/usage/wm-widgets.rst @@ -0,0 +1,101 @@ +********************** +Window manager widgets +********************** + +Awesome widget +============== + +.. note:: Powerline currently only supports awesome 3.5 and 4+. + +.. note:: The Powerline widget will spawn a shell script that runs in the + background and updates the statusline with ``awesome-client``. + +Add the following to :file:`rc.lua`, where ``{repository_root}`` is the absolute +path to Powerline installation directory (see :ref:`repository root +<repository-root>`): + +.. code-block:: lua + + package.path = package.path .. ';{repository_root}/powerline/bindings/awesome/?.lua' + require('powerline') + +Then add the ``powerline_widget`` to ``wibox``: + +.. code-block:: lua + + -- awesome3.5 + right_layout:add(powerline_widget) + + -- awesome4+ + s.mywibox:setup { + ... + { -- Right widgets + ... + powerline_widget, + }, + } + +Qtile widget +============ + +Add the following to :file:`~/.config/qtile/config.py`: + +.. code-block:: python + + from libqtile.bar import Bar + from libqtile.config import Screen + from libqtile.widget import Spacer + + from powerline.bindings.qtile.widget import PowerlineTextBox + + screens = [ + Screen( + top=Bar([ + PowerlineTextBox(update_interval=2, side='left'), + Spacer(), + PowerlineTextBox(update_interval=2, side='right'), + ], + 35 # width + ), + ), + ] + +.. _lemonbar-usage: + +lemonbar (formerly bar-aint-recursive) +====================================== + +To run the bar simply start the binding script: + + python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py + +You can specify options to be passed to ``lemonbar`` after ``--``, like so: + + python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py --height 16 -- -f "Source Code Pro for Powerline-9" + +to run with i3, simply ``exec`` this in the i3 config file and set the ``--i3`` switch: + + exec python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py --i3 + +Running the binding in i3-mode will require `i3ipc <https://github.com/acrisci/i3ipc-python>`_. + +See the `lemonbar documentation <https://github.com/LemonBoy/bar>`_ for more +information and options. + +All ``powerline-lemonbar.py`` arguments: + +.. automan:: powerline.commands.lemonbar + :prog: powerline-lemonbar.py + :minimal: true + +I3 bar +====== + +Add the following to :file:`~/.config/i3/config`:: + + bar { + status_command python /path/to/powerline/bindings/i3/powerline-i3.py + font pango:PowerlineFont 12 + } + +where ``PowerlineFont`` is any system font with powerline support. diff --git a/font/10-powerline-symbols.conf b/font/10-powerline-symbols.conf new file mode 100644 index 0000000..7e34a12 --- /dev/null +++ b/font/10-powerline-symbols.conf @@ -0,0 +1,105 @@ +<?xml version="1.0"?> +<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> + +<fontconfig> + <alias> + <family>monospace</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Droid Sans Mono</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Droid Sans Mono Slashed</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Droid Sans Mono Dotted</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>DejaVu Sans Mono</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>DejaVu Sans Mono</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Envy Code R</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Inconsolata</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Lucida Console</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Monaco</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Pragmata</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>PragmataPro</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Menlo</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Source Code Pro</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Consolas</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Anonymous pro</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Bitstream Vera Sans Mono</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Liberation Mono</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Ubuntu Mono</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Meslo LG L</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Meslo LG L DZ</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Meslo LG M</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Meslo LG M DZ</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Meslo LG S</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> + <alias> + <family>Meslo LG S DZ</family> + <prefer><family>PowerlineSymbols</family></prefer> + </alias> +</fontconfig> diff --git a/font/PowerlineSymbols.otf b/font/PowerlineSymbols.otf Binary files differnew file mode 100644 index 0000000..b1582af --- /dev/null +++ b/font/PowerlineSymbols.otf diff --git a/powerline/__init__.py b/powerline/__init__.py new file mode 100644 index 0000000..a50b939 --- /dev/null +++ b/powerline/__init__.py @@ -0,0 +1,991 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import sys +import logging + +from threading import Lock, Event + +from powerline.colorscheme import Colorscheme +from powerline.lib.config import ConfigLoader +from powerline.lib.unicode import unicode, safe_unicode, FailedUnicode +from powerline.config import DEFAULT_SYSTEM_CONFIG_DIR +from powerline.lib.dict import mergedicts +from powerline.lib.encoding import get_preferred_output_encoding +from powerline.lib.path import join +from powerline.version import __version__ + +class NotInterceptedError(BaseException): + pass + + +def _config_loader_condition(path): + if path and os.path.isfile(path): + return path + return None + + +def _find_config_files(search_paths, config_file, config_loader=None, loader_callback=None): + config_file += '.json' + found = False + for path in search_paths: + config_file_path = join(path, config_file) + if os.path.isfile(config_file_path): + yield config_file_path + found = True + elif config_loader: + config_loader.register_missing(_config_loader_condition, loader_callback, config_file_path) + if not found: + raise IOError('Config file not found in search paths ({0}): {1}'.format( + ', '.join(search_paths), + config_file + )) + + +class PowerlineLogger(object): + '''Proxy class for logging.Logger instance + + It emits messages in format ``{ext}:{prefix}:{message}`` where + + ``{ext}`` + is a used powerline extension (e.g. “vim”, “shell”, “ipython”). + ``{prefix}`` + is a local prefix, usually a segment name. + ``{message}`` + is the original message passed to one of the logging methods. + + Each of the methods (``critical``, ``exception``, ``info``, ``error``, + ``warn``, ``debug``) expects to receive message in an ``str.format`` format, + not in printf-like format. + + Log is saved to the location :ref:`specified by user <config-common-log>`. + ''' + + 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 '') + msg = safe_unicode(msg) + if args or kwargs: + args = [safe_unicode(s) if isinstance(s, bytes) else s for s in args] + kwargs = dict(( + (k, safe_unicode(v) if isinstance(v, bytes) else v) + for k, v in kwargs.items() + )) + 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) + + +_fallback_logger = None + + +def get_fallback_logger(stream=None): + global _fallback_logger + if _fallback_logger: + return _fallback_logger + + log_format = '%(asctime)s:%(levelname)s:%(message)s' + formatter = logging.Formatter(log_format) + + level = logging.WARNING + handler = logging.StreamHandler(stream) + handler.setLevel(level) + handler.setFormatter(formatter) + + logger = logging.Logger('powerline') + logger.setLevel(level) + logger.addHandler(handler) + _fallback_logger = PowerlineLogger(None, logger, '_fallback_') + return _fallback_logger + + +def _generate_change_callback(lock, key, dictionary): + def on_file_change(path): + with lock: + dictionary[key] = True + return on_file_change + + +def get_config_paths(): + '''Get configuration paths from environment variables. + + Uses $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS according to the XDG specification. + + :return: list of paths + ''' + config_home = os.environ.get('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config')) + config_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[:0] = reversed([join(d, 'powerline') for d in config_dirs.split(':')]) + plugin_path = join(os.path.realpath(os.path.dirname(__file__)), 'config_files') + config_paths.insert(0, plugin_path) + return config_paths + + +def generate_config_finder(get_config_paths=get_config_paths): + '''Generate find_config_files function + + This function will find .json file given its path. + + :param function get_config_paths: + Function that being called with no arguments will return a list of paths + that should be searched for configuration files. + + :return: + Function that being given configuration file name will return full path + to it or raise IOError if it failed to find the file. + ''' + config_paths = get_config_paths() + return lambda *args: _find_config_files(config_paths, *args) + + +def load_config(cfg_path, find_config_files, config_loader, loader_callback=None): + '''Load configuration file and setup watches + + Watches are only set up if loader_callback is not None. + + :param str cfg_path: + Path for configuration file that should be loaded. + :param function find_config_files: + Function that finds configuration file. Check out the description of + the return value of ``generate_config_finder`` function. + :param ConfigLoader config_loader: + Configuration file loader class instance. + :param function loader_callback: + Function that will be called by config_loader when change to + configuration file is detected. + + :return: Configuration file contents. + ''' + found_files = find_config_files(cfg_path, config_loader, loader_callback) + ret = None + for path in found_files: + if loader_callback: + config_loader.register(loader_callback, path) + if ret is None: + ret = config_loader.load(path) + else: + mergedicts(ret, config_loader.load(path)) + return ret + + +def _set_log_handlers(common_config, logger, get_module_attr, stream=None): + '''Set log handlers + + :param dict common_config: + Configuration dictionary used to create handler. + :param logging.Logger logger: + Logger to which handlers will be attached. + :param func get_module_attr: + :py:func:`gen_module_attr_getter` output. + :param file stream: + Stream to use by default for :py:class:`logging.StreamHandler` in place + of :py:attr:`sys.stderr`. May be ``None``. + ''' + log_targets = common_config['log_file'] + num_handlers = 0 + for log_target in log_targets: + if log_target is None: + log_target = ['logging.StreamHandler', []] + elif isinstance(log_target, unicode): + log_target = os.path.expanduser(log_target) + log_dir = os.path.dirname(log_target) + if log_dir and not os.path.isdir(log_dir): + os.mkdir(log_dir) + log_target = ['logging.FileHandler', [[log_target]]] + module, handler_class_name = log_target[0].rpartition('.')[::2] + module = module or 'logging.handlers' + try: + handler_class_args = log_target[1][0] + except IndexError: + if module == 'logging' and handler_class_name == 'StreamHandler': + handler_class_args = [stream] + else: + handler_class_args = () + try: + handler_class_kwargs = log_target[1][1] + except IndexError: + handler_class_kwargs = {} + module = str(module) + handler_class_name = str(handler_class_name) + handler_class = get_module_attr(module, handler_class_name) + if not handler_class: + continue + handler = handler_class(*handler_class_args, **handler_class_kwargs) + try: + handler_level_name = log_target[2] + except IndexError: + handler_level_name = common_config['log_level'] + try: + handler_format = log_target[3] + except IndexError: + handler_format = common_config['log_format'] + handler.setLevel(getattr(logging, handler_level_name)) + handler.setFormatter(logging.Formatter(handler_format)) + logger.addHandler(handler) + num_handlers += 1 + if num_handlers == 0 and log_targets: + raise ValueError('Failed to set up any handlers') + + +def create_logger(common_config, use_daemon_threads=True, ext='__unknown__', + import_paths=None, imported_modules=None, stream=None): + '''Create logger according to provided configuration + + :param dict common_config: + Common configuration, from :py:func:`finish_common_config`. + :param bool use_daemon_threads: + Whether daemon threads should be used. Argument to + :py:class:`PowerlineLogger` constructor. + :param str ext: + Used extension. Argument to :py:class:`PowerlineLogger` constructor. + :param set imported_modules: + Set where imported modules are saved. Argument to + :py:func:`gen_module_attr_getter`. May be ``None``, in this case new + empty set is used. + :param file stream: + Stream to use by default for :py:class:`logging.StreamHandler` in place + of :py:attr:`sys.stderr`. May be ``None``. + + :return: Three objects: + + #. :py:class:`logging.Logger` instance. + #. :py:class:`PowerlineLogger` instance. + #. Function, output of :py:func:`gen_module_attr_getter`. + ''' + logger = logging.Logger('powerline') + level = getattr(logging, common_config['log_level']) + logger.setLevel(level) + + pl = PowerlineLogger(use_daemon_threads, logger, ext) + get_module_attr = gen_module_attr_getter( + pl, common_config['paths'], + set() if imported_modules is None else imported_modules) + + _set_log_handlers(common_config, logger, get_module_attr, stream) + + return logger, pl, get_module_attr + + +def get_default_theme(is_unicode=True): + '''Get default theme used by powerline + + :param bool is_unicode: + If true, return theme for unicode environments, otherwise return theme + that is supposed to be ASCII-only. + + :return: theme name. + ''' + return 'powerline_terminus' if is_unicode else 'ascii' + + +def finish_common_config(encoding, common_config): + '''Add default values to common config and expand ~ in paths + + :param dict common_config: + Common configuration, as it was just loaded. + + :return: + Copy of common configuration with all configuration keys and expanded + paths. + ''' + encoding = encoding.lower() + default_top_theme = get_default_theme( + encoding.startswith('utf') or encoding.startswith('ucs')) + + common_config = common_config.copy() + common_config.setdefault('default_top_theme', default_top_theme) + common_config.setdefault('paths', []) + common_config.setdefault('watcher', 'auto') + common_config.setdefault('log_level', 'WARNING') + common_config.setdefault('log_format', '%(asctime)s:%(levelname)s:%(message)s') + common_config.setdefault('term_truecolor', False) + common_config.setdefault('term_escape_style', 'auto') + common_config.setdefault('ambiwidth', 1) + common_config.setdefault('additional_escapes', None) + common_config.setdefault('reload_config', True) + common_config.setdefault('interval', None) + common_config.setdefault('log_file', [None]) + + if not isinstance(common_config['log_file'], list): + common_config['log_file'] = [common_config['log_file']] + + common_config['paths'] = [ + os.path.expanduser(path) for path in common_config['paths'] + ] + + return common_config + + +if sys.version_info < (3,): + # `raise exception[0], None, exception[1]` is a SyntaxError in python-3* + # Not using ('''…''') because this syntax does not work in python-2.6 + exec(( + 'def reraise(exception):\n' + ' if type(exception) is tuple:\n' + ' raise exception[0], None, exception[1]\n' + ' else:\n' + ' raise exception\n' + )) +else: + def reraise(exception): + if type(exception) is tuple: + raise exception[0].with_traceback(exception[1]) + else: + raise exception + + +def gen_module_attr_getter(pl, import_paths, imported_modules): + def get_module_attr(module, attr, prefix='powerline'): + '''Import module and get its attribute. + + Replaces ``from {module} import {attr}``. + + :param str module: + Module name, will be passed as first argument to ``__import__``. + :param str attr: + Module attribute, will be passed to ``__import__`` as the only value + in ``fromlist`` tuple. + + :return: + Attribute value or ``None``. Note: there is no way to distinguish + between successful import of attribute equal to ``None`` and + unsuccessful import. + ''' + oldpath = sys.path + sys.path = import_paths + sys.path + module = str(module) + attr = str(attr) + try: + imported_modules.add(module) + return getattr(__import__(module, fromlist=(attr,)), attr) + except Exception as e: + pl.exception('Failed to import attr {0} from module {1}: {2}', attr, module, str(e), prefix=prefix) + return None + finally: + sys.path = oldpath + + return get_module_attr + + +LOG_KEYS = set(('log_format', 'log_level', 'log_file', 'paths')) +'''List of keys related to logging +''' + + +def _get_log_keys(common_config): + '''Return a common configuration copy with only log-related config left + + :param dict common_config: + Common configuration. + + :return: + :py:class:`dict` instance which has only keys from + :py:attr:`powerline.LOG_KEYS` left. + ''' + return dict(( + (k, v) for k, v in common_config.items() if k in LOG_KEYS + )) + + +DEFAULT_UPDATE_INTERVAL = 2 +'''Default value for :ref:`update_interval <config-ext-update_interval>` +''' + + +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.renderers.{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``). When ``.foo`` (with leading + dot) variant is used ``renderer_module`` will be + ``powerline.renderers.{ext}{renderer_module}``. + :param bool run_once: + Determines whether :py:meth:`render` method will be run only once + during python session. + :param Logger logger: + If present no new logger will be created and the provided logger will be + used. + :param bool use_daemon_threads: + When creating threads make them daemon ones. + :param Event shutdown_event: + Use this Event as shutdown_event instead of creating new event. + :param ConfigLoader config_loader: + Instance of the class that manages (re)loading of the configuration. + ''' + + def __init__(self, *args, **kwargs): + self.init_args = (args, kwargs) + self.init(*args, **kwargs) + + def init(self, + ext, + renderer_module=None, + run_once=False, + logger=None, + use_daemon_threads=True, + shutdown_event=None, + config_loader=None): + '''Do actual initialization. + + __init__ function only stores the arguments and runs this function. This + function exists for powerline to be able to reload itself: it is easier + to make ``__init__`` store arguments and call overridable ``init`` than + tell developers that each time they override Powerline.__init__ in + subclasses they must store actual arguments. + ''' + self.ext = ext + self.run_once = run_once + self.logger = logger + self.had_logger = bool(self.logger) + self.use_daemon_threads = use_daemon_threads + + if not renderer_module: + self.renderer_module = 'powerline.renderers.' + ext + elif '.' not in renderer_module: + self.renderer_module = 'powerline.renderers.' + renderer_module + elif renderer_module.startswith('.'): + self.renderer_module = 'powerline.renderers.' + ext + renderer_module + elif renderer_module.endswith('.'): + self.renderer_module = renderer_module[:-1] + else: + self.renderer_module = renderer_module + + self.find_config_files = generate_config_finder(self.get_config_paths) + + self.cr_kwargs_lock = Lock() + self.cr_kwargs = {} + self.cr_callbacks = {} + for key in ('main', 'colors', 'colorscheme', 'theme'): + self.cr_kwargs['load_' + key] = True + self.cr_callbacks[key] = _generate_change_callback( + self.cr_kwargs_lock, + 'load_' + key, + self.cr_kwargs + ) + + self.shutdown_event = shutdown_event or Event() + self.config_loader = config_loader or ConfigLoader(shutdown_event=self.shutdown_event, run_once=run_once) + self.run_loader_update = False + + self.renderer_options = {} + + self.prev_common_config = None + self.prev_ext_config = None + self.pl = None + self.setup_args = () + self.setup_kwargs = {} + self.imported_modules = set() + self.update_interval = DEFAULT_UPDATE_INTERVAL + + get_encoding = staticmethod(get_preferred_output_encoding) + '''Get encoding used by the current application + + Usually returns encoding of the current locale. + ''' + + def create_logger(self): + '''Create logger + + This function is used to create logger unless it was already specified + at initialization. + + :return: Three objects: + + #. :py:class:`logging.Logger` instance. + #. :py:class:`PowerlineLogger` instance. + #. Function, output of :py:func:`gen_module_attr_getter`. + ''' + return create_logger( + common_config=self.common_config, + use_daemon_threads=self.use_daemon_threads, + ext=self.ext, + imported_modules=self.imported_modules, + stream=self.default_log_stream, + ) + + def create_renderer(self, load_main=False, load_colors=False, load_colorscheme=False, load_theme=False): + '''(Re)create renderer object. Can be used after Powerline object was + successfully initialized. If any of the below parameters except + ``load_main`` is True renderer object will be recreated. + + :param bool load_main: + Determines whether main configuration file (:file:`config.json`) + should be loaded. If appropriate configuration changes implies + ``load_colorscheme`` and ``load_theme`` and recreation of renderer + object. Won’t trigger recreation if only unrelated configuration + changed. + :param bool load_colors: + Determines whether colors configuration from :file:`colors.json` + should be (re)loaded. + :param bool load_colorscheme: + Determines whether colorscheme configuration should be (re)loaded. + :param bool load_theme: + Determines whether theme configuration should be reloaded. + ''' + common_config_differs = False + ext_config_differs = False + if load_main: + self._purge_configs('main') + config = self.load_main_config() + self.common_config = finish_common_config(self.get_encoding(), config['common']) + if self.common_config != self.prev_common_config: + common_config_differs = True + + load_theme = (load_theme + or not self.prev_common_config + or self.prev_common_config['default_top_theme'] != self.common_config['default_top_theme']) + + log_keys_differ = (not self.prev_common_config or ( + _get_log_keys(self.prev_common_config) != _get_log_keys(self.common_config) + )) + + self.prev_common_config = self.common_config + + if log_keys_differ: + if self.had_logger: + self.pl = PowerlineLogger(self.use_daemon_threads, self.logger, self.ext) + self.get_module_attr = gen_module_attr_getter( + self.pl, self.common_config['paths'], self.imported_modules) + else: + self.logger, self.pl, self.get_module_attr = self.create_logger() + self.config_loader.pl = self.pl + + if not self.run_once: + self.config_loader.set_watcher(self.common_config['watcher']) + + mergedicts(self.renderer_options, dict( + pl=self.pl, + term_truecolor=self.common_config['term_truecolor'], + term_escape_style=self.common_config['term_escape_style'], + ambiwidth=self.common_config['ambiwidth'], + tmux_escape=self.common_config['additional_escapes'] == 'tmux', + screen_escape=self.common_config['additional_escapes'] == 'screen', + theme_kwargs={ + 'ext': self.ext, + 'common_config': self.common_config, + 'run_once': self.run_once, + 'shutdown_event': self.shutdown_event, + 'get_module_attr': self.get_module_attr, + }, + )) + + if not self.run_once and self.common_config['reload_config']: + interval = self.common_config['interval'] + 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] + + top_theme = ( + self.ext_config.get('top_theme') + or self.common_config['default_top_theme'] + ) + self.theme_levels = ( + os.path.join('themes', top_theme), + os.path.join('themes', self.ext, '__main__'), + ) + self.renderer_options['theme_kwargs']['top_theme'] = top_theme + + if self.ext_config != self.prev_ext_config: + ext_config_differs = True + if ( + not self.prev_ext_config + or self.ext_config.get('components') != self.prev_ext_config.get('components') + ): + self.setup_components(self.ext_config.get('components')) + 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')) + self.update_interval = self.ext_config.get('update_interval', 2) + 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['theme_kwargs']['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: + Renderer = self.get_module_attr(self.renderer_module, 'renderer') + if not Renderer: + if hasattr(self, 'renderer'): + return + else: + raise ImportError('Failed to obtain renderer') + + # 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.exception('Failed to construct renderer object: {0}', str(e)) + if not hasattr(self, 'renderer'): + raise + else: + self.renderer = renderer + + default_log_stream = sys.stdout + '''Default stream for default log handler + + Usually it is ``sys.stderr``, but there is sometimes a reason to prefer + ``sys.stdout`` or a custom file-like object. It is not supposed to be used + to write to some file. + ''' + + def setup_components(self, components): + '''Run component-specific setup + + :param set components: + Set of the enabled components or None. + + Should be overridden by subclasses. + ''' + pass + + @staticmethod + def get_config_paths(): + '''Get configuration paths. + + Should be overridden in subclasses in order to provide a way to override + used paths. + + :return: list of paths + ''' + return get_config_paths() + + def load_config(self, cfg_path, cfg_type): + '''Load configuration and setup watches + + :param str cfg_path: + Path to the configuration file without any powerline configuration + directory or ``.json`` suffix. + :param str cfg_type: + Configuration type. May be one of ``main`` (for ``config.json`` + file), ``colors``, ``colorscheme``, ``theme``. + + :return: dictionary with loaded configuration. + ''' + return load_config( + cfg_path, + self.find_config_files, + self.config_loader, + self.cr_callbacks[cfg_type] + ) + + def _purge_configs(self, cfg_type): + function = self.cr_callbacks[cfg_type] + self.config_loader.unregister_functions(set((function,))) + self.config_loader.unregister_missing(set(((self.find_config_files, function),))) + + 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_hierarhical_config(self, cfg_type, levels, ignore_levels): + '''Load and merge multiple configuration files + + :param str cfg_type: + Type of the loaded configuration files (e.g. ``colorscheme``, + ``theme``). + :param list levels: + Configuration names resembling levels in hierarchy, sorted by + priority. Configuration file names with higher priority should go + last. + :param set ignore_levels: + If only files listed in this variable are present then configuration + file is considered not loaded: at least one file on the level not + listed in this variable must be present. + ''' + config = {} + loaded = 0 + exceptions = [] + for i, cfg_path in enumerate(levels): + try: + lvl_config = self.load_config(cfg_path, cfg_type) + except IOError as e: + if sys.version_info < (3,): + tb = sys.exc_info()[2] + exceptions.append((e, tb)) + else: + exceptions.append(e) + else: + if i not in ignore_levels: + loaded += 1 + mergedicts(config, lvl_config) + if not loaded: + for exception in exceptions: + if type(exception) is tuple: + e = exception[0] + else: + e = exception + self.exception('Failed to load %s: {0}' % cfg_type, e, exception=exception) + raise e + return config + + 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>`. + ''' + levels = ( + os.path.join('colorschemes', name), + os.path.join('colorschemes', self.ext, '__main__'), + os.path.join('colorschemes', self.ext, name), + ) + return self._load_hierarhical_config('colorscheme', levels, (1,)) + + 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>` + ''' + levels = self.theme_levels + ( + os.path.join('themes', self.ext, name), + ) + return self._load_hierarhical_config('theme', levels, (0, 1,)) + + 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() + cr_kwargs = None + with self.cr_kwargs_lock: + if self.cr_kwargs: + cr_kwargs = self.cr_kwargs.copy() + if cr_kwargs: + try: + self.create_renderer(**cr_kwargs) + except Exception as e: + self.exception('Failed to create renderer: {0}', str(e)) + if hasattr(self, 'renderer'): + with self.cr_kwargs_lock: + self.cr_kwargs.clear() + else: + raise + else: + with self.cr_kwargs_lock: + self.cr_kwargs.clear() + + def render(self, *args, **kwargs): + '''Update/create renderer if needed and pass all arguments further to + ``self.renderer.render()``. + ''' + try: + self.update_renderer() + return self.renderer.render(*args, **kwargs) + except Exception as e: + exc = e + try: + self.exception('Failed to render: {0}', str(e)) + except Exception as e: + exc = e + ret = FailedUnicode(safe_unicode(exc)) + if kwargs.get('output_width', False): + ret = ret, len(ret) + return ret + + def render_above_lines(self, *args, **kwargs): + '''Like .render(), but for ``self.renderer.render_above_lines()`` + ''' + try: + self.update_renderer() + for line in self.renderer.render_above_lines(*args, **kwargs): + yield line + except Exception as e: + exc = e + try: + self.exception('Failed to render: {0}', str(e)) + except Exception as e: + exc = e + yield FailedUnicode(safe_unicode(exc)) + + def setup(self, *args, **kwargs): + '''Setup the environment to use powerline. + + Must not be overridden by subclasses. This one only saves setup + arguments for :py:meth:`reload` method and calls :py:meth:`do_setup`. + ''' + self.shutdown_event.clear() + self.setup_args = args + self.setup_kwargs.update(kwargs) + self.do_setup(*args, **kwargs) + + @staticmethod + def do_setup(): + '''Function that does initialization + + Should be overridden by subclasses. May accept any number of regular or + keyword arguments. + ''' + pass + + def reload(self): + '''Reload powerline after update. + + Should handle most (but not all) powerline updates. + + Purges out all powerline modules and modules imported by powerline for + segment and matcher functions. Requires defining ``setup`` function that + updates reference to main powerline object. + + .. warning:: + Not guaranteed to work properly, use it at your own risk. It + may break your python code. + ''' + import sys + modules = self.imported_modules | set((module for module in sys.modules if module.startswith('powerline'))) + modules_holder = [] + for module in modules: + try: + # Needs to hold module to prevent garbage collecting until they + # are all reloaded. + modules_holder.append(sys.modules.pop(module)) + except KeyError: + pass + PowerlineClass = getattr(__import__(self.__module__, fromlist=(self.__class__.__name__,)), self.__class__.__name__) + self.shutdown(set_event=True) + init_args, init_kwargs = self.init_args + powerline = PowerlineClass(*init_args, **init_kwargs) + powerline.setup(*self.setup_args, **self.setup_kwargs) + + def shutdown(self, set_event=True): + '''Shut down all background threads. + + :param bool set_event: + Set ``shutdown_event`` and call ``renderer.shutdown`` which should + shut down all threads. Set it to False unless you are exiting an + application. + + If set to False this does nothing more then resolving reference + cycle ``powerline → config_loader → bound methods → powerline`` by + unsubscribing from config_loader events. + ''' + if set_event: + self.shutdown_event.set() + try: + self.renderer.shutdown() + except AttributeError: + pass + functions = tuple(self.cr_callbacks.values()) + self.config_loader.unregister_functions(set(functions)) + self.config_loader.unregister_missing(set(((self.find_config_files, function) for function in functions))) + + def __enter__(self): + return self + + def __exit__(self, *args): + self.shutdown() + + def exception(self, msg, *args, **kwargs): + if 'prefix' not in kwargs: + kwargs['prefix'] = 'powerline' + exception = kwargs.pop('exception', None) + pl = getattr(self, 'pl', None) or get_fallback_logger(self.default_log_stream) + if exception: + try: + reraise(exception) + except Exception: + return pl.exception(msg, *args, **kwargs) + return pl.exception(msg, *args, **kwargs) diff --git a/powerline/bindings/__init__.py b/powerline/bindings/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/powerline/bindings/__init__.py diff --git a/powerline/bindings/awesome/powerline-awesome.py b/powerline/bindings/awesome/powerline-awesome.py new file mode 100755 index 0000000..500d47d --- /dev/null +++ b/powerline/bindings/awesome/powerline-awesome.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys + +from powerline.bindings.wm import DEFAULT_UPDATE_INTERVAL +from powerline.bindings.wm.awesome import run + + +def main(): + try: + interval = float(sys.argv[1]) + except IndexError: + interval = DEFAULT_UPDATE_INTERVAL + run(interval=interval) + + +if __name__ == '__main__': + main() diff --git a/powerline/bindings/awesome/powerline.lua b/powerline/bindings/awesome/powerline.lua new file mode 100644 index 0000000..470901f --- /dev/null +++ b/powerline/bindings/awesome/powerline.lua @@ -0,0 +1,15 @@ +local wibox = require('wibox') +local awful = require('awful') + +powerline_widget = wibox.widget.textbox() +powerline_widget:set_align('right') + +function powerline(mode, widget) end + +if string.find(awesome.version, 'v4') then + awful.spawn.with_shell('powerline-daemon -q') + awful.spawn.with_shell('powerline wm.awesome') +else + awful.util.spawn_with_shell('powerline-daemon -q') + awful.util.spawn_with_shell('powerline wm.awesome') +end diff --git a/powerline/bindings/bar/powerline-bar.py b/powerline/bindings/bar/powerline-bar.py new file mode 100755 index 0000000..71e8ae3 --- /dev/null +++ b/powerline/bindings/bar/powerline-bar.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import sys +import time + +from threading import Lock, Timer +from argparse import ArgumentParser + +from powerline.lemonbar import LemonbarPowerline +from powerline.lib.encoding import get_unicode_writer +from powerline.bindings.wm import DEFAULT_UPDATE_INTERVAL + + +if __name__ == '__main__': + parser = ArgumentParser(description='Powerline lemonbar bindings.') + parser.add_argument( + '--i3', action='store_true', + help='Subscribe for i3 events.' + ) + args = parser.parse_args() + powerline = LemonbarPowerline() + powerline.update_renderer() + powerline.pl.warn("The 'bar' bindings are deprecated, please switch to 'lemonbar'") + lock = Lock() + modes = ['default'] + write = get_unicode_writer(encoding='utf-8') + + def render(reschedule=False): + if reschedule: + Timer(DEFAULT_UPDATE_INTERVAL, render, kwargs={'reschedule': True}).start() + + global lock + with lock: + write(powerline.render(mode=modes[0])) + write('\n') + sys.stdout.flush() + + def update(evt): + modes[0] = evt.change + render() + + render(reschedule=True) + + if args.i3: + try: + import i3ipc + except ImportError: + import i3 + i3.Subscription(lambda evt, data, sub: print(render()), 'workspace') + else: + conn = i3ipc.Connection() + conn.on('workspace::focus', lambda conn, evt: render()) + conn.on('mode', lambda conn, evt: update(evt)) + conn.main() + + while True: + time.sleep(1e8) diff --git a/powerline/bindings/bash/powerline.sh b/powerline/bindings/bash/powerline.sh new file mode 100644 index 0000000..2c0943c --- /dev/null +++ b/powerline/bindings/bash/powerline.sh @@ -0,0 +1,153 @@ +_powerline_columns_fallback() { + if command -v stty &>/dev/null ; then + local cols="$(stty size 2>/dev/null)" + if ! test -z "$cols" ; then + echo "${cols#* }" + return 0 + fi + fi + echo 0 + return 0 +} + +_powerline_tmux_pane() { + echo "${TMUX_PANE:-`TMUX="$_POWERLINE_TMUX" tmux display -p "#D"`}" | \ + tr -d ' %' +} + +_powerline_tmux_setenv() { + TMUX="$_POWERLINE_TMUX" tmux setenv -g TMUX_"$1"_`_powerline_tmux_pane` "$2" + TMUX="$_POWERLINE_TMUX" tmux refresh -S +} + +_powerline_tmux_set_pwd() { + if test "$_POWERLINE_SAVED_PWD" != "$PWD" ; then + _POWERLINE_SAVED_PWD="$PWD" + _powerline_tmux_setenv PWD "$PWD" + fi +} + +_powerline_return() { + return $1 +} + +_POWERLINE_HAS_PIPESTATUS="$( + _powerline_return 0 | _powerline_return 43 + test "${PIPESTATUS[*]}" = "0 43" + echo "$?" +)" + +_powerline_has_pipestatus() { + return $_POWERLINE_HAS_PIPESTATUS +} + +_powerline_status_wrapper() { + local last_exit_code=$? last_pipe_status=( "${PIPESTATUS[@]}" ) + + if ! _powerline_has_pipestatus \ + || test "${#last_pipe_status[@]}" -eq "0" \ + || test "$last_exit_code" != "${last_pipe_status[$(( ${#last_pipe_status[@]} - 1 ))]}" ; then + last_pipe_status=() + fi + "$@" $last_exit_code "${last_pipe_status[*]}" + return $last_exit_code +} + +_powerline_add_status_wrapped_command() { + local action="$1" ; shift + local cmd="$1" ; shift + full_cmd="_powerline_status_wrapper $cmd" + if test "$action" = "append" ; then + PROMPT_COMMAND="$PROMPT_COMMAND"$'\n'"$full_cmd" + else + PROMPT_COMMAND="$full_cmd"$'\n'"$PROMPT_COMMAND" + fi +} + +_powerline_tmux_set_columns() { + _powerline_tmux_setenv COLUMNS "${COLUMNS:-`_powerline_columns_fallback`}" +} + +_powerline_init_tmux_support() { + if test -n "$TMUX" && tmux refresh -S &>/dev/null ; then + # TMUX variable may be unset to create new tmux session inside this one + _POWERLINE_TMUX="$TMUX" + + trap '_powerline_tmux_set_columns' WINCH + _powerline_tmux_set_columns + + test "$PROMPT_COMMAND" != "${PROMPT_COMMAND/_powerline_tmux_set_pwd}" \ + || _powerline_add_status_wrapped_command append _powerline_tmux_set_pwd + fi +} + +_powerline_local_prompt() { + # Arguments: + # 1: side + # 2: renderer_module arg + # 3: last_exit_code + # 4: last_pipe_status + # 5: jobnum + # 6: local theme + "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \ + $2 \ + --last-exit-code=$3 \ + --last-pipe-status="$4" \ + --jobnum=$5 \ + --renderer-arg="client_id=$$" \ + --renderer-arg="local_theme=$6" +} + +_powerline_prompt() { + # Arguments: + # 1: side + # 2: last_exit_code + # 3: last_pipe_status + # 4: jobnum + "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \ + --width="${COLUMNS:-$(_powerline_columns_fallback)}" \ + -r.bash \ + --last-exit-code=$2 \ + --last-pipe-status="$3" \ + --jobnum=$4 \ + --renderer-arg="client_id=$$" +} + +_powerline_set_prompt() { + local last_exit_code=$1 ; shift + local last_pipe_status=$1 ; shift + local jobnum="$(jobs -p|wc -l)" + PS1="$(_powerline_prompt aboveleft $last_exit_code "$last_pipe_status" $jobnum)" + if test -n "$POWERLINE_SHELL_CONTINUATION$POWERLINE_BASH_CONTINUATION" ; then + PS2="$(_powerline_local_prompt left -r.bash $last_exit_code "$last_pipe_status" $jobnum continuation)" + fi + if test -n "$POWERLINE_SHELL_SELECT$POWERLINE_BASH_SELECT" ; then + PS3="$(_powerline_local_prompt left '' $last_exit_code "$last_pipe_status" $jobnum select)" + fi +} + +_powerline_setup_prompt() { + VIRTUAL_ENV_DISABLE_PROMPT=1 + if test -z "${POWERLINE_COMMAND}" ; then + POWERLINE_COMMAND="$("$POWERLINE_CONFIG_COMMAND" shell command)" + fi + test "$PROMPT_COMMAND" != "${PROMPT_COMMAND%_powerline_set_prompt*}" \ + || _powerline_add_status_wrapped_command prepend _powerline_set_prompt + PS2="$(_powerline_local_prompt left -r.bash 0 0 0 continuation)" + PS3="$(_powerline_local_prompt left '' 0 0 0 select)" +} + +if test -z "${POWERLINE_CONFIG_COMMAND}" ; then + if command -v powerline-config >/dev/null ; then + POWERLINE_CONFIG_COMMAND=powerline-config + else + POWERLINE_CONFIG_COMMAND="$(dirname "$BASH_SOURCE")/../../../scripts/powerline-config" + fi +fi + +if "${POWERLINE_CONFIG_COMMAND}" shell --shell=bash uses prompt ; then + _powerline_setup_prompt +fi +if "${POWERLINE_CONFIG_COMMAND}" shell --shell=bash uses tmux ; then + _powerline_init_tmux_support +fi diff --git a/powerline/bindings/config.py b/powerline/bindings/config.py new file mode 100644 index 0000000..3100633 --- /dev/null +++ b/powerline/bindings/config.py @@ -0,0 +1,286 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import re +import sys +import subprocess +import shlex + +from powerline.config import POWERLINE_ROOT, TMUX_CONFIG_DIRECTORY +from powerline.lib.config import ConfigLoader +from powerline import generate_config_finder, load_config, create_logger, finish_common_config +from powerline.shell import ShellPowerline +from powerline.lib.shell import which +from powerline.bindings.tmux import (TmuxVersionInfo, run_tmux_command, set_tmux_environment, get_tmux_version, + source_tmux_file) +from powerline.lib.encoding import get_preferred_output_encoding +from powerline.renderers.tmux import attrs_to_tmux_attrs +from powerline.commands.main import finish_args + + +CONFIG_FILE_NAME = re.compile(r'powerline_tmux_(?P<major>\d+)\.(?P<minor>\d+)(?P<suffix>[a-z]+)?(?:_(?P<mod>plus|minus))?\.conf') +CONFIG_MATCHERS = { + None: (lambda a, b: a.major == b.major and a.minor == b.minor), + 'plus': (lambda a, b: a[:2] <= b[:2]), + 'minus': (lambda a, b: a[:2] >= b[:2]), +} +CONFIG_PRIORITY = { + None: 3, + 'plus': 2, + 'minus': 1, +} + + +def list_all_tmux_configs(): + '''List all version-specific tmux configuration files''' + for root, dirs, files in os.walk(TMUX_CONFIG_DIRECTORY): + dirs[:] = () + for fname in files: + match = CONFIG_FILE_NAME.match(fname) + if match: + assert match.group('suffix') is None + yield ( + os.path.join(root, fname), + CONFIG_MATCHERS[match.group('mod')], + CONFIG_PRIORITY[match.group('mod')], + TmuxVersionInfo( + int(match.group('major')), + int(match.group('minor')), + match.group('suffix'), + ), + ) + + +def get_tmux_configs(version): + '''Get tmux configuration suffix given parsed tmux version + + :param TmuxVersionInfo version: Parsed tmux version. + ''' + for fname, matcher, priority, file_version in list_all_tmux_configs(): + if matcher(file_version, version): + yield (fname, priority + file_version.minor * 10 + file_version.major * 10000) + + +def source_tmux_files(pl, args, tmux_version=None, source_tmux_file=source_tmux_file): + '''Source relevant version-specific tmux configuration files + + Files are sourced in the following order: + * First relevant files with older versions are sourced. + * If files for same versions are to be sourced then first _minus files are + sourced, then _plus files and then files without _minus or _plus suffixes. + ''' + tmux_version = tmux_version or get_tmux_version(pl) + source_tmux_file(os.path.join(TMUX_CONFIG_DIRECTORY, 'powerline-base.conf')) + for fname, priority in sorted(get_tmux_configs(tmux_version), key=(lambda v: v[1])): + source_tmux_file(fname) + if not os.environ.get('POWERLINE_COMMAND'): + cmd = deduce_command() + if cmd: + set_tmux_environment('POWERLINE_COMMAND', deduce_command(), remove=False) + try: + run_tmux_command('refresh-client') + except subprocess.CalledProcessError: + # On tmux-2.0 this command may fail for whatever reason. Since it is + # critical just ignore the failure. + pass + + +class EmptyArgs(object): + def __init__(self, ext, config_path): + self.ext = [ext] + self.side = 'left' + self.config_path = None + + def __getattr__(self, attr): + return None + + +def init_tmux_environment(pl, args, set_tmux_environment=set_tmux_environment): + '''Initialize tmux environment from tmux configuration + ''' + powerline = ShellPowerline(finish_args(None, os.environ, EmptyArgs('tmux', args.config_path))) + # TODO Move configuration files loading out of Powerline object and use it + # directly + powerline.update_renderer() + # FIXME Use something more stable then `theme_kwargs` + colorscheme = powerline.renderer_options['theme_kwargs']['colorscheme'] + + def get_highlighting(group): + return colorscheme.get_highlighting([group], None) + + for varname, highlight_group in ( + ('_POWERLINE_BACKGROUND_COLOR', 'background'), + ('_POWERLINE_ACTIVE_WINDOW_STATUS_COLOR', 'active_window_status'), + ('_POWERLINE_WINDOW_STATUS_COLOR', 'window_status'), + ('_POWERLINE_ACTIVITY_STATUS_COLOR', 'activity_status'), + ('_POWERLINE_BELL_STATUS_COLOR', 'bell_status'), + ('_POWERLINE_WINDOW_COLOR', 'window'), + ('_POWERLINE_WINDOW_DIVIDER_COLOR', 'window:divider'), + ('_POWERLINE_WINDOW_CURRENT_COLOR', 'window:current'), + ('_POWERLINE_WINDOW_NAME_COLOR', 'window_name'), + ('_POWERLINE_SESSION_COLOR', 'session'), + ): + highlight = get_highlighting(highlight_group) + set_tmux_environment(varname, powerline.renderer.hlstyle(**highlight)[2:-1]) + for varname, prev_group, next_group in ( + ('_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_COLOR', 'window', 'window:current'), + ('_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_NEXT_COLOR', 'window:current', 'window'), + ('_POWERLINE_SESSION_HARD_DIVIDER_NEXT_COLOR', 'session', 'background'), + ): + prev_highlight = get_highlighting(prev_group) + next_highlight = get_highlighting(next_group) + set_tmux_environment( + varname, + powerline.renderer.hlstyle( + fg=prev_highlight['bg'], + bg=next_highlight['bg'], + attrs=0, + )[2:-1] + ) + for varname, attr, group in ( + ('_POWERLINE_ACTIVE_WINDOW_FG', 'fg', 'active_window_status'), + ('_POWERLINE_WINDOW_STATUS_FG', 'fg', 'window_status'), + ('_POWERLINE_ACTIVITY_STATUS_FG', 'fg', 'activity_status'), + ('_POWERLINE_ACTIVITY_STATUS_ATTR', 'attrs', 'activity_status'), + ('_POWERLINE_BELL_STATUS_FG', 'fg', 'bell_status'), + ('_POWERLINE_BELL_STATUS_ATTR', 'attrs', 'bell_status'), + ('_POWERLINE_BACKGROUND_FG', 'fg', 'background'), + ('_POWERLINE_BACKGROUND_BG', 'bg', 'background'), + ('_POWERLINE_SESSION_FG', 'fg', 'session'), + ('_POWERLINE_SESSION_BG', 'bg', 'session'), + ('_POWERLINE_SESSION_ATTR', 'attrs', 'session'), + ('_POWERLINE_SESSION_PREFIX_FG', 'fg', 'session:prefix'), + ('_POWERLINE_SESSION_PREFIX_BG', 'bg', 'session:prefix'), + ('_POWERLINE_SESSION_PREFIX_ATTR', 'attrs', 'session:prefix'), + ): + if attr == 'attrs': + attrs = attrs_to_tmux_attrs(get_highlighting(group)[attr]) + set_tmux_environment(varname, ']#['.join(attrs)) + set_tmux_environment(varname + '_LEGACY', (','.join( + # Tmux-1.6 does not accept no… attributes in + # window-status-…-attr options. + (attr for attr in attrs if not attr.startswith('no'))) + # But it does not support empty attributes as well. + or 'none')) + else: + if powerline.common_config['term_truecolor']: + set_tmux_environment(varname, '#{0:06x}'.format(get_highlighting(group)[attr][1])) + else: + set_tmux_environment(varname, 'colour' + str(get_highlighting(group)[attr][0])) + + left_dividers = powerline.renderer.theme.dividers['left'] + set_tmux_environment('_POWERLINE_LEFT_HARD_DIVIDER', left_dividers['hard']) + set_tmux_environment('_POWERLINE_LEFT_SOFT_DIVIDER', left_dividers['soft']) + set_tmux_environment('_POWERLINE_LEFT_HARD_DIVIDER_SPACES', ( + ' ' * powerline.renderer.strwidth(left_dividers['hard']))) + + +TMUX_VAR_RE = re.compile('\$(_POWERLINE_\w+)') + + +def tmux_setup(pl, args): + tmux_environ = {} + tmux_version = get_tmux_version(pl) + + def set_tmux_environment_nosource(varname, value, remove=True): + tmux_environ[varname] = value + + def replace_cb(match): + return tmux_environ[match.group(1)] + + def replace_env(s): + return TMUX_VAR_RE.subn(replace_cb, s)[0] + + def source_tmux_file_nosource(fname): + with open(fname) as fd: + for line in fd: + if line.startswith('#') or line == '\n': + continue + args = shlex.split(line) + args = [args[0]] + [replace_env(arg) for arg in args[1:]] + run_tmux_command(*args) + + if args.source is None: + args.source = tmux_version < (1, 9) + + if args.source: + ste = set_tmux_environment + stf = source_tmux_file + else: + ste = set_tmux_environment_nosource + stf = source_tmux_file_nosource + + init_tmux_environment(pl, args, set_tmux_environment=ste) + source_tmux_files(pl, args, tmux_version=tmux_version, source_tmux_file=stf) + + +def get_main_config(args): + find_config_files = generate_config_finder() + config_loader = ConfigLoader(run_once=True) + return load_config('config', find_config_files, config_loader) + + +def create_powerline_logger(args): + config = get_main_config(args) + common_config = finish_common_config(get_preferred_output_encoding(), config['common']) + logger, pl, get_module_attr = create_logger(common_config) + return pl + + +def check_command(cmd): + if which(cmd): + return cmd + + +def deduce_command(): + '''Deduce which command to use for ``powerline`` + + Candidates: + + * ``powerline``. Present only when installed system-wide. + * ``{powerline_root}/scripts/powerline``. Present after ``pip install -e`` + was run and C client was compiled (in this case ``pip`` does not install + binary file). + * ``{powerline_root}/client/powerline.sh``. Useful when ``sh``, ``sed`` and + ``socat`` are present, but ``pip`` or ``setup.py`` was not run. + * ``{powerline_root}/client/powerline.py``. Like above, but when one of + ``sh``, ``sed`` and ``socat`` was not present. + * ``powerline-render``. Should not really ever be used. + * ``{powerline_root}/scripts/powerline-render``. Same. + ''' + return ( + None + or check_command('powerline') + or check_command(os.path.join(POWERLINE_ROOT, 'scripts', 'powerline')) + or ((which('sh') and which('sed') and which('socat')) + and check_command(os.path.join(POWERLINE_ROOT, 'client', 'powerline.sh'))) + or check_command(os.path.join(POWERLINE_ROOT, 'client', 'powerline.py')) + or check_command('powerline-render') + or check_command(os.path.join(POWERLINE_ROOT, 'scripts', 'powerline-render')) + ) + + +def shell_command(pl, args): + cmd = deduce_command() + if cmd: + print(cmd) + else: + sys.exit(1) + + +def uses(pl, args): + component = args.component + if not component: + raise ValueError('Must specify component') + shell = args.shell + template = 'POWERLINE_NO_{shell}_{component}' + for sh in (shell, 'shell') if shell else ('shell'): + varname = template.format(shell=sh.upper(), component=component.upper()) + if os.environ.get(varname): + sys.exit(1) + config = get_main_config(args) + if component in config.get('ext', {}).get('shell', {}).get('components', ('tmux', 'prompt')): + sys.exit(0) + else: + sys.exit(1) diff --git a/powerline/bindings/fish/powerline-setup.fish b/powerline/bindings/fish/powerline-setup.fish new file mode 100644 index 0000000..f5d02d6 --- /dev/null +++ b/powerline/bindings/fish/powerline-setup.fish @@ -0,0 +1,100 @@ +function powerline-setup + function _powerline_columns + if which stty >/dev/null + if stty size >/dev/null + stty size | cut -d' ' -f2 + return 0 + end + end + echo 0 + return 0 + end + + if test -z "$POWERLINE_CONFIG_COMMAND" + if which powerline-config >/dev/null + set -g POWERLINE_CONFIG_COMMAND powerline-config + else + set -g POWERLINE_CONFIG_COMMAND (dirname (status -f))/../../../scripts/powerline-config + end + end + + if env $POWERLINE_CONFIG_COMMAND shell --shell=fish uses prompt + if test -z "$POWERLINE_COMMAND" + set -g POWERLINE_COMMAND (env $POWERLINE_CONFIG_COMMAND shell command) + end + function _powerline_set_default_mode --on-variable fish_key_bindings + if test $fish_key_bindings != fish_vi_key_bindings + set -g _POWERLINE_DEFAULT_MODE default + else + set -g -e _POWERLINE_DEFAULT_MODE + end + end + function _powerline_update --on-variable POWERLINE_COMMAND + set -l addargs "--last-exit-code=\$status" + set -l addargs "$addargs --last-pipe-status=\$status" + set -l addargs "$addargs --jobnum=(jobs -p | wc -l)" + # One random value has an 1/32767 = 0.0031% probability of having + # the same value in two shells + set -l addargs "$addargs --renderer-arg=client_id="(random) + set -l addargs "$addargs --width=\$_POWERLINE_COLUMNS" + set -l addargs "$addargs --renderer-arg=mode=\$fish_bind_mode" + set -l addargs "$addargs --renderer-arg=default_mode=\$_POWERLINE_DEFAULT_MODE" + set -l promptside + set -l rpromptpast + set -l columnsexpr + if test -z "$POWERLINE_NO_FISH_ABOVE$POWERLINE_NO_SHELL_ABOVE" + set promptside aboveleft + set rpromptpast 'echo -n " "' + set columnsexpr '(math (_powerline_columns) - 1)' + else + set promptside left + set rpromptpast + set columnsexpr '(_powerline_columns)' + end + echo " + function fish_prompt + env \$POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS shell $promptside $addargs + end + function fish_right_prompt + env \$POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS shell right $addargs + $rpromptpast + end + function fish_mode_prompt + end + function _powerline_set_columns --on-signal WINCH + set -g _POWERLINE_COLUMNS $columnsexpr + end + " | source + _powerline_set_columns + end + _powerline_set_default_mode + _powerline_update + end + if env $POWERLINE_CONFIG_COMMAND shell --shell=fish uses tmux + if test -n "$TMUX" + if tmux refresh -S ^/dev/null + set -g _POWERLINE_TMUX "$TMUX" + function _powerline_tmux_pane + if test -z "$TMUX_PANE" + env TMUX="$_POWERLINE_TMUX" tmux display -p "#D" | tr -d ' %' + else + echo "$TMUX_PANE" | tr -d ' %' + end + end + function _powerline_tmux_setenv + env TMUX="$_POWERLINE_TMUX" tmux setenv -g TMUX_$argv[1]_(_powerline_tmux_pane) "$argv[2]" + env TMUX="$_POWERLINE_TMUX" tmux refresh -S + end + function _powerline_tmux_set_pwd --on-variable PWD + _powerline_tmux_setenv PWD "$PWD" + end + function _powerline_tmux_set_columns --on-signal WINCH + _powerline_tmux_setenv COLUMNS (_powerline_columns) + end + _powerline_tmux_set_columns + _powerline_tmux_set_pwd + end + end + end +end +# vim: ft=fish diff --git a/powerline/bindings/i3/powerline-i3.py b/powerline/bindings/i3/powerline-i3.py new file mode 100755 index 0000000..f44e928 --- /dev/null +++ b/powerline/bindings/i3/powerline-i3.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import time + +from threading import Lock + +from powerline.bindings.wm import get_i3_connection, i3_subscribe + +from powerline import Powerline +from powerline.lib.monotonic import monotonic + + +class I3Powerline(Powerline): + '''Powerline child for i3bar + + Currently only changes the default log target. + ''' + default_log_stream = sys.stderr + + +if __name__ == '__main__': + name = 'wm' + if len(sys.argv) > 1: + name = sys.argv[1] + + powerline = I3Powerline(name, renderer_module='i3bar') + powerline.update_renderer() + + interval = 0.5 + + print ('{"version": 1}') + print ('[') + print ('[]') + + lock = Lock() + + def render(event=None, data=None, sub=None): + global lock + with lock: + print (',[' + powerline.render()[:-1] + ']') + sys.stdout.flush() + + i3 = get_i3_connection() + i3_subscribe(i3, 'workspace', render) + + while True: + start_time = monotonic() + render() + time.sleep(max(interval - (monotonic() - start_time), 0.1)) diff --git a/powerline/bindings/ipython/__init__.py b/powerline/bindings/ipython/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/powerline/bindings/ipython/__init__.py diff --git a/powerline/bindings/ipython/post_0_11.py b/powerline/bindings/ipython/post_0_11.py new file mode 100644 index 0000000..3213c51 --- /dev/null +++ b/powerline/bindings/ipython/post_0_11.py @@ -0,0 +1,126 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, + absolute_import, print_function) + +from weakref import ref +from warnings import warn + +try: + from IPython.core.prompts import PromptManager + has_prompt_manager = True +except ImportError: + has_prompt_manager = False +from IPython.core.magic import Magics, magics_class, line_magic + +from powerline.ipython import IPythonPowerline, IPythonInfo + +if has_prompt_manager: + from powerline.ipython import RewriteResult + + +@magics_class +class PowerlineMagics(Magics): + def __init__(self, ip, powerline): + super(PowerlineMagics, self).__init__(ip) + self._powerline = powerline + + @line_magic + def powerline(self, line): + if line == 'reload': + self._powerline.reload() + else: + raise ValueError('Expected `reload`, but got {0}'.format(line)) + + +old_prompt_manager = None + + +class ShutdownHook(object): + def __init__(self, ip): + self.powerline = lambda: None + ip.hooks.shutdown_hook.add(self) + + def __call__(self): + from IPython.core.hooks import TryNext + powerline = self.powerline() + if powerline is not None: + powerline.shutdown() + raise TryNext() + + +if has_prompt_manager: + class PowerlinePromptManager(PromptManager): + 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): + res = self.powerline.render( + is_prompt=name.startswith('in'), + side='left', + output_width=True, + output_raw=not color, + matcher_info=name, + segment_info=self.powerline_segment_info, + ) + self.txtwidth = res[-1] + self.width = res[-1] + ret = res[0] if color else res[1] + if name == 'rewrite': + return RewriteResult(ret) + else: + return ret + + 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.config_paths = config.get('config_paths') + if has_prompt_manager: + renderer_module = '.pre_5' + else: + renderer_module = '.since_7' + super(ConfigurableIPythonPowerline, self).init( + renderer_module=renderer_module) + + def do_setup(self, ip, shutdown_hook): + global old_prompt_manager + + if old_prompt_manager is None: + old_prompt_manager = ip.prompt_manager + prompt_manager = PowerlinePromptManager( + powerline=self, + shell=ip.prompt_manager.shell, + ) + ip.prompt_manager = prompt_manager + + magics = PowerlineMagics(ip, self) + shutdown_hook.powerline = ref(self) + ip.register_magics(magics) + + +def load_ipython_extension(ip): + if has_prompt_manager: + shutdown_hook = ShutdownHook(ip) + powerline = ConfigurableIPythonPowerline(ip) + powerline.setup(ip, shutdown_hook) + else: + from powerline.bindings.ipython.since_7 import PowerlinePrompts + ip.prompts_class = PowerlinePrompts + ip.prompts = PowerlinePrompts(ip) + warn(DeprecationWarning( + 'post_0_11 extension is deprecated since IPython 5, use\n' + ' from powerline.bindings.ipython.since_7 import PowerlinePrompts\n' + ' c.TerminalInteractiveShell.prompts_class = PowerlinePrompts\n' + 'or check: \n' + 'https://powerline.readthedocs.io/en/master/usage/other.html\n' + )) + + +def unload_ipython_extension(ip): + global old_prompt_manager + if old_prompt_manager is not None: + ip.prompt_manager = old_prompt_manager + old_prompt_manager = None diff --git a/powerline/bindings/ipython/pre_0_11.py b/powerline/bindings/ipython/pre_0_11.py new file mode 100644 index 0000000..2bd8095 --- /dev/null +++ b/powerline/bindings/ipython/pre_0_11.py @@ -0,0 +1,146 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import re + +from weakref import ref + +from IPython.Prompts import BasePrompt +from IPython.ipapi import get as get_ipython +from IPython.ipapi import TryNext + +from powerline.ipython import IPythonPowerline, RewriteResult +from powerline.lib.unicode import string + + +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): + self.p_str, self.p_str_nocolor, self.powerline_prompt_width = ( + self.powerline.render( + is_prompt=self.powerline_is_prompt, + side='left', + output_raw=True, + output_width=True, + segment_info=self.powerline_segment_info, + matcher_info=self.powerline_prompt_type, + ) + ) + + @staticmethod + def set_colors(): + pass + + +class PowerlinePrompt1(PowerlinePrompt): + powerline_prompt_type = 'in' + powerline_is_prompt = True + 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.powerline_last_in['nrspaces'] = self.nrspaces + + def auto_rewrite(self): + return RewriteResult(self.powerline.render( + is_prompt=False, + side='left', + matcher_info='rewrite', + segment_info=self.powerline_segment_info) + (' ' * self.nrspaces) + ) + + +class PowerlinePromptOut(PowerlinePrompt): + powerline_prompt_type = 'out' + powerline_is_prompt = False + + def set_p_str(self): + super(PowerlinePromptOut, self).set_p_str() + spaces = ' ' * self.powerline_last_in['nrspaces'] + self.p_str += spaces + self.p_str_nocolor += spaces + + +class PowerlinePrompt2(PowerlinePromptOut): + powerline_prompt_type = 'in2' + powerline_is_prompt = True + + +class ConfigurableIPythonPowerline(IPythonPowerline): + def init(self, config_overrides=None, theme_overrides={}, config_paths=None): + self.config_overrides = config_overrides + self.theme_overrides = theme_overrides + self.config_paths = config_paths + super(ConfigurableIPythonPowerline, self).init(renderer_module='.pre_5') + + def ipython_magic(self, ip, parameter_s=''): + if parameter_s == 'reload': + self.reload() + else: + raise ValueError('Expected `reload`, but got {0}'.format(parameter_s)) + + def do_setup(self, ip, shutdown_hook): + last_in = {'nrspaces': 0} + for attr, prompt_class in ( + ('prompt1', PowerlinePrompt1), + ('prompt2', PowerlinePrompt2), + ('prompt_out', PowerlinePromptOut) + ): + old_prompt = getattr(ip.IP.outputcache, attr) + prompt = prompt_class(self, last_in, old_prompt) + setattr(ip.IP.outputcache, attr, prompt) + ip.expose_magic('powerline', self.ipython_magic) + shutdown_hook.powerline = ref(self) + + +class ShutdownHook(object): + powerline = lambda: None + + def __call__(self): + from IPython.ipapi import TryNext + powerline = self.powerline() + if powerline is not None: + powerline.shutdown() + raise TryNext() + + +def setup(**kwargs): + ip = get_ipython() + + powerline = ConfigurableIPythonPowerline(**kwargs) + shutdown_hook = ShutdownHook() + + def late_startup_hook(): + powerline.setup(ip, shutdown_hook) + raise TryNext() + + ip.IP.hooks.late_startup_hook.add(late_startup_hook) + ip.IP.hooks.shutdown_hook.add(shutdown_hook) diff --git a/powerline/bindings/ipython/since_5.py b/powerline/bindings/ipython/since_5.py new file mode 100644 index 0000000..5a899ae --- /dev/null +++ b/powerline/bindings/ipython/since_5.py @@ -0,0 +1,81 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from weakref import ref + +from IPython.terminal.prompts import Prompts +from pygments.token import Token # NOQA + +from powerline.ipython import IPythonPowerline +from powerline.renderers.ipython.since_5 import PowerlinePromptStyle +from powerline.bindings.ipython.post_0_11 import PowerlineMagics, ShutdownHook + + +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.config_paths = config.get('config_paths') + super(ConfigurableIPythonPowerline, self).init( + renderer_module='.since_5') + + def do_setup(self, ip, prompts, shutdown_hook): + prompts.powerline = self + + msfn_missing = () + saved_msfn = getattr(ip, '_make_style_from_name', msfn_missing) + + if hasattr(saved_msfn, 'powerline_original'): + saved_msfn = saved_msfn.powerline_original + + def _make_style_from_name(ip, name): + prev_style = saved_msfn(name) + new_style = PowerlinePromptStyle(lambda: prev_style) + return new_style + + _make_style_from_name.powerline_original = saved_msfn + + if not isinstance(ip._style, PowerlinePromptStyle): + prev_style = ip._style + ip._style = PowerlinePromptStyle(lambda: prev_style) + + if not isinstance(saved_msfn, type(self.init)): + _saved_msfn = saved_msfn + saved_msfn = lambda: _saved_msfn(ip) + + if saved_msfn is not msfn_missing: + ip._make_style_from_name = _make_style_from_name + + magics = PowerlineMagics(ip, self) + ip.register_magics(magics) + + if shutdown_hook: + shutdown_hook.powerline = ref(self) + + +class PowerlinePrompts(Prompts): + '''Class that returns powerline prompts + ''' + def __init__(self, shell): + shutdown_hook = ShutdownHook(shell) + powerline = ConfigurableIPythonPowerline(shell) + self.shell = shell + powerline.do_setup(shell, self, shutdown_hook) + self.last_output_count = None + self.last_output = {} + + for prompt in ('in', 'continuation', 'rewrite', 'out'): + exec(( + 'def {0}_prompt_tokens(self, *args, **kwargs):\n' + ' if self.last_output_count != self.shell.execution_count:\n' + ' self.last_output.clear()\n' + ' self.last_output_count = self.shell.execution_count\n' + ' if "{0}" not in self.last_output:\n' + ' self.last_output["{0}"] = self.powerline.render(' + ' side="left",' + ' matcher_info="{1}",' + ' segment_info=self.shell,' + ' ) + [(Token.Generic.Prompt, " ")]\n' + ' return self.last_output["{0}"]' + ).format(prompt, 'in2' if prompt == 'continuation' else prompt)) diff --git a/powerline/bindings/ipython/since_7.py b/powerline/bindings/ipython/since_7.py new file mode 100644 index 0000000..4d35b68 --- /dev/null +++ b/powerline/bindings/ipython/since_7.py @@ -0,0 +1,78 @@ +# vim:fileencoding=utf-8:noet +from weakref import ref +from atexit import register as atexit + +from IPython.terminal.prompts import Prompts +from pygments.token import Token # NOQA + +from powerline.ipython import IPythonPowerline +from powerline.renderers.ipython.since_7 import PowerlinePromptStyle +from powerline.bindings.ipython.post_0_11 import PowerlineMagics + + +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.config_paths = config.get('config_paths') + super(ConfigurableIPythonPowerline, self).init( + renderer_module='.since_7') + + def do_setup(self, ip, prompts): + prompts.powerline = self + + msfn_missing = () + saved_msfn = getattr(ip, '_make_style_from_name', msfn_missing) + + if hasattr(saved_msfn, 'powerline_original'): + saved_msfn = saved_msfn.powerline_original + + def _make_style_from_name(ip, name): + prev_style = saved_msfn(name) + new_style = PowerlinePromptStyle(lambda: prev_style) + return new_style + + _make_style_from_name.powerline_original = saved_msfn + + if not isinstance(ip._style, PowerlinePromptStyle): + prev_style = ip._style + ip._style = PowerlinePromptStyle(lambda: prev_style) + + if not isinstance(saved_msfn, type(self.init)): + _saved_msfn = saved_msfn + saved_msfn = lambda: _saved_msfn(ip) + + if saved_msfn is not msfn_missing: + ip._make_style_from_name = _make_style_from_name + + magics = PowerlineMagics(ip, self) + ip.register_magics(magics) + + atexit(self.shutdown) + + +class PowerlinePrompts(Prompts): + '''Class that returns powerline prompts + ''' + def __init__(self, shell): + powerline = ConfigurableIPythonPowerline(shell) + self.shell = shell + powerline.do_setup(shell, self) + self.last_output_count = None + self.last_output = {} + + for prompt in ('in', 'continuation', 'rewrite', 'out'): + exec(( + 'def {0}_prompt_tokens(self, *args, **kwargs):\n' + ' if self.last_output_count != self.shell.execution_count:\n' + ' self.last_output.clear()\n' + ' self.last_output_count = self.shell.execution_count\n' + ' if "{0}" not in self.last_output:\n' + ' self.last_output["{0}"] = self.powerline.render(' + ' side="left",' + ' matcher_info="{1}",' + ' segment_info=self.shell,' + ' ) + [(Token.Generic.Prompt, " ")]\n' + ' return self.last_output["{0}"]' + ).format(prompt, 'in2' if prompt == 'continuation' else prompt)) diff --git a/powerline/bindings/lemonbar/powerline-lemonbar.py b/powerline/bindings/lemonbar/powerline-lemonbar.py new file mode 100755 index 0000000..9511f28 --- /dev/null +++ b/powerline/bindings/lemonbar/powerline-lemonbar.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import time +import re +import subprocess + +from threading import Lock, Timer + +from powerline.lemonbar import LemonbarPowerline +from powerline.commands.lemonbar import get_argparser +from powerline.bindings.wm import get_connected_xrandr_outputs + + +if __name__ == '__main__': + parser = get_argparser() + args = parser.parse_args() + + powerline = LemonbarPowerline() + powerline.update_renderer() + bars = [] + + for screen in get_connected_xrandr_outputs(powerline.pl): + command = [args.bar_command, '-g', '{0}x{1}+{2}+{3}'.format(screen['width'], args.height, screen['x'], screen['y'])] + args.args[1:] + process = subprocess.Popen(command, stdin=subprocess.PIPE) + bars.append((screen['name'], process, int(screen['width']) / 5)) + + lock = Lock() + modes = ['default'] + + def render(reschedule=False): + if reschedule: + Timer(args.interval, render, kwargs={'reschedule': True}).start() + + global lock + with lock: + for output, process, width in bars: + process.stdin.write(powerline.render(mode=modes[0], width=width, matcher_info=output).encode('utf-8') + b'\n') + process.stdin.flush() + + def update(evt): + modes[0] = evt.change + render() + + render(reschedule=True) + + if args.i3: + try: + import i3ipc + except ImportError: + import i3 + i3.Subscription(lambda evt, data, sub: render(), 'workspace') + else: + conn = i3ipc.Connection() + conn.on('workspace::focus', lambda conn, evt: render()) + conn.on('mode', lambda conn, evt: update(evt)) + conn.main() + + while True: + time.sleep(1e8) diff --git a/powerline/bindings/pdb/__init__.py b/powerline/bindings/pdb/__init__.py new file mode 100644 index 0000000..4033e61 --- /dev/null +++ b/powerline/bindings/pdb/__init__.py @@ -0,0 +1,183 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import pdb + +from powerline.pdb import PDBPowerline +from powerline.lib.encoding import get_preferred_output_encoding +from powerline.lib.unicode import unicode + + +if sys.version_info < (3,): + # XXX The below classes make code compatible with PDBpp which uses pyrepl + # which does not expect unicode or something above ASCII. They are + # completely not needed if pdbpp is not used, but that’s not always the + # case. + class PowerlineRenderBytesResult(bytes): + def __new__(cls, s, encoding=None): + encoding = encoding or s.encoding + if isinstance(s, PowerlineRenderResult): + return s.encode(encoding) + self = bytes.__new__(cls, s.encode(encoding) if isinstance(s, unicode) else s) + self.encoding = encoding + return self + + for meth in ( + '__contains__', + 'partition', 'rpartition', + 'split', 'rsplit', + 'count', 'join', + ): + exec(( + 'def {0}(self, *args):\n' + ' if any((isinstance(arg, unicode) for arg in args)):\n' + ' return self.__unicode__().{0}(*args)\n' + ' else:\n' + ' return bytes.{0}(self, *args)' + ).format(meth)) + + for meth in ( + 'find', 'rfind', + 'index', 'rindex', + ): + exec(( + 'def {0}(self, *args):\n' + ' if any((isinstance(arg, unicode) for arg in args)):\n' + ' args = [arg.encode(self.encoding) if isinstance(arg, unicode) else arg for arg in args]\n' + ' return bytes.{0}(self, *args)' + ).format(meth)) + + def __len__(self): + return len(self.decode(self.encoding)) + + def __getitem__(self, *args): + return PowerlineRenderBytesResult(bytes.__getitem__(self, *args), encoding=self.encoding) + + def __getslice__(self, *args): + return PowerlineRenderBytesResult(bytes.__getslice__(self, *args), encoding=self.encoding) + + @staticmethod + def add(encoding, *args): + if any((isinstance(arg, unicode) for arg in args)): + return PowerlineRenderResult(''.join(( + arg + if isinstance(arg, unicode) + else arg.decode(encoding) + for arg in args + )), encoding) + else: + return PowerlineRenderBytesResult(b''.join(args), encoding=encoding) + + def __add__(self, other): + return self.add(self.encoding, self, other) + + def __radd__(self, other): + return self.add(self.encoding, other, self) + + def __unicode__(self): + return PowerlineRenderResult(self) + + class PowerlineRenderResult(unicode): + def __new__(cls, s, encoding=None): + encoding = ( + encoding + or getattr(s, 'encoding', None) + or get_preferred_output_encoding() + ) + if isinstance(s, unicode): + self = unicode.__new__(cls, s) + else: + self = unicode.__new__(cls, s, encoding, 'replace') + self.encoding = encoding + return self + + def __str__(self): + return PowerlineRenderBytesResult(self) + + def __getitem__(self, *args): + return PowerlineRenderResult(unicode.__getitem__(self, *args)) + + def __getslice__(self, *args): + return PowerlineRenderResult(unicode.__getslice__(self, *args)) + + @staticmethod + def add(encoding, *args): + return PowerlineRenderResult(''.join(( + arg + if isinstance(arg, unicode) + else arg.decode(encoding) + for arg in args + )), encoding) + + def __add__(self, other): + return self.add(self.encoding, self, other) + + def __radd__(self, other): + return self.add(self.encoding, other, self) + + def encode(self, *args, **kwargs): + return PowerlineRenderBytesResult(unicode.encode(self, *args, **kwargs), args[0]) +else: + PowerlineRenderResult = str + + +def use_powerline_prompt(cls): + '''Decorator that installs powerline prompt to the class + + :param pdb.Pdb cls: + Class that should be decorated. + + :return: + ``cls`` argument or a class derived from it. Latter is used to turn + old-style classes into new-style classes. + ''' + @property + def prompt(self): + try: + powerline = self.powerline + except AttributeError: + powerline = PDBPowerline() + powerline.setup(self) + self.powerline = powerline + return PowerlineRenderResult(powerline.render(side='left')) + + @prompt.setter + def prompt(self, _): + pass + + @prompt.deleter + def prompt(self): + pass + + if not hasattr(cls, '__class__'): + # Old-style class: make it new-style or @property will not work. + old_cls = cls + + class cls(cls, object): + __module__ = cls.__module__ + __doc__ = cls.__doc__ + + cls.__name__ = old_cls.__name__ + + cls.prompt = prompt + + return cls + + +def main(): + '''Run module as a script + + Uses :py:func:`pdb.main` function directly, but prior to that it mocks + :py:class:`pdb.Pdb` class with powerline-specific class instance. + ''' + orig_pdb = pdb.Pdb + + @use_powerline_prompt + class Pdb(pdb.Pdb, object): + def __init__(self): + orig_pdb.__init__(self) + + pdb.Pdb = Pdb + + return pdb.main() diff --git a/powerline/bindings/pdb/__main__.py b/powerline/bindings/pdb/__main__.py new file mode 100755 index 0000000..768b2f2 --- /dev/null +++ b/powerline/bindings/pdb/__main__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from powerline.bindings.pdb import main + + +if __name__ == '__main__': + main() diff --git a/powerline/bindings/qtile/__init__.py b/powerline/bindings/qtile/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/powerline/bindings/qtile/__init__.py diff --git a/powerline/bindings/qtile/widget.py b/powerline/bindings/qtile/widget.py new file mode 100644 index 0000000..92e3a27 --- /dev/null +++ b/powerline/bindings/qtile/widget.py @@ -0,0 +1,61 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from libqtile.bar import CALCULATED +from libqtile.widget import TextBox + +from powerline import Powerline + + +class QTilePowerline(Powerline): + def do_setup(self, obj): + obj.powerline = self + + +class PowerlineTextBox(TextBox): + # TODO Replace timeout argument with update_interval argument in next major + # release. + def __init__(self, timeout=2, text=b' ', width=CALCULATED, side='right', update_interval=None, **config): + super(PowerlineTextBox, self).__init__(text, width, **config) + self.side = side + self.update_interval = update_interval or timeout + self.did_run_timer_setup = False + powerline = QTilePowerline(ext='wm', renderer_module='pango_markup') + powerline.setup(self) + + def update(self): + if not self.configured: + return True + self.text = self.powerline.render(side=self.side).encode('utf-8') + self.bar.draw() + return True + + def cmd_update(self, text): + self.update(text) + + def cmd_get(self): + return self.text + + def timer_setup(self): + if not self.did_run_timer_setup: + self.did_run_timer_setup = True + self.timeout_add(self.update_interval, self.update) + + def _configure(self, qtile, bar): + super(PowerlineTextBox, self)._configure(qtile, bar) + if self.layout.markup: + # QTile-0.9.1: no need to recreate layout or run timer_setup + return + self.layout = self.drawer.textlayout( + self.text, + self.foreground, + self.font, + self.fontsize, + self.fontshadow, + markup=True, + ) + self.timer_setup() + + +# TODO: Remove this at next major release +Powerline = PowerlineTextBox diff --git a/powerline/bindings/rc/powerline.rc b/powerline/bindings/rc/powerline.rc new file mode 100644 index 0000000..b2d6538 --- /dev/null +++ b/powerline/bindings/rc/powerline.rc @@ -0,0 +1,92 @@ +fn _powerline_sigwinch { + _POWERLINE_COLUMNS = `{ + stty size | cut -d' ' -f2 + } + _powerline_tmux_setenv COLUMNS $_POWERLINE_COLUMNS +} +fn _powerline_update_pwd { + _POWERLINE_NEW_PWD = `{pwd} + if (test $^_POWERLINE_NEW_PWD '=' $^_POWERLINE_SAVED_PWD) { + _POWERLINE_SAVED_PWD = $_POWERLINE_NEW_PWD + _powerline_tmux_setenv PWD $_POWERLINE_SAVED_PWD + } +} +fn _powerline_continuation_prompt { + _powerline_prompt --renderer-arg 'local_theme=continuation' $* +} +fn _powerline_prompt { + $POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS shell aboveleft -r.readline --last-pipe-status $^_POWERLINE_STATUS --last-exit-code $_POWERLINE_STATUS($#_POWERLINE_STATUS) --jobnum $_POWERLINE_JOBNUM --renderer-arg 'client_id='$pid $* +} +fn _powerline_set_prompt { + _POWERLINE_STATUS = ( $status ) + _POWERLINE_JOBNUM = $#apids + prompt = (``() { + _powerline_prompt + } ``() { + _powerline_continuation_prompt + }) + _powerline_update_pwd +} + +fn _powerline_common_setup { + fn sigwinch { + _powerline_sigwinch + } + _powerline_sigwinch + _POWERLINE_SAVED_PWD = '' +} + +fn _powerline_tmux_pane { + if (test -n $TMUX_PANE) { + echo $TMUX_PANE | tr -d ' %' + } else { + TMUX=$_POWERLINE_TMUX tmux display -p '#D' | tr -d ' %' + } +} + +fn _powerline_tmux_setenv { +} + +if (test -z $POWERLINE_CONFIG_COMMAND) { + if (which powerline-config >/dev/null) { + POWERLINE_CONFIG_COMMAND = powerline-config + } else { + echo powerline-config executable not found, unable to proceed >[2=1] + } +} +if (test -n $POWERLINE_CONFIG_COMMAND) { + if ($POWERLINE_CONFIG_COMMAND shell --shell rcsh uses prompt) { + if (test -n $POWERLINE_COMMAND_ARGS) { + # Perform splitting + POWERLINE_COMMAND_ARGS=( `{echo $POWERLINE_COMMAND_ARGS} ) + } + fn prompt { + _powerline_set_prompt + } + if (test -z $POWERLINE_SHELL_CONTINUATION$POWERLINE_RCSH_CONTINUATION) { + _POWERLINE_STATUS = 0 + _POWERLINE_JOBNUM = 0 + _POWERLINE_CONTINUATION = `{ + _powerline_continuation_prompt + } + fn _powerline_continuation_prompt { + echo -n $_POWERLINE_CONTINUATION + } + } + _powerline_common_setup + } + if (test -n $TMUX) { + if ($POWERLINE_CONFIG_COMMAND shell --shell rcsh uses tmux) { + _POWERLINE_TMUX=$TMUX + fn _powerline_tmux_setenv { + if (test -n $2) { + TMUX=$_POWERLINE_TMUX tmux setenv -g TMUX_$1^_`{ + _powerline_tmux_pane + } $2 + } + } + _powerline_common_setup + } + } +} +# vim: ft=rcshell diff --git a/powerline/bindings/shell/powerline.sh b/powerline/bindings/shell/powerline.sh new file mode 100644 index 0000000..e1b067d --- /dev/null +++ b/powerline/bindings/shell/powerline.sh @@ -0,0 +1,239 @@ +_POWERLINE_SOURCED="$_" +_powerline_columns_fallback() { + if command -v stty >/dev/null ; then + # Ksh does not have “local” built-in + _powerline_cols="$(stty size 2>/dev/null)" + if ! test -z "$_powerline_cols" ; then + echo "${_powerline_cols#* }" + return 0 + fi + fi + echo 0 + return 0 +} + +_powerline_has_jobs_in_subshell() { + if test -n "$_POWERLINE_HAS_JOBS_IN_SUBSHELL" ; then + return $_POWERLINE_HAS_JOBS_IN_SUBSHELL + elif test -z "$1" ; then + sleep 1 & + # Check whether shell outputs anything in a subshell when using jobs + # built-in. Shells like dash will not output anything meaning that + # I have to bother with temporary files. + test "$(jobs -p|wc -l)" -gt 0 + else + case "$1" in + dash|bb|ash) return 1 ;; + mksh|ksh|bash) return 0 ;; + *) _powerline_has_jobs_in_subshell ;; + esac + fi + _POWERLINE_HAS_JOBS_IN_SUBSHELL=$? + return $_POWERLINE_HAS_JOBS_IN_SUBSHELL +} + +_powerline_set_append_trap() { + if _powerline_has_jobs_in_subshell "$@" ; then + _powerline_append_trap() { + # Arguments: command, signal + # Ksh does not have “local” built-in + _powerline_traps="$(trap)" + if echo "$_powerline_traps" | grep -cm1 $2'$' >/dev/null ; then + _powerline_traps="$(echo "$_powerline_traps" | sed "s/ $2/'\\n$1' $2/")" + eval "$_powerline_traps" + else + trap "$1" $2 + fi + } + else + _powerline_append_trap() { + # Arguments: command, signal + _powerline_create_temp + trap > $_POWERLINE_TEMP + if grep -cm1 $2'$' $_POWERLINE_TEMP >/dev/null ; then + sed -i -e "s/ $2/'\\n$1' $2/" + . $_POWERLINE_TEMP + else + trap "$1" $2 + fi + echo -n > $_POWERLINE_TEMP + } + fi + _powerline_set_append_trap() { + return 0 + } +} + +_powerline_create_temp() { + if test -z "$_POWERLINE_TEMP" || ! test -e "$_POWERLINE_TEMP" ; then + _POWERLINE_TEMP="$(mktemp "${TMPDIR:-/tmp}/powerline.XXXXXXXX")" + _powerline_append_trap 'rm $_POWERLINE_TEMP' EXIT + fi +} + +_powerline_set_set_jobs() { + if _powerline_has_jobs_in_subshell "$@" ; then + _powerline_set_jobs() { + _POWERLINE_JOBS="$(jobs -p|wc -l|tr -d ' ')" + } + else + _powerline_set_append_trap "$@" + _POWERLINE_PID=$$ + _powerline_append_trap '_powerline_do_set_jobs' USR1 + _powerline_do_set_jobs() { + _powerline_create_temp + jobs -p > $_POWERLINE_TEMP + } + # This command will always be launched from a subshell, thus a hack is + # needed to run `jobs -p` outside of the subshell. + _powerline_set_jobs() { + kill -USR1 $_POWERLINE_PID + # Note: most likely this will read data from the previous run. Tests + # show that it is OK for some reasons. + _POWERLINE_JOBS="$(wc -l < $_POWERLINE_TEMP | tr -d ' ')" + } + fi + _powerline_set_set_jobs() { + return 0 + } +} + +_powerline_set_command() { + if test -z "${POWERLINE_COMMAND}" ; then + POWERLINE_COMMAND="$("$POWERLINE_CONFIG_COMMAND" shell command)" + fi +} + +_powerline_tmux_pane() { + echo "${TMUX_PANE:-`TMUX="$_POWERLINE_TMUX" tmux display -p "#D"`}" | \ + tr -d ' %' +} + +_powerline_tmux_setenv() { + TMUX="$_POWERLINE_TMUX" tmux setenv -g TMUX_"$1"_`_powerline_tmux_pane` "$2" + TMUX="$_POWERLINE_TMUX" tmux refresh -S +} + +_powerline_tmux_set_pwd() { + if test "$_POWERLINE_SAVED_PWD" != "$PWD" ; then + _POWERLINE_SAVED_PWD="$PWD" + _powerline_tmux_setenv PWD "$PWD" + fi +} + +_powerline_tmux_set_columns() { + _powerline_tmux_setenv COLUMNS "${COLUMNS:-$(_powerline_columns_fallback)}" +} + +_powerline_set_renderer_arg() { + case "$1" in + bb|ash) _POWERLINE_RENDERER_ARG="-r .bash" ;; + mksh|ksh) _POWERLINE_RENDERER_ARG="-r .ksh" ;; + bash|dash) _POWERLINE_RENDERER_ARG= ;; + esac +} + +_powerline_set_jobs() { + _powerline_set_set_jobs + _powerline_set_jobs +} + +_powerline_local_prompt() { + # Arguments: side, exit_code, local theme + _powerline_set_jobs + "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \ + $_POWERLINE_RENDERER_ARG \ + --renderer-arg="client_id=$$" \ + --last-exit-code=$2 \ + --jobnum=$_POWERLINE_JOBS \ + --renderer-arg="local_theme=$3" +} + +_powerline_prompt() { + # Arguments: side, exit_code + _powerline_set_jobs + "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \ + --width="${COLUMNS:-$(_powerline_columns_fallback)}" \ + $_POWERLINE_RENDERER_ARG \ + --renderer-arg="client_id=$$" \ + --last-exit-code=$2 \ + --jobnum=$_POWERLINE_JOBS + _powerline_update_psN +} + +_powerline_setup_psN() { + case "$1" in + mksh|ksh|bash) + _POWERLINE_PID=$$ + _powerline_update_psN() { + kill -USR1 $_POWERLINE_PID + } + # No command substitution in PS2 and PS3 + _powerline_set_psN() { + if test -n "$POWERLINE_SHELL_CONTINUATION" ; then + PS2="$(_powerline_local_prompt left $? continuation)" + fi + if test -n "$POWERLINE_SHELL_SELECT" ; then + PS3="$(_powerline_local_prompt left $? select)" + fi + } + _powerline_append_trap '_powerline_set_psN' USR1 + _powerline_set_psN + ;; + bb|ash|dash) + _powerline_update_psN() { + # Do nothing + return + } + PS2='$(_powerline_local_prompt left $? continuation)' + # No select support + ;; + esac +} + +_powerline_setup_prompt() { + VIRTUAL_ENV_DISABLE_PROMPT=1 + _powerline_set_append_trap "$@" + _powerline_set_set_jobs "$@" + _powerline_set_command "$@" + _powerline_set_renderer_arg "$@" + PS1='$(_powerline_prompt aboveleft $?)' + PS2="$(_powerline_local_prompt left 0 continuation)" + PS3="$(_powerline_local_prompt left 0 select)" + _powerline_setup_psN "$@" +} + +_powerline_init_tmux_support() { + # Dash does not have &>/dev/null + if test -n "$TMUX" && tmux refresh -S >/dev/null 2>/dev/null ; then + # TMUX variable may be unset to create new tmux session inside this one + _POWERLINE_TMUX="$TMUX" + + _powerline_set_append_trap "$@" + + # If _powerline_tmux_set_pwd is used before _powerline_prompt it sets $? + # to zero in ksh. + PS1="$PS1"'$(_powerline_tmux_set_pwd)' + _powerline_append_trap '_powerline_tmux_set_columns' WINCH + _powerline_tmux_set_columns + fi +} + +if test -z "${POWERLINE_CONFIG_COMMAND}" ; then + if command -v powerline-config >/dev/null ; then + POWERLINE_CONFIG_COMMAND=powerline-config + else + POWERLINE_CONFIG_COMMAND="$(dirname "$_POWERLINE_SOURCED")/../../../scripts/powerline-config" + fi +fi + +# Strips the leading `-`: it may be present when shell is a login shell +_POWERLINE_USED_SHELL=${0#-} +_POWERLINE_USED_SHELL=${_POWERLINE_USED_SHELL##*/} + +if "${POWERLINE_CONFIG_COMMAND}" shell uses tmux ; then + _powerline_init_tmux_support $_POWERLINE_USED_SHELL +fi +if "${POWERLINE_CONFIG_COMMAND}" shell --shell=bash uses prompt ; then + _powerline_setup_prompt $_POWERLINE_USED_SHELL +fi diff --git a/powerline/bindings/tcsh/powerline.tcsh b/powerline/bindings/tcsh/powerline.tcsh new file mode 100644 index 0000000..4897b4c --- /dev/null +++ b/powerline/bindings/tcsh/powerline.tcsh @@ -0,0 +1,60 @@ +# http://unix.stackexchange.com/questions/4650/determining-path-to-sourced-shell-script: +# > In tcsh, $_ at the beginning of the script will contain the location if the +# > file was sourced and $0 contains it if it was run. +# +# Guess this relies on `$_` being set as to last argument to previous command +# which must be `.` or `source` in this case +set POWERLINE_SOURCED=($_) +if ! $?POWERLINE_CONFIG_COMMAND then + if ( { which powerline-config > /dev/null } ) then + set POWERLINE_CONFIG_COMMAND="powerline-config" + else + set POWERLINE_CONFIG_COMMAND="$POWERLINE_SOURCED[2]:h:h:h:h/scripts/powerline-config" + endif +else + if "$POWERLINE_CONFIG_COMMAND" == "" then + if ( { which powerline-config > /dev/null } ) then + set POWERLINE_CONFIG_COMMAND="powerline-config" + else + set POWERLINE_CONFIG_COMMAND="$POWERLINE_SOURCED[2]:h:h:h:h/scripts/powerline-config" + endif + endif +endif +if ( { $POWERLINE_CONFIG_COMMAND shell --shell=tcsh uses tmux } ) then + if ( $?TMUX_PANE ) then + if ( "$TMUX_PANE" == "" ) then + set _POWERLINE_TMUX_PANE="`tmux display -p '#D'`" + else + set _POWERLINE_TMUX_PANE="$TMUX_PANE" + endif + else + set _POWERLINE_TMUX_PANE="`tmux display -p '#D'`" + endif + set _POWERLINE_TMUX_PANE="`echo $_POWERLINE_TMUX_PANE:q | tr -d '% '`" + alias _powerline_tmux_set_pwd 'if ( $?TMUX && { tmux refresh -S >&/dev/null } ) tmux setenv -g TMUX_PWD_$_POWERLINE_TMUX_PANE $PWD:q ; if ( $?TMUX ) tmux refresh -S >&/dev/null' + alias cwdcmd "`alias cwdcmd` ; _powerline_tmux_set_pwd" +endif +if ( { $POWERLINE_CONFIG_COMMAND shell --shell=tcsh uses prompt } ) then + if ! $?POWERLINE_COMMAND then + set POWERLINE_COMMAND="`$POWERLINE_CONFIG_COMMAND:q shell command`" + else + if "$POWERLINE_COMMAND" == "" then + set POWERLINE_COMMAND="`$POWERLINE_CONFIG_COMMAND:q shell command`" + endif + endif + if ! $?POWERLINE_COMMAND_ARGS then + set POWERLINE_COMMAND_ARGS="" + endif + + if ( $?POWERLINE_NO_TCSH_ABOVE || $?POWERLINE_NO_SHELL_ABOVE ) then + alias _powerline_above true + else + alias _powerline_above '$POWERLINE_COMMAND:q $POWERLINE_COMMAND_ARGS shell above --renderer-arg=client_id=$$ --last-exit-code=$POWERLINE_STATUS --width=$POWERLINE_COLUMNS' + endif + + alias _powerline_set_prompt 'set prompt="`$POWERLINE_COMMAND:q $POWERLINE_COMMAND_ARGS shell left -r .tcsh --renderer-arg=client_id=$$ --last-exit-code=$POWERLINE_STATUS --width=$POWERLINE_COLUMNS`"' + alias _powerline_set_rprompt 'set rprompt="`$POWERLINE_COMMAND:q $POWERLINE_COMMAND_ARGS shell right -r .tcsh --renderer-arg=client_id=$$ --last-exit-code=$POWERLINE_STATUS --width=$POWERLINE_COLUMNS`"' + alias _powerline_set_columns 'set POWERLINE_COLUMNS=`stty size|cut -d" " -f2` ; set POWERLINE_COLUMNS=`expr $POWERLINE_COLUMNS - 2`' + + alias precmd 'set POWERLINE_STATUS=$? ; '"`alias precmd`"' ; _powerline_set_columns ; _powerline_above ; _powerline_set_prompt ; _powerline_set_rprompt' +endif diff --git a/powerline/bindings/tmux/__init__.py b/powerline/bindings/tmux/__init__.py new file mode 100644 index 0000000..eb84e7a --- /dev/null +++ b/powerline/bindings/tmux/__init__.py @@ -0,0 +1,85 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import re +import os +import subprocess + +from collections import namedtuple + +from powerline.lib.shell import run_cmd + + +TmuxVersionInfo = namedtuple('TmuxVersionInfo', ('major', 'minor', 'suffix')) + + +def get_tmux_executable_name(): + '''Returns tmux executable name + + It should be defined in POWERLINE_TMUX_EXE environment variable, otherwise + it is simply “tmux”. + ''' + + return os.environ.get('POWERLINE_TMUX_EXE', 'tmux') + + +def _run_tmux(runner, args): + return runner([get_tmux_executable_name()] + list(args)) + + +def run_tmux_command(*args): + '''Run tmux command, ignoring the output''' + _run_tmux(subprocess.check_call, args) + + +def get_tmux_output(pl, *args): + '''Run tmux command and return its output''' + return _run_tmux(lambda cmd: run_cmd(pl, cmd), args) + + +def set_tmux_environment(varname, value, remove=True): + '''Set tmux global environment variable + + :param str varname: + Name of the variable to set. + :param str value: + Variable value. + :param bool remove: + True if variable should be removed from the environment prior to + attaching any client (runs ``tmux set-environment -r {varname}``). + ''' + run_tmux_command('set-environment', '-g', varname, value) + if remove: + try: + run_tmux_command('set-environment', '-r', varname) + except subprocess.CalledProcessError: + # On tmux-2.0 this command may fail for whatever reason. Since it is + # critical just ignore the failure. + pass + + +def source_tmux_file(fname): + '''Source tmux configuration file + + :param str fname: + Full path to the sourced file. + ''' + run_tmux_command('source', fname) + + +NON_DIGITS = re.compile('[^0-9]+') +DIGITS = re.compile('[0-9]+') +NON_LETTERS = re.compile('[^a-z]+') + + +def get_tmux_version(pl): + version_string = get_tmux_output(pl, '-V') + _, version_string = version_string.split(' ') + version_string = version_string.strip() + if version_string == 'master': + return TmuxVersionInfo(float('inf'), 0, version_string) + major, minor = version_string.split('.') + major = NON_DIGITS.subn('', major)[0] + suffix = DIGITS.subn('', minor)[0] or None + minor = NON_DIGITS.subn('', minor)[0] + return TmuxVersionInfo(int(major), int(minor), suffix) diff --git a/powerline/bindings/tmux/powerline-base.conf b/powerline/bindings/tmux/powerline-base.conf new file mode 100644 index 0000000..50a1079 --- /dev/null +++ b/powerline/bindings/tmux/powerline-base.conf @@ -0,0 +1,11 @@ +set -g status on +set -g status-interval 2 +set -g status-left-length 20 +set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right -R pane_id=#{pane_id})' +set -g status-right-length 150 +set -g window-status-format "#[$_POWERLINE_WINDOW_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER_SPACES#I#F #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W $_POWERLINE_LEFT_HARD_DIVIDER_SPACES" +set -g window-status-current-format "#[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#[$_POWERLINE_WINDOW_CURRENT_COLOR]#I#F $_POWERLINE_LEFT_SOFT_DIVIDER#[$_POWERLINE_WINDOW_NAME_COLOR]#W #[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER" + +# Legacy status-left definition to be overwritten for tmux Versions 1.8+ +set -g status-left "#[$_POWERLINE_SESSION_COLOR] #S #[$_POWERLINE_SESSION_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#(env \"\$POWERLINE_COMMAND\" tmux left -R pane_id=#{pane_id})" +# vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline.conf b/powerline/bindings/tmux/powerline.conf new file mode 100644 index 0000000..29ec6a4 --- /dev/null +++ b/powerline/bindings/tmux/powerline.conf @@ -0,0 +1,2 @@ +if-shell 'env "$POWERLINE_CONFIG_COMMAND" tmux setup' '' 'run-shell "powerline-config tmux setup"' +# vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf b/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf new file mode 100644 index 0000000..ab7d0b4 --- /dev/null +++ b/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf @@ -0,0 +1,3 @@ +set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right -R pane_id=#{pane_id} --width=#{client_width} -R width_adjust=#{status-left-length})' +set -g status-left "#[$_POWERLINE_SESSION_COLOR] #S #[$_POWERLINE_SESSION_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#(env \"\$POWERLINE_COMMAND\" tmux left --width=#{client_width} -R width_adjust=#{status-right-length} -R pane_id=#{pane_id})" +# vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline_tmux_1.8.conf b/powerline/bindings/tmux/powerline_tmux_1.8.conf new file mode 100644 index 0000000..fbcd2a5 --- /dev/null +++ b/powerline/bindings/tmux/powerline_tmux_1.8.conf @@ -0,0 +1,5 @@ +# powerline_tmux_1.8.conf +# tmux Version 1.8 introduces window-status-last-{attr,bg,fg}, which is +# deprecated for versions 1.9+, thus only applicable to version 1.8. +set -qg window-status-last-fg "$_POWERLINE_ACTIVE_WINDOW_FG" +# vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline_tmux_1.8_minus.conf b/powerline/bindings/tmux/powerline_tmux_1.8_minus.conf new file mode 100644 index 0000000..284eee0 --- /dev/null +++ b/powerline/bindings/tmux/powerline_tmux_1.8_minus.conf @@ -0,0 +1,11 @@ +# powerline_tmux_legacy_common.conf +# tmux Version 1.8 and earlier (legacy) common options. The foo-{attr,bg,fg} +# options are deprecated starting with tmux Version 1.9. +set -g status-fg "$_POWERLINE_BACKGROUND_FG" +set -g status-bg "$_POWERLINE_BACKGROUND_BG" +set-window-option -g window-status-fg "$_POWERLINE_WINDOW_STATUS_FG" +set-window-option -g window-status-activity-attr "$_POWERLINE_ACTIVITY_STATUS_ATTR_LEGACY" +set-window-option -g window-status-bell-attr "$_POWERLINE_BELL_STATUS_ATTR_LEGACY" +set-window-option -g window-status-activity-fg "$_POWERLINE_ACTIVITY_STATUS_FG" +set-window-option -g window-status-bell-fg "$_POWERLINE_BELL_STATUS_FG" +# vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf b/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf new file mode 100644 index 0000000..e7144fb --- /dev/null +++ b/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf @@ -0,0 +1,5 @@ +# powerline_tmux_1.8_plus.conf +# tmux Version 1.8 introduces the 'client_prefix' format variable, applicable +# for versions 1.8+ +set -qg status-left "#{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_FG]#[bg=$_POWERLINE_SESSION_PREFIX_BG]#[$_POWERLINE_SESSION_PREFIX_ATTR],#[fg=$_POWERLINE_SESSION_FG]#[bg=$_POWERLINE_SESSION_BG]#[$_POWERLINE_SESSION_ATTR]} #S #{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_BG],#[fg=$_POWERLINE_SESSION_BG]}#[bg=$_POWERLINE_BACKGROUND_BG]#[nobold]$_POWERLINE_LEFT_HARD_DIVIDER#(env \$POWERLINE_COMMAND \$POWERLINE_COMMAND_ARGS tmux left --width=#{client_width} -R width_adjust=#{status-right-length} -R pane_id=#{pane_id})" +# vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline_tmux_1.9_plus.conf b/powerline/bindings/tmux/powerline_tmux_1.9_plus.conf new file mode 100644 index 0000000..b1afaf4 --- /dev/null +++ b/powerline/bindings/tmux/powerline_tmux_1.9_plus.conf @@ -0,0 +1,9 @@ +# powerline_tmux_1.9_plus.conf +# Version 1.9 introduces the foo-style options, applicable to version 1.9+ +set-option -qg status-style "$_POWERLINE_BACKGROUND_COLOR" +set-option -qg window-status-last-style "$_POWERLINE_ACTIVE_WINDOW_STATUS_COLOR" +set-window-option -qg window-status-style "$_POWERLINE_WINDOW_STATUS_COLOR" +set-window-option -qg window-status-activity-style "$_POWERLINE_ACTIVITY_STATUS_COLOR" +set-window-option -qg window-status-bell-style "$_POWERLINE_BELL_STATUS_COLOR" +set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right --width=#{client_width} -R width_adjust=#{status-left-length} -R pane_id=#{pane_id} -R pane_current_path=#{q:pane_current_path})' +# vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline_tmux_2.1_plus.conf b/powerline/bindings/tmux/powerline_tmux_2.1_plus.conf new file mode 100644 index 0000000..16703b7 --- /dev/null +++ b/powerline/bindings/tmux/powerline_tmux_2.1_plus.conf @@ -0,0 +1,3 @@ +# Starting from tmux-2.1 escaping of dollar signs inside #() is harmful +set -qg status-left "#{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_FG]#[bg=$_POWERLINE_SESSION_PREFIX_BG]#[$_POWERLINE_SESSION_PREFIX_ATTR],#[fg=$_POWERLINE_SESSION_FG]#[bg=$_POWERLINE_SESSION_BG]#[$_POWERLINE_SESSION_ATTR]} #S #{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_BG],#[fg=$_POWERLINE_SESSION_BG]}#[bg=$_POWERLINE_BACKGROUND_BG]#[nobold]$_POWERLINE_LEFT_HARD_DIVIDER#(env $POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS tmux left --width=#{client_width} -R width_adjust=#{status-right-length} -R pane_id=#{pane_id} -R pane_current_path=#{q:pane_current_path})" +set -g window-status-format "#[$_POWERLINE_WINDOW_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER_SPACES#I#{?window_flags,#F, } #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W $_POWERLINE_LEFT_HARD_DIVIDER_SPACES" diff --git a/powerline/bindings/vim/__init__.py b/powerline/bindings/vim/__init__.py new file mode 100644 index 0000000..b754c1f --- /dev/null +++ b/powerline/bindings/vim/__init__.py @@ -0,0 +1,482 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import codecs + +try: + import vim +except ImportError: + vim = object() + +from powerline.lib.unicode import unicode + + +if ( + hasattr(vim, 'options') + and hasattr(vim, 'vvars') + and vim.vvars['version'] > 703 +): + if sys.version_info < (3,): + def get_vim_encoding(): + return vim.options['encoding'] or 'ascii' + else: + def get_vim_encoding(): + return vim.options['encoding'].decode('ascii') or 'ascii' +elif hasattr(vim, 'eval'): + def get_vim_encoding(): + return vim.eval('&encoding') or 'ascii' +else: + def get_vim_encoding(): + return 'utf-8' + +get_vim_encoding.__doc__ = ( + '''Get encoding used for Vim strings + + :return: + Value of ``&encoding``. If it is empty (i.e. Vim is compiled + without +multibyte) returns ``'ascii'``. When building documentation + outputs ``'utf-8'`` unconditionally. + ''' +) + + +vim_encoding = get_vim_encoding() + + +python_to_vim_types = { + unicode: ( + lambda o: b'\'' + (o.translate({ + ord('\''): '\'\'', + }).encode(vim_encoding)) + b'\'' + ), + list: ( + lambda o: b'[' + ( + b','.join((python_to_vim(i) for i in o)) + ) + b']' + ), + bytes: (lambda o: b'\'' + o.replace(b'\'', b'\'\'') + b'\''), + int: (str if str is bytes else (lambda o: unicode(o).encode('ascii'))), +} +python_to_vim_types[float] = python_to_vim_types[int] + + +def python_to_vim(o): + return python_to_vim_types[type(o)](o) + + +if sys.version_info < (3,): + def str_to_bytes(s): + return s + + def unicode_eval(expr): + ret = vim.eval(expr) + return ret.decode(vim_encoding, 'powerline_vim_strtrans_error') +else: + def str_to_bytes(s): + return s.encode(vim_encoding) + + def unicode_eval(expr): + return vim.eval(expr) + + +def safe_bytes_eval(expr): + return bytes(bytearray(( + int(chunk) for chunk in ( + vim.eval( + b'substitute(' + expr + b', ' + + b'\'^.*$\', \'\\=join(map(range(len(submatch(0))), ' + + b'"char2nr(submatch(0)[v:val])"))\', "")' + ).split() + ) + ))) + + +def eval_bytes(expr): + try: + return str_to_bytes(vim.eval(expr)) + except UnicodeDecodeError: + return safe_bytes_eval(expr) + + +def eval_unicode(expr): + try: + return unicode_eval(expr) + except UnicodeDecodeError: + return safe_bytes_eval(expr).decode(vim_encoding, 'powerline_vim_strtrans_error') + + +if hasattr(vim, 'bindeval'): + rettype_func = { + None: lambda f: f, + 'unicode': ( + lambda f: ( + lambda *args, **kwargs: ( + f(*args, **kwargs).decode( + vim_encoding, 'powerline_vim_strtrans_error' + )))) + } + rettype_func['int'] = rettype_func['bytes'] = rettype_func[None] + rettype_func['str'] = rettype_func['bytes'] if str is bytes else rettype_func['unicode'] + + def vim_get_func(f, rettype=None): + '''Return a vim function binding.''' + try: + func = vim.bindeval('function("' + f + '")') + except vim.error: + return None + else: + return rettype_func[rettype](func) +else: + rettype_eval = { + None: getattr(vim, 'eval', None), + 'int': lambda expr: int(vim.eval(expr)), + 'bytes': eval_bytes, + 'unicode': eval_unicode, + } + rettype_eval['str'] = rettype_eval[None] + + class VimFunc(object): + '''Evaluate a vim function using vim.eval(). + + This is a fallback class for older vim versions. + ''' + __slots__ = ('f', 'eval') + + def __init__(self, f, rettype=None): + self.f = f.encode('utf-8') + self.eval = rettype_eval[rettype] + + def __call__(self, *args): + return self.eval(self.f + b'(' + (b','.join(( + python_to_vim(o) for o in args + ))) + b')') + + vim_get_func = VimFunc + + +def vim_get_autoload_func(f, rettype=None): + func = vim_get_func(f) + if not func: + vim.command('runtime! ' + f.replace('#', '/')[:f.rindex('#')] + '.vim') + func = vim_get_func(f) + return func + + +if hasattr(vim, 'Function'): + def vim_func_exists(f): + try: + vim.Function(f) + except ValueError: + return False + else: + return True +else: + def vim_func_exists(f): + try: + return bool(int(vim.eval('exists("*{0}")'.format(f)))) + except vim.error: + return False + + +if type(vim) is object: + vim_get_func = lambda *args, **kwargs: None + + +_getbufvar = vim_get_func('getbufvar') +_vim_exists = vim_get_func('exists', rettype='int') + + +# It may crash on some old vim versions and I do not remember in which patch +# I fixed this crash. +if hasattr(vim, 'vvars') and vim.vvars[str('version')] > 703: + _vim_to_python_types = { + getattr(vim, 'Dictionary', None) or type(vim.bindeval('{}')): + lambda value: dict(( + (_vim_to_python(k), _vim_to_python(v)) + for k, v in value.items() + )), + getattr(vim, 'List', None) or type(vim.bindeval('[]')): + lambda value: [_vim_to_python(item) for item in value], + getattr(vim, 'Function', None) or type(vim.bindeval('function("mode")')): + lambda _: None, + } + + def vim_getvar(varname): + return _vim_to_python(vim.vars[str(varname)]) + + def bufvar_exists(buffer, varname): + buffer = buffer or vim.current.buffer + return varname in buffer.vars + + def vim_getwinvar(segment_info, varname): + return _vim_to_python(segment_info['window'].vars[str(varname)]) + + def vim_global_exists(name): + try: + vim.vars[name] + except KeyError: + return False + else: + return True +else: + _vim_to_python_types = { + dict: (lambda value: dict(((k, _vim_to_python(v)) for k, v in value.items()))), + list: (lambda value: [_vim_to_python(i) for i in value]), + } + + def vim_getvar(varname): + varname = 'g:' + varname + if _vim_exists(varname): + return vim.eval(varname) + else: + raise KeyError(varname) + + def bufvar_exists(buffer, varname): + if not buffer or buffer.number == vim.current.buffer.number: + return int(vim.eval('exists("b:{0}")'.format(varname))) + else: + return int(vim.eval( + 'has_key(getbufvar({0}, ""), {1})'.format(buffer.number, varname) + )) + + def vim_getwinvar(segment_info, varname): + result = vim.eval('getwinvar({0}, "{1}")'.format(segment_info['winnr'], varname)) + if result == '': + if not int(vim.eval('has_key(getwinvar({0}, ""), "{1}")'.format(segment_info['winnr'], varname))): + raise KeyError(varname) + return result + + def vim_global_exists(name): + return int(vim.eval('exists("g:' + name + '")')) + + +def vim_command_exists(name): + return _vim_exists(':' + name) + + +if sys.version_info < (3,): + getbufvar = _getbufvar +else: + _vim_to_python_types[bytes] = lambda value: value.decode(vim_encoding) + + def getbufvar(*args): + return _vim_to_python(_getbufvar(*args)) + + +_id = lambda value: value + + +def _vim_to_python(value): + return _vim_to_python_types.get(type(value), _id)(value) + + +if hasattr(vim, 'options'): + def vim_getbufoption(info, option): + return _vim_to_python(info['buffer'].options[str(option)]) + + def vim_getoption(option): + return vim.options[str(option)] + + def vim_setoption(option, value): + vim.options[str(option)] = value +else: + def vim_getbufoption(info, option): + return getbufvar(info['bufnr'], '&' + option) + + def vim_getoption(option): + return vim.eval('&g:' + option) + + def vim_setoption(option, value): + vim.command('let &g:{option} = {value}'.format( + option=option, value=python_to_vim(value))) + + +if hasattr(vim, 'tabpages'): + current_tabpage = lambda: vim.current.tabpage + list_tabpages = lambda: vim.tabpages + + def list_tabpage_buffers_segment_info(segment_info): + return ( + {'buffer': window.buffer, 'bufnr': window.buffer.number} + for window in segment_info['tabpage'].windows + ) +else: + class FalseObject(object): + @staticmethod + def __nonzero__(): + return False + + __bool__ = __nonzero__ + + def get_buffer(number): + for buffer in vim.buffers: + if buffer.number == number: + return buffer + raise KeyError(number) + + class WindowVars(object): + __slots__ = ('tabnr', 'winnr') + + def __init__(self, window): + self.tabnr = window.tabnr + self.winnr = window.number + + def __getitem__(self, key): + has_key = vim.eval('has_key(gettabwinvar({0}, {1}, ""), "{2}")'.format(self.tabnr, self.winnr, key)) + if has_key == '0': + raise KeyError + return vim.eval('gettabwinvar({0}, {1}, "{2}")'.format(self.tabnr, self.winnr, key)) + + def get(self, key, default=None): + try: + return self[key] + except KeyError: + return default + + class Window(FalseObject): + __slots__ = ('tabnr', 'number', '_vars') + + def __init__(self, tabnr, number): + self.tabnr = tabnr + self.number = number + self.vars = WindowVars(self) + + @property + def buffer(self): + return get_buffer(int(vim.eval('tabpagebuflist({0})[{1}]'.format(self.tabnr, self.number - 1)))) + + class Tabpage(FalseObject): + __slots__ = ('number',) + + def __init__(self, number): + self.number = number + + def __eq__(self, tabpage): + if not isinstance(tabpage, Tabpage): + raise NotImplementedError + return self.number == tabpage.number + + @property + def window(self): + return Window(self.number, int(vim.eval('tabpagewinnr({0})'.format(self.number)))) + + def _last_tab_nr(): + return int(vim.eval('tabpagenr("$")')) + + def current_tabpage(): + return Tabpage(int(vim.eval('tabpagenr()'))) + + def list_tabpages(): + return [Tabpage(nr) for nr in range(1, _last_tab_nr() + 1)] + + class TabBufSegmentInfo(dict): + def __getitem__(self, key): + try: + return super(TabBufSegmentInfo, self).__getitem__(key) + except KeyError: + if key != 'buffer': + raise + else: + buffer = get_buffer(super(TabBufSegmentInfo, self).__getitem__('bufnr')) + self['buffer'] = buffer + return buffer + + def list_tabpage_buffers_segment_info(segment_info): + return ( + TabBufSegmentInfo(bufnr=int(bufnrstr)) + for bufnrstr in vim.eval('tabpagebuflist({0})'.format(segment_info['tabnr'])) + ) + + +class VimEnviron(object): + @staticmethod + def __getitem__(key): + return vim.eval('$' + key) + + @staticmethod + def get(key, default=None): + return vim.eval('$' + key) or default + + @staticmethod + def __setitem__(key, value): + return vim.command( + 'let ${0}="{1}"'.format( + key, + value.replace('"', '\\"') + .replace('\\', '\\\\') + .replace('\n', '\\n') + .replace('\0', '') + ) + ) + + +if sys.version_info < (3,): + def buffer_name(segment_info): + return segment_info['buffer'].name +else: + vim_bufname = vim_get_func('bufname', rettype='bytes') + + def buffer_name(segment_info): + try: + name = segment_info['buffer'].name + except UnicodeDecodeError: + return vim_bufname(segment_info['bufnr']) + else: + return name.encode(segment_info['encoding']) if name else None + + +vim_strtrans = vim_get_func('strtrans', rettype='unicode') + + +def powerline_vim_strtrans_error(e): + if not isinstance(e, UnicodeDecodeError): + raise NotImplementedError + text = vim_strtrans(e.object[e.start:e.end]) + return (text, e.end) + + +codecs.register_error('powerline_vim_strtrans_error', powerline_vim_strtrans_error) + + +did_autocmd = False +buffer_caches = [] + + +def register_buffer_cache(cachedict): + global did_autocmd + global buffer_caches + from powerline.vim import get_default_pycmd, pycmd + if not did_autocmd: + import __main__ + __main__.powerline_on_bwipe = on_bwipe + vim.command('augroup Powerline') + vim.command(' autocmd! BufWipeout * :{pycmd} powerline_on_bwipe()'.format( + pycmd=(pycmd or get_default_pycmd()))) + vim.command('augroup END') + did_autocmd = True + buffer_caches.append(cachedict) + return cachedict + + +def on_bwipe(): + global buffer_caches + bufnr = int(vim.eval('expand("<abuf>")')) + for cachedict in buffer_caches: + cachedict.pop(bufnr, None) + + +environ = VimEnviron() + + +def create_ruby_dpowerline(): + vim.command(( + ''' + ruby + if $powerline == nil + class Powerline + end + $powerline = Powerline.new + end + ''' + )) diff --git a/powerline/bindings/vim/autoload/powerline/debug.vim b/powerline/bindings/vim/autoload/powerline/debug.vim new file mode 100644 index 0000000..244319a --- /dev/null +++ b/powerline/bindings/vim/autoload/powerline/debug.vim @@ -0,0 +1,20 @@ +python import cProfile +python powerline_pr = cProfile.Profile() + +function powerline#debug#profile_pyeval(s) + python powerline_pr.enable() + try + let ret = pyeval(a:s) + finally + python powerline_pr.disable() + endtry + return ret +endfunction + +function powerline#debug#write_profile(fname) + python import vim + python powerline_pr.dump_stats(vim.eval('a:fname')) + python powerline_pr = cProfile.Profile() +endfunction + +command -nargs=1 -complete=file WriteProfiling :call powerline#debug#write_profile(<q-args>) diff --git a/powerline/bindings/vim/plugin/powerline.vim b/powerline/bindings/vim/plugin/powerline.vim new file mode 100644 index 0000000..b06a389 --- /dev/null +++ b/powerline/bindings/vim/plugin/powerline.vim @@ -0,0 +1,169 @@ +if exists('g:powerline_loaded') + finish +endif +let g:powerline_loaded = 1 + +if exists('g:powerline_pycmd') + let s:pycmd = substitute(g:powerline_pycmd, '\v\C^(py)%[thon](3?)$', '\1\2', '') + if s:pycmd is# 'py' + let s:has_python = has('python') + let s:pyeval = get(g:, 'powerline_pyeval', 'pyeval') + elseif s:pycmd is# 'py3' + let s:has_python = has('python3') + let s:pyeval = 'py3eval' + let s:pyeval = get(g:, 'powerline_pyeval', 'py3eval') + else + if !exists('g:powerline_pyeval') + echohl ErrorMsg + echomsg 'g:powerline_pycmd was set to an unknown values, but g:powerline_pyeval' + echomsg 'was not set. You should either set g:powerline_pycmd to "py3" or "py",' + echomsg 'specify g:powerline_pyeval explicitly or unset both and let powerline' + echomsg 'figure them out.' + echohl None + unlet s:pycmd + finish + endif + let s:pyeval = g:powerline_pyeval + let s:has_python = 1 + endif +elseif has('python3') + let s:has_python = 1 + let s:pycmd = 'py3' + let s:pyeval = get(g:, 'powerline_pyeval', 'py3eval') +elseif has('python') + let s:has_python = 1 + let s:pycmd = 'py' + let s:pyeval = get(g:, 'powerline_pyeval', 'pyeval') +else + let s:has_python = 0 +endif + +if !s:has_python + if !exists('g:powerline_no_python_error') + echohl ErrorMsg + echomsg 'You need vim compiled with Python 2.6, 2.7 or 3.2 and later support' + echomsg 'for Powerline to work. Please consult the documentation for more' + echomsg 'details.' + echohl None + endif + unlet s:has_python + finish +endif +unlet s:has_python + +let s:import_cmd = 'from powerline.vim import VimPowerline' +function s:rcmd(s) + if !exists('s:pystr') + let s:pystr = a:s . "\n" + else + let s:pystr = s:pystr . a:s . "\n" + endif +endfunction +try + let s:can_replace_pyeval = !exists('g:powerline_pyeval') + call s:rcmd('try:') + call s:rcmd(' powerline_appended_path = None') + call s:rcmd(' try:') + call s:rcmd(' '.s:import_cmd.'') + call s:rcmd(' except ImportError:') + call s:rcmd(' import sys, vim') + call s:rcmd(' powerline_appended_path = vim.eval("expand(\"<sfile>:h:h:h:h:h\")")') + call s:rcmd(' sys.path.append(powerline_appended_path)') + call s:rcmd(' '.s:import_cmd.'') + call s:rcmd(' import vim') + call s:rcmd(' powerline_instance = VimPowerline()') + call s:rcmd(' powerline_instance.setup(pyeval=vim.eval("s:pyeval"), pycmd=vim.eval("s:pycmd"), can_replace_pyeval=int(vim.eval("s:can_replace_pyeval")))') + call s:rcmd(' del VimPowerline') + call s:rcmd(' del powerline_instance') + call s:rcmd('except Exception:') + call s:rcmd(' import traceback, sys') + call s:rcmd(' traceback.print_exc(file=sys.stdout)') + call s:rcmd(' raise') + execute s:pycmd s:pystr + unlet s:pystr + let s:launched = 1 +finally + unlet s:can_replace_pyeval + unlet s:import_cmd + if !exists('s:launched') + unlet s:pystr + echohl ErrorMsg + echomsg 'An error occurred while importing powerline module.' + echomsg 'This could be caused by invalid sys.path setting,' + echomsg 'or by an incompatible Python version (powerline requires' + echomsg 'Python 2.6, 2.7 or 3.2 and later to work). Please consult' + echomsg 'the troubleshooting section in the documentation for' + echomsg 'possible solutions.' + if s:pycmd is# 'py' && has('python3') + echomsg 'If powerline on your system is installed for python 3 only you' + echomsg 'should set g:powerline_pycmd to "py3" to make it load correctly.' + endif + echohl None + call s:rcmd('def powerline_troubleshoot():') + call s:rcmd(' import sys') + call s:rcmd(' import vim') + call s:rcmd(' if sys.version_info < (2, 6):') + call s:rcmd(' print("Too old python version: " + sys.version + " (first supported is 2.6)")') + call s:rcmd(' elif sys.version_info[0] == 3 and sys.version_info[1] < 2:') + call s:rcmd(' print("Too old python 3 version: " + sys.version + " (first supported is 3.2)")') + call s:rcmd(' try:') + call s:rcmd(' import powerline') + call s:rcmd(' except ImportError:') + call s:rcmd(' print("Unable to import powerline, is it installed?")') + call s:rcmd(' else:') + call s:rcmd(' if not vim.eval(''expand("<sfile>")'').startswith("/usr/"):') + call s:rcmd(' import os') + call s:rcmd(' powerline_dir = os.path.realpath(os.path.normpath(powerline.__file__))') + call s:rcmd(' powerline_dir = os.path.dirname(powerline.__file__)') + call s:rcmd(' this_dir = os.path.realpath(os.path.normpath(vim.eval(''expand("<sfile>:p")'')))') + call s:rcmd(' this_dir = os.path.dirname(this_dir)') " powerline/bindings/vim/plugin + call s:rcmd(' this_dir = os.path.dirname(this_dir)') " powerline/bindings/vim + call s:rcmd(' this_dir = os.path.dirname(this_dir)') " powerline/bindings + call s:rcmd(' this_dir = os.path.dirname(this_dir)') " powerline + call s:rcmd(' if os.path.basename(this_dir) != "powerline":') + call s:rcmd(' print("Check your installation:")') + call s:rcmd(' print("this script is not in powerline[/bindings/vim/plugin] directory,")') + call s:rcmd(' print("neither it is installed system-wide")') + call s:rcmd(' real_powerline_dir = os.path.realpath(powerline_dir)') + call s:rcmd(' real_this_dir = os.path.realpath(this_dir)') + call s:rcmd(' this_dir_par = os.path.dirname(real_this_dir)') + call s:rcmd(' powerline_appended_path = globals().get("powerline_appended_path")') + call s:rcmd(' if powerline_appended_path is not None and this_dir_par != powerline_appended_path:') + call s:rcmd(' print("Check your installation: this script is symlinked somewhere")') + call s:rcmd(' print("where powerline is not present: {0!r} != {1!r}.".format(') + call s:rcmd(' real_this_dir, powerline_appended_path))') + call s:rcmd(' elif real_powerline_dir != real_this_dir:') + call s:rcmd(' print("It appears that you have two powerline versions installed:")') + call s:rcmd(' print("one in " + real_powerline_dir + ", other in " + real_this_dir + ".")') + call s:rcmd(' print("You should remove one of this. Check out troubleshooting section,")') + call s:rcmd(' print("it contains some information about the alternatives.")') + call s:rcmd(' try:') + call s:rcmd(' from powerline.lint import check') + call s:rcmd(' except ImportError:') + call s:rcmd(' print("Failed to import powerline.lint.check, cannot run powerline-lint")') + call s:rcmd(' else:') + call s:rcmd(' try:') + call s:rcmd(' paths = powerline_instance.get_config_paths()') + call s:rcmd(' except NameError:') + call s:rcmd(' pass') + call s:rcmd(' else:') + call s:rcmd(' from powerline.lint.markedjson.error import echoerr') + call s:rcmd(' ee = lambda *args, **kwargs: echoerr(*args, stream=sys.stdout, **kwargs)') + call s:rcmd(' check(paths=paths, echoerr=ee, require_ext="vim")') + call s:rcmd('try:') + call s:rcmd(' powerline_troubleshoot()') + call s:rcmd('finally:') + call s:rcmd(' del powerline_troubleshoot') + execute s:pycmd s:pystr + unlet s:pystr + unlet s:pycmd + unlet s:pyeval + delfunction s:rcmd + finish + else + unlet s:launched + endif + unlet s:pycmd + unlet s:pyeval + delfunction s:rcmd +endtry diff --git a/powerline/bindings/wm/__init__.py b/powerline/bindings/wm/__init__.py new file mode 100644 index 0000000..d2c6f30 --- /dev/null +++ b/powerline/bindings/wm/__init__.py @@ -0,0 +1,72 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import re + +from powerline.theme import requires_segment_info +from powerline.lib.shell import run_cmd +from powerline.bindings.wm.awesome import AwesomeThread + + +DEFAULT_UPDATE_INTERVAL = 0.5 + + +conn = None + + +def i3_subscribe(conn, event, callback): + '''Subscribe to i3 workspace event + + :param conn: + Connection returned by :py:func:`get_i3_connection`. + :param str event: + Event to subscribe to, e.g. ``'workspace'``. + :param func callback: + Function to run on event. + ''' + conn.on(event, callback) + + from threading import Thread + + class I3Thread(Thread): + daemon = True + + def __init__(self, conn): + super(I3Thread, self).__init__() + self.__conn = conn + + def run(self): + self.__conn.main() + + thread = I3Thread(conn=conn) + + thread.start() + + +def get_i3_connection(): + '''Return a valid, cached i3 Connection instance + ''' + global conn + if not conn: + import i3ipc + conn = i3ipc.Connection() + return conn + + +XRANDR_OUTPUT_RE = re.compile(r'^(?P<name>[0-9A-Za-z-]+) connected(?P<primary> primary)? (?P<width>\d+)x(?P<height>\d+)\+(?P<x>\d+)\+(?P<y>\d+)', re.MULTILINE) + + +def get_connected_xrandr_outputs(pl): + '''Iterate over xrandr outputs + + Outputs are represented by a dictionary with ``name``, ``width``, + ``height``, ``primary``, ``x`` and ``y`` keys. + ''' + return (match.groupdict() for match in XRANDR_OUTPUT_RE.finditer( + run_cmd(pl, ['xrandr', '-q']) + )) + + +wm_threads = { + 'awesome': AwesomeThread, +} diff --git a/powerline/bindings/wm/awesome.py b/powerline/bindings/wm/awesome.py new file mode 100644 index 0000000..b6e07f2 --- /dev/null +++ b/powerline/bindings/wm/awesome.py @@ -0,0 +1,59 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys + +from threading import Thread, Event +from time import sleep +from subprocess import Popen, PIPE + +from powerline import Powerline +from powerline.lib.monotonic import monotonic + + +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') + + +def run(thread_shutdown_event=None, pl_shutdown_event=None, pl_config_loader=None, + interval=None): + powerline = Powerline( + 'wm', + renderer_module='pango_markup', + shutdown_event=pl_shutdown_event, + config_loader=pl_config_loader, + ) + powerline.update_renderer() + + if not thread_shutdown_event: + thread_shutdown_event = powerline.shutdown_event + + while not thread_shutdown_event.is_set(): + # powerline.update_interval may change over time + used_interval = interval or powerline.update_interval + start_time = monotonic() + s = powerline.render(side='right') + request = 'powerline_widget:set_markup(\'' + s.translate({'\'': '\\\'', '\\': '\\\\'}) + '\')\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) + thread_shutdown_event.wait(max(used_interval - (monotonic() - start_time), 0.1)) + + +class AwesomeThread(Thread): + __slots__ = ('powerline_shutdown_event',) + + def __init__(self, **kwargs): + super(AwesomeThread, self).__init__() + self.powerline_run_kwargs = kwargs + + def run(self): + run(**self.powerline_run_kwargs) diff --git a/powerline/bindings/zsh/__init__.py b/powerline/bindings/zsh/__init__.py new file mode 100644 index 0000000..44f5c69 --- /dev/null +++ b/powerline/bindings/zsh/__init__.py @@ -0,0 +1,225 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import atexit + +from weakref import WeakValueDictionary, ref + +import zsh + +from powerline.shell import ShellPowerline +from powerline.lib.overrides import parsedotval, parse_override_var +from powerline.lib.unicode import unicode, u +from powerline.lib.encoding import (get_preferred_output_encoding, + get_preferred_environment_encoding) +from powerline.lib.dict import mergeargs + + +used_powerlines = WeakValueDictionary() + + +def shutdown(): + for powerline in tuple(used_powerlines.values()): + powerline.shutdown() + + +def get_var_config(var): + try: + val = zsh.getvalue(var) + if isinstance(val, dict): + return mergeargs([parsedotval((u(k), u(v))) for k, v in val.items()]) + elif isinstance(val, (unicode, str, bytes)): + return mergeargs(parse_override_var(u(val))) + else: + return None + except: + return None + + +class Args(object): + __slots__ = ('last_pipe_status', 'last_exit_code') + ext = ['shell'] + renderer_module = '.zsh' + + @property + def config_override(self): + return get_var_config('POWERLINE_CONFIG_OVERRIDES') + + @property + def theme_override(self): + return get_var_config('POWERLINE_THEME_OVERRIDES') + + @property + def config_path(self): + try: + ret = zsh.getvalue('POWERLINE_CONFIG_PATHS') + except IndexError: + return None + else: + if isinstance(ret, (unicode, str, bytes)): + return [ + path + for path in ret.split((b':' if isinstance(ret, bytes) else ':')) + if path + ] + else: + return ret + + @property + def jobnum(self): + return zsh.getvalue('_POWERLINE_JOBNUM') + + +def string(s): + if type(s) is bytes: + return s.decode(get_preferred_environment_encoding(), '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 + + @staticmethod + def __contains__(key): + try: + zsh.getvalue(key) + return True + except IndexError: + return False + + +environ = Environment() + + +if hasattr(zsh, 'expand') and zsh.expand('${:-}') == '': + zsh_expand = zsh.expand +else: + def zsh_expand(s): + zsh.eval('local _POWERLINE_REPLY="' + s + '"') + ret = zsh.getvalue('_POWERLINE_REPLY') + zsh.setvalue('_POWERLINE_REPLY', None) + return ret + + +class ZshPowerline(ShellPowerline): + def init(self, **kwargs): + super(ZshPowerline, self).init(Args(), **kwargs) + + def precmd(self): + self.args.last_pipe_status = zsh.pipestatus() + self.args.last_exit_code = zsh.last_exit_code() + + def do_setup(self, zsh_globals): + set_prompt(self, 'PS1', 'left', None, above=True) + set_prompt(self, 'RPS1', 'right', None) + set_prompt(self, 'PS2', 'left', 'continuation') + set_prompt(self, 'RPS2', 'right', 'continuation') + set_prompt(self, 'PS3', 'left', 'select') + used_powerlines[id(self)] = self + zsh_globals['_powerline'] = self + + +class Prompt(object): + __slots__ = ('powerline', 'side', 'savedpsvar', 'savedps', 'args', 'theme', 'above', '__weakref__') + + def __init__(self, powerline, side, theme, savedpsvar=None, savedps=None, above=False): + self.powerline = powerline + self.side = side + self.above = above + self.savedpsvar = savedpsvar + self.savedps = savedps + self.args = powerline.args + self.theme = theme + + def __str__(self): + parser_state = u(zsh_expand('${(%):-%_}')) + shortened_path = u(zsh_expand('${(%):-%~}')) + try: + mode = u(zsh.getvalue('_POWERLINE_MODE')) + except IndexError: + mode = None + try: + default_mode = u(zsh.getvalue('_POWERLINE_DEFAULT_MODE')) + except IndexError: + default_mode = None + segment_info = { + 'args': self.args, + 'environ': environ, + 'client_id': 1, + 'local_theme': self.theme, + 'parser_state': parser_state, + 'shortened_path': shortened_path, + 'mode': mode, + 'default_mode': default_mode, + } + try: + zle_rprompt_indent = zsh.getvalue('ZLE_RPROMPT_INDENT') + except IndexError: + zle_rprompt_indent = 1 + r = '' + if self.above: + for line in self.powerline.render_above_lines( + width=zsh.columns() - zle_rprompt_indent, + segment_info=segment_info, + ): + if line: + r += line + '\n' + r += self.powerline.render( + width=zsh.columns(), + side=self.side, + segment_info=segment_info, + mode=mode, + ) + if type(r) is not str: + if type(r) is bytes: + return r.decode(get_preferred_output_encoding(), 'replace') + else: + return r.encode(get_preferred_output_encoding(), 'replace') + return r + + def __del__(self): + if self.savedps: + zsh.setvalue(self.savedpsvar, self.savedps) + self.powerline.shutdown() + + +def set_prompt(powerline, psvar, side, theme, above=False): + try: + savedps = zsh.getvalue(psvar) + except IndexError: + savedps = None + zpyvar = 'ZPYTHON_POWERLINE_' + psvar + prompt = Prompt(powerline, side, theme, psvar, savedps, above) + zsh.setvalue(zpyvar, None) + zsh.set_special_string(zpyvar, prompt) + zsh.setvalue(psvar, '${' + zpyvar + '}') + return ref(prompt) + + +def reload(): + for powerline in tuple(used_powerlines.values()): + powerline.reload() + + +def reload_config(): + for powerline in used_powerlines.values(): + powerline.create_renderer(load_main=True, load_colors=True, load_colorscheme=True, load_theme=True) + + +def setup(zsh_globals): + powerline = ZshPowerline() + powerline.setup(zsh_globals) + atexit.register(shutdown) diff --git a/powerline/bindings/zsh/powerline.zsh b/powerline/bindings/zsh/powerline.zsh new file mode 100644 index 0000000..ff46cb0 --- /dev/null +++ b/powerline/bindings/zsh/powerline.zsh @@ -0,0 +1,216 @@ +local _POWERLINE_SOURCED="$0:A" + +_powerline_columns_fallback() { + if which stty &>/dev/null ; then + local cols="$(stty size 2>/dev/null)" + if ! test -z "$cols" ; then + echo "${cols#* }" + return 0 + fi + fi + echo 0 + return 0 +} + +_powerline_append_precmd_function() { + if test -z "${precmd_functions[(re)$1]}" ; then + precmd_functions+=( $1 ) + fi +} + +integer -g _POWERLINE_JOBNUM=0 + +_powerline_tmux_pane() { + local -x TMUX="$_POWERLINE_TMUX" + echo "${TMUX_PANE:-`tmux display -p "#D"`}" | tr -d ' %' +} + +_powerline_tmux_pane() { + local -x TMUX="$_POWERLINE_TMUX" + echo "${TMUX_PANE:-`tmux display -p "#D"`}" | tr -d ' %' +} + +_powerline_init_tmux_support() { + emulate -L zsh + if test -n "$TMUX" && tmux refresh -S &>/dev/null ; then + # TMUX variable may be unset to create new tmux session inside this one + typeset -g _POWERLINE_TMUX="$TMUX" + + function -g _powerline_tmux_setenv() { + emulate -L zsh + local -x TMUX="$_POWERLINE_TMUX" + tmux setenv -g TMUX_"$1"_$(_powerline_tmux_pane) "$2" + tmux refresh -S + } + + function -g _powerline_tmux_set_pwd() { + _powerline_tmux_setenv PWD "$PWD" + } + + function -g _powerline_tmux_set_columns() { + _powerline_tmux_setenv COLUMNS "${COLUMNS:-$(_powerline_columns_fallback)}" + } + + chpwd_functions+=( _powerline_tmux_set_pwd ) + trap '_powerline_tmux_set_columns' SIGWINCH + _powerline_tmux_set_columns + _powerline_tmux_set_pwd + fi +} + +_powerline_init_modes_support() { + emulate -L zsh + + test -z "$ZSH_VERSION" && return 0 + + local -a vs + vs=( ${(s:.:)ZSH_VERSION} ) + + # Mode support requires >=zsh-4.3.11 + if (( vs[1] < 4 || (vs[1] == 4 && (vs[2] < 3 || (vs[2] == 3 && vs[3] < 11))) )) ; then + return 0 + fi + + function -g _powerline_get_main_keymap_name() { + REPLY="${${(Q)${${(z)${"$(bindkey -lL main)"}}[3]}}:-.safe}" + } + + function -g _powerline_set_true_keymap_name() { + typeset -g _POWERLINE_MODE="${1}" + local plm_bk="$(bindkey -lL ${_POWERLINE_MODE})" + if [[ $plm_bk = 'bindkey -A'* ]] ; then + _powerline_set_true_keymap_name ${(Q)${${(z)plm_bk}[3]}} + fi + } + + function -g _powerline_zle_keymap_select() { + _powerline_set_true_keymap_name $KEYMAP + zle reset-prompt + test -z "$_POWERLINE_SAVE_WIDGET" || zle $_POWERLINE_SAVE_WIDGET + } + + function -g _powerline_set_main_keymap_name() { + local REPLY + _powerline_get_main_keymap_name + _powerline_set_true_keymap_name "$REPLY" + } + + _powerline_add_widget zle-keymap-select _powerline_zle_keymap_select + _powerline_set_main_keymap_name + + if [[ "$_POWERLINE_MODE" != vi* ]] ; then + typeset -g _POWERLINE_DEFAULT_MODE="$_POWERLINE_MODE" + fi + + _powerline_append_precmd_function _powerline_set_main_keymap_name +} + +_powerline_set_jobnum() { + # If you are wondering why I am not using the same code as I use for bash + # ($(jobs|wc -l)): consider the following test: + # echo abc | less + # <C-z> + # . This way jobs will print + # [1] + done echo abc | + # suspended less -M + # ([ is in first column). You see: any line counting thingie will return + # wrong number of jobs. You need to filter the lines first. Or not use + # jobs built-in at all. + integer -g _POWERLINE_JOBNUM=${(%):-%j} +} + +_powerline_update_counter() { + zpython '_powerline.precmd()' +} + +_powerline_setup_prompt() { + emulate -L zsh + + _powerline_append_precmd_function _powerline_set_jobnum + + typeset -g VIRTUAL_ENV_DISABLE_PROMPT=1 + + if test -z "${POWERLINE_NO_ZSH_ZPYTHON}" && { zmodload libzpython || zmodload zsh/zpython } &>/dev/null ; then + _powerline_append_precmd_function _powerline_update_counter + zpython 'from powerline.bindings.zsh import setup as _powerline_setup' + zpython '_powerline_setup(globals())' + zpython 'del _powerline_setup' + powerline-reload() { + zpython 'from powerline.bindings.zsh import reload as _powerline_reload' + zpython '_powerline_reload()' + zpython 'del _powerline_reload' + } + powerline-reload-config() { + zpython 'from powerline.bindings.zsh import reload_config as _powerline_reload_config' + zpython '_powerline_reload_config()' + zpython 'del _powerline_reload_config' + } + else + if test -z "${POWERLINE_COMMAND}" ; then + typeset -g POWERLINE_COMMAND="$($POWERLINE_CONFIG_COMMAND shell command)" + fi + + local add_args='-r .zsh' + add_args+=' --last-exit-code=$?' + add_args+=' --last-pipe-status="$pipestatus"' + add_args+=' --renderer-arg="client_id=$$"' + add_args+=' --renderer-arg="shortened_path=${(%):-%~}"' + add_args+=' --jobnum=$_POWERLINE_JOBNUM' + add_args+=' --renderer-arg="mode=$_POWERLINE_MODE"' + add_args+=' --renderer-arg="default_mode=$_POWERLINE_DEFAULT_MODE"' + local new_args_2=' --renderer-arg="parser_state=${(%%):-%_}"' + new_args_2+=' --renderer-arg="local_theme=continuation"' + local add_args_3=$add_args' --renderer-arg="local_theme=select"' + local add_args_2=$add_args$new_args_2 + add_args+=' --width=$(( ${COLUMNS:-$(_powerline_columns_fallback)} - ${ZLE_RPROMPT_INDENT:-1} ))' + local add_args_r2=$add_args$new_args_2 + typeset -g PS1='$("$POWERLINE_COMMAND" $=POWERLINE_COMMAND_ARGS shell aboveleft '$add_args')' + typeset -g RPS1='$("$POWERLINE_COMMAND" $=POWERLINE_COMMAND_ARGS shell right '$add_args')' + typeset -g PS2='$("$POWERLINE_COMMAND" $=POWERLINE_COMMAND_ARGS shell left '$add_args_2')' + typeset -g RPS2='$("$POWERLINE_COMMAND" $=POWERLINE_COMMAND_ARGS shell right '$add_args_r2')' + typeset -g PS3='$("$POWERLINE_COMMAND" $=POWERLINE_COMMAND_ARGS shell left '$add_args_3')' + fi +} + +_powerline_add_widget() { + local widget="$1" + local function="$2" + local old_widget_command="$(zle -l -L $widget)" + if [[ "$old_widget_command" = "zle -N $widget $function" ]] ; then + return 0 + elif [[ -z "$old_widget_command" ]] ; then + zle -N $widget $function + else + local save_widget="_powerline_save_$widget" + local -i i=0 + while ! test -z "$(zle -l -L $save_widget)" ; do + save_widget="${save_widget}_$i" + (( i++ )) + done + # If widget was defined with `zle -N widget` (without `function` + # argument) then this function will be handy. + eval "function $save_widget() { emulate -L zsh; $widget \$@ }" + eval "${old_widget_command/$widget/$save_widget}" + zle -N $widget $function + typeset -g _POWERLINE_SAVE_WIDGET="$save_widget" + fi +} + +if test -z "${POWERLINE_CONFIG_COMMAND}" ; then + if which powerline-config >/dev/null 2>/dev/null ; then + typeset -g POWERLINE_CONFIG_COMMAND=powerline-config + else + typeset -g POWERLINE_CONFIG_COMMAND="${_POWERLINE_SOURCED:h:h:h:h}/scripts/powerline-config" + fi +fi + +setopt promptpercent +setopt promptsubst + +if "${POWERLINE_CONFIG_COMMAND}" shell --shell=zsh uses prompt ; then + _powerline_setup_prompt + _powerline_init_modes_support +fi +if "${POWERLINE_CONFIG_COMMAND}" shell --shell=zsh uses tmux ; then + _powerline_init_tmux_support +fi diff --git a/powerline/colorscheme.py b/powerline/colorscheme.py new file mode 100644 index 0000000..66416b5 --- /dev/null +++ b/powerline/colorscheme.py @@ -0,0 +1,147 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from copy import copy + +from powerline.lib.unicode import unicode + + +DEFAULT_MODE_KEY = None +ATTR_BOLD = 1 +ATTR_ITALIC = 2 +ATTR_UNDERLINE = 4 + + +def get_attrs_flag(attrs): + '''Convert an attribute array to a renderer flag.''' + attrs_flag = 0 + if 'bold' in attrs: + attrs_flag |= ATTR_BOLD + if 'italic' in attrs: + attrs_flag |= ATTR_ITALIC + if 'underline' in attrs: + attrs_flag |= ATTR_UNDERLINE + return attrs_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))] + + +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_group_props(self, mode, trans, group, translate_colors=True): + if isinstance(group, (str, unicode)): + try: + group_props = trans['groups'][group] + except KeyError: + try: + group_props = self.groups[group] + except KeyError: + return None + else: + return self.get_group_props(mode, trans, group_props, True) + else: + return self.get_group_props(mode, trans, group_props, False) + else: + if translate_colors: + group_props = copy(group) + try: + ctrans = trans['colors'] + except KeyError: + pass + else: + for key in ('fg', 'bg'): + try: + group_props[key] = ctrans[group_props[key]] + except KeyError: + pass + return group_props + else: + return group + + def get_highlighting(self, groups, mode, gradient_level=None): + trans = self.translations.get(mode, {}) + for group in groups: + group_props = self.get_group_props(mode, trans, group) + if group_props: + break + else: + raise KeyError('Highlighting groups not found in colorscheme: ' + ', '.join(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']), + 'attrs': get_attrs_flag(group_props.get('attrs', [])), + } + + +# 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 +) diff --git a/powerline/commands/__init__.py b/powerline/commands/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/powerline/commands/__init__.py diff --git a/powerline/commands/config.py b/powerline/commands/config.py new file mode 100644 index 0000000..e9ca5f9 --- /dev/null +++ b/powerline/commands/config.py @@ -0,0 +1,109 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (division, absolute_import, print_function) + +import argparse + +import powerline.bindings.config as config + + +class StrFunction(object): + def __init__(self, function, name=None): + self.name = name or function.__name__ + self.function = function + + def __call__(self, *args, **kwargs): + self.function(*args, **kwargs) + + def __str__(self): + return self.name + + +TMUX_ACTIONS = { + 'source': StrFunction(config.source_tmux_files, 'source'), + 'setenv': StrFunction(config.init_tmux_environment, 'setenv'), + 'setup': StrFunction(config.tmux_setup, 'setup'), +} + + +SHELL_ACTIONS = { + 'command': StrFunction(config.shell_command, 'command'), + 'uses': StrFunction(config.uses), +} + + +class ConfigArgParser(argparse.ArgumentParser): + def parse_args(self, *args, **kwargs): + ret = super(ConfigArgParser, self).parse_args(*args, **kwargs) + if not hasattr(ret, 'function'): + # In Python-3* `powerline-config` (without arguments) raises + # AttributeError. I have not found any standard way to display same + # error message as in Python-2*. + self.error('too few arguments') + return ret + + +def get_argparser(ArgumentParser=ConfigArgParser): + parser = ArgumentParser(description='Script used to obtain powerline configuration.') + parser.add_argument( + '-p', '--config-path', action='append', metavar='PATH', + help='Path to configuration directory. If it is present ' + 'then configuration files will only be sought in the provided path. ' + 'May be provided multiple times to search in a list of directories.' + ) + subparsers = parser.add_subparsers() + tmux_parser = subparsers.add_parser('tmux', help='Tmux-specific commands') + tmux_parser.add_argument( + 'function', + choices=tuple(TMUX_ACTIONS.values()), + metavar='ACTION', + type=(lambda v: TMUX_ACTIONS.get(v)), + help='If action is `source\' then version-specific tmux configuration ' + 'files are sourced, if it is `setenv\' then special ' + '(prefixed with `_POWERLINE\') tmux global environment variables ' + 'are filled with data from powerline configuration. ' + 'Action `setup\' is just doing `setenv\' then `source\'.' + ) + tpg = tmux_parser.add_mutually_exclusive_group() + tpg.add_argument( + '-s', '--source', action='store_true', default=None, + help='When using `setup\': always use configuration file sourcing. ' + 'By default this is determined automatically based on tmux ' + 'version: this is the default for tmux 1.8 and below.', + ) + tpg.add_argument( + '-n', '--no-source', action='store_false', dest='source', default=None, + help='When using `setup\': in place of sourcing directly execute ' + 'configuration files. That is, read each needed ' + 'powerline-specific configuration file, substitute ' + '`$_POWERLINE_…\' variables with appropriate values and run ' + '`tmux config line\'. This is the default behaviour for ' + 'tmux 1.9 and above.' + ) + + shell_parser = subparsers.add_parser('shell', help='Shell-specific commands') + shell_parser.add_argument( + 'function', + choices=tuple(SHELL_ACTIONS.values()), + type=(lambda v: SHELL_ACTIONS.get(v)), + metavar='ACTION', + help='If action is `command\' then preferred powerline command is ' + 'output, if it is `uses\' then powerline-config script will exit ' + 'with 1 if specified component is disabled and 0 otherwise.', + ) + shell_parser.add_argument( + 'component', + nargs='?', + choices=('tmux', 'prompt'), + metavar='COMPONENT', + help='Only applicable for `uses\' subcommand: makes `powerline-config\' ' + 'exit with 0 if specific component is enabled and with 1 otherwise. ' + '`tmux\' component stands for tmux bindings ' + '(e.g. those that notify tmux about current directory changes), ' + '`prompt\' component stands for shell prompt.' + ) + shell_parser.add_argument( + '-s', '--shell', + metavar='SHELL', + help='Shell for which query is run', + ) + return parser diff --git a/powerline/commands/daemon.py b/powerline/commands/daemon.py new file mode 100644 index 0000000..7e8c8ab --- /dev/null +++ b/powerline/commands/daemon.py @@ -0,0 +1,24 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (division, absolute_import, print_function) + +import argparse + + +def get_argparser(ArgumentParser=argparse.ArgumentParser): + parser = ArgumentParser(description='Daemon that improves powerline performance.') + parser.add_argument( + '--quiet', '-q', action='store_true', + help='Without other options: do not complain about already running ' + 'powerline-daemon instance. ' + 'Will still exit with 1. ' + 'With `--kill\' and `--replace\': do not show any messages. ' + 'With `--foreground\': ignored. ' + 'Does not silence exceptions in any case.' + ) + parser.add_argument('--socket', '-s', help='Specify socket which will be used for connecting to daemon.') + exclusive_group = parser.add_mutually_exclusive_group() + exclusive_group.add_argument('--kill', '-k', action='store_true', help='Kill an already running instance.') + replace_group = exclusive_group.add_argument_group() + replace_group.add_argument('--foreground', '-f', action='store_true', help='Run in the foreground (don’t daemonize).') + replace_group.add_argument('--replace', '-r', action='store_true', help='Replace an already running instance.') + return parser diff --git a/powerline/commands/lemonbar.py b/powerline/commands/lemonbar.py new file mode 100644 index 0000000..547c52c --- /dev/null +++ b/powerline/commands/lemonbar.py @@ -0,0 +1,35 @@ +# vim:fileencoding=utf-8:noet +# WARNING: using unicode_literals causes errors in argparse +from __future__ import (division, absolute_import, print_function) + +import argparse + + +def get_argparser(ArgumentParser=argparse.ArgumentParser): + parser = ArgumentParser( + description='Powerline BAR bindings.' + ) + parser.add_argument( + '--i3', action='store_true', + help='Subscribe for i3 events.' + ) + parser.add_argument( + '--height', default='', + metavar='PIXELS', help='Bar height.' + ) + parser.add_argument( + '--interval', '-i', + type=float, default=0.5, + metavar='SECONDS', help='Refresh interval.' + ) + parser.add_argument( + '--bar-command', '-C', + default='lemonbar', + metavar='CMD', help='Name of the lemonbar executable to use.' + ) + parser.add_argument( + 'args', nargs=argparse.REMAINDER, + help='Extra arguments for lemonbar. Should be preceded with ``--`` ' + 'argument in order not to be confused with script own arguments.' + ) + return parser diff --git a/powerline/commands/lint.py b/powerline/commands/lint.py new file mode 100755 index 0000000..8961a65 --- /dev/null +++ b/powerline/commands/lint.py @@ -0,0 +1,21 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (division, absolute_import, print_function) + +import argparse + + +def get_argparser(ArgumentParser=argparse.ArgumentParser): + parser = ArgumentParser(description='Powerline configuration checker.') + parser.add_argument( + '-p', '--config-path', action='append', metavar='PATH', + help='Paths where configuration should be checked, in order. You must ' + 'supply all paths necessary for powerline to work, ' + 'checking partial (e.g. only user overrides) configuration ' + 'is not supported.' + ) + parser.add_argument( + '-d', '--debug', action='store_const', const=True, + help='Display additional information. Used for debugging ' + '`powerline-lint\' itself, not for debugging configuration.' + ) + return parser diff --git a/powerline/commands/main.py b/powerline/commands/main.py new file mode 100644 index 0000000..373225f --- /dev/null +++ b/powerline/commands/main.py @@ -0,0 +1,190 @@ +# vim:fileencoding=utf-8:noet +# WARNING: using unicode_literals causes errors in argparse +from __future__ import (division, absolute_import, print_function) + +import argparse +import sys + +from itertools import chain + +from powerline.lib.overrides import parsedotval, parse_override_var +from powerline.lib.dict import mergeargs +from powerline.lib.encoding import get_preferred_arguments_encoding +from powerline.lib.unicode import u, unicode +from powerline.bindings.wm import wm_threads + + +if sys.version_info < (3,): + encoding = get_preferred_arguments_encoding() + + def arg_to_unicode(s): + return unicode(s, encoding, 'replace') if not isinstance(s, unicode) else s # NOQA +else: + def arg_to_unicode(s): + return s + + +def finish_args(parser, environ, args, is_daemon=False): + '''Do some final transformations + + Transforms ``*_override`` arguments into dictionaries, adding overrides from + environment variables. Transforms ``renderer_arg`` argument into dictionary + as well, but only if it is true. + + :param dict environ: + Environment from which additional overrides should be taken from. + :param args: + Arguments object returned by + :py:meth:`argparse.ArgumentParser.parse_args`. Will be modified + in-place. + + :return: Object received as second (``args``) argument. + ''' + args.config_override = mergeargs(chain( + parse_override_var(environ.get('POWERLINE_CONFIG_OVERRIDES', '')), + (parsedotval(v) for v in args.config_override or ()), + )) + args.theme_override = mergeargs(chain( + parse_override_var(environ.get('POWERLINE_THEME_OVERRIDES', '')), + (parsedotval(v) for v in args.theme_override or ()), + )) + if args.renderer_arg: + args.renderer_arg = mergeargs((parsedotval(v) for v in args.renderer_arg), remove=True) + if 'pane_id' in args.renderer_arg: + if isinstance(args.renderer_arg['pane_id'], (bytes, unicode)): + try: + args.renderer_arg['pane_id'] = int(args.renderer_arg['pane_id'].lstrip(' %')) + except ValueError: + pass + if 'client_id' not in args.renderer_arg: + args.renderer_arg['client_id'] = args.renderer_arg['pane_id'] + args.config_path = ( + [path for path in environ.get('POWERLINE_CONFIG_PATHS', '').split(':') if path] + + (args.config_path or []) + ) + if args.ext[0].startswith('wm.'): + if not is_daemon: + parser.error('WM bindings must be used with daemon only') + elif args.ext[0][3:] not in wm_threads: + parser.error('WM binding not found') + elif not args.side: + parser.error('expected one argument') + return args + + +def int_or_sig(s): + if s.startswith('sig'): + return u(s) + else: + return int(s) + + +def get_argparser(ArgumentParser=argparse.ArgumentParser): + parser = ArgumentParser(description='Powerline prompt and statusline script.') + parser.add_argument( + 'ext', nargs=1, + help='Extension: application for which powerline command is launched ' + '(usually `shell\' or `tmux\'). Also supports `wm.\' extensions: ' + + ', '.join(('`wm.' + key + '\'' for key in wm_threads.keys())) + '.' + ) + parser.add_argument( + 'side', nargs='?', choices=('left', 'right', 'above', 'aboveleft'), + help='Side: `left\' and `right\' represent left and right side ' + 'respectively, `above\' emits lines that are supposed to be printed ' + 'just above the prompt and `aboveleft\' is like concatenating ' + '`above\' with `left\' with the exception that only one Python ' + 'instance is used in this case. May be omitted for `wm.*\' extensions.' + ) + parser.add_argument( + '-r', '--renderer-module', metavar='MODULE', type=str, + help='Renderer module. Usually something like `.bash\' or `.zsh\' ' + '(with leading dot) which is `powerline.renderers.{ext}{MODULE}\', ' + 'may also be full module name (must contain at least one dot or ' + 'end with a dot in case it is top-level module) or ' + '`powerline.renderers\' submodule (in case there are no dots).' + ) + parser.add_argument( + '-w', '--width', type=int, + help='Maximum prompt with. Triggers truncation of some segments.' + ) + parser.add_argument( + '--last-exit-code', metavar='INT', type=int_or_sig, + help='Last exit code.' + ) + parser.add_argument( + '--last-pipe-status', metavar='LIST', default='', + type=lambda s: [int_or_sig(status) for status in s.split()], + help='Like above, but is supposed to contain space-separated array ' + 'of statuses, representing exit statuses of commands in one pipe.' + ) + parser.add_argument( + '--jobnum', metavar='INT', type=int, + help='Number of jobs.' + ) + parser.add_argument( + '-c', '--config-override', metavar='KEY.KEY=VALUE', type=arg_to_unicode, + action='append', + help='Configuration overrides for `config.json\'. Is translated to a ' + 'dictionary and merged with the dictionary obtained from actual ' + 'JSON configuration: KEY.KEY=VALUE is translated to ' + '`{"KEY": {"KEY": VALUE}}\' and then merged recursively. ' + 'VALUE may be any JSON value, values that are not ' + '`null\', `true\', `false\', start with digit, `{\', `[\' ' + 'are treated like strings. If VALUE is omitted ' + 'then corresponding key is removed.' + ) + parser.add_argument( + '-t', '--theme-override', metavar='THEME.KEY.KEY=VALUE', type=arg_to_unicode, + action='append', + help='Like above, but theme-specific. THEME should point to ' + 'an existing and used theme to have any effect, but it is fine ' + 'to use any theme here.' + ) + parser.add_argument( + '-R', '--renderer-arg', + metavar='KEY=VAL', type=arg_to_unicode, action='append', + help='Like above, but provides argument for renderer. Is supposed ' + 'to be used only by shell bindings to provide various data like ' + 'last-exit-code or last-pipe-status (they are not using ' + '`--renderer-arg\' for historical reasons: `--renderer-arg\' ' + 'was added later).' + ) + parser.add_argument( + '-p', '--config-path', action='append', metavar='PATH', + help='Path to configuration directory. If it is present then ' + 'configuration files will only be sought in the provided path. ' + 'May be provided multiple times to search in a list of directories.' + ) + parser.add_argument( + '--socket', metavar='ADDRESS', type=str, + help='Socket address to use in daemon clients. Is always UNIX domain ' + 'socket on linux and file socket on Mac OS X. Not used here, ' + 'present only for compatibility with other powerline clients. ' + 'This argument must always be the first one and be in a form ' + '`--socket ADDRESS\': no `=\' or short form allowed ' + '(in other powerline clients, not here).' + ) + return parser + + +def write_output(args, powerline, segment_info, write): + if args.renderer_arg: + segment_info.update(args.renderer_arg) + if args.side.startswith('above'): + for line in powerline.render_above_lines( + width=args.width, + segment_info=segment_info, + mode=segment_info.get('mode', None), + ): + if line: + write(line + '\n') + args.side = args.side[len('above'):] + + if args.side: + rendered = powerline.render( + width=args.width, + side=args.side, + segment_info=segment_info, + mode=segment_info.get('mode', None), + ) + write(rendered) diff --git a/powerline/config.py b/powerline/config.py new file mode 100644 index 0000000..edcf921 --- /dev/null +++ b/powerline/config.py @@ -0,0 +1,10 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os + + +POWERLINE_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +BINDINGS_DIRECTORY = os.path.join(POWERLINE_ROOT, 'powerline', 'bindings') +TMUX_CONFIG_DIRECTORY = os.path.join(BINDINGS_DIRECTORY, 'tmux') +DEFAULT_SYSTEM_CONFIG_DIR = None diff --git a/powerline/config_files/colors.json b/powerline/config_files/colors.json new file mode 100644 index 0000000..1564f18 --- /dev/null +++ b/powerline/config_files/colors.json @@ -0,0 +1,124 @@ +{ + "colors": { + "black": 16, + "white": 231, + + "green": 2, + "darkestgreen": 22, + "darkgreen": 28, + "mediumgreen": 70, + "brightgreen": 148, + + "darkestcyan": 23, + "darkcyan": 74, + "mediumcyan": 117, + "brightcyan": 159, + + "darkestblue": 24, + "darkblue": 31, + + "red": 1, + "darkestred": 52, + "darkred": 88, + "mediumred": 124, + "brightred": 160, + "brightestred": 196, + + "darkestpurple": 55, + "mediumpurple": 98, + "brightpurple": 189, + + "darkorange": 94, + "mediumorange": 166, + "brightorange": 208, + "brightestorange": 214, + + "yellow": 11, + "brightyellow": 220, + + "gray0": 233, + "gray1": 235, + "gray2": 236, + "gray3": 239, + "gray4": 240, + "gray5": 241, + "gray6": 244, + "gray7": 245, + "gray8": 247, + "gray9": 250, + "gray10": 252, + + "gray11": 234, + "gray90": 254, + + "gray70": [249, "b3b3b3"], + + "lightyellowgreen": 106, + "gold3": 178, + "orangered": 202, + + "steelblue": 67, + "darkorange3": 166, + "skyblue1": 117, + "khaki1": 228, + + "solarized:base03": [8, "002b36"], + "solarized:base02": [0, "073642"], + "solarized:base01": [10, "586e75"], + "solarized:base00": [11, "657b83"], + "solarized:base0": [12, "839496"], + "solarized:base1": [14, "93a1a1"], + "solarized:base2": [7, "eee8d5"], + "solarized:base3": [15, "fdf6e3"], + "solarized:yellow": [3, "b58900"], + "solarized:orange": [9, "cb4b16"], + "solarized:red": [1, "dc322f"], + "solarized:magenta": [5, "d33682"], + "solarized:violet": [13, "6c71c4"], + "solarized:blue": [4, "268bd2"], + "solarized:cyan": [6, "2aa198"], + "solarized:green": [2, "859900"] + }, + "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, 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, 94, 94, 94, 94, 94, 94, 94, 88, 52], + ["006000", "006000", "006000", "006000", "006000", "006000", "006000", "006000", "006000", "036000", "076000", "0a6000", "0d6000", "106000", "126000", "146000", "166000", "186000", "1a6000", "1b6000", "1d6000", "1e6000", "206000", "216000", "236000", "246000", "256000", "266000", "286000", "296000", "2a6000", "2b6000", "2c6100", "2d6100", "2f6100", "306100", "316100", "326100", "336100", "346100", "356100", "366100", "376100", "386100", "386100", "396100", "3a6100", "3b6100", "3c6100", "3d6100", "3e6100", "3f6100", "406100", "406100", "416100", "426000", "436000", "446000", "456000", "456000", "466000", "476000", "486000", "496000", "496000", "4a6000", "4b6000", "4c6000", "4d6000", "4d6000", "4e6000", "4f6000", "506000", "506000", "516000", "526000", "536000", "536000", "546000", "556000", "566000", "566000", "576000", "586000", "596000", "596000", "5a6000", "5d6000", "616000", "646000", "686000", "6b6000", "6f6000", "726000", "766000", "796000", "7d6000", "806000", "7e5500", "6f3105", "5d0001"] + ], + "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"] + ], + "white_red": [ + [231, 255, 223, 216, 209, 202, 196], + ["ffffff", "fefefe", "fdfdfd", "fdfdfd", "fcfcfc", "fbfbfb", "fafafa", "fafafa", "f9f9f9", "f8f8f8", "f7f7f7", "f7f7f7", "f6f6f6", "f5f5f5", "f4f4f4", "f4f3f4", "f3f3f3", "f2f2f2", "f1f1f1", "f0f0f0", "f0f0f0", "efefef", "eeeeee", "efecea", "f1eae4", "f2e8de", "f3e6d8", "f5e4d3", "f6e2cd", "f7e0c7", "f8dec2", "f9dcbc", "fadab6", "fad8b1", "fbd5ac", "fbd2a9", "fbcea5", "fbcaa1", "fbc79e", "fbc39a", "fbc097", "fbbc93", "fbb88f", "fbb58c", "fab188", "faad85", "faaa81", "fba67e", "fba37a", "fb9f76", "fb9c73", "fb986f", "fb946c", "fb9168", "fa8d65", "fa8961", "fa865c", "fa8256", "fb7f4f", "fb7b48", "fb7841", "fb743a", "fb7133", "fb6d2c", "fa6a23", "fa661a", "fa620e", "fa5f03", "fa5d03", "fa5b03", "fa5a03", "fa5803", "fa5703", "fa5503", "fa5303", "fa5103", "fa4f03", "fa4e03", "fa4c03", "fa4a04", "fa4804", "fa4604", "fa4404", "fa4204", "fa3f04", "fa3d04", "fa3b04", "fa3805", "fa3605", "fa3305", "fb3105", "fb2e05", "fb2a05", "fb2705", "fb2306", "fb1f06", "fb1b06", "fb1506", "fb0e06", "fa0506", "fa0007"] + ], + "dark_green_gray": [ + [70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247], + ["51b000", "52b000", "54b000", "55b002", "56b007", "57b00d", "58b011", "59af15", "5aaf18", "5caf1b", "5daf1e", "5eaf21", "5faf23", "60ae25", "61ae27", "62ae2a", "63ae2c", "64ae2e", "65ae30", "66ae31", "67ad33", "68ad35", "69ad37", "69ad38", "6aad3a", "6bad3c", "6cac3d", "6dac3f", "6eac40", "6fac42", "70ac44", "70ac45", "71ab47", "72ab48", "73ab49", "74ab4b", "75ab4c", "75ab4e", "76aa4f", "77aa51", "78aa52", "79aa53", "79aa55", "7aaa56", "7ba957", "7ca959", "7ca95a", "7da95b", "7ea95d", "7fa95e", "7fa85f", "80a861", "81a862", "81a863", "82a865", "83a766", "83a767", "84a768", "85a76a", "85a76b", "86a66c", "87a66d", "87a66f", "88a670", "89a671", "89a672", "8aa574", "8ba575", "8ba576", "8ca577", "8da579", "8da47a", "8ea47b", "8ea47c", "8fa47d", "90a47f", "90a380", "91a381", "91a382", "92a384", "93a385", "93a286", "94a287", "94a288", "95a28a", "95a18b", "96a18c", "97a18d", "97a18e", "98a190", "98a091", "99a092", "99a093", "9aa094", "9aa096", "9b9f97", "9b9f98", "9c9f99", "9c9f9a", "9d9e9c", "9d9e9d"] + ], + "light_green_gray": [ + [148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 187, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250], + ["a3d900", "a4d800", "a4d800", "a5d805", "a5d80d", "a6d714", "a6d719", "a6d71d", "a7d621", "a7d625", "a8d628", "a8d62b", "a8d52e", "a9d531", "a9d533", "aad536", "aad438", "aad43a", "abd43d", "abd33f", "abd341", "acd343", "acd345", "acd247", "add249", "add24b", "add14d", "aed14f", "aed151", "aed152", "afd054", "afd056", "afd058", "b0d059", "b0cf5b", "b0cf5d", "b1cf5e", "b1ce60", "b1ce62", "b1ce63", "b2ce65", "b2cd67", "b2cd68", "b3cd6a", "b3cc6b", "b3cc6d", "b3cc6e", "b4cc70", "b4cb71", "b4cb73", "b4cb75", "b5ca76", "b5ca78", "b5ca79", "b5ca7a", "b6c97c", "b6c97d", "b6c97f", "b6c880", "b6c882", "b7c883", "b7c885", "b7c786", "b7c788", "b7c789", "b8c68a", "b8c68c", "b8c68d", "b8c68f", "b8c590", "b9c591", "b9c593", "b9c494", "b9c496", "b9c497", "b9c498", "bac39a", "bac39b", "bac39d", "bac29e", "bac29f", "bac2a1", "bac2a2", "bac1a4", "bbc1a5", "bbc1a6", "bbc0a8", "bbc0a9", "bbc0aa", "bbc0ac", "bbbfad", "bbbfae", "bbbfb0", "bbbeb1", "bcbeb3", "bcbeb4", "bcbdb5", "bcbdb7", "bcbdb8", "bcbdb9", "bcbcbb"] + ] + } +} diff --git a/powerline/config_files/colorschemes/default.json b/powerline/config_files/colorschemes/default.json new file mode 100644 index 0000000..767e72e --- /dev/null +++ b/powerline/config_files/colorschemes/default.json @@ -0,0 +1,57 @@ +{ + "name": "Default", + "groups": { + "information:additional": { "fg": "gray9", "bg": "gray4", "attrs": [] }, + "information:regular": { "fg": "gray10", "bg": "gray4", "attrs": ["bold"] }, + "information:highlighted": { "fg": "white", "bg": "gray4", "attrs": [] }, + "information:priority": { "fg": "brightyellow", "bg": "mediumorange", "attrs": [] }, + "warning:regular": { "fg": "white", "bg": "brightred", "attrs": ["bold"] }, + "critical:failure": { "fg": "white", "bg": "darkestred", "attrs": [] }, + "critical:success": { "fg": "white", "bg": "darkestgreen", "attrs": [] }, + "background": { "fg": "white", "bg": "gray0", "attrs": [] }, + "background:divider": { "fg": "gray5", "bg": "gray0", "attrs": [] }, + "session": { "fg": "black", "bg": "gray10", "attrs": ["bold"] }, + "date": { "fg": "gray8", "bg": "gray2", "attrs": [] }, + "time": { "fg": "gray10", "bg": "gray2", "attrs": ["bold"] }, + "time:divider": { "fg": "gray5", "bg": "gray2", "attrs": [] }, + "email_alert": "warning:regular", + "email_alert_gradient": { "fg": "white", "bg": "yellow_orange_red", "attrs": ["bold"] }, + "hostname": { "fg": "black", "bg": "gray10", "attrs": ["bold"] }, + "weather": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "weather_temp_gradient": { "fg": "blue_red", "bg": "gray0", "attrs": [] }, + "weather_condition_hot": { "fg": "khaki1", "bg": "gray0", "attrs": [] }, + "weather_condition_snowy": { "fg": "skyblue1", "bg": "gray0", "attrs": [] }, + "weather_condition_rainy": { "fg": "skyblue1", "bg": "gray0", "attrs": [] }, + "uptime": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "external_ip": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "internal_ip": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "network_load": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "network_load_gradient": { "fg": "green_yellow_orange_red", "bg": "gray0", "attrs": [] }, + "network_load_sent_gradient": "network_load_gradient", + "network_load_recv_gradient": "network_load_gradient", + "network_load:divider": "background:divider", + "system_load": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "system_load_gradient": { "fg": "green_yellow_orange_red", "bg": "gray0", "attrs": [] }, + "environment": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "cpu_load_percent": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "cpu_load_percent_gradient": { "fg": "green_yellow_orange_red", "bg": "gray0", "attrs": [] }, + "battery": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "battery_gradient": { "fg": "white_red", "bg": "gray0", "attrs": [] }, + "battery_full": { "fg": "red", "bg": "gray0", "attrs": [] }, + "battery_empty": { "fg": "white", "bg": "gray0", "attrs": [] }, + "player": { "fg": "gray10", "bg": "black", "attrs": [] }, + "user": { "fg": "white", "bg": "darkblue", "attrs": ["bold"] }, + "branch": { "fg": "gray9", "bg": "gray2", "attrs": [] }, + "branch_dirty": { "fg": "brightyellow", "bg": "gray2", "attrs": [] }, + "branch_clean": { "fg": "gray9", "bg": "gray2", "attrs": [] }, + "branch:divider": { "fg": "gray7", "bg": "gray2", "attrs": [] }, + "stash": "branch_dirty", + "stash:divider": "branch:divider", + "cwd": "information:additional", + "cwd:current_folder": "information:regular", + "cwd:divider": { "fg": "gray7", "bg": "gray4", "attrs": [] }, + "virtualenv": { "fg": "white", "bg": "darkcyan", "attrs": [] }, + "attached_clients": { "fg": "gray8", "bg": "gray0", "attrs": [] }, + "workspace": "information:regular" + } +} diff --git a/powerline/config_files/colorschemes/ipython/__main__.json b/powerline/config_files/colorschemes/ipython/__main__.json new file mode 100644 index 0000000..982ea35 --- /dev/null +++ b/powerline/config_files/colorschemes/ipython/__main__.json @@ -0,0 +1,6 @@ +{ + "groups": { + "prompt": "information:additional", + "prompt_count": "information:highlighted" + } +} diff --git a/powerline/config_files/colorschemes/pdb/__main__.json b/powerline/config_files/colorschemes/pdb/__main__.json new file mode 100644 index 0000000..01a51fe --- /dev/null +++ b/powerline/config_files/colorschemes/pdb/__main__.json @@ -0,0 +1,8 @@ +{ + "groups": { + "current_code_name": "information:additional", + "current_context": "current_code_name", + "current_line": "information:regular", + "current_file": "information:regular" + } +} diff --git a/powerline/config_files/colorschemes/pdb/default.json b/powerline/config_files/colorschemes/pdb/default.json new file mode 100644 index 0000000..b97acf7 --- /dev/null +++ b/powerline/config_files/colorschemes/pdb/default.json @@ -0,0 +1,5 @@ +{ + "groups": { + "stack_depth": { "fg": "gray1", "bg": "gray10", "attrs": ["bold"] } + } +} diff --git a/powerline/config_files/colorschemes/pdb/solarized.json b/powerline/config_files/colorschemes/pdb/solarized.json new file mode 100644 index 0000000..2e1c787 --- /dev/null +++ b/powerline/config_files/colorschemes/pdb/solarized.json @@ -0,0 +1,5 @@ +{ + "groups": { + "stack_depth": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] } + } +} diff --git a/powerline/config_files/colorschemes/shell/__main__.json b/powerline/config_files/colorschemes/shell/__main__.json new file mode 100644 index 0000000..6e3856f --- /dev/null +++ b/powerline/config_files/colorschemes/shell/__main__.json @@ -0,0 +1,10 @@ +{ + "groups": { + "continuation": "cwd", + "continuation:current": "cwd:current_folder", + "exit_fail": "critical:failure", + "exit_success": "critical:success", + "jobnum": "information:priority", + "superuser": "warning:regular" + } +} diff --git a/powerline/config_files/colorschemes/shell/default.json b/powerline/config_files/colorschemes/shell/default.json new file mode 100644 index 0000000..1126feb --- /dev/null +++ b/powerline/config_files/colorschemes/shell/default.json @@ -0,0 +1,16 @@ +{ + "name": "Default color scheme for shell prompts", + "groups": { + "hostname": { "fg": "brightyellow", "bg": "mediumorange", "attrs": [] }, + "environment": { "fg": "white", "bg": "darkestgreen", "attrs": [] }, + "mode": { "fg": "darkestgreen", "bg": "brightgreen", "attrs": ["bold"] }, + "attached_clients": { "fg": "white", "bg": "darkestgreen", "attrs": [] } + }, + "mode_translations": { + "vicmd": { + "groups": { + "mode": {"fg": "darkestcyan", "bg": "white", "attrs": ["bold"]} + } + } + } +} diff --git a/powerline/config_files/colorschemes/shell/solarized.json b/powerline/config_files/colorschemes/shell/solarized.json new file mode 100644 index 0000000..69dcab1 --- /dev/null +++ b/powerline/config_files/colorschemes/shell/solarized.json @@ -0,0 +1,13 @@ +{ + "name": "Solarized dark for shell", + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:green", "attrs": ["bold"] } + }, + "mode_translations": { + "vicmd": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] } + } + } + } +} diff --git a/powerline/config_files/colorschemes/solarized.json b/powerline/config_files/colorschemes/solarized.json new file mode 100644 index 0000000..7951f0b --- /dev/null +++ b/powerline/config_files/colorschemes/solarized.json @@ -0,0 +1,40 @@ +{ + "name": "Solarized dark", + "groups": { + "information:additional": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] }, + "information:regular": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] }, + "information:highlighted": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"]}, + "information:priority": { "fg": "solarized:base3", "bg": "solarized:yellow", "attrs": [] }, + "warning:regular": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": [] }, + "critical:failure": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": [] }, + "critical:success": { "fg": "solarized:base3", "bg": "solarized:green", "attrs": [] }, + "background": { "fg": "solarized:base3", "bg": "solarized:base02", "attrs": [] }, + "background:divider": { "fg": "solarized:base1", "bg": "solarized:base03", "attrs": [] }, + "user": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] }, + "virtualenv": { "fg": "solarized:base3", "bg": "solarized:green", "attrs": [] }, + "branch": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base02", "attrs": [] }, + "branch_clean": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "stash": "branch_dirty", + "email_alert_gradient": { "fg": "solarized:base3", "bg": "yellow_orange_red", "attrs": [] }, + "email_alert": "warning:regular", + "cwd": "information:additional", + "cwd:current_folder": "information:regular", + "cwd:divider": { "fg": "solarized:base1", "bg": "solarized:base01", "attrs": [] }, + "network_load": { "fg": "solarized:base1", "bg": "solarized:base03", "attrs": [] }, + "network_load:divider": "network_load", + "network_load_gradient": { "fg": "green_yellow_orange_red", "bg": "solarized:base03", "attrs": [] }, + "network_load_sent_gradient": "network_load_gradient", + "network_load_recv_gradient": "network_load_gradient", + "hostname": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "environment": { "fg": "solarized:base3", "bg": "solarized:green", "attrs": [] }, + "attached_clients": { "fg": "solarized:base3", "bg": "solarized:green", "attrs": [] }, + "date": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "time": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": ["bold"] }, + "time:divider": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "system_load": { "fg": "solarized:base1", "bg": "solarized:base03", "attrs": [] }, + "weather_temp_gradient": { "fg": "blue_red", "bg": "solarized:base03", "attrs": [] }, + "weather": { "fg": "solarized:base1", "bg": "solarized:base03", "attrs": [] }, + "uptime": { "fg": "solarized:base1", "bg": "solarized:base03", "attrs": [] } + } +} diff --git a/powerline/config_files/colorschemes/tmux/default.json b/powerline/config_files/colorschemes/tmux/default.json new file mode 100644 index 0000000..8525fb0 --- /dev/null +++ b/powerline/config_files/colorschemes/tmux/default.json @@ -0,0 +1,14 @@ +{ + "groups": { + "active_window_status": {"fg": "darkblue", "bg": "gray0", "attrs": []}, + "window_status": {"fg": "gray70", "bg": "gray0", "attrs": []}, + "activity_status": {"fg": "yellow", "bg": "gray0", "attrs": []}, + "bell_status": {"fg": "red", "bg": "gray0", "attrs": []}, + "window": {"fg": "gray6", "bg": "gray0", "attrs": []}, + "window:divider": {"fg": "gray4", "bg": "gray0", "attrs": []}, + "window:current": {"fg": "mediumcyan", "bg": "darkblue", "attrs": []}, + "window_name": {"fg": "white", "bg": "darkblue", "attrs": ["bold"]}, + "session": {"fg": "black", "bg": "gray90", "attrs": ["bold"]}, + "session:prefix": {"fg": "gray90", "bg": "darkblue", "attrs": ["bold"]} + } +} diff --git a/powerline/config_files/colorschemes/tmux/solarized.json b/powerline/config_files/colorschemes/tmux/solarized.json new file mode 100644 index 0000000..20c42d3 --- /dev/null +++ b/powerline/config_files/colorschemes/tmux/solarized.json @@ -0,0 +1,14 @@ +{ + "groups": { + "active_window_status": { "fg": "solarized:blue", "bg": "solarized:base02", "attrs": [] }, + "window_status": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "activity_status": { "fg": "solarized:yellow", "bg": "solarized:base02", "attrs": [] }, + "bell_status": { "fg": "solarized:red", "bg": "solarized:base02", "attrs": [] }, + "window": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "window:divider": { "fg": "solarized:base01", "bg": "solarized:base02", "attrs": [] }, + "window:current": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "window_name": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] }, + "session": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "session:prefix": { "fg": "solarized:base01", "bg": "solarized:base3", "attrs": [] } + } +} diff --git a/powerline/config_files/colorschemes/vim/__main__.json b/powerline/config_files/colorschemes/vim/__main__.json new file mode 100644 index 0000000..4f2a817 --- /dev/null +++ b/powerline/config_files/colorschemes/vim/__main__.json @@ -0,0 +1,51 @@ +{ + "groups": { + "branch_clean": "branch", + "environment": "information:unimportant", + "file_size": "information:unimportant", + "file_format": "information:unimportant", + "file_encoding": "file_format", + "file_bom": "file_format", + "file_type": "file_format", + "branch": "information:additional", + "file_scheme": "file_name", + "file_directory": "information:additional", + "file_name_empty": "file_directory", + "line_percent": "information:additional", + "line_count": "line_current", + "position": "information:additional", + "single_tab": "line_current", + "many_tabs": "line_current", + "bufnr": "file_directory", + "winnr": "information:unimportant", + "tabnr": "file_directory", + "capslock_indicator": "paste_indicator", + + "csv:column_number": "line_current", + "csv:column_name": "line_current_symbol", + + "tab:background": "background", + "tab:divider": "background:divider", + + "tab_nc:modified_indicator": "modified_indicator", + "tab_nc:file_directory": "information:unimportant", + "tab_nc:file_name": "tab_nc:file_directory", + "tab_nc:tabnr": "tab_nc:file_directory", + + "buf_nc:file_directory": "tab_nc:file_directory", + "buf_nc:file_name": "buf_nc:file_directory", + "buf_nc:bufnr": "buf_nc:file_directory", + "buf_nc:modified_indicator": "tab_nc:modified_indicator", + + "buf_nc_mod:file_directory": "tab_nc:file_directory", + "buf_nc_mod:file_name": "buf_nc_mod:file_directory", + "buf_nc_mod:bufnr": "buf_nc_mod:file_directory", + "buf_nc_mod:modified_indicator": "tab_nc:modified_indicator", + + + "commandt:label": "file_name", + "commandt:background": "background", + "commandt:finder": "file_name", + "commandt:path": "file_directory" + } +} diff --git a/powerline/config_files/colorschemes/vim/default.json b/powerline/config_files/colorschemes/vim/default.json new file mode 100644 index 0000000..e02a160 --- /dev/null +++ b/powerline/config_files/colorschemes/vim/default.json @@ -0,0 +1,154 @@ +{ + "name": "Default color scheme", + "groups": { + "information:unimportant": { "fg": "gray8", "bg": "gray2", "attrs": [] }, + "information:additional": { "fg": "gray9", "bg": "gray4", "attrs": [] }, + "background": { "fg": "white", "bg": "gray2", "attrs": [] }, + "background:divider": { "fg": "gray6", "bg": "gray2", "attrs": [] }, + "mode": { "fg": "darkestgreen", "bg": "brightgreen", "attrs": ["bold"] }, + "visual_range": { "fg": "brightestorange", "bg": "darkorange", "attrs": ["bold"] }, + "modified_indicator": { "fg": "brightyellow", "bg": "gray4", "attrs": ["bold"] }, + "paste_indicator": { "fg": "white", "bg": "mediumorange", "attrs": ["bold"] }, + "readonly_indicator": { "fg": "brightestred", "bg": "gray4", "attrs": [] }, + "branch_dirty": { "fg": "brightyellow", "bg": "gray4", "attrs": [] }, + "branch:divider": { "fg": "gray7", "bg": "gray4", "attrs": [] }, + "file_name": { "fg": "white", "bg": "gray4", "attrs": ["bold"] }, + "window_title": { "fg": "white", "bg": "gray4", "attrs": [] }, + "file_name_no_file": { "fg": "gray9", "bg": "gray4", "attrs": ["bold"] }, + "file_vcs_status": { "fg": "brightestred", "bg": "gray4", "attrs": [] }, + "file_vcs_status_M": { "fg": "brightyellow", "bg": "gray4", "attrs": [] }, + "file_vcs_status_A": { "fg": "brightgreen", "bg": "gray4", "attrs": [] }, + "line_percent": { "fg": "gray9", "bg": "gray4", "attrs": [] }, + "line_percent_gradient": { "fg": "dark_green_gray", "bg": "gray4", "attrs": [] }, + "position": { "fg": "gray9", "bg": "gray4", "attrs": [] }, + "position_gradient": { "fg": "green_yellow_red", "bg": "gray4", "attrs": [] }, + "line_current": { "fg": "gray1", "bg": "gray10", "attrs": ["bold"] }, + "line_current_symbol": { "fg": "gray1", "bg": "gray10", "attrs": [] }, + "virtcol_current_gradient": { "fg": "dark_GREEN_Orange_red", "bg": "gray10", "attrs": [] }, + "col_current": { "fg": "gray6", "bg": "gray10", "attrs": [] }, + "modified_buffers": { "fg": "brightyellow", "bg": "gray2", "attrs": [] }, + "attached_clients": { "fg": "gray8", "bg": "gray2", "attrs": [] }, + "error": { "fg": "brightestred", "bg": "darkred", "attrs": ["bold"] }, + "warning": { "fg": "brightyellow", "bg": "darkorange", "attrs": ["bold"] }, + "current_tag": { "fg": "gray9", "bg": "gray2", "attrs": [] }, + + "tab_nc:modified_indicator": { "fg": "brightyellow", "bg": "gray2", "attrs": ["bold"] } + }, + "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", + "dark_green_gray": "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", + "dark_green_gray": "light_green_gray" + }, + "groups": { + "mode": { "fg": "darkestcyan", "bg": "white", "attrs": ["bold"] }, + "background:divider": { "fg": "darkcyan", "bg": "darkestblue", "attrs": [] }, + "branch:divider": { "fg": "darkcyan", "bg": "darkblue", "attrs": [] } + } + }, + "ic": { + "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", + "dark_green_gray": "light_green_gray" + }, + "groups": { + "mode": { "fg": "darkestcyan", "bg": "white", "attrs": ["bold"] }, + "background:divider": { "fg": "darkcyan", "bg": "darkestblue", "attrs": [] }, + "branch:divider": { "fg": "darkcyan", "bg": "darkblue", "attrs": [] } + } + }, + "ix": { + "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", + "dark_green_gray": "light_green_gray" + }, + "groups": { + "mode": { "fg": "darkestcyan", "bg": "white", "attrs": ["bold"] }, + "background:divider": { "fg": "darkcyan", "bg": "darkestblue", "attrs": [] }, + "branch:divider": { "fg": "darkcyan", "bg": "darkblue", "attrs": [] } + } + }, + "v": { + "groups": { + "mode": { "fg": "darkorange", "bg": "brightestorange", "attrs": ["bold"] } + } + }, + "V": { + "groups": { + "mode": { "fg": "darkorange", "bg": "brightestorange", "attrs": ["bold"] } + } + }, + "^V": { + "groups": { + "mode": { "fg": "darkorange", "bg": "brightestorange", "attrs": ["bold"] } + } + }, + "R": { + "groups": { + "mode": { "fg": "white", "bg": "brightred", "attrs": ["bold"] } + } + }, + "Rc": { + "groups": { + "mode": { "fg": "white", "bg": "brightred", "attrs": ["bold"] } + } + }, + "Rx": { + "groups": { + "mode": { "fg": "white", "bg": "brightred", "attrs": ["bold"] } + } + } + } +} diff --git a/powerline/config_files/colorschemes/vim/solarized.json b/powerline/config_files/colorschemes/vim/solarized.json new file mode 100644 index 0000000..55cfaa7 --- /dev/null +++ b/powerline/config_files/colorschemes/vim/solarized.json @@ -0,0 +1,121 @@ +{ + "name": "Solarized dark for vim", + "groups": { + "information:additional": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] }, + "information:unimportant": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "background": { "fg": "solarized:base3", "bg": "solarized:base02", "attrs": [] }, + "background:divider": { "fg": "solarized:base00", "bg": "solarized:base02", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:green", "attrs": ["bold"] }, + "visual_range": { "fg": "solarized:green", "bg": "solarized:base3", "attrs": ["bold"] }, + "modified_indicator": { "fg": "solarized:yellow", "bg": "solarized:base01", "attrs": ["bold"] }, + "paste_indicator": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] }, + "readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base01", "attrs": [] }, + "branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base01", "attrs": [] }, + "branch:divider": { "fg": "solarized:base1", "bg": "solarized:base01", "attrs": [] }, + "stash:divider": "branch:divider", + "file_name": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] }, + "window_title": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "file_name_no_file": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] }, + "file_format": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "file_vcs_status": { "fg": "solarized:red", "bg": "solarized:base01", "attrs": [] }, + "file_vcs_status_M": { "fg": "solarized:yellow", "bg": "solarized:base01", "attrs": [] }, + "file_vcs_status_A": { "fg": "solarized:green", "bg": "solarized:base01", "attrs": [] }, + "line_percent": { "fg": "solarized:base3", "bg": "solarized:base00", "attrs": [] }, + "line_percent_gradient": { "fg": "green_yellow_orange_red", "bg": "solarized:base00", "attrs": [] }, + "position": { "fg": "solarized:base3", "bg": "solarized:base00", "attrs": [] }, + "position_gradient": { "fg": "green_yellow_orange_red", "bg": "solarized:base00", "attrs": [] }, + "line_current": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] }, + "line_current_symbol": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "virtcol_current_gradient": { "fg": "GREEN_Orange_red", "bg": "solarized:base2", "attrs": [] }, + "col_current": { "fg": "solarized:base0", "bg": "solarized:base2", "attrs": [] }, + "environment": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "attached_clients": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "error": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] }, + "warning": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] }, + "current_tag": { "fg": "solarized:base3", "bg": "solarized:base02", "attrs": ["bold"] } + }, + "mode_translations": { + "nc": { + "colors": { + "solarized:base01": "solarized:base02", + "solarized:base00": "solarized:base02", + "solarized:base0": "solarized:base01", + "solarized:base1": "solarized:base00", + "solarized:base2": "solarized:base0", + "solarized:base3": "solarized:base1" + } + }, + "i": { + "groups": { + "background": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "background:divider": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] }, + "modified_indicator": { "fg": "solarized:yellow", "bg": "solarized:base2", "attrs": ["bold"] }, + "paste_indicator": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] }, + "readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base2", "attrs": [] }, + "branch": { "fg": "solarized:base01", "bg": "solarized:base2", "attrs": [] }, + "branch:divider": { "fg": "solarized:base00", "bg": "solarized:base2", "attrs": [] }, + "file_directory": { "fg": "solarized:base01", "bg": "solarized:base2", "attrs": [] }, + "file_name": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": ["bold"] }, + "file_size": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] }, + "file_name_no_file": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": ["bold"] }, + "file_name_empty": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] }, + "file_format": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] }, + "file_vcs_status": { "fg": "solarized:red", "bg": "solarized:base2", "attrs": [] }, + "file_vcs_status_M": { "fg": "solarized:yellow", "bg": "solarized:base2", "attrs": [] }, + "file_vcs_status_A": { "fg": "solarized:green", "bg": "solarized:base2", "attrs": [] }, + "line_percent": { "fg": "solarized:base3", "bg": "solarized:base1", "attrs": [] }, + "line_percent_gradient": { "fg": "solarized:base3", "bg": "solarized:base1", "attrs": [] }, + "position": { "fg": "solarized:base3", "bg": "solarized:base1", "attrs": [] }, + "position_gradient": { "fg": "solarized:base3", "bg": "solarized:base1", "attrs": [] }, + "line_current": { "fg": "solarized:base03", "bg": "solarized:base3", "attrs": ["bold"] }, + "line_current_symbol": { "fg": "solarized:base03", "bg": "solarized:base3", "attrs": [] }, + "col_current": { "fg": "solarized:base0", "bg": "solarized:base3", "attrs": [] } + } + }, + "ic": { + "groups": { + "background": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "background:divider": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] } + } + }, + "ix": { + "groups": { + "background": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, + "background:divider": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] } + } + }, + "v": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } + } + }, + "V": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } + } + }, + "^V": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } + } + }, + "R": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } + } + }, + "Rc": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } + } + }, + "Rx": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } + } + } + } +} diff --git a/powerline/config_files/colorschemes/vim/solarizedlight.json b/powerline/config_files/colorschemes/vim/solarizedlight.json new file mode 100644 index 0000000..f862d39 --- /dev/null +++ b/powerline/config_files/colorschemes/vim/solarizedlight.json @@ -0,0 +1,122 @@ +{ + "name": "Solarized light for vim", + "groups": { + "information:additional": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] }, + "information:unimportant": { "fg": "solarized:base1", "bg": "solarized:base01", "attrs": [] }, + "background": { "fg": "solarized:base03", "bg": "solarized:base01", "attrs": [] }, + "background:divider": { "fg": "solarized:base0", "bg": "solarized:base01", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:green", "attrs": ["bold"] }, + "visual_range": { "fg": "solarized:green", "bg": "solarized:base3", "attrs": ["bold"] }, + "modified_indicator": { "fg": "solarized:yellow", "bg": "solarized:base2", "attrs": ["bold"] }, + "paste_indicator": { "fg": "solarized:red", "bg": "solarized:base2", "attrs": ["bold"] }, + "readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base2", "attrs": [] }, + "branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base2", "attrs": [] }, + "branch:divider": { "fg": "solarized:base1", "bg": "solarized:base2", "attrs": [] }, + "stash": "branch_dirty", + "stash:divider": "branch:divider", + "file_name": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] }, + "window_title": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "file_size": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "file_name_no_file": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] }, + "file_name_empty": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "file_vcs_status": { "fg": "solarized:red", "bg": "solarized:base2", "attrs": [] }, + "file_vcs_status_M": { "fg": "solarized:yellow", "bg": "solarized:base2", "attrs": [] }, + "file_vcs_status_A": { "fg": "solarized:green", "bg": "solarized:base2", "attrs": [] }, + "line_percent": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "line_percent_gradient": { "fg": "green_yellow_orange_red", "bg": "solarized:base2", "attrs": [] }, + "position": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "position_gradient": { "fg": "green_yellow_orange_red", "bg": "solarized:base2", "attrs": [] }, + "line_current": { "fg": "solarized:base3", "bg": "solarized:base02", "attrs": ["bold"] }, + "line_current_symbol": { "fg": "solarized:base3", "bg": "solarized:base02", "attrs": [] }, + "virtcol_current_gradient": { "fg": "yellow_orange_red", "bg": "solarized:base02", "attrs": [] }, + "col_current": { "fg": "solarized:base00", "bg": "solarized:base02", "attrs": [] }, + "error": { "fg": "solarized:base03", "bg": "solarized:red", "attrs": ["bold"] }, + "warning": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] }, + "current_tag": { "fg": "solarized:base03", "bg": "solarized:base01", "attrs": ["bold"] } + }, + "mode_translations": { + "nc": { + "colors": { + "solarized:base2": "solarized:base01", + "solarized:base0": "solarized:base01", + "solarized:base00": "solarized:base2", + "solarized:base1": "solarized:base0", + "solarized:base02": "solarized:base00", + "solarized:base03": "solarized:base1" + } + }, + "i": { + "groups": { + "background": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "background:divider": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] }, + "modified_indicator": { "fg": "solarized:yellow", "bg": "solarized:base02", "attrs": ["bold"] }, + "paste_indicator": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] }, + "readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base02", "attrs": [] }, + "branch": { "fg": "solarized:base2", "bg": "solarized:base02", "attrs": [] }, + "branch:divider": { "fg": "solarized:base0", "bg": "solarized:base02", "attrs": [] }, + "file_directory": { "fg": "solarized:base2", "bg": "solarized:base02", "attrs": [] }, + "file_name": { "fg": "solarized:base01", "bg": "solarized:base02", "attrs": ["bold"] }, + "file_size": { "fg": "solarized:base01", "bg": "solarized:base02", "attrs": [] }, + "file_name_no_file": { "fg": "solarized:base01", "bg": "solarized:base02", "attrs": ["bold"] }, + "file_name_empty": { "fg": "solarized:base01", "bg": "solarized:base02", "attrs": [] }, + "file_format": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] }, + "file_vcs_status": { "fg": "solarized:red", "bg": "solarized:base02", "attrs": [] }, + "file_vcs_status_M": { "fg": "solarized:yellow", "bg": "solarized:base02", "attrs": [] }, + "file_vcs_status_A": { "fg": "solarized:green", "bg": "solarized:base02", "attrs": [] }, + "line_percent": { "fg": "solarized:base03", "bg": "solarized:base1", "attrs": [] }, + "line_percent_gradient": { "fg": "solarized:base03", "bg": "solarized:base1", "attrs": [] }, + "position": { "fg": "solarized:base03", "bg": "solarized:base1", "attrs": [] }, + "position_gradient": { "fg": "solarized:base03", "bg": "solarized:base1", "attrs": [] }, + "line_current": { "fg": "solarized:base3", "bg": "solarized:base03", "attrs": ["bold"] }, + "line_current_symbol": { "fg": "solarized:base3", "bg": "solarized:base03", "attrs": [] }, + "virtcol_current_gradient": { "fg": "yellow_orange_red", "bg": "solarized:base03", "attrs": [] }, + "col_current": { "fg": "solarized:base00", "bg": "solarized:base03", "attrs": [] } + } + }, + "ic": { + "groups": { + "background": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "background:divider": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] } + } + }, + "ix": { + "groups": { + "background": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, + "background:divider": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] }, + "mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] } + } + }, + "v": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } + } + }, + "V": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } + } + }, + "^V": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } + } + }, + "R": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } + } + }, + "Rc": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } + } + }, + "Rx": { + "groups": { + "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } + } + } + } +} diff --git a/powerline/config_files/config.json b/powerline/config_files/config.json new file mode 100644 index 0000000..4491885 --- /dev/null +++ b/powerline/config_files/config.json @@ -0,0 +1,53 @@ +{ + "common": { + "term_truecolor": false + }, + "ext": { + "ipython": { + "colorscheme": "default", + "theme": "in", + "local_themes": { + "rewrite": "rewrite", + "out": "out", + "in2": "in2" + } + }, + "pdb": { + "colorscheme": "default", + "theme": "default" + }, + "shell": { + "colorscheme": "default", + "theme": "default", + "local_themes": { + "continuation": "continuation", + "select": "select" + } + }, + "tmux": { + "colorscheme": "default", + "theme": "default" + }, + "vim": { + "colorscheme": "default", + "theme": "default", + "local_themes": { + "__tabline__": "tabline", + + "cmdwin": "cmdwin", + "help": "help", + "quickfix": "quickfix", + + "powerline.matchers.vim.plugin.nerdtree.nerdtree": "plugin_nerdtree", + "powerline.matchers.vim.plugin.commandt.commandt": "plugin_commandt", + "powerline.matchers.vim.plugin.gundo.gundo": "plugin_gundo", + "powerline.matchers.vim.plugin.gundo.gundo_preview": "plugin_gundo-preview" + } + }, + "wm": { + "colorscheme": "default", + "theme": "default", + "update_interval": 2 + } + } +} diff --git a/powerline/config_files/themes/ascii.json b/powerline/config_files/themes/ascii.json new file mode 100644 index 0000000..0ea05e7 --- /dev/null +++ b/powerline/config_files/themes/ascii.json @@ -0,0 +1,153 @@ +{ + "use_non_breaking_spaces": false, + "dividers": { + "left": { + "hard": " ", + "soft": "| " + }, + "right": { + "hard": " ", + "soft": " |" + } + }, + "spaces": 1, + "segment_data": { + "branch": { + "before": "BR " + }, + "stash": { + "before": "ST " + }, + "cwd": { + "args": { + "ellipsis": "..." + } + }, + "player": { + "args": { + "state_symbols": { + "fallback": "", + "play": ">", + "pause": "~", + "stop": "X" + } + } + }, + + "line_current_symbol": { + "contents": "LN " + }, + + "time": { + "before": "" + }, + + "powerline.segments.common.net.network_load": { + "args": { + "recv_format": "DL {value:>8}", + "sent_format": "UL {value:>8}" + } + }, + "powerline.segments.common.net.hostname": { + "before": "H " + }, + "powerline.segments.common.bat.battery": { + "args": { + "full_heart": "O", + "empty_heart": "O", + "online": "C", + "offline": " " + } + }, + "powerline.segments.common.sys.uptime": { + "before": "UP " + }, + "powerline.segments.common.mail.email_imap_alert": { + "before": "MAIL " + }, + "powerline.segments.common.env.virtualenv": { + "before": "(e) " + }, + "powerline.segments.common.wthr.weather": { + "args": { + "icons": { + "day": "DAY", + "blustery": "WIND", + "rainy": "RAIN", + "cloudy": "CLOUDS", + "snowy": "SNOW", + "stormy": "STORM", + "foggy": "FOG", + "sunny": "SUN", + "night": "NIGHT", + "windy": "WINDY", + "not_available": "NA", + "unknown": "UKN" + }, + "temp_format": "{temp:.0f} C" + } + }, + "powerline.segments.common.time.fuzzy_time": { + "args": { + "unicode_text": false + } + }, + + "powerline.segments.vim.mode": { + "args": { + "override": { + "n": "NORMAL", + "no": "N-OPER", + "v": "VISUAL", + "V": "V-LINE", + "^V": "V-BLCK", + "s": "SELECT", + "S": "S-LINE", + "^S": "S-BLCK", + "i": "INSERT", + "ic": "I-COMP", + "ix": "I-C_X ", + "R": "RPLACE", + "Rv": "V-RPLC", + "Rc": "R-COMP", + "Rx": "R-C_X ", + "c": "COMMND", + "cv": "VIM-EX", + "ce": "NRM-EX", + "r": "PROMPT", + "rm": "-MORE-", + "r?": "CNFIRM", + "!": "!SHELL", + "t": "TERM " + } + } + }, + "powerline.segments.vim.visual_range": { + "args": { + "CTRL_V_text": "{rows} x {vcols}", + "v_text_oneline": "C:{vcols}", + "v_text_multiline": "L:{rows}", + "V_text": "L:{rows}" + } + }, + "powerline.segments.vim.readonly_indicator": { + "args": { + "text": "RO" + } + }, + "powerline.segments.vim.modified_indicator": { + "args": { + "text": "+" + } + }, + + "powerline.segments.i3wm.scratchpad": { + "args": { + "icons": { + "fresh": "O", + "changed": "X" + } + } + } + } +} diff --git a/powerline/config_files/themes/ipython/in.json b/powerline/config_files/themes/ipython/in.json new file mode 100644 index 0000000..edd4d29 --- /dev/null +++ b/powerline/config_files/themes/ipython/in.json @@ -0,0 +1,25 @@ +{ + "segments": { + "left": [ + { + "function": "powerline.segments.common.env.virtualenv", + "priority": 10 + }, + { + "type": "string", + "contents": "In [", + "draw_soft_divider": false, + "highlight_groups": ["prompt"] + }, + { + "function": "powerline.segments.ipython.prompt_count", + "draw_soft_divider": false + }, + { + "type": "string", + "contents": "]", + "highlight_groups": ["prompt"] + } + ] + } +} diff --git a/powerline/config_files/themes/ipython/in2.json b/powerline/config_files/themes/ipython/in2.json new file mode 100644 index 0000000..422c44b --- /dev/null +++ b/powerline/config_files/themes/ipython/in2.json @@ -0,0 +1,12 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "contents": "", + "width": "auto", + "highlight_groups": ["prompt"] + } + ] + } +} diff --git a/powerline/config_files/themes/ipython/out.json b/powerline/config_files/themes/ipython/out.json new file mode 100644 index 0000000..2425d0b --- /dev/null +++ b/powerline/config_files/themes/ipython/out.json @@ -0,0 +1,24 @@ +{ + "default_module": "powerline.segments.ipython", + "segments": { + "left": [ + { + "type": "string", + "contents": "Out[", + "draw_soft_divider": false, + "width": "auto", + "align": "r", + "highlight_groups": ["prompt"] + }, + { + "function": "prompt_count", + "draw_soft_divider": false + }, + { + "type": "string", + "contents": "]", + "highlight_groups": ["prompt"] + } + ] + } +} diff --git a/powerline/config_files/themes/ipython/rewrite.json b/powerline/config_files/themes/ipython/rewrite.json new file mode 100644 index 0000000..8192fe4 --- /dev/null +++ b/powerline/config_files/themes/ipython/rewrite.json @@ -0,0 +1,23 @@ +{ + "default_module": "powerline.segments.ipython", + "segments": { + "left": [ + { + "type": "string", + "contents": "", + "draw_soft_divider": false, + "width": "auto", + "highlight_groups": ["prompt"] + }, + { + "function": "prompt_count", + "draw_soft_divider": false + }, + { + "type": "string", + "contents": ">", + "highlight_groups": ["prompt"] + } + ] + } +} diff --git a/powerline/config_files/themes/pdb/default.json b/powerline/config_files/themes/pdb/default.json new file mode 100644 index 0000000..dcae108 --- /dev/null +++ b/powerline/config_files/themes/pdb/default.json @@ -0,0 +1,27 @@ +{ + "default_module": "powerline.segments.pdb", + "segments": { + "left": [ + { + "function": "stack_depth" + }, + { + "type": "segment_list", + "function": "powerline.listers.pdb.frame_lister", + "segments": [ + { + "function": "current_file", + "after": ":" + }, + { + "function": "current_line", + "after": " " + }, + { + "function": "current_code_name" + } + ] + } + ] + } +} diff --git a/powerline/config_files/themes/powerline.json b/powerline/config_files/themes/powerline.json new file mode 100644 index 0000000..366a7ea --- /dev/null +++ b/powerline/config_files/themes/powerline.json @@ -0,0 +1,151 @@ +{ + "dividers": { + "left": { + "hard": " ", + "soft": " " + }, + "right": { + "hard": " ", + "soft": " " + } + }, + "spaces": 1, + "segment_data": { + "branch": { + "before": " " + }, + "stash": { + "before": "⌆ " + }, + "cwd": { + "args": { + "ellipsis": "⋯" + } + }, + + "line_current_symbol": { + "contents": " " + }, + "player": { + "args": { + "state_symbols": { + "fallback": "♫", + "play": "▶", + "pause": "▮▮", + "stop": "■" + } + } + }, + + "time": { + "before": "⌚ " + }, + + "powerline.segments.common.net.network_load": { + "args": { + "recv_format": "⬇ {value:>8}", + "sent_format": "⬆ {value:>8}" + } + }, + "powerline.segments.common.net.hostname": { + "before": " " + }, + "powerline.segments.common.bat.battery": { + "args": { + "full_heart": "♥", + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " + } + }, + "powerline.segments.common.sys.uptime": { + "before": "⇑ " + }, + "powerline.segments.common.mail.email_imap_alert": { + "before": "✉ " + }, + "powerline.segments.common.env.virtualenv": { + "before": "ⓔ " + }, + "powerline.segments.common.wthr.weather": { + "args": { + "icons": { + "day": "〇", + "blustery": "⚑", + "rainy": "☔", + "cloudy": "☁", + "snowy": "❅", + "stormy": "☈", + "foggy": "≡", + "sunny": "☼", + "night": "☾", + "windy": "☴", + "not_available": "�", + "unknown": "⚠" + } + } + }, + "powerline.segments.common.time.fuzzy_time": { + "args": { + "unicode_text": true + } + }, + + "powerline.segments.vim.mode": { + "args": { + "override": { + "n": "NORMAL", + "no": "N·OPER", + "v": "VISUAL", + "V": "V·LINE", + "^V": "V·BLCK", + "s": "SELECT", + "S": "S·LINE", + "^S": "S·BLCK", + "i": "INSERT", + "ic": "I·COMP", + "ix": "I·C-X ", + "R": "RPLACE", + "Rv": "V·RPLC", + "Rc": "R·COMP", + "Rx": "R·C-X ", + "c": "COMMND", + "cv": "VIM·EX", + "ce": "NRM·EX", + "r": "PROMPT", + "rm": "-MORE-", + "r?": "CNFIRM", + "!": "!SHELL", + "t": "TERM " + } + } + }, + "powerline.segments.vim.visual_range": { + "args": { + "CTRL_V_text": "↕{rows} ↔{vcols}", + "v_text_oneline": "↔{vcols}", + "v_text_multiline": "↕{rows}", + "V_text": "⇕{rows}" + } + }, + "powerline.segments.vim.readonly_indicator": { + "args": { + "text": "" + } + }, + "powerline.segments.vim.modified_indicator": { + "args": { + "text": "+" + } + }, + + "powerline.segments.i3wm.scratchpad": { + "args": { + "icons": { + "fresh": "●", + "changed": "○" + } + } + } + } +} diff --git a/powerline/config_files/themes/powerline_terminus.json b/powerline/config_files/themes/powerline_terminus.json new file mode 100644 index 0000000..e5fb1c8 --- /dev/null +++ b/powerline/config_files/themes/powerline_terminus.json @@ -0,0 +1,151 @@ +{ + "dividers": { + "left": { + "hard": " ", + "soft": " " + }, + "right": { + "hard": " ", + "soft": " " + } + }, + "spaces": 1, + "segment_data": { + "branch": { + "before": " " + }, + "stash": { + "before": "ST " + }, + "cwd": { + "args": { + "ellipsis": "…" + } + }, + + "line_current_symbol": { + "contents": " " + }, + "player": { + "args": { + "state_symbols": { + "fallback": "♫", + "play": "▶", + "pause": "▮▮", + "stop": "■" + } + } + }, + + "time": { + "before": "" + }, + + "powerline.segments.common.net.network_load": { + "args": { + "recv_format": "⇓ {value:>8}", + "sent_format": "⇑ {value:>8}" + } + }, + "powerline.segments.common.net.hostname": { + "before": " " + }, + "powerline.segments.common.bat.battery": { + "args": { + "full_heart": "♥", + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " + } + }, + "powerline.segments.common.sys.uptime": { + "before": "↑ " + }, + "powerline.segments.common.mail.email_imap_alert": { + "before": "MAIL " + }, + "powerline.segments.common.env.virtualenv": { + "before": "(e) " + }, + "powerline.segments.common.wthr.weather": { + "args": { + "icons": { + "day": "DAY", + "blustery": "WIND", + "rainy": "RAIN", + "cloudy": "CLOUDS", + "snowy": "SNOW", + "stormy": "STORM", + "foggy": "FOG", + "sunny": "SUN", + "night": "NIGHT", + "windy": "WINDY", + "not_available": "NA", + "unknown": "UKN" + } + } + }, + "powerline.segments.common.time.fuzzy_time": { + "args": { + "unicode_text": true + } + }, + + "powerline.segments.vim.mode": { + "args": { + "override": { + "n": "NORMAL", + "no": "N·OPER", + "v": "VISUAL", + "V": "V·LINE", + "^V": "V·BLCK", + "s": "SELECT", + "S": "S·LINE", + "^S": "S·BLCK", + "i": "INSERT", + "ic": "I·COMP", + "ix": "I·C-X ", + "R": "RPLACE", + "Rv": "V·RPLC", + "Rc": "R·COMP", + "Rx": "R·C-X ", + "c": "COMMND", + "cv": "VIM·EX", + "ce": "NRM·EX", + "r": "PROMPT", + "rm": "-MORE-", + "r?": "CNFIRM", + "!": "!SHELL", + "t": "TERM " + } + } + }, + "powerline.segments.vim.visual_range": { + "args": { + "CTRL_V_text": "↕{rows} ↔{vcols}", + "v_text_oneline": "↔{vcols}", + "v_text_multiline": "↕{rows}", + "V_text": "⇕{rows}" + } + }, + "powerline.segments.vim.readonly_indicator": { + "args": { + "text": "" + } + }, + "powerline.segments.vim.modified_indicator": { + "args": { + "text": "+" + } + }, + + "powerline.segments.i3wm.scratchpad": { + "args": { + "icons": { + "fresh": "●", + "changed": "○" + } + } + } + } +} diff --git a/powerline/config_files/themes/powerline_unicode7.json b/powerline/config_files/themes/powerline_unicode7.json new file mode 100644 index 0000000..bd62826 --- /dev/null +++ b/powerline/config_files/themes/powerline_unicode7.json @@ -0,0 +1,165 @@ +{ + "dividers": { + "left": { + "hard": " ", + "soft": " " + }, + "right": { + "hard": " ", + "soft": " " + } + }, + "spaces": 1, + "segment_data": { + "branch": { + "before": "🔀 " + }, + "stash": { + "before": "📝" + }, + "cwd": { + "args": { + "ellipsis": "⋯" + } + }, + + "line_current_symbol": { + "contents": " " + }, + "player": { + "args": { + "state_symbols": { + "fallback": "♫", + "play": "⏵", + "pause": "⏸", + "stop": "⏹" + } + } + }, + + "time": { + "before": "🕐 " + }, + + "powerline.segments.common.net.network_load": { + "args": { + "recv_format": "⬇ {value:>8}", + "sent_format": "⬆ {value:>8}" + } + }, + "powerline.segments.common.net.hostname": { + "before": "🏠 " + }, + "powerline.segments.common.bat.battery": { + "args": { + "full_heart": "💙", + "empty_heart": "💛", + "online": "⚡️", + "offline": " " + } + }, + "powerline.segments.common.sys.uptime": { + "before": "⇑ " + }, + "powerline.segments.common.mail.email_imap_alert": { + "before": "✉ " + }, + "powerline.segments.common.env.virtualenv": { + "before": "🐍 " + }, + "powerline.segments.common.wthr.weather": { + "args": { + "icons": { + "tornado": "🌪", + "hurricane": "🌀", + "showers": "☔", + "scattered_showers": "☔", + "thunderstorms": "🌩", + "isolated_thunderstorms": "🌩", + "scattered_thunderstorms": "🌩", + "dust": "🌫", + "fog": "🌫", + "cold": "❄", + "partly_cloudy_day": "🌤", + "mostly_cloudy_day": "🌥", + "sun": "🌣", + "hot": "♨", + "day": "☀", + "blustery": "⚑", + "rainy": "☂", + "cloudy": "☁", + "snowy": "☃", + "stormy": "☈", + "foggy": "🌁", + "sunny": "🌣", + "night": "☾", + "windy": "☴", + "not_available": "�", + "unknown": "⚠" + } + } + }, + "powerline.segments.common.time.fuzzy_time": { + "args": { + "unicode_text": true + } + }, + + "powerline.segments.vim.mode": { + "args": { + "override": { + "n": "NORMAL", + "no": "N·OPER", + "v": "VISUAL", + "V": "V·LINE", + "^V": "V·BLCK", + "s": "SELECT", + "S": "S·LINE", + "^S": "S·BLCK", + "i": "INSERT", + "ic": "I·COMP", + "ix": "I·C-X ", + "R": "RPLACE", + "Rv": "V·RPLC", + "Rc": "R·COMP", + "Rx": "R·C-X ", + "c": "COMMND", + "cv": "VIM·EX", + "ce": "NRM·EX", + "r": "PROMPT", + "rm": "-MORE-", + "r?": "CNFIRM", + "!": "!SHELL", + "t": "TERM " + } + } + }, + "powerline.segments.vim.visual_range": { + "args": { + "CTRL_V_text": "↕{rows} ↔{vcols}", + "v_text_oneline": "↔{vcols}", + "v_text_multiline": "↕{rows}", + "V_text": "⇕{rows}" + } + }, + "powerline.segments.vim.readonly_indicator": { + "args": { + "text": "🔏" + } + }, + "powerline.segments.vim.modified_indicator": { + "args": { + "text": "🖫⃥" + } + }, + + "powerline.segments.i3wm.scratchpad": { + "args": { + "icons": { + "fresh": "●", + "changed": "○" + } + } + } + } +} diff --git a/powerline/config_files/themes/shell/__main__.json b/powerline/config_files/themes/shell/__main__.json new file mode 100644 index 0000000..13ae942 --- /dev/null +++ b/powerline/config_files/themes/shell/__main__.json @@ -0,0 +1,14 @@ +{ + "segment_data": { + "hostname": { + "args": { + "only_if_ssh": true + } + }, + "cwd": { + "args": { + "dir_limit_depth": 3 + } + } + } +} diff --git a/powerline/config_files/themes/shell/continuation.json b/powerline/config_files/themes/shell/continuation.json new file mode 100644 index 0000000..9307fc0 --- /dev/null +++ b/powerline/config_files/themes/shell/continuation.json @@ -0,0 +1,12 @@ +{ + "default_module": "powerline.segments.shell", + "segments": { + "left": [ + { + "function": "continuation" + } + ], + "right": [ + ] + } +} diff --git a/powerline/config_files/themes/shell/default.json b/powerline/config_files/themes/shell/default.json new file mode 100644 index 0000000..38039d8 --- /dev/null +++ b/powerline/config_files/themes/shell/default.json @@ -0,0 +1,43 @@ +{ + "segments": { + "left": [ + { + "function": "powerline.segments.shell.mode" + }, + { + "function": "powerline.segments.common.net.hostname", + "priority": 10 + }, + { + "function": "powerline.segments.common.env.user", + "priority": 30 + }, + { + "function": "powerline.segments.common.env.virtualenv", + "priority": 50 + }, + { + "function": "powerline.segments.shell.cwd", + "priority": 10 + }, + { + "function": "powerline.segments.shell.jobnum", + "priority": 20 + } + ], + "right": [ + { + "function": "powerline.segments.shell.last_pipe_status", + "priority": 10 + }, + { + "function": "powerline.segments.common.vcs.stash", + "priority": 50 + }, + { + "function": "powerline.segments.common.vcs.branch", + "priority": 40 + } + ] + } +} diff --git a/powerline/config_files/themes/shell/default_leftonly.json b/powerline/config_files/themes/shell/default_leftonly.json new file mode 100644 index 0000000..b576273 --- /dev/null +++ b/powerline/config_files/themes/shell/default_leftonly.json @@ -0,0 +1,34 @@ +{ + "segments": { + "left": [ + { + "function": "powerline.segments.common.net.hostname", + "priority": 10 + }, + { + "function": "powerline.segments.common.env.user", + "priority": 30 + }, + { + "function": "powerline.segments.common.env.virtualenv", + "priority": 50 + }, + { + "function": "powerline.segments.common.vcs.branch", + "priority": 40 + }, + { + "function": "powerline.segments.shell.cwd", + "priority": 10 + }, + { + "function": "powerline.segments.shell.jobnum", + "priority": 20 + }, + { + "function": "powerline.segments.shell.last_pipe_status", + "priority": 10 + } + ] + } +} diff --git a/powerline/config_files/themes/shell/select.json b/powerline/config_files/themes/shell/select.json new file mode 100644 index 0000000..3d81408 --- /dev/null +++ b/powerline/config_files/themes/shell/select.json @@ -0,0 +1,13 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "contents": "Select variant", + "width": "auto", + "align": "r", + "highlight_groups": ["continuation:current"] + } + ] + } +} diff --git a/powerline/config_files/themes/tmux/default.json b/powerline/config_files/themes/tmux/default.json new file mode 100644 index 0000000..4532ced --- /dev/null +++ b/powerline/config_files/themes/tmux/default.json @@ -0,0 +1,28 @@ +{ + "segments": { + "right": [ + { + "function": "powerline.segments.common.sys.uptime", + "priority": 50 + }, + { + "function": "powerline.segments.common.sys.system_load", + "priority": 50 + }, + { + "function": "powerline.segments.common.time.date" + }, + { + "function": "powerline.segments.common.time.date", + "name": "time", + "args": { + "format": "%H:%M", + "istime": true + } + }, + { + "function": "powerline.segments.common.net.hostname" + } + ] + } +} diff --git a/powerline/config_files/themes/unicode.json b/powerline/config_files/themes/unicode.json new file mode 100644 index 0000000..0802852 --- /dev/null +++ b/powerline/config_files/themes/unicode.json @@ -0,0 +1,151 @@ +{ + "dividers": { + "left": { + "hard": "▌ ", + "soft": "│ " + }, + "right": { + "hard": " ▐", + "soft": " │" + } + }, + "spaces": 1, + "segment_data": { + "branch": { + "before": "⎇ " + }, + "stash": { + "before": "⌆" + }, + "cwd": { + "args": { + "ellipsis": "⋯" + } + }, + "player": { + "args": { + "state_symbols": { + "fallback": "♫", + "play": "▶", + "pause": "▮▮", + "stop": "■" + } + } + }, + + "line_current_symbol": { + "contents": " " + }, + + "time": { + "before": "⌚ " + }, + + "powerline.segments.common.net.network_load": { + "args": { + "recv_format": "⬇ {value:>8}", + "sent_format": "⬆ {value:>8}" + } + }, + "powerline.segments.common.net.hostname": { + "before": "⌂ " + }, + "powerline.segments.common.bat.battery": { + "args": { + "full_heart": "♥", + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " + } + }, + "powerline.segments.common.sys.uptime": { + "before": "⇑ " + }, + "powerline.segments.common.mail.email_imap_alert": { + "before": "✉ " + }, + "powerline.segments.common.env.virtualenv": { + "before": "ⓔ " + }, + "powerline.segments.common.wthr.weather": { + "args": { + "icons": { + "day": "〇", + "blustery": "⚑", + "rainy": "☔", + "cloudy": "☁", + "snowy": "❅", + "stormy": "☈", + "foggy": "≡", + "sunny": "☼", + "night": "☾", + "windy": "☴", + "not_available": "�", + "unknown": "⚠" + } + } + }, + "powerline.segments.common.time.fuzzy_time": { + "args": { + "unicode_text": true + } + }, + + "powerline.segments.vim.mode": { + "args": { + "override": { + "n": "NORMAL", + "no": "N·OPER", + "v": "VISUAL", + "V": "V·LINE", + "^V": "V·BLCK", + "s": "SELECT", + "S": "S·LINE", + "^S": "S·BLCK", + "i": "INSERT", + "ic": "I·COMP", + "ix": "I·C-X ", + "R": "RPLACE", + "Rv": "V·RPLC", + "Rc": "R·COMP", + "Rx": "R·C-X ", + "c": "COMMND", + "cv": "VIM·EX", + "ce": "NRM·EX", + "r": "PROMPT", + "rm": "-MORE-", + "r?": "CNFIRM", + "!": "!SHELL", + "t": "TERM " + } + } + }, + "powerline.segments.vim.visual_range": { + "args": { + "CTRL_V_text": "↕{rows} ↔{vcols}", + "v_text_oneline": "↔{vcols}", + "v_text_multiline": "↕{rows}", + "V_text": "⇕{rows}" + } + }, + "powerline.segments.vim.readonly_indicator": { + "args": { + "text": "⊗" + } + }, + "powerline.segments.vim.modified_indicator": { + "args": { + "text": "+" + } + }, + + "powerline.segments.i3wm.scratchpad": { + "args": { + "icons": { + "fresh": "●", + "changed": "○" + } + } + } + } +} diff --git a/powerline/config_files/themes/unicode_terminus.json b/powerline/config_files/themes/unicode_terminus.json new file mode 100644 index 0000000..9c76985 --- /dev/null +++ b/powerline/config_files/themes/unicode_terminus.json @@ -0,0 +1,151 @@ +{ + "dividers": { + "left": { + "hard": "▌ ", + "soft": "│ " + }, + "right": { + "hard": " ▐", + "soft": " │" + } + }, + "spaces": 1, + "segment_data": { + "branch": { + "before": "BR " + }, + "stash": { + "before": "ST " + }, + "cwd": { + "args": { + "ellipsis": "…" + } + }, + + "line_current_symbol": { + "contents": " " + }, + "player": { + "args": { + "state_symbols": { + "fallback": "♫", + "play": "▶", + "pause": "▮▮", + "stop": "■" + } + } + }, + + "time": { + "before": "" + }, + + "powerline.segments.common.net.network_load": { + "args": { + "recv_format": "⇓ {value:>8}", + "sent_format": "⇑ {value:>8}" + } + }, + "powerline.segments.common.net.hostname": { + "before": "⌂ " + }, + "powerline.segments.common.bat.battery": { + "args": { + "full_heart": "♥", + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " + } + }, + "powerline.segments.common.sys.uptime": { + "before": "↑ " + }, + "powerline.segments.common.mail.email_imap_alert": { + "before": "MAIL " + }, + "powerline.segments.common.env.virtualenv": { + "before": "(e) " + }, + "powerline.segments.common.wthr.weather": { + "args": { + "icons": { + "day": "DAY", + "blustery": "WIND", + "rainy": "RAIN", + "cloudy": "CLOUDS", + "snowy": "SNOW", + "stormy": "STORM", + "foggy": "FOG", + "sunny": "SUN", + "night": "NIGHT", + "windy": "WINDY", + "not_available": "NA", + "unknown": "UKN" + } + } + }, + "powerline.segments.common.time.fuzzy_time": { + "args": { + "unicode_text": true + } + }, + + "powerline.segments.vim.mode": { + "args": { + "override": { + "n": "NORMAL", + "no": "N·OPER", + "v": "VISUAL", + "V": "V·LINE", + "^V": "V·BLCK", + "s": "SELECT", + "S": "S·LINE", + "^S": "S·BLCK", + "i": "INSERT", + "ic": "I·COMP", + "ix": "I·C-X ", + "R": "RPLACE", + "Rv": "V·RPLC", + "Rc": "R·COMP", + "Rx": "R·C-X ", + "c": "COMMND", + "cv": "VIM·EX", + "ce": "NRM·EX", + "r": "PROMPT", + "rm": "-MORE-", + "r?": "CNFIRM", + "!": "!SHELL", + "t": "TERM " + } + } + }, + "powerline.segments.vim.visual_range": { + "args": { + "CTRL_V_text": "{rows} × {vcols}", + "v_text_oneline": "C:{vcols}", + "v_text_multiline": "L:{rows}", + "V_text": "L:{rows}" + } + }, + "powerline.segments.vim.readonly_indicator": { + "args": { + "text": "RO" + } + }, + "powerline.segments.vim.modified_indicator": { + "args": { + "text": "+" + } + }, + + "powerline.segments.i3wm.scratchpad": { + "args": { + "icons": { + "fresh": "●", + "changed": "○" + } + } + } + } +} diff --git a/powerline/config_files/themes/unicode_terminus_condensed.json b/powerline/config_files/themes/unicode_terminus_condensed.json new file mode 100644 index 0000000..421f5c8 --- /dev/null +++ b/powerline/config_files/themes/unicode_terminus_condensed.json @@ -0,0 +1,151 @@ +{ + "dividers": { + "left": { + "hard": "▌", + "soft": "│" + }, + "right": { + "hard": "▐", + "soft": "│" + } + }, + "spaces": 0, + "segment_data": { + "branch": { + "before": "B " + }, + "stash": { + "before": "S " + }, + "cwd": { + "args": { + "use_path_separator": true, + "ellipsis": "…" + } + }, + + "line_current_symbol": { + "contents": "" + }, + "player": { + "args": { + "state_symbols": { + "fallback": "♫", + "play": "▶", + "pause": "▮▮", + "stop": "■" + } + } + }, + + "time": { + "before": "" + }, + + "powerline.segments.common.net.network_load": { + "args": { + "recv_format": "⇓{value:>8}", + "sent_format": "⇑{value:>8}" + } + }, + "powerline.segments.common.net.hostname": { + "before": "⌂" + }, + "powerline.segments.common.bat.battery": { + "args": { + "full_heart": "♥", + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " + } + }, + "powerline.segments.common.sys.uptime": { + "before": "↑" + }, + "powerline.segments.common.mail.email_imap_alert": { + "before": "M " + }, + "powerline.segments.common.env.virtualenv": { + "before": "E " + }, + "powerline.segments.common.wthr.weather": { + "args": { + "icons": { + "day": "D", + "blustery": "W", + "rainy": "R", + "cloudy": "c", + "snowy": "*", + "stormy": "S", + "foggy": "f", + "sunny": "s", + "night": "N", + "windy": "w", + "not_available": "-", + "unknown": "!" + } + } + }, + "powerline.segments.common.time.fuzzy_time": { + "args": { + "unicode_text": true + } + }, + + "powerline.segments.vim.mode": { + "args": { + "override": { + "n": "NML", + "no": "NOP", + "v": "VIS", + "V": "VLN", + "^V": "VBL", + "s": "SEL", + "S": "SLN", + "^S": "SBL", + "i": "INS", + "ic": "I-C", + "ix": "I^X", + "R": "REP", + "Rv": "VRP", + "Rc": "R-C", + "Rx": "R^X", + "c": "CMD", + "cv": "VEX", + "ce": " EX", + "r": "PRT", + "rm": "MOR", + "r?": "CON", + "!": " SH" + } + } + }, + "powerline.segments.vim.visual_range": { + "args": { + "CTRL_V_text": "{rows}×{vcols}", + "v_text_oneline": "↔{vcols}", + "v_text_multiline": "↕{rows}", + "V_text": "⇕{rows}" + } + }, + "powerline.segments.vim.readonly_indicator": { + "args": { + "text": "RO" + } + }, + "powerline.segments.vim.modified_indicator": { + "args": { + "text": "+" + } + }, + + "powerline.segments.i3wm.scratchpad": { + "args": { + "icons": { + "fresh": "●", + "changed": "○" + } + } + } + } +} diff --git a/powerline/config_files/themes/vim/__main__.json b/powerline/config_files/themes/vim/__main__.json new file mode 100644 index 0000000..7cd3305 --- /dev/null +++ b/powerline/config_files/themes/vim/__main__.json @@ -0,0 +1,10 @@ +{ + "segment_data": { + "line_percent": { + "args": { + "gradient": true + }, + "after": "%" + } + } +} diff --git a/powerline/config_files/themes/vim/cmdwin.json b/powerline/config_files/themes/vim/cmdwin.json new file mode 100644 index 0000000..e6a05b0 --- /dev/null +++ b/powerline/config_files/themes/vim/cmdwin.json @@ -0,0 +1,18 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "contents": "Command Line", + "highlight_groups": ["file_name"] + }, + { + "type": "string", + "highlight_groups": ["background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ] + } +} diff --git a/powerline/config_files/themes/vim/default.json b/powerline/config_files/themes/vim/default.json new file mode 100644 index 0000000..9b0c744 --- /dev/null +++ b/powerline/config_files/themes/vim/default.json @@ -0,0 +1,128 @@ +{ + "segments": { + "left": [ + { + "function": "mode", + "exclude_modes": ["nc"] + }, + { + "function": "visual_range", + "include_modes": ["v", "V", "^V", "s", "S", "^S"], + "priority": 10 + }, + { + "function": "paste_indicator", + "exclude_modes": ["nc"], + "priority": 10 + }, + { + "function": "powerline.segments.vim.plugin.capslock.capslock_indicator", + "include_modes": ["i", "R", "Rv"], + "priority": 10 + }, + { + "function": "branch", + "exclude_modes": ["nc"], + "priority": 30 + }, + { + "function": "readonly_indicator", + "draw_soft_divider": false, + "after": " " + }, + { + "function": "file_scheme", + "priority": 20 + }, + { + "function": "file_directory", + "priority": 40, + "draw_soft_divider": false + }, + { + "function": "file_name", + "draw_soft_divider": false + }, + { + "function": "file_vcs_status", + "before": " ", + "draw_soft_divider": false + }, + { + "function": "modified_indicator", + "before": " " + }, + { + "exclude_modes": ["i", "R", "Rv"], + "function": "trailing_whitespace", + "display": false, + "priority": 60 + }, + { + "exclude_modes": ["nc"], + "function": "powerline.segments.vim.plugin.syntastic.syntastic", + "priority": 50 + }, + { + "exclude_modes": ["nc"], + "function": "powerline.segments.vim.plugin.tagbar.current_tag", + "draw_soft_divider": false, + "priority": 50 + }, + { + "type": "string", + "highlight_groups": ["background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + { + "function": "file_format", + "draw_soft_divider": false, + "exclude_modes": ["nc"], + "priority": 60 + }, + { + "function": "file_encoding", + "exclude_modes": ["nc"], + "priority": 60 + }, + { + "function": "file_type", + "exclude_modes": ["nc"], + "priority": 60 + }, + { + "function": "line_percent", + "priority": 50, + "width": 4, + "align": "r" + }, + { + "function": "csv_col_current", + "priority": 30 + }, + { + "type": "string", + "name": "line_current_symbol", + "highlight_groups": ["line_current_symbol", "line_current"] + }, + { + "function": "line_current", + "draw_soft_divider": false, + "width": 3, + "align": "r" + }, + { + "function": "virtcol_current", + "draw_soft_divider": false, + "priority": 20, + "before": ":", + "width": 3, + "align": "l" + } + ] + } +} diff --git a/powerline/config_files/themes/vim/help.json b/powerline/config_files/themes/vim/help.json new file mode 100644 index 0000000..45c9458 --- /dev/null +++ b/powerline/config_files/themes/vim/help.json @@ -0,0 +1,36 @@ +{ + "segments": { + "left": [ + { + "function": "file_name", + "draw_soft_divider": false + }, + { + "type": "string", + "highlight_groups": ["background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + { + "function": "line_percent", + "priority": 30, + "width": 4, + "align": "r" + }, + { + "type": "string", + "name": "line_current_symbol", + "highlight_groups": ["line_current_symbol", "line_current"] + }, + { + "function": "line_current", + "draw_soft_divider": false, + "width": 3, + "align": "r" + } + ] + } +} diff --git a/powerline/config_files/themes/vim/plugin_commandt.json b/powerline/config_files/themes/vim/plugin_commandt.json new file mode 100644 index 0000000..dd6748f --- /dev/null +++ b/powerline/config_files/themes/vim/plugin_commandt.json @@ -0,0 +1,26 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "contents": "Command-T", + "highlight_groups": ["commandt:label"] + }, + { + "function": "powerline.segments.vim.plugin.commandt.finder" + }, + { + "function": "powerline.segments.vim.plugin.commandt.path" + }, + { + "type": "string", + "highlight_groups": ["commandt:background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + ] + } +} diff --git a/powerline/config_files/themes/vim/plugin_gundo-preview.json b/powerline/config_files/themes/vim/plugin_gundo-preview.json new file mode 100644 index 0000000..ad8432c --- /dev/null +++ b/powerline/config_files/themes/vim/plugin_gundo-preview.json @@ -0,0 +1,18 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "highlight_groups": ["gundo:name", "file_name"], + "contents": "Undo diff" + }, + { + "type": "string", + "highlight_groups": ["gundo:background", "background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ] + } +} diff --git a/powerline/config_files/themes/vim/plugin_gundo.json b/powerline/config_files/themes/vim/plugin_gundo.json new file mode 100644 index 0000000..a03b256 --- /dev/null +++ b/powerline/config_files/themes/vim/plugin_gundo.json @@ -0,0 +1,18 @@ +{ + "segments": { + "left": [ + { + "type": "string", + "highlight_groups": ["gundo:name", "file_name"], + "contents": "Undo tree" + }, + { + "type": "string", + "highlight_groups": ["gundo:background", "background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ] + } +} diff --git a/powerline/config_files/themes/vim/plugin_nerdtree.json b/powerline/config_files/themes/vim/plugin_nerdtree.json new file mode 100644 index 0000000..896d393 --- /dev/null +++ b/powerline/config_files/themes/vim/plugin_nerdtree.json @@ -0,0 +1,17 @@ +{ + "default_module": "powerline.segments.vim.plugin.nerdtree", + "segments": { + "left": [ + { + "function": "nerdtree" + }, + { + "type": "string", + "highlight_groups": ["background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ] + } +} diff --git a/powerline/config_files/themes/vim/quickfix.json b/powerline/config_files/themes/vim/quickfix.json new file mode 100644 index 0000000..ae4d5a5 --- /dev/null +++ b/powerline/config_files/themes/vim/quickfix.json @@ -0,0 +1,40 @@ +{ + "segment_data": { + "buffer_name": { + "contents": "Location List" + } + }, + "segments": { + "left": [ + { + "type": "string", + "name": "buffer_name", + "highlight_groups": ["file_name"] + }, + { + "function": "window_title", + "draw_soft_divider": false + }, + { + "type": "string", + "highlight_groups": ["background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + { + "type": "string", + "name": "line_current_symbol", + "highlight_groups": ["line_current_symbol", "line_current"] + }, + { + "function": "line_current", + "draw_soft_divider": false, + "width": 3, + "align": "r" + } + ] + } +} diff --git a/powerline/config_files/themes/vim/tabline.json b/powerline/config_files/themes/vim/tabline.json new file mode 100644 index 0000000..1e3130e --- /dev/null +++ b/powerline/config_files/themes/vim/tabline.json @@ -0,0 +1,93 @@ +{ + "default_module": "powerline.segments.vim", + "segments": { + "left": [ + { + "type": "segment_list", + "function": "powerline.listers.vim.tablister", + "exclude_function": "single_tab", + "segments": [ + { + "function": "tab" + }, + { + "function": "tabnr", + "after": " ", + "priority": 5 + }, + { + "function": "file_directory", + "priority": 40 + }, + { + "function": "file_name", + "args": { + "display_no_file": true + }, + "priority": 10 + }, + { + "function": "tab_modified_indicator", + "priority": 5 + } + ] + }, + { + "function": "tab", + "args": { + "end": true + } + }, + { + "type": "segment_list", + "function": "powerline.listers.vim.bufferlister", + "include_function": "single_tab", + "segments": [ + { + "function": "bufnr", + "after": " ", + "priority": 5 + }, + { + "function": "file_directory", + "priority": 40 + }, + { + "function": "file_name", + "args": { + "display_no_file": true + }, + "priority": 10 + }, + { + "function": "modified_indicator", + "priority": 5 + } + ] + }, + { + "type": "string", + "highlight_groups": ["tab:background"], + "draw_soft_divider": false, + "draw_hard_divider": false, + "width": "auto" + } + ], + "right": [ + { + "type": "string", + "contents": "Bufs", + "name": "single_tab", + "highlight_groups": ["single_tab"], + "include_function": "single_tab" + }, + { + "type": "string", + "contents": "Tabs", + "name": "many_tabs", + "highlight_groups": ["many_tabs"], + "exclude_function": "single_tab" + } + ] + } +} diff --git a/powerline/config_files/themes/wm/default.json b/powerline/config_files/themes/wm/default.json new file mode 100644 index 0000000..3d468b4 --- /dev/null +++ b/powerline/config_files/themes/wm/default.json @@ -0,0 +1,17 @@ +{ + "segments": { + "right": [ + { + "function": "powerline.segments.common.time.date" + }, + { + "function": "powerline.segments.common.time.date", + "name": "time", + "args": { + "format": "%H:%M", + "istime": true + } + } + ] + } +} diff --git a/powerline/dist/systemd/powerline-daemon.service b/powerline/dist/systemd/powerline-daemon.service new file mode 100644 index 0000000..96b685d --- /dev/null +++ b/powerline/dist/systemd/powerline-daemon.service @@ -0,0 +1,10 @@ +[Unit] +Description=powerline-daemon - Daemon that improves powerline performance +Documentation=man:powerline-daemon(1) +Documentation=https://powerline.readthedocs.org/en/latest/ + +[Service] +ExecStart=/usr/bin/powerline-daemon --foreground + +[Install] +WantedBy=default.target diff --git a/powerline/ipython.py b/powerline/ipython.py new file mode 100644 index 0000000..cb84fc7 --- /dev/null +++ b/powerline/ipython.py @@ -0,0 +1,68 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from powerline import Powerline +from powerline.lib.dict import mergedicts +from powerline.lib.unicode import string + + +class IPythonInfo(object): + def __init__(self, shell): + self._shell = shell + + @property + def prompt_count(self): + return self._shell.execution_count + + +# 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 IPythonPowerline(Powerline): + def init(self, **kwargs): + super(IPythonPowerline, self).init( + 'ipython', + use_daemon_threads=True, + **kwargs + ) + + def get_config_paths(self): + if self.config_paths: + return self.config_paths + 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 + + def do_setup(self, wrefs): + for wref in wrefs: + obj = wref() + if obj is not None: + setattr(obj, 'powerline', self) diff --git a/powerline/lemonbar.py b/powerline/lemonbar.py new file mode 100644 index 0000000..b49f86b --- /dev/null +++ b/powerline/lemonbar.py @@ -0,0 +1,21 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from powerline import Powerline +from powerline.lib.dict import mergedicts + + +class LemonbarPowerline(Powerline): + def init(self): + super(LemonbarPowerline, self).init(ext='wm', renderer_module='lemonbar') + + get_encoding = staticmethod(lambda: 'utf-8') + + def get_local_themes(self, local_themes): + if not local_themes: + return {} + + return dict(( + (key, {'config': self.load_theme_config(val)}) + for key, val in local_themes.items() + )) diff --git a/powerline/lib/__init__.py b/powerline/lib/__init__.py new file mode 100644 index 0000000..2a5fbd0 --- /dev/null +++ b/powerline/lib/__init__.py @@ -0,0 +1,28 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from functools import wraps + + +def wraps_saveargs(wrapped): + def dec(wrapper): + r = wraps(wrapped)(wrapper) + r.powerline_origin = getattr(wrapped, 'powerline_origin', wrapped) + return r + return dec + + +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 diff --git a/powerline/lib/config.py b/powerline/lib/config.py new file mode 100644 index 0000000..0c95e47 --- /dev/null +++ b/powerline/lib/config.py @@ -0,0 +1,218 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import json +import codecs + +from copy import deepcopy +from threading import Event, Lock +from collections import defaultdict + +from powerline.lib.threaded import MultiRunnedThread +from powerline.lib.watcher import create_file_watcher + + +def open_file(path): + return codecs.open(path, encoding='utf-8') + + +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 DummyWatcher(object): + def __call__(self, *args, **kwargs): + return False + + def watch(self, *args, **kwargs): + pass + + +class DeferredWatcher(object): + def __init__(self, *args, **kwargs): + self.args = args + self.kwargs = kwargs + self.calls = [] + + def __call__(self, *args, **kwargs): + self.calls.append(('__call__', args, kwargs)) + + def watch(self, *args, **kwargs): + self.calls.append(('watch', args, kwargs)) + + def unwatch(self, *args, **kwargs): + self.calls.append(('unwatch', args, kwargs)) + + def transfer_calls(self, watcher): + for attr, args, kwargs in self.calls: + getattr(watcher, attr)(*args, **kwargs) + + +class ConfigLoader(MultiRunnedThread): + def __init__(self, shutdown_event=None, watcher=None, watcher_type=None, load=load_json_config, run_once=False): + super(ConfigLoader, self).__init__() + self.shutdown_event = shutdown_event or Event() + if run_once: + self.watcher = DummyWatcher() + self.watcher_type = 'dummy' + else: + self.watcher = watcher or DeferredWatcher() + if watcher: + if not watcher_type: + raise ValueError('When specifying watcher you must also specify watcher type') + self.watcher_type = watcher_type + else: + self.watcher_type = 'deferred' + self._load = load + + self.pl = None + self.interval = None + + self.lock = Lock() + + self.watched = defaultdict(set) + self.missing = defaultdict(set) + self.loaded = {} + + def set_watcher(self, watcher_type, force=False): + if watcher_type == self.watcher_type: + return + watcher = create_file_watcher(self.pl, watcher_type) + with self.lock: + if self.watcher_type == 'deferred': + self.watcher.transfer_calls(watcher) + self.watcher = watcher + self.watcher_type = watcher_type + + 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 logged and ignored. IOError exception + will be ignored without logging. + :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 deepcopy(self.loaded[path]) + except KeyError: + r = self._load(path) + self.loaded[path] = deepcopy(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 IOError: + pass + 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] = deepcopy(self._load(path)) + except Exception as e: + self.exception('Error while loading {0}: {1}', path, str(e)) + try: + self.loaded.pop(path) + except KeyError: + pass + try: + self.loaded.pop(path) + except KeyError: + pass + + 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 diff --git a/powerline/lib/debug.py b/powerline/lib/debug.py new file mode 100755 index 0000000..515e8c4 --- /dev/null +++ b/powerline/lib/debug.py @@ -0,0 +1,97 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import gc +import sys + +from types import FrameType +from itertools import chain + + +# From http://code.activestate.com/recipes/523004-find-cyclical-references/ +def print_cycles(objects, outstream=sys.stdout, show_progress=False): + '''Find reference cycles + + :param list objects: + A list of objects to find cycles in. It is often useful to pass in + gc.garbage to find the cycles that are preventing some objects from + being garbage collected. + :param file outstream: + The stream for output. + :param bool show_progress: + If True, print the number of objects reached as they are found. + ''' + def print_path(path): + for i, step in enumerate(path): + # next “wraps around” + next = path[(i + 1) % len(path)] + + outstream.write(' %s -- ' % str(type(step))) + written = False + if isinstance(step, dict): + for key, val in step.items(): + if val is next: + outstream.write('[%s]' % repr(key)) + written = True + break + if key is next: + outstream.write('[key] = %s' % repr(val)) + written = True + break + elif isinstance(step, (list, tuple)): + for i, item in enumerate(step): + if item is next: + outstream.write('[%d]' % i) + written = True + elif getattr(type(step), '__getattribute__', None) in (object.__getattribute__, type.__getattribute__): + for attr in chain(dir(step), getattr(step, '__dict__', ())): + if getattr(step, attr, None) is next: + try: + outstream.write('%r.%s' % (step, attr)) + except TypeError: + outstream.write('.%s' % (step, attr)) + written = True + break + if not written: + outstream.write(repr(step)) + outstream.write(' ->\n') + outstream.write('\n') + + def recurse(obj, start, all, current_path): + if show_progress: + outstream.write('%d\r' % len(all)) + + all[id(obj)] = None + + referents = gc.get_referents(obj) + for referent in referents: + # If we’ve found our way back to the start, this is + # a cycle, so print it out + if referent is start: + try: + outstream.write('Cyclic reference: %r\n' % referent) + except TypeError: + try: + outstream.write('Cyclic reference: %i (%r)\n' % (id(referent), type(referent))) + except TypeError: + outstream.write('Cyclic reference: %i\n' % id(referent)) + print_path(current_path) + + # Don’t go back through the original list of objects, or + # through temporary references to the object, since those + # are just an artifact of the cycle detector itself. + elif referent is objects or isinstance(referent, FrameType): + continue + + # We haven’t seen this object before, so recurse + elif id(referent) not in all: + recurse(referent, start, all, current_path + (obj,)) + + for obj in objects: + # We are not interested in non-powerline cyclic references + try: + if not type(obj).__module__.startswith('powerline'): + continue + except AttributeError: + continue + recurse(obj, obj, {}, ()) diff --git a/powerline/lib/dict.py b/powerline/lib/dict.py new file mode 100644 index 0000000..c06ab30 --- /dev/null +++ b/powerline/lib/dict.py @@ -0,0 +1,88 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + + +REMOVE_THIS_KEY = object() + + +def mergeargs(argvalue, remove=False): + if not argvalue: + return None + r = {} + for subval in argvalue: + mergedicts(r, dict([subval]), remove=remove) + return r + + +def _clear_special_values(d): + '''Remove REMOVE_THIS_KEY values from dictionary + ''' + l = [d] + while l: + i = l.pop() + pops = [] + for k, v in i.items(): + if v is REMOVE_THIS_KEY: + pops.append(k) + elif isinstance(v, dict): + l.append(v) + for k in pops: + i.pop(k) + + +def mergedicts(d1, d2, remove=True): + '''Recursively merge two dictionaries + + First dictionary is modified in-place. + ''' + _setmerged(d1, d2) + for k in d2: + if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict): + mergedicts(d1[k], d2[k], remove) + elif remove and d2[k] is REMOVE_THIS_KEY: + d1.pop(k, None) + else: + if remove and isinstance(d2[k], dict): + _clear_special_values(d2[k]) + d1[k] = d2[k] + + +def mergedefaults(d1, d2): + '''Recursively merge two dictionaries, keeping existing values + + First dictionary is modified in-place. + ''' + for k in d2: + if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict): + mergedefaults(d1[k], d2[k]) + else: + d1.setdefault(k, d2[k]) + + +def _setmerged(d1, d2): + if hasattr(d1, 'setmerged'): + d1.setmerged(d2) + + +def mergedicts_copy(d1, d2): + '''Recursively merge two dictionaries. + + Dictionaries are not modified. Copying happens only if necessary. Assumes + that first dictionary supports .copy() method. + ''' + ret = d1.copy() + _setmerged(ret, d2) + for k in d2: + if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict): + ret[k] = mergedicts_copy(d1[k], d2[k]) + else: + ret[k] = d2[k] + return ret + + +def updated(d, *args, **kwargs): + '''Copy dictionary and update it with provided arguments + ''' + d = d.copy() + d.update(*args, **kwargs) + return d diff --git a/powerline/lib/encoding.py b/powerline/lib/encoding.py new file mode 100644 index 0000000..76a51d8 --- /dev/null +++ b/powerline/lib/encoding.py @@ -0,0 +1,125 @@ +# vim:fileencoding=utf-8:noet + +'''Encodings support + +This is the only module from which functions obtaining encoding should be +exported. Note: you should always care about errors= argument since it is not +guaranteed that encoding returned by some function can encode/decode given +string. + +All functions in this module must always return a valid encoding. Most of them +are not thread-safe. +''' + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import locale + + +def get_preferred_file_name_encoding(): + '''Get preferred file name encoding + ''' + return ( + sys.getfilesystemencoding() + or locale.getpreferredencoding() + or 'utf-8' + ) + + +def get_preferred_file_contents_encoding(): + '''Get encoding preferred for file contents + ''' + return ( + locale.getpreferredencoding() + or 'utf-8' + ) + + +def get_preferred_output_encoding(): + '''Get encoding that should be used for printing strings + + .. warning:: + Falls back to ASCII, so that output is most likely to be displayed + correctly. + ''' + if hasattr(locale, 'LC_MESSAGES'): + return ( + locale.getlocale(locale.LC_MESSAGES)[1] + or locale.getdefaultlocale()[1] + or 'ascii' + ) + + return ( + locale.getdefaultlocale()[1] + or 'ascii' + ) + + +def get_preferred_input_encoding(): + '''Get encoding that should be used for reading shell command output + + .. warning:: + Falls back to latin1 so that function is less likely to throw as decoded + output is primary searched for ASCII values. + ''' + if hasattr(locale, 'LC_MESSAGES'): + return ( + locale.getlocale(locale.LC_MESSAGES)[1] + or locale.getdefaultlocale()[1] + or 'latin1' + ) + + return ( + locale.getdefaultlocale()[1] + or 'latin1' + ) + + +def get_preferred_arguments_encoding(): + '''Get encoding that should be used for command-line arguments + + .. warning:: + Falls back to latin1 so that function is less likely to throw as + non-ASCII command-line arguments most likely contain non-ASCII + filenames and screwing them up due to unidentified locale is not much of + a problem. + ''' + return ( + locale.getdefaultlocale()[1] + or 'latin1' + ) + + +def get_preferred_environment_encoding(): + '''Get encoding that should be used for decoding environment variables + ''' + return ( + locale.getpreferredencoding() + or 'utf-8' + ) + + +def get_unicode_writer(stream=sys.stdout, encoding=None, errors='replace'): + '''Get function which will write unicode string to the given stream + + Writing is done using encoding returned by + :py:func:`get_preferred_output_encoding`. + + :param file stream: + Stream to write to. Default value is :py:attr:`sys.stdout`. + :param str encoding: + Determines which encoding to use. If this argument is specified then + :py:func:`get_preferred_output_encoding` is not used. + :param str errors: + Determines what to do with characters which cannot be encoded. See + ``errors`` argument of :py:func:`codecs.encode`. + + :return: Callable which writes unicode string to the given stream using + the preferred output encoding. + ''' + encoding = encoding or get_preferred_output_encoding() + if sys.version_info < (3,) or not hasattr(stream, 'buffer'): + return lambda s: stream.write(s.encode(encoding, errors)) + else: + return lambda s: stream.buffer.write(s.encode(encoding, errors)) diff --git a/powerline/lib/humanize_bytes.py b/powerline/lib/humanize_bytes.py new file mode 100644 index 0000000..c98a117 --- /dev/null +++ b/powerline/lib/humanize_bytes.py @@ -0,0 +1,25 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +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)) diff --git a/powerline/lib/inotify.py b/powerline/lib/inotify.py new file mode 100644 index 0000000..8b74a7f --- /dev/null +++ b/powerline/lib/inotify.py @@ -0,0 +1,184 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import os +import errno +import ctypes +import struct + +from ctypes.util import find_library + +from powerline.lib.encoding import get_preferred_file_name_encoding + + +__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>' +__docformat__ = 'restructuredtext en' + + +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') + if sys.platform == 'darwin': + raise INotifyError('INotify not available on OS X') + if not hasattr(ctypes, 'c_ssize_t'): + raise INotifyError('You need python >= 2.7 to use inotify') + 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'))) + + # 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'))) + + # 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'))) + _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): + 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 = get_preferred_file_name_encoding() + self.hdr = struct.Struct(b'iIII') + # 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): + eno = ctypes.get_errno() + extra = '' + if eno == errno.ENOSPC: + extra = 'You may need to increase the inotify limits on your system, via /proc/sys/fs/inotify/max_user_*' + raise OSError(eno, self.os.strerror(eno) + str(extra)) + + 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): + 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') + pos += name_len + self.process_event(wd, mask, cookie, name) + + def process_event(self, *args): + raise NotImplementedError() diff --git a/powerline/lib/memoize.py b/powerline/lib/memoize.py new file mode 100644 index 0000000..cedbe45 --- /dev/null +++ b/powerline/lib/memoize.py @@ -0,0 +1,42 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +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 diff --git a/powerline/lib/monotonic.py b/powerline/lib/monotonic.py new file mode 100644 index 0000000..cd7c414 --- /dev/null +++ b/powerline/lib/monotonic.py @@ -0,0 +1,100 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +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 + + monotonic = lambda: clock_gettime(CLOCK_ID) + except ImportError: + # >=python-3.3 + from time import monotonic +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(): + 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(): + 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(): + 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 diff --git a/powerline/lib/overrides.py b/powerline/lib/overrides.py new file mode 100644 index 0000000..3257d98 --- /dev/null +++ b/powerline/lib/overrides.py @@ -0,0 +1,80 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import json + +from powerline.lib.dict import REMOVE_THIS_KEY + + +def parse_value(s): + '''Convert string to Python object + + Rules: + + * Empty string means that corresponding key should be removed from the + dictionary. + * Strings that start with a minus, digit or with some character that starts + JSON collection or string object are parsed as JSON. + * JSON special values ``null``, ``true``, ``false`` (case matters) are + parsed as JSON. + * All other values are considered to be raw strings. + + :param str s: Parsed string. + + :return: Python object. + ''' + if not s: + return REMOVE_THIS_KEY + elif s[0] in '"{[0123456789-' or s in ('null', 'true', 'false'): + return json.loads(s) + else: + return s + + +def keyvaluesplit(s): + '''Split K1.K2=VAL into K1.K2 and parsed VAL + ''' + 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 = parse_value(s[idx + 1:]) + return (o, val) + + +def parsedotval(s): + '''Parse K1.K2=VAL into {"K1":{"K2":VAL}} + + ``VAL`` is processed according to rules defined in :py:func:`parse_value`. + ''' + if type(s) is tuple: + o, val = s + val = parse_value(val) + 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) + + +def parse_override_var(s): + '''Parse a semicolon-separated list of strings into a sequence of values + + Emits the same items in sequence as :py:func:`parsedotval` does. + ''' + return ( + parsedotval(item) + for item in s.split(';') + if item + ) diff --git a/powerline/lib/path.py b/powerline/lib/path.py new file mode 100644 index 0000000..49ff433 --- /dev/null +++ b/powerline/lib/path.py @@ -0,0 +1,18 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os + + +def realpath(path): + return os.path.abspath(os.path.realpath(path)) + + +def join(*components): + if any((isinstance(p, bytes) for p in components)): + return os.path.join(*[ + p if isinstance(p, bytes) else p.encode('ascii') + for p in components + ]) + else: + return os.path.join(*components) diff --git a/powerline/lib/shell.py b/powerline/lib/shell.py new file mode 100644 index 0000000..2082e82 --- /dev/null +++ b/powerline/lib/shell.py @@ -0,0 +1,133 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import os + +from subprocess import Popen, PIPE +from functools import partial + +from powerline.lib.encoding import get_preferred_input_encoding, get_preferred_output_encoding + + +if sys.platform.startswith('win32'): + # Prevent windows from launching consoles when calling commands + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx + Popen = partial(Popen, creationflags=0x08000000) + + +def run_cmd(pl, cmd, stdin=None, strip=True): + '''Run command and return its stdout, stripped + + If running command fails returns None and logs failure to ``pl`` argument. + + :param PowerlineLogger pl: + Logger used to log failures. + :param list cmd: + Command which will be run. + :param str stdin: + String passed to command. May be None. + :param bool strip: + True if the result should be stripped. + ''' + try: + p = Popen(cmd, shell=False, stdout=PIPE, stdin=PIPE) + except OSError as e: + pl.exception('Could not execute command ({0}): {1}', e, cmd) + return None + else: + stdout, err = p.communicate( + stdin if stdin is None else stdin.encode(get_preferred_output_encoding())) + stdout = stdout.decode(get_preferred_input_encoding()) + return stdout.strip() if strip else stdout + + +def asrun(pl, ascript): + '''Run the given AppleScript and return the standard output and error.''' + return run_cmd(pl, ['osascript', '-'], ascript) + + +def readlines(cmd, cwd): + '''Run command and read its output, line by line + + :param list cmd: + Command which will be run. + :param str cwd: + Working directory of the command which will be run. + ''' + p = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, cwd=cwd) + encoding = get_preferred_input_encoding() + p.stderr.close() + with p.stdout: + for line in p.stdout: + yield line[:-1].decode(encoding) + + +try: + from shutil import which +except ImportError: + # shutil.which was added in python-3.3. Here is what was added: + # Lib/shutil.py, commit 5abe28a9c8fe701ba19b1db5190863384e96c798 + def which(cmd, mode=os.F_OK | os.X_OK, path=None): + '''Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + ``mode`` defaults to os.F_OK | os.X_OK. ``path`` defaults to the result + of ``os.environ.get('PATH')``, or can be overridden with a custom search + path. + ''' + # Check that a given file can be accessed with the correct mode. + # Additionally check that `file` is not a directory, as on Windows + # directories pass the os.access check. + def _access_check(fn, mode): + return ( + os.path.exists(fn) + and os.access(fn, mode) + and not os.path.isdir(fn) + ) + + # If we’re given a path with a directory part, look it up directly rather + # than referring to PATH directories. This includes checking relative to the + # current directory, e.g. ./script + if os.path.dirname(cmd): + if _access_check(cmd, mode): + return cmd + return None + + if path is None: + path = os.environ.get('PATH', os.defpath) + if not path: + return None + path = path.split(os.pathsep) + + if sys.platform == 'win32': + # The current directory takes precedence on Windows. + if os.curdir not in path: + path.insert(0, os.curdir) + + # PATHEXT is necessary to check on Windows. + pathext = os.environ.get('PATHEXT', '').split(os.pathsep) + # See if the given file matches any of the expected path extensions. + # This will allow us to short circuit when given 'python.exe'. + # If it does match, only test that one, otherwise we have to try + # others. + if any(cmd.lower().endswith(ext.lower()) for ext in pathext): + files = [cmd] + else: + files = [cmd + ext for ext in pathext] + else: + # On other platforms you don’t have things like PATHEXT to tell you + # what file suffixes are executable, so just pass on cmd as-is. + files = [cmd] + + seen = set() + for dir in path: + normdir = os.path.normcase(dir) + if normdir not in seen: + seen.add(normdir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None diff --git a/powerline/lib/threaded.py b/powerline/lib/threaded.py new file mode 100644 index 0000000..e5a6b3e --- /dev/null +++ b/powerline/lib/threaded.py @@ -0,0 +1,262 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from threading import Thread, Lock, Event +from types import MethodType + +from powerline.lib.monotonic import monotonic +from powerline.segments import Segment + + +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(Segment, MultiRunnedThread): + min_sleep_time = 0.1 + update_first = True + interval = 1 + daemon = False + + argmethods = ('render', 'set_state') + + def __init__(self): + super(ThreadedSegment, self).__init__() + self.run_once = True + self.crashed = 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__. + self.start() + update_value = self.get_update_value(self.do_update_first) + else: + update_value = self.get_update_value(not self.updated) + + if self.crashed: + return self.crashed_value + + return self.render(update_value, update_first=update_first, pl=pl, **kwargs) + + def set_update_value(self): + try: + self.update_value = self.update(self.update_value) + except Exception as e: + self.exception('Exception while updating: {0}', str(e)) + self.crashed = True + except KeyboardInterrupt: + self.warn('Caught keyboard interrupt while updating') + self.crashed = True + else: + self.crashed = False + self.updated = True + + def get_update_value(self, update=False): + if update: + self.set_update_value() + return self.update_value + + def run(self): + if self.do_update_first: + start_time = monotonic() + while True: + self.shutdown_event.wait(max(self.interval - (monotonic() - start_time), self.min_sleep_time)) + if self.shutdown_event.is_set(): + break + start_time = monotonic() + self.set_update_value() + else: + while not self.shutdown_event.is_set(): + start_time = monotonic() + self.set_update_value() + 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.do_update_first = update_first and self.update_first + self.updated = self.updated or (not self.do_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) + + def argspecobjs(self): + for name in self.argmethods: + try: + yield name, getattr(self, name) + except AttributeError: + pass + + def additional_args(self): + return (('interval', self.interval),) + + _omitted_args = { + 'render': (0,), + 'set_state': ('shutdown_event',), + } + + def omitted_args(self, name, method): + ret = self._omitted_args.get(name, ()) + if isinstance(getattr(self, name, None), MethodType): + ret = tuple((i + 1 if isinstance(i, int) else i for i in ret)) + return ret + + +class KwThreadedSegment(ThreadedSegment): + update_first = True + + argmethods = ('render', 'set_state', 'key', 'render_one') + + 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, key=None, after_update=False, **kwargs): + queries, crashed = update_value + if key is None: + key = self.key(**kwargs) + if key in crashed: + return self.crashed_value + + try: + update_state = queries[key][1] + except KeyError: + with self.write_lock: + self.new_queries.append(key) + if self.do_update_first or self.run_once: + if after_update: + self.error('internal error: value was not computed even though update_first was set') + update_state = None + else: + return self.render( + update_value=self.get_update_value(True), + update_first=False, + key=key, + after_update=True, + **kwargs + ) + else: + update_state = None + + return self.render_one(update_state, **kwargs) + + def update_one(self, crashed, updates, key): + try: + updates[key] = (monotonic(), 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) + + def update(self, old_update_value): + updates = {} + crashed = set() + update_value = (updates, crashed) + queries = old_update_value[0] + + new_queries = self.new_queries + with self.write_lock: + self.new_queries = [] + + for key, (last_query_time, state) in queries.items(): + if last_query_time < monotonic() < last_query_time + self.interval: + updates[key] = (last_query_time, state) + else: + self.update_one(crashed, updates, key) + + for key in new_queries: + self.update_one(crashed, updates, key) + + return update_value + + def set_state(self, interval=None, update_first=True, shutdown_event=None, **kwargs): + self.set_interval(interval) + self.do_update_first = update_first and self.update_first + self.shutdown_event = shutdown_event or Event() + + @staticmethod + def render_one(update_state, **kwargs): + return update_state + + _omitted_args = { + 'render': ('update_value', 'key', 'after_update'), + 'set_state': ('shutdown_event',), + 'render_one': (0,), + } diff --git a/powerline/lib/unicode.py b/powerline/lib/unicode.py new file mode 100644 index 0000000..eeae387 --- /dev/null +++ b/powerline/lib/unicode.py @@ -0,0 +1,283 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import codecs + +from unicodedata import east_asian_width, combining + +from powerline.lib.encoding import get_preferred_output_encoding + + +try: + from __builtin__ import unicode +except ImportError: + unicode = str + + +try: + from __builtin__ import unichr +except ImportError: + unichr = chr + + +if sys.maxunicode < 0x10FFFF: + _unichr = unichr + + def unichr(ch): + if ch <= sys.maxunicode: + return _unichr(ch) + else: + ch -= 0x10000 + return _unichr((ch >> 10) + 0xD800) + _unichr((ch & ((1 << 10) - 1)) + 0xDC00) + + +def u(s): + '''Return unicode instance assuming UTF-8 encoded string. + ''' + if type(s) is unicode: + return s + else: + return unicode(s, 'utf-8') + + +if sys.version_info < (3,): + def tointiter(s): + '''Convert a byte string to the sequence of integers + ''' + return (ord(c) for c in s) +else: + def tointiter(s): + '''Convert a byte string to the sequence of integers + ''' + return iter(s) + + +def powerline_decode_error(e): + if not isinstance(e, UnicodeDecodeError): + raise NotImplementedError + return (''.join(( + '<{0:02X}>'.format(c) + for c in tointiter(e.object[e.start:e.end]) + )), e.end) + + +codecs.register_error('powerline_decode_error', powerline_decode_error) + + +last_swe_idx = 0 + + +def register_strwidth_error(strwidth): + '''Create new encode errors handling method similar to ``replace`` + + Like ``replace`` this method uses question marks in place of the characters + that cannot be represented in the requested encoding. Unlike ``replace`` the + amount of question marks is identical to the amount of display cells + offending character occupies. Thus encoding ``…`` (U+2026, HORIZONTAL + ELLIPSIS) to ``latin1`` will emit one question mark, but encoding ``A`` + (U+FF21, FULLWIDTH LATIN CAPITAL LETTER A) will emit two question marks. + + Since width of some characters depends on the terminal settings and + powerline knows how to respect them a single error handling method cannot be + used. Instead of it the generator function is used which takes ``strwidth`` + function (function that knows how to compute string width respecting all + needed settings) and emits new error handling method name. + + :param function strwidth: + Function that computs string width measured in display cells the string + occupies when displayed. + + :return: New error handling method name. + ''' + global last_swe_idx + last_swe_idx += 1 + + def powerline_encode_strwidth_error(e): + if not isinstance(e, UnicodeEncodeError): + raise NotImplementedError + return ('?' * strwidth(e.object[e.start:e.end]), e.end) + + ename = 'powerline_encode_strwidth_error_{0}'.format(last_swe_idx) + codecs.register_error(ename, powerline_encode_strwidth_error) + return ename + + +def out_u(s): + '''Return unicode string suitable for displaying + + Unlike other functions assumes get_preferred_output_encoding() first. Unlike + u() does not throw exceptions for invalid unicode strings. Unlike + safe_unicode() does throw an exception if object is not a string. + ''' + if isinstance(s, unicode): + return s + elif isinstance(s, bytes): + return unicode(s, get_preferred_output_encoding(), 'powerline_decode_error') + else: + raise TypeError('Expected unicode or bytes instance, got {0}'.format(repr(type(s)))) + + +def safe_unicode(s): + '''Return unicode instance without raising an exception. + + Order of assumptions: + * ASCII string or unicode object + * UTF-8 string + * Object with __str__() or __repr__() method that returns UTF-8 string or + unicode object (depending on python version) + * String in powerline.lib.encoding.get_preferred_output_encoding() encoding + * If everything failed use safe_unicode on last exception with which + everything failed + ''' + try: + try: + if type(s) is bytes: + return unicode(s, 'ascii') + else: + return unicode(s) + except UnicodeDecodeError: + try: + return unicode(s, 'utf-8') + except TypeError: + return unicode(str(s), 'utf-8') + except UnicodeDecodeError: + return unicode(s, get_preferred_output_encoding()) + except Exception as e: + return safe_unicode(e) + + +class FailedUnicode(unicode): + '''Builtin ``unicode`` subclass indicating fatal error + + If your code for some reason wants to determine whether `.render()` method + failed it should check returned string for being a FailedUnicode instance. + Alternatively you could subclass Powerline and override `.render()` method + to do what you like in place of catching the exception and returning + FailedUnicode. + ''' + pass + + +if sys.version_info < (3,): + def string(s): + if type(s) is not str: + return s.encode('utf-8') + else: + return s +else: + def string(s): + if type(s) is not str: + return s.decode('utf-8') + else: + return s + + +string.__doc__ = ( + '''Transform ``unicode`` or ``bytes`` object into ``str`` object + + On Python-2 this encodes ``unicode`` to ``bytes`` (which is ``str``) using + UTF-8 encoding; on Python-3 this decodes ``bytes`` to ``unicode`` (which is + ``str``) using UTF-8 encoding. + + Useful for functions that expect an ``str`` object in both unicode versions, + not caring about the semantic differences between them in Python-2 and + Python-3. + ''' +) + + +def surrogate_pair_to_character(high, low): + '''Transform a pair of surrogate codepoints to one codepoint + ''' + return 0x10000 + ((high - 0xD800) << 10) + (low - 0xDC00) + + +_strwidth_documentation = ( + '''Compute string width in display cells + + {0} + + :param dict width_data: + Dictionary which maps east_asian_width property values to strings + lengths. It is expected to contain the following keys and values (from + `East Asian Width annex <http://www.unicode.org/reports/tr11/>`_): + + === ====== =========================================================== + Key Value Description + === ====== =========================================================== + F 2 Fullwidth: all characters that are defined as Fullwidth in + the Unicode Standard [Unicode] by having a compatibility + decomposition of type <wide> to characters elsewhere in the + Unicode Standard that are implicitly narrow but unmarked. + H 1 Halfwidth: all characters that are explicitly defined as + Halfwidth in the Unicode Standard by having a compatibility + decomposition of type <narrow> to characters elsewhere in + the Unicode Standard that are implicitly wide but unmarked, + plus U+20A9 ₩ WON SIGN. + W 2 Wide: all other characters that are always wide. These + characters occur only in the context of East Asian + typography where they are wide characters (such as the + Unified Han Ideographs or Squared Katakana Symbols). This + category includes characters that have explicit halfwidth + counterparts. + Na 1 Narrow: characters that are always narrow and have explicit + fullwidth or wide counterparts. These characters are + implicitly narrow in East Asian typography and legacy + character sets because they have explicit fullwidth or wide + counterparts. All of ASCII is an example of East Asian + Narrow characters. + A 1 or 2 Ambiguous: characters that may sometimes be wide and + sometimes narrow. Ambiguous characters require additional + information not contained in the character code to further + resolve their width. This information is usually defined in + terminal setting that should in turn respect glyphs widths + in used fonts. Also see :ref:`ambiwidth configuration + option <config-common-ambiwidth>`. + N 1 Neutral characters: character that does not occur in legacy + East Asian character sets. + === ====== =========================================================== + + :param unicode string: + String whose width will be calculated. + + :return: unsigned integer.''') + + +def strwidth_ucs_4(width_data, string): + return sum((( + ( + 0 + ) if combining(symbol) else ( + width_data[east_asian_width(symbol)] + ) + ) for symbol in string)) + + +strwidth_ucs_4.__doc__ = _strwidth_documentation.format( + '''This version of function expects that characters above 0xFFFF are + represented using one symbol. This is only the case in UCS-4 Python builds. + + .. note: + Even in UCS-4 Python builds it is possible to represent characters above + 0xFFFF using surrogate pairs. Characters represented this way are not + supported.''') + + +def strwidth_ucs_2(width_data, string): + return sum((( + ( + width_data[east_asian_width(string[i - 1] + symbol)] + ) if 0xDC00 <= ord(symbol) <= 0xDFFF else ( + 0 + ) if combining(symbol) or 0xD800 <= ord(symbol) <= 0xDBFF else ( + width_data[east_asian_width(symbol)] + ) + ) for i, symbol in enumerate(string))) + + +strwidth_ucs_2.__doc__ = _strwidth_documentation.format( + '''This version of function expects that characters above 0xFFFF are + represented using two symbols forming a surrogate pair, which is the only + option in UCS-2 Python builds. It still works correctly in UCS-4 Python + builds, but is slower then its UCS-4 counterpart.''') diff --git a/powerline/lib/url.py b/powerline/lib/url.py new file mode 100644 index 0000000..f25919c --- /dev/null +++ b/powerline/lib/url.py @@ -0,0 +1,17 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +try: + from urllib.error import HTTPError # NOQA + from urllib.request import urlopen # NOQA + 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 diff --git a/powerline/lib/vcs/__init__.py b/powerline/lib/vcs/__init__.py new file mode 100644 index 0000000..f862c6b --- /dev/null +++ b/powerline/lib/vcs/__init__.py @@ -0,0 +1,276 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import errno + +from threading import Lock +from collections import defaultdict + +from powerline.lib.watcher import create_tree_watcher +from powerline.lib.unicode import out_u +from powerline.lib.path import join + + +def generate_directories(path): + if os.path.isdir(path): + yield path + while True: + if os.path.ismount(path): + break + old_path = path + path = os.path.dirname(path) + if path == old_path or not path: + break + yield path + + +_file_watcher = None + + +def file_watcher(create_watcher): + global _file_watcher + if _file_watcher is None: + _file_watcher = create_watcher() + return _file_watcher + + +_branch_watcher = None + + +def branch_watcher(create_watcher): + global _branch_watcher + if _branch_watcher is None: + _branch_watcher = create_watcher() + return _branch_watcher + + +branch_name_cache = {} +branch_lock = Lock() +file_status_lock = Lock() + + +def get_branch_name(directory, config_file, get_func, create_watcher): + global branch_name_cache + with branch_lock: + # Check if the repo directory was moved/deleted + fw = branch_watcher(create_watcher) + is_watched = fw.is_watching(directory) + try: + changed = fw(directory) + except OSError as e: + if getattr(e, 'errno', None) != errno.ENOENT: + raise + changed = True + if changed: + branch_name_cache.pop(config_file, None) + # Remove the watches for this repo + if is_watched: + fw.unwatch(directory) + fw.unwatch(config_file) + else: + # Check if the config file has changed + try: + changed = fw(config_file) + except OSError as e: + if getattr(e, 'errno', None) != errno.ENOENT: + raise + # Config file does not exist (happens for mercurial) + if config_file not in branch_name_cache: + branch_name_cache[config_file] = out_u(get_func(directory, config_file)) + if changed: + # Config file has changed or was not tracked + branch_name_cache[config_file] = out_u(get_func(directory, config_file)) + return branch_name_cache[config_file] + + +class FileStatusCache(dict): + def __init__(self): + self.dirstate_map = defaultdict(set) + self.ignore_map = defaultdict(set) + self.keypath_ignore_map = {} + + def update_maps(self, keypath, directory, dirstate_file, ignore_file_name, extra_ignore_files): + parent = keypath + ignore_files = set() + while parent != directory: + nparent = os.path.dirname(keypath) + if nparent == parent: + break + parent = nparent + ignore_files.add(join(parent, ignore_file_name)) + for f in extra_ignore_files: + ignore_files.add(f) + self.keypath_ignore_map[keypath] = ignore_files + for ignf in ignore_files: + self.ignore_map[ignf].add(keypath) + self.dirstate_map[dirstate_file].add(keypath) + + def invalidate(self, dirstate_file=None, ignore_file=None): + for keypath in self.dirstate_map[dirstate_file]: + self.pop(keypath, None) + for keypath in self.ignore_map[ignore_file]: + self.pop(keypath, None) + + def ignore_files(self, keypath): + for ignf in self.keypath_ignore_map[keypath]: + yield ignf + + +file_status_cache = FileStatusCache() + + +def get_file_status(directory, dirstate_file, file_path, ignore_file_name, get_func, create_watcher, extra_ignore_files=()): + global file_status_cache + keypath = file_path if os.path.isabs(file_path) else join(directory, file_path) + file_status_cache.update_maps(keypath, directory, dirstate_file, ignore_file_name, extra_ignore_files) + + with file_status_lock: + # Optimize case of keypath not being cached + if keypath not in file_status_cache: + file_status_cache[keypath] = ans = get_func(directory, file_path) + return ans + + # Check if any relevant files have changed + file_changed = file_watcher(create_watcher) + changed = False + # Check if dirstate has changed + try: + changed = file_changed(dirstate_file) + except OSError as e: + if getattr(e, 'errno', None) != errno.ENOENT: + raise + # The .git index file does not exist for a new git repo + return get_func(directory, file_path) + + if changed: + # Remove all cached values for files that depend on this + # dirstate_file + file_status_cache.invalidate(dirstate_file=dirstate_file) + else: + # Check if the file itself has changed + try: + changed ^= file_changed(keypath) + except OSError as e: + if getattr(e, 'errno', None) != errno.ENOENT: + raise + # Do not call get_func again for a non-existent file + if keypath not in file_status_cache: + file_status_cache[keypath] = get_func(directory, file_path) + return file_status_cache[keypath] + + if changed: + file_status_cache.pop(keypath, None) + else: + # Check if one of the ignore files has changed + for ignf in file_status_cache.ignore_files(keypath): + try: + changed ^= file_changed(ignf) + except OSError as e: + if getattr(e, 'errno', None) != errno.ENOENT: + raise + if changed: + # Invalidate cache for all files that might be affected + # by this ignore file + file_status_cache.invalidate(ignore_file=ignf) + break + + try: + return file_status_cache[keypath] + except KeyError: + file_status_cache[keypath] = ans = get_func(directory, file_path) + return ans + + +class TreeStatusCache(dict): + def __init__(self, pl): + self.tw = create_tree_watcher(pl) + self.pl = pl + + def cache_and_get(self, key, status): + ans = self.get(key, self) + if ans is self: + ans = self[key] = status() + return ans + + def __call__(self, repo): + key = repo.directory + try: + if self.tw(key, ignore_event=getattr(repo, 'ignore_event', None)): + self.pop(key, None) + except OSError as e: + self.pl.warn('Failed to check {0} for changes, with error: {1}', key, str(e)) + return self.cache_and_get(key, repo.status) + + +_tree_status_cache = None + + +def tree_status(repo, pl): + global _tree_status_cache + if _tree_status_cache is None: + _tree_status_cache = TreeStatusCache(pl) + return _tree_status_cache(repo) + + +vcs_props = ( + ('git', '.git', os.path.exists), + ('mercurial', '.hg', os.path.isdir), + ('bzr', '.bzr', os.path.isdir), +) + + +vcs_props_bytes = [ + (vcs, vcs_dir.encode('ascii'), check) + for vcs, vcs_dir, check in vcs_props +] + + +def guess(path, create_watcher): + for directory in generate_directories(path): + for vcs, vcs_dir, check in (vcs_props_bytes if isinstance(path, bytes) else vcs_props): + repo_dir = os.path.join(directory, vcs_dir) + if check(repo_dir): + if os.path.isdir(repo_dir) and not os.access(repo_dir, os.X_OK): + continue + try: + if vcs not in globals(): + globals()[vcs] = getattr(__import__(str('powerline.lib.vcs'), fromlist=[str(vcs)]), str(vcs)) + return globals()[vcs].Repository(directory, create_watcher) + except: + pass + return None + + +def get_fallback_create_watcher(): + from powerline.lib.watcher import create_file_watcher + from powerline import get_fallback_logger + from functools import partial + return partial(create_file_watcher, get_fallback_logger(), 'auto') + + +def debug(): + '''Test run guess(), repo.branch() and repo.status() + + To use:: + python -c 'from powerline.lib.vcs import debug; debug()' some_file_to_watch. + ''' + import sys + dest = sys.argv[-1] + repo = guess(os.path.abspath(dest), get_fallback_create_watcher) + if repo is None: + print ('%s is not a recognized vcs repo' % dest) + raise SystemExit(1) + print ('Watching %s' % dest) + print ('Press Ctrl-C to exit.') + try: + while True: + if os.path.isdir(dest): + print ('Branch name: %s Status: %s' % (repo.branch(), repo.status())) + else: + print ('File status: %s' % repo.status(dest)) + raw_input('Press Enter to check again: ') + except KeyboardInterrupt: + pass + except EOFError: + pass diff --git a/powerline/lib/vcs/bzr.py b/powerline/lib/vcs/bzr.py new file mode 100644 index 0000000..e47d8b2 --- /dev/null +++ b/powerline/lib/vcs/bzr.py @@ -0,0 +1,108 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import os +import re + +from io import StringIO + +from bzrlib import (workingtree, status, library_state, trace, ui) + +from powerline.lib.vcs import get_branch_name, get_file_status +from powerline.lib.path import join +from powerline.lib.encoding import get_preferred_file_contents_encoding + |