pax_global_header00006660000000000000000000000064146640525260014524gustar00rootroot0000000000000052 comment=51570938d4a558578fa3512a4b546584530e23c1 powerline-2.8.4/000077500000000000000000000000001466405252600135435ustar00rootroot00000000000000powerline-2.8.4/.editorconfig000066400000000000000000000010651466405252600162220ustar00rootroot00000000000000# 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 powerline-2.8.4/.gitattributes000066400000000000000000000000371466405252600164360ustar00rootroot00000000000000*.rst whitespace=-blank-at-eol powerline-2.8.4/.github/000077500000000000000000000000001466405252600151035ustar00rootroot00000000000000powerline-2.8.4/.github/workflows/000077500000000000000000000000001466405252600171405ustar00rootroot00000000000000powerline-2.8.4/.github/workflows/main.yaml000066400000000000000000000020131466405252600207440ustar00rootroot00000000000000name: 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: [3.7, 3.8, 3.9, 3.11, 3.12] 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/ powerline-2.8.4/.gitignore000066400000000000000000000001631466405252600155330ustar00rootroot00000000000000tags *.py[co] __pycache__ *.egg *.egg-info dist build message.fail /client/powerline /tests/tmp /tests/status powerline-2.8.4/.local.vimrc000066400000000000000000000007651466405252600157650ustar00rootroot00000000000000" 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 powerline-2.8.4/.travis.yml000066400000000000000000000011341466405252600156530ustar00rootroot00000000000000sudo: 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 powerline-2.8.4/CONTRIBUTING.rst000066400000000000000000000114501466405252600162050ustar00rootroot00000000000000***************** 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 `_. * Submit an `issue on GitHub `_, 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 `_ 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 `_. 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 `` to squash or reword commits before submitting a pull request. * Submit a pull request to `powerline repository `_. powerline-2.8.4/LICENSE000066400000000000000000000021541466405252600145520ustar00rootroot00000000000000Copyright 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. powerline-2.8.4/MANIFEST.in000066400000000000000000000004241466405252600153010ustar00rootroot00000000000000recursive-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 powerline-2.8.4/README.rst000066400000000000000000000134521466405252600152370ustar00rootroot00000000000000Powerline ========= .. 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 `_ 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 `_ for more details. See also the `segment reference `_ for available segments and their configuration. * Check out `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 powerline-2.8.4/client/000077500000000000000000000000001466405252600150215ustar00rootroot00000000000000powerline-2.8.4/client/powerline.c000066400000000000000000000073231466405252600171760ustar00rootroot00000000000000/* vim:fileencoding=utf-8:noet */ #include #include #include #include #include #include #include #include #include #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; } powerline-2.8.4/client/powerline.py000077500000000000000000000041721466405252600174060ustar00rootroot00000000000000#!/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)) powerline-2.8.4/client/powerline.sh000077500000000000000000000020371466405252600173660ustar00rootroot00000000000000#!/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 powerline-2.8.4/docs/000077500000000000000000000000001466405252600144735ustar00rootroot00000000000000powerline-2.8.4/docs/.gitignore000066400000000000000000000000071466405252600164600ustar00rootroot00000000000000_build powerline-2.8.4/docs/Makefile000066400000000000000000000021561466405252600161370ustar00rootroot00000000000000# 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 ' where 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." powerline-2.8.4/docs/source/000077500000000000000000000000001466405252600157735ustar00rootroot00000000000000powerline-2.8.4/docs/source/_static/000077500000000000000000000000001466405252600174215ustar00rootroot00000000000000powerline-2.8.4/docs/source/_static/css/000077500000000000000000000000001466405252600202115ustar00rootroot00000000000000powerline-2.8.4/docs/source/_static/css/theme_overrides.css000066400000000000000000000002351466405252600241070ustar00rootroot00000000000000.wy-table-responsive > table > tbody > tr > td { white-space: unset; } .wy-table-responsive > table > tbody > tr > td:first-child { vertical-align: top; } powerline-2.8.4/docs/source/_static/img/000077500000000000000000000000001466405252600201755ustar00rootroot00000000000000powerline-2.8.4/docs/source/_static/img/icons/000077500000000000000000000000001466405252600213105ustar00rootroot00000000000000powerline-2.8.4/docs/source/_static/img/icons/cross.png000066400000000000000000000007311466405252600231500ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<{IDATxb? q0 8wxʧ8 K@[?&}@͇@P5l=c@GzߡAl, }?f `P­ i6`I g VSca_ P,~c63 \fL@Ͳ2 ]/3E @{˰4{Y?>1 aƑ,Ä9jF _ ` b0vjX]I 73iBfFJ3@VlaeIENDB`powerline-2.8.4/docs/source/_static/img/pl-mode-insert.png000066400000000000000000000153561466405252600235540ustar00rootroot00000000000000PNG  IHDRvf2bKGD pHYs  tIME -FsNg{IDATxw|UeFz 4  U;qFQ}g^:sxQEEFii!$OG䤡b?rY{ﵞlA$ۘ7Yz'MߛJ_8 8xɀz6.NdZ AU ҭ&%^qy4+}Pۈd ^?cx(z) b G %Pw`֨PbMEB_q"x*v(.3 >ZU1HW'ǗKHrG/&/ A._.?wP'= ݁:s9>L7^J޷$|[ž񸷝fpQ7$B5oմ0%l? 9|5Sk93~͝3MOia85{j'#L=#cI4[^f4nH6-el*JoC}|00??Ĺ&Re{'9 yj+ilҋ%wơHϧU/~Cz*ᵙl,e$AU`n.- w|n -d*ύ^DHvvWݯ.Ǫ"%&ɛ!7:߷ņ+&'$hB&LaW<2Fe1LH`ICOF4a2OpAiFMLOf9p$5XPǰ3]ZZ ֮cAK»vuaɋ) p_'Ӝ?(9rǏ%J- YB#6y'Ѭ'cC`{&-v} ;JaMUt7Dgx;_j;Ľ$G3.1W;%zr D( wǖ3JmT=KH ZsK_f r;qݢ/f= G٫'&OB0'"x?R̞ѡn3(5^ACA,ڶA] Ҁ,3xrRn凚&)p @͹: aCQ,6ڧHUKm(\ j|6f*ue+y.>=;{Opa4\j(壔EWv0y#9D(bD$$DъE-"3SXtRi<#f4SP8̞* 4Q=';6zbfFaӌx"a^&ՐZ#‹CS^ $v\hs 8*a<,'ؘׄ?ܽ6I:^*_4+ u 8RIywA${*l8 g>(\G4/EGXm (Vgq1$ew!>ύ/g Pi|9r=Ek UXuzP~= ܇XAskKrPxnWuCy׋0ed{Zf@|?x0Vr.<(VNmD T&$' dv5tjZNܔqw#26W1a/*.{G񰧕i%Sr8VȰkXmjBL:zC3Q$ ogljpu>vȀ6zA`tLC_;5T:s#;,X?t5^‰b'(ppS6ǻ_RyM`}\f {K Ryu쬶Rs=v-/}ԩxYA?^͚/xɻSu?O- )ڿ6i䓩s.wΚ] .2̍_z*]T5cJcfu+YVpbĚOؔf=/0ـpaPjHk6t& LJ=*<69 p7|s'>Yɀ6ONM 3HVRy%"~w޶SN}}PWCU,b->uMRY2Xs,8hqAޯ# g欉շJmz%P;&j[I.J#\.e, WFH-TJaQ.y NrDC=F{;+/^Ǎ&s|MQ2s)ַ_CAt'd!7VֺΙpYW4Td!N#&2ǵo$=#_^ljʩ,m3rGwf;k$Țoy}c>v⾻߰n|Y?& #Tw-%p0dmԖ*dFntMű8Ȍumfww6!Cu3io8  ?M' ]g(Q |`K3/1n(=B[m#Zœړ&Z4+g|9w  ]>5poxjyo!>iCKX2nc[e(%3m_UbWZ-*&H͵=kq)7ubGOXxcWVaǡZteԋ4yȸqld}F-}dN q0jM245CIGx',YN&SeƚrSb5Yj>|}񁀉M鍾+u Kw /e%"V.Y񳝤 @oDڛ#g$1,f s"fINoɜ|]HCYf꘱h|tSfa-P)ϭG*h' هWol BSQ&(+ڹyF$ŠN(&zE5MYhjl&3╤dV;TQ#Rɕܝ;B;\2 KϥG3Ccd̋ͥY PZ̓@u"QJq*P2SMf8o'y: !zҐNd.#d#$Q`Z WMM& R60*/jPY#agtR&UuFOK6mل2;J3ƾ*Z p-:pFS#G!gȽ; i(Mf}FM`rÔEbG`hmo#b@K])t`+#xir/*e`'y6=뿙11iBg.m@_׀79g3+C%LQbyo 79 |CѶQ E-SF`-7(B=^ޑsMVCtT$2:[w|7#K #rt",4Pk$<*ZGll C5z2w0rV[>5#!~H?PQ@5zCxkTOc Xzp|pW΢`wЋI# cө~~:oA[ =͋_47Z!lIXɮ4t8w6yr6>Dk:6eS\V3zۉ,:J B#OHŴc1q| 5_1ͅKff/]H]z5m1wG9_ܐOɗax04*xfKZmF{! |dFz8&ZV/4%9#j2*D'6 %d5(Ac9ފwl(vD_yJd1ԑY)Jbzz:%X-EI,RgNJa'nhvnFs5)kEZ`ewKY:̎d^Lq"z<ѱZo<3B]̙lfLW`SoZu|:)Y,k\r IIA<6s6/RCFxx+Jk}yeܝ/f͂xUNYȚw2[+KM&E>f03GNgg"W%gڔYԐLRwi@AEIXGIET$*(PR*;70LjQuGHz^ڞ:5 G ci,;ێğZ+z2e0sMA\3F3C-/ȪfFo52(/8ϛ:0YǺrjKγڷ|܌O8Wx㜾g%Z(kۇ&@m^y fK|Y͚fFIăep>S0V$sɛHW|˃M%H#Q#}GYI 2rJꋱ]SW;<(njl]{(_GN^i`dIo8sPz-hR gErW<ţF|~9H T C-4W/fŬY|K=_3),T<]\d><`KS7m L#q@kd|x+In@>Rό8҃(A 1JY7\K}LPjX6t:ϣk+&a]:ç]HolUJkaAe !w<s|e_|ݽK2L-ěGjyB^БSx2WILֽ¸Kr=d?[G 5E,3P7H7M8xaO=[NܦnuAp&A] R;e]4KgdX66y9jJA3F뒑W #Y¯u4YRS؍ζ\DA]qaX*ّ\@` %~\z~_LQ ُߚE AaIENDB`powerline-2.8.4/docs/source/_static/img/pl-mode-normal.png000066400000000000000000000153371466405252600235370ustar00rootroot00000000000000PNG  IHDRvf2bKGD pHYs  tIME -$lIDATxw|Tוǿo4w!@Z" 6I;mmw)nެڱ;cl\tE PAKQ/:}#!4 |>Lyw=iwTw~7n_;e8Qk',e ZAZ[0Cc1Dd]|߳lگ8]D^D<񛸔6T9w9FeJ $hv,3- wX 0e/f`h$) XhI]zvzѠNإ<3|#/o}> б~ jaw×Y ~ 5?ϏB10>Z;q%IxrAJimg7y0m݃ *>87|}Zxv}9%.LNN|3 gUm@x2jax-VE4q: soN'l#*#Ĺ #Xܳ,O Din$ozgTsFГc|ОZ˟W^N;yb8k>I_Ӷ"s|>a*l2 exGe͠bshۼM!,$9(F$PJi("eQHR}U}:gŏfG"?Zc-;+M,eT-b&2L7CFhY= _'ya:@+lD*XY۩m01EE5Ҡhdr=eET$^ w߂"T{z I!;!(lHfC%tq*rhP ̘?DoȮ9`9=ʂ 1Isia_/0"y&ftW<.VtjX{izp!fęϱ/S atB _jl\ƃ LbUxp+CYMEe ze'b)8Ʊb񩏱x AɊ_f=H"9ϧ17@%K1 9{v!ќ=e!ywL|Ƹ8~F;K}uJAgP_ԄJ//%C+w9Ii]>H$b]h;nx1T1|B*A8O`Ij,u{7sLch,+5Y)Xs<D?MK#-E*ʃ r~CO!}|`i,ݥ>DxZhi]scxQs+2|~ #MzlW2aD8-#'}!erjfO/EvD &:D| .ƾL8N#Fx6swXf m)0 qf\G?FuEUjڬU]eIAބr9ܰ fGBrpPv r"!oߔކQg nR3>$@[)ȭ,(|3RtVaRw#[Տ?ANmM]o,mTdQ% "ګL"*^DϮ*8'Ք&CI)ˮ 8==3>?ˬ!A/ڏֱ`B3֦lzn96|g-d5;:oՀXoǀ5QG)ĺ2nJ EkMTK@(~C&L\MV:44I@_!GQGIQ0o4 {uf.voM]˦B#ͼf kּ͖r3.#WBZiW]͝D%UG^'(?OنNGч%NMNa1ȭqTP~<6 si[q&OPݢE}$j!a> P?o {.Qqjb ]Ц 'yH"%/<Ǣq8I12(1c "zh|1ѱ oܿ2H܁Nz#z55+\,`^>r[`2yf5^efy &xs{65}3rzha$we̲훴DbC#,-i̋E^^<02*;lνYp4fDg㮐\D&02p\ʼ9-IQ5LRl,FO㴎}ohЂD. v ?V3V$ʦkqdGϲExN2n,jn0ci``y[y)r6/0cBV͞E|ogb$O^6S;f/SݴKP]ʊ iݰU,gD3zS)?]¬c 9ފӸ0L!\g33tm V d8IL@EgwRxe¦ אA.EFd/~c 4n| Ƚc?5f$spJ }\$ V,O,86fvϗʵP+}z9;C}Bo{h\ 71Y4l!];i*Rc o:KX:m$ugxFOxRO{j"m?ȼeK W}I6^Z CCyY$͑v63rꉗthUp؞!H9 YhX^G!QM\>Wo}բ6S;8ql-hp 3:\E^nuwɲ6U!ϰ1(>K^CE@d-+<+Y)px@DlfX[Tח ;ٰSSpg*ٺ=$ʇ}N.%A6.ON%0u4`< ZLP0k4̈__ aL8M:[ oR'#o8ˎ/9S=fd(Ϡ/ZUE&Cai:6,Mh`bSR֊́vQKND%3 2]]P(3k8å8vt4R1-2Bp:* D?Ϫ@Eue *fK"C"HB{® 9dk< DǬ彩z3egOe uډyl?_ӘAzQvԢiVC,6 nѓ* @L4E27m#}:)cЭf)9L&AD "A*G"zaD3:T&qq^ԟ KGZYnwW}̀ [Quޢ+޳DzcU@WTƔ`owBVɢ8KْO3'Kn6|ۚ"bn.̉o9ng0ͧ~)d'@'o?5 G%E6B*/_ |/֯gWĖr{)}2^|?⇓}UC Y̏yӮo_,LTh2(f8w5(wf#lzC/v9Q(%JN f]*2?&KNcy8OhGԼlq'遙D8 Q{=mIqn7\cіRi b҄h|=>vJ5>X_O'lM*͡N4Qv&y75PX+'vBHLMCQͺ5D* R0؎t$u xA)FR_of>?I)>ߞE` T䠮l._&|fA} hUqȌ<c+=ɒא0>@"sb1]~ys9d_{ $ѾQφ䮸Sm~,KYOSW1յGDsQ|G?'[h,ҀҲ0lod~i~r>!R'RW3[ b'%2('j% EdD36u*ʏB_' NL^ vCk`k0`:K$ F̊|:Wyxlzk)W=҄\ΦHpE5nx.KqD]ہMONRov'~'ՅW?.L~R3iNWX}e聶=29N`g~)'Q߀Z|݁V|6v91**ipD(~ai=pe?%-id|G3ʵSyXS9ε`LÙml/ d>y0Qut?$Ǚn^#Cێc>l#OtdE+dTJÁS`,޺B4W]`XX2ę]T HІuap`E:o/nW7~x 1m@N?k}ufmrMu|o J|P" }cvn$%`pJ\љؾwa0R>3;ʜ q4yڻ}}]^M{B??;?Й ݽtH^Bnɤtw9}WOX|ĝDD楸OEDヘCt_WOnWĭK0|?P7D\M8 )w)ısCT\ڌZ*@j T,rkS#p,Q+jZ`.(?)ּ3$oF>.<%|{_V]AԤqx*8vhsg֡۷U2KOw/c; /:? 4*IENDB`powerline-2.8.4/docs/source/_static/img/pl-mode-replace.png000066400000000000000000000154451466405252600236620ustar00rootroot00000000000000PNG  IHDRvf2bKGD pHYs  tIME - IDATxytU?ګB A" "*LfEǶvz챻eF[[ ".(aš@BR +TJ# BR" 99{^|G8lGĠvOpc5q^l$GZ\vN/04UQ]рE^ 3(|Ovs|?" &*.A<=OV YœGJtC\Ÿt)+™x!e=6Yd K|~a^ޡfoB{|;|I]7ѸsF^ j1~AcFa8xEl׎ejs(fGvݠ" MW߱QywpQEmzvmҒCP ^1i Sqoxr{E1lVYq+\S=NͩoГ9RطfrtͶJzWd.W੩DD#SX0gwkw?"!QzΔ8|c()@DJX#@qGuSh34>%SP `_H} uJ$®Dr/:,5UВQvk3{X('8c;n;"))CsPWBMCϷ rt:N\y:|a&=ٰ ^?*t:GF2 tf<u+YaEL vB$9QGؙS PD<ȿ͌Bu][2}6PD0)ҩ^R`PJ%r2d c{F4*쀀T!n)boQ(?Hss-ICYEd7 OdL ; 6obËH*5g˜w=ٛ6):L[`|ж>A[u)ٻy{DkȮ!u1oPo .ĤL--|1D-%x,iѷb u!fx⬧l/T8a^q_ vY=I!|t[7 ^ !eE6.)rsә?$۹(a>@MiENڕI\w>6XUf)ߖ*@c*#[+oRA{ߡ[ 9'Xw|r-88 Xr2kཥKYteS1x(N2v6Ϧ3#]3;;NcAͤU99l]U:l Dxk66j+v&{F9 u\dYU'lW4m<uʇpHqTy,dWI@Ъs,RwA@1\Z/ SP:P/N: }Sbr@ܤVZ &`u#rKoq>$u, _b*HEI~DxpVQF= h,u|Rr,UF.$hv>ӅmZ+Qj"§{6Xʡyh'3& Du("%W*3r~j/BFW=AR8o*kO2XNC,#PpGL&ݗA,do^ \BSBD+%Gsi.?O\Ȥe&|dhO>LEgN˜G ?}Z4K[-cmyR.}u _y&- Z[0D%iE^'Zp,Ձ;mr渤PLVZ@7.>yod8 щc]1V qh=?ݿWC$J7pE]o6[cUoljs1'ֈG8XOm&KwcUkC5:So0v6Æ]"]SMgع'&u]K%G0oX.l"v&mQ ԗ$cMA33m*&DyZąE:C r+u+Ǝ@ [ 25*dOpckJ]א.Z7?+ Fgͬ,gQZS-@& -|RL' WZp,ܶ220iCIaFl ( Bx[g6 cyr] 2}h0Sl|+kR+2I,.֊!Ca71at) &֯FN]/&LDFfd@P(36$y_14c'Obdw,_}Օd4//&Do.$Ա!HM&KK֚0VQ>0]A@*ڿ2r$Pr 7km\ތYY"4S|bs~Sn]{sJ^PwCcyI>BEP2Sd@(&v@ӘP*N0ޅ b[ n-.HHDъ""IxH丨tBڮ5'9)tWe;DBMEh[~*cme]iP :,^8[!{=(fqQ{l75KEZ_ĉrZԣ7tCL+p/,-Lp}nh^G;J<" `Y+*-Y? ?sMD.p X|d Όܟ=!l¢?Kv8^y_뻿`_5\h+ɋ7| T[ixۙ"A[]Eɩ\zнۭлXS^nTz۶Kk;v499u êw_V  `Y:ʸ/ۀeP=8˶.'Rb䮸Cw.i88)Y4FmGX)޻ G~ɱf:ۮ;ur3 fʵrM/YCBP2|*=αm[z[}rL~X cDlpcLgO+=ǏCbSs5pXYx?; |n=;\2Mt?ڪf\|zdž0Г-D&\Uc%K˸Y2_`Nš-I9%l:T-%֢-~طP]#y>u 0R{Z{߮~~bC:rg>K:FrX>q]ؗWW!8rN++'6Q>g\Lu)v¼'FacYٻ 'hXE d9c)mzD9O/ԑk3%Pm,`(d9c;~SSMZmɤ7W $pUe3 v v0#Y|YZd0@hBՑ/Y\a-y x',iH8=wӭ<25RK]pc5q^~lØp[?c 1)SctuGgR`5|y?7~481t@a֡b콕n驠"l&~]5{T{\0q}ΧD楸OCxdw׆o^^{q+}/x⇣{^gVk4TaIf)sH;_u%G^PK=A_K׏a({6Bk./vZj\lѺhլu]=od~{>:Aʈr(3} j'[C%0{ǺzvOkdUN~}cn.{5ԏ*AIENDB`powerline-2.8.4/docs/source/_static/img/pl-mode-visual.png000066400000000000000000000153241466405252600235460ustar00rootroot00000000000000PNG  IHDRvf2bKGD pHYs  tIME -ѡaIDATxwxו?tz]fh0.M'1ۉ~q~٘ubv &6x]D7HBm44F34 <<<}={įz,'Rg8s(B-Po>'U4rٻ"mviV,\ &#st {5H?P9cYC귮=Nyz|̩\DzߊI{B2șdp #608tlc $/u.3,>AϽ_/I'zuV*_j~Q~}῏@{ -Cp D ˃NRBt;Gk}osWxtleS O}UM&w_DJZ,j{ %UX2Yx*aT91{rat:dU bT22R=OUF8$I*۰7IEHj-\ȇƊqFD]r7r3 <0*ci!)dvrp x?1[YJaz)e%,]H1zaꢇY8k2c#mvg,|k (owvl AEH5/sg8QYJ9oozP%PX+s{|/){C_D2)Q%cm8>~3-ގТW&.i\sᰃ"E22C]_Q\spPTV7zNhdu\I1che$d0.Bwɉb*kwQc ŦhN}3>GN˖w7[4U|4n{ӟDW+^ݻ8BT(=DGM.nDLIAA=/TEMc . A*‘K2RbݽbE3YR>X;}. SQą1Ox{ogk, D)DKuX4=cW2XrDIT܏L"jTm/l| 1U143 gb,C2ypA /,^Mn#ky{*V {yNVLz\ʕ?eQr~QC,@.ğ 'Gˎbge[!SgkO6./?G;^[sf9ŗk J2O'VջLPTD@ʌjaʏ.N~D ]:O "AY%pSgc -\VZŻvecO05Y44`th0دyG@\73#x~cxtJJ7η> 6F>n,/ o^$0"<(.]ǥ34wQll 6jΠu'UOm7Qr}BW4[zbE mFNkJR6]uT ]0VqtWٌ 5h'xD'R_IT\ڳw_ F$)Mh dx`םbӦSN˱Z~3-n SQVPpq4P 7$ FE7qJ "c$Z8QHN:-()=LcLf~\wڞp")N@~j +nOÆ3K_UZ6+x[OWd5rbPQAHbڌ*ʓYEI Q"5*PESF<[ 4Խ`C-\:Q@mh(oN&$jBN03CL f{\U1~-a)cl:Q7SO'gd2#L`l }c۝k%HK#6,Q#܎b zq B:;_s'P/@T <+ҳp{tQn//ӿ7gE֣ۿNbOeye-|;*p x0gQ4Y\0cQt;0Y2'vS61Ia5JRt»xUM;Җ6?Yg뾦Iz9[VCfeӷUphk1˞͢6|czvy Z[Й6a6"6좀 ,h?Ϟ|/;K6f,u8X²iSIJ~˝Ll*' _4 Ia2#d<>U*:V,.)SyFy ըh,-\b4 km*zs)S7'. xEpķ,&c) W]S_$7YˑE$-N Z$%|>ՠ+^INȷ< z]oPC,"~ =juep &( ]g?6_5Z5ƩHZ{xsJFcZAwCG;;_LJ5g&(@gّ+NI}5]r[R?/j"S.a򇙝 {ut~3o} i y%)*ow9h'_b™@pi3Ԣi6شxnI@ReFtG^6t_U:,[n"Ik⛍ip{_R{"2RPwK^GU@\m+YQl]I _Dۮ V[7xsg*۴}z>!C3-6ĽB8QvAX-N(9ŕ9m0<9ov,9Kwva'_3$}Dg,A"K #-WaD+FT&7 㩒^֟^ KKG[(:'bXP%ޝz^Ww O[Xj4tަ+SHJbvmix#8zJXj9ɶ^5f D;"bm)o8ig ͧٔAeGUuu[|ojAg[NP J%$yQ\ _τaN@hI.-WF󛣉Ի#҆s:7C_c=]>$& ( >Y4qAN|f*~nja#]`kT+?&2*Yu7ʉ=0_?F騣\o fKX(-T5u$jb'0AY%m j@rt,''ۘTDCe>,Ne7Nj'gF"-uXo/OTĶJg)}"^x?゠M9<,?wzL7~8 PSw*)yGȼ6/FҢq܋alD3bکR$|d&R9;kQYu4ђ>d=4XwzA4j'>@&搕}Ӆ?6}9pf&KL)vZn?;i3O!R"y yf9c vRv y: -e {h5rF.XƂ 5sN삊q[νEm}KZL8h//AGzҢZ|5#c4F)W9adßpTc&"5Q77q;^n,d{dP h;p Y >Q[y ,i9uP{* E8Tcqo4s~GĮ&4ږ}.tصQ8<Ǚ3+Y Uʉ_#V|2dA#Uɢ쀥 !'tz3[JØ"{kP+j縷 =b7vݼȢ#fydR }stdU1KbO $%^bnwݻdɓaNoϥ_Lj4:;Rkn^Y)Tx50q@U'?7v/&C6$0:%|06._۽vav:,[ P=6 s)[^k+&it2'(av=NQ/)18y2Ä\ ?;1Puh4M&tgIP=y a%lژG>>}NjK$3>FݱExOM@l=^?/~x;U{ușݷ~HR(+k٢v:5Դh]4Rouk^)ߒɰgpսyK_/Gk;TQLEW(p Uc ݹٮ[ w2R&Hw{sv%lG.89vK,{t&"o _fA;$|>?  Pj'Ǖ2' pL)vę$No0阐&_C'EX _F@em0R" p"OX6(+fky*:9FaILj`D$=ؖJo"D( y+b:+pi4ack}R>!-n>+fH9i7m7qo y"rk WL`ej#im=ҹ34*isU#ߍȮ`3VCi= 7d ,+Iy)G=˴i-42P6, &36yhreϟTLK-0)uas1>K/9̜vY8xR*2p,d<6z Nص^Η08}6T]^ zȾpWJ3qGIJAy%IȜNZ`%ߧ`tC)pɢ)!8 oT [Kɩ|FiǛ [w8ة,)a)ih"0 }[)2*JN N irOJ? #ؕ f \EAp.CA @X<H HH)EP,kYif)lA(6Ygi2:GY= Zd'T!jGNmQ~(*Eem&rE(("\8๬^b?RnGz |'{= ˴ͭ5 ^{8#*"zՉ^g?B%$j|h ʔTI-ѯ?<:pOЙ<$|w*=He0eq$Yf$,F:01G/4Xaa 47]= N+q(BIgOD){'łl .B%PW&|SZH 8g^Ul""|GZp!&i.#-9KF$$YٌN⊧s*Nk/| bfO;=E L'۩uul<@$F; Uu{ @_A@|l/l+x81K1ˈO}THVL7svA y>R-9=\ @_ݻصc)#Cg<6űT5,.>(a>@}Q~NgpB $Q%wpo#᳒ukb[PIZ  'n*\`F?%1a@|Z24[kְfGv`cs`e4-X릜wT\ʠT/|w kuD$/`Kf.!BCM;d+g^;[Si:?f[ '©o933S33zU(k% J7!Tw7b)|t7"SÚ5kxoK W`3+:Y4Ҥ(RfܶpJ#L~,& !5N0;"eGp*_k z+k?ZdžZ XNui-_ <ڿ}?WJBc;TSueܔ@8rP]Mԛthi“ҏԇai,IT!\2.ߚrS%}MFśyo֬y-f\Fⅴ4Ү<( ;i)KA:O4Q~*& &R1JDj%N!c[㈻fx&m= ?L̡EIB(|7~8`'fy\ַĔ-lMN zE8K^xEc=q*bdh[oRcDb6 acs2* #s:데`|@V0cV3ȯ(n7k0y3g۳# ȜEoNrW,{xѾQK$642B̼(_(Æ _ℓ`6#:w"6Yl ,p!FPiH rf$F'/`e7zvu >7~C$J7pIڵvobE ȝv<]RƑzf<;l䪹&Pbwݎ͂U:mw0$bĖ Y5{;n"t>zL혥LYBt>o,A9v)+/ufrz֞yM]6Rlt %x+N0]͌е)X-XV9$1QkwE ƺ6\C1;V̖q Mp(:Pleplo-7"E>~iot;[@1$Y? "ݠ;.=Q8{@rIaR(>΂cSafi]]%]qӗ6A@pgȽ;Bm ՜U8v!&4Uy m`3MEjsb7MgɱFRw'-`ۏW!dx\&v= YK\Fڸ_~ݗnO04 \⚭KRܜ;;0ќSOso?G u]G ѽF2T^7RE:l-`M~"^' cgn@ENx*r;XK y$ƏAFF_=`"*j"nY3Yɢ5hL+TǨZ$`3gڢBg~_ɆrZ S]@& +Џ⪮yJ:"r+n,Y]ajz@YaFZ(c*āo"6~:1yYv|ιB1#C}FT~ѻ-z 6 NGIgi*F#LVl]] D9.ݑ:̌;'pVv-yALcHJ̬EL;zJJǴ8˼ _<Ýk.븪Y@M6Ư?IɳBۻ Un0k`D^A@*؋xeNȑ S\U($2@f}Wԛi?+k>^+['v~McE?Qmp[ c$ȻUO@63Eܴ|餌v`SҚͧL0XO(C a@*h)L"Rߨ|DtU]6L^iϢvS$NLtTQZ5aG><Ҡ2{s zNYϖ|5]zE0ېjss gN|9u;B[L%=x)׈y#se\ vg/iз/3hm2%9n *vGFUϘQ@=4MWKޝho%=ҦDM' >QM F4Q'/Di# $txBl5j-]ؤD=1HE3,鋘aBvM%.,Q3 N$DAy6WG xV^y5~ybN \ӎI{F ~oͷ~l?1C? L@b~3k<by `DkAy0Sƹۯ ̄@c|iV;ԻQ+,v G)Q4v7Z1a^t25eKy\F{8b-4gdK;I$‘BdXpӇiHsf Jc&DA $xSp܀|]N~)z?Xe%ƞRiu3t7)Z9MDdmn6!bVn5vt#3\= Jq>7} 7iߠHIJ,Zng5h:'u]-egsi0o2g0k@%|Chd.[)L=ϑ˛!#[%l~6V׉ wMh3cIXθTZ= %(= "eì?3\}gvT8AA@"iط4wc>Ɓᓇ??;?Й ݽt^Bnɤtw9~WǕ+ >;cJq Kqϟ9?};-݋$;9ëݮ[GY an 8 )w)ısCT\T!$yyF9Kܥ0;)I6Up<# 7DCeECc=Dod!_ƈw R^~šuz R*IENDB`powerline-2.8.4/docs/source/_static/img/pl-truncate2.png000066400000000000000000000126451466405252600232330ustar00rootroot00000000000000PNG  IHDRwtYbKGD pHYs  tIME ;>Sp2IDATxw|eǿd;B@ JM ]wWWu֫{w{])  `轥H2efRϼ I!9|>;y;9as"=Ϗ>4YqQ7SKSEX0t:˦=jL.zIPy 'Ydb_R 6Lp$=Aՠ$)CnW^!Dz#w7twKœfN/w3PuO;)~Cgd[Δ%jKa0ކo÷:8o_j#,fx}ow$毇*9y(؜PۮΩ+nGHQ{wAYE~Q[!?׳tQwQ!^\hʏ@|$]MbcmBW^$<2O‘"~+et;mԫ/.xWSRx9jMzL {IwiP)So`{;#i7b-2In͟<5/nm*Zhhi-K!>c,\ߧihٚPoهqQwV,e6m}5-c+m]@~X[ުy µ οuPhFU2ar%.lɬ0$ +X$b,??ZEzKՂG }Н$֭@C{ɱ_m&sEOL~c|j [75!y捬;#kd̯2:`n+~{Ϭ_.CT{۩̥LdzJB.zK ^ 5+ct_?du H F(ǘޏrc;3fO]:ƶRh aPlGvsl45 QnſjM@V JPI@tn4p]YtLF.{Qp.#@nҀW%.RF"'<t`s<03gxJKٻְYb&K P޵`B|d|õZRBJV ?yo|K 8˨!N/Ҹi037n>PA6u>}-=oown2 { #vZͬ<~*vWX@˜q*j™)H2 P Hٝ (gٱHQS}g۸}VPD3)WZjTfJvlDyHo㋓ hĺBҁ虭 (@?3-mI-4j1 :.O%=!l"gHV̀IgQ#YC79|kUXOO Ljn%}7uCCU؛J8 MP@"#/$+^24))iُ_A;b`czs_>ѧ[xl$w35shJMks4@F-pt|A .m0h5`x p9l& -P̑&pn8J .vu H˸Ć.*)"ˆEA)<6<k!Ȉ}U9FY8=8~9Rl];ر;i7g,p,ѾR xdF 5(=rVP髗YZQIp̬d/DPc,%C-hTe\`F43N̡2cG+I=-cٲ`dK/h?%ʸBJ+̎Q)wFNGB)ۗE} rعr9&:y }$X wj6EѾVj+܌wqU|yKs+x 45-GɈֶL۝iTȨ(Yׄ<pS$2 6-'e˖bK!W'$)hB$i)WhZgE-r L|uhA[\Ҭ0#$-<azIE(*v|? 4>pJ-ߥ)H(ƙg$Ĉ*Jޫ 0B/X~WVju&$AHrxkr4#q[F3>7!G8,/r)}aD#;݂8Ɓ<Hw! /_Gp" ]ǃgQcAYr&qQOaA|IΣKT*nጟ9u/6ܞ̥X)3]R 1pM 8 aeF>A梾<[O4S|2e\4ͣOj2+&rCZin*>|Z#[k |IENG=l}vB&$*"ѡL ?oGZiH|JG!5!(U}ḬH.lg7:=8sn;n3ͦKnŪL U7b3q佑d넫S%\`)yH1q(-Nj/bz|5i TKW}ot" Q^dAp'M1^SXı iݣ͂E@{5ZǶ.[=,y*p\?_GFYcػ=[R_b;S+?#-ỈlKYt)K.㓍] Kyy퉭4H7aiȷhKZ+PW7cuUfAަӜMɱih7[co-G\j>2 RġbZ=\qlc$p_p#Yu]U"֦JJ*uo)WX^I QKw}[ ԣ\>.65[9@p QM.r rx%Jp0zvN%0z0`W'(qY|!i0v\i3d7AI<^-{%E zK? %9) dT5.٩rE/ VR!GLq$W tTX fǴIyg?>e;m vs.W*ԕX\Fj 4Ү13.Nq#̸orhE[#G9E?[}{-X+o *Le0 3 (^H<2lp\3^М֢ػM]M1K(-EOݔ^-Y$Ԝ<\<>V6a] BڒXb-fҿֆr#E%c -rh{* ygx]G|h ̔c&#qs?&r˚_'s豉5C185+QT?E[wC%JNҨ!\_(ejn1QK"t}B&FQm~¦\(:vXSBЖ(1a=\vL4RZԊ!ؕw;Wsa| TNgB y`jJ |9@"ub5_}ҳ\h!ПKaUAF4]G{#0EEyֽ Aw`o86?(Q-[9uzNŚQШw|4ԔjƮbXKE^Ώ@|3S1i0qܾv`w)jQi1! d=.n?qԶg{.RNIIyP^Yl-6\}sA$i1P{zȜ1uw<)?,'e}Ģϲpl8Q^) v%Er G{Pg'Y[H<Δ]d:Lnw(F0駘9tIؽE3 Ž47̏g5$ dҹ`0Sul#Tw 9ě %(PGJsQwztl 5DK5͔O3uM;y|/|vHP4յ]{ =@;9nCغ5)מw]? 4KbQ=H?=<*b~oO$ K<27Wֳa\م?RǏYr Ok3`@SP1:J]hfh2-)[8 CS6ZjԔ7È]S 6ehh>l9>}An%l{zn;ѠwAEl$*Pɬv=?A߾Z7 WKԩE8{IENDB`powerline-2.8.4/docs/source/_static/img/pl-truncate3.png000066400000000000000000000060251466405252600232270ustar00rootroot00000000000000PNG  IHDRwtYbKGD pHYs  tIME :5L3 IDATxwtTU?oJ&tBB&LBs`HUQѵJQXDp]g^\tH@RL2!!u&=1 HĐd~93oᄍE21ygwm)!p\r4՞!y1p,n5D+vwл,A³AmOB,]=A /Hh^ü6D :0;z7"w3Jvn}$LӷoJptLfn&S?*[)+2h`?+[_`~AП<, ]E)o@ nG6GM)hou Z`wɕvaMv 8_zk#UՏq?"1f_&U:?^l-;k9y>k'(9޷S$?@N@)H1h1”X@5 0|L|{&.%ɴj؛ UW&8e<֟@buVBY)ԉhD^?@-N5wHEDŃ5 fЀfpuەC3zNuÈBtm7h k]{kބ nBjց^.ah$m_&5=A/rI*,d\0`tO3Ӏ-_ge3]ow̧y(%ѻt̩N[L0ƣ˙`976֬;cg{KߺS{9T`hJwd)l5Mp+"dp4xn?)oMAR6# );V25=DT]Eݏ~H8JK7@ !$&;-j$ZIp9*#%ː|T&%-U@vਡ  D( /uڔݽ&(<>Q]°?TCP{o$u,tVNyv<*aGX߾$͉wh˓8W.'TG;[yh$"B`yjx&A^:Ⱥn躅,X?aO1OW{60*گS ­fhSXfsVvp-~Q[. o2g8?EpQn r"[uݦ \ǢCfQ`4hс~Wty16lO6 *TZ7. ˗|A|2:vAW`"! FEu_*-¾:ԿQA)I^w1vHګ`ck% Mp~*%7NZ^$<&Cr!N4W/@ ܋XA !A?AAӯz{F^SsqV>.@bq;^q+.h"eAJPsϫ h0ں&D)4hv]OحرSet&^Zv\6ǡ2HS[8RT7qf-ΣpY*N_KTW$ywJR̍IҹGwbu<@ U?(_je(L(jE%<0d'@\L:`v9eʝM0g AnQN{{cyd( gB\,af.CLW&xz!WcvcpdGzn?uH[i.b2h4|+x [IJ2'^ =E\Th t[y_uPpyz6KڹR}ޮZvP_h-H*@۠5e{e6(Z3̵D^f:yY\,w_eO $TJ6*O(Py\#~C7Ĺ Zeq62&}ϗb_zYu$6Ż{ٖR2\K6J; K&Ns$@M|΁QKvX i?tS2G ZQ[] lۻ_#JsK0UͅU(^X4Yp2J \!ƥiਫ਼FҖޙ_̍U3tZ@p N.luC|?a_[q&im#s`ǬJ@ڇxH 퉽z0m* iFpǹ_-7ÊA_߾ }VRGBή|;#תR 6զUQۙ9s( Iw'[@b*'/ר0\@opKyB,b\!&:vq!=_7CrY~ߏ{E E8| ̈́GǠaNJ\2U ԛ6ё>Ge"LՏr+~{D Qcݙr vL (Ml{vP|0V#S *dn7f֮ÎoGQ٘L* Z~bҝ@ nՐ92Y^GԄKN\WWYl;uQZ[+؍m` :file:`{powerline}/config.json` :ref:`Colorschemes ` :file:`{powerline}/colorschemes/{name}.json`, :file:`{powerline}/colorschemes/{extension}/__main__.json`, :file:`{powerline}/colorschemes/{extension}/{name}.json` :ref:`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 `. .. _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 ` 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 `. 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 `_ 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 `_ 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 powerline-2.8.4/docs/source/configuration/000077500000000000000000000000001466405252600206425ustar00rootroot00000000000000powerline-2.8.4/docs/source/configuration/listers.rst000066400000000000000000000017541466405252600230700ustar00rootroot00000000000000.. _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 `). More information in :ref:`Writing listers ` section. Vim listers ----------- .. automodule:: powerline.listers.vim :members: Pdb listers ----------- .. automodule:: powerline.listers.pdb :members: i3wm listers ------------ .. automodule:: powerline.listers.i3wm :members: powerline-2.8.4/docs/source/configuration/local.rst000066400000000000000000000263551466405252600225010ustar00rootroot00000000000000.. _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 `. Level is always :ref:`log_level `, same for format. .. warning:: This variable is deprecated. Use :ref:`log_file option ` in conjunction with :py:class:`powerline.vim.VimVarHandler` class and :ref:`Vim config overrides variable `. 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 ` 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 `. 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 ` 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 ` 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 ` 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 ` take overrides from :ref:`environment variables `. powerline-2.8.4/docs/source/configuration/reference.rst000066400000000000000000000600321466405252600233330ustar00rootroot00000000000000*********************** 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 ` 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 ` 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 ` or :ref:`Vim local_themes option `. 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 ` and has the same format. #. Optional format string. Partially overrides :ref:`log_format key ` 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 ` 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 `. ``bg`` Background color. Must be defined in :ref:`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 `. ``groups`` Segment highlighting groups for this mode. Same syntax as the main :ref:`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 ` or from :ref:`default_top_theme common configuration key `. 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 `. 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 ` 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 `, :ref:`before `, :ref:`contents ` (only for string segments if :ref:`name ` is defined), :ref:`display `. Key :ref:`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 ` 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 `. For the :ref:`default 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 ` ``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 `. List of function segments is available in :ref:`Segment reference ` section. ``string`` A static string segment where the contents is defined in the :ref:`contents option `, and the highlighting group is defined in the :ref:`highlight_groups option `. ``segment_list`` Sub-list of segments. This list only allows :ref:`function `, :ref:`segments ` and :ref:`args ` options. List of lister segments is available in :ref:`Lister reference ` section. .. _config-themes-seg-name: ``name`` Segment name. If present allows referring to this segment in :ref:`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 `. .. 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 ` 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 ` 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. powerline-2.8.4/docs/source/configuration/segments.rst000066400000000000000000000013511466405252600232210ustar00rootroot00000000000000.. _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 `, 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 ` section. Available segments ================== .. toctree:: :glob: segments/* powerline-2.8.4/docs/source/configuration/segments/000077500000000000000000000000001466405252600224675ustar00rootroot00000000000000powerline-2.8.4/docs/source/configuration/segments/common.rst000066400000000000000000000014661466405252600245200ustar00rootroot00000000000000*************** 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: powerline-2.8.4/docs/source/configuration/segments/i3wm.rst000066400000000000000000000001401466405252600240730ustar00rootroot00000000000000************* i3wm segments ************* .. automodule:: powerline.segments.i3wm :members: powerline-2.8.4/docs/source/configuration/segments/pdb.rst000066400000000000000000000001351466405252600237650ustar00rootroot00000000000000************ PDB segments ************ .. automodule:: powerline.segments.pdb :members: powerline-2.8.4/docs/source/configuration/segments/shell.rst000066400000000000000000000001441466405252600243270ustar00rootroot00000000000000************** Shell segments ************** .. automodule:: powerline.segments.shell :members: powerline-2.8.4/docs/source/configuration/segments/tmux.rst000066400000000000000000000001401466405252600242110ustar00rootroot00000000000000************* Tmux segments ************* .. automodule:: powerline.segments.tmux :members: powerline-2.8.4/docs/source/configuration/segments/vim.rst000066400000000000000000000014661466405252600240230ustar00rootroot00000000000000************ 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: powerline-2.8.4/docs/source/configuration/selectors.rst000066400000000000000000000005741466405252600234050ustar00rootroot00000000000000.. _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 `. Available selectors =================== .. toctree:: :glob: selectors/* powerline-2.8.4/docs/source/configuration/selectors/000077500000000000000000000000001466405252600226455ustar00rootroot00000000000000powerline-2.8.4/docs/source/configuration/selectors/vim.rst000066400000000000000000000001401466405252600241650ustar00rootroot00000000000000************* Vim selectors ************* .. automodule:: powerline.selectors.vim :members: powerline-2.8.4/docs/source/develop.rst000066400000000000000000000003111466405252600201560ustar00rootroot00000000000000*************** Developer guide *************** .. toctree:: :maxdepth: 2 :glob: develop/segments develop/listers develop/local-themes develop/extensions develop/tips-and-tricks powerline-2.8.4/docs/source/develop/000077500000000000000000000000001466405252600174315ustar00rootroot00000000000000powerline-2.8.4/docs/source/develop/extensions.rst000066400000000000000000000041321466405252600223620ustar00rootroot00000000000000******************************** 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 `. 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: powerline-2.8.4/docs/source/develop/listers.rst000066400000000000000000000037441466405252600216600ustar00rootroot00000000000000.. _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 ` 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 ` (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 ` 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`. powerline-2.8.4/docs/source/develop/local-themes.rst000066400000000000000000000062751466405252600225520ustar00rootroot00000000000000************ 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 `. 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 `. This function always takes a single value named ``matcher_info`` which is the same dictionary as :ref:`segment_info dictionary `. 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 ` 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 `) and dictionary with theme. This dictionary is merged with :ref:`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.  | +---------+------------+-------------------------------------------------------+ powerline-2.8.4/docs/source/develop/segments.rst000066400000000000000000000505271466405252600220210ustar00rootroot00000000000000.. _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 ` 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 `. And also any other argument(s) specified by user in :ref:`args key ` (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 ` 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 ` are present) and ``segment_data`` is a dictionary like the one that is contained inside :ref:`segment_data dictionary in configuration `. 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 `. .. _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 `). 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 `. * Any arguments found in user configuration for the given segment (i.e. :ref:`args key `). It must return new value of :ref:`contents ` key. .. _dev-segments-truncate: ``truncate`` Like :ref:`expand function `, 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 `. All keys in segments returned by the function override those obtained from :ref:`configuration ` 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 `, :ref:`after `, :ref:`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 ` (:ref:`draw_inner_divider `). .. _dev-segments-highlight_groups: ``highlight_groups`` Determines segment highlighting. Refer to :ref:`themes documentation ` 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 ` 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-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 ` or function name (last component of the :ref:`function key `). May be ``None``. ``type`` :ref:`Segment 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-segments-seg-around: ``before``, ``after`` Value of :ref:`before ` or :ref:`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 `. May be ``None``. ``priority`` :ref:`Segment 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 `. ``side`` Segment side: ``right`` or ``left``. ``display_condition`` Contains function that takes three position parameters: :py:class:`powerline.PowerlineLogger` instance, :ref:`segment_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 ` and :ref:`exclude_/include_function keys `. ``width``, ``align`` :ref:`Width and align options `. May be ``None``. ``expand``, ``truncate`` Partially applied :ref:`expand ` or :ref:`truncate ` function. Accepts ``pl``, ``amount`` and ``segment`` positional parameters, keyword parameters from :ref:`args ` key were applied. ``startup`` Partially applied :ref:`startup function `. Accepts ``pl`` and ``shutdown_event`` positional parameters, keyword parameters from :ref:`args ` key were applied. ``shutdown`` :ref:`Shutdown function `. 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 `. 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: powerline-2.8.4/docs/source/develop/tips-and-tricks.rst000066400000000000000000000013471466405252600232040ustar00rootroot00000000000000**************************************** 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. powerline-2.8.4/docs/source/index.rst000066400000000000000000000005141466405252600176340ustar00rootroot00000000000000********* 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` powerline-2.8.4/docs/source/installation.rst000066400000000000000000000115271466405252600212340ustar00rootroot00000000000000************ 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 ` 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 ` may be enabled if used terminal emulator supports it (see :ref:`the terminal emulator support matrix `). 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 OS X powerline-2.8.4/docs/source/installation/000077500000000000000000000000001466405252600204745ustar00rootroot00000000000000powerline-2.8.4/docs/source/installation/linux.rst000066400000000000000000000104331466405252600223660ustar00rootroot00000000000000********************* 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 `_ * `Arch Linux (AUR), Python 3 version `_ * Gentoo Live ebuild in `raiagent `_ overlay * Powerline package is available for Debian starting from Wheezy (via `backports `_). Use `search `_ 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 `. 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. powerline-2.8.4/docs/source/installation/osx.rst000066400000000000000000000044171466405252600220450ustar00rootroot00000000000000******************** Installation on OS X ******************** Python package ============== 1. Install a proper Python version (see `issue #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*. powerline-2.8.4/docs/source/license-and-credits.rst000066400000000000000000000020551466405252600223440ustar00rootroot00000000000000******************* License and credits ******************* Powerline is licensed under the `MIT 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 `_ * `Nikolay Pavlov `_ * `Kovid Goyal `_ Contributors ------------ * `List of 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 powerline-2.8.4/docs/source/overview.rst000066400000000000000000000052611466405252600203770ustar00rootroot00000000000000******** 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 `_ 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 powerline-2.8.4/docs/source/powerline_autodoc.py000066400000000000000000000034421466405252600220720ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from sphinx.ext import autodoc from powerline.lint.inspect import formatconfigargspec, 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 formatconfigargspec(*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) powerline-2.8.4/docs/source/powerline_automan.py000066400000000000000000000265511466405252600221060ustar00rootroot00000000000000# 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 # `abc`. '', *([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) powerline-2.8.4/docs/source/tips-and-tricks.rst000066400000000000000000000065071466405252600215510ustar00rootroot00000000000000*************** 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() powerline-2.8.4/docs/source/troubleshooting.rst000066400000000000000000000340471466405252600217640ustar00rootroot00000000000000*************** Troubleshooting *************** System-specific issues ====================== .. toctree:: Linux OS X 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 `_. 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 `_ 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 `. * Alternative: set :ref:`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 ````. 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 `_ 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 `_ 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 ` 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 `_ 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 `_ and removed in version 6.5.0 of its successor `minibufexplorer `_. It is highly advised to use the latter because `minibufexpl`_ was last updated late in 2004. powerline-2.8.4/docs/source/troubleshooting/000077500000000000000000000000001466405252600212225ustar00rootroot00000000000000powerline-2.8.4/docs/source/troubleshooting/linux.rst000066400000000000000000000064221466405252600231170ustar00rootroot00000000000000************************ 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 ` 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 `_ 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 Terminus Symbola (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. powerline-2.8.4/docs/source/troubleshooting/osx.rst000066400000000000000000000060311466405252600225650ustar00rootroot00000000000000*********************** Troubleshooting on OS X *********************** I can’t see any fancy symbols, what’s wrong? -------------------------------------------- * If you’re using iTerm2, please update to `this revision `_ 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 ` 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 `_ for a discussion and other possible solutions for this issue. I receive “FSEventStreamStart: register_with_server: ERROR” with status_colors ------------------------------------------------------------------------------ This is `a known `_ 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``). powerline-2.8.4/docs/source/usage.rst000066400000000000000000000071601466405252600176350ustar00rootroot00000000000000***** 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 ` 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 powerline-2.8.4/docs/source/usage/000077500000000000000000000000001466405252600170775ustar00rootroot00000000000000powerline-2.8.4/docs/source/usage/other.rst000066400000000000000000000173041466405252600207570ustar00rootroot00000000000000************* 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 `). 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 `):: 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 `. It is not required to use powerline shell prompt, :ref:`components setting ` 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 ` 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 `_. powerline-2.8.4/docs/source/usage/shell-prompts.rst000066400000000000000000000131131466405252600224410ustar00rootroot00000000000000.. _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 `): .. 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 `): .. 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 `): .. 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 `) 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 `). 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``. powerline-2.8.4/docs/source/usage/wm-widgets.rst000066400000000000000000000051021466405252600217160ustar00rootroot00000000000000********************** 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 `): .. 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 `_. See the `lemonbar documentation `_ 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. powerline-2.8.4/font/000077500000000000000000000000001466405252600145115ustar00rootroot00000000000000powerline-2.8.4/font/10-powerline-symbols.conf000066400000000000000000000052311466405252600212710ustar00rootroot00000000000000 monospace PowerlineSymbols Droid Sans Mono PowerlineSymbols Droid Sans Mono Slashed PowerlineSymbols Droid Sans Mono Dotted PowerlineSymbols DejaVu Sans Mono PowerlineSymbols DejaVu Sans Mono PowerlineSymbols Envy Code R PowerlineSymbols Inconsolata PowerlineSymbols Lucida Console PowerlineSymbols Monaco PowerlineSymbols Pragmata PowerlineSymbols PragmataPro PowerlineSymbols Menlo PowerlineSymbols Source Code Pro PowerlineSymbols Consolas PowerlineSymbols Anonymous pro PowerlineSymbols Bitstream Vera Sans Mono PowerlineSymbols Liberation Mono PowerlineSymbols Ubuntu Mono PowerlineSymbols Meslo LG L PowerlineSymbols Meslo LG L DZ PowerlineSymbols Meslo LG M PowerlineSymbols Meslo LG M DZ PowerlineSymbols Meslo LG S PowerlineSymbols Meslo LG S DZ PowerlineSymbols powerline-2.8.4/font/PowerlineSymbols.otf000066400000000000000000000043301466405252600205400ustar00rootroot00000000000000OTTO 0CFF eFFTMfP_GDEFOS/2RB `cmap ,Rhead`b6hhea5$hmtxt_maxp Pname%Xpost j_< hhI!IZ!P 1 PfEd% 8Z 4j(9 h     P  b    Created with FontForge 2.0 (http://fontforge.sf.net)Created with FontForge 2.0 (http://fontforge.sf.net)PowerlineSymbolsPowerlineSymbolsMediumMediumFontForge : PowerlineSymbols : 17-1-2013FontForge : PowerlineSymbols : 17-1-2013PowerlineSymbolsPowerlineSymbolsVersion 001.000 Version 001.000 PowerlineSymbolsPowerlineSymbolsL0%%ybUPowerlineSymbols=#$% 䊂 $ oKL!  ")07k{blockuniE0A0uniE0A1uniE0A2uniE0B0uniE0B1uniE0B2uniE0B3Created with FontForge 2.0 (http://fontforge.sf.net)PowerlineSymbolsPowerlineSymbols #LYq55wEELodFP";#;5ai~q~qwtnx@[fspryqqf~[Qj@ @Kc>e ;K׋R ܋Kwd)}pqjddj}qopm}f^)dwrZ]tc{{uo)$)T2u}zryuLo [[\Ko[] ʌ Γ =5ZI_=powerline-2.8.4/powerline/000077500000000000000000000000001466405252600155475ustar00rootroot00000000000000powerline-2.8.4/powerline/__init__.py000066400000000000000000000760501466405252600176700ustar00rootroot00000000000000# 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 `. ''' 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 ` ''' 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 `. ''' 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 `. ''' 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 ` ''' 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 `. ''' 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) powerline-2.8.4/powerline/bindings/000077500000000000000000000000001466405252600173445ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/__init__.py000066400000000000000000000000001466405252600214430ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/awesome/000077500000000000000000000000001466405252600210045ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/awesome/powerline-awesome.py000077500000000000000000000006501466405252600250240ustar00rootroot00000000000000#!/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() powerline-2.8.4/powerline/bindings/awesome/powerline.lua000066400000000000000000000006641466405252600235210ustar00rootroot00000000000000local 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 powerline-2.8.4/powerline/bindings/bar/000077500000000000000000000000001466405252600201105ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/bar/powerline-bar.py000077500000000000000000000027351466405252600232420ustar00rootroot00000000000000#!/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) powerline-2.8.4/powerline/bindings/bash/000077500000000000000000000000001466405252600202615ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/bash/powerline.sh000066400000000000000000000101271466405252600226220ustar00rootroot00000000000000_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 powerline-2.8.4/powerline/bindings/config.py000066400000000000000000000235311466405252600211670ustar00rootroot00000000000000# 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\d+)\.(?P\d+)(?P[a-z]+)?(?:_(?Pplus|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(r'\$(_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) powerline-2.8.4/powerline/bindings/fish/000077500000000000000000000000001466405252600202755ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/fish/powerline-setup.fish000066400000000000000000000061101466405252600243100ustar00rootroot00000000000000function 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 powerline-2.8.4/powerline/bindings/i3/000077500000000000000000000000001466405252600176575ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/i3/powerline-i3.py000077500000000000000000000020531466405252600225510ustar00rootroot00000000000000#!/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)) powerline-2.8.4/powerline/bindings/ipython/000077500000000000000000000000001466405252600210365ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/ipython/__init__.py000066400000000000000000000000001466405252600231350ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/ipython/post_0_11.py000066400000000000000000000066231466405252600231240ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/bindings/ipython/pre_0_11.py000066400000000000000000000074201466405252600227210ustar00rootroot00000000000000# 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) powerline-2.8.4/powerline/bindings/ipython/since_5.py000066400000000000000000000051251466405252600227400ustar00rootroot00000000000000# 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)) powerline-2.8.4/powerline/bindings/ipython/since_7.py000066400000000000000000000055131466405252600227430ustar00rootroot00000000000000# 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)) powerline-2.8.4/powerline/bindings/lemonbar/000077500000000000000000000000001466405252600211435ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/lemonbar/powerline-lemonbar.py000077500000000000000000000031411466405252600253200ustar00rootroot00000000000000#!/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) powerline-2.8.4/powerline/bindings/pdb/000077500000000000000000000000001466405252600201115ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/pdb/__init__.py000066400000000000000000000112161466405252600222230ustar00rootroot00000000000000# 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() powerline-2.8.4/powerline/bindings/pdb/__main__.py000077500000000000000000000003271466405252600222100ustar00rootroot00000000000000#!/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() powerline-2.8.4/powerline/bindings/qtile/000077500000000000000000000000001466405252600204625ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/qtile/__init__.py000066400000000000000000000000001466405252600225610ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/qtile/widget.py000066400000000000000000000031461466405252600223230ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/bindings/rc/000077500000000000000000000000001466405252600177505ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/rc/powerline.rc000066400000000000000000000044511466405252600223060ustar00rootroot00000000000000fn _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 powerline-2.8.4/powerline/bindings/shell/000077500000000000000000000000001466405252600204535ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/shell/powerline.sh000066400000000000000000000144351466405252600230220ustar00rootroot00000000000000_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 powerline-2.8.4/powerline/bindings/tcsh/000077500000000000000000000000001466405252600203055ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/tcsh/powerline.tcsh000066400000000000000000000054651466405252600232060ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/bindings/tmux/000077500000000000000000000000001466405252600203415ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/tmux/__init__.py000066400000000000000000000043171466405252600224570ustar00rootroot00000000000000# 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) powerline-2.8.4/powerline/bindings/tmux/powerline-base.conf000066400000000000000000000017531466405252600241320ustar00rootroot00000000000000set -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 powerline-2.8.4/powerline/bindings/tmux/powerline.conf000066400000000000000000000001621466405252600232130ustar00rootroot00000000000000if-shell 'env "$POWERLINE_CONFIG_COMMAND" tmux setup' '' 'run-shell "powerline-config tmux setup"' # vim: ft=tmux powerline-2.8.4/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf000066400000000000000000000006661466405252600257310ustar00rootroot00000000000000set -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 powerline-2.8.4/powerline/bindings/tmux/powerline_tmux_1.8.conf000066400000000000000000000003631466405252600246610ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/bindings/tmux/powerline_tmux_1.8_minus.conf000066400000000000000000000012361466405252600260740ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf000066400000000000000000000012421466405252600257210ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/bindings/tmux/powerline_tmux_1.9_plus.conf000066400000000000000000000013141466405252600257220ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/bindings/tmux/powerline_tmux_2.1_plus.conf000066400000000000000000000015531466405252600257200ustar00rootroot00000000000000# 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" powerline-2.8.4/powerline/bindings/vim/000077500000000000000000000000001466405252600201375ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/vim/__init__.py000066400000000000000000000262751466405252600222640ustar00rootroot00000000000000# 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("")')) 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 ''' )) powerline-2.8.4/powerline/bindings/vim/autoload/000077500000000000000000000000001466405252600217475ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/vim/autoload/powerline/000077500000000000000000000000001466405252600237535ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/vim/autoload/powerline/debug.vim000066400000000000000000000007731466405252600255650ustar00rootroot00000000000000python 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() powerline-2.8.4/powerline/bindings/vim/plugin/000077500000000000000000000000001466405252600214355ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/vim/plugin/powerline.vim000066400000000000000000000155401466405252600241630ustar00rootroot00000000000000if 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(\":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("")'').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(":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 powerline-2.8.4/powerline/bindings/wm/000077500000000000000000000000001466405252600177675ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/wm/__init__.py000066400000000000000000000030011466405252600220720ustar00rootroot00000000000000# 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[0-9A-Za-z-]+) connected(?P primary)? (?P\d+)x(?P\d+)\+(?P\d+)\+(?P\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, } powerline-2.8.4/powerline/bindings/wm/awesome.py000066400000000000000000000033551466405252600220070ustar00rootroot00000000000000# 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) powerline-2.8.4/powerline/bindings/zsh/000077500000000000000000000000001466405252600201505ustar00rootroot00000000000000powerline-2.8.4/powerline/bindings/zsh/__init__.py000066400000000000000000000125361466405252600222700ustar00rootroot00000000000000# 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) powerline-2.8.4/powerline/bindings/zsh/powerline.zsh000066400000000000000000000150441466405252600227060ustar00rootroot00000000000000local _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 # # . 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 powerline-2.8.4/powerline/colorscheme.py000066400000000000000000000143241466405252600204300ustar00rootroot00000000000000# 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 ) powerline-2.8.4/powerline/commands/000077500000000000000000000000001466405252600173505ustar00rootroot00000000000000powerline-2.8.4/powerline/commands/__init__.py000066400000000000000000000000001466405252600214470ustar00rootroot00000000000000powerline-2.8.4/powerline/commands/config.py000066400000000000000000000075471466405252600212040ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/commands/daemon.py000066400000000000000000000022631466405252600211700ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/commands/lemonbar.py000066400000000000000000000017001466405252600215170ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/commands/lint.py000077500000000000000000000014161466405252600206750ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/commands/main.py000066400000000000000000000156771466405252600206660ustar00rootroot00000000000000# 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) powerline-2.8.4/powerline/config.py000066400000000000000000000005721466405252600173720ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/config_files/000077500000000000000000000000001466405252600201765ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/colors.json000066400000000000000000000330011466405252600223670ustar00rootroot00000000000000{ "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"] ] } } powerline-2.8.4/powerline/config_files/colorschemes/000077500000000000000000000000001466405252600226645ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/colorschemes/default.json000066400000000000000000000077711466405252600252170ustar00rootroot00000000000000{ "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" } } powerline-2.8.4/powerline/config_files/colorschemes/ipython/000077500000000000000000000000001466405252600243565ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/colorschemes/ipython/__main__.json000066400000000000000000000001541466405252600267710ustar00rootroot00000000000000{ "groups": { "prompt": "information:additional", "prompt_count": "information:highlighted" } } powerline-2.8.4/powerline/config_files/colorschemes/pdb/000077500000000000000000000000001466405252600234315ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/colorschemes/pdb/__main__.json000066400000000000000000000003141466405252600260420ustar00rootroot00000000000000{ "groups": { "current_code_name": "information:additional", "current_context": "current_code_name", "current_line": "information:regular", "current_file": "information:regular" } } powerline-2.8.4/powerline/config_files/colorschemes/pdb/default.json000066400000000000000000000001321466405252600257440ustar00rootroot00000000000000{ "groups": { "stack_depth": { "fg": "gray1", "bg": "gray10", "attrs": ["bold"] } } } powerline-2.8.4/powerline/config_files/colorschemes/pdb/solarized.json000066400000000000000000000001561466405252600263220ustar00rootroot00000000000000{ "groups": { "stack_depth": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] } } } powerline-2.8.4/powerline/config_files/colorschemes/shell/000077500000000000000000000000001466405252600237735ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/colorschemes/shell/__main__.json000066400000000000000000000004371466405252600264120ustar00rootroot00000000000000{ "groups": { "continuation": "cwd", "continuation:current": "cwd:current_folder", "exit_fail": "critical:failure", "exit_success": "critical:success", "jobnum": "information:priority", "superuser": "warning:regular" } } powerline-2.8.4/powerline/config_files/colorschemes/shell/default.json000066400000000000000000000010161466405252600263100ustar00rootroot00000000000000{ "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"]} } } } } powerline-2.8.4/powerline/config_files/colorschemes/shell/solarized.json000066400000000000000000000004371466405252600266660ustar00rootroot00000000000000{ "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"] } } } } } powerline-2.8.4/powerline/config_files/colorschemes/solarized.json000066400000000000000000000062421466405252600255570ustar00rootroot00000000000000{ "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": [] } } } powerline-2.8.4/powerline/config_files/colorschemes/tmux/000077500000000000000000000000001466405252600236615ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/colorschemes/tmux/default.json000066400000000000000000000014731466405252600262050ustar00rootroot00000000000000{ "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"]} } } powerline-2.8.4/powerline/config_files/colorschemes/tmux/solarized.json000066400000000000000000000017171466405252600265560ustar00rootroot00000000000000{ "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": [] } } } powerline-2.8.4/powerline/config_files/colorschemes/vim/000077500000000000000000000000001466405252600234575ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/colorschemes/vim/__main__.json000066400000000000000000000036171466405252600261010ustar00rootroot00000000000000{ "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" } } powerline-2.8.4/powerline/config_files/colorschemes/vim/default.json000066400000000000000000000131671466405252600260060ustar00rootroot00000000000000{ "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"] } } } } } powerline-2.8.4/powerline/config_files/colorschemes/vim/solarized.json000066400000000000000000000162141466405252600263520ustar00rootroot00000000000000{ "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"] } } } } } powerline-2.8.4/powerline/config_files/colorschemes/vim/solarizedlight.json000066400000000000000000000163121466405252600274010ustar00rootroot00000000000000{ "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"] } } } } } powerline-2.8.4/powerline/config_files/config.json000066400000000000000000000020751466405252600223420ustar00rootroot00000000000000{ "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 } } } powerline-2.8.4/powerline/config_files/themes/000077500000000000000000000000001466405252600214635ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/themes/ascii.json000066400000000000000000000053621466405252600234540ustar00rootroot00000000000000{ "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" } } } } } powerline-2.8.4/powerline/config_files/themes/ipython/000077500000000000000000000000001466405252600231555ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/themes/ipython/in.json000066400000000000000000000006711466405252600244620ustar00rootroot00000000000000{ "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"] } ] } } powerline-2.8.4/powerline/config_files/themes/ipython/in2.json000066400000000000000000000002221466405252600245340ustar00rootroot00000000000000{ "segments": { "left": [ { "type": "string", "contents": "", "width": "auto", "highlight_groups": ["prompt"] } ] } } powerline-2.8.4/powerline/config_files/themes/ipython/out.json000066400000000000000000000006341466405252600246620ustar00rootroot00000000000000{ "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"] } ] } } powerline-2.8.4/powerline/config_files/themes/ipython/rewrite.json000066400000000000000000000006061466405252600255330ustar00rootroot00000000000000{ "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"] } ] } } powerline-2.8.4/powerline/config_files/themes/pdb/000077500000000000000000000000001466405252600222305ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/themes/pdb/default.json000066400000000000000000000006541466405252600245540ustar00rootroot00000000000000{ "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" } ] } ] } } powerline-2.8.4/powerline/config_files/themes/powerline.json000066400000000000000000000053431466405252600243670ustar00rootroot00000000000000{ "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": "○" } } } } } powerline-2.8.4/powerline/config_files/themes/powerline_terminus.json000066400000000000000000000053511466405252600263140ustar00rootroot00000000000000{ "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": "○" } } } } } powerline-2.8.4/powerline/config_files/themes/powerline_unicode7.json000066400000000000000000000066211466405252600261640ustar00rootroot00000000000000{ "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": "○" } } } } } powerline-2.8.4/powerline/config_files/themes/shell/000077500000000000000000000000001466405252600225725ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/themes/shell/__main__.json000066400000000000000000000002231466405252600252020ustar00rootroot00000000000000{ "segment_data": { "hostname": { "args": { "only_if_ssh": true } }, "cwd": { "args": { "dir_limit_depth": 3 } } } } powerline-2.8.4/powerline/config_files/themes/shell/continuation.json000066400000000000000000000002201466405252600261710ustar00rootroot00000000000000{ "default_module": "powerline.segments.shell", "segments": { "left": [ { "function": "continuation" } ], "right": [ ] } } powerline-2.8.4/powerline/config_files/themes/shell/default.json000066400000000000000000000014341466405252600251130ustar00rootroot00000000000000{ "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 } ] } } powerline-2.8.4/powerline/config_files/themes/shell/default_leftonly.json000066400000000000000000000011731466405252600270270ustar00rootroot00000000000000{ "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 } ] } } powerline-2.8.4/powerline/config_files/themes/shell/select.json000066400000000000000000000003001466405252600247350ustar00rootroot00000000000000{ "segments": { "left": [ { "type": "string", "contents": "Select variant", "width": "auto", "align": "r", "highlight_groups": ["continuation:current"] } ] } } powerline-2.8.4/powerline/config_files/themes/tmux/000077500000000000000000000000001466405252600224605ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/themes/tmux/default.json000066400000000000000000000007621466405252600250040ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/unicode.json000066400000000000000000000053421466405252600240100ustar00rootroot00000000000000{ "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": "○" } } } } } powerline-2.8.4/powerline/config_files/themes/unicode_terminus.json000066400000000000000000000053411466405252600257350ustar00rootroot00000000000000{ "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": "○" } } } } } powerline-2.8.4/powerline/config_files/themes/unicode_terminus_condensed.json000066400000000000000000000051531466405252600277600ustar00rootroot00000000000000{ "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": "○" } } } } } powerline-2.8.4/powerline/config_files/themes/vim/000077500000000000000000000000001466405252600222565ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/themes/vim/__main__.json000066400000000000000000000001521466405252600246670ustar00rootroot00000000000000{ "segment_data": { "line_percent": { "args": { "gradient": true }, "after": "%" } } } powerline-2.8.4/powerline/config_files/themes/vim/cmdwin.json000066400000000000000000000004511466405252600244320ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/vim/default.json000066400000000000000000000046531466405252600246050ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/vim/help.json000066400000000000000000000011521466405252600241000ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/vim/plugin_commandt.json000066400000000000000000000007321466405252600263330ustar00rootroot00000000000000{ "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": [ ] } } powerline-2.8.4/powerline/config_files/themes/vim/plugin_gundo-preview.json000066400000000000000000000005101466405252600273160ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/vim/plugin_gundo.json000066400000000000000000000005101466405252600256370ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/vim/plugin_nerdtree.json000066400000000000000000000004451466405252600263420ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/vim/quickfix.json000066400000000000000000000012741466405252600250000ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/vim/tabline.json000066400000000000000000000032451466405252600245730ustar00rootroot00000000000000{ "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" } ] } } powerline-2.8.4/powerline/config_files/themes/wm/000077500000000000000000000000001466405252600221065ustar00rootroot00000000000000powerline-2.8.4/powerline/config_files/themes/wm/default.json000066400000000000000000000003751466405252600244320ustar00rootroot00000000000000{ "segments": { "right": [ { "function": "powerline.segments.common.time.date" }, { "function": "powerline.segments.common.time.date", "name": "time", "args": { "format": "%H:%M", "istime": true } } ] } } powerline-2.8.4/powerline/dist/000077500000000000000000000000001466405252600165125ustar00rootroot00000000000000powerline-2.8.4/powerline/dist/systemd/000077500000000000000000000000001466405252600202025ustar00rootroot00000000000000powerline-2.8.4/powerline/dist/systemd/powerline-daemon.service000066400000000000000000000004211466405252600250260ustar00rootroot00000000000000[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 powerline-2.8.4/powerline/ipython.py000066400000000000000000000032271466405252600176170ustar00rootroot00000000000000# 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) powerline-2.8.4/powerline/lemonbar.py000066400000000000000000000010601466405252600177150ustar00rootroot00000000000000# 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() )) powerline-2.8.4/powerline/lib/000077500000000000000000000000001466405252600163155ustar00rootroot00000000000000powerline-2.8.4/powerline/lib/__init__.py000066400000000000000000000011241466405252600204240ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/lib/config.py000066400000000000000000000141021466405252600201320ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/lib/debug.py000077500000000000000000000057201466405252600177640ustar00rootroot00000000000000# 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, {}, ()) powerline-2.8.4/powerline/lib/dict.py000066400000000000000000000036271466405252600176220ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/lib/encoding.py000066400000000000000000000062531466405252600204630ustar00rootroot00000000000000# 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.getlocale()[1] or 'ascii' ) return ( locale.getlocale()[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.getlocale()[1] or 'latin1' ) return ( locale.getlocale()[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.getlocale()[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)) powerline-2.8.4/powerline/lib/humanize_bytes.py000066400000000000000000000014501466405252600217150ustar00rootroot00000000000000# 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)) powerline-2.8.4/powerline/lib/inotify.py000066400000000000000000000137011466405252600203520ustar00rootroot00000000000000# 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 ' __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 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 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() powerline-2.8.4/powerline/lib/memoize.py000066400000000000000000000023231466405252600203340ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/lib/monotonic.py000066400000000000000000000052411466405252600206760ustar00rootroot00000000000000# 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 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 powerline-2.8.4/powerline/lib/overrides.py000066400000000000000000000034271466405252600206770ustar00rootroot00000000000000# 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 ) powerline-2.8.4/powerline/lib/path.py000066400000000000000000000006451466405252600176300ustar00rootroot00000000000000# 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) powerline-2.8.4/powerline/lib/shell.py000066400000000000000000000101041466405252600177720ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/lib/threaded.py000066400000000000000000000161541466405252600204560ustar00rootroot00000000000000# 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,), } powerline-2.8.4/powerline/lib/unicode.py000066400000000000000000000220631466405252600203200ustar00rootroot00000000000000# 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 `_): === ====== =========================================================== 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 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 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 `. 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.''') powerline-2.8.4/powerline/lib/url.py000066400000000000000000000010021466405252600174620ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/lib/vcs/000077500000000000000000000000001466405252600171105ustar00rootroot00000000000000powerline-2.8.4/powerline/lib/vcs/__init__.py000066400000000000000000000167051466405252600212320ustar00rootroot00000000000000# 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 powerline-2.8.4/powerline/lib/vcs/bzr.py000066400000000000000000000056671466405252600202750ustar00rootroot00000000000000# 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 class CoerceIO(StringIO): def write(self, arg): if isinstance(arg, bytes): arg = arg.decode(get_preferred_file_contents_encoding(), 'replace') return super(CoerceIO, self).write(arg) nick_pat = re.compile(br'nickname\s*=\s*(.+)') def branch_name_from_config_file(directory, config_file): ans = None try: with open(config_file, 'rb') as f: for line in f: m = nick_pat.match(line) if m is not None: ans = m.group(1).strip().decode(get_preferred_file_contents_encoding(), 'replace') break except Exception: pass return ans or os.path.basename(directory) state = None class Repository(object): def __init__(self, directory, create_watcher): self.directory = os.path.abspath(directory) self.create_watcher = create_watcher def status(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :'D?': dirty (tracked modified files: added, removed, deleted, modified), :'?U': untracked-dirty (added, but not tracked files) :None: clean (status is empty) With file argument: returns status of this file: The status codes are those returned by bzr status -S ''' if path is not None: return get_file_status( directory=self.directory, dirstate_file=join(self.directory, '.bzr', 'checkout', 'dirstate'), file_path=path, ignore_file_name='.bzrignore', get_func=self.do_status, create_watcher=self.create_watcher, ) return self.do_status(self.directory, path) def do_status(self, directory, path): try: return self._status(self.directory, path) except Exception: pass def _status(self, directory, path): global state if state is None: state = library_state.BzrLibraryState(ui=ui.SilentUIFactory, trace=trace.DefaultConfig()) buf = CoerceIO() w = workingtree.WorkingTree.open(directory) status.show_tree_status(w, specific_files=[path] if path else None, to_file=buf, short=True) raw = buf.getvalue() if not raw.strip(): return if path: ans = raw[:2] if ans == 'I ': # Ignored ans = None return ans dirtied = untracked = ' ' for line in raw.splitlines(): if len(line) > 1 and line[1] in 'ACDMRIN': dirtied = 'D' elif line and line[0] == '?': untracked = 'U' ans = dirtied + untracked return ans if ans.strip() else None def branch(self): config_file = join(self.directory, '.bzr', 'branch', 'branch.conf') return get_branch_name( directory=self.directory, config_file=config_file, get_func=branch_name_from_config_file, create_watcher=self.create_watcher, ) powerline-2.8.4/powerline/lib/vcs/git.py000066400000000000000000000136341466405252600202540ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import re from powerline.lib.vcs import get_branch_name, get_file_status from powerline.lib.shell import readlines from powerline.lib.path import join from powerline.lib.encoding import (get_preferred_file_name_encoding, get_preferred_file_contents_encoding) from powerline.lib.shell import which _ref_pat = re.compile(br'ref:\s*refs/heads/(.+)') def branch_name_from_config_file(directory, config_file): try: with open(config_file, 'rb') as f: raw = f.read() except EnvironmentError: return os.path.basename(directory) m = _ref_pat.match(raw) if m is not None: return m.group(1).decode(get_preferred_file_contents_encoding(), 'replace') return raw[:7] def git_directory(directory): path = join(directory, '.git') if os.path.isfile(path): with open(path, 'rb') as f: raw = f.read() if not raw.startswith(b'gitdir: '): raise IOError('invalid gitfile format') raw = raw[8:] if raw[-1:] == b'\n': raw = raw[:-1] if not isinstance(path, bytes): raw = raw.decode(get_preferred_file_name_encoding()) if not raw: raise IOError('no path in gitfile') return os.path.abspath(os.path.join(directory, raw)) else: return path class GitRepository(object): __slots__ = ('directory', 'create_watcher') def __init__(self, directory, create_watcher): self.directory = os.path.abspath(directory) self.create_watcher = create_watcher def status(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :First column: working directory status (D: dirty / space) :Second column: index status (I: index dirty / space) :Third column: presence of untracked files (U: untracked files / space) :None: repository clean With file argument: returns status of this file. Output is equivalent to the first two columns of ``git status --porcelain`` (except for merge statuses as they are not supported by libgit2). ''' if path: gitd = git_directory(self.directory) # We need HEAD as without it using fugitive to commit causes the # current file’s status (and only the current file) to not be updated # for some reason I cannot be bothered to figure out. return get_file_status( directory=self.directory, dirstate_file=join(gitd, 'index'), file_path=path, ignore_file_name='.gitignore', get_func=self.do_status, create_watcher=self.create_watcher, extra_ignore_files=tuple(join(gitd, x) for x in ('logs/HEAD', 'info/exclude')), ) return self.do_status(self.directory, path) def branch(self): directory = git_directory(self.directory) head = join(directory, 'HEAD') return get_branch_name( directory=directory, config_file=head, get_func=branch_name_from_config_file, create_watcher=self.create_watcher, ) try: import pygit2 as git class Repository(GitRepository): @staticmethod def ignore_event(path, name): return False def stash(self): try: stashref = git.Repository(git_directory(self.directory)).lookup_reference('refs/stash') except KeyError: return 0 return sum(1 for _ in stashref.log()) def do_status(self, directory, path): if path: try: status = git.Repository(directory).status_file(path) except (KeyError, ValueError): return None if status == git.GIT_STATUS_CURRENT: return None else: if status & git.GIT_STATUS_WT_NEW: return '??' if status & git.GIT_STATUS_IGNORED: return '!!' if status & git.GIT_STATUS_INDEX_NEW: index_status = 'A' elif status & git.GIT_STATUS_INDEX_DELETED: index_status = 'D' elif status & git.GIT_STATUS_INDEX_MODIFIED: index_status = 'M' else: index_status = ' ' if status & git.GIT_STATUS_WT_DELETED: wt_status = 'D' elif status & git.GIT_STATUS_WT_MODIFIED: wt_status = 'M' else: wt_status = ' ' return index_status + wt_status else: wt_column = ' ' index_column = ' ' untracked_column = ' ' for status in git.Repository(directory).status().values(): if status & git.GIT_STATUS_WT_NEW: untracked_column = 'U' continue if status & (git.GIT_STATUS_WT_DELETED | git.GIT_STATUS_WT_MODIFIED): wt_column = 'D' if status & ( git.GIT_STATUS_INDEX_NEW | git.GIT_STATUS_INDEX_MODIFIED | git.GIT_STATUS_INDEX_DELETED ): index_column = 'I' r = wt_column + index_column + untracked_column return r if r != ' ' else None except ImportError: class Repository(GitRepository): def __init__(self, *args, **kwargs): if not which('git'): raise OSError('git executable is not available') super(Repository, self).__init__(*args, **kwargs) @staticmethod def ignore_event(path, name): # Ignore changes to the index.lock file, since they happen # frequently and don't indicate an actual change in the working tree # status return path.endswith('.git') and name == 'index.lock' def _gitcmd(self, directory, *args): return readlines(('git',) + args, directory) def stash(self): return sum(1 for _ in self._gitcmd(self.directory, '--no-optional-locks', 'stash', 'list')) def do_status(self, directory, path): if path: try: return next(self._gitcmd(directory, '--no-optional-locks', 'status', '--porcelain', '--ignored', '--', path))[:2] except StopIteration: return None else: wt_column = ' ' index_column = ' ' untracked_column = ' ' for line in self._gitcmd(directory, '--no-optional-locks', 'status', '--porcelain'): if line[0] == '?': untracked_column = 'U' continue elif line[0] == '!': continue if line[0] != ' ': index_column = 'I' if line[1] != ' ': wt_column = 'D' r = wt_column + index_column + untracked_column return r if r != ' ' else None powerline-2.8.4/powerline/lib/vcs/mercurial.py000066400000000000000000000051661466405252600214550ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import hglib 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 def branch_name_from_config_file(directory, config_file): try: with open(config_file, 'rb') as f: raw = f.read() return raw.decode(get_preferred_file_contents_encoding(), 'replace').strip() except Exception: return 'default' class Repository(object): __slots__ = ('directory', 'create_watcher') # hg status -> (powerline file status, repo status flag) statuses = { b'M': ('M', 1), b'A': ('A', 1), b'R': ('R', 1), b'!': ('D', 1), b'?': ('U', 2), b'I': ('I', 0), b'C': ('', 0), } repo_statuses_str = (None, 'D ', ' U', 'DU') def __init__(self, directory, create_watcher): self.directory = os.path.abspath(directory) self.create_watcher = create_watcher def _repo(self, directory): # Cannot create this object once and use always: when repository updates # functions emit invalid results return hglib.open(directory) def status(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :'D?': dirty (tracked modified files: added, removed, deleted, modified), :'?U': untracked-dirty (added, but not tracked files) :None: clean (status is empty) With file argument: returns status of this file: `M`odified, `A`dded, `R`emoved, `D`eleted (removed from filesystem, but still tracked), `U`nknown, `I`gnored, (None)Clean. ''' if path: return get_file_status( directory=self.directory, dirstate_file=join(self.directory, '.hg', 'dirstate'), file_path=path, ignore_file_name='.hgignore', get_func=self.do_status, create_watcher=self.create_watcher, ) return self.do_status(self.directory, path) def do_status(self, directory, path): with self._repo(directory) as repo: if path: path = os.path.join(directory, path) statuses = repo.status(include=path, all=True) for status, paths in statuses: if paths: return self.statuses[status][0] return None else: resulting_status = 0 for status, paths in repo.status(all=True): if paths: resulting_status |= self.statuses[status][1] return self.repo_statuses_str[resulting_status] def branch(self): config_file = join(self.directory, '.hg', 'branch') return get_branch_name( directory=self.directory, config_file=config_file, get_func=branch_name_from_config_file, create_watcher=self.create_watcher, ) powerline-2.8.4/powerline/lib/watcher/000077500000000000000000000000001466405252600177525ustar00rootroot00000000000000powerline-2.8.4/powerline/lib/watcher/__init__.py000066400000000000000000000053541466405252600220720ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys from powerline.lib.watcher.stat import StatFileWatcher from powerline.lib.watcher.inotify import INotifyFileWatcher from powerline.lib.watcher.tree import TreeWatcher from powerline.lib.watcher.uv import UvFileWatcher, UvNotFound from powerline.lib.inotify import INotifyError def create_file_watcher(pl, watcher_type='auto', expire_time=10): '''Create an object that can watch for changes to specified files Use ``.__call__()`` method of the returned object to start watching the file or check whether file has changed since last call. Use ``.unwatch()`` method of the returned object to stop watching the file. Uses inotify if available, then pyuv, otherwise tracks mtimes. expire_time is the number of minutes after the last query for a given path for the inotify watch for that path to be automatically removed. This conserves kernel resources. :param PowerlineLogger pl: Logger. :param str watcher_type One of ``inotify`` (linux only), ``uv``, ``stat``, ``auto``. Determines what watcher will be used. ``auto`` will use ``inotify`` if available, then ``libuv`` and then fall back to ``stat``. :param int expire_time: Number of minutes since last ``.__call__()`` before inotify watcher will stop watching given file. ''' if watcher_type == 'stat': pl.debug('Using requested stat-based watcher', prefix='watcher') return StatFileWatcher() if watcher_type == 'inotify': # Explicitly selected inotify watcher: do not catch INotifyError then. pl.debug('Using requested inotify watcher', prefix='watcher') return INotifyFileWatcher(expire_time=expire_time) elif watcher_type == 'uv': pl.debug('Using requested uv watcher', prefix='watcher') return UvFileWatcher() if sys.platform.startswith('linux'): try: pl.debug('Trying to use inotify watcher', prefix='watcher') return INotifyFileWatcher(expire_time=expire_time) except INotifyError: pl.info('Failed to create inotify watcher', prefix='watcher') try: pl.debug('Using libuv-based watcher') return UvFileWatcher() except UvNotFound: pl.debug('Failed to import pyuv') pl.debug('Using stat-based watcher') return StatFileWatcher() def create_tree_watcher(pl, watcher_type='auto', expire_time=10): '''Create an object that can watch for changes in specified directories :param PowerlineLogger pl: Logger. :param str watcher_type: Watcher type. Currently the only supported types are ``inotify`` (linux only), ``uv``, ``dummy`` and ``auto``. :param int expire_time: Number of minutes since last ``.__call__()`` before inotify watcher will stop watching given file. ''' return TreeWatcher(pl, watcher_type, expire_time) powerline-2.8.4/powerline/lib/watcher/inotify.py000066400000000000000000000173651466405252600220210ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import errno import os import ctypes from threading import RLock from powerline.lib.inotify import INotify from powerline.lib.monotonic import monotonic from powerline.lib.path import realpath class INotifyFileWatcher(INotify): def __init__(self, expire_time=10): super(INotifyFileWatcher, self).__init__() self.watches = {} self.modified = {} self.last_query = {} self.lock = RLock() self.expire_time = expire_time * 60 def expire_watches(self): now = monotonic() for path, last_query in tuple(self.last_query.items()): if last_query - now > self.expire_time: self.unwatch(path) def process_event(self, wd, mask, cookie, name): if wd == -1 and (mask & self.Q_OVERFLOW): # We missed some INOTIFY events, so we don't # know the state of any tracked files. for path in tuple(self.modified): if os.path.exists(path): self.modified[path] = True else: self.watches.pop(path, None) self.modified.pop(path, None) self.last_query.pop(path, None) return for path, num in tuple(self.watches.items()): if num == wd: if mask & self.IGNORED: self.watches.pop(path, None) self.modified.pop(path, None) self.last_query.pop(path, None) else: if mask & self.ATTRIB: # The watched file could have had its inode changed, in # which case we will not get any more events for this # file, so re-register the watch. For example by some # other file being renamed as this file. try: self.unwatch(path) except OSError: pass try: self.watch(path) except OSError as e: if getattr(e, 'errno', None) != errno.ENOENT: raise else: self.modified[path] = True else: self.modified[path] = True def unwatch(self, path): ''' Remove the watch for path. Raises an OSError if removing the watch fails for some reason. ''' path = realpath(path) with self.lock: self.modified.pop(path, None) self.last_query.pop(path, None) wd = self.watches.pop(path, None) if wd is not None: if self._rm_watch(self._inotify_fd, wd) != 0: self.handle_error() def watch(self, path): ''' Register a watch for the file/directory named path. Raises an OSError if path does not exist. ''' path = realpath(path) with self.lock: if path not in self.watches: bpath = path if isinstance(path, bytes) else path.encode(self.fenc) flags = self.MOVE_SELF | self.DELETE_SELF buf = ctypes.c_char_p(bpath) # Try watching path as a directory wd = self._add_watch(self._inotify_fd, buf, flags | self.ONLYDIR) if wd == -1: eno = ctypes.get_errno() if eno != errno.ENOTDIR: self.handle_error() # Try watching path as a file flags |= (self.MODIFY | self.ATTRIB) wd = self._add_watch(self._inotify_fd, buf, flags) if wd == -1: self.handle_error() self.watches[path] = wd self.modified[path] = False def is_watching(self, path): with self.lock: return realpath(path) in self.watches def __call__(self, path): ''' Return True if path has been modified since the last call. Can raise OSError if the path does not exist. ''' path = realpath(path) with self.lock: self.last_query[path] = monotonic() self.expire_watches() if path not in self.watches: # Try to re-add the watch, it will fail if the file does not # exist/you don't have permission self.watch(path) return True self.read(get_name=False) if path not in self.modified: # An ignored event was received which means the path has been # automatically unwatched return True ans = self.modified[path] if ans: self.modified[path] = False return ans def close(self): with self.lock: for path in tuple(self.watches): try: self.unwatch(path) except OSError: pass super(INotifyFileWatcher, self).close() class NoSuchDir(ValueError): pass class BaseDirChanged(ValueError): pass class DirTooLarge(ValueError): def __init__(self, bdir): ValueError.__init__(self, 'The directory {0} is too large to monitor. Try increasing the value in /proc/sys/fs/inotify/max_user_watches'.format(bdir)) class INotifyTreeWatcher(INotify): is_dummy = False def __init__(self, basedir, ignore_event=None): super(INotifyTreeWatcher, self).__init__() self.basedir = realpath(basedir) self.watch_tree() self.modified = True self.ignore_event = (lambda path, name: False) if ignore_event is None else ignore_event def watch_tree(self): self.watched_dirs = {} self.watched_rmap = {} try: self.add_watches(self.basedir) except OSError as e: if e.errno == errno.ENOSPC: raise DirTooLarge(self.basedir) def add_watches(self, base, top_level=True): ''' Add watches for this directory and all its descendant directories, recursively. ''' base = realpath(base) # There may exist a link which leads to an endless # add_watches loop or to maximum recursion depth exceeded if not top_level and base in self.watched_dirs: return try: is_dir = self.add_watch(base) except OSError as e: if e.errno == errno.ENOENT: # The entry could have been deleted between listdir() and # add_watch(). if top_level: raise NoSuchDir('The dir {0} does not exist'.format(base)) return if e.errno == errno.EACCES: # We silently ignore entries for which we don't have permission, # unless they are the top level dir if top_level: raise NoSuchDir('You do not have permission to monitor {0}'.format(base)) return raise else: if is_dir: try: files = os.listdir(base) except OSError as e: if e.errno in (errno.ENOTDIR, errno.ENOENT): # The dir was deleted/replaced between the add_watch() # and listdir() if top_level: raise NoSuchDir('The dir {0} does not exist'.format(base)) return raise for x in files: self.add_watches(os.path.join(base, x), top_level=False) elif top_level: # The top level dir is a file, not good. raise NoSuchDir('The dir {0} does not exist'.format(base)) def add_watch(self, path): bpath = path if isinstance(path, bytes) else path.encode(self.fenc) wd = self._add_watch( self._inotify_fd, ctypes.c_char_p(bpath), # Ignore symlinks and watch only directories self.DONT_FOLLOW | self.ONLYDIR | self.MODIFY | self.CREATE | self.DELETE | self.MOVE_SELF | self.MOVED_FROM | self.MOVED_TO | self.ATTRIB | self.DELETE_SELF ) if wd == -1: eno = ctypes.get_errno() if eno == errno.ENOTDIR: return False raise OSError(eno, 'Failed to add watch for: {0}: {1}'.format(path, self.os.strerror(eno))) self.watched_dirs[path] = wd self.watched_rmap[wd] = path return True def process_event(self, wd, mask, cookie, name): if wd == -1 and (mask & self.Q_OVERFLOW): # We missed some INOTIFY events, so we don't # know the state of any tracked dirs. self.watch_tree() self.modified = True return path = self.watched_rmap.get(wd, None) if path is not None: if not self.ignore_event(path, name): self.modified = True if mask & self.CREATE: # A new sub-directory might have been created, monitor it. try: if not isinstance(path, bytes): name = name.decode(self.fenc) self.add_watch(os.path.join(path, name)) except OSError as e: if e.errno == errno.ENOENT: # Deleted before add_watch() pass elif e.errno == errno.ENOSPC: raise DirTooLarge(self.basedir) else: raise if (mask & self.DELETE_SELF or mask & self.MOVE_SELF) and path == self.basedir: raise BaseDirChanged('The directory %s was moved/deleted' % path) def __call__(self): self.read() ret = self.modified self.modified = False return ret powerline-2.8.4/powerline/lib/watcher/stat.py000066400000000000000000000016741466405252600213070ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from threading import RLock from powerline.lib.path import realpath class StatFileWatcher(object): def __init__(self): self.watches = {} self.lock = RLock() def watch(self, path): path = realpath(path) with self.lock: self.watches[path] = os.path.getmtime(path) def unwatch(self, path): path = realpath(path) with self.lock: self.watches.pop(path, None) def is_watching(self, path): with self.lock: return realpath(path) in self.watches def __call__(self, path): path = realpath(path) with self.lock: if path not in self.watches: self.watches[path] = os.path.getmtime(path) return True mtime = os.path.getmtime(path) if mtime != self.watches[path]: self.watches[path] = mtime return True return False def close(self): with self.lock: self.watches.clear() powerline-2.8.4/powerline/lib/watcher/tree.py000066400000000000000000000050141466405252600212630ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys from powerline.lib.monotonic import monotonic from powerline.lib.inotify import INotifyError from powerline.lib.path import realpath from powerline.lib.watcher.inotify import INotifyTreeWatcher, DirTooLarge, NoSuchDir, BaseDirChanged from powerline.lib.watcher.uv import UvTreeWatcher, UvNotFound class DummyTreeWatcher(object): is_dummy = True def __init__(self, basedir): self.basedir = realpath(basedir) def __call__(self): return False class TreeWatcher(object): def __init__(self, pl, watcher_type, expire_time): self.watches = {} self.last_query_times = {} self.expire_time = expire_time * 60 self.pl = pl self.watcher_type = watcher_type def get_watcher(self, path, ignore_event): if self.watcher_type == 'inotify': return INotifyTreeWatcher(path, ignore_event=ignore_event) if self.watcher_type == 'uv': return UvTreeWatcher(path, ignore_event=ignore_event) if self.watcher_type == 'dummy': return DummyTreeWatcher(path) # FIXME if self.watcher_type == 'stat': return DummyTreeWatcher(path) if self.watcher_type == 'auto': if sys.platform.startswith('linux'): try: return INotifyTreeWatcher(path, ignore_event=ignore_event) except (INotifyError, DirTooLarge) as e: if not isinstance(e, INotifyError): self.pl.warn('Failed to watch path: {0} with error: {1}'.format(path, e)) try: return UvTreeWatcher(path, ignore_event=ignore_event) except UvNotFound: pass return DummyTreeWatcher(path) else: raise ValueError('Unknown watcher type: {0}'.format(self.watcher_type)) def watch(self, path, ignore_event=None): path = realpath(path) w = self.get_watcher(path, ignore_event) self.watches[path] = w return w def expire_old_queries(self): pop = [] now = monotonic() for path, lt in self.last_query_times.items(): if now - lt > self.expire_time: pop.append(path) for path in pop: del self.last_query_times[path] def __call__(self, path, ignore_event=None): path = realpath(path) self.expire_old_queries() self.last_query_times[path] = monotonic() w = self.watches.get(path, None) if w is None: try: self.watch(path, ignore_event=ignore_event) except NoSuchDir: pass return True try: return w() except BaseDirChanged: self.watches.pop(path, None) return True except DirTooLarge as e: self.pl.warn(str(e)) self.watches[path] = DummyTreeWatcher(path) return False powerline-2.8.4/powerline/lib/watcher/uv.py000066400000000000000000000113661466405252600207650ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from collections import defaultdict from threading import RLock from functools import partial from threading import Thread from errno import ENOENT from powerline.lib.path import realpath from powerline.lib.encoding import get_preferred_file_name_encoding class UvNotFound(NotImplementedError): pass pyuv = None pyuv_version_info = None def import_pyuv(): global pyuv global pyuv_version_info if not pyuv: try: pyuv = __import__('pyuv') except ImportError: raise UvNotFound else: pyuv_version_info = tuple((int(c) for c in pyuv.__version__.split('.'))) class UvThread(Thread): daemon = True def __init__(self, loop): self.uv_loop = loop self.async_handle = pyuv.Async(loop, self._async_cb) super(UvThread, self).__init__() def _async_cb(self, handle): self.uv_loop.stop() self.async_handle.close() def run(self): self.uv_loop.run() def join(self): self.async_handle.send() return super(UvThread, self).join() _uv_thread = None def start_uv_thread(): global _uv_thread if _uv_thread is None: loop = pyuv.Loop() _uv_thread = UvThread(loop) _uv_thread.start() return _uv_thread.uv_loop def normpath(path, fenc): path = realpath(path) if isinstance(path, bytes): return path.decode(fenc) else: return path class UvWatcher(object): def __init__(self): import_pyuv() self.watches = {} self.lock = RLock() self.loop = start_uv_thread() self.fenc = get_preferred_file_name_encoding() if pyuv_version_info >= (1, 0): self._start_watch = self._start_watch_1_x else: self._start_watch = self._start_watch_0_x def _start_watch_1_x(self, path): handle = pyuv.fs.FSEvent(self.loop) handle.start(path, 0, partial(self._record_event, path)) self.watches[path] = handle def _start_watch_0_x(self, path): self.watches[path] = pyuv.fs.FSEvent( self.loop, path, partial(self._record_event, path), pyuv.fs.UV_CHANGE | pyuv.fs.UV_RENAME ) def watch(self, path): path = normpath(path, self.fenc) with self.lock: if path not in self.watches: try: self._start_watch(path) except pyuv.error.FSEventError as e: code = e.args[0] if code == pyuv.errno.UV_ENOENT: raise OSError(ENOENT, 'No such file or directory: ' + path) else: raise def unwatch(self, path): path = normpath(path, self.fenc) with self.lock: try: watch = self.watches.pop(path) except KeyError: return watch.close(partial(self._stopped_watching, path)) def is_watching(self, path): with self.lock: return normpath(path, self.fenc) in self.watches def __del__(self): try: lock = self.lock except AttributeError: pass else: with lock: while self.watches: path, watch = self.watches.popitem() watch.close(partial(self._stopped_watching, path)) class UvFileWatcher(UvWatcher): def __init__(self): super(UvFileWatcher, self).__init__() self.events = defaultdict(list) def _record_event(self, path, fsevent_handle, filename, events, error): with self.lock: self.events[path].append(events) if events | pyuv.fs.UV_RENAME: if not os.path.exists(path): self.watches.pop(path).close() def _stopped_watching(self, path, *args): self.events.pop(path, None) def __call__(self, path): path = normpath(path, self.fenc) with self.lock: events = self.events.pop(path, None) if events: return True if path not in self.watches: self.watch(path) return True return False class UvTreeWatcher(UvWatcher): is_dummy = False def __init__(self, basedir, ignore_event=None): super(UvTreeWatcher, self).__init__() self.ignore_event = ignore_event or (lambda path, name: False) self.basedir = normpath(basedir, self.fenc) self.modified = True self.watch_directory(self.basedir) def watch_directory(self, path): for root, dirs, files in os.walk(normpath(path, self.fenc)): self.watch_one_directory(root) def watch_one_directory(self, dirname): try: self.watch(dirname) except OSError: pass def _stopped_watching(self, path, *args): pass def _record_event(self, path, fsevent_handle, filename, events, error): if not self.ignore_event(path, filename): self.modified = True if events == pyuv.fs.UV_CHANGE | pyuv.fs.UV_RENAME: # Stat changes to watched directory are UV_CHANGE|UV_RENAME. It # is weird. pass elif events | pyuv.fs.UV_RENAME: if not os.path.isdir(path): self.unwatch(path) else: full_name = os.path.join(path, filename) if os.path.isdir(full_name): # For some reason mkdir and rmdir both fall into this # category self.watch_directory(full_name) def __call__(self): return self.__dict__.pop('modified', False) powerline-2.8.4/powerline/lint/000077500000000000000000000000001466405252600165155ustar00rootroot00000000000000powerline-2.8.4/powerline/lint/__init__.py000066400000000000000000000515661466405252600206430ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import logging from collections import defaultdict from itertools import chain from functools import partial from powerline import generate_config_finder, get_config_paths, load_config from powerline.segments.vim import vim_modes from powerline.lib.dict import mergedicts_copy from powerline.lib.config import ConfigLoader from powerline.lib.unicode import unicode from powerline.lib.path import join from powerline.lint.markedjson import load from powerline.lint.markedjson.error import echoerr, EchoErr, MarkedError from powerline.lint.checks import (check_matcher_func, check_ext, check_config, check_top_theme, check_color, check_translated_group_name, check_group, check_segment_module, check_exinclude_function, type_keys, check_segment_function, check_args, get_one_segment_function, check_highlight_groups, check_highlight_group, check_full_segment_data, get_all_possible_functions, check_segment_data_key, register_common_name, highlight_group_spec, check_log_file_level, check_logging_handler) from powerline.lint.spec import Spec from powerline.lint.context import Context def open_file(path): return open(path, 'rb') def generate_json_config_loader(lhadproblem): def load_json_config(config_file_path, load=load, open_file=open_file): with open_file(config_file_path) as config_file_fp: r, hadproblem = load(config_file_fp) if hadproblem: lhadproblem[0] = True return r return load_json_config function_name_re = r'^(\w+\.)*[a-zA-Z_]\w*$' divider_spec = Spec().printable().len( 'le', 3, (lambda value: 'Divider {0!r} is too large!'.format(value))).copy ext_theme_spec = Spec().type(unicode).func(lambda *args: check_config('themes', *args)).copy top_theme_spec = Spec().type(unicode).func(check_top_theme).copy ext_spec = Spec( colorscheme=Spec().type(unicode).func( (lambda *args: check_config('colorschemes', *args)) ), theme=ext_theme_spec(), top_theme=top_theme_spec().optional(), ).copy gen_components_spec = (lambda *components: Spec().list(Spec().type(unicode).oneof(set(components)))) log_level_spec = Spec().re('^[A-Z]+$').func( (lambda value, *args: (True, True, not hasattr(logging, value))), (lambda value: 'unknown debugging level {0}'.format(value)) ).copy log_format_spec = Spec().type(unicode).copy main_spec = (Spec( common=Spec( default_top_theme=top_theme_spec().optional(), term_truecolor=Spec().type(bool).optional(), term_escape_style=Spec().type(unicode).oneof(set(('auto', 'xterm', 'fbterm'))).optional(), # Python is capable of loading from zip archives. Thus checking path # only for existence of the path, not for it being a directory paths=Spec().list( (lambda value, *args: (True, True, not os.path.exists(os.path.expanduser(value.value)))), (lambda value: 'path does not exist: {0}'.format(value)) ).optional(), log_file=Spec().either( Spec().type(unicode).func( ( lambda value, *args: ( True, True, not os.path.isdir(os.path.dirname(os.path.expanduser(value))) ) ), (lambda value: 'directory does not exist: {0}'.format(os.path.dirname(value))) ), Spec().list(Spec().either( Spec().type(unicode, type(None)), Spec().tuple( Spec().re(function_name_re).func(check_logging_handler), Spec().tuple( Spec().type(list).optional(), Spec().type(dict).optional(), ), log_level_spec().func(check_log_file_level).optional(), log_format_spec().optional(), ), )) ).optional(), log_level=log_level_spec().optional(), log_format=log_format_spec().optional(), interval=Spec().either(Spec().cmp('gt', 0.0), Spec().type(type(None))).optional(), reload_config=Spec().type(bool).optional(), watcher=Spec().type(unicode).oneof(set(('auto', 'inotify', 'stat'))).optional(), ).context_message('Error while loading common configuration (key {key})'), ext=Spec( vim=ext_spec().update( components=gen_components_spec('statusline', 'tabline').optional(), local_themes=Spec( __tabline__=ext_theme_spec(), ).unknown_spec( Spec().re(function_name_re).func(partial(check_matcher_func, 'vim')), ext_theme_spec() ), ).optional(), ipython=ext_spec().update( local_themes=Spec( in2=ext_theme_spec(), out=ext_theme_spec(), rewrite=ext_theme_spec(), ), ).optional(), shell=ext_spec().update( components=gen_components_spec('tmux', 'prompt').optional(), local_themes=Spec( continuation=ext_theme_spec(), select=ext_theme_spec(), ), ).optional(), wm=ext_spec().update( local_themes=Spec().unknown_spec( Spec().re('^[0-9A-Za-z-]+$'), ext_theme_spec() ).optional(), update_interval=Spec().cmp('gt', 0.0).optional(), ).optional(), ).unknown_spec( check_ext, ext_spec(), ).context_message('Error while loading extensions configuration (key {key})'), ).context_message('Error while loading main configuration')) term_color_spec = Spec().unsigned().cmp('le', 255).copy true_color_spec = Spec().re( '^[0-9a-fA-F]{6}$', (lambda value: '"{0}" is not a six-digit hexadecimal unsigned integer written as a string'.format(value)) ).copy colors_spec = (Spec( colors=Spec().unknown_spec( Spec().ident(), Spec().either( Spec().tuple(term_color_spec(), true_color_spec()), term_color_spec() ) ).context_message('Error while checking colors (key {key})'), gradients=Spec().unknown_spec( Spec().ident(), Spec().tuple( Spec().len('gt', 1).list(term_color_spec()), Spec().len('gt', 1).list(true_color_spec()).optional(), ) ).context_message('Error while checking gradients (key {key})'), ).context_message('Error while loading colors configuration')) color_spec = Spec().type(unicode).func(check_color).copy name_spec = Spec().type(unicode).len('gt', 0).optional().copy group_name_spec = Spec().ident().copy group_spec = Spec().either(Spec( fg=color_spec(), bg=color_spec(), attrs=Spec().list(Spec().type(unicode).oneof(set(('bold', 'italic', 'underline')))), ), group_name_spec().func(check_group)).copy groups_spec = Spec().unknown_spec( group_name_spec(), group_spec(), ).context_message('Error while loading groups (key {key})').copy colorscheme_spec = (Spec( name=name_spec(), groups=groups_spec(), ).context_message('Error while loading coloscheme')) mode_translations_value_spec = Spec( colors=Spec().unknown_spec( color_spec(), color_spec(), ).optional(), groups=Spec().unknown_spec( group_name_spec().func(check_translated_group_name), group_spec(), ).optional(), ).copy top_colorscheme_spec = (Spec( name=name_spec(), groups=groups_spec(), mode_translations=Spec().unknown_spec( Spec().type(unicode), mode_translations_value_spec(), ).optional().context_message('Error while loading mode translations (key {key})').optional(), ).context_message('Error while loading top-level coloscheme')) vim_mode_spec = Spec().oneof(set(list(vim_modes) + ['nc', 'tab_nc', 'buf_nc'])).copy vim_colorscheme_spec = (Spec( name=name_spec(), groups=groups_spec(), mode_translations=Spec().unknown_spec( vim_mode_spec(), mode_translations_value_spec(), ).optional().context_message('Error while loading mode translations (key {key})'), ).context_message('Error while loading vim colorscheme')) shell_mode_spec = Spec().re(r'^(?:[\w\-]+|\.safe)$').copy shell_colorscheme_spec = (Spec( name=name_spec(), groups=groups_spec(), mode_translations=Spec().unknown_spec( shell_mode_spec(), mode_translations_value_spec(), ).optional().context_message('Error while loading mode translations (key {key})'), ).context_message('Error while loading shell colorscheme')) args_spec = Spec( pl=Spec().error('pl object must be set by powerline').optional(), segment_info=Spec().error('Segment info dictionary must be set by powerline').optional(), ).unknown_spec(Spec(), Spec()).optional().copy segment_module_spec = Spec().type(unicode).func(check_segment_module).optional().copy exinclude_spec = Spec().re(function_name_re).func(check_exinclude_function).copy segment_spec_base = Spec( name=Spec().re(r'^[a-zA-Z_]\w*$').optional(), function=Spec().re(function_name_re).func(check_segment_function).optional(), exclude_modes=Spec().list(vim_mode_spec()).optional(), include_modes=Spec().list(vim_mode_spec()).optional(), exclude_function=exinclude_spec().optional(), include_function=exinclude_spec().optional(), draw_hard_divider=Spec().type(bool).optional(), draw_soft_divider=Spec().type(bool).optional(), draw_inner_divider=Spec().type(bool).optional(), display=Spec().type(bool).optional(), module=segment_module_spec(), priority=Spec().type(int, float, type(None)).optional(), after=Spec().printable().optional(), before=Spec().printable().optional(), width=Spec().either(Spec().unsigned(), Spec().cmp('eq', 'auto')).optional(), align=Spec().oneof(set('lr')).optional(), args=args_spec().func(lambda *args, **kwargs: check_args(get_one_segment_function, *args, **kwargs)), contents=Spec().printable().optional(), highlight_groups=Spec().list( highlight_group_spec().re( '^(?:(?!:divider$).)+$', (lambda value: 'it is recommended that only divider highlight group names end with ":divider"') ) ).func(check_highlight_groups).optional(), divider_highlight_group=highlight_group_spec().func(check_highlight_group).re( ':divider$', (lambda value: 'it is recommended that divider highlight group names end with ":divider"') ).optional(), ).func(check_full_segment_data).copy subsegment_spec = segment_spec_base().update( type=Spec().oneof(set((key for key in type_keys if key != 'segment_list'))).optional(), ) segment_spec = segment_spec_base().update( type=Spec().oneof(type_keys).optional(), segments=Spec().optional().list(subsegment_spec), ) segments_spec = Spec().optional().list(segment_spec).copy segdict_spec = Spec( left=segments_spec().context_message('Error while loading segments from left side (key {key})'), right=segments_spec().context_message('Error while loading segments from right side (key {key})'), ).func( (lambda value, *args: (True, True, not (('left' in value) or ('right' in value)))), (lambda value: 'segments dictionary must contain either left, right or both keys') ).context_message('Error while loading segments (key {key})').copy divside_spec = Spec( hard=divider_spec(), soft=divider_spec(), ).copy segment_data_value_spec = Spec( after=Spec().printable().optional(), before=Spec().printable().optional(), display=Spec().type(bool).optional(), args=args_spec().func(lambda *args, **kwargs: check_args(get_all_possible_functions, *args, **kwargs)), contents=Spec().printable().optional(), ).copy dividers_spec = Spec( left=divside_spec(), right=divside_spec(), ).copy spaces_spec = Spec().unsigned().cmp( 'le', 2, (lambda value: 'Are you sure you need such a big ({0}) number of spaces?'.format(value)) ).copy common_theme_spec = Spec( default_module=segment_module_spec().optional(), cursor_space=Spec().type(int, float).cmp('le', 100).cmp('gt', 0).optional(), cursor_columns=Spec().type(int).cmp('gt', 0).optional(), ).context_message('Error while loading theme').copy top_theme_spec = common_theme_spec().update( dividers=dividers_spec(), spaces=spaces_spec(), use_non_breaking_spaces=Spec().type(bool).optional(), segment_data=Spec().unknown_spec( Spec().func(check_segment_data_key), segment_data_value_spec(), ).optional().context_message('Error while loading segment data (key {key})'), ) main_theme_spec = common_theme_spec().update( dividers=dividers_spec().optional(), spaces=spaces_spec().optional(), segment_data=Spec().unknown_spec( Spec().func(check_segment_data_key), segment_data_value_spec(), ).optional().context_message('Error while loading segment data (key {key})'), ) theme_spec = common_theme_spec().update( dividers=dividers_spec().optional(), spaces=spaces_spec().optional(), segment_data=Spec().unknown_spec( Spec().func(check_segment_data_key), segment_data_value_spec(), ).optional().context_message('Error while loading segment data (key {key})'), segments=segdict_spec().update(above=Spec().list(segdict_spec()).optional()), ) def register_common_names(): register_common_name('player', 'powerline.segments.common.players', '_player') def load_json_file(path): with open_file(path) as F: try: config, hadproblem = load(F) except MarkedError as e: return True, None, str(e) else: return hadproblem, config, None def updated_with_config(d): hadproblem, config, error = load_json_file(d['path']) d.update( hadproblem=hadproblem, config=config, error=error, ) return d def find_all_ext_config_files(search_paths, subdir): for config_root in search_paths: top_config_subpath = join(config_root, subdir) if not os.path.isdir(top_config_subpath): if os.path.exists(top_config_subpath): yield { 'error': 'Path {0} is not a directory'.format(top_config_subpath), 'path': top_config_subpath, } continue for ext_name in os.listdir(top_config_subpath): ext_path = os.path.join(top_config_subpath, ext_name) if not os.path.isdir(ext_path): if ext_name.endswith('.json') and os.path.isfile(ext_path): yield updated_with_config({ 'error': False, 'path': ext_path, 'name': ext_name[:-5], 'ext': None, 'type': 'top_' + subdir, }) else: yield { 'error': 'Path {0} is not a directory or configuration file'.format(ext_path), 'path': ext_path, } continue for config_file_name in os.listdir(ext_path): config_file_path = os.path.join(ext_path, config_file_name) if config_file_name.endswith('.json') and os.path.isfile(config_file_path): yield updated_with_config({ 'error': False, 'path': config_file_path, 'name': config_file_name[:-5], 'ext': ext_name, 'type': subdir, }) else: yield { 'error': 'Path {0} is not a configuration file'.format(config_file_path), 'path': config_file_path, } def dict2(d): return defaultdict(dict, ((k, dict(v)) for k, v in d.items())) def check(paths=None, debug=False, echoerr=echoerr, require_ext=None): '''Check configuration sanity :param list paths: Paths from which configuration should be loaded. :param bool debug: Determines whether some information useful for debugging linter should be output. :param function echoerr: Function that will be used to echo the error(s). Should accept four optional keyword parameters: ``problem`` and ``problem_mark``, and ``context`` and ``context_mark``. :param str require_ext: Require configuration for some extension to be present. :return: ``False`` if user configuration seems to be completely sane and ``True`` if some problems were found. ''' hadproblem = False register_common_names() search_paths = paths or get_config_paths() find_config_files = generate_config_finder(lambda: search_paths) logger = logging.getLogger('powerline-lint') logger.setLevel(logging.DEBUG if debug else logging.ERROR) logger.addHandler(logging.StreamHandler()) ee = EchoErr(echoerr, logger) if require_ext: used_main_spec = main_spec.copy() try: used_main_spec['ext'][require_ext].required() except KeyError: used_main_spec['ext'][require_ext] = ext_spec() else: used_main_spec = main_spec lhadproblem = [False] load_json_config = generate_json_config_loader(lhadproblem) config_loader = ConfigLoader(run_once=True, load=load_json_config) lists = { 'colorschemes': set(), 'themes': set(), 'exts': set(), } found_dir = { 'themes': False, 'colorschemes': False, } config_paths = defaultdict(lambda: defaultdict(dict)) loaded_configs = defaultdict(lambda: defaultdict(dict)) for d in chain( find_all_ext_config_files(search_paths, 'colorschemes'), find_all_ext_config_files(search_paths, 'themes'), ): if d['error']: hadproblem = True ee(problem=d['error']) continue if d['hadproblem']: hadproblem = True if d['ext']: found_dir[d['type']] = True lists['exts'].add(d['ext']) if d['name'] == '__main__': pass elif d['name'].startswith('__') or d['name'].endswith('__'): hadproblem = True ee(problem='File name is not supposed to start or end with “__”: {0}'.format( d['path'])) else: lists[d['type']].add(d['name']) config_paths[d['type']][d['ext']][d['name']] = d['path'] loaded_configs[d['type']][d['ext']][d['name']] = d['config'] else: config_paths[d['type']][d['name']] = d['path'] loaded_configs[d['type']][d['name']] = d['config'] for typ in ('themes', 'colorschemes'): if not found_dir[typ]: hadproblem = True ee(problem='Subdirectory {0} was not found in paths {1}'.format(typ, ', '.join(search_paths))) diff = set(config_paths['colorschemes']) - set(config_paths['themes']) if diff: hadproblem = True for ext in diff: typ = 'colorschemes' if ext in config_paths['themes'] else 'themes' if not config_paths['top_' + typ] or typ == 'themes': ee(problem='{0} extension {1} not present in {2}'.format( ext, 'configuration' if ( ext in loaded_configs['themes'] and ext in loaded_configs['colorschemes'] ) else 'directory', typ, )) try: main_config = load_config('config', find_config_files, config_loader) except IOError: main_config = {} ee(problem='Configuration file not found: config.json') hadproblem = True except MarkedError as e: main_config = {} ee(problem=str(e)) hadproblem = True else: if used_main_spec.match( main_config, data={'configs': config_paths, 'lists': lists}, context=Context(main_config), echoerr=ee )[1]: hadproblem = True import_paths = [os.path.expanduser(path) for path in main_config.get('common', {}).get('paths', [])] try: colors_config = load_config('colors', find_config_files, config_loader) except IOError: colors_config = {} ee(problem='Configuration file not found: colors.json') hadproblem = True except MarkedError as e: colors_config = {} ee(problem=str(e)) hadproblem = True else: if colors_spec.match(colors_config, context=Context(colors_config), echoerr=ee)[1]: hadproblem = True if lhadproblem[0]: hadproblem = True top_colorscheme_configs = dict(loaded_configs['top_colorschemes']) data = { 'ext': None, 'top_colorscheme_configs': top_colorscheme_configs, 'ext_colorscheme_configs': {}, 'colors_config': colors_config } for colorscheme, config in loaded_configs['top_colorschemes'].items(): data['colorscheme'] = colorscheme if top_colorscheme_spec.match(config, context=Context(config), data=data, echoerr=ee)[1]: hadproblem = True ext_colorscheme_configs = dict2(loaded_configs['colorschemes']) for ext, econfigs in ext_colorscheme_configs.items(): data = { 'ext': ext, 'top_colorscheme_configs': top_colorscheme_configs, 'ext_colorscheme_configs': ext_colorscheme_configs, 'colors_config': colors_config, } for colorscheme, config in econfigs.items(): data['colorscheme'] = colorscheme if ext == 'vim': spec = vim_colorscheme_spec elif ext == 'shell': spec = shell_colorscheme_spec else: spec = colorscheme_spec if spec.match(config, context=Context(config), data=data, echoerr=ee)[1]: hadproblem = True colorscheme_configs = {} for ext in lists['exts']: colorscheme_configs[ext] = {} for colorscheme in lists['colorschemes']: econfigs = ext_colorscheme_configs[ext] ecconfigs = econfigs.get(colorscheme) mconfigs = ( top_colorscheme_configs.get(colorscheme), econfigs.get('__main__'), ecconfigs, ) if not (mconfigs[0] or mconfigs[2]): continue config = None for mconfig in mconfigs: if not mconfig: continue if config: config = mergedicts_copy(config, mconfig) else: config = mconfig colorscheme_configs[ext][colorscheme] = config theme_configs = dict2(loaded_configs['themes']) top_theme_configs = dict(loaded_configs['top_themes']) for ext, configs in theme_configs.items(): data = { 'ext': ext, 'colorscheme_configs': colorscheme_configs, 'import_paths': import_paths, 'main_config': main_config, 'top_themes': top_theme_configs, 'ext_theme_configs': configs, 'colors_config': colors_config } for theme, config in configs.items(): data['theme'] = theme if theme == '__main__': data['theme_type'] = 'main' spec = main_theme_spec else: data['theme_type'] = 'regular' spec = theme_spec if spec.match(config, context=Context(config), data=data, echoerr=ee)[1]: hadproblem = True for top_theme, config in top_theme_configs.items(): data = { 'ext': None, 'colorscheme_configs': colorscheme_configs, 'import_paths': import_paths, 'main_config': main_config, 'theme_configs': theme_configs, 'ext_theme_configs': None, 'colors_config': colors_config } data['theme_type'] = 'top' data['theme'] = top_theme if top_theme_spec.match(config, context=Context(config), data=data, echoerr=ee)[1]: hadproblem = True return hadproblem powerline-2.8.4/powerline/lint/checks.py000066400000000000000000000710741466405252600203400ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import re import logging from collections import defaultdict from powerline.lib.threaded import ThreadedSegment from powerline.lib.unicode import unicode from powerline.lint.markedjson.markedvalue import MarkedUnicode from powerline.lint.markedjson.error import DelayedEchoErr, Mark from powerline.lint.selfcheck import havemarks from powerline.lint.context import JStr, list_themes from powerline.lint.imp import WithPath, import_function, import_segment from powerline.lint.spec import Spec from powerline.lint.inspect import getconfigargspec list_sep = JStr(', ') generic_keys = set(( 'exclude_modes', 'include_modes', 'exclude_function', 'include_function', 'width', 'align', 'name', 'draw_soft_divider', 'draw_hard_divider', 'priority', 'after', 'before', 'display' )) type_keys = { 'function': set(('function', 'args', 'draw_inner_divider')), 'string': set(('contents', 'type', 'highlight_groups', 'divider_highlight_group')), 'segment_list': set(('function', 'segments', 'args', 'type')), } required_keys = { 'function': set(('function',)), 'string': set(()), 'segment_list': set(('function', 'segments',)), } highlight_keys = set(('highlight_groups', 'name')) def get_function_strings(function_name, context, ext): if '.' in function_name: module, function_name = function_name.rpartition('.')[::2] else: module = context[0][1].get( 'default_module', MarkedUnicode('powerline.segments.' + ext, None)) return module, function_name def check_matcher_func(ext, match_name, data, context, echoerr): havemarks(match_name) import_paths = [os.path.expanduser(path) for path in context[0][1].get('common', {}).get('paths', [])] match_module, separator, match_function = match_name.rpartition('.') if not separator: match_module = 'powerline.matchers.{0}'.format(ext) match_function = match_name with WithPath(import_paths): try: func = getattr(__import__(str(match_module), fromlist=[str(match_function)]), str(match_function)) except ImportError: echoerr(context='Error while loading matcher functions', problem='failed to load module {0}'.format(match_module), problem_mark=match_name.mark) return True, False, True except AttributeError: echoerr(context='Error while loading matcher functions', problem='failed to load matcher function {0}'.format(match_function), problem_mark=match_name.mark) return True, False, True if not callable(func): echoerr(context='Error while loading matcher functions', problem='loaded “function” {0} is not callable'.format(match_function), problem_mark=match_name.mark) return True, False, True if hasattr(func, 'func_code') and hasattr(func.func_code, 'co_argcount'): if func.func_code.co_argcount != 1: echoerr( context='Error while loading matcher functions', problem=( 'function {0} accepts {1} arguments instead of 1. ' 'Are you sure it is the proper function?' ).format(match_function, func.func_code.co_argcount), problem_mark=match_name.mark ) return True, False, False def check_ext(ext, data, context, echoerr): havemarks(ext) hadsomedirs = False hadproblem = False if ext not in data['lists']['exts']: hadproblem = True echoerr(context='Error while loading {0} extension configuration'.format(ext), context_mark=ext.mark, problem='extension configuration does not exist') else: for typ in ('themes', 'colorschemes'): if ext not in data['configs'][typ] and not data['configs']['top_' + typ]: hadproblem = True echoerr(context='Error while loading {0} extension configuration'.format(ext), context_mark=ext.mark, problem='{0} configuration does not exist'.format(typ)) else: hadsomedirs = True return hadsomedirs, hadproblem def check_config(d, theme, data, context, echoerr): if len(context) == 4: ext = context[-2][0] else: # local_themes ext = context[-3][0] if ext not in data['lists']['exts']: echoerr(context='Error while loading {0} extension configuration'.format(ext), context_mark=ext.mark, problem='extension configuration does not exist') return True, False, True if ( (ext not in data['configs'][d] or theme not in data['configs'][d][ext]) and theme not in data['configs']['top_' + d] ): echoerr(context='Error while loading {0} from {1} extension configuration'.format(d[:-1], ext), problem='failed to find configuration file {0}/{1}/{2}.json'.format(d, ext, theme), problem_mark=theme.mark) return True, False, True return True, False, False def check_top_theme(theme, data, context, echoerr): havemarks(theme) if theme not in data['configs']['top_themes']: echoerr(context='Error while checking extension configuration (key {key})'.format(key=context.key), context_mark=context[-2][0].mark, problem='failed to find top theme {0}'.format(theme), problem_mark=theme.mark) return True, False, True return True, False, False def check_color(color, data, context, echoerr): havemarks(color) if (color not in data['colors_config'].get('colors', {}) and color not in data['colors_config'].get('gradients', {})): echoerr( context='Error while checking highlight group in colorscheme (key {key})'.format( key=context.key), problem='found unexistent color or gradient {0}'.format(color), problem_mark=color.mark ) return True, False, True return True, False, False def check_translated_group_name(group, data, context, echoerr): return check_group(group, data, context, echoerr) def check_group(group, data, context, echoerr): havemarks(group) if not isinstance(group, unicode): return True, False, False colorscheme = data['colorscheme'] ext = data['ext'] configs = None if ext: def listed_key(d, k): try: return [d[k]] except KeyError: return [] if colorscheme == '__main__': colorscheme_names = set(data['ext_colorscheme_configs'][ext]) colorscheme_names.update(data['top_colorscheme_configs']) colorscheme_names.discard('__main__') configs = [ ( name, listed_key(data['ext_colorscheme_configs'][ext], name) + listed_key(data['ext_colorscheme_configs'][ext], '__main__') + listed_key(data['top_colorscheme_configs'], name) ) for name in colorscheme_names ] else: configs = [ ( colorscheme, listed_key(data['ext_colorscheme_configs'][ext], colorscheme) + listed_key(data['ext_colorscheme_configs'][ext], '__main__') + listed_key(data['top_colorscheme_configs'], colorscheme) ) ] else: try: configs = [(colorscheme, [data['top_colorscheme_configs'][colorscheme]])] except KeyError: pass hadproblem = False for new_colorscheme, config_lst in configs: not_found = [] new_data = data.copy() new_data['colorscheme'] = new_colorscheme for config in config_lst: havemarks(config) try: group_data = config['groups'][group] except KeyError: not_found.append(config.mark.name) else: proceed, echo, chadproblem = check_group( group_data, new_data, context, echoerr, ) if chadproblem: hadproblem = True if not proceed: break if not_found and len(not_found) == len(config_lst): echoerr( context='Error while checking group definition in colorscheme (key {key})'.format( key=context.key), problem='name {0} is not present anywhere in {1} {2} {3} colorschemes: {4}'.format( group, len(not_found), ext, new_colorscheme, ', '.join(not_found)), problem_mark=group.mark ) hadproblem = True return True, False, hadproblem def check_key_compatibility(segment, data, context, echoerr): havemarks(segment) segment_type = segment.get('type', MarkedUnicode('function', None)) havemarks(segment_type) if segment_type not in type_keys: echoerr(context='Error while checking segments (key {key})'.format(key=context.key), problem='found segment with unknown type {0}'.format(segment_type), problem_mark=segment_type.mark) return False, False, True hadproblem = False keys = set(segment) if not ((keys - generic_keys) < type_keys[segment_type]): unknown_keys = keys - generic_keys - type_keys[segment_type] echoerr( context='Error while checking segments (key {key})'.format(key=context.key), context_mark=context[-1][1].mark, problem='found keys not used with the current segment type: {0}'.format( list_sep.join(unknown_keys)), problem_mark=list(unknown_keys)[0].mark ) hadproblem = True if not (keys >= required_keys[segment_type]): missing_keys = required_keys[segment_type] - keys echoerr( context='Error while checking segments (key {key})'.format(key=context.key), context_mark=context[-1][1].mark, problem='found missing required keys: {0}'.format( list_sep.join(missing_keys)) ) hadproblem = True if not (segment_type == 'function' or (keys & highlight_keys)): echoerr( context='Error while checking segments (key {key})'.format(key=context.key), context_mark=context[-1][1].mark, problem=( 'found missing keys required to determine highlight group. ' 'Either highlight_groups or name key must be present' ) ) hadproblem = True return True, False, hadproblem def check_segment_module(module, data, context, echoerr): havemarks(module) with WithPath(data['import_paths']): try: __import__(str(module)) except ImportError as e: if echoerr.logger.level >= logging.DEBUG: echoerr.logger.exception(e) echoerr(context='Error while checking segments (key {key})'.format(key=context.key), problem='failed to import module {0}'.format(module), problem_mark=module.mark) return True, False, True return True, False, False def check_full_segment_data(segment, data, context, echoerr): if 'name' not in segment and 'function' not in segment: return True, False, False ext = data['ext'] theme_segment_data = context[0][1].get('segment_data', {}) main_theme_name = data['main_config'].get('ext', {}).get(ext, {}).get('theme', None) if not main_theme_name or data['theme'] == main_theme_name: top_segment_data = {} else: top_segment_data = data['ext_theme_configs'].get(main_theme_name, {}).get('segment_data', {}) if segment.get('type', 'function') == 'function': function_name = segment.get('function') if function_name: module, function_name = get_function_strings(function_name, context, ext) names = [module + '.' + function_name, function_name] else: names = [] elif segment.get('name'): names = [segment['name']] else: return True, False, False segment_copy = segment.copy() for key in ('before', 'after', 'args', 'contents'): if key not in segment_copy: for segment_data in [theme_segment_data, top_segment_data]: for name in names: try: val = segment_data[name][key] k = segment_data[name].keydict[key] segment_copy[k] = val except KeyError: pass return check_key_compatibility(segment_copy, data, context, echoerr) highlight_group_spec = Spec().ident().copy _highlight_group_spec = highlight_group_spec().context_message( 'Error while checking function documentation while checking theme (key {key})') def check_hl_group_name(hl_group, context_mark, context, echoerr): '''Check highlight group name: it should match naming conventions :param str hl_group: Checked group. :param Mark context_mark: Context mark. May be ``None``. :param Context context: Current context. :param func echoerr: Function used for error reporting. :return: ``False`` if check succeeded and ``True`` if it failed. ''' return _highlight_group_spec.match(hl_group, context_mark=context_mark, context=context, echoerr=echoerr)[1] def check_segment_function(function_name, data, context, echoerr): havemarks(function_name) ext = data['ext'] module, function_name = get_function_strings(function_name, context, ext) if context[-2][1].get('type', 'function') == 'function': func = import_segment(function_name, data, context, echoerr, module=module) if not func: return True, False, True hl_groups = [] divider_hl_group = None hadproblem = False if func.__doc__: NO_H_G_USED_STR = 'No highlight groups are used (literal segment).' H_G_USED_STR = 'Highlight groups used: ' LHGUS = len(H_G_USED_STR) D_H_G_USED_STR = 'Divider highlight group used: ' LDHGUS = len(D_H_G_USED_STR) pointer = 0 mark_name = '<{0} docstring>'.format(function_name) for i, line in enumerate(func.__doc__.split('\n')): if H_G_USED_STR in line: idx = line.index(H_G_USED_STR) + LHGUS if hl_groups is None: idx -= LHGUS mark = Mark(mark_name, i + 1, idx + 1, func.__doc__, pointer + idx) echoerr( context='Error while checking theme (key {key})'.format(key=context.key), context_mark=function_name.mark, problem=( 'found highlight group definition in addition to sentence stating that ' 'no highlight groups are used' ), problem_mark=mark, ) hadproblem = True continue hl_groups.append(( line[idx:], (mark_name, i + 1, idx + 1, func.__doc__), pointer + idx )) elif D_H_G_USED_STR in line: idx = line.index(D_H_G_USED_STR) + LDHGUS + 2 mark = Mark(mark_name, i + 1, idx + 1, func.__doc__, pointer + idx) divider_hl_group = MarkedUnicode(line[idx:-3], mark) elif NO_H_G_USED_STR in line: idx = line.index(NO_H_G_USED_STR) if hl_groups: mark = Mark(mark_name, i + 1, idx + 1, func.__doc__, pointer + idx) echoerr( context='Error while checking theme (key {key})'.format(key=context.key), context_mark=function_name.mark, problem=( 'found sentence stating that no highlight groups are used ' 'in addition to highlight group definition' ), problem_mark=mark, ) hadproblem = True continue hl_groups = None pointer += len(line) + len('\n') if divider_hl_group: r = hl_exists(divider_hl_group, data, context, echoerr, allow_gradients=True) if r: echoerr( context='Error while checking theme (key {key})'.format(key=context.key), context_mark=function_name.mark, problem=( 'found highlight group {0} not defined in the following colorschemes: {1}\n' '(Group name was obtained from function documentation.)' ).format(divider_hl_group, list_sep.join(r)), problem_mark=divider_hl_group.mark, ) hadproblem = True if check_hl_group_name(divider_hl_group, function_name.mark, context, echoerr): hadproblem = True if hl_groups: greg = re.compile(r'``([^`]+)``( \(gradient\))?') parsed_hl_groups = [] for line, mark_args, pointer in hl_groups: for s in line.split(', '): required_pack = [] sub_pointer = pointer for subs in s.split(' or '): match = greg.match(subs) try: if not match: continue hl_group = MarkedUnicode( match.group(1), Mark(*mark_args, pointer=sub_pointer + match.start(1)) ) if check_hl_group_name(hl_group, function_name.mark, context, echoerr): hadproblem = True gradient = bool(match.group(2)) required_pack.append((hl_group, gradient)) finally: sub_pointer += len(subs) + len(' or ') parsed_hl_groups.append(required_pack) pointer += len(s) + len(', ') del hl_group, gradient for required_pack in parsed_hl_groups: rs = [ hl_exists(hl_group, data, context, echoerr, allow_gradients=('force' if gradient else False)) for hl_group, gradient in required_pack ] if all(rs): echoerr( context='Error while checking theme (key {key})'.format(key=context.key), problem=( 'found highlight groups list ({0}) with all groups not defined in some colorschemes\n' '(Group names were taken from function documentation.)' ).format(list_sep.join((h[0] for h in required_pack))), problem_mark=function_name.mark ) for r, h in zip(rs, required_pack): echoerr( context='Error while checking theme (key {key})'.format(key=context.key), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( h[0], list_sep.join(r)) ) hadproblem = True elif hl_groups is not None: r = hl_exists(function_name, data, context, echoerr, allow_gradients=True) if r: echoerr( context='Error while checking theme (key {key})'.format(key=context.key), problem=( 'found highlight group {0} not defined in the following colorschemes: {1}\n' '(If not specified otherwise in documentation, ' 'highlight group for function segments\n' 'is the same as the function name.)' ).format(function_name, list_sep.join(r)), problem_mark=function_name.mark ) hadproblem = True return True, False, hadproblem elif context[-2][1].get('type') != 'segment_list': if function_name not in context[0][1].get('segment_data', {}): main_theme_name = data['main_config'].get('ext', {}).get(ext, {}).get('theme', None) if data['theme'] == main_theme_name: main_theme = {} else: main_theme = data['ext_theme_configs'].get(main_theme_name, {}) if ( function_name not in main_theme.get('segment_data', {}) and function_name not in data['ext_theme_configs'].get('__main__', {}).get('segment_data', {}) and not any(((function_name in theme.get('segment_data', {})) for theme in data['top_themes'].values())) ): echoerr(context='Error while checking segments (key {key})'.format(key=context.key), problem='found useless use of name key (such name is not present in theme/segment_data)', problem_mark=function_name.mark) return True, False, False def hl_group_in_colorscheme(hl_group, cconfig, allow_gradients, data, context, echoerr): havemarks(hl_group, cconfig) if hl_group not in cconfig.get('groups', {}): return False elif not allow_gradients or allow_gradients == 'force': group_config = cconfig['groups'][hl_group] while isinstance(group_config, unicode): try: group_config = cconfig['groups'][group_config] except KeyError: # No such group. Error was already reported when checking # colorschemes. return True havemarks(group_config) hadgradient = False for ckey in ('fg', 'bg'): color = group_config.get(ckey) if not color: # No color. Error was already reported when checking # colorschemes. return True havemarks(color) # Gradients are only allowed for function segments. Note that # whether *either* color or gradient exists should have been # already checked hascolor = color in data['colors_config'].get('colors', {}) hasgradient = color in data['colors_config'].get('gradients', {}) if hasgradient: hadgradient = True if allow_gradients is False and not hascolor and hasgradient: echoerr( context='Error while checking highlight group in theme (key {key})'.format( key=context.key), context_mark=hl_group.mark, problem='group {0} is using gradient {1} instead of a color'.format(hl_group, color), problem_mark=color.mark ) return False if allow_gradients == 'force' and not hadgradient: echoerr( context='Error while checking highlight group in theme (key {key})'.format( key=context.key), context_mark=hl_group.mark, problem='group {0} should have at least one gradient color, but it has no'.format(hl_group), problem_mark=group_config.mark ) return False return True def hl_exists(hl_group, data, context, echoerr, allow_gradients=False): havemarks(hl_group) ext = data['ext'] if ext not in data['colorscheme_configs']: # No colorschemes. Error was already reported, no need to report it # twice return [] r = [] found = False for colorscheme, cconfig in data['colorscheme_configs'][ext].items(): if hl_group_in_colorscheme(hl_group, cconfig, allow_gradients, data, context, echoerr): found = True else: r.append(colorscheme) if not found: pass return r def check_highlight_group(hl_group, data, context, echoerr): havemarks(hl_group) r = hl_exists(hl_group, data, context, echoerr) if r: echoerr( context='Error while checking theme (key {key})'.format(key=context.key), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( hl_group, list_sep.join(r)), problem_mark=hl_group.mark ) return True, False, True return True, False, False def check_highlight_groups(hl_groups, data, context, echoerr): havemarks(hl_groups) rs = [hl_exists(hl_group, data, context, echoerr) for hl_group in hl_groups] if all(rs): echoerr( context='Error while checking theme (key {key})'.format(key=context.key), problem='found highlight groups list ({0}) with all groups not defined in some colorschemes'.format( list_sep.join((unicode(h) for h in hl_groups))), problem_mark=hl_groups.mark ) for r, hl_group in zip(rs, hl_groups): echoerr( context='Error while checking theme (key {key})'.format(key=context.key), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( hl_group, list_sep.join(r)), problem_mark=hl_group.mark ) return True, False, True return True, False, False def check_segment_data_key(key, data, context, echoerr): havemarks(key) has_module_name = '.' in key found = False for ext, theme in list_themes(data, context): for segments in theme.get('segments', {}).values(): for segment in segments: if 'name' in segment: if key == segment['name']: found = True break else: function_name = segment.get('function') if function_name: module, function_name = get_function_strings(function_name, ((None, theme),), ext) if has_module_name: full_name = module + '.' + function_name if key == full_name: found = True break else: if key == function_name: found = True break if found: break if found: break else: if data['theme_type'] != 'top': echoerr(context='Error while checking segment data', problem='found key {0} that cannot be associated with any segment'.format(key), problem_mark=key.mark) return True, False, True return True, False, False threaded_args_specs = { 'interval': Spec().cmp('gt', 0.0), 'update_first': Spec().type(bool), 'shutdown_event': Spec().error('Shutdown event must be set by powerline'), } def check_args_variant(func, args, data, context, echoerr): havemarks(args) argspec = getconfigargspec(func) present_args = set(args) all_args = set(argspec.args) required_args = set(argspec.args[:-len(argspec.defaults)]) hadproblem = False if required_args - present_args: echoerr( context='Error while checking segment arguments (key {key})'.format(key=context.key), context_mark=args.mark, problem='some of the required keys are missing: {0}'.format(list_sep.join(required_args - present_args)) ) hadproblem = True if not all_args >= present_args: echoerr(context='Error while checking segment arguments (key {key})'.format(key=context.key), context_mark=args.mark, problem='found unknown keys: {0}'.format(list_sep.join(present_args - all_args)), problem_mark=next(iter(present_args - all_args)).mark) hadproblem = True if isinstance(func, ThreadedSegment): for key in set(threaded_args_specs) & present_args: proceed, khadproblem = threaded_args_specs[key].match( args[key], args.mark, data, context.enter_key(args, key), echoerr ) if khadproblem: hadproblem = True if not proceed: return hadproblem return hadproblem def check_args(get_functions, args, data, context, echoerr): new_echoerr = DelayedEchoErr(echoerr) count = 0 hadproblem = False for func in get_functions(data, context, new_echoerr): count += 1 shadproblem = check_args_variant(func, args, data, context, echoerr) if shadproblem: hadproblem = True if not count: hadproblem = True if new_echoerr: new_echoerr.echo_all() else: echoerr(context='Error while checking segment arguments (key {key})'.format(key=context.key), context_mark=context[-2][1].mark, problem='no suitable segments found') return True, False, hadproblem def get_one_segment_function(data, context, echoerr): ext = data['ext'] function_name = context[-2][1].get('function') if function_name: module, function_name = get_function_strings(function_name, context, ext) func = import_segment(function_name, data, context, echoerr, module=module) if func: yield func common_names = defaultdict(set) def register_common_name(name, cmodule, cname): s = cmodule + '.' + cname cmodule_mark = Mark('', 1, 1, s, 1) cname_mark = Mark('', 1, len(cmodule) + 1, s, len(cmodule) + 1) common_names[name].add((MarkedUnicode(cmodule, cmodule_mark), MarkedUnicode(cname, cname_mark))) def get_all_possible_functions(data, context, echoerr): name = context[-2][0] module, name = name.rpartition('.')[::2] if module: func = import_segment(name, data, context, echoerr, module=module) if func: yield func else: if name in common_names: for cmodule, cname in common_names[name]: cfunc = import_segment(cname, data, context, echoerr, module=MarkedUnicode(cmodule, None)) if cfunc: yield cfunc for ext, theme_config in list_themes(data, context): for segments in theme_config.get('segments', {}).values(): for segment in segments: if segment.get('type', 'function') == 'function': function_name = segment.get('function') current_name = segment.get('name') if function_name: module, function_name = get_function_strings(function_name, ((None, theme_config),), ext) if current_name == name or function_name == name: func = import_segment(function_name, data, context, echoerr, module=module) if func: yield func def check_exinclude_function(name, data, context, echoerr): ext = data['ext'] module, name = name.rpartition('.')[::2] if not module: module = MarkedUnicode('powerline.selectors.' + ext, None) func = import_function('selector', name, data, context, echoerr, module=module) if not func: return True, False, True return True, False, False def check_log_file_level(this_level, data, context, echoerr): '''Check handler level specified in :ref:`log_file key ` This level must be greater or equal to the level in :ref:`log_level key `. ''' havemarks(this_level) hadproblem = False top_level = context[0][1].get('common', {}).get('log_level', 'WARNING') top_level_str = top_level top_level_mark = getattr(top_level, 'mark', None) if ( not isinstance(top_level, unicode) or not hasattr(logging, top_level) or not isinstance(this_level, unicode) or not hasattr(logging, this_level) ): return True, False, hadproblem top_level = getattr(logging, top_level) this_level_str = this_level this_level_mark = this_level.mark this_level = getattr(logging, this_level) if this_level < top_level: echoerr( context='Error while checking log level index (key {key})'.format( key=context.key), context_mark=this_level_mark, problem='found level that is less critical then top level ({0} < {0})'.format( this_level_str, top_level_str), problem_mark=top_level_mark, ) hadproblem = True return True, False, hadproblem def check_logging_handler(handler_name, data, context, echoerr): havemarks(handler_name) import_paths = [os.path.expanduser(path) for path in context[0][1].get('common', {}).get('paths', [])] handler_module, separator, handler_class = handler_name.rpartition('.') if not separator: handler_module = 'logging.handlers' handler_class = handler_name with WithPath(import_paths): try: handler = getattr(__import__(str(handler_module), fromlist=[str(handler_class)]), str(handler_class)) except ImportError: echoerr(context='Error while loading logger class (key {key})'.format(key=context.key), problem='failed to load module {0}'.format(handler_module), problem_mark=handler_name.mark) return True, False, True except AttributeError: echoerr(context='Error while loading logger class (key {key})'.format(key=context.key), problem='failed to load handler class {0}'.format(handler_class), problem_mark=handler_name.mark) return True, False, True if not issubclass(handler, logging.Handler): echoerr(context='Error while loading logger class (key {key})'.format(key=context.key), problem='loaded class {0} is not a logging.Handler subclass'.format(handler_class), problem_mark=handler_name.mark) return True, False, True return True, False, False powerline-2.8.4/powerline/lint/context.py000066400000000000000000000037761466405252600205700ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import itertools from powerline.lib.unicode import unicode from powerline.lint.markedjson.markedvalue import MarkedUnicode from powerline.lint.selfcheck import havemarks class JStr(unicode): def join(self, iterable): return super(JStr, self).join((unicode(item) for item in iterable)) key_sep = JStr('/') def list_themes(data, context): theme_type = data['theme_type'] ext = data['ext'] main_theme_name = data['main_config'].get('ext', {}).get(ext, {}).get('theme', None) is_main_theme = (data['theme'] == main_theme_name) if theme_type == 'top': return list(itertools.chain(*[ [(theme_ext, theme) for theme in theme_configs.values()] for theme_ext, theme_configs in data['theme_configs'].items() ])) elif theme_type == 'main' or is_main_theme: return [(ext, theme) for theme in data['ext_theme_configs'].values()] else: return [(ext, context[0][1])] class Context(tuple): for func in dir(tuple): if func in ('__getitem__', '__init__', '__getattribute__', '__len__', '__iter__'): continue exec(( 'def {0}(self, *args, **kwargs):\n' ' raise TypeError("{0} is not allowed for Context")' ).format(func)) del func __slots__ = () def __new__(cls, base, context_key=None, context_value=None): if context_key is not None: assert(context_value is not None) assert(type(base) is Context) havemarks(context_key, context_value) return tuple.__new__(cls, tuple.__add__(base, ((context_key, context_value),))) else: havemarks(base) return tuple.__new__(cls, ((MarkedUnicode('', base.mark), base),)) @property def key(self): return key_sep.join((c[0] for c in self)) def enter_key(self, value, key): return self.enter(value.keydict[key], value[key]) def enter_item(self, name, item): return self.enter(MarkedUnicode(name, item.mark), item) def enter(self, context_key, context_value): return Context.__new__(Context, self, context_key, context_value) powerline-2.8.4/powerline/lint/imp.py000066400000000000000000000035241466405252600176600ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys from powerline.lint.selfcheck import havemarks class WithPath(object): def __init__(self, import_paths): self.import_paths = import_paths def __enter__(self): self.oldpath = sys.path sys.path = self.import_paths + sys.path def __exit__(self, *args): sys.path = self.oldpath def import_function(function_type, name, data, context, echoerr, module): havemarks(name, module) if module == 'powerline.segments.i3wm' and name == 'workspaces': echoerr(context='Warning while checking segments (key {key})'.format(key=context.key), context_mark=name.mark, problem='segment {0} from {1} is deprecated'.format(name, module), problem_mark=module.mark) with WithPath(data['import_paths']): try: func = getattr(__import__(str(module), fromlist=[str(name)]), str(name)) except ImportError: echoerr(context='Error while checking segments (key {key})'.format(key=context.key), context_mark=name.mark, problem='failed to import module {0}'.format(module), problem_mark=module.mark) return None except AttributeError: echoerr(context='Error while loading {0} function (key {key})'.format(function_type, key=context.key), problem='failed to load function {0} from module {1}'.format(name, module), problem_mark=name.mark) return None if not callable(func): echoerr(context='Error while checking segments (key {key})'.format(key=context.key), context_mark=name.mark, problem='imported “function” {0} from module {1} is not callable'.format(name, module), problem_mark=module.mark) return None return func def import_segment(*args, **kwargs): return import_function('segment', *args, **kwargs) powerline-2.8.4/powerline/lint/inspect.py000066400000000000000000000052661466405252600205450ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from inspect import FullArgSpec, getfullargspec from itertools import zip_longest from powerline.segments import Segment def getconfigargspec(obj): if hasattr(obj, 'powerline_origin'): obj = obj.powerline_origin else: obj = obj args = [] defaults = [] if isinstance(obj, Segment): additional_args = obj.additional_args() argspecobjs = obj.argspecobjs() get_omitted_args = obj.omitted_args else: additional_args = () argspecobjs = ((None, obj),) get_omitted_args = lambda *args: () for arg in additional_args: args.append(arg[0]) if len(arg) > 1: defaults.append(arg[1]) requires_segment_info = hasattr(obj, 'powerline_requires_segment_info') requires_filesystem_watcher = hasattr(obj, 'powerline_requires_filesystem_watcher') for name, method in argspecobjs: argspec = getfullargspec(method) omitted_args = get_omitted_args(name, method) largs = len(argspec.args) for i, arg in enumerate(reversed(argspec.args)): if ( largs - (i + 1) in omitted_args or arg in omitted_args or arg == 'pl' or arg == 'self' or (arg == 'create_watcher' and requires_filesystem_watcher) or (arg == 'segment_info' and requires_segment_info) ): continue if argspec.defaults and len(argspec.defaults) > i: if arg in args: idx = args.index(arg) if len(args) - idx > len(defaults): args.pop(idx) else: continue default = argspec.defaults[-(i + 1)] defaults.append(default) args.append(arg) else: if arg not in args: args.insert(0, arg) return FullArgSpec(args=args, varargs=None, varkw=None, defaults=tuple(defaults), kwonlyargs=(), kwonlydefaults={}, annotations={}) def formatconfigargspec(args, varargs=None, varkw=None, defaults=None, kwonlyargs=(), kwonlydefaults={}, annotations={}, formatvalue=lambda value: '=' + repr(value)): '''Format an argument spec from the values returned by getconfigargspec. This is a specialized replacement for inspect.formatargspec, which has been deprecated since Python 3.5 and was removed in Python 3.11. It supports valid values for args, defaults and formatvalue; all other parameters are expected to be either empty or None. ''' assert varargs is None assert varkw is None assert not kwonlyargs assert not kwonlydefaults assert not annotations specs = [] if defaults: firstdefault = len(args) - len(defaults) for i, arg in enumerate(args): spec = arg if defaults and i >= firstdefault: spec += formatvalue(defaults[i - firstdefault]) specs.append(spec) return '(' + ', '.join(specs) + ')' powerline-2.8.4/powerline/lint/markedjson/000077500000000000000000000000001466405252600206525ustar00rootroot00000000000000powerline-2.8.4/powerline/lint/markedjson/__init__.py000066400000000000000000000010501466405252600227570ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lint.markedjson.loader import Loader def load(stream, Loader=Loader): '''Parse JSON value and produce the corresponding Python object :return: (hadproblem, object) where first argument is true if there were errors during loading JSON stream and second is the corresponding JSON object. ''' loader = Loader(stream) try: r = loader.get_single_data() return r, loader.haserrors finally: loader.dispose() powerline-2.8.4/powerline/lint/markedjson/composer.py000066400000000000000000000070051466405252600230550ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lint.markedjson import nodes from powerline.lint.markedjson import events from powerline.lint.markedjson.error import MarkedError __all__ = ['Composer', 'ComposerError'] class ComposerError(MarkedError): pass class Composer: def __init__(self): pass def check_node(self): # Drop the STREAM-START event. if self.check_event(events.StreamStartEvent): self.get_event() # If there are more documents available? return not self.check_event(events.StreamEndEvent) def get_node(self): # Get the root node of the next document. if not self.check_event(events.StreamEndEvent): return self.compose_document() def get_single_node(self): # Drop the STREAM-START event. self.get_event() # Compose a document if the stream is not empty. document = None if not self.check_event(events.StreamEndEvent): document = self.compose_document() # Ensure that the stream contains no more documents. if not self.check_event(events.StreamEndEvent): event = self.get_event() raise ComposerError( 'expected a single document in the stream', document.start_mark, 'but found another document', event.start_mark ) # Drop the STREAM-END event. self.get_event() return document def compose_document(self): # Drop the DOCUMENT-START event. self.get_event() # Compose the root node. node = self.compose_node(None, None) # Drop the DOCUMENT-END event. self.get_event() return node def compose_node(self, parent, index): self.descend_resolver(parent, index) if self.check_event(events.ScalarEvent): node = self.compose_scalar_node() elif self.check_event(events.SequenceStartEvent): node = self.compose_sequence_node() elif self.check_event(events.MappingStartEvent): node = self.compose_mapping_node() self.ascend_resolver() return node def compose_scalar_node(self): event = self.get_event() tag = event.tag if tag is None or tag == '!': tag = self.resolve(nodes.ScalarNode, event.value, event.implicit, event.start_mark) node = nodes.ScalarNode(tag, event.value, event.start_mark, event.end_mark, style=event.style) return node def compose_sequence_node(self): start_event = self.get_event() tag = start_event.tag if tag is None or tag == '!': tag = self.resolve(nodes.SequenceNode, None, start_event.implicit) node = nodes.SequenceNode(tag, [], start_event.start_mark, None, flow_style=start_event.flow_style) index = 0 while not self.check_event(events.SequenceEndEvent): node.value.append(self.compose_node(node, index)) index += 1 end_event = self.get_event() node.end_mark = end_event.end_mark return node def compose_mapping_node(self): start_event = self.get_event() tag = start_event.tag if tag is None or tag == '!': tag = self.resolve(nodes.MappingNode, None, start_event.implicit) node = nodes.MappingNode(tag, [], start_event.start_mark, None, flow_style=start_event.flow_style) while not self.check_event(events.MappingEndEvent): # key_event = self.peek_event() item_key = self.compose_node(node, None) # if item_key in node.value: # raise ComposerError('while composing a mapping', start_event.start_mark, # 'found duplicate key', key_event.start_mark) item_value = self.compose_node(node, item_key) # node.value[item_key] = item_value node.value.append((item_key, item_value)) end_event = self.get_event() node.end_mark = end_event.end_mark return node powerline-2.8.4/powerline/lint/markedjson/constructor.py000066400000000000000000000171331466405252600236160ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import collections import types from functools import wraps from powerline.lint.markedjson.error import MarkedError from powerline.lint.markedjson import nodes from powerline.lint.markedjson.markedvalue import gen_marked_value from powerline.lib.unicode import unicode def marked(func): @wraps(func) def f(self, node, *args, **kwargs): return gen_marked_value(func(self, node, *args, **kwargs), node.start_mark) return f class ConstructorError(MarkedError): pass class BaseConstructor: yaml_constructors = {} def __init__(self): self.constructed_objects = {} self.state_generators = [] self.deep_construct = False def check_data(self): # If there are more documents available? return self.check_node() def get_data(self): # Construct and return the next document. if self.check_node(): return self.construct_document(self.get_node()) def get_single_data(self): # Ensure that the stream contains a single document and construct it. node = self.get_single_node() if node is not None: return self.construct_document(node) return None def construct_document(self, node): data = self.construct_object(node) while self.state_generators: state_generators = self.state_generators self.state_generators = [] for generator in state_generators: for dummy in generator: pass self.constructed_objects = {} self.deep_construct = False return data def construct_object(self, node, deep=False): if node in self.constructed_objects: return self.constructed_objects[node] if deep: old_deep = self.deep_construct self.deep_construct = True constructor = None tag_suffix = None if node.tag in self.yaml_constructors: constructor = self.yaml_constructors[node.tag] else: raise ConstructorError(None, None, 'no constructor for tag %s' % node.tag) if tag_suffix is None: data = constructor(self, node) else: data = constructor(self, tag_suffix, node) if isinstance(data, types.GeneratorType): generator = data data = next(generator) if self.deep_construct: for dummy in generator: pass else: self.state_generators.append(generator) self.constructed_objects[node] = data if deep: self.deep_construct = old_deep return data @marked def construct_scalar(self, node): if not isinstance(node, nodes.ScalarNode): raise ConstructorError( None, None, 'expected a scalar node, but found %s' % node.id, node.start_mark ) return node.value def construct_sequence(self, node, deep=False): if not isinstance(node, nodes.SequenceNode): raise ConstructorError( None, None, 'expected a sequence node, but found %s' % node.id, node.start_mark ) return [ self.construct_object(child, deep=deep) for child in node.value ] @marked def construct_mapping(self, node, deep=False): if not isinstance(node, nodes.MappingNode): raise ConstructorError( None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark ) mapping = {} for key_node, value_node in node.value: key = self.construct_object(key_node, deep=deep) if not isinstance(key, collections.abc.Hashable): self.echoerr( 'While constructing a mapping', node.start_mark, 'found unhashable key', key_node.start_mark ) continue elif type(key.value) != unicode: self.echoerr( 'Error while constructing a mapping', node.start_mark, 'found key that is not a string', key_node.start_mark ) continue elif key in mapping: self.echoerr( 'Error while constructing a mapping', node.start_mark, 'found duplicate key', key_node.start_mark ) continue value = self.construct_object(value_node, deep=deep) mapping[key] = value return mapping @classmethod def add_constructor(cls, tag, constructor): if 'yaml_constructors' not in cls.__dict__: cls.yaml_constructors = cls.yaml_constructors.copy() cls.yaml_constructors[tag] = constructor class Constructor(BaseConstructor): def construct_scalar(self, node): if isinstance(node, nodes.MappingNode): for key_node, value_node in node.value: if key_node.tag == 'tag:yaml.org,2002:value': return self.construct_scalar(value_node) return BaseConstructor.construct_scalar(self, node) def flatten_mapping(self, node): merge = [] index = 0 while index < len(node.value): key_node, value_node = node.value[index] if key_node.tag == 'tag:yaml.org,2002:merge': del node.value[index] if isinstance(value_node, nodes.MappingNode): self.flatten_mapping(value_node) merge.extend(value_node.value) elif isinstance(value_node, nodes.SequenceNode): submerge = [] for subnode in value_node.value: if not isinstance(subnode, nodes.MappingNode): raise ConstructorError( 'while constructing a mapping', node.start_mark, 'expected a mapping for merging, but found %s' % subnode.id, subnode.start_mark ) self.flatten_mapping(subnode) submerge.append(subnode.value) submerge.reverse() for value in submerge: merge.extend(value) else: raise ConstructorError( 'while constructing a mapping', node.start_mark, ('expected a mapping or list of mappings for merging, but found %s' % value_node.id), value_node.start_mark ) elif key_node.tag == 'tag:yaml.org,2002:value': key_node.tag = 'tag:yaml.org,2002:str' index += 1 else: index += 1 if merge: node.value = merge + node.value def construct_mapping(self, node, deep=False): if isinstance(node, nodes.MappingNode): self.flatten_mapping(node) return BaseConstructor.construct_mapping(self, node, deep=deep) @marked def construct_yaml_null(self, node): self.construct_scalar(node) return None @marked def construct_yaml_bool(self, node): value = self.construct_scalar(node).value return bool(value) @marked def construct_yaml_int(self, node): value = self.construct_scalar(node).value sign = +1 if value[0] == '-': sign = -1 if value[0] in '+-': value = value[1:] if value == '0': return 0 else: return sign * int(value) @marked def construct_yaml_float(self, node): value = self.construct_scalar(node).value sign = +1 if value[0] == '-': sign = -1 if value[0] in '+-': value = value[1:] else: return sign * float(value) def construct_yaml_str(self, node): return self.construct_scalar(node) def construct_yaml_seq(self, node): data = gen_marked_value([], node.start_mark) yield data data.extend(self.construct_sequence(node)) def construct_yaml_map(self, node): data = gen_marked_value({}, node.start_mark) yield data value = self.construct_mapping(node) data.update(value) def construct_undefined(self, node): raise ConstructorError( None, None, 'could not determine a constructor for the tag %r' % node.tag, node.start_mark ) Constructor.add_constructor( 'tag:yaml.org,2002:null', Constructor.construct_yaml_null) Constructor.add_constructor( 'tag:yaml.org,2002:bool', Constructor.construct_yaml_bool) Constructor.add_constructor( 'tag:yaml.org,2002:int', Constructor.construct_yaml_int) Constructor.add_constructor( 'tag:yaml.org,2002:float', Constructor.construct_yaml_float) Constructor.add_constructor( 'tag:yaml.org,2002:str', Constructor.construct_yaml_str) Constructor.add_constructor( 'tag:yaml.org,2002:seq', Constructor.construct_yaml_seq) Constructor.add_constructor( 'tag:yaml.org,2002:map', Constructor.construct_yaml_map) Constructor.add_constructor( None, Constructor.construct_undefined) powerline-2.8.4/powerline/lint/markedjson/error.py000066400000000000000000000154441466405252600223650ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import re from powerline.lib.encoding import get_preferred_output_encoding NON_PRINTABLE_STR = ( '[^' # ASCII control characters: 0x00-0x19 + '\t\n' # Tab, newline: allowed ASCII control characters + '\x20-\x7E' # ASCII printable characters # Unicode control characters: 0x7F-0x9F + '\u0085' # Allowed unicode control character: next line character + '\u00A0-\uD7FF' # Surrogate escapes: 0xD800-0xDFFF + '\uE000-\uFFFD' + (( '\uD800-\uDFFF' ) if sys.maxunicode < 0x10FFFF else ( '\U00010000-\U0010FFFF' )) + ']' + (( # Paired surrogate escapes: allowed in UCS-2 builds as the only way to # represent characters above 0xFFFF. Only paired variant is allowed. '|(?' % ord(s.group()) def strtrans(s): return NON_PRINTABLE_RE.sub(repl, s.replace('\t', '>---')) class Mark: def __init__(self, name, line, column, buffer, pointer, old_mark=None, merged_marks=None): self.name = name self.line = line self.column = column self.buffer = buffer self.pointer = pointer self.old_mark = old_mark self.merged_marks = merged_marks or [] def copy(self): return Mark(self.name, self.line, self.column, self.buffer, self.pointer, self.old_mark, self.merged_marks[:]) def get_snippet(self, indent=4, max_length=75): if self.buffer is None: return None head = '' start = self.pointer while start > 0 and self.buffer[start - 1] not in '\0\n': start -= 1 if self.pointer - start > max_length / 2 - 1: head = ' ... ' start += 5 break tail = '' end = self.pointer while end < len(self.buffer) and self.buffer[end] not in '\0\n': end += 1 if end - self.pointer > max_length / 2 - 1: tail = ' ... ' end -= 5 break snippet = [self.buffer[start:self.pointer], self.buffer[self.pointer], self.buffer[self.pointer + 1:end]] snippet = [strtrans(s) for s in snippet] return ( ' ' * indent + head + ''.join(snippet) + tail + '\n' + ' ' * (indent + len(head) + len(snippet[0])) + '^' ) def advance_string(self, diff): ret = self.copy() # FIXME Currently does not work properly with escaped strings. ret.column += diff ret.pointer += diff return ret def set_old_mark(self, old_mark): if self is old_mark: return checked_marks = set([id(self)]) older_mark = old_mark while True: if id(older_mark) in checked_marks: raise ValueError('Trying to set recursive marks') checked_marks.add(id(older_mark)) older_mark = older_mark.old_mark if not older_mark: break self.old_mark = old_mark def set_merged_mark(self, merged_mark): self.merged_marks.append(merged_mark) def to_string(self, indent=0, head_text='in ', add_snippet=True): mark = self where = '' processed_marks = set() while mark: indentstr = ' ' * indent where += ('%s %s"%s", line %d, column %d' % ( indentstr, head_text, mark.name, mark.line + 1, mark.column + 1)) if add_snippet: snippet = mark.get_snippet(indent=(indent + 4)) if snippet: where += ':\n' + snippet if mark.merged_marks: where += '\n' + indentstr + ' with additionally merged\n' where += mark.merged_marks[0].to_string(indent + 4, head_text='', add_snippet=False) for mmark in mark.merged_marks[1:]: where += '\n' + indentstr + ' and\n' where += mmark.to_string(indent + 4, head_text='', add_snippet=False) if add_snippet: processed_marks.add(id(mark)) if mark.old_mark: where += '\n' + indentstr + ' which replaced value\n' indent += 4 mark = mark.old_mark if id(mark) in processed_marks: raise ValueError('Trying to dump recursive mark') return where if sys.version_info < (3,): def __str__(self): return self.to_string().encode('utf-8') def __unicode__(self): return self.to_string() else: def __str__(self): return self.to_string() def __eq__(self, other): return self is other or ( self.name == other.name and self.line == other.line and self.column == other.column ) if sys.version_info < (3,): def echoerr(**kwargs): stream = kwargs.pop('stream', sys.stderr) stream.write('\n') stream.write((format_error(**kwargs) + '\n').encode(get_preferred_output_encoding())) else: def echoerr(**kwargs): stream = kwargs.pop('stream', sys.stderr) stream.write('\n') stream.write(format_error(**kwargs) + '\n') def format_error(context=None, context_mark=None, problem=None, problem_mark=None, note=None, indent=0): lines = [] indentstr = ' ' * indent if context is not None: lines.append(indentstr + context) if ( context_mark is not None and ( problem is None or problem_mark is None or context_mark != problem_mark ) ): lines.append(context_mark.to_string(indent=indent)) if problem is not None: lines.append(indentstr + problem) if problem_mark is not None: lines.append(problem_mark.to_string(indent=indent)) if note is not None: lines.append(indentstr + note) return '\n'.join(lines) class MarkedError(Exception): def __init__(self, context=None, context_mark=None, problem=None, problem_mark=None, note=None): Exception.__init__(self, format_error(context, context_mark, problem, problem_mark, note)) class EchoErr(object): __slots__ = ('echoerr', 'logger', 'indent') def __init__(self, echoerr, logger, indent=0): self.echoerr = echoerr self.logger = logger self.indent = indent def __call__(self, **kwargs): kwargs = kwargs.copy() kwargs.setdefault('indent', self.indent) self.echoerr(**kwargs) class DelayedEchoErr(EchoErr): __slots__ = ('echoerr', 'logger', 'errs', 'message', 'separator_message', 'indent', 'indent_shift') def __init__(self, echoerr, message='', separator_message=''): super(DelayedEchoErr, self).__init__(echoerr, echoerr.logger) self.errs = [[]] self.message = message self.separator_message = separator_message self.indent_shift = (4 if message or separator_message else 0) self.indent = echoerr.indent + self.indent_shift def __call__(self, **kwargs): kwargs = kwargs.copy() kwargs['indent'] = kwargs.get('indent', 0) + self.indent self.errs[-1].append(kwargs) def next_variant(self): self.errs.append([]) def echo_all(self): if self.message: self.echoerr(problem=self.message, indent=(self.indent - self.indent_shift)) for variant in self.errs: if not variant: continue if self.separator_message and variant is not self.errs[0]: self.echoerr(problem=self.separator_message, indent=(self.indent - self.indent_shift)) for kwargs in variant: self.echoerr(**kwargs) def __nonzero__(self): return not not self.errs __bool__ = __nonzero__ powerline-2.8.4/powerline/lint/markedjson/events.py000066400000000000000000000041551466405252600225350ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) # Abstract classes. class Event(object): def __init__(self, start_mark=None, end_mark=None): self.start_mark = start_mark self.end_mark = end_mark def __repr__(self): attributes = [ key for key in ['implicit', 'value'] if hasattr(self, key) ] arguments = ', '.join([ '%s=%r' % (key, getattr(self, key)) for key in attributes ]) return '%s(%s)' % (self.__class__.__name__, arguments) class NodeEvent(Event): def __init__(self, start_mark=None, end_mark=None): self.start_mark = start_mark self.end_mark = end_mark class CollectionStartEvent(NodeEvent): def __init__(self, implicit, start_mark=None, end_mark=None, flow_style=None): self.tag = None self.implicit = implicit self.start_mark = start_mark self.end_mark = end_mark self.flow_style = flow_style class CollectionEndEvent(Event): pass # Implementations. class StreamStartEvent(Event): def __init__(self, start_mark=None, end_mark=None, encoding=None): self.start_mark = start_mark self.end_mark = end_mark self.encoding = encoding class StreamEndEvent(Event): pass class DocumentStartEvent(Event): def __init__(self, start_mark=None, end_mark=None, explicit=None, version=None, tags=None): self.start_mark = start_mark self.end_mark = end_mark self.explicit = explicit self.version = version self.tags = tags class DocumentEndEvent(Event): def __init__(self, start_mark=None, end_mark=None, explicit=None): self.start_mark = start_mark self.end_mark = end_mark self.explicit = explicit class AliasEvent(NodeEvent): pass class ScalarEvent(NodeEvent): def __init__(self, implicit, value, start_mark=None, end_mark=None, style=None): self.tag = None self.implicit = implicit self.value = value self.start_mark = start_mark self.end_mark = end_mark self.style = style class SequenceStartEvent(CollectionStartEvent): pass class SequenceEndEvent(CollectionEndEvent): pass class MappingStartEvent(CollectionStartEvent): pass class MappingEndEvent(CollectionEndEvent): pass powerline-2.8.4/powerline/lint/markedjson/loader.py000066400000000000000000000015571466405252600225020ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lint.markedjson.reader import Reader from powerline.lint.markedjson.scanner import Scanner from powerline.lint.markedjson.parser import Parser from powerline.lint.markedjson.composer import Composer from powerline.lint.markedjson.constructor import Constructor from powerline.lint.markedjson.resolver import Resolver from powerline.lint.markedjson.error import echoerr class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver): def __init__(self, stream): Reader.__init__(self, stream) Scanner.__init__(self) Parser.__init__(self) Composer.__init__(self) Constructor.__init__(self) Resolver.__init__(self) self.haserrors = False def echoerr(self, *args, **kwargs): echoerr(*args, **kwargs) self.haserrors = True powerline-2.8.4/powerline/lint/markedjson/markedvalue.py000066400000000000000000000067341466405252600235360ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lib.unicode import unicode def gen_new(cls): def __new__(arg_cls, value, mark): r = super(arg_cls, arg_cls).__new__(arg_cls, value) r.mark = mark r.value = value return r return __new__ def gen_init(cls): def __init__(self, value, mark): return cls.__init__(self, value) return __init__ def gen_getnewargs(cls): def __getnewargs__(self): return (self.value, self.mark) return __getnewargs__ class MarkedUnicode(unicode): __new__ = gen_new(unicode) __getnewargs__ = gen_getnewargs(unicode) def _proc_partition(self, part_result): pointdiff = 1 r = [] for s in part_result: r.append(MarkedUnicode(s, self.mark.advance_string(pointdiff))) pointdiff += len(s) return tuple(r) def rpartition(self, sep): return self._proc_partition(super(MarkedUnicode, self).rpartition(sep)) def partition(self, sep): return self._proc_partition(super(MarkedUnicode, self).partition(sep)) class MarkedInt(int): __new__ = gen_new(int) __getnewargs__ = gen_getnewargs(int) class MarkedFloat(float): __new__ = gen_new(float) __getnewargs__ = gen_getnewargs(float) class MarkedDict(dict): __init__ = gen_init(dict) __getnewargs__ = gen_getnewargs(dict) def __new__(arg_cls, value, mark): r = super(arg_cls, arg_cls).__new__(arg_cls, value) r.mark = mark r.value = value r.keydict = dict(((key, key) for key in r)) return r def setmerged(self, d): try: self.mark.set_merged_mark(d.mark) except AttributeError: pass def __setitem__(self, key, value): try: old_value = self[key] except KeyError: pass else: try: key.mark.set_old_mark(self.keydict[key].mark) except AttributeError: pass except KeyError: pass try: value.mark.set_old_mark(old_value.mark) except AttributeError: pass dict.__setitem__(self, key, value) self.keydict[key] = key def update(self, *args, **kwargs): dict.update(self, *args, **kwargs) self.keydict = dict(((key, key) for key in self)) def copy(self): return MarkedDict(super(MarkedDict, self).copy(), self.mark) class MarkedList(list): __new__ = gen_new(list) __init__ = gen_init(list) __getnewargs__ = gen_getnewargs(list) class MarkedValue: def __init__(self, value, mark): self.mark = mark self.value = value __getinitargs__ = gen_getnewargs(None) specialclasses = { unicode: MarkedUnicode, int: MarkedInt, float: MarkedFloat, dict: MarkedDict, list: MarkedList, } classcache = {} def gen_marked_value(value, mark, use_special_classes=True): if use_special_classes and value.__class__ in specialclasses: Marked = specialclasses[value.__class__] elif value.__class__ in classcache: Marked = classcache[value.__class__] else: class Marked(MarkedValue): for func in value.__class__.__dict__: if func == 'copy': def copy(self): return self.__class__(self.value.copy(), self.mark) elif func not in set(('__init__', '__new__', '__getattribute__')): if func in set(('__eq__',)): # HACK to make marked dictionaries always work exec (( 'def {0}(self, *args):\n' ' return self.value.{0}(*[arg.value if isinstance(arg, MarkedValue) else arg for arg in args])' ).format(func)) else: exec (( 'def {0}(self, *args, **kwargs):\n' ' return self.value.{0}(*args, **kwargs)\n' ).format(func)) classcache[value.__class__] = Marked return Marked(value, mark) powerline-2.8.4/powerline/lint/markedjson/nodes.py000066400000000000000000000024351466405252600223400ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) class Node(object): def __init__(self, tag, value, start_mark, end_mark): self.tag = tag self.value = value self.start_mark = start_mark self.end_mark = end_mark def __repr__(self): value = self.value # if isinstance(value, list): # if len(value) == 0: # value = '' # elif len(value) == 1: # value = '<1 item>' # else: # value = '<%d items>' % len(value) # else: # if len(value) > 75: # value = repr(value[:70]+u' ... ') # else: # value = repr(value) value = repr(value) return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value) class ScalarNode(Node): id = 'scalar' def __init__(self, tag, value, start_mark=None, end_mark=None, style=None): self.tag = tag self.value = value self.start_mark = start_mark self.end_mark = end_mark self.style = style class CollectionNode(Node): def __init__(self, tag, value, start_mark=None, end_mark=None, flow_style=None): self.tag = tag self.value = value self.start_mark = start_mark self.end_mark = end_mark self.flow_style = flow_style class SequenceNode(CollectionNode): id = 'sequence' class MappingNode(CollectionNode): id = 'mapping' powerline-2.8.4/powerline/lint/markedjson/parser.py000066400000000000000000000176741466405252600225370ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lint.markedjson.error import MarkedError from powerline.lint.markedjson import tokens from powerline.lint.markedjson import events class ParserError(MarkedError): pass class Parser: def __init__(self): self.current_event = None self.yaml_version = None self.states = [] self.marks = [] self.state = self.parse_stream_start def dispose(self): # Reset the state attributes (to clear self-references) self.states = [] self.state = None def check_event(self, *choices): # Check the type of the next event. if self.current_event is None: if self.state: self.current_event = self.state() if self.current_event is not None: if not choices: return True for choice in choices: if isinstance(self.current_event, choice): return True return False def peek_event(self): # Get the next event. if self.current_event is None: if self.state: self.current_event = self.state() return self.current_event def get_event(self): # Get the next event and proceed further. if self.current_event is None: if self.state: self.current_event = self.state() value = self.current_event self.current_event = None return value # stream ::= STREAM-START implicit_document? explicit_document* STREAM-END # implicit_document ::= block_node DOCUMENT-END* # explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* def parse_stream_start(self): # Parse the stream start. token = self.get_token() event = events.StreamStartEvent(token.start_mark, token.end_mark, encoding=token.encoding) # Prepare the next state. self.state = self.parse_implicit_document_start return event def parse_implicit_document_start(self): # Parse an implicit document. if not self.check_token(tokens.StreamEndToken): token = self.peek_token() start_mark = end_mark = token.start_mark event = events.DocumentStartEvent(start_mark, end_mark, explicit=False) # Prepare the next state. self.states.append(self.parse_document_end) self.state = self.parse_node return event else: return self.parse_document_start() def parse_document_start(self): # Parse an explicit document. if not self.check_token(tokens.StreamEndToken): token = self.peek_token() self.echoerr( None, None, ('expected \'\', but found %r' % token.id), token.start_mark ) return events.StreamEndEvent(token.start_mark, token.end_mark) else: # Parse the end of the stream. token = self.get_token() event = events.StreamEndEvent(token.start_mark, token.end_mark) assert not self.states assert not self.marks self.state = None return event def parse_document_end(self): # Parse the document end. token = self.peek_token() start_mark = end_mark = token.start_mark explicit = False event = events.DocumentEndEvent(start_mark, end_mark, explicit=explicit) # Prepare the next state. self.state = self.parse_document_start return event def parse_document_content(self): return self.parse_node() def parse_node(self, indentless_sequence=False): start_mark = end_mark = None if start_mark is None: start_mark = end_mark = self.peek_token().start_mark event = None implicit = True if self.check_token(tokens.ScalarToken): token = self.get_token() end_mark = token.end_mark if token.plain: implicit = (True, False) else: implicit = (False, True) event = events.ScalarEvent(implicit, token.value, start_mark, end_mark, style=token.style) self.state = self.states.pop() elif self.check_token(tokens.FlowSequenceStartToken): end_mark = self.peek_token().end_mark event = events.SequenceStartEvent(implicit, start_mark, end_mark, flow_style=True) self.state = self.parse_flow_sequence_first_entry elif self.check_token(tokens.FlowMappingStartToken): end_mark = self.peek_token().end_mark event = events.MappingStartEvent(implicit, start_mark, end_mark, flow_style=True) self.state = self.parse_flow_mapping_first_key else: token = self.peek_token() raise ParserError( 'while parsing a flow node', start_mark, 'expected the node content, but found %r' % token.id, token.start_mark ) return event def parse_flow_sequence_first_entry(self): token = self.get_token() self.marks.append(token.start_mark) return self.parse_flow_sequence_entry(first=True) def parse_flow_sequence_entry(self, first=False): if not self.check_token(tokens.FlowSequenceEndToken): if not first: if self.check_token(tokens.FlowEntryToken): self.get_token() if self.check_token(tokens.FlowSequenceEndToken): token = self.peek_token() self.echoerr( 'While parsing a flow sequence', self.marks[-1], ('expected sequence value, but got %r' % token.id), token.start_mark ) else: token = self.peek_token() raise ParserError( 'while parsing a flow sequence', self.marks[-1], ('expected \',\' or \']\', but got %r' % token.id), token.start_mark ) if not self.check_token(tokens.FlowSequenceEndToken): self.states.append(self.parse_flow_sequence_entry) return self.parse_node() token = self.get_token() event = events.SequenceEndEvent(token.start_mark, token.end_mark) self.state = self.states.pop() self.marks.pop() return event def parse_flow_sequence_entry_mapping_end(self): self.state = self.parse_flow_sequence_entry token = self.peek_token() return events.MappingEndEvent(token.start_mark, token.start_mark) def parse_flow_mapping_first_key(self): token = self.get_token() self.marks.append(token.start_mark) return self.parse_flow_mapping_key(first=True) def parse_flow_mapping_key(self, first=False): if not self.check_token(tokens.FlowMappingEndToken): if not first: if self.check_token(tokens.FlowEntryToken): self.get_token() if self.check_token(tokens.FlowMappingEndToken): token = self.peek_token() self.echoerr( 'While parsing a flow mapping', self.marks[-1], ('expected mapping key, but got %r' % token.id), token.start_mark ) else: token = self.peek_token() raise ParserError( 'while parsing a flow mapping', self.marks[-1], ('expected \',\' or \'}\', but got %r' % token.id), token.start_mark ) if self.check_token(tokens.KeyToken): token = self.get_token() if not self.check_token(tokens.ValueToken, tokens.FlowEntryToken, tokens.FlowMappingEndToken): self.states.append(self.parse_flow_mapping_value) return self.parse_node() else: token = self.peek_token() raise ParserError( 'while parsing a flow mapping', self.marks[-1], ('expected value, but got %r' % token.id), token.start_mark ) elif not self.check_token(tokens.FlowMappingEndToken): token = self.peek_token() expect_key = self.check_token(tokens.ValueToken, tokens.FlowEntryToken) if not expect_key: self.get_token() expect_key = self.check_token(tokens.ValueToken) if expect_key: raise ParserError( 'while parsing a flow mapping', self.marks[-1], ('expected string key, but got %r' % token.id), token.start_mark ) else: token = self.peek_token() raise ParserError( 'while parsing a flow mapping', self.marks[-1], ('expected \':\', but got %r' % token.id), token.start_mark ) token = self.get_token() event = events.MappingEndEvent(token.start_mark, token.end_mark) self.state = self.states.pop() self.marks.pop() return event def parse_flow_mapping_value(self): if self.check_token(tokens.ValueToken): token = self.get_token() if not self.check_token(tokens.FlowEntryToken, tokens.FlowMappingEndToken): self.states.append(self.parse_flow_mapping_key) return self.parse_node() token = self.peek_token() raise ParserError( 'while parsing a flow mapping', self.marks[-1], ('expected mapping value, but got %r' % token.id), token.start_mark ) powerline-2.8.4/powerline/lint/markedjson/reader.py000066400000000000000000000077171466405252600225020ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import codecs from powerline.lint.markedjson.error import MarkedError, Mark, NON_PRINTABLE_RE from powerline.lib.unicode import unicode # This module contains abstractions for the input stream. You don’t have to # looks further, there are no pretty code. class ReaderError(MarkedError): pass class Reader(object): # Reader: # - determines the data encoding and converts it to a unicode string, # - checks if characters are in allowed range, # - adds '\0' to the end. # Reader accepts # - a file-like object with its `read` method returning `str`, # Yeah, it’s ugly and slow. def __init__(self, stream): self.name = None self.stream = None self.stream_pointer = 0 self.eof = True self.buffer = '' self.pointer = 0 self.full_buffer = unicode('') self.full_pointer = 0 self.raw_buffer = None self.raw_decode = codecs.utf_8_decode self.encoding = 'utf-8' self.index = 0 self.line = 0 self.column = 0 self.stream = stream self.name = getattr(stream, 'name', '') self.eof = False self.raw_buffer = None while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2): self.update_raw() self.update(1) def peek(self, index=0): try: return self.buffer[self.pointer + index] except IndexError: self.update(index + 1) return self.buffer[self.pointer + index] def prefix(self, length=1): if self.pointer + length >= len(self.buffer): self.update(length) return self.buffer[self.pointer:self.pointer + length] def update_pointer(self, length): while length: ch = self.buffer[self.pointer] self.pointer += 1 self.full_pointer += 1 self.index += 1 if ch == '\n': self.line += 1 self.column = 0 else: self.column += 1 length -= 1 def forward(self, length=1): if self.pointer + length + 1 >= len(self.buffer): self.update(length + 1) self.update_pointer(length) def get_mark(self): return Mark(self.name, self.line, self.column, self.full_buffer, self.full_pointer) def check_printable(self, data): match = NON_PRINTABLE_RE.search(data) if match: self.update_pointer(match.start()) raise ReaderError( 'while reading from stream', None, 'found special characters which are not allowed', Mark(self.name, self.line, self.column, self.full_buffer, self.full_pointer) ) def update(self, length): if self.raw_buffer is None: return self.buffer = self.buffer[self.pointer:] self.pointer = 0 while len(self.buffer) < length: if not self.eof: self.update_raw() try: data, converted = self.raw_decode(self.raw_buffer, 'strict', self.eof) except UnicodeDecodeError as exc: character = self.raw_buffer[exc.start] position = self.stream_pointer - len(self.raw_buffer) + exc.start data, converted = self.raw_decode(self.raw_buffer[:exc.start], 'strict', self.eof) self.buffer += data self.full_buffer += data + '<' + str(ord(character)) + '>' self.raw_buffer = self.raw_buffer[converted:] self.update_pointer(exc.start - 1) raise ReaderError( 'while reading from stream', None, 'found character #x%04x that cannot be decoded by UTF-8 codec' % ord(character), Mark(self.name, self.line, self.column, self.full_buffer, position) ) self.buffer += data self.full_buffer += data self.raw_buffer = self.raw_buffer[converted:] self.check_printable(data) if self.eof: self.buffer += '\0' self.raw_buffer = None break def update_raw(self, size=-1): # Was size=4096 assert(size < 0) # WARNING: reading the whole stream at once. To change this behaviour to # former reading N characters at once one must make sure that reading # never ends at partial unicode character. data = self.stream.read(size) if self.raw_buffer is None: self.raw_buffer = data else: self.raw_buffer += data self.stream_pointer += len(data) if not data: self.eof = True powerline-2.8.4/powerline/lint/markedjson/resolver.py000066400000000000000000000074501466405252600230730ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import re from powerline.lint.markedjson.error import MarkedError from powerline.lint.markedjson import nodes class ResolverError(MarkedError): pass class BaseResolver: DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str' DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq' DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map' yaml_implicit_resolvers = {} yaml_path_resolvers = {} def __init__(self): self.resolver_exact_paths = [] self.resolver_prefix_paths = [] @classmethod def add_implicit_resolver(cls, tag, regexp, first): if 'yaml_implicit_resolvers' not in cls.__dict__: cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy() if first is None: first = [None] for ch in first: cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp)) def descend_resolver(self, current_node, current_index): if not self.yaml_path_resolvers: return exact_paths = {} prefix_paths = [] if current_node: depth = len(self.resolver_prefix_paths) for path, kind in self.resolver_prefix_paths[-1]: if self.check_resolver_prefix(depth, path, kind, current_node, current_index): if len(path) > depth: prefix_paths.append((path, kind)) else: exact_paths[kind] = self.yaml_path_resolvers[path, kind] else: for path, kind in self.yaml_path_resolvers: if not path: exact_paths[kind] = self.yaml_path_resolvers[path, kind] else: prefix_paths.append((path, kind)) self.resolver_exact_paths.append(exact_paths) self.resolver_prefix_paths.append(prefix_paths) def ascend_resolver(self): if not self.yaml_path_resolvers: return self.resolver_exact_paths.pop() self.resolver_prefix_paths.pop() def check_resolver_prefix(self, depth, path, kind, current_node, current_index): node_check, index_check = path[depth - 1] if isinstance(node_check, str): if current_node.tag != node_check: return elif node_check is not None: if not isinstance(current_node, node_check): return if index_check is True and current_index is not None: return if ((index_check is False or index_check is None) and current_index is None): return if isinstance(index_check, str): if not (isinstance(current_index, nodes.ScalarNode) and index_check == current_index.value): return elif isinstance(index_check, int) and not isinstance(index_check, bool): if index_check != current_index: return return True def resolve(self, kind, value, implicit, mark=None): if kind is nodes.ScalarNode and implicit[0]: if value == '': resolvers = self.yaml_implicit_resolvers.get('', []) else: resolvers = self.yaml_implicit_resolvers.get(value[0], []) resolvers += self.yaml_implicit_resolvers.get(None, []) for tag, regexp in resolvers: if regexp.match(value): return tag else: self.echoerr( 'While resolving plain scalar', None, 'expected floating-point value, integer, null or boolean, but got %r' % value, mark ) return self.DEFAULT_SCALAR_TAG if kind is nodes.ScalarNode: return self.DEFAULT_SCALAR_TAG elif kind is nodes.SequenceNode: return self.DEFAULT_SEQUENCE_TAG elif kind is nodes.MappingNode: return self.DEFAULT_MAPPING_TAG class Resolver(BaseResolver): pass Resolver.add_implicit_resolver( 'tag:yaml.org,2002:bool', re.compile(r'''^(?:true|false)$''', re.X), list('yYnNtTfFoO')) Resolver.add_implicit_resolver( 'tag:yaml.org,2002:float', re.compile(r'^-?(?:0|[1-9]\d*)(?=[.eE])(?:\.\d+)?(?:[eE][-+]?\d+)?$', re.X), list('-0123456789')) Resolver.add_implicit_resolver( 'tag:yaml.org,2002:int', re.compile(r'^(?:0|-?[1-9]\d*)$', re.X), list('-0123456789')) Resolver.add_implicit_resolver( 'tag:yaml.org,2002:null', re.compile(r'^null$', re.X), ['n']) powerline-2.8.4/powerline/lint/markedjson/scanner.py000066400000000000000000000336131466405252600226630ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from string import hexdigits from powerline.lint.markedjson.error import MarkedError from powerline.lint.markedjson import tokens from powerline.lib.unicode import unicode, unichr, surrogate_pair_to_character hexdigits_set = set(hexdigits) # Scanner produces tokens of the following types: # STREAM-START # STREAM-END # DOCUMENT-START # DOCUMENT-END # FLOW-SEQUENCE-START # FLOW-MAPPING-START # FLOW-SEQUENCE-END # FLOW-MAPPING-END # FLOW-ENTRY # KEY # VALUE # SCALAR(value, plain, style) # # Read comments in the Scanner code for more details. class ScannerError(MarkedError): pass class SimpleKey: # See below simple keys treatment. def __init__(self, token_number, index, line, column, mark): self.token_number = token_number self.index = index self.line = line self.column = column self.mark = mark class Scanner: def __init__(self): '''Initialize the scanner.''' # It is assumed that Scanner and Reader will have a common descendant. # Reader do the dirty work of checking for BOM and converting the # input data to Unicode. It also adds NUL to the end. # # Reader supports the following methods # self.peek(i=0) # peek the next i-th character # self.prefix(l=1) # peek the next l characters # self.forward(l=1) # read the next l characters and move the pointer. # Had we reached the end of the stream? self.done = False # The number of unclosed '{' and '['. `flow_level == 0` means block # context. self.flow_level = 0 # List of processed tokens that are not yet emitted. self.tokens = [] # Add the STREAM-START token. self.fetch_stream_start() # Number of tokens that were emitted through the `get_token` method. self.tokens_taken = 0 # Variables related to simple keys treatment. # A simple key is a key that is not denoted by the '?' indicator. # We emit the KEY token before all keys, so when we find a potential # simple key, we try to locate the corresponding ':' indicator. # Simple keys should be limited to a single line. # Can a simple key start at the current position? A simple key may # start: # - after '{', '[', ',' (in the flow context), self.allow_simple_key = False # Keep track of possible simple keys. This is a dictionary. The key # is `flow_level`; there can be no more that one possible simple key # for each level. The value is a SimpleKey record: # (token_number, index, line, column, mark) # A simple key may start with SCALAR(flow), '[', or '{' tokens. self.possible_simple_keys = {} # Public methods. def check_token(self, *choices): # Check if the next token is one of the given types. while self.need_more_tokens(): self.fetch_more_tokens() if self.tokens: if not choices: return True for choice in choices: if isinstance(self.tokens[0], choice): return True return False def peek_token(self): # Return the next token, but do not delete if from the queue. while self.need_more_tokens(): self.fetch_more_tokens() if self.tokens: return self.tokens[0] def get_token(self): # Return the next token. while self.need_more_tokens(): self.fetch_more_tokens() if self.tokens: self.tokens_taken += 1 return self.tokens.pop(0) # Private methods. def need_more_tokens(self): if self.done: return False if not self.tokens: return True # The current token may be a potential simple key, so we # need to look further. self.stale_possible_simple_keys() if self.next_possible_simple_key() == self.tokens_taken: return True def fetch_more_tokens(self): # Eat whitespaces and comments until we reach the next token. self.scan_to_next_token() # Remove obsolete possible simple keys. self.stale_possible_simple_keys() # Peek the next character. ch = self.peek() # Is it the end of stream? if ch == '\0': return self.fetch_stream_end() # Note: the order of the following checks is NOT significant. # Is it the flow sequence start indicator? if ch == '[': return self.fetch_flow_sequence_start() # Is it the flow mapping start indicator? if ch == '{': return self.fetch_flow_mapping_start() # Is it the flow sequence end indicator? if ch == ']': return self.fetch_flow_sequence_end() # Is it the flow mapping end indicator? if ch == '}': return self.fetch_flow_mapping_end() # Is it the flow entry indicator? if ch == ',': return self.fetch_flow_entry() # Is it the value indicator? if ch == ':' and self.flow_level: return self.fetch_value() # Is it a double quoted scalar? if ch == '"': return self.fetch_double() # It must be a plain scalar then. if self.check_plain(): return self.fetch_plain() # No? It’s an error. Let’s produce a nice error message. raise ScannerError( 'while scanning for the next token', None, 'found character %r that cannot start any token' % ch, self.get_mark() ) # Simple keys treatment. def next_possible_simple_key(self): # Return the number of the nearest possible simple key. Actually we # don’t need to loop through the whole dictionary. We may replace it # with the following code: # if not self.possible_simple_keys: # return None # return self.possible_simple_keys[ # min(self.possible_simple_keys.keys())].token_number min_token_number = None for level in self.possible_simple_keys: key = self.possible_simple_keys[level] if min_token_number is None or key.token_number < min_token_number: min_token_number = key.token_number return min_token_number def stale_possible_simple_keys(self): # Remove entries that are no longer possible simple keys. According to # the YAML specification, simple keys # - should be limited to a single line, # Disabling this procedure will allow simple keys of any length and # height (may cause problems if indentation is broken though). for level in list(self.possible_simple_keys): key = self.possible_simple_keys[level] if key.line != self.line: del self.possible_simple_keys[level] def save_possible_simple_key(self): # The next token may start a simple key. We check if it’s possible # and save its position. This function is called for # SCALAR(flow), '[', and '{'. # The next token might be a simple key. Let’s save it’s number and # position. if self.allow_simple_key: self.remove_possible_simple_key() token_number = self.tokens_taken + len(self.tokens) key = SimpleKey(token_number, self.index, self.line, self.column, self.get_mark()) self.possible_simple_keys[self.flow_level] = key def remove_possible_simple_key(self): # Remove the saved possible key position at the current flow level. if self.flow_level in self.possible_simple_keys: del self.possible_simple_keys[self.flow_level] # Fetchers. def fetch_stream_start(self): # We always add STREAM-START as the first token and STREAM-END as the # last token. # Read the token. mark = self.get_mark() # Add STREAM-START. self.tokens.append(tokens.StreamStartToken(mark, mark, encoding=self.encoding)) def fetch_stream_end(self): # Reset simple keys. self.remove_possible_simple_key() self.allow_simple_key = False self.possible_simple_keys = {} # Read the token. mark = self.get_mark() # Add STREAM-END. self.tokens.append(tokens.StreamEndToken(mark, mark)) # The steam is finished. self.done = True def fetch_flow_sequence_start(self): self.fetch_flow_collection_start(tokens.FlowSequenceStartToken) def fetch_flow_mapping_start(self): self.fetch_flow_collection_start(tokens.FlowMappingStartToken) def fetch_flow_collection_start(self, TokenClass): # '[' and '{' may start a simple key. self.save_possible_simple_key() # Increase the flow level. self.flow_level += 1 # Simple keys are allowed after '[' and '{'. self.allow_simple_key = True # Add FLOW-SEQUENCE-START or FLOW-MAPPING-START. start_mark = self.get_mark() self.forward() end_mark = self.get_mark() self.tokens.append(TokenClass(start_mark, end_mark)) def fetch_flow_sequence_end(self): self.fetch_flow_collection_end(tokens.FlowSequenceEndToken) def fetch_flow_mapping_end(self): self.fetch_flow_collection_end(tokens.FlowMappingEndToken) def fetch_flow_collection_end(self, TokenClass): # Reset possible simple key on the current level. self.remove_possible_simple_key() # Decrease the flow level. self.flow_level -= 1 # No simple keys after ']' or '}'. self.allow_simple_key = False # Add FLOW-SEQUENCE-END or FLOW-MAPPING-END. start_mark = self.get_mark() self.forward() end_mark = self.get_mark() self.tokens.append(TokenClass(start_mark, end_mark)) def fetch_value(self): # Do we determine a simple key? if self.flow_level in self.possible_simple_keys: # Add KEY. key = self.possible_simple_keys[self.flow_level] del self.possible_simple_keys[self.flow_level] self.tokens.insert(key.token_number - self.tokens_taken, tokens.KeyToken(key.mark, key.mark)) # There cannot be two simple keys one after another. self.allow_simple_key = False # Add VALUE. start_mark = self.get_mark() self.forward() end_mark = self.get_mark() self.tokens.append(tokens.ValueToken(start_mark, end_mark)) def fetch_flow_entry(self): # Simple keys are allowed after ','. self.allow_simple_key = True # Reset possible simple key on the current level. self.remove_possible_simple_key() # Add FLOW-ENTRY. start_mark = self.get_mark() self.forward() end_mark = self.get_mark() self.tokens.append(tokens.FlowEntryToken(start_mark, end_mark)) def fetch_double(self): # A flow scalar could be a simple key. self.save_possible_simple_key() # No simple keys after flow scalars. self.allow_simple_key = False # Scan and add SCALAR. self.tokens.append(self.scan_flow_scalar()) def fetch_plain(self): self.save_possible_simple_key() # No simple keys after plain scalars. self.allow_simple_key = False # Scan and add SCALAR. May change `allow_simple_key`. self.tokens.append(self.scan_plain()) # Checkers. def check_plain(self): return self.peek() in '0123456789-ntf' # Scanners. def scan_to_next_token(self): while self.peek() in ' \t\n': self.forward() def scan_flow_scalar(self): # See the specification for details. # Note that we loose indentation rules for quoted scalars. Quoted # scalars don’t need to adhere indentation because " and ' clearly # mark the beginning and the end of them. Therefore we are less # restrictive then the specification requires. We only need to check # that document separators are not included in scalars. chunks = [] start_mark = self.get_mark() quote = self.peek() self.forward() chunks.extend(self.scan_flow_scalar_non_spaces(start_mark)) while self.peek() != quote: chunks.extend(self.scan_flow_scalar_spaces(start_mark)) chunks.extend(self.scan_flow_scalar_non_spaces(start_mark)) self.forward() end_mark = self.get_mark() return tokens.ScalarToken(unicode().join(chunks), False, start_mark, end_mark, '"') ESCAPE_REPLACEMENTS = { 'b': '\x08', 't': '\x09', 'n': '\x0A', 'f': '\x0C', 'r': '\x0D', '"': '\"', '\\': '\\', } ESCAPE_CODES = { 'u': 4, } def scan_flow_scalar_non_spaces(self, start_mark): # See the specification for details. chunks = [] while True: length = 0 while self.peek(length) not in '\"\\\0 \t\n': length += 1 if length: chunks.append(self.prefix(length)) self.forward(length) ch = self.peek() if ch == '\\': self.forward() ch = self.peek() if ch in self.ESCAPE_REPLACEMENTS: chunks.append(self.ESCAPE_REPLACEMENTS[ch]) self.forward() elif ch in self.ESCAPE_CODES: length = self.ESCAPE_CODES[ch] self.forward() for k in range(length): if self.peek(k) not in hexdigits: raise ScannerError( 'while scanning a double-quoted scalar', start_mark, 'expected escape sequence of %d hexdecimal numbers, but found %r' % ( length, self.peek(k)), self.get_mark() ) code = int(self.prefix(length), 16) self.forward(length) if 0xD800 <= code <= 0xDC00: # Start of the surrogate pair next_char = self.prefix(6) if ( next_char[0] != '\\' or next_char[1] != 'u' or not (set(next_char[2:]) < hexdigits_set) or not (0xDC00 <= int(next_char[2:], 16) <= 0xDFFF) ): raise ScannerError( 'while scanning a double-quoted scalar', start_mark, 'expected escape sequence with the next character in surrogate pair, but found %r' % ( next_char ), self.get_mark() ) code = surrogate_pair_to_character(code, int(next_char[2:], 16)) self.forward(6) chunks.append(unichr(code)) else: raise ScannerError( 'while scanning a double-quoted scalar', start_mark, ('found unknown escape character %r' % ch), self.get_mark() ) else: return chunks def scan_flow_scalar_spaces(self, start_mark): # See the specification for details. chunks = [] length = 0 while self.peek(length) in ' \t': length += 1 whitespaces = self.prefix(length) self.forward(length) ch = self.peek() if ch == '\0': raise ScannerError( 'while scanning a quoted scalar', start_mark, 'found unexpected end of stream', self.get_mark() ) elif ch == '\n': raise ScannerError( 'while scanning a quoted scalar', start_mark, 'found unexpected line end', self.get_mark() ) else: chunks.append(whitespaces) return chunks def scan_plain(self): chunks = [] start_mark = self.get_mark() spaces = [] while True: length = 0 while True: if self.peek(length) not in 'eE.0123456789nul-tr+fas': break length += 1 if length == 0: break self.allow_simple_key = False chunks.extend(spaces) chunks.append(self.prefix(length)) self.forward(length) end_mark = self.get_mark() return tokens.ScalarToken(''.join(chunks), True, start_mark, end_mark) powerline-2.8.4/powerline/lint/markedjson/tokens.py000066400000000000000000000024471466405252600225360ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) class Token(object): def __init__(self, start_mark, end_mark): self.start_mark = start_mark self.end_mark = end_mark def __repr__(self): attributes = [ key for key in self.__dict__ if not key.endswith('_mark') ] attributes.sort() arguments = ', '.join([ '%s=%r' % (key, getattr(self, key)) for key in attributes ]) return '%s(%s)' % (self.__class__.__name__, arguments) class StreamStartToken(Token): id = '' def __init__(self, start_mark=None, end_mark=None, encoding=None): self.start_mark = start_mark self.end_mark = end_mark self.encoding = encoding class StreamEndToken(Token): id = '' class FlowSequenceStartToken(Token): id = '[' class FlowMappingStartToken(Token): id = '{' class FlowSequenceEndToken(Token): id = ']' class FlowMappingEndToken(Token): id = '}' class KeyToken(Token): id = '?' class ValueToken(Token): id = ':' class FlowEntryToken(Token): id = ',' class ScalarToken(Token): id = '' def __init__(self, value, plain, start_mark, end_mark, style=None): self.value = value self.plain = plain self.start_mark = start_mark self.end_mark = end_mark self.style = style powerline-2.8.4/powerline/lint/selfcheck.py000066400000000000000000000011361466405252600210170ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lib.unicode import unicode def havemarks(*args, **kwargs): origin = kwargs.get('origin', '') for i, v in enumerate(args): if not hasattr(v, 'mark'): raise AssertionError('Value #{0}/{1} ({2!r}) has no attribute `mark`'.format(origin, i, v)) if isinstance(v, dict): for key, val in v.items(): havemarks(key, val, origin=(origin + '[' + unicode(i) + ']/' + unicode(key))) elif isinstance(v, list): havemarks(*v, origin=(origin + '[' + unicode(i) + ']')) powerline-2.8.4/powerline/lint/spec.py000066400000000000000000000557311466405252600200340ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import itertools import re from copy import copy from powerline.lib.unicode import unicode from powerline.lint.markedjson.error import echoerr, DelayedEchoErr, NON_PRINTABLE_STR from powerline.lint.selfcheck import havemarks NON_PRINTABLE_RE = re.compile( NON_PRINTABLE_STR.translate({ ord('\t'): None, ord('\n'): None, 0x0085: None, }) ) class Spec(object): '''Class that describes some JSON value In powerline it is only used to describe JSON values stored in powerline configuration. :param dict keys: Dictionary that maps keys that may be present in the given JSON dictionary to their descriptions. If this parameter is not empty it implies that described value has dictionary type. Non-dictionary types must be described using ``Spec()``: without arguments. .. note:: Methods that create the specifications return ``self``, so calls to them may be chained: ``Spec().type(unicode).re('^\\w+$')``. This does not apply to functions that *apply* specification like :py:meth`Spec.match`. .. note:: Methods starting with ``check_`` return two values: first determines whether caller should proceed on running other checks, second determines whether there were any problems (i.e. whether error was reported). One should not call these methods directly: there is :py:meth:`Spec.match` method for checking values. .. note:: In ``check_`` and ``match`` methods specifications are identified by their indexes for the purpose of simplyfying :py:meth:`Spec.copy` method. Some common parameters: ``data``: Whatever data supplied by the first caller for checker functions. Is not processed by :py:class:`Spec` methods in any fashion. ``context``: :py:class:`powerline.lint.context.Context` instance, describes context of the value. :py:class:`Spec` methods only use its ``.key`` methods for error messages. ``echoerr``: Callable that should be used to echo errors. Is supposed to take four optional keyword arguments: ``problem``, ``problem_mark``, ``context``, ``context_mark``. ``value``: Checked value. ''' def __init__(self, **keys): self.specs = [] self.keys = {} self.checks = [] self.cmsg = '' self.isoptional = False self.uspecs = [] self.ufailmsg = lambda key: 'found unknown key: {0}'.format(key) self.did_type = False self.update(**keys) def update(self, **keys): '''Describe additional keys that may be present in given JSON value If called with some keyword arguments implies that described value is a dictionary. If called without keyword parameters it is no-op. :return: self. ''' for k, v in keys.items(): self.keys[k] = len(self.specs) self.specs.append(v) if self.keys and not self.did_type: self.type(dict) self.did_type = True return self def copy(self, copied=None): '''Deep copy the spec :param dict copied: Internal dictionary used for storing already copied values. This parameter should not be used. :return: New :py:class:`Spec` object that is a deep copy of ``self``. ''' copied = copied or {} try: return copied[id(self)] except KeyError: instance = self.__class__() copied[id(self)] = instance return self.__class__()._update(self.__dict__, copied) def _update(self, d, copied): '''Helper for the :py:meth:`Spec.copy` function Populates new instance with values taken from the old one. :param dict d: ``__dict__`` of the old instance. :param dict copied: Storage for already copied values. ''' self.__dict__.update(d) self.keys = copy(self.keys) self.checks = copy(self.checks) self.uspecs = copy(self.uspecs) self.specs = [spec.copy(copied) for spec in self.specs] return self def unknown_spec(self, keyfunc, spec): '''Define specification for non-static keys This method should be used if key names cannot be determined at runtime or if a number of keys share identical spec (in order to not repeat it). :py:meth:`Spec.match` method processes dictionary in the given order: * First it tries to use specifications provided at the initialization or by the :py:meth:`Spec.update` method. * If no specification for given key was provided it processes specifications from ``keyfunc`` argument in order they were supplied. Once some key matches specification supplied second ``spec`` argument is used to determine correctness of the value. :param Spec keyfunc: :py:class:`Spec` instance or a regular function that returns two values (the same :py:meth:`Spec.match` returns). This argument is used to match keys that were not provided at initialization or via :py:meth:`Spec.update`. :param Spec spec: :py:class:`Spec` instance that will be used to check keys matched by ``keyfunc``. :return: self. ''' if isinstance(keyfunc, Spec): self.specs.append(keyfunc) keyfunc = len(self.specs) - 1 self.specs.append(spec) self.uspecs.append((keyfunc, len(self.specs) - 1)) return self def unknown_msg(self, msgfunc): '''Define message which will be used when unknown key was found “Unknown” is a key that was not provided at the initialization and via :py:meth:`Spec.update` and did not match any ``keyfunc`` provided via :py:meth:`Spec.unknown_spec`. :param msgfunc: Function that takes that unknown key as an argument and returns the message text. Text will appear at the top (start of the sentence). :return: self. ''' self.ufailmsg = msgfunc return self def context_message(self, msg): '''Define message that describes context :param str msg: Message that describes context. Is written using the :py:meth:`str.format` syntax and is expected to display keyword parameter ``key``. :return: self. ''' self.cmsg = msg for spec in self.specs: if not spec.cmsg: spec.context_message(msg) return self def check_type(self, value, context_mark, data, context, echoerr, types): '''Check that given value matches given type(s) :param tuple types: List of accepted types. Since :py:class:`Spec` is supposed to describe JSON values only ``dict``, ``list``, ``unicode``, ``bool``, ``float`` and ``NoneType`` types make any sense. :return: proceed, hadproblem. ''' havemarks(value) if type(value.value) not in types: echoerr( context=self.cmsg.format(key=context.key), context_mark=context_mark, problem='{0!r} must be a {1} instance, not {2}'.format( value, ', '.join((t.__name__ for t in types)), type(value.value).__name__ ), problem_mark=value.mark ) return False, True return True, False def check_func(self, value, context_mark, data, context, echoerr, func, msg_func): '''Check value using given function :param function func: Callable that should accept four positional parameters: #. checked value, #. ``data`` parameter with arbitrary data (supplied by top-level caller), #. current context and #. function used for echoing errors. This callable should return three values: #. determines whether ``check_func`` caller should proceed calling other checks, #. determines whether ``check_func`` should echo error on its own (it should be set to False if ``func`` echoes error itself) and #. determines whether function has found some errors in the checked value. :param function msg_func: Callable that takes checked value as the only positional parameter and returns a string that describes the problem. Only useful for small checker functions since it is ignored when second returned value is false. :return: proceed, hadproblem. ''' havemarks(value) proceed, echo, hadproblem = func(value, data, context, echoerr) if echo and hadproblem: echoerr(context=self.cmsg.format(key=context.key), context_mark=context_mark, problem=msg_func(value), problem_mark=value.mark) return proceed, hadproblem def check_list(self, value, context_mark, data, context, echoerr, item_func, msg_func): '''Check that each value in the list matches given specification :param function item_func: Callable like ``func`` from :py:meth:`Spec.check_func`. Unlike ``func`` this callable is called for each value in the list and may be a :py:class:`Spec` object index. :param func msg_func: Callable like ``msg_func`` from :py:meth:`Spec.check_func`. Should accept one problematic item and is not used for :py:class:`Spec` object indices in ``item_func`` method. :return: proceed, hadproblem. ''' havemarks(value) i = 0 hadproblem = False for item in value: havemarks(item) if isinstance(item_func, int): spec = self.specs[item_func] proceed, fhadproblem = spec.match( item, value.mark, data, context.enter_item('list item ' + unicode(i), item), echoerr ) else: proceed, echo, fhadproblem = item_func(item, data, context, echoerr) if echo and fhadproblem: echoerr(context=self.cmsg.format(key=context.key + '/list item ' + unicode(i)), context_mark=value.mark, problem=msg_func(item), problem_mark=item.mark) if fhadproblem: hadproblem = True if not proceed: return proceed, hadproblem i += 1 return True, hadproblem def check_either(self, value, context_mark, data, context, echoerr, start, end): '''Check that given value matches one of the given specifications :param int start: First specification index. :param int end: Specification index that is greater by 1 then last specification index. This method does not give an error if any specification from ``self.specs[start:end]`` is matched by the given value. ''' havemarks(value) new_echoerr = DelayedEchoErr( echoerr, 'One of the either variants failed. Messages from the first variant:', 'messages from the next variant:' ) hadproblem = False for spec in self.specs[start:end]: proceed, hadproblem = spec.match(value, value.mark, data, context, new_echoerr) new_echoerr.next_variant() if not proceed: break if not hadproblem: return True, False new_echoerr.echo_all() return False, hadproblem def check_tuple(self, value, context_mark, data, context, echoerr, start, end): '''Check that given value is a list with items matching specifications :param int start: First specification index. :param int end: Specification index that is greater by 1 then last specification index. This method checks that each item in the value list matches specification with index ``start + item_number``. ''' havemarks(value) hadproblem = False for (i, item, spec) in zip(itertools.count(), value, self.specs[start:end]): proceed, ihadproblem = spec.match( item, value.mark, data, context.enter_item('tuple item ' + unicode(i), item), echoerr ) if ihadproblem: hadproblem = True if not proceed: return False, hadproblem return True, hadproblem def check_printable(self, value, context_mark, data, context, echoerr, _): '''Check that given unicode string contains only printable characters ''' hadproblem = False for match in NON_PRINTABLE_RE.finditer(value): hadproblem = True echoerr( context=self.cmsg.format(key=context.key), context_mark=value.mark, problem='found not printable character U+{0:04x} in a configuration string'.format( ord(match.group(0))), problem_mark=value.mark.advance_string(match.start() + 1) ) return True, hadproblem def printable(self, *args): self.type(unicode) self.checks.append(('check_printable', args)) return self def type(self, *args): '''Describe value that has one of the types given in arguments :param args: List of accepted types. Since :py:class:`Spec` is supposed to describe JSON values only ``dict``, ``list``, ``unicode``, ``bool``, ``float`` and ``NoneType`` types make any sense. :return: self. ''' self.checks.append(('check_type', args)) return self cmp_funcs = { 'le': lambda x, y: x <= y, 'lt': lambda x, y: x < y, 'ge': lambda x, y: x >= y, 'gt': lambda x, y: x > y, 'eq': lambda x, y: x == y, } cmp_msgs = { 'le': 'lesser or equal to', 'lt': 'lesser then', 'ge': 'greater or equal to', 'gt': 'greater then', 'eq': 'equal to', } def len(self, comparison, cint, msg_func=None): '''Describe value that has given length :param str comparison: Type of the comparison. Valid values: ``le``, ``lt``, ``ge``, ``gt``, ``eq``. :param int cint: Integer with which length is compared. :param function msg_func: Function that should accept checked value and return message that describes the problem with this value. Default value will emit something like “length of ['foo', 'bar'] is not greater then 10”. :return: self. ''' cmp_func = self.cmp_funcs[comparison] msg_func = ( msg_func or (lambda value: 'length of {0!r} is not {1} {2}'.format( value, self.cmp_msgs[comparison], cint)) ) self.checks.append(( 'check_func', (lambda value, *args: (True, True, not cmp_func(len(value), cint))), msg_func )) return self def cmp(self, comparison, cint, msg_func=None): '''Describe value that is a number or string that has given property :param str comparison: Type of the comparison. Valid values: ``le``, ``lt``, ``ge``, ``gt``, ``eq``. This argument will restrict the number or string to emit True on the given comparison. :param cint: Number or string with which value is compared. Type of this parameter affects required type of the checked value: ``str`` and ``unicode`` types imply ``unicode`` values, ``float`` type implies that value can be either ``int`` or ``float``, ``int`` type implies ``int`` value and for any other type the behavior is undefined. :param function msg_func: Function that should accept checked value and return message that describes the problem with this value. Default value will emit something like “10 is not greater then 10”. :return: self. ''' if type(cint) is str: self.type(unicode) elif type(cint) is float: self.type(int, float) else: self.type(type(cint)) cmp_func = self.cmp_funcs[comparison] msg_func = msg_func or (lambda value: '{0} is not {1} {2}'.format(value, self.cmp_msgs[comparison], cint)) self.checks.append(( 'check_func', (lambda value, *args: (True, True, not cmp_func(value.value, cint))), msg_func )) return self def unsigned(self, msg_func=None): '''Describe unsigned integer value :param function msg_func: Function that should accept checked value and return message that describes the problem with this value. :return: self. ''' self.type(int) self.checks.append(( 'check_func', (lambda value, *args: (True, True, value < 0)), (lambda value: '{0} must be greater then zero'.format(value)) )) return self def list(self, item_func, msg_func=None): '''Describe list with any number of elements, each matching given spec :param item_func: :py:class:`Spec` instance or a callable. Check out :py:meth:`Spec.check_list` documentation for more details. Note that in :py:meth:`Spec.check_list` description :py:class:`Spec` instance is replaced with its index in ``self.specs``. :param function msg_func: Function that should accept checked value and return message that describes the problem with this value. Default value will emit just “failed check”, which is rather indescriptive. :return: self. ''' self.type(list) if isinstance(item_func, Spec): self.specs.append(item_func) item_func = len(self.specs) - 1 self.checks.append(('check_list', item_func, msg_func or (lambda item: 'failed check'))) return self def tuple(self, *specs): '''Describe list with the given number of elements, each matching corresponding spec :param (Spec,) specs: List of specifications. Last element(s) in this list may be optional. Each element in this list describes element with the same index in the checked value. Check out :py:meth:`Spec.check_tuple` for more details, but note that there list of specifications is replaced with start and end indices in ``self.specs``. :return: self. ''' self.type(list) max_len = len(specs) min_len = max_len for spec in reversed(specs): if spec.isoptional: min_len -= 1 else: break if max_len == min_len: self.len('eq', len(specs)) else: if min_len > 0: self.len('ge', min_len) self.len('le', max_len) start = len(self.specs) for i, spec in zip(itertools.count(), specs): self.specs.append(spec) self.checks.append(('check_tuple', start, len(self.specs))) return self def func(self, func, msg_func=None): '''Describe value that is checked by the given function Check out :py:meth:`Spec.check_func` documentation for more details. ''' self.checks.append(('check_func', func, msg_func or (lambda value: 'failed check'))) return self def re(self, regex, msg_func=None): '''Describe value that is a string that matches given regular expression :param str regex: Regular expression that should be matched by the value. :param function msg_func: Function that should accept checked value and return message that describes the problem with this value. Default value will emit something like “String "xyz" does not match "[a-f]+"”. :return: self. ''' self.type(unicode) compiled = re.compile(regex) msg_func = msg_func or (lambda value: 'String "{0}" does not match "{1}"'.format(value, regex)) self.checks.append(( 'check_func', (lambda value, *args: (True, True, not compiled.match(value.value))), msg_func )) return self def ident(self, msg_func=None): '''Describe value that is an identifier like ``foo:bar`` or ``foo`` :param function msg_func: Function that should accept checked value and return message that describes the problem with this value. Default value will emit something like “String "xyz" is not an … identifier”. :return: self. ''' msg_func = ( msg_func or (lambda value: 'String "{0}" is not an alphanumeric/underscore colon-separated identifier'.format(value)) ) return self.re(r'^\w+(?::\w+)?$', msg_func) def oneof(self, collection, msg_func=None): '''Describe value that is equal to one of the value in the collection :param set collection: A collection of possible values. :param function msg_func: Function that should accept checked value and return message that describes the problem with this value. Default value will emit something like “"xyz" must be one of {'abc', 'def', 'ghi'}”. :return: self. ''' msg_func = msg_func or (lambda value: '"{0}" must be one of {1!r}'.format(value, list(collection))) self.checks.append(( 'check_func', (lambda value, *args: (True, True, value not in collection)), msg_func )) return self def error(self, msg): '''Describe value that must not be there Useful for giving more descriptive errors for some specific keys then just “found unknown key: shutdown_event” or for forbidding certain values when :py:meth:`Spec.unknown_spec` was used. :param str msg: Message given for the offending value. It is formatted using :py:meth:`str.format` with the only positional parameter which is the value itself. :return: self. ''' self.checks.append(( 'check_func', (lambda *args: (True, True, True)), (lambda value: msg.format(value)) )) return self def either(self, *specs): '''Describes value that matches one of the given specs Check out :py:meth:`Spec.check_either` method documentation for more details, but note that there a list of specs was replaced by start and end indices in ``self.specs``. :return: self. ''' start = len(self.specs) self.specs.extend(specs) self.checks.append(('check_either', start, len(self.specs))) return self def optional(self): '''Mark value as optional Only useful for key specs in :py:meth:`Spec.__init__` and :py:meth:`Spec.update` and some last supplied to :py:meth:`Spec.tuple`. :return: self. ''' self.isoptional = True return self def required(self): '''Mark value as required Only useful for key specs in :py:meth:`Spec.__init__` and :py:meth:`Spec.update` and some last supplied to :py:meth:`Spec.tuple`. .. note:: Value is required by default. This method is only useful for altering existing specification (or rather its copy). :return: self. ''' self.isoptional = False return self def match_checks(self, *args): '''Process checks registered for the given value Processes only “top-level” checks: key specifications given using at the initialization or via :py:meth:`Spec.unknown_spec` are processed by :py:meth:`Spec.match`. :return: proceed, hadproblem. ''' hadproblem = False for check in self.checks: proceed, chadproblem = getattr(self, check[0])(*(args + check[1:])) if chadproblem: hadproblem = True if not proceed: return False, hadproblem return True, hadproblem def match(self, value, context_mark=None, data=None, context=(), echoerr=echoerr): '''Check that given value matches this specification :return: proceed, hadproblem. ''' havemarks(value) proceed, hadproblem = self.match_checks(value, context_mark, data, context, echoerr) if proceed: if self.keys or self.uspecs: for key, vali in self.keys.items(): valspec = self.specs[vali] if key in value: proceed, mhadproblem = valspec.match( value[key], value.mark, data, context.enter_key(value, key), echoerr ) if mhadproblem: hadproblem = True if not proceed: return False, hadproblem else: if not valspec.isoptional: hadproblem = True echoerr(context=self.cmsg.format(key=context.key), context_mark=None, problem='required key is missing: {0}'.format(key), problem_mark=value.mark) for key in value.keys(): havemarks(key) if key not in self.keys: for keyfunc, vali in self.uspecs: valspec = self.specs[vali] if isinstance(keyfunc, int): spec = self.specs[keyfunc] proceed, khadproblem = spec.match(key, context_mark, data, context, echoerr) else: proceed, khadproblem = keyfunc(key, data, context, echoerr) if khadproblem: hadproblem = True if proceed: proceed, vhadproblem = valspec.match( value[key], value.mark, data, context.enter_key(value, key), echoerr ) if vhadproblem: hadproblem = True break else: hadproblem = True if self.ufailmsg: echoerr(context=self.cmsg.format(key=context.key), context_mark=None, problem=self.ufailmsg(key), problem_mark=key.mark) return True, hadproblem def __getitem__(self, key): '''Get specification for the given key ''' return self.specs[self.keys[key]] def __setitem__(self, key, value): '''Set specification for the given key ''' self.update(**{key: value}) powerline-2.8.4/powerline/listers/000077500000000000000000000000001466405252600172345ustar00rootroot00000000000000powerline-2.8.4/powerline/listers/__init__.py000066400000000000000000000000001466405252600213330ustar00rootroot00000000000000powerline-2.8.4/powerline/listers/i3wm.py000066400000000000000000000033211466405252600204640ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.theme import requires_segment_info from powerline.lib.dict import updated from powerline.bindings.wm import get_i3_connection, get_connected_xrandr_outputs @requires_segment_info def output_lister(pl, segment_info): '''List all outputs in segment_info format ''' return ( ( updated(segment_info, output=output['name']), { 'draw_inner_divider': None } ) for output in get_connected_xrandr_outputs(pl) ) @requires_segment_info def workspace_lister(pl, segment_info, only_show=None, output=None): '''List all workspaces in segment_info format Sets the segment info values of ``workspace`` and ``output`` to the name of the i3 workspace and the ``xrandr`` output respectively and the keys ``"visible"``, ``"urgent"`` and ``"focused"`` to a boolean indicating these states. :param list only_show: Specifies which workspaces to list. Valid entries are ``"visible"``, ``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces are listed. :param str output: May be set to the name of an X output. If specified, only workspaces on that output are listed. Overrides automatic output detection by the lemonbar renderer and bindings. Set to ``false`` to force all workspaces to be shown. ''' if output == None: output = output or segment_info.get('output') return ( ( updated( segment_info, output=w.output, workspace=w, ), { 'draw_inner_divider': None } ) for w in get_i3_connection().get_workspaces() if (((not only_show or any(getattr(w, typ) for typ in only_show)) and (not output or w.output == output))) ) powerline-2.8.4/powerline/listers/pdb.py000066400000000000000000000017301466405252600203540ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.theme import requires_segment_info @requires_segment_info def frame_lister(pl, segment_info, full_stack=False, maxframes=3): '''List all frames in segment_info format :param bool full_stack: If true, then all frames in the stack are listed. Normally N first frames are discarded where N is a number of frames present at the first invocation of the prompt minus one. :param int maxframes: Maximum number of frames to display. ''' if full_stack: initial_stack_length = 0 frames = segment_info['pdb'].stack else: initial_stack_length = segment_info['initial_stack_length'] frames = segment_info['pdb'].stack[initial_stack_length:] if len(frames) > maxframes: frames = frames[-maxframes:] return ( ( { 'curframe': frame[0], 'initial_stack_length': initial_stack_length, }, {} ) for frame in frames ) powerline-2.8.4/powerline/listers/vim.py000066400000000000000000000073531466405252600204110ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.theme import requires_segment_info from powerline.bindings.vim import (current_tabpage, list_tabpages) try: import vim except ImportError: vim = object() def tabpage_updated_segment_info(segment_info, tabpage): segment_info = segment_info.copy() window = tabpage.window buffer = window.buffer segment_info.update( tabpage=tabpage, tabnr=tabpage.number, window=window, winnr=window.number, window_id=int(window.vars.get('powerline_window_id', -1)), buffer=buffer, bufnr=buffer.number, ) return segment_info @requires_segment_info def tablister(pl, segment_info, **kwargs): '''List all tab pages in segment_info format Specifically generates a list of segment info dictionaries with ``window``, ``winnr``, ``window_id``, ``buffer`` and ``bufnr`` keys set to tab-local ones and additional ``tabpage`` and ``tabnr`` keys. Adds either ``tab:`` or ``tab_nc:`` prefix to all segment highlight groups. Works best with vim-7.4 or later: earlier versions miss tabpage object and thus window objects are not available as well. ''' cur_tabpage = current_tabpage() cur_tabnr = cur_tabpage.number def add_multiplier(tabpage, dct): dct['priority_multiplier'] = 1 + (0.001 * abs(tabpage.number - cur_tabnr)) return dct return ( (lambda tabpage, prefix: ( tabpage_updated_segment_info(segment_info, tabpage), add_multiplier(tabpage, { 'highlight_group_prefix': prefix, 'divider_highlight_group': 'tab:divider' }) ))(tabpage, 'tab' if tabpage == cur_tabpage else 'tab_nc') for tabpage in list_tabpages() ) def buffer_updated_segment_info(segment_info, buffer): segment_info = segment_info.copy() segment_info.update( window=None, winnr=None, window_id=None, buffer=buffer, bufnr=buffer.number, ) return segment_info @requires_segment_info def bufferlister(pl, segment_info, show_unlisted=False, **kwargs): '''List all buffers in segment_info format Specifically generates a list of segment info dictionaries with ``buffer`` and ``bufnr`` keys set to buffer-specific ones, ``window``, ``winnr`` and ``window_id`` keys set to None. Adds one of ``buf:``, ``buf_nc:``, ``buf_mod:``, or ``buf_nc_mod`` prefix to all segment highlight groups. :param bool show_unlisted: True if unlisted buffers should be shown as well. Current buffer is always shown. ''' cur_buffer = vim.current.buffer cur_bufnr = cur_buffer.number def add_multiplier(buffer, dct): dct['priority_multiplier'] = 1 + (0.001 * abs(buffer.number - cur_bufnr)) return dct return ( (lambda buffer, current, modified: ( buffer_updated_segment_info(segment_info, buffer), add_multiplier(buffer, { 'highlight_group_prefix': '{0}{1}'.format(current, modified), 'divider_highlight_group': 'tab:divider' }) ))( buffer, 'buf' if buffer is cur_buffer else 'buf_nc', '_mod' if int(vim.eval('getbufvar({0}, \'&modified\')'.format(buffer.number))) > 0 else '' ) for buffer in vim.buffers if ( buffer is cur_buffer or show_unlisted # We can't use vim_getbufoption(segment_info, 'buflisted') # here for performance reasons. Querying the buffer options # through the vim python module's option attribute caused # vim to think it needed to update the tabline for every # keystroke after any event that changed the buffer's # options. # # Using the vim module's eval method to directly use the # buflisted(nr) vim method instead does not cause vim to # update the tabline after every keystroke, but rather after # events that would change that status. Fixes #1281 or int(vim.eval('buflisted(%s)' % buffer.number)) > 0 ) ) powerline-2.8.4/powerline/matchers/000077500000000000000000000000001466405252600173555ustar00rootroot00000000000000powerline-2.8.4/powerline/matchers/__init__.py000066400000000000000000000003001466405252600214570ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from pkgutil import extend_path __path__ = extend_path(__path__, __name__) powerline-2.8.4/powerline/matchers/vim/000077500000000000000000000000001466405252600201505ustar00rootroot00000000000000powerline-2.8.4/powerline/matchers/vim/__init__.py000066400000000000000000000007571466405252600222720ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from powerline.bindings.vim import vim_getbufoption, buffer_name def help(matcher_info): return vim_getbufoption(matcher_info, 'buftype') == 'help' def cmdwin(matcher_info): name = buffer_name(matcher_info) return name and os.path.basename(name) == b'[Command Line]' def quickfix(matcher_info): return vim_getbufoption(matcher_info, 'buftype') == 'quickfix' powerline-2.8.4/powerline/matchers/vim/plugin/000077500000000000000000000000001466405252600214465ustar00rootroot00000000000000powerline-2.8.4/powerline/matchers/vim/plugin/__init__.py000066400000000000000000000003001466405252600235500ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from pkgutil import extend_path __path__ = extend_path(__path__, __name__) powerline-2.8.4/powerline/matchers/vim/plugin/commandt.py000066400000000000000000000005771466405252600236330ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from powerline.bindings.vim import vim_getbufoption, buffer_name def commandt(matcher_info): name = buffer_name(matcher_info) return ( vim_getbufoption(matcher_info, 'filetype') == 'command-t' or (name and os.path.basename(name) == b'GoToFile') ) powerline-2.8.4/powerline/matchers/vim/plugin/gundo.py000066400000000000000000000006501466405252600231350ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from powerline.bindings.vim import buffer_name def gundo(matcher_info): name = buffer_name(matcher_info) return name and os.path.basename(name) == b'__Gundo__' def gundo_preview(matcher_info): name = buffer_name(matcher_info) return name and os.path.basename(name) == b'__Gundo_Preview__' powerline-2.8.4/powerline/matchers/vim/plugin/nerdtree.py000066400000000000000000000005431466405252600236320ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import re from powerline.bindings.vim import buffer_name NERD_TREE_RE = re.compile(b'NERD_tree_\\d+') def nerdtree(matcher_info): name = buffer_name(matcher_info) return name and NERD_TREE_RE.match(os.path.basename(name)) powerline-2.8.4/powerline/pdb.py000066400000000000000000000027031466405252600166700ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import platform import os from powerline import Powerline from powerline.lib.overrides import parse_override_var from powerline.lib.dict import mergeargs, mergedicts class PDBPowerline(Powerline): '''PDB-specific powerline bindings ''' def init(self, **kwargs): return super(PDBPowerline, self).init( ext='pdb', renderer_module='pdb', **kwargs ) def do_setup(self, pdb): self.update_renderer() self.renderer.set_pdb(pdb) def load_main_config(self): r = super(PDBPowerline, self).load_main_config() config_overrides = os.environ.get('POWERLINE_CONFIG_OVERRIDES') if config_overrides: mergedicts(r, mergeargs(parse_override_var(config_overrides))) return r def load_theme_config(self, name): r = super(PDBPowerline, self).load_theme_config(name) theme_overrides = os.environ.get('POWERLINE_THEME_OVERRIDES') if theme_overrides: theme_overrides_dict = mergeargs(parse_override_var(theme_overrides)) if name in theme_overrides_dict: mergedicts(r, theme_overrides_dict[name]) return r def get_config_paths(self): paths = [path for path in os.environ.get('POWERLINE_CONFIG_PATHS', '').split(':') if path] return paths or super(PDBPowerline, self).get_config_paths() if sys.version_info < (3,) and platform.python_implementation() == 'PyPy': get_encoding = staticmethod(lambda: 'ascii') powerline-2.8.4/powerline/renderer.py000066400000000000000000000510631466405252600177340ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import os import re import operator from itertools import chain from powerline.theme import Theme from powerline.lib.unicode import unichr, strwidth_ucs_2, strwidth_ucs_4 NBSP = ' ' np_control_character_translations = dict(( # Control characters: ^@ … ^Y (i1, '^' + unichr(i1 + 0x40)) for i1 in range(0x20) )) '''Control character translations Dictionary that maps characters in range 0x00–0x1F (inclusive) to strings ``'^@'``, ``'^A'`` and so on. .. note: maps tab to ``^I`` and newline to ``^J``. ''' np_invalid_character_translations = dict(( # Invalid unicode characters obtained using 'surrogateescape' error # handler. (i2, '<{0:02x}>'.format(i2 - 0xDC00)) for i2 in range(0xDC80, 0xDD00) )) '''Invalid unicode character translations When using ``surrogateescape`` encoding error handling method characters in range 0x80–0xFF (inclusive) are transformed into unpaired surrogate escape unicode codepoints 0xDC80–0xDD00. This dictionary maps such characters to ``<80>``, ``<81>``, and so on: in Python-3 they cannot be printed or converted to UTF-8 because UTF-8 standard does not allow surrogate escape characters, not even paired ones. Python-2 contains a bug that allows such action, but printing them in any case makes no sense. ''' # XXX: not using `r` because it makes no sense. np_invalid_character_re = re.compile('(? width: for segment in chain(segments_priority, no_priority_segments): if segment['truncate'] is not None: segment['contents'] = segment['truncate'](self.pl, current_width - width, segment) segments_priority = iter(segments_priority) if current_width > width and len(segments) > 100: # When there are too many segments use faster, but less correct # algorithm for width computation diff = current_width - width for segment in segments_priority: segments.remove(segment) diff -= segment['_len'] if diff <= 0: break current_width = self._render_length(theme, segments, divider_widths) if current_width > width: # When there are not too much use more precise, but much slower # width computation. It also finishes computations in case # previous variant did not free enough space. for segment in segments_priority: segments.remove(segment) current_width = self._render_length(theme, segments, divider_widths) if current_width <= width: break del segments_priority # Distribute the remaining space on spacer segments segments_spacers = [segment for segment in segments if segment['expand'] is not None] if segments_spacers: distribute_len, distribute_len_remainder = divmod(width - current_width, len(segments_spacers)) for segment in segments_spacers: segment['contents'] = ( segment['expand']( self.pl, distribute_len + (1 if distribute_len_remainder > 0 else 0), segment)) distribute_len_remainder -= 1 # `_len` key is not needed anymore, but current_width should have an # actual value for various bindings. current_width = width elif output_width: current_width = self._render_length(theme, segments, divider_widths) rendered_highlighted = self.hl_join([ segment['_rendered_hl'] for segment in self._render_segments(theme, segments, hl_args) ]) if rendered_highlighted: rendered_highlighted += self.hlstyle(**hl_args) return construct_returned_value(rendered_highlighted, segments, current_width, output_raw, output_width) def _prepare_segments(self, segments, calculate_contents_len): '''Translate non-printable characters and calculate segment width ''' for segment in segments: segment['contents'] = translate_np(segment['contents']) if calculate_contents_len: for segment in segments: if segment['literal_contents'][1]: segment['_contents_len'] = segment['literal_contents'][0] else: segment['_contents_len'] = self.strwidth(segment['contents']) def _render_length(self, theme, segments, divider_widths): '''Update segments lengths and return them ''' segments_len = len(segments) ret = 0 divider_spaces = theme.get_spaces() prev_segment = theme.EMPTY_SEGMENT try: first_segment = next(iter(( segment for segment in segments if not segment['literal_contents'][1] ))) except StopIteration: first_segment = None try: last_segment = next(iter(( segment for segment in reversed(segments) if not segment['literal_contents'][1] ))) except StopIteration: last_segment = None for index, segment in enumerate(segments): side = segment['side'] segment_len = segment['_contents_len'] if not segment['literal_contents'][1]: if side == 'left': if segment is not last_segment: compare_segment = next(iter(( segment for segment in segments[index + 1:] if not segment['literal_contents'][1] ))) else: compare_segment = theme.EMPTY_SEGMENT else: compare_segment = prev_segment divider_type = 'soft' if compare_segment['highlight']['bg'] == segment['highlight']['bg'] else 'hard' outer_padding = int(bool( segment is first_segment if side == 'left' else segment is last_segment )) * theme.outer_padding draw_divider = segment['draw_' + divider_type + '_divider'] segment_len += outer_padding if draw_divider: segment_len += divider_widths[side][divider_type] + divider_spaces prev_segment = segment segment['_len'] = segment_len ret += segment_len return ret def _render_segments(self, theme, segments, hl_args, render_highlighted=True): '''Internal segment rendering method. This method loops through the segment array and compares the foreground/background colors and divider properties and returns the rendered statusline as a string. The method always renders the raw segment contents (i.e. without highlighting strings added), and only renders the highlighted statusline if render_highlighted is True. ''' segments_len = len(segments) divider_spaces = theme.get_spaces() prev_segment = theme.EMPTY_SEGMENT try: first_segment = next(iter(( segment for segment in segments if not segment['literal_contents'][1] ))) except StopIteration: first_segment = None try: last_segment = next(iter(( segment for segment in reversed(segments) if not segment['literal_contents'][1] ))) except StopIteration: last_segment = None for index, segment in enumerate(segments): side = segment['side'] if not segment['literal_contents'][1]: if side == 'left': if segment is not last_segment: compare_segment = next(iter(( segment for segment in segments[index + 1:] if not segment['literal_contents'][1] ))) else: compare_segment = theme.EMPTY_SEGMENT else: compare_segment = prev_segment outer_padding = int(bool( segment is first_segment if side == 'left' else segment is last_segment )) * theme.outer_padding * ' ' divider_type = 'soft' if compare_segment['highlight']['bg'] == segment['highlight']['bg'] else 'hard' divider_highlighted = '' contents_raw = segment['contents'] contents_highlighted = '' draw_divider = segment['draw_' + divider_type + '_divider'] segment_hl_args = {} segment_hl_args.update(segment['highlight']) segment_hl_args.update(hl_args) # XXX Make sure self.hl() calls are called in the same order # segments are displayed. This is needed for Vim renderer to work. if draw_divider: divider_raw = self.escape(theme.get_divider(side, divider_type)) if side == 'left': contents_raw = outer_padding + contents_raw + (divider_spaces * ' ') else: contents_raw = (divider_spaces * ' ') + contents_raw + outer_padding if divider_type == 'soft': divider_highlight_group_key = 'highlight' if segment['divider_highlight_group'] is None else 'divider_highlight' divider_fg = segment[divider_highlight_group_key]['fg'] divider_bg = segment[divider_highlight_group_key]['bg'] else: divider_fg = segment['highlight']['bg'] divider_bg = compare_segment['highlight']['bg'] if side == 'left': if render_highlighted: contents_highlighted = self.hl(self.escape(contents_raw), **segment_hl_args) divider_highlighted = self.hl(divider_raw, divider_fg, divider_bg, False, **hl_args) segment['_rendered_raw'] = contents_raw + divider_raw segment['_rendered_hl'] = contents_highlighted + divider_highlighted else: if render_highlighted: divider_highlighted = self.hl(divider_raw, divider_fg, divider_bg, False, **hl_args) contents_highlighted = self.hl(self.escape(contents_raw), **segment_hl_args) segment['_rendered_raw'] = divider_raw + contents_raw segment['_rendered_hl'] = divider_highlighted + contents_highlighted else: if side == 'left': contents_raw = outer_padding + contents_raw else: contents_raw = contents_raw + outer_padding contents_highlighted = self.hl(self.escape(contents_raw), **segment_hl_args) segment['_rendered_raw'] = contents_raw segment['_rendered_hl'] = contents_highlighted prev_segment = segment else: segment['_rendered_raw'] = ' ' * segment['literal_contents'][0] segment['_rendered_hl'] = segment['literal_contents'][1] yield segment def escape(self, string): '''Method that escapes segment contents. ''' return string.translate(self.character_translations) def hlstyle(fg=None, bg=None, attrs=None, **kwargs): '''Output highlight style string. Assuming highlighted string looks like ``{style}{contents}`` this method should output ``{style}``. If it is called without arguments this method is supposed to reset style to its default. ''' raise NotImplementedError def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs): '''Output highlighted chunk. This implementation just outputs :py:meth:`hlstyle` joined with ``contents``. ''' return self.hlstyle(fg, bg, attrs, **kwargs) + (contents or '') powerline-2.8.4/powerline/renderers/000077500000000000000000000000001466405252600175405ustar00rootroot00000000000000powerline-2.8.4/powerline/renderers/__init__.py000066400000000000000000000000001466405252600216370ustar00rootroot00000000000000powerline-2.8.4/powerline/renderers/i3bar.py000066400000000000000000000016161466405252600211160ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import json from powerline.renderer import Renderer class I3barRenderer(Renderer): '''I3bar Segment Renderer. Currently works only for i3bgbar (i3 bar with custom patches). ''' @staticmethod def hlstyle(*args, **kwargs): # We don’t need to explicitly reset attributes, so skip those calls return '' def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs): segment = { 'full_text': contents, 'separator': False, 'separator_block_width': 0, # no separators } if fg is not None: if fg is not False and fg[1] is not False: segment['color'] = '#{0:06x}'.format(fg[1]) if bg is not None: if bg is not False and bg[1] is not False: segment['background'] = '#{0:06x}'.format(bg[1]) return json.dumps(segment) + ',' renderer = I3barRenderer powerline-2.8.4/powerline/renderers/ipython/000077500000000000000000000000001466405252600212325ustar00rootroot00000000000000powerline-2.8.4/powerline/renderers/ipython/__init__.py000066400000000000000000000016071466405252600233470ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.theme import Theme from powerline.renderers.shell import PromptRenderer class IPythonRenderer(PromptRenderer): '''Powerline ipython segment renderer.''' def get_segment_info(self, segment_info, mode): r = self.segment_info.copy() r['ipython'] = segment_info return r def get_theme(self, matcher_info): if matcher_info == 'in': return self.theme else: match = self.local_themes[matcher_info] try: return match['theme'] except KeyError: match['theme'] = Theme( theme_config=match['config'], main_theme_config=self.theme_config, **self.theme_kwargs ) return match['theme'] def shutdown(self): self.theme.shutdown() for match in self.local_themes.values(): if 'theme' in match: match['theme'].shutdown() powerline-2.8.4/powerline/renderers/ipython/pre_5.py000066400000000000000000000035231466405252600226210ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderers.shell import ShellRenderer from powerline.renderers.shell.readline import ReadlineRenderer from powerline.renderers.ipython import IPythonRenderer class IPythonPre50Renderer(IPythonRenderer, ShellRenderer): '''Powerline ipython segment renderer for pre-5.0 IPython versions.''' def render(self, **kwargs): # XXX super(ShellRenderer), *not* super(IPythonPre50Renderer) return super(ShellRenderer, self).render(**kwargs) def do_render(self, segment_info, **kwargs): segment_info.update(client_id='ipython') return super(IPythonPre50Renderer, self).do_render( segment_info=segment_info, **kwargs ) class IPythonPromptRenderer(IPythonPre50Renderer, ReadlineRenderer): '''Powerline ipython prompt (in and in2) renderer''' pass class IPythonNonPromptRenderer(IPythonPre50Renderer): '''Powerline ipython non-prompt (out and rewrite) renderer''' pass class RendererProxy(object): '''Powerline IPython renderer proxy which chooses appropriate renderer Instantiates two renderer objects: one will be used for prompts and the other for non-prompts. ''' def __init__(self, **kwargs): old_widths = {} self.non_prompt_renderer = IPythonNonPromptRenderer(old_widths=old_widths, **kwargs) self.prompt_renderer = IPythonPromptRenderer(old_widths=old_widths, **kwargs) def render_above_lines(self, *args, **kwargs): return self.non_prompt_renderer.render_above_lines(*args, **kwargs) def render(self, is_prompt, *args, **kwargs): return (self.prompt_renderer if is_prompt else self.non_prompt_renderer).render( *args, **kwargs) def shutdown(self, *args, **kwargs): self.prompt_renderer.shutdown(*args, **kwargs) self.non_prompt_renderer.shutdown(*args, **kwargs) renderer = RendererProxy powerline-2.8.4/powerline/renderers/ipython/since_5.py000066400000000000000000000065031466405252600231350ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import operator from collections import defaultdict try: from __builtin__ import reduce except ImportError: from functools import reduce from pygments.token import Token from prompt_toolkit.styles import DynamicStyle, Attrs from powerline.renderers.ipython import IPythonRenderer from powerline.ipython import IPythonInfo from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE PowerlinePromptToken = Token.Generic.Prompt.Powerline # Note: since 2.7 there is dict.__missing__ with same purpose. But in 2.6 one # must use defaultdict to get __missing__ working. class PowerlineStyleDict(defaultdict): '''Dictionary used for getting pygments style for Powerline groups ''' def __new__(cls, missing_func): return defaultdict.__new__(cls) def __init__(self, missing_func): super(PowerlineStyleDict, self).__init__() self.missing_func = missing_func def __missing__(self, key): return self.missing_func(key) class PowerlinePromptStyle(DynamicStyle): def get_attrs_for_token(self, token): if ( token not in PowerlinePromptToken or len(token) != len(PowerlinePromptToken) + 1 or not token[-1].startswith('Pl') or token[-1] == 'Pl' ): return super(PowerlinePromptStyle, self).get_attrs_for_token(token) ret = { 'color': None, 'bgcolor': None, 'bold': None, 'underline': None, 'italic': None, 'reverse': False, 'blink': False, } for prop in token[-1][3:].split('_'): if prop[0] == 'a': ret[prop[1:]] = True elif prop[0] == 'f': ret['color'] = prop[1:] elif prop[0] == 'b': ret['bgcolor'] = prop[1:] return Attrs(**ret) def get_token_to_attributes_dict(self): dct = super(PowerlinePromptStyle, self).get_token_to_attributes_dict() def fallback(key): try: return dct[key] except KeyError: return self.get_attrs_for_token(key) return PowerlineStyleDict(fallback) def invalidation_hash(self): return super(PowerlinePromptStyle, self).invalidation_hash() + 1 class IPythonPygmentsRenderer(IPythonRenderer): reduce_initial = [] def get_segment_info(self, segment_info, mode): return super(IPythonPygmentsRenderer, self).get_segment_info( IPythonInfo(segment_info), mode) @staticmethod def hl_join(segments): return reduce(operator.iadd, segments, []) def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs): '''Output highlighted chunk. This implementation outputs a list containing a single pair (:py:class:`pygments.token.Token`, :py:class:`powerline.lib.unicode.unicode`). ''' guifg = None guibg = None attrs = [] if fg is not None and fg is not False: guifg = fg[1] if bg is not None and bg is not False: guibg = bg[1] if attrs: attrs = [] if attrs & ATTR_BOLD: attrs.append('bold') if attrs & ATTR_ITALIC: attrs.append('italic') if attrs & ATTR_UNDERLINE: attrs.append('underline') name = ( 'Pl' + ''.join(('_a' + attr for attr in attrs)) + (('_f%6x' % guifg) if guifg is not None else '') + (('_b%6x' % guibg) if guibg is not None else '') ) return [(getattr(Token.Generic.Prompt.Powerline, name), contents)] def hlstyle(self, **kwargs): return [] def get_client_id(self, segment_info): return id(self) renderer = IPythonPygmentsRenderer powerline-2.8.4/powerline/renderers/ipython/since_7.py000066400000000000000000000052661466405252600231440ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet import operator try: from __builtin__ import reduce except ImportError: from functools import reduce from pygments.token import Token from prompt_toolkit.styles import DynamicStyle from powerline.renderers.ipython import IPythonRenderer from powerline.ipython import IPythonInfo from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE used_styles = [] seen = set() class PowerlinePromptStyle(DynamicStyle): @property def style_rules(self): return (self.get_style() or self._dummy).style_rules + used_styles def invalidation_hash(self): return (h + 1 for h in tuple(super(PowerlinePromptStyle, self).invalidation_hash())) class IPythonPygmentsRenderer(IPythonRenderer): reduce_initial = [] def __init__(self, **kwargs): super(IPythonPygmentsRenderer, self).__init__(**kwargs) self.character_translations[ord(' ')] = ' ' def get_segment_info(self, segment_info, mode): return super(IPythonPygmentsRenderer, self).get_segment_info( IPythonInfo(segment_info), mode) @staticmethod def hl_join(segments): return reduce(operator.iadd, segments, []) def hl(self, escaped_contents, fg=None, bg=None, attrs=None, *args, **kwargs): '''Output highlighted chunk. This implementation outputs a list containing a single pair (:py:class:`string`, :py:class:`powerline.lib.unicode.unicode`). ''' guifg = None guibg = None att = [] if fg is not None and fg is not False: guifg = fg[1] if bg is not None and bg is not False: guibg = bg[1] if attrs: att = [] if attrs & ATTR_BOLD: att.append('bold') if attrs & ATTR_ITALIC: att.append('italic') if attrs & ATTR_UNDERLINE: att.append('underline') fg = (('%06x' % guifg) if guifg is not None else '') bg = (('%06x' % guibg) if guibg is not None else '') name = ( 'pl' + ''.join(('_a' + attr for attr in att)) + '_f' + fg + '_b' + bg ) global seen if not (name in seen): global used_styles used_styles += [('pygments.' + name, ''.join((' ' + attr for attr in att)) + (' fg:#' + fg if fg != '' else ' fg:') + (' bg:#' + bg if bg != '' else ' bg:'))] seen.add(name) return [((name,), escaped_contents)] def hlstyle(self, *args, **kwargs): return [] def get_client_id(self, segment_info): return id(self) renderer = IPythonPygmentsRenderer powerline-2.8.4/powerline/renderers/lemonbar.py000066400000000000000000000034341466405252600217150ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderer import Renderer from powerline.theme import Theme from powerline.colorscheme import ATTR_UNDERLINE class LemonbarRenderer(Renderer): '''lemonbar (formerly bar/bar ain't recursive) renderer See documentation of `lemonbar `_ and :ref:`the usage instructions ` ''' character_translations = Renderer.character_translations.copy() character_translations[ord('%')] = '%%{}' @staticmethod def hlstyle(*args, **kwargs): # We don’t need to explicitly reset attributes, so skip those calls return '' def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs): text = '' if fg is not None: if fg is not False and fg[1] is not False: text += '%{{F#ff{0:06x}}}'.format(fg[1]) if bg is not None: if bg is not False and bg[1] is not False: text += '%{{B#ff{0:06x}}}'.format(bg[1]) if attrs & ATTR_UNDERLINE: text += '%{+u}' return text + contents + '%{F-B--u}' def render(self, *args, **kwargs): return '%{{l}}{0}%{{r}}{1}'.format( super(LemonbarRenderer, self).render(side='left', segment_info={'output': kwargs.get('matcher_info')}, *args, **kwargs), super(LemonbarRenderer, self).render(side='right', segment_info={'output': kwargs.get('matcher_info')}, *args, **kwargs), ) def get_theme(self, matcher_info): if not matcher_info or matcher_info not in self.local_themes: return self.theme match = self.local_themes[matcher_info] try: return match['theme'] except KeyError: match['theme'] = Theme( theme_config=match['config'], main_theme_config=self.theme_config, **self.theme_kwargs ) return match['theme'] renderer = LemonbarRenderer powerline-2.8.4/powerline/renderers/pango_markup.py000066400000000000000000000023551466405252600226020ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from xml.sax.saxutils import escape as _escape from powerline.renderer import Renderer from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE class PangoMarkupRenderer(Renderer): '''Powerline Pango markup segment renderer.''' @staticmethod def hlstyle(*args, **kwargs): # We don’t need to explicitly reset attributes, so skip those calls return '' def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs): '''Highlight a segment.''' awesome_attr = [] if fg is not None: if fg is not False and fg[1] is not False: awesome_attr += ['foreground="#{0:06x}"'.format(fg[1])] if bg is not None: if bg is not False and bg[1] is not False: awesome_attr += ['background="#{0:06x}"'.format(bg[1])] if attrs is not None and attrs is not False: if attrs & ATTR_BOLD: awesome_attr += ['font_weight="bold"'] if attrs & ATTR_ITALIC: awesome_attr += ['font_style="italic"'] if attrs & ATTR_UNDERLINE: awesome_attr += ['underline="single"'] return '' + contents + '' escape = staticmethod(_escape) renderer = PangoMarkupRenderer powerline-2.8.4/powerline/renderers/pdb.py000066400000000000000000000026271466405252600206660ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import platform from powerline.renderers.shell.readline import ReadlineRenderer from powerline.renderer import Renderer class PDBRenderer(ReadlineRenderer): '''PDB-specific powerline renderer ''' pdb = None initial_stack_length = None def get_segment_info(self, segment_info, mode): r = self.segment_info.copy() r['pdb'] = self.pdb r['initial_stack_length'] = self.initial_stack_length r['curframe'] = self.pdb.curframe return r def set_pdb(self, pdb): '''Record currently used :py:class:`pdb.Pdb` instance Must be called before first calling :py:meth:`render` method. :param pdb.Pdb pdb: Used :py:class:`pdb.Pdb` instance. This instance will later be used by :py:meth:`get_segment_info` for patching :ref:`segment_info ` dictionary. ''' self.pdb = pdb def render(self, **kwargs): if self.initial_stack_length is None: self.initial_stack_length = len(self.pdb.stack) - 1 return Renderer.render(self, **kwargs) if sys.version_info < (3,) and platform.python_implementation() == 'PyPy': def do_render(self, **kwargs): # Make sure that only ASCII characters survive ret = super(PDBRenderer, self).do_render(**kwargs) ret = ret.encode('ascii', 'replace') ret = ret.decode('ascii') return ret renderer = PDBRenderer powerline-2.8.4/powerline/renderers/shell/000077500000000000000000000000001466405252600206475ustar00rootroot00000000000000powerline-2.8.4/powerline/renderers/shell/__init__.py000066400000000000000000000122331466405252600227610ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderer import Renderer from powerline.theme import Theme from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE def int_to_rgb(num): r = (num >> 16) & 0xff g = (num >> 8) & 0xff b = num & 0xff return r, g, b class PromptRenderer(Renderer): '''Powerline generic prompt segment renderer''' def __init__(self, old_widths=None, **kwargs): super(PromptRenderer, self).__init__(**kwargs) self.old_widths = old_widths if old_widths is not None else {} def get_client_id(self, segment_info): '''Get client ID given segment info This is used by daemon to correctly cache widths for different clients using a single renderer instance. :param dict segment_info: :ref:`Segment info dictionary `. Out of it only ``client_id`` key is used. It is OK for this dictionary to not contain this key. :return: Any hashable value or ``None``. ''' return segment_info.get('client_id') if isinstance(segment_info, dict) else None def do_render(self, output_width, segment_info, side, theme, width=None, **kwargs): client_id = self.get_client_id(segment_info) if client_id is not None: local_key = (client_id, side, None if theme is self.theme else id(theme)) key = (client_id, side, None) did_width = False if local_key[-1] != key[-1] and side == 'left': try: width = self.old_widths[key] except KeyError: pass else: did_width = True if not did_width and width is not None: if theme.cursor_space_multiplier is not None: width = int(width * theme.cursor_space_multiplier) elif theme.cursor_columns: width -= theme.cursor_columns if side == 'right': try: width -= self.old_widths[(client_id, 'left', local_key[-1])] except KeyError: pass res = super(PromptRenderer, self).do_render( output_width=True, width=width, theme=theme, segment_info=segment_info, side=side, **kwargs ) if client_id is not None: self.old_widths[local_key] = res[-1] ret = res if output_width else res[:-1] if len(ret) == 1: return ret[0] else: return ret class ShellRenderer(PromptRenderer): '''Powerline shell segment renderer.''' escape_hl_start = '' escape_hl_end = '' term_truecolor = False term_escape_style = 'auto' tmux_escape = False screen_escape = False character_translations = Renderer.character_translations.copy() def render(self, segment_info, **kwargs): local_theme = segment_info.get('local_theme') return super(ShellRenderer, self).render( matcher_info=local_theme, segment_info=segment_info, **kwargs ) def do_render(self, segment_info, **kwargs): if self.term_escape_style == 'auto': if segment_info['environ'].get('TERM') == 'fbterm': self.used_term_escape_style = 'fbterm' else: self.used_term_escape_style = 'xterm' else: self.used_term_escape_style = self.term_escape_style return super(ShellRenderer, self).do_render(segment_info=segment_info, **kwargs) def hlstyle(self, fg=None, bg=None, attrs=None, escape=True, **kwargs): '''Highlight a segment. If an argument is None, the argument is ignored. If an argument is False, the argument is reset to the terminal defaults. If an argument is a valid color or attribute, it’s added to the ANSI escape code. ''' ansi = [0] is_fbterm = self.used_term_escape_style == 'fbterm' term_truecolor = not is_fbterm and self.term_truecolor if fg is not None: if fg is False or fg[0] is False: ansi += [39] else: if term_truecolor: ansi += [38, 2] + list(int_to_rgb(fg[1])) else: ansi += [38, 5, fg[0]] if bg is not None: if bg is False or bg[0] is False: ansi += [49] else: if term_truecolor: ansi += [48, 2] + list(int_to_rgb(bg[1])) else: ansi += [48, 5, bg[0]] if attrs is not None: if attrs is False: ansi += [22] else: if attrs & ATTR_BOLD: ansi += [1] elif attrs & ATTR_ITALIC: # Note: is likely not to work or even be inverse in place of # italic. Omit using this in colorschemes. ansi += [3] elif attrs & ATTR_UNDERLINE: ansi += [4] if is_fbterm: r = [] while ansi: cur_ansi = ansi.pop(0) if cur_ansi == 38: ansi.pop(0) r.append('\033[1;{0}}}'.format(ansi.pop(0))) elif cur_ansi == 48: ansi.pop(0) r.append('\033[2;{0}}}'.format(ansi.pop(0))) else: r.append('\033[{0}m'.format(cur_ansi)) r = ''.join(r) else: r = '\033[{0}m'.format(';'.join(str(attr) for attr in ansi)) if self.tmux_escape: r = '\033Ptmux;' + r.replace('\033', '\033\033') + '\033\\' elif self.screen_escape: r = '\033P' + r.replace('\033', '\033\033') + '\033\\' return self.escape_hl_start + r + self.escape_hl_end if escape else r def get_theme(self, matcher_info): if not matcher_info: return self.theme match = self.local_themes[matcher_info] try: return match['theme'] except KeyError: match['theme'] = Theme( theme_config=match['config'], main_theme_config=self.theme_config, **self.theme_kwargs ) return match['theme'] renderer = ShellRenderer powerline-2.8.4/powerline/renderers/shell/bash.py000066400000000000000000000050531466405252600221410ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderers.shell import ShellRenderer class BashPromptRenderer(ShellRenderer): '''Powerline bash prompt segment renderer.''' escape_hl_start = '\\[' escape_hl_end = '\\]' character_translations = ShellRenderer.character_translations.copy() character_translations[ord('$')] = '\\$' character_translations[ord('`')] = '\\`' character_translations[ord('\\')] = '\\\\' def do_render(self, side, line, width, output_width, output_raw, hl_args, **kwargs): # we are rendering the normal left prompt if side == 'left' and line == 0 and width is not None: # we need left prompt's width to render the raw spacer output_width = output_width or output_raw left = super(BashPromptRenderer, self).do_render( side=side, line=line, output_width=output_width, width=width, output_raw=output_raw, hl_args=hl_args, **kwargs ) left_rendered = left[0] if output_width else left # we don't escape color sequences in the right prompt so we can do escaping as a whole if hl_args: hl_args = hl_args.copy() hl_args.update({'escape': False}) else: hl_args = {'escape': False} right = super(BashPromptRenderer, self).do_render( side='right', line=line, output_width=True, width=width, output_raw=output_raw, hl_args=hl_args, **kwargs ) ret = [] if right[-1] > 0: # if the right prompt is not empty we embed it in the left prompt # it must be escaped as a whole so readline doesn't see it ret.append(''.join(( left_rendered, self.escape_hl_start, '\033[s', # save the cursor position '\033[{0}C'.format(width), # move to the right edge of the terminal '\033[{0}D'.format(right[-1] - 1), # move back to the right prompt position right[0], '\033[u', # restore the cursor position self.escape_hl_end ))) if output_raw: ret.append(''.join(( left[1], ' ' * (width - left[-1] - right[-1]), right[1] ))) else: ret.append(left_rendered) if output_raw: ret.append(left[1]) if output_width: ret.append(left[-1]) if len(ret) == 1: return ret[0] else: return ret else: return super(BashPromptRenderer, self).do_render( side=side, line=line, width=width, output_width=output_width, output_raw=output_raw, hl_args=hl_args, **kwargs ) renderer = BashPromptRenderer powerline-2.8.4/powerline/renderers/shell/ksh.py000066400000000000000000000007311466405252600220070ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderers.shell import ShellRenderer ESCAPE_CHAR = '\001' class KshPromptRenderer(ShellRenderer): '''Powerline bash prompt segment renderer.''' escape_hl_start = '\001' escape_hl_end = '\001' def render(self, *args, **kwargs): return '\001\r' + super(KshPromptRenderer, self).render(*args, **kwargs) renderer = KshPromptRenderer powerline-2.8.4/powerline/renderers/shell/rcsh.py000066400000000000000000000003221466405252600221550ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderers.shell.readline import ReadlineRenderer renderer = ReadlineRenderer powerline-2.8.4/powerline/renderers/shell/readline.py000066400000000000000000000005421466405252600230050ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderers.shell import ShellRenderer class ReadlineRenderer(ShellRenderer): '''Renderer useful for some applications that use readline ''' escape_hl_start = '\x01' escape_hl_end = '\x02' renderer = ReadlineRenderer powerline-2.8.4/powerline/renderers/shell/tcsh.py000066400000000000000000000021371466405252600221650ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderers.shell.zsh import ZshPromptRenderer class TcshPromptRenderer(ZshPromptRenderer): '''Powerline tcsh prompt segment renderer.''' character_translations = ZshPromptRenderer.character_translations.copy() character_translations[ord('%')] = '%%' character_translations[ord('\\')] = '\\\\' character_translations[ord('^')] = '\\^' character_translations[ord('!')] = '\\!' def do_render(self, **kwargs): ret = super(TcshPromptRenderer, self).do_render(**kwargs) nbsp = self.character_translations.get(ord(' '), ' ') end = self.hlstyle() assert not ret or ret.endswith(end) if ret.endswith(nbsp + end): # Exchange nbsp and highlight end because tcsh removes trailing # %{%} part of the prompt for whatever reason ret = ret[:-(len(nbsp) + len(end))] + end + nbsp else: # We *must* end prompt with non-%{%} sequence for the reasons # explained above. So add nbsp if it is not already there. ret += nbsp return ret renderer = TcshPromptRenderer powerline-2.8.4/powerline/renderers/shell/zsh.py000066400000000000000000000006751466405252600220350ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderers.shell import ShellRenderer class ZshPromptRenderer(ShellRenderer): '''Powerline zsh prompt segment renderer.''' escape_hl_start = '%{' escape_hl_end = '%}' character_translations = ShellRenderer.character_translations.copy() character_translations[ord('%')] = '%%' renderer = ZshPromptRenderer powerline-2.8.4/powerline/renderers/tmux.py000066400000000000000000000043641466405252600211160ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.renderer import Renderer from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE def attrs_to_tmux_attrs(attrs): if attrs is False: return ['nobold', 'noitalics', 'nounderscore'] else: ret = [] if attrs & ATTR_BOLD: ret += ['bold'] else: ret += ['nobold'] if attrs & ATTR_ITALIC: ret += ['italics'] else: ret += ['noitalics'] if attrs & ATTR_UNDERLINE: ret += ['underscore'] else: ret += ['nounderscore'] return ret class TmuxRenderer(Renderer): '''Powerline tmux segment renderer.''' character_translations = Renderer.character_translations.copy() character_translations[ord('#')] = '##[]' def render(self, width=None, segment_info={}, **kwargs): if width and segment_info: width -= segment_info.get('width_adjust', 0) if width < 10: width = 10 return super(TmuxRenderer, self).render(width=width, segment_info=segment_info, **kwargs) def hlstyle(self, fg=None, bg=None, attrs=None, **kwargs): '''Highlight a segment.''' # We don’t need to explicitly reset attributes, so skip those calls if not attrs and not bg and not fg: return '' tmux_attrs = [] if fg is not None: if fg is False or fg[0] is False: tmux_attrs += ['fg=default'] else: if self.term_truecolor and fg[1]: tmux_attrs += ['fg=#{0:06x}'.format(int(fg[1]))] else: tmux_attrs += ['fg=colour' + str(fg[0])] if bg is not None: if bg is False or bg[0] is False: tmux_attrs += ['bg=default'] else: if self.term_truecolor and bg[1]: tmux_attrs += ['bg=#{0:06x}'.format(int(bg[1]))] else: tmux_attrs += ['bg=colour' + str(bg[0])] if attrs is not None: tmux_attrs += attrs_to_tmux_attrs(attrs) return '#[' + ','.join(tmux_attrs) + ']' def get_segment_info(self, segment_info, mode): r = self.segment_info.copy() if segment_info: r.update(segment_info) if 'pane_current_path' in r: r['getcwd'] = lambda: r['pane_current_path'] elif 'pane_id' in r: varname = 'TMUX_PWD_' + str(r['pane_id']) if varname in r['environ']: r['getcwd'] = lambda: r['environ'][varname] r['mode'] = mode return r renderer = TmuxRenderer powerline-2.8.4/powerline/renderers/vim.py000066400000000000000000000132431466405252600207100ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import vim from powerline.bindings.vim import vim_get_func, vim_getoption, environ, current_tabpage, get_vim_encoding from powerline.renderer import Renderer from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE from powerline.theme import Theme from powerline.lib.unicode import unichr, register_strwidth_error vim_mode = vim_get_func('mode', rettype='unicode') if int(vim.eval('v:version')) >= 702: _vim_mode = vim_mode vim_mode = lambda: _vim_mode(1) mode_translations = { unichr(ord('V') - 0x40): '^V', unichr(ord('S') - 0x40): '^S', } class VimRenderer(Renderer): '''Powerline vim segment renderer.''' character_translations = Renderer.character_translations.copy() character_translations[ord('%')] = '%%' segment_info = Renderer.segment_info.copy() segment_info.update(environ=environ) def __init__(self, *args, **kwargs): if not hasattr(vim, 'strwidth'): # Hope nobody want to change this at runtime if vim.eval('&ambiwidth') == 'double': kwargs = dict(**kwargs) kwargs['ambigious'] = 2 super(VimRenderer, self).__init__(*args, **kwargs) self.hl_groups = {} self.prev_highlight = None self.strwidth_error_name = register_strwidth_error(self.strwidth) self.encoding = get_vim_encoding() def shutdown(self): self.theme.shutdown() for match in self.local_themes.values(): if 'theme' in match: match['theme'].shutdown() def add_local_theme(self, matcher, theme): if matcher in self.local_themes: raise KeyError('There is already a local theme with given matcher') self.local_themes[matcher] = theme def get_matched_theme(self, match): try: return match['theme'] except KeyError: match['theme'] = Theme(theme_config=match['config'], main_theme_config=self.theme_config, **self.theme_kwargs) return match['theme'] def get_theme(self, matcher_info): if matcher_info is None: return self.get_matched_theme(self.local_themes[None]) for matcher in self.local_themes.keys(): if matcher and matcher(matcher_info): return self.get_matched_theme(self.local_themes[matcher]) else: return self.theme if hasattr(vim, 'strwidth'): if sys.version_info < (3,): def strwidth(self, string): # Does not work with tabs, but neither is strwidth from default # renderer return vim.strwidth(string.encode(self.encoding, 'replace')) else: @staticmethod def strwidth(string): return vim.strwidth(string) def get_segment_info(self, segment_info, mode): return segment_info or self.segment_info def render(self, window=None, window_id=None, winnr=None, is_tabline=False): '''Render all segments.''' segment_info = self.segment_info.copy() if window is vim.current.window: mode = vim_mode() mode = mode_translations.get(mode, mode) else: mode = 'nc' segment_info.update( window=window, mode=mode, window_id=window_id, winnr=winnr, buffer=window.buffer, tabpage=current_tabpage(), encoding=self.encoding, ) segment_info['tabnr'] = segment_info['tabpage'].number segment_info['bufnr'] = segment_info['buffer'].number if is_tabline: winwidth = int(vim_getoption('columns')) else: winwidth = segment_info['window'].width statusline = super(VimRenderer, self).render( mode=mode, width=winwidth, segment_info=segment_info, matcher_info=(None if is_tabline else segment_info), ) statusline = statusline.encode(self.encoding, self.strwidth_error_name) return statusline def reset_highlight(self): self.hl_groups.clear() def hlstyle(self, fg=None, bg=None, attrs=None, **kwargs): '''Highlight a segment. If an argument is None, the argument is ignored. If an argument is False, the argument is reset to the terminal defaults. If an argument is a valid color or attribute, it’s added to the vim highlight group. ''' # In order not to hit E541 two consequent identical highlighting # specifiers may be squashed into one. attrs = attrs or 0 # Normalize `attrs` if (fg, bg, attrs) == self.prev_highlight: return '' self.prev_highlight = (fg, bg, attrs) # We don’t need to explicitly reset attributes in vim, so skip those # calls if not attrs and not bg and not fg: return '' if not (fg, bg, attrs) in self.hl_groups: hl_group = { 'ctermfg': 'NONE', 'guifg': None, 'ctermbg': 'NONE', 'guibg': None, 'attrs': ['NONE'], 'name': '', } if fg is not None and fg is not False: hl_group['ctermfg'] = fg[0] hl_group['guifg'] = fg[1] if bg is not None and bg is not False: hl_group['ctermbg'] = bg[0] hl_group['guibg'] = bg[1] if attrs: hl_group['attrs'] = [] if attrs & ATTR_BOLD: hl_group['attrs'].append('bold') if attrs & ATTR_ITALIC: hl_group['attrs'].append('italic') if attrs & ATTR_UNDERLINE: hl_group['attrs'].append('underline') hl_group['name'] = ( 'Pl_' + str(hl_group['ctermfg']) + '_' + str(hl_group['guifg']) + '_' + str(hl_group['ctermbg']) + '_' + str(hl_group['guibg']) + '_' + ''.join(hl_group['attrs']) ) self.hl_groups[(fg, bg, attrs)] = hl_group vim.command('hi {group} ctermfg={ctermfg} guifg={guifg} guibg={guibg} ctermbg={ctermbg} cterm={attrs} gui={attrs}'.format( group=hl_group['name'], ctermfg=hl_group['ctermfg'], guifg='#{0:06x}'.format(hl_group['guifg']) if hl_group['guifg'] is not None else 'NONE', ctermbg=hl_group['ctermbg'], guibg='#{0:06x}'.format(hl_group['guibg']) if hl_group['guibg'] is not None else 'NONE', attrs=','.join(hl_group['attrs']), )) return '%#' + self.hl_groups[(fg, bg, attrs)]['name'] + '#' renderer = VimRenderer powerline-2.8.4/powerline/segment.py000066400000000000000000000322601466405252600175660ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lib.watcher import create_file_watcher def list_segment_key_values(segment, theme_configs, segment_data, key, function_name=None, name=None, module=None, default=None): try: yield segment[key] except KeyError: pass found_module_key = False for theme_config in theme_configs: try: segment_data = theme_config['segment_data'] except KeyError: pass else: if function_name and not name: if module: try: yield segment_data[module + '.' + function_name][key] found_module_key = True except KeyError: pass if not found_module_key: try: yield segment_data[function_name][key] except KeyError: pass if name: try: yield segment_data[name][key] except KeyError: pass if segment_data is not None: try: yield segment_data[key] except KeyError: pass yield default def get_segment_key(merge, *args, **kwargs): if merge: ret = None for value in list_segment_key_values(*args, **kwargs): if ret is None: ret = value elif isinstance(ret, dict) and isinstance(value, dict): old_ret = ret ret = value.copy() ret.update(old_ret) else: return ret return ret else: return next(list_segment_key_values(*args, **kwargs)) def get_function(data, segment): function_name = segment['function'] if '.' in function_name: module, function_name = function_name.rpartition('.')[::2] else: module = data['default_module'] function = data['get_module_attr'](module, function_name, prefix='segment_generator') if not function: raise ImportError('Failed to obtain segment function') return None, function, module, function_name, segment.get('name') def get_string(data, segment): name = segment.get('name') return data['get_key'](False, segment, None, None, name, 'contents'), None, None, None, name segment_getters = { 'function': get_function, 'string': get_string, 'segment_list': get_function, } def get_attr_func(contents_func, key, args, is_space_func=False): try: func = getattr(contents_func, key) except AttributeError: return None else: if is_space_func: def expand_func(pl, amount, segment): try: return func(pl=pl, amount=amount, segment=segment, **args) except Exception as e: pl.exception('Exception while computing {0} function: {1}', key, str(e)) return segment['contents'] + (' ' * amount) return expand_func else: return lambda pl, shutdown_event: func(pl=pl, shutdown_event=shutdown_event, **args) def process_segment_lister(pl, segment_info, parsed_segments, side, mode, colorscheme, lister, subsegments, patcher_args): subsegments = [ subsegment for subsegment in subsegments if subsegment['display_condition'](pl, segment_info, mode) ] for subsegment_info, subsegment_update in lister(pl=pl, segment_info=segment_info, **patcher_args): draw_inner_divider = subsegment_update.pop('draw_inner_divider', False) old_pslen = len(parsed_segments) for subsegment in subsegments: if subsegment_update: subsegment = subsegment.copy() subsegment.update(subsegment_update) if 'priority_multiplier' in subsegment_update and subsegment['priority']: subsegment['priority'] *= subsegment_update['priority_multiplier'] process_segment( pl, side, subsegment_info, parsed_segments, subsegment, mode, colorscheme, ) new_pslen = len(parsed_segments) while parsed_segments[new_pslen - 1]['literal_contents'][1]: new_pslen -= 1 if new_pslen > old_pslen + 1 and draw_inner_divider is not None: for i in range(old_pslen, new_pslen - 1) if side == 'left' else range(old_pslen + 1, new_pslen): parsed_segments[i]['draw_soft_divider'] = draw_inner_divider return None def set_segment_highlighting(pl, colorscheme, segment, mode): if segment['literal_contents'][1]: return True try: highlight_group_prefix = segment['highlight_group_prefix'] except KeyError: hl_groups = lambda hlgs: hlgs else: hl_groups = lambda hlgs: [highlight_group_prefix + ':' + hlg for hlg in hlgs] + hlgs try: segment['highlight'] = colorscheme.get_highlighting( hl_groups(segment['highlight_groups']), mode, segment.get('gradient_level') ) if segment['divider_highlight_group']: segment['divider_highlight'] = colorscheme.get_highlighting( hl_groups([segment['divider_highlight_group']]), mode ) else: segment['divider_highlight'] = None except Exception as e: pl.exception('Failed to set highlight group: {0}', str(e)) return False else: return True def process_segment(pl, side, segment_info, parsed_segments, segment, mode, colorscheme): segment = segment.copy() pl.prefix = segment['name'] if segment['type'] in ('function', 'segment_list'): try: if segment['type'] == 'function': contents = segment['contents_func'](pl, segment_info) else: contents = segment['contents_func'](pl, segment_info, parsed_segments, side, mode, colorscheme) except Exception as e: pl.exception('Exception while computing segment: {0}', str(e)) return if contents is None: return if isinstance(contents, list): # Needs copying here, but it was performed at the very start of the # function segment_base = segment if contents: draw_divider_position = -1 if side == 'left' else 0 for key, i, newval in ( ('before', 0, ''), ('after', -1, ''), ('draw_soft_divider', draw_divider_position, True), ('draw_hard_divider', draw_divider_position, True), ): try: contents[i][key] = segment_base.pop(key) segment_base[key] = newval except KeyError: pass draw_inner_divider = None if side == 'right': append = parsed_segments.append else: pslen = len(parsed_segments) append = lambda item: parsed_segments.insert(pslen, item) for subsegment in (contents if side == 'right' else reversed(contents)): segment_copy = segment_base.copy() segment_copy.update(subsegment) if draw_inner_divider is not None: segment_copy['draw_soft_divider'] = draw_inner_divider draw_inner_divider = segment_copy.pop('draw_inner_divider', None) if set_segment_highlighting(pl, colorscheme, segment_copy, mode): append(segment_copy) else: segment['contents'] = contents if set_segment_highlighting(pl, colorscheme, segment, mode): parsed_segments.append(segment) elif segment['width'] == 'auto' or (segment['type'] == 'string' and segment['contents'] is not None): if set_segment_highlighting(pl, colorscheme, segment, mode): parsed_segments.append(segment) always_true = lambda pl, segment_info, mode: True get_fallback_segment = { 'name': 'fallback', 'type': 'string', 'highlight_groups': ['background'], 'divider_highlight_group': None, 'before': None, 'after': None, 'contents': '', 'literal_contents': (0, ''), 'priority': None, 'draw_soft_divider': True, 'draw_hard_divider': True, 'draw_inner_divider': True, 'display_condition': always_true, 'width': None, 'align': None, 'expand': None, 'truncate': None, 'startup': None, 'shutdown': None, '_rendered_raw': '', '_rendered_hl': '', '_len': None, '_contents_len': None, }.copy def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, get_module_attr, top_theme): data = { 'default_module': default_module or 'powerline.segments.' + ext, 'get_module_attr': get_module_attr, 'segment_data': None, } def get_key(merge, segment, module, function_name, name, key, default=None): return get_segment_key(merge, segment, theme_configs, data['segment_data'], key, function_name, name, module, default) data['get_key'] = get_key def get_selector(function_name): if '.' in function_name: module, function_name = function_name.rpartition('.')[::2] else: module = 'powerline.selectors.' + ext function = get_module_attr(module, function_name, prefix='segment_generator/selector_function') if not function: pl.error('Failed to get segment selector, ignoring it') return function def get_segment_selector(segment, selector_type): try: function_name = segment[selector_type + '_function'] except KeyError: function = None else: function = get_selector(function_name) try: modes = segment[selector_type + '_modes'] except KeyError: modes = None if modes: if function: return lambda pl, segment_info, mode: ( mode in modes or function(pl=pl, segment_info=segment_info, mode=mode) ) else: return lambda pl, segment_info, mode: mode in modes else: if function: return lambda pl, segment_info, mode: ( function(pl=pl, segment_info=segment_info, mode=mode) ) else: return None def gen_display_condition(segment): include_function = get_segment_selector(segment, 'include') exclude_function = get_segment_selector(segment, 'exclude') if include_function: if exclude_function: return lambda *args: ( include_function(*args) and not exclude_function(*args)) else: return include_function else: if exclude_function: return lambda *args: not exclude_function(*args) else: return always_true def get(segment, side): segment_type = segment.get('type', 'function') try: get_segment_info = segment_getters[segment_type] except KeyError: pl.error('Unknown segment type: {0}', segment_type) return None try: contents, _contents_func, module, function_name, name = get_segment_info(data, segment) except Exception as e: pl.exception('Failed to generate segment from {0!r}: {1}', segment, str(e), prefix='segment_generator') return None if not get_key(False, segment, module, function_name, name, 'display', True): return None segment_datas = getattr(_contents_func, 'powerline_segment_datas', None) if segment_datas: try: data['segment_data'] = segment_datas[top_theme] except KeyError: pass if segment_type == 'function': highlight_groups = [function_name] else: highlight_groups = segment.get('highlight_groups') or [name] if segment_type in ('function', 'segment_list'): args = dict(( (str(k), v) for k, v in get_key(True, segment, module, function_name, name, 'args', {}).items() )) display_condition = gen_display_condition(segment) if segment_type == 'segment_list': # Handle startup and shutdown of _contents_func? subsegments = [ subsegment for subsegment in ( get(subsegment, side) for subsegment in segment['segments'] ) if subsegment ] return { 'name': name or function_name, 'type': segment_type, 'highlight_groups': None, 'divider_highlight_group': None, 'before': None, 'after': None, 'contents_func': lambda pl, segment_info, parsed_segments, side, mode, colorscheme: ( process_segment_lister( pl, segment_info, parsed_segments, side, mode, colorscheme, patcher_args=args, subsegments=subsegments, lister=_contents_func, ) ), 'contents': None, 'literal_contents': None, 'priority': None, 'draw_soft_divider': None, 'draw_hard_divider': None, 'draw_inner_divider': None, 'side': side, 'display_condition': display_condition, 'width': None, 'align': None, 'expand': None, 'truncate': None, 'startup': None, 'shutdown': None, '_rendered_raw': '', '_rendered_hl': '', '_len': None, '_contents_len': None, } if segment_type == 'function': startup_func = get_attr_func(_contents_func, 'startup', args) shutdown_func = getattr(_contents_func, 'shutdown', None) expand_func = get_attr_func(_contents_func, 'expand', args, True) truncate_func = get_attr_func(_contents_func, 'truncate', args, True) if hasattr(_contents_func, 'powerline_requires_filesystem_watcher'): create_watcher = lambda: create_file_watcher(pl, common_config['watcher']) args[str('create_watcher')] = create_watcher if hasattr(_contents_func, 'powerline_requires_segment_info'): contents_func = lambda pl, segment_info: _contents_func(pl=pl, segment_info=segment_info, **args) else: contents_func = lambda pl, segment_info: _contents_func(pl=pl, **args) else: startup_func = None shutdown_func = None contents_func = None expand_func = None truncate_func = None return { 'name': name or function_name, 'type': segment_type, 'highlight_groups': highlight_groups, 'divider_highlight_group': None, 'before': get_key(False, segment, module, function_name, name, 'before', ''), 'after': get_key(False, segment, module, function_name, name, 'after', ''), 'contents_func': contents_func, 'contents': contents, 'literal_contents': (0, ''), 'priority': segment.get('priority', None), 'draw_hard_divider': segment.get('draw_hard_divider', True), 'draw_soft_divider': segment.get('draw_soft_divider', True), 'draw_inner_divider': segment.get('draw_inner_divider', False), 'side': side, 'display_condition': display_condition, 'width': segment.get('width'), 'align': segment.get('align', 'l'), 'expand': expand_func, 'truncate': truncate_func, 'startup': startup_func, 'shutdown': shutdown_func, '_rendered_raw': '', '_rendered_hl': '', '_len': None, '_contents_len': None, } return get powerline-2.8.4/powerline/segments/000077500000000000000000000000001466405252600173745ustar00rootroot00000000000000powerline-2.8.4/powerline/segments/__init__.py000066400000000000000000000032271466405252600215110ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys from pkgutil import extend_path from types import MethodType __path__ = extend_path(__path__, __name__) class Segment(object): '''Base class for any segment that is not a function Required for powerline.lint.inspect to work properly: it defines methods for omitting existing or adding new arguments. .. note:: Until python-3.4 ``inspect.getargspec`` does not support querying callable classes for arguments of their ``__call__`` method, requiring to use this method directly (i.e. before 3.4 you should write ``getargspec(obj.__call__)`` in place of ``getargspec(obj)``). ''' if sys.version_info < (3, 4): def argspecobjs(self): yield '__call__', self.__call__ else: def argspecobjs(self): yield '__call__', self argspecobjs.__doc__ = ( '''Return a list of valid arguments for inspect.getargspec Used to determine function arguments. ''' ) def omitted_args(self, name, method): '''List arguments which should be omitted Returns a tuple with indexes of omitted arguments. .. note::``segment_info``, ``create_watcher`` and ``pl`` will be omitted regardless of the below return (for ``segment_info`` and ``create_watcher``: only if object was marked to require segment info or filesystem watcher). ''' if isinstance(self.__call__, MethodType): return (0,) else: return () @staticmethod def additional_args(): '''Returns a list of (additional argument name[, default value]) tuples. ''' return () def with_docstring(instance, doc): instance.__doc__ = doc return instance powerline-2.8.4/powerline/segments/common/000077500000000000000000000000001466405252600206645ustar00rootroot00000000000000powerline-2.8.4/powerline/segments/common/__init__.py000066400000000000000000000000001466405252600227630ustar00rootroot00000000000000powerline-2.8.4/powerline/segments/common/bat.py000066400000000000000000000250361466405252600220120ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import sys import re from powerline.lib.shell import run_cmd def _fetch_battery_info(pl): try: import dbus except ImportError: pl.debug('Not using DBUS+UPower as dbus is not available') else: try: bus = dbus.SystemBus() except Exception as e: pl.exception('Failed to connect to system bus: {0}', str(e)) else: interface = 'org.freedesktop.UPower' try: up = bus.get_object(interface, '/org/freedesktop/UPower') except dbus.exceptions.DBusException as e: if getattr(e, '_dbus_error_name', '').endswith('ServiceUnknown'): pl.debug('Not using DBUS+UPower as UPower is not available via dbus') else: pl.exception('Failed to get UPower service with dbus: {0}', str(e)) else: devinterface = 'org.freedesktop.DBus.Properties' devtype_name = interface + '.Device' devices = [] for devpath in up.EnumerateDevices(dbus_interface=interface): dev = bus.get_object(interface, devpath) devget = lambda what: dev.Get( devtype_name, what, dbus_interface=devinterface ) if int(devget('Type')) != 2: pl.debug('Not using DBUS+UPower with {0}: invalid type', devpath) continue if not bool(devget('IsPresent')): pl.debug('Not using DBUS+UPower with {0}: not present', devpath) continue if not bool(devget('PowerSupply')): pl.debug('Not using DBUS+UPower with {0}: not a power supply', devpath) continue devices.append(devpath) pl.debug('Using DBUS+UPower with {0}', devpath) if devices: def _flatten_battery(pl): energy = 0.0 energy_full = 0.0 state = True for devpath in devices: dev = bus.get_object(interface, devpath) energy_full += float( dbus.Interface(dev, dbus_interface=devinterface).Get( devtype_name, 'EnergyFull' ), ) energy += float( dbus.Interface(dev, dbus_interface=devinterface).Get( devtype_name, 'Energy' ), ) state &= dbus.Interface(dev, dbus_interface=devinterface).Get( devtype_name, 'State' ) != 2 if energy_full > 0: return (energy * 100.0 / energy_full), state else: return 0.0, state return _flatten_battery pl.debug('Not using DBUS+UPower as no batteries were found') if os.path.isdir('/sys/class/power_supply'): # ENERGY_* attributes represents capacity in µWh only. # CHARGE_* attributes represents capacity in µAh only. linux_capacity_units = ('energy', 'charge') linux_energy_full_fmt = '/sys/class/power_supply/{0}/{1}_full' linux_energy_fmt = '/sys/class/power_supply/{0}/{1}_now' linux_status_fmt = '/sys/class/power_supply/{0}/status' devices = [] for linux_supplier in os.listdir('/sys/class/power_supply'): for unit in linux_capacity_units: energy_path = linux_energy_fmt.format(linux_supplier, unit) if not os.path.exists(energy_path): continue pl.debug('Using /sys/class/power_supply with battery {0} and unit {1}', linux_supplier, unit) devices.append((linux_supplier, unit)) break # energy or charge, not both if devices: def _get_battery_status(pl): energy = 0.0 energy_full = 0.0 state = True for device, unit in devices: with open(linux_energy_full_fmt.format(device, unit), 'r') as f: energy_full += int(float(f.readline().split()[0])) with open(linux_energy_fmt.format(device, unit), 'r') as f: energy += int(float(f.readline().split()[0])) try: with open(linux_status_fmt.format(device), 'r') as f: state &= (f.readline().strip() != 'Discharging') except IOError: state = None return (energy * 100.0 / energy_full), state return _get_battery_status pl.debug('Not using /sys/class/power_supply as no batteries were found') else: pl.debug("Checking for first capacity battery percentage") for batt in os.listdir('/sys/class/power_supply'): if os.path.exists('/sys/class/power_supply/{0}/capacity'.format(batt)): def _get_battery_perc(pl): state = True with open('/sys/class/power_supply/{0}/capacity'.format(batt), 'r') as f: perc = int(f.readline().split()[0]) try: with open(linux_status_fmt.format(batt), 'r') as f: state &= (f.readline().strip() != 'Discharging') except IOError: state = None return perc, state return _get_battery_perc else: pl.debug('Not using /sys/class/power_supply: no directory') try: from shutil import which # Python-3.3 and later except ImportError: pl.info('Using dumb “which” which only checks for file in /usr/bin') which = lambda f: (lambda fp: os.path.exists(fp) and fp)(os.path.join('/usr/bin', f)) if which('pmset'): pl.debug('Using pmset') BATTERY_PERCENT_RE = re.compile(r'(\d+)%') def _get_battery_status(pl): battery_summary = run_cmd(pl, ['pmset', '-g', 'batt']) battery_percent = BATTERY_PERCENT_RE.search(battery_summary).group(1) ac_charging = 'AC' in battery_summary return int(battery_percent), ac_charging return _get_battery_status else: pl.debug('Not using pmset: executable not found') if sys.platform.startswith('win') or sys.platform == 'cygwin': # From http://stackoverflow.com/a/21083571/273566, reworked try: from win32com.client import GetObject except ImportError: pl.debug('Not using win32com.client as it is not available') else: try: wmi = GetObject('winmgmts:') except Exception as e: pl.exception('Failed to run GetObject from win32com.client: {0}', str(e)) else: for battery in wmi.InstancesOf('Win32_Battery'): pl.debug('Using win32com.client with Win32_Battery') def _get_battery_status(pl): # http://msdn.microsoft.com/en-us/library/aa394074(v=vs.85).aspx return battery.EstimatedChargeRemaining, battery.BatteryStatus == 6 return _get_battery_status pl.debug('Not using win32com.client as no batteries were found') from ctypes import Structure, c_byte, c_ulong, byref if sys.platform == 'cygwin': pl.debug('Using cdll to communicate with kernel32 (Cygwin)') from ctypes import cdll library_loader = cdll else: pl.debug('Using windll to communicate with kernel32 (Windows)') from ctypes import windll library_loader = windll class PowerClass(Structure): _fields_ = [ ('ACLineStatus', c_byte), ('BatteryFlag', c_byte), ('BatteryLifePercent', c_byte), ('Reserved1', c_byte), ('BatteryLifeTime', c_ulong), ('BatteryFullLifeTime', c_ulong) ] def _get_battery_status(pl): powerclass = PowerClass() result = library_loader.kernel32.GetSystemPowerStatus(byref(powerclass)) # http://msdn.microsoft.com/en-us/library/windows/desktop/aa372693(v=vs.85).aspx if result: return None return powerclass.BatteryLifePercent, powerclass.ACLineStatus == 1 if _get_battery_status() is None: pl.debug('Not using GetSystemPowerStatus because it failed') else: pl.debug('Using GetSystemPowerStatus') return _get_battery_status raise NotImplementedError def _get_battery_status(pl): global _get_battery_status def _failing_get_status(pl): raise NotImplementedError try: _get_battery_status = _fetch_battery_info(pl) except NotImplementedError: _get_battery_status = _failing_get_status except Exception as e: pl.exception('Exception while obtaining battery status: {0}', str(e)) _get_battery_status = _failing_get_status return _get_battery_status(pl) def battery(pl, format='{ac_state} {capacity:3.0%}', steps=5, gamify=False, full_heart='O', empty_heart='O', online='C', offline=' '): '''Return battery charge status. :param str format: Percent format in case gamify is False. Format arguments: ``ac_state`` which is equal to either ``online`` or ``offline`` string arguments and ``capacity`` which is equal to current battery capacity in interval [0, 100]. :param int steps: Number of discrete steps to show between 0% and 100% capacity if gamify is True. :param bool gamify: Measure in hearts (♥) instead of percentages. For full hearts ``battery_full`` highlighting group is preferred, for empty hearts there is ``battery_empty``. ``battery_online`` or ``battery_offline`` group will be used for leading segment containing ``online`` or ``offline`` argument contents. :param str full_heart: Heart displayed for “full” part of battery. :param str empty_heart: Heart displayed for “used” part of battery. It is also displayed using another gradient level and highlighting group, so it is OK for it to be the same as full_heart as long as necessary highlighting groups are defined. :param str online: Symbol used if computer is connected to a power supply. :param str offline: Symbol used if computer is not connected to a power supply. ``battery_gradient`` and ``battery`` groups are used in any case, first is preferred. Highlight groups used: ``battery_full`` or ``battery_gradient`` (gradient) or ``battery``, ``battery_empty`` or ``battery_gradient`` (gradient) or ``battery``, ``battery_online`` or ``battery_ac_state`` or ``battery_gradient`` (gradient) or ``battery``, ``battery_offline`` or ``battery_ac_state`` or ``battery_gradient`` (gradient) or ``battery``. ''' try: capacity, ac_powered = _get_battery_status(pl) except NotImplementedError: pl.info('Unable to get battery status.') return None ret = [] if gamify: denom = int(steps) numer = int(denom * capacity / 100) ret.append({ 'contents': online if ac_powered else offline, 'draw_inner_divider': False, 'highlight_groups': ['battery_online' if ac_powered else 'battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'], 'gradient_level': 0, }) ret.append({ 'contents': full_heart * numer, 'draw_inner_divider': False, 'highlight_groups': ['battery_full', 'battery_gradient', 'battery'], # Using zero as “nothing to worry about”: it is least alert color. 'gradient_level': 0, }) ret.append({ 'contents': empty_heart * (denom - numer), 'draw_inner_divider': False, 'highlight_groups': ['battery_empty', 'battery_gradient', 'battery'], # Using a hundred as it is most alert color. 'gradient_level': 100, }) else: ret.append({ 'contents': format.format(ac_state=(online if ac_powered else offline), capacity=(capacity / 100.0)), 'highlight_groups': ['battery_gradient', 'battery'], # Gradients are “least alert – most alert” by default, capacity has # the opposite semantics. 'gradient_level': 100 - capacity, }) return ret powerline-2.8.4/powerline/segments/common/env.py000066400000000000000000000136221466405252600220320ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from powerline.lib.unicode import out_u from powerline.theme import requires_segment_info from powerline.segments import Segment, with_docstring @requires_segment_info def environment(pl, segment_info, variable=None): '''Return the value of any defined environment variable :param string variable: The environment variable to return if found ''' return segment_info['environ'].get(variable, None) @requires_segment_info def virtualenv(pl, segment_info, ignore_venv=False, ignore_conda=False, ignored_names=("venv", ".venv")): '''Return the name of the current Python or conda virtualenv. :param list ignored_names: Names of venvs to ignore. Will then get the name of the venv by ascending to the parent directory :param bool ignore_venv: Whether to ignore virtual environments. Default is False. :param bool ignore_conda: Whether to ignore conda environments. Default is False. ''' if not ignore_venv: for candidate in reversed(segment_info['environ'].get('VIRTUAL_ENV', '').split("/")): if candidate and candidate not in ignored_names: return candidate if not ignore_conda: for candidate in reversed(segment_info['environ'].get('CONDA_DEFAULT_ENV', '').split("/")): if candidate and candidate not in ignored_names: return candidate return None @requires_segment_info class CwdSegment(Segment): def argspecobjs(self): for obj in super(CwdSegment, self).argspecobjs(): yield obj yield 'get_shortened_path', self.get_shortened_path def omitted_args(self, name, method): if method is self.get_shortened_path: return () else: return super(CwdSegment, self).omitted_args(name, method) def get_shortened_path(self, pl, segment_info, shorten_home=True, **kwargs): try: path = out_u(segment_info['getcwd']()) except OSError as e: if e.errno == 2: # user most probably deleted the directory # this happens when removing files from Mercurial repos for example pl.warn('Current directory not found') return '[not found]' else: raise if shorten_home: home = segment_info['home'] if home: home = out_u(home) if path.startswith(home): path = '~' + path[len(home):] return path def __call__(self, pl, segment_info, dir_shorten_len=None, dir_limit_depth=None, use_path_separator=False, ellipsis='...', **kwargs): cwd = self.get_shortened_path(pl, segment_info, **kwargs) cwd_split = cwd.split(os.sep) cwd_split_len = len(cwd_split) cwd = [i[0:dir_shorten_len] if dir_shorten_len and i else i for i in cwd_split[:-1]] + [cwd_split[-1]] if dir_limit_depth and cwd_split_len > dir_limit_depth + 1: del(cwd[0:-dir_limit_depth]) if ellipsis is not None: cwd.insert(0, ellipsis) ret = [] if not cwd[0]: cwd[0] = '/' draw_inner_divider = not use_path_separator for part in cwd: if not part: continue if use_path_separator: part += os.sep ret.append({ 'contents': part, 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': draw_inner_divider, }) ret[-1]['highlight_groups'] = ['cwd:current_folder', 'cwd'] if use_path_separator: ret[-1]['contents'] = ret[-1]['contents'][:-1] if len(ret) > 1 and ret[0]['contents'][0] == os.sep: ret[0]['contents'] = ret[0]['contents'][1:] return ret cwd = with_docstring(CwdSegment(), '''Return the current working directory. Returns a segment list to create a breadcrumb-like effect. :param int dir_shorten_len: shorten parent directory names to this length (e.g. :file:`/long/path/to/powerline` → :file:`/l/p/t/powerline`) :param int dir_limit_depth: limit directory depth to this number (e.g. :file:`/long/path/to/powerline` → :file:`⋯/to/powerline`) :param bool use_path_separator: Use path separator in place of soft divider. :param bool shorten_home: Shorten home directory to ``~``. :param str ellipsis: Specifies what to use in place of omitted directories. Use None to not show this subsegment at all. Divider highlight group used: ``cwd:divider``. Highlight groups used: ``cwd:current_folder`` or ``cwd``. It is recommended to define all highlight groups. ''') try: import psutil # psutil-2.0.0: psutil.Process.username is unbound method if callable(psutil.Process.username): def _get_user(): return psutil.Process(os.getpid()).username() # pre psutil-2.0.0: psutil.Process.username has type property else: def _get_user(): return psutil.Process(os.getpid()).username except ImportError: try: import pwd except ImportError: from getpass import getuser as _get_user else: try: from os import geteuid as getuid except ImportError: from os import getuid def _get_user(): return pwd.getpwuid(getuid()).pw_name username = False # os.geteuid is not available on windows _geteuid = getattr(os, 'geteuid', lambda: 1) @requires_segment_info def user(pl, segment_info, hide_user=None, hide_domain=False): '''Return the current user. :param str hide_user: Omit showing segment for users with names equal to this string. :param bool hide_domain: Drop domain component if it exists in a username (delimited by '@'). Highlights the user with the ``superuser`` if the effective user ID is 0. Highlight groups used: ``superuser`` or ``user``. It is recommended to define all highlight groups. ''' global username if ( segment_info['environ'].get('_POWERLINE_RUNNING_SHELL_TESTS') == 'ee5bcdc6-b749-11e7-9456-50465d597777' ): return 'user' if username is False: username = _get_user() if username is None: pl.warn('Failed to get username') return None if username == hide_user: return None if hide_domain: try: username = username[:username.index('@')] except ValueError: pass euid = _geteuid() return [{ 'contents': username, 'highlight_groups': ['user'] if euid != 0 else ['superuser', 'user'], }] powerline-2.8.4/powerline/segments/common/mail.py000066400000000000000000000062431466405252600221650ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import re from imaplib import IMAP4_SSL_PORT, IMAP4_SSL, IMAP4 from collections import namedtuple from powerline.lib.threaded import KwThreadedSegment from powerline.segments import with_docstring _IMAPKey = namedtuple('Key', 'username password server port folder use_ssl') class EmailIMAPSegment(KwThreadedSegment): interval = 60 @staticmethod def key(username='', password='', server='imap.gmail.com', port=IMAP4_SSL_PORT, username_variable='', password_variable='', server_variable='', port_variable='', folder='INBOX', use_ssl=None, **kwargs): if use_ssl is None: use_ssl = (port == IMAP4_SSL_PORT) # catch if user set custom mail credential env variables if username_variable: username = os.environ[username_variable] if password_variable: password = os.environ[password_variable] if server_variable: server = os.environ[server_variable] if port_variable: port = os.environ[port_variable] return _IMAPKey(username, password, server, port, folder, use_ssl) def compute_state(self, key): if not key.username or not key.password: self.warn('Username and password are not configured') return None if key.use_ssl: mail = IMAP4_SSL(key.server, key.port) else: mail = IMAP4(key.server, key.port) mail.login(key.username, key.password) rc, message = mail.status(key.folder, '(UNSEEN)') unread_str = message[0].decode('utf-8') unread_count = int(re.search(r'UNSEEN (\d+)', unread_str).group(1)) return unread_count @staticmethod def render_one(unread_count, max_msgs=None, **kwargs): if not unread_count: return None elif type(unread_count) != int or not max_msgs: return [{ 'contents': str(unread_count), 'highlight_groups': ['email_alert'], }] else: return [{ 'contents': str(unread_count), 'highlight_groups': ['email_alert_gradient', 'email_alert'], 'gradient_level': min(unread_count * 100.0 / max_msgs, 100), }] email_imap_alert = with_docstring(EmailIMAPSegment(), ('''Return unread e-mail count for IMAP servers. :param str username: login username :param str password: login password :param str server: e-mail server :param int port: e-mail server port :param str username_variable: name of environment variable to check for login username :param str password_variable: name of environment variable to check for login password :param str server_variable: name of environment variable to check for email server :param str port_variable: name of environment variable to check for email server port :param str folder: folder to check for e-mails :param int max_msgs: Maximum number of messages. If there are more messages then max_msgs then it will use gradient level equal to 100, otherwise gradient level is equal to ``100 * msgs_num / max_msgs``. If not present gradient is not computed. :param bool use_ssl: If ``True`` then use SSL connection. If ``False`` then do not use it. Default is ``True`` if port is equal to {ssl_port} and ``False`` otherwise. Highlight groups used: ``email_alert_gradient`` (gradient), ``email_alert``. ''').format(ssl_port=IMAP4_SSL_PORT)) powerline-2.8.4/powerline/segments/common/net.py000066400000000000000000000232101466405252600220220ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import re import os import socket from powerline.lib.url import urllib_read from powerline.lib.threaded import ThreadedSegment, KwThreadedSegment from powerline.lib.monotonic import monotonic from powerline.lib.humanize_bytes import humanize_bytes from powerline.segments import with_docstring from powerline.theme import requires_segment_info @requires_segment_info def hostname(pl, segment_info, only_if_ssh=False, exclude_domain=False): '''Return the current hostname. :param bool only_if_ssh: only return the hostname if currently in an SSH session :param bool exclude_domain: return the hostname without domain if there is one ''' if ( segment_info['environ'].get('_POWERLINE_RUNNING_SHELL_TESTS') == 'ee5bcdc6-b749-11e7-9456-50465d597777' ): return 'hostname' if only_if_ssh and not segment_info['environ'].get('SSH_CLIENT'): return None if exclude_domain: return socket.gethostname().split('.')[0] return socket.gethostname() def _external_ip(query_url='http://ipv4.icanhazip.com/'): return urllib_read(query_url).strip() class ExternalIpSegment(ThreadedSegment): interval = 300 def set_state(self, query_url='http://ipv4.icanhazip.com/', **kwargs): self.query_url = query_url super(ExternalIpSegment, self).set_state(**kwargs) def update(self, old_ip): return _external_ip(query_url=self.query_url) def render(self, ip, **kwargs): if not ip: return None return [{'contents': ip, 'divider_highlight_group': 'background:divider'}] external_ip = with_docstring(ExternalIpSegment(), '''Return external IP address. :param str query_url: URI to query for IP address, should return only the IP address as a text string Suggested URIs: * http://ipv4.icanhazip.com/ * http://ipv6.icanhazip.com/ * http://icanhazip.com/ (returns IPv6 address if available, else IPv4) Divider highlight group used: ``background:divider``. ''') try: import netifaces except ImportError: def internal_ip(pl, interface='auto', ipv=4): return None else: _interface_starts = { 'eth': 10, # Regular ethernet adapters : eth1 'enp': 10, # Regular ethernet adapters, Gentoo : enp2s0 'en': 10, # OS X : en0 'ath': 9, # Atheros WiFi adapters : ath0 'wlan': 9, # Other WiFi adapters : wlan1 'wlp': 9, # Other WiFi adapters, Gentoo : wlp5s0 'teredo': 1, # miredo interface : teredo 'lo': -10, # Loopback interface : lo 'docker': -5, # Docker bridge interface : docker0 'vmnet': -5, # VMWare bridge interface : vmnet1 'vboxnet': -5, # VirtualBox bridge interface : vboxnet0 } _interface_start_re = re.compile(r'^([a-z]+?)(\d|$)') def _interface_key(interface): match = _interface_start_re.match(interface) if match: try: base = _interface_starts[match.group(1)] * 100 except KeyError: base = 500 if match.group(2): return base - int(match.group(2)) else: return base else: return 0 def internal_ip(pl, interface='auto', ipv=4): family = netifaces.AF_INET6 if ipv == 6 else netifaces.AF_INET if interface == 'auto': try: interface = next(iter(sorted(netifaces.interfaces(), key=_interface_key, reverse=True))) except StopIteration: pl.info('No network interfaces found') return None elif interface == 'default_gateway': try: interface = netifaces.gateways()['default'][family][1] except KeyError: pl.info('No default gateway found for IPv{0}', ipv) return None addrs = netifaces.ifaddresses(interface) try: return addrs[family][0]['addr'] except (KeyError, IndexError): pl.info("No IPv{0} address found for interface {1}", ipv, interface) return None internal_ip = with_docstring(internal_ip, '''Return internal IP address Requires ``netifaces`` module to work properly. :param str interface: Interface on which IP will be checked. Use ``auto`` to automatically detect interface. In this case interfaces with lower numbers will be preferred over interfaces with similar names. Order of preference based on names: #. ``eth`` and ``enp`` followed by number or the end of string. #. ``ath``, ``wlan`` and ``wlp`` followed by number or the end of string. #. ``teredo`` followed by number or the end of string. #. Any other interface that is not ``lo*``. #. ``lo`` followed by number or the end of string. Use ``default_gateway`` to detect the interface based on the machine's `default gateway `_ (i.e., the router to which it is connected). :param int ipv: 4 or 6 for ipv4 and ipv6 respectively, depending on which IP address you need exactly. ''') try: import psutil def _get_bytes(interface): try: io_counters = psutil.net_io_counters(pernic=True) except AttributeError: io_counters = psutil.network_io_counters(pernic=True) if_io = io_counters.get(interface) if not if_io: return None return if_io.bytes_recv, if_io.bytes_sent def _get_interfaces(): try: io_counters = psutil.net_io_counters(pernic=True) except AttributeError: io_counters = psutil.network_io_counters(pernic=True) for interface, data in io_counters.items(): if data: yield interface, data.bytes_recv, data.bytes_sent except ImportError: def _get_bytes(interface): with open('/sys/class/net/{interface}/statistics/rx_bytes'.format(interface=interface), 'rb') as file_obj: rx = int(file_obj.read()) with open('/sys/class/net/{interface}/statistics/tx_bytes'.format(interface=interface), 'rb') as file_obj: tx = int(file_obj.read()) return (rx, tx) def _get_interfaces(): for interface in os.listdir('/sys/class/net'): x = _get_bytes(interface) if x is not None: yield interface, x[0], x[1] class NetworkLoadSegment(KwThreadedSegment): interfaces = {} replace_num_pat = re.compile(r'[a-zA-Z]+') @staticmethod def key(interface='auto', **kwargs): return interface def compute_state(self, interface): if interface == 'auto': proc_exists = getattr(self, 'proc_exists', None) if proc_exists is None: proc_exists = self.proc_exists = os.path.exists('/proc/net/route') if proc_exists: # Look for default interface in routing table with open('/proc/net/route', 'rb') as f: for line in f.readlines(): parts = line.split() if len(parts) > 1: iface, destination = parts[:2] if not destination.replace(b'0', b''): interface = iface.decode('utf-8') break if interface == 'auto': # Choose interface with most total activity, excluding some # well known interface names interface, total = 'eth0', -1 for name, rx, tx in _get_interfaces(): base = self.replace_num_pat.match(name) if None in (base, rx, tx) or base.group() in ('lo', 'vmnet', 'sit'): continue activity = rx + tx if activity > total: total = activity interface = name try: idata = self.interfaces[interface] try: idata['prev'] = idata['last'] except KeyError: pass except KeyError: idata = {} if self.run_once: idata['prev'] = (monotonic(), _get_bytes(interface)) self.shutdown_event.wait(self.interval) self.interfaces[interface] = idata idata['last'] = (monotonic(), _get_bytes(interface)) return idata.copy() def render_one(self, idata, recv_format='DL {value:>8}', sent_format='UL {value:>8}', suffix='B/s', si_prefix=False, **kwargs): if not idata or 'prev' not in idata: return None t1, b1 = idata['prev'] t2, b2 = idata['last'] measure_interval = t2 - t1 if None in (b1, b2): return None r = [] for i, key in zip((0, 1), ('recv', 'sent')): format = locals()[key + '_format'] try: value = (b2[i] - b1[i]) / measure_interval except ZeroDivisionError: self.warn('Measure interval zero.') value = 0 max_key = key + '_max' is_gradient = max_key in kwargs hl_groups = ['network_load_' + key, 'network_load'] if is_gradient: hl_groups[:0] = (group + '_gradient' for group in hl_groups) r.append({ 'contents': format.format(value=humanize_bytes(value, suffix, si_prefix)), 'divider_highlight_group': 'network_load:divider', 'highlight_groups': hl_groups, }) if is_gradient: max = kwargs[max_key] if value >= max: r[-1]['gradient_level'] = 100 else: r[-1]['gradient_level'] = value * 100.0 / max return r network_load = with_docstring(NetworkLoadSegment(), '''Return the network load. Uses the ``psutil`` module if available for multi-platform compatibility, falls back to reading :file:`/sys/class/net/{interface}/statistics/{rx,tx}_bytes`. :param str interface: Network interface to measure (use the special value "auto" to have powerline try to auto-detect the network interface). :param str suffix: String appended to each load string. :param bool si_prefix: Use SI prefix, e.g. MB instead of MiB. :param str recv_format: Format string that determines how download speed should look like. Receives ``value`` as argument. :param str sent_format: Format string that determines how upload speed should look like. Receives ``value`` as argument. :param float recv_max: Maximum number of received bytes per second. Is only used to compute gradient level. :param float sent_max: Maximum number of sent bytes per second. Is only used to compute gradient level. Divider highlight group used: ``network_load:divider``. Highlight groups used: ``network_load_sent_gradient`` (gradient) or ``network_load_recv_gradient`` (gradient) or ``network_load_gradient`` (gradient), ``network_load_sent`` or ``network_load_recv`` or ``network_load``. ''') powerline-2.8.4/powerline/segments/common/players.py000066400000000000000000000436771466405252600227360ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import re from powerline.lib.shell import asrun, run_cmd from powerline.lib.unicode import out_u from powerline.segments import Segment, with_docstring STATE_SYMBOLS = { 'fallback': '', 'play': '>', 'pause': '~', 'stop': 'X', } def _convert_state(state): '''Guess player state''' state = state.lower() if 'play' in state: return 'play' if 'pause' in state: return 'pause' if 'stop' in state: return 'stop' return 'fallback' def _convert_seconds(seconds): '''Convert seconds to minutes:seconds format''' if isinstance(seconds, str): seconds = seconds.replace(",",".") return '{0:.0f}:{1:02.0f}'.format(*divmod(float(seconds), 60)) class PlayerSegment(Segment): def __call__(self, format='{state_symbol} {artist} - {title} ({total})', state_symbols=STATE_SYMBOLS, **kwargs): stats = { 'state': 'fallback', 'album': None, 'artist': None, 'title': None, 'elapsed': None, 'total': None, } func_stats = self.get_player_status(**kwargs) if not func_stats: return None stats.update(func_stats) stats['state_symbol'] = state_symbols.get(stats['state']) return [{ 'contents': format.format(**stats), 'highlight_groups': ['player_' + (stats['state'] or 'fallback'), 'player'], }] def get_player_status(self, pl): pass def argspecobjs(self): for ret in super(PlayerSegment, self).argspecobjs(): yield ret yield 'get_player_status', self.get_player_status def omitted_args(self, name, method): return () _common_args = ''' This player segment should be added like this: .. code-block:: json {{ "function": "powerline.segments.common.players.{0}", "name": "player" }} (with additional ``"args": {{…}}`` if needed). Highlight groups used: ``player_fallback`` or ``player``, ``player_play`` or ``player``, ``player_pause`` or ``player``, ``player_stop`` or ``player``. :param str format: Format used for displaying data from player. Should be a str.format-like string with the following keyword parameters: +------------+-------------------------------------------------------------+ |Parameter |Description | +============+=============================================================+ |state_symbol|Symbol displayed for play/pause/stop states. There is also | | |“fallback” state used in case function failed to get player | | |state. For this state symbol is by default empty. All | | |symbols are defined in ``state_symbols`` argument. | +------------+-------------------------------------------------------------+ |album |Album that is currently played. | +------------+-------------------------------------------------------------+ |artist |Artist whose song is currently played | +------------+-------------------------------------------------------------+ |title |Currently played composition. | +------------+-------------------------------------------------------------+ |elapsed |Composition duration in format M:SS (minutes:seconds). | +------------+-------------------------------------------------------------+ |total |Composition length in format M:SS. | +------------+-------------------------------------------------------------+ :param dict state_symbols: Symbols used for displaying state. Must contain all of the following keys: ======== ======================================================== Key Description ======== ======================================================== play Displayed when player is playing. pause Displayed when player is paused. stop Displayed when player is not playing anything. fallback Displayed if state is not one of the above or not known. ======== ======================================================== ''' _player = with_docstring(PlayerSegment(), _common_args.format('_player')) class CmusPlayerSegment(PlayerSegment): def get_player_status(self, pl): '''Return cmus player information. cmus-remote -Q returns data with multi-level information i.e. status playing file tag artist tag title tag .. tag n set continue set repeat set .. set n For the information we are looking for we don’t really care if we’re on the tag level or the set level. The dictionary comprehension in this method takes anything in ignore_levels and brings the key inside that to the first level of the dictionary. ''' now_playing_str = run_cmd(pl, ['cmus-remote', '-Q']) if not now_playing_str: return ignore_levels = ('tag', 'set',) now_playing = dict(((token[0] if token[0] not in ignore_levels else token[1], (' '.join(token[1:]) if token[0] not in ignore_levels else ' '.join(token[2:]))) for token in [line.split(' ') for line in now_playing_str.split('\n')[:-1]])) state = _convert_state(now_playing.get('status')) return { 'state': state, 'album': now_playing.get('album'), 'artist': now_playing.get('artist'), 'title': now_playing.get('title'), 'elapsed': _convert_seconds(now_playing.get('position', 0)), 'total': _convert_seconds(now_playing.get('duration', 0)), } cmus = with_docstring(CmusPlayerSegment(), ('''Return CMUS player information Requires cmus-remote command be accessible from $PATH. {0} ''').format(_common_args.format('cmus'))) class MpdPlayerSegment(PlayerSegment): def get_player_status(self, pl, host='localhost', password=None, port=6600): try: import mpd except ImportError: if password: host = password + '@' + host now_playing = run_cmd(pl, [ 'mpc', '-h', host, '-p', str(port) ], strip=False) album = run_cmd(pl, [ 'mpc', 'current', '-f', '%album%', '-h', host, '-p', str(port) ]) if not now_playing or now_playing.count("\n") != 3: return now_playing = re.match( r"(.*) - (.*)\n\[([a-z]+)\] +[#0-9\/]+ +([0-9\:]+)\/([0-9\:]+)", now_playing ) return { 'state': _convert_state(now_playing[3]), 'album': album, 'artist': now_playing[1], 'title': now_playing[2], 'elapsed': now_playing[4], 'total': now_playing[5] } else: try: client = mpd.MPDClient(use_unicode=True) except TypeError: # python-mpd 1.x does not support use_unicode client = mpd.MPDClient() client.connect(host, port) if password: client.password(password) now_playing = client.currentsong() if not now_playing: return status = client.status() client.close() client.disconnect() return { 'state': status.get('state'), 'album': now_playing.get('album'), 'artist': now_playing.get('artist'), 'title': now_playing.get('title'), 'elapsed': _convert_seconds(status.get('elapsed', 0)), 'total': _convert_seconds(now_playing.get('time', 0)), } mpd = with_docstring(MpdPlayerSegment(), ('''Return Music Player Daemon information Requires ``mpd`` Python module (e.g. |python-mpd2|_ or |python-mpd|_ Python package) or alternatively the ``mpc`` command to be accessible from $PATH. .. |python-mpd| replace:: ``python-mpd`` .. _python-mpd: https://pypi.python.org/pypi/python-mpd .. |python-mpd2| replace:: ``python-mpd2`` .. _python-mpd2: https://pypi.python.org/pypi/python-mpd2 {0} :param str host: Host on which mpd runs. :param str password: Password used for connecting to daemon. :param int port: Port which should be connected to. ''').format(_common_args.format('mpd'))) try: import dbus except ImportError: def _get_dbus_player_status(pl, player_name, **kwargs): pl.error('Could not add {0} segment: requires dbus module', player_name) return else: def _get_dbus_player_status(pl, bus_name=None, iface_prop='org.freedesktop.DBus.Properties', iface_player='org.mpris.MediaPlayer2.Player', player_path='/org/mpris/MediaPlayer2', player_name='player'): bus = dbus.SessionBus() if bus_name is None: for service in bus.list_names(): if re.match('org.mpris.MediaPlayer2.', service): bus_name = service break try: player = bus.get_object(bus_name, player_path) iface = dbus.Interface(player, iface_prop) info = iface.Get(iface_player, 'Metadata') status = iface.Get(iface_player, 'PlaybackStatus') except dbus.exceptions.DBusException: return if not info: return try: elapsed = iface.Get(iface_player, 'Position') except dbus.exceptions.DBusException: pl.warning('Missing player elapsed time') elapsed = None else: elapsed = _convert_seconds(elapsed / 1e6) album = info.get('xesam:album') title = info.get('xesam:title') artist = info.get('xesam:artist') state = _convert_state(status) if album: album = out_u(album) if title: title = out_u(title) if artist: artist = out_u(artist[0]) length = info.get('mpris:length') # avoid parsing `None` length values, that would # raise an error otherwise parsed_length = length and _convert_seconds(length / 1e6) return { 'state': state, 'album': album, 'artist': artist, 'title': title, 'elapsed': elapsed, 'total': parsed_length, } class DbusPlayerSegment(PlayerSegment): get_player_status = staticmethod(_get_dbus_player_status) dbus_player = with_docstring(DbusPlayerSegment(), ('''Return generic dbus player state Requires ``dbus`` python module. Only for players that support specific protocol (e.g. like :py:func:`spotify` and :py:func:`clementine`). {0} :param str player_name: Player name. Used in error messages only. :param str bus_name: Dbus bus name. :param str player_path: Path to the player on the given bus. :param str iface_prop: Interface properties name for use with dbus.Interface. :param str iface_player: Player name. ''').format(_common_args.format('dbus_player'))) class SpotifyDbusPlayerSegment(PlayerSegment): def get_player_status(self, pl): player_status = _get_dbus_player_status( pl=pl, player_name='Spotify', bus_name='org.mpris.MediaPlayer2.spotify', player_path='/org/mpris/MediaPlayer2', iface_prop='org.freedesktop.DBus.Properties', iface_player='org.mpris.MediaPlayer2.Player', ) if player_status is not None: return player_status # Fallback for legacy spotify client with different DBus protocol return _get_dbus_player_status( pl=pl, player_name='Spotify', bus_name='com.spotify.qt', player_path='/', iface_prop='org.freedesktop.DBus.Properties', iface_player='org.freedesktop.MediaPlayer2', ) spotify_dbus = with_docstring(SpotifyDbusPlayerSegment(), ('''Return spotify player information Requires ``dbus`` python module. {0} ''').format(_common_args.format('spotify_dbus'))) class SpotifyAppleScriptPlayerSegment(PlayerSegment): def get_player_status(self, pl): status_delimiter = '-~`/=' ascript = ''' tell application "System Events" set process_list to (name of every process) end tell if process_list contains "Spotify" then tell application "Spotify" if player state is playing or player state is paused then set track_name to name of current track set artist_name to artist of current track set album_name to album of current track set track_length to duration of current track set now_playing to "" & player state & "{0}" & album_name & "{0}" & artist_name & "{0}" & track_name & "{0}" & track_length & "{0}" & player position return now_playing else return player state end if end tell else return "stopped" end if '''.format(status_delimiter) spotify = asrun(pl, ascript) if not asrun: return None spotify_status = spotify.split(status_delimiter) state = _convert_state(spotify_status[0]) if state == 'stop': return None return { 'state': state, 'album': spotify_status[1], 'artist': spotify_status[2], 'title': spotify_status[3], 'total': _convert_seconds(int(spotify_status[4])/1000), 'elapsed': _convert_seconds(spotify_status[5]), } spotify_apple_script = with_docstring(SpotifyAppleScriptPlayerSegment(), ('''Return spotify player information Requires ``osascript`` available in $PATH. {0} ''').format(_common_args.format('spotify_apple_script'))) if not sys.platform.startswith('darwin'): spotify = spotify_dbus _old_name = 'spotify_dbus' else: spotify = spotify_apple_script _old_name = 'spotify_apple_script' spotify = with_docstring(spotify, spotify.__doc__.replace(_old_name, 'spotify')) class ClementinePlayerSegment(PlayerSegment): def get_player_status(self, pl): return _get_dbus_player_status( pl=pl, player_name='Clementine', bus_name='org.mpris.MediaPlayer2.clementine', player_path='/org/mpris/MediaPlayer2', iface_prop='org.freedesktop.DBus.Properties', iface_player='org.mpris.MediaPlayer2.Player', ) clementine = with_docstring(ClementinePlayerSegment(), ('''Return clementine player information Requires ``dbus`` python module. {0} ''').format(_common_args.format('clementine'))) class RhythmboxPlayerSegment(PlayerSegment): def get_player_status(self, pl): now_playing = run_cmd(pl, [ 'rhythmbox-client', '--no-start', '--no-present', '--print-playing-format', '%at\n%aa\n%tt\n%te\n%td' ], strip=False) if not now_playing: return now_playing = now_playing.split('\n') return { 'album': now_playing[0], 'artist': now_playing[1], 'title': now_playing[2], 'elapsed': now_playing[3], 'total': now_playing[4], } rhythmbox = with_docstring(RhythmboxPlayerSegment(), ('''Return rhythmbox player information Requires ``rhythmbox-client`` available in $PATH. {0} ''').format(_common_args.format('rhythmbox'))) class RDIOPlayerSegment(PlayerSegment): def get_player_status(self, pl): status_delimiter = '-~`/=' ascript = ''' tell application "System Events" set rdio_active to the count(every process whose name is "Rdio") if rdio_active is 0 then return end if end tell tell application "Rdio" set rdio_name to the name of the current track set rdio_artist to the artist of the current track set rdio_album to the album of the current track set rdio_duration to the duration of the current track set rdio_state to the player state set rdio_elapsed to the player position return rdio_name & "{0}" & rdio_artist & "{0}" & rdio_album & "{0}" & rdio_elapsed & "{0}" & rdio_duration & "{0}" & rdio_state end tell '''.format(status_delimiter) now_playing = asrun(pl, ascript) if not now_playing: return now_playing = now_playing.split(status_delimiter) if len(now_playing) != 6: return state = _convert_state(now_playing[5]) total = _convert_seconds(now_playing[4]) elapsed = _convert_seconds(float(now_playing[3]) * float(now_playing[4]) / 100) return { 'title': now_playing[0], 'artist': now_playing[1], 'album': now_playing[2], 'elapsed': elapsed, 'total': total, 'state': state, } rdio = with_docstring(RDIOPlayerSegment(), ('''Return rdio player information Requires ``osascript`` available in $PATH. {0} ''').format(_common_args.format('rdio'))) class ITunesPlayerSegment(PlayerSegment): def get_player_status(self, pl): status_delimiter = '-~`/=' ascript = ''' tell application "System Events" set process_list to (name of every process) end tell if process_list contains "iTunes" then tell application "iTunes" if player state is playing then set t_title to name of current track set t_artist to artist of current track set t_album to album of current track set t_duration to duration of current track set t_elapsed to player position set t_state to player state return t_title & "{0}" & t_artist & "{0}" & t_album & "{0}" & t_elapsed & "{0}" & t_duration & "{0}" & t_state end if end tell end if '''.format(status_delimiter) now_playing = asrun(pl, ascript) if not now_playing: return now_playing = now_playing.split(status_delimiter) if len(now_playing) != 6: return title, artist, album = now_playing[0], now_playing[1], now_playing[2] state = _convert_state(now_playing[5]) total = _convert_seconds(now_playing[4]) elapsed = _convert_seconds(now_playing[3]) return { 'title': title, 'artist': artist, 'album': album, 'total': total, 'elapsed': elapsed, 'state': state } itunes = with_docstring(ITunesPlayerSegment(), ('''Return iTunes now playing information Requires ``osascript``. {0} ''').format(_common_args.format('itunes'))) class MocPlayerSegment(PlayerSegment): def get_player_status(self, pl): '''Return Music On Console (mocp) player information. ``mocp -i`` returns current information i.e. .. code-block:: File: filename.format Title: full title Artist: artist name SongTitle: song title Album: album name TotalTime: 00:00 TimeLeft: 00:00 TotalSec: 000 CurrentTime: 00:00 CurrentSec: 000 Bitrate: 000kbps AvgBitrate: 000kbps Rate: 00kHz For the information we are looking for we don’t really care if we have extra-timing information or bit rate level. The dictionary comprehension in this method takes anything in ignore_info and brings the key inside that to the right info of the dictionary. ''' now_playing_str = run_cmd(pl, ['mocp', '-i']) if not now_playing_str: return now_playing = dict(( line.split(': ', 1) for line in now_playing_str.split('\n')[:-1] )) state = _convert_state(now_playing.get('State', 'stop')) return { 'state': state, 'album': now_playing.get('Album', ''), 'artist': now_playing.get('Artist', ''), 'title': now_playing.get('SongTitle', ''), 'elapsed': _convert_seconds(now_playing.get('CurrentSec', 0)), 'total': _convert_seconds(now_playing.get('TotalSec', 0)), } mocp = with_docstring(MocPlayerSegment(), ('''Return MOC (Music On Console) player information Requires version >= 2.3.0 and ``mocp`` executable in ``$PATH``. {0} ''').format(_common_args.format('mocp'))) powerline-2.8.4/powerline/segments/common/sys.py000066400000000000000000000131351466405252600220570ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from multiprocessing import cpu_count as _cpu_count from powerline.lib.threaded import ThreadedSegment from powerline.lib import add_divider_highlight_group from powerline.segments import with_docstring cpu_count = None def system_load(pl, format='{avg:.1f}', threshold_good=1, threshold_bad=2, track_cpu_count=False, short=False): '''Return system load average. Highlights using ``system_load_good``, ``system_load_bad`` and ``system_load_ugly`` highlighting groups, depending on the thresholds passed to the function. :param str format: format string, receives ``avg`` as an argument :param float threshold_good: threshold for gradient level 0: any normalized load average below this value will have this gradient level. :param float threshold_bad: threshold for gradient level 100: any normalized load average above this value will have this gradient level. Load averages between ``threshold_good`` and ``threshold_bad`` receive gradient level that indicates relative position in this interval: (``100 * (cur-good) / (bad-good)``). Note: both parameters are checked against normalized load averages. :param bool track_cpu_count: if True powerline will continuously poll the system to detect changes in the number of CPUs. :param bool short: if True only the sys load over last 1 minute will be displayed. Divider highlight group used: ``background:divider``. Highlight groups used: ``system_load_gradient`` (gradient) or ``system_load``. ''' global cpu_count try: cpu_num = cpu_count = _cpu_count() if cpu_count is None or track_cpu_count else cpu_count except NotImplementedError: pl.warn('Unable to get CPU count: method is not implemented') return None ret = [] for avg in os.getloadavg(): normalized = avg / cpu_num if normalized < threshold_good: gradient_level = 0 elif normalized < threshold_bad: gradient_level = (normalized - threshold_good) * 100.0 / (threshold_bad - threshold_good) else: gradient_level = 100 ret.append({ 'contents': format.format(avg=avg), 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': gradient_level, }) if short: return ret ret[0]['contents'] += ' ' ret[1]['contents'] += ' ' return ret try: import psutil class CPULoadPercentSegment(ThreadedSegment): interval = 1 def update(self, old_cpu): return psutil.cpu_percent(interval=None) def run(self): while not self.shutdown_event.is_set(): try: self.update_value = psutil.cpu_percent(interval=self.interval) except Exception as e: self.exception('Exception while calculating cpu_percent: {0}', str(e)) def render(self, cpu_percent, format='{0:.0f}%', **kwargs): return [{ 'contents': format.format(cpu_percent), 'gradient_level': cpu_percent, 'highlight_groups': ['cpu_load_percent_gradient', 'cpu_load_percent'], }] except ImportError: class CPULoadPercentSegment(ThreadedSegment): interval = 1 @staticmethod def startup(**kwargs): pass @staticmethod def start(): pass @staticmethod def shutdown(): pass @staticmethod def render(cpu_percent, pl, format='{0:.0f}%', **kwargs): pl.warn('Module “psutil” is not installed, thus CPU load is not available') return None cpu_load_percent = with_docstring(CPULoadPercentSegment(), '''Return the average CPU load as a percentage. Requires the ``psutil`` module. :param str format: Output format. Accepts measured CPU load as the first argument. Highlight groups used: ``cpu_load_percent_gradient`` (gradient) or ``cpu_load_percent``. ''') if os.path.exists('/proc/uptime'): def _get_uptime(): with open('/proc/uptime', 'r') as f: return int(float(f.readline().split()[0])) elif 'psutil' in globals(): from time import time if hasattr(psutil, 'boot_time'): def _get_uptime(): return int(time() - psutil.boot_time()) else: def _get_uptime(): return int(time() - psutil.BOOT_TIME) else: def _get_uptime(): raise NotImplementedError @add_divider_highlight_group('background:divider') def uptime(pl, days_format='{days:d}d', hours_format=' {hours:d}h', minutes_format=' {minutes:02d}m', seconds_format=' {seconds:02d}s', shorten_len=3): '''Return system uptime. :param str days_format: day format string, will be passed ``days`` as the argument :param str hours_format: hour format string, will be passed ``hours`` as the argument :param str minutes_format: minute format string, will be passed ``minutes`` as the argument :param str seconds_format: second format string, will be passed ``seconds`` as the argument :param int shorten_len: shorten the amount of units (days, hours, etc.) displayed Divider highlight group used: ``background:divider``. ''' try: seconds = _get_uptime() except NotImplementedError: pl.warn('Unable to get uptime. You should install psutil module') return None minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) days, hours = divmod(hours, 24) time_formatted = list(filter(None, [ days_format.format(days=days) if days_format else None, hours_format.format(hours=hours) if hours_format else None, minutes_format.format(minutes=minutes) if minutes_format else None, seconds_format.format(seconds=seconds) if seconds_format else None, ])) first_non_zero = next((i for i, x in enumerate([days, hours, minutes, seconds]) if x != 0)) time_formatted = time_formatted[first_non_zero:first_non_zero + shorten_len] return ''.join(time_formatted).strip() powerline-2.8.4/powerline/segments/common/time.py000066400000000000000000000071421466405252600222000ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from datetime import datetime, timezone def date(pl, format='%Y-%m-%d', istime=False, timezone=None): '''Return the current date. :param str format: strftime-style date format string :param bool istime: If true then segment uses ``time`` highlight group. :param string timezone: Specify a timezone to use as ``+HHMM`` or ``-HHMM``. (Defaults to system defaults.) Divider highlight group used: ``time:divider``. Highlight groups used: ``time`` or ``date``. ''' try: tz = datetime.strptime(timezone, '%z').tzinfo if timezone else None except ValueError: tz = None nw = datetime.now(tz) try: contents = nw.strftime(format) except UnicodeEncodeError: contents = nw.strftime(format.encode('utf-8')).decode('utf-8') return [{ 'contents': contents, 'highlight_groups': (['time'] if istime else []) + ['date'], 'divider_highlight_group': 'time:divider' if istime else None, }] UNICODE_TEXT_TRANSLATION = { ord('\''): '’', ord('-'): '‐', } def fuzzy_time(pl, format=None, unicode_text=False, timezone=None, hour_str=['twelve', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven'], minute_str = { '0': '{hour_str} o\'clock', '5': 'five past {hour_str}', '10': 'ten past {hour_str}','15': 'quarter past {hour_str}', '20': 'twenty past {hour_str}', '25': 'twenty-five past {hour_str}', '30': 'half past {hour_str}', '35': 'twenty-five to {hour_str}', '40': 'twenty to {hour_str}', '45': 'quarter to {hour_str}', '50': 'ten to {hour_str}', '55': 'five to {hour_str}' }, special_case_str = { '(23, 58)': 'round about midnight', '(23, 59)': 'round about midnight', '(0, 0)': 'midnight', '(0, 1)': 'round about midnight', '(0, 2)': 'round about midnight', '(12, 0)': 'noon', }): '''Display the current time as fuzzy time, e.g. "quarter past six". :param string format: (unused) :param bool unicode_text: If true then hyphenminuses (regular ASCII ``-``) and single quotes are replaced with unicode dashes and apostrophes. :param string timezone: Specify a timezone to use as ``+HHMM`` or ``-HHMM``. (Defaults to system defaults.) :param string list hour_str: Strings to be used to display the hour, starting with midnight. (This list may contain 12 or 24 entries.) :param dict minute_str: Dictionary mapping minutes to strings to be used to display them. Each entry may optionally come with a format field "{hour_str}" to indicate the position of the string used for the current hour. :param dict special_case_str: Special strings for special times. Highlight groups used: ``fuzzy_time``. ''' try: tz = datetime.strptime(timezone, '%z').tzinfo if timezone else None except ValueError: tz = None now = datetime.now(tz) try: # We don't want to enforce a special type of spaces/ alignment in the input from ast import literal_eval special_case_str = {literal_eval(x):special_case_str[x] for x in special_case_str} result = special_case_str[(now.hour, now.minute)] if unicode_text: result = result.translate(UNICODE_TEXT_TRANSLATION) return result except KeyError: pass hour = now.hour if now.minute >= 32: hour = hour + 1 hour = hour % len(hour_str) min_dis = 100 min_pos = 0 for mn in minute_str: mn = int(mn) if now.minute >= mn and now.minute - mn < min_dis: min_dis = now.minute - mn min_pos = mn elif now.minute < mn and mn - now.minute < min_dis: min_dis = mn - now.minute min_pos = mn result = minute_str[str(min_pos)].format(hour_str=hour_str[hour]) if unicode_text: result = result.translate(UNICODE_TEXT_TRANSLATION) return result powerline-2.8.4/powerline/segments/common/vcs.py000066400000000000000000000053061466405252600220350ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.lib.vcs import guess, tree_status from powerline.segments import Segment, with_docstring from powerline.theme import requires_segment_info, requires_filesystem_watcher @requires_filesystem_watcher @requires_segment_info class BranchSegment(Segment): divider_highlight_group = None @staticmethod def get_directory(segment_info): return segment_info['getcwd']() def __call__(self, pl, segment_info, create_watcher, status_colors=False, ignore_statuses=()): name = self.get_directory(segment_info) if name: repo = guess(path=name, create_watcher=create_watcher) if repo is not None: branch = repo.branch() scol = ['branch'] if status_colors: try: status = tree_status(repo, pl) except Exception as e: pl.exception('Failed to compute tree status: {0}', str(e)) status = '?' else: status = status and status.strip() if status in ignore_statuses: status = None scol.insert(0, 'branch_dirty' if status else 'branch_clean') return [{ 'contents': branch, 'highlight_groups': scol, 'divider_highlight_group': self.divider_highlight_group, }] branch = with_docstring(BranchSegment(), '''Return the current VCS branch. :param bool status_colors: Determines whether repository status will be used to determine highlighting. Default: False. :param list ignore_statuses: List of statuses which will not result in repo being marked as dirty. Most useful is setting this option to ``["U"]``: this will ignore repository which has just untracked files (i.e. repository with modified, deleted or removed files will be marked as dirty, while just untracked files will make segment show clean repository). Only applicable if ``status_colors`` option is True. Highlight groups used: ``branch_clean``, ``branch_dirty``, ``branch``. ''') @requires_filesystem_watcher @requires_segment_info class StashSegment(Segment): divider_highlight_group = None @staticmethod def get_directory(segment_info): return segment_info['getcwd']() def __call__(self, pl, segment_info, create_watcher): name = self.get_directory(segment_info) if name: repo = guess(path=name, create_watcher=create_watcher) if repo is not None: stash = getattr(repo, 'stash', None) if stash: stashes = stash() if stashes: return [{ 'contents': str(stashes), 'highlight_groups': ['stash'], 'divider_highlight_group': self.divider_highlight_group }] stash = with_docstring(StashSegment(), '''Return the number of current VCS stash entries, if any. Highlight groups used: ``stash``. ''') powerline-2.8.4/powerline/segments/common/wthr.py000066400000000000000000000146751466405252600222370ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import json from collections import namedtuple from powerline.lib.url import urllib_read, urllib_urlencode from powerline.lib.threaded import KwThreadedSegment from powerline.segments import with_docstring _WeatherKey = namedtuple('Key', 'location_query weather_api_key') # XXX Warning: module name must not be equal to the segment name as long as this # segment is imported into powerline.segments.common module. # Weather condition code descriptions available at # https://openweathermap.org/weather-conditions weather_conditions_codes = { 200: ('stormy',), 201: ('stormy',), 202: ('stormy',), 210: ('stormy',), 211: ('stormy',), 212: ('stormy',), 221: ('stormy',), 230: ('stormy',), 231: ('stormy',), 232: ('stormy',), 300: ('rainy',), 301: ('rainy',), 302: ('rainy',), 310: ('rainy',), 311: ('rainy',), 312: ('rainy',), 313: ('rainy',), 314: ('rainy',), 321: ('rainy',), 500: ('rainy',), 501: ('rainy',), 502: ('rainy',), 503: ('rainy',), 504: ('rainy',), 511: ('snowy',), 520: ('rainy',), 521: ('rainy',), 522: ('rainy',), 531: ('rainy',), 600: ('snowy',), 601: ('snowy',), 602: ('snowy',), 611: ('snowy',), 612: ('snowy',), 613: ('snowy',), 615: ('snowy',), 616: ('snowy',), 620: ('snowy',), 621: ('snowy',), 622: ('snowy',), 701: ('foggy',), 711: ('foggy',), 721: ('foggy',), 731: ('foggy',), 741: ('foggy',), 751: ('foggy',), 761: ('foggy',), 762: ('foggy',), 771: ('foggy',), 781: ('foggy',), 800: ('sunny',), 801: ('cloudy',), 802: ('cloudy',), 803: ('cloudy',), 804: ('cloudy',), } weather_conditions_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_conversions = { 'C': lambda temp: temp - 273.15, 'F': lambda temp: (temp * 9 / 5) - 459.67, 'K': lambda temp: temp, } # Note: there are also unicode characters for units: ℃, ℉ and K temp_units = { 'C': '°C', 'F': '°F', 'K': 'K', } class WeatherSegment(KwThreadedSegment): interval = 600 default_location = None location_urls = {} weather_api_key = "fbc9549d91a5e4b26c15be0dbdac3460" @staticmethod def key(location_query=None, **kwargs): try: weather_api_key = kwargs["weather_api_key"] except KeyError: weather_api_key = WeatherSegment.weather_api_key return _WeatherKey(location_query, weather_api_key) def get_request_url(self, weather_key): try: return self.location_urls[weather_key] except KeyError: query_data = { "appid": weather_key.weather_api_key } location_query = weather_key.location_query if location_query is None: location_data = json.loads(urllib_read('https://freegeoip.app/json/')) query_data["lat"] = location_data["latitude"] query_data["lon"] = location_data["longitude"] else: query_data["q"] = location_query self.location_urls[location_query] = url = ( "https://api.openweathermap.org/data/2.5/weather?" + urllib_urlencode(query_data)) return url def compute_state(self, weather_key): url = self.get_request_url(weather_key) raw_response = urllib_read(url) if not raw_response: self.error('Failed to get response') return None response = json.loads(raw_response) try: condition = response['weather'][0] condition_code = int(condition['id']) temp = float(response['main']['temp']) except (KeyError, ValueError): self.exception('OpenWeatherMap returned malformed or unexpected response: {0}', repr(raw_response)) return None try: icon_names = weather_conditions_codes[condition_code] except IndexError: icon_names = ('unknown',) self.error('Unknown condition code: {0}', condition_code) return (temp, icon_names) def render_one(self, weather, icons=None, unit='C', temp_format=None, temp_coldest=-30, temp_hottest=40, **kwargs): if not weather: return None temp, icon_names = weather for icon_name in icon_names: if icons: if icon_name in icons: icon = icons[icon_name] break else: icon = weather_conditions_icons[icon_names[-1]] temp_format = temp_format or ('{temp:.0f}' + temp_units[unit]) converted_temp = temp_conversions[unit](temp) if converted_temp <= temp_coldest: gradient_level = 0 elif converted_temp >= temp_hottest: gradient_level = 100 else: gradient_level = (converted_temp - temp_coldest) * 100.0 / (temp_hottest - temp_coldest) groups = ['weather_condition_' + icon_name for icon_name in icon_names] + ['weather_conditions', 'weather'] return [ { 'contents': icon + ' ', 'highlight_groups': groups, 'divider_highlight_group': 'background:divider', }, { 'contents': temp_format.format(temp=converted_temp), 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'divider_highlight_group': 'background:divider', 'gradient_level': gradient_level, }, ] weather = with_docstring(WeatherSegment(), '''Return weather from OpenWeatherMaps. Uses GeoIP lookup from https://freegeoip.app to automatically determine your current location. This should be changed if you’re in a VPN or if your IP address is registered at another location. Returns a list of colorized icon and temperature segments depending on weather conditions. :param str unit: temperature unit, can be one of ``F``, ``C`` or ``K`` :param str location_query: location query for your current location, e.g. ``oslo, norway`` :param dict icons: dict for overriding default icons, e.g. ``{'heavy_snow' : u'❆'}`` :param str temp_format: format string, receives ``temp`` as an argument. Should also hold unit. :param float temp_coldest: coldest temperature. Any temperature below it will have gradient level equal to zero. :param float temp_hottest: hottest temperature. Any temperature above it will have gradient level equal to 100. Temperatures between ``temp_coldest`` and ``temp_hottest`` receive gradient level that indicates relative position in this interval (``100 * (cur-coldest) / (hottest-coldest)``). Divider highlight group used: ``background:divider``. Highlight groups used: ``weather_conditions`` or ``weather``, ``weather_temp_gradient`` (gradient) or ``weather``. Also uses ``weather_conditions_{condition}`` for all weather conditions supported by OpenWeatherMap. ''') powerline-2.8.4/powerline/segments/i3wm.py000066400000000000000000000235441466405252600206350ustar00rootroot00000000000000# 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.bindings.wm import get_i3_connection WORKSPACE_REGEX = re.compile(r'^[0-9]+: ?') def workspace_groups(w): group = [] if w.focused: group.append('workspace:focused') group.append('w_focused') if w.urgent: group.append('workspace:urgent') group.append('w_urgent') if w.visible: group.append('workspace:visible') group.append('w_visible') group.append('workspace') return group def format_name(name, strip=False): if strip: return WORKSPACE_REGEX.sub('', name, count=1) return name def is_empty_workspace(workspace, containers): if workspace.focused or workspace.visible: return False wins = [win for win in containers[workspace.name].leaves()] return False if len(wins) > 0 else True WS_ICONS = {"multiple": "M"} def get_icon(workspace, separator, icons, show_multiple_icons, ws_containers): icons_tmp = WS_ICONS icons_tmp.update(icons) icons = icons_tmp wins = [win for win in ws_containers[workspace.name].leaves() \ if win.parent.scratchpad_state == 'none'] if len(wins) == 0: return '' result = '' cnt = 0 for key in icons: if not icons[key] or len(icons[key]) < 1: continue if any(key in win.window_class for win in wins if win.window_class): result += (separator if cnt > 0 else '') + icons[key] cnt += 1 if not show_multiple_icons and cnt > 1: if 'multiple' in icons: return icons['multiple'] else: return '' return result @requires_segment_info def workspaces(pl, segment_info, only_show=None, output=None, strip=0, format='{name}', icons=WS_ICONS, sort_workspaces=False, show_output=False, priority_workspaces=[], hide_empty_workspaces=False): '''Return list of used workspaces :param list only_show: Specifies which workspaces to show. Valid entries are ``"visible"``, ``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces are shown. :param str output: May be set to the name of an X output. If specified, only workspaces on that output are shown. Overrides automatic output detection by the lemonbar renderer and bindings. Use "__all__" to show workspaces on all outputs. :param int strip: Specifies how many characters from the front of each workspace name should be stripped (e.g. to remove workspace numbers). Defaults to zero. :param str format: Specifies the format used to display workspaces; defaults to ``{name}``. Valid fields are: ``name`` (workspace name), ``number`` (workspace number if present), `stipped_name`` (workspace name stripped of leading number), ``icon`` (if available, icon for application running in the workspace, uses the ``multiple`` icon instead of multiple different icons), ``multi_icon`` (similar to ``icon``, but does not use ``multiple``, instead joins all icons with a single space) :param dict icons: A dictionary mapping a substring of window classes to strings to be used as an icon for that window class. Further, there is a ``multiple`` icon for workspaces containing more than one window. :param bool sort_workspaces: Sort the workspaces displayed by their name according to the natural ordering. :param bool show_output: Shows the name of the output if more than one output is connected. :param list priority_workspaces: A list of workspace names to be sorted before any other workspaces in the given order. :param bool hide_empty_workspaces: Hides all workspaces without any open window. Also hides non-focussed workspaces containing only an open scratchpad. Highlight groups used: ``workspace`` or ``w_visible``, ``workspace:visible``, ``workspace`` or ``w_focused``, ``workspace:focused``, ``workspace`` or ``w_urgent``, ``workspace:urgent``, ``workspace`` or ``output``. ''' conn = get_i3_connection() if not output == "__all__": output = output or segment_info.get('output') else: output = None if output: output = [output] else: output = [o.name for o in conn.get_outputs() if o.active] def sort_ws(ws): if sort_workspaces: def natural_key(ws): str = ws.name return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', str)] ws = sorted(ws, key=natural_key) result = [] for n in priority_workspaces: result += [w for w in ws if w.name == n] return result + [w for w in ws if not w.name in priority_workspaces] ws_containers = {w_con.name : w_con for w_con in conn.get_tree().workspaces()} if len(output) <= 1: res = [] if show_output: res += [{ 'contents': output[0], 'highlight_groups': ['output'] }] res += [{ 'contents': format.format(name = w.name[min(len(w.name), strip):], stripped_name = format_name(w.name, strip=True), number = w.num, icon = get_icon(w, '', icons, False, ws_containers), multi_icon = get_icon(w, ' ', icons, True, ws_containers)), 'highlight_groups': workspace_groups(w) } for w in sort_ws(conn.get_workspaces()) \ if (not only_show or any(getattr(w, tp) for tp in only_show)) \ if w.output == output[0] \ if not (hide_empty_workspaces and is_empty_workspace(w, ws_containers))] return res else: res = [] for n in output: if show_output: res += [{ 'contents': n, 'highlight_groups': ['output'] }] res += [{ 'contents': format.format(name = w.name[min(len(w.name), strip):], stripped_name = format_name(w.name, strip=True), number = w.num, icon = get_icon(w, '', icons, False, ws_containers), multi_icon = get_icon(w, ' ', icons, True, ws_containers)), 'highlight_groups': workspace_groups(w) } for w in sort_ws(conn.get_workspaces()) \ if (not only_show or any(getattr(w, tp) for tp in only_show)) \ if w.output == n \ if not (hide_empty_workspaces and is_empty_workspace(w, ws_containers))] return res @requires_segment_info def workspace(pl, segment_info, workspace=None, strip=False, format=None, icons=WS_ICONS): '''Return the specified workspace name :param str workspace: Specifies which workspace to show. If unspecified, may be set by the ``list_workspaces`` lister if used, otherwise falls back to currently focused workspace. :param bool strip: Specifies whether workspace numbers (in the ``1: name`` format) should be stripped from workspace names before being displayed. Defaults to false. Deprecated: Use {name} or {stripped_name} of format instead. :param str format: Specifies the format used to display workspaces; defaults to ``{name}``. Valid fields are: ``name`` (workspace name), ``number`` (workspace number if present), `stipped_name`` (workspace name stripped of leading number), ``icon`` (if available, icon for application running in the workspace, uses the ``multiple`` icon instead of multiple different icons), ``multi_icon`` (similar to ``icon``, but does not use ``multiple``, instead joins all icons with a single space) :param dict icons: A dictionary mapping a substring of window classes to strings to be used as an icon for that window class. Further, there is a ``multiple`` icon for workspaces containing more than one window. Highlight groups used: ``workspace`` or ``w_visible``, ``workspace:visible``, ``workspace`` or ``w_focused``, ``workspace:focused``, ``workspace`` or ``w_urgent``, ``workspace:urgent``, ``workspace``. ''' if format == None: format = '{stripped_name}' if strip else '{name}' conn = get_i3_connection() ws_containers = {w_con.name : w_con for w_con in conn.get_tree().workspaces()} if workspace: try: w = next(( w for w in conn.get_workspaces() if w.name == workspace )) except StopIteration: return None elif segment_info.get('workspace'): w = segment_info['workspace'] else: try: w = next(( w for w in conn.get_workspaces() if w.focused )) except StopIteration: return None return [{ 'contents': format.format(name = w.name, stripped_name = format_name(w.name, strip=True), number = w.num, icon = get_icon(w, '', icons, False, ws_containers), multi_icon = get_icon(w, ' ', icons, True, ws_containers)), 'highlight_groups': workspace_groups(w) }] @requires_segment_info def mode(pl, segment_info, names={'default': None}): '''Returns current i3 mode :param dict names: Specifies the string to show for various modes. Use ``null`` to hide a mode (``default`` is hidden by default). Highligh groups used: ``mode`` ''' mode = segment_info['mode'] if mode in names: return names[mode] return mode def scratchpad_groups(w): group = [] if w.urgent: group.append('scratchpad:urgent') if w.nodes[0].focused: group.append('scratchpad:focused') if w.workspace().name != '__i3_scratch': group.append('scratchpad:visible') group.append('scratchpad') return group SCRATCHPAD_ICONS = { 'fresh': 'O', 'changed': 'X', } def scratchpad(pl, icons=SCRATCHPAD_ICONS): '''Returns the windows currently on the scratchpad :param dict icons: Specifies the strings to show for the different scratchpad window states. Must contain the keys ``fresh`` and ``changed``. Highlight groups used: ``scratchpad`` or ``scratchpad:visible``, ``scratchpad`` or ``scratchpad:focused``, ``scratchpad`` or ``scratchpad:urgent``. ''' return [ { 'contents': icons.get(w.scratchpad_state, icons['changed']), 'highlight_groups': scratchpad_groups(w) } for w in get_i3_connection().get_tree().descendants() if w.scratchpad_state != 'none' ] def active_window(pl, cutoff=100): '''Returns the title of the currently active window. :param int cutoff: Maximum title length. If the title is longer, the window_class is used instead. Highlight groups used: ``active_window_title``. ''' focused = get_i3_connection().get_tree().find_focused() cont = focused.name if len(cont) > cutoff: cont = focused.window_class return [{'contents': cont, 'highlight_groups': ['active_window_title']}] if focused.name != focused.workspace().name else [] powerline-2.8.4/powerline/segments/ipython.py000066400000000000000000000004251466405252600214410ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.theme import requires_segment_info @requires_segment_info def prompt_count(pl, segment_info): return str(segment_info['ipython'].prompt_count) powerline-2.8.4/powerline/segments/pdb.py000066400000000000000000000031131466405252600205110ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from powerline.theme import requires_segment_info @requires_segment_info def current_line(pl, segment_info): '''Displays line number that is next to be run ''' return str(segment_info['curframe'].f_lineno) @requires_segment_info def current_file(pl, segment_info, basename=True): '''Displays current file name :param bool basename: If true only basename is displayed. ''' filename = segment_info['curframe'].f_code.co_filename if basename: filename = os.path.basename(filename) return filename @requires_segment_info def current_code_name(pl, segment_info): '''Displays name of the code object of the current frame ''' return segment_info['curframe'].f_code.co_name @requires_segment_info def current_context(pl, segment_info): '''Displays currently executed context name This is similar to :py:func:`current_code_name`, but gives more details. Currently it only gives module file name if code_name happens to be ````. ''' name = segment_info['curframe'].f_code.co_name if name == '': name = os.path.basename(segment_info['curframe'].f_code.co_filename) return name @requires_segment_info def stack_depth(pl, segment_info, full_stack=False): '''Displays current stack depth Result is relative to the stack depth at the time prompt was first run. :param bool full_stack: If true then absolute depth is used. ''' return str(len(segment_info['pdb'].stack) - ( 0 if full_stack else segment_info['initial_stack_length'])) powerline-2.8.4/powerline/segments/shell.py000066400000000000000000000137761466405252600210730ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.theme import requires_segment_info from powerline.segments import with_docstring from powerline.segments.common.env import CwdSegment from powerline.lib.unicode import out_u @requires_segment_info def jobnum(pl, segment_info, show_zero=False): '''Return the number of jobs. :param bool show_zero: If False (default) shows nothing if there are no jobs. Otherwise shows zero for no jobs. ''' jobnum = segment_info['args'].jobnum if jobnum is None or (not show_zero and jobnum == 0): return None else: return str(jobnum) try: import signal exit_codes = dict((k, v) for v, k in reversed(sorted(signal.__dict__.items())) \ if v.startswith('SIG') and not v.startswith('SIG_')) except ImportError: exit_codes = dict() @requires_segment_info def last_status(pl, segment_info, signal_names=True): '''Return last exit code. :param bool signal_names: If True (default), translate signal numbers to human-readable names. Highlight groups used: ``exit_fail`` ''' if not segment_info['args'].last_exit_code: return None try: if signal_names and segment_info['args'].last_exit_code - 128 in exit_codes: return [{'contents': exit_codes[segment_info['args'].last_exit_code - 128], 'highlight_groups': ['exit_fail']}] except TypeError: pass return [{'contents': str(segment_info['args'].last_exit_code), 'highlight_groups': ['exit_fail']}] @requires_segment_info def last_pipe_status(pl, segment_info, signal_names=True): '''Return last pipe status. :param bool signal_names: If True (default), translate signal numbers to human-readable names. Highlight groups used: ``exit_fail``, ``exit_success`` ''' last_pipe_status = ( segment_info['args'].last_pipe_status or (segment_info['args'].last_exit_code,) ) if any(last_pipe_status): try: return [{ 'contents': exit_codes[status - 128] if signal_names and \ status - 128 in exit_codes else str(status), 'highlight_groups': ['exit_fail' if status else 'exit_success'], 'draw_inner_divider': True } for status in last_pipe_status] except TypeError: return [{ 'contents': str(status), 'highlight_groups': ['exit_fail' if status else 'exit_success'], 'draw_inner_divider': True } for status in last_pipe_status] else: return None @requires_segment_info def mode(pl, segment_info, override={'vicmd': 'COMMND', 'viins': 'INSERT'}, default=None): '''Return the current mode. :param dict override: dict for overriding mode strings. :param str default: If current mode is equal to this string then this segment will not get displayed. If not specified the value is taken from ``$POWERLINE_DEFAULT_MODE`` variable. This variable is set by zsh bindings for any mode that does not start from ``vi``. ''' mode = segment_info.get('mode', None) if not mode: pl.debug('No mode specified') return None default = default or segment_info.get('default_mode', None) if mode == default: return None try: return override[mode] except KeyError: # Note: with zsh line editor you can emulate as much modes as you wish. # Thus having unknown mode is not an error: maybe just some developer # added support for his own zle widgets. As there is no built-in mode() # function like in VimL and mode is likely be defined by our code or by # somebody knowing what he is doing there is absolutely no need in # keeping translations dictionary. return mode.upper() @requires_segment_info def continuation(pl, segment_info, omit_cmdsubst=True, right_align=False, renames={}): '''Display parser state. :param bool omit_cmdsubst: Do not display cmdsubst parser state if it is the last one. :param bool right_align: Align to the right. :param dict renames: Rename states: ``{old_name : new_name}``. If ``new_name`` is ``None`` then given state is not displayed. Highlight groups used: ``continuation``, ``continuation:current``. ''' if not segment_info.get('parser_state'): return [{ 'contents': '', 'width': 'auto', 'highlight_groups': ['continuation:current', 'continuation'], }] ret = [] for state in segment_info['parser_state'].split(): state = renames.get(state, state) if state: ret.append({ 'contents': state, 'highlight_groups': ['continuation'], 'draw_inner_divider': True, }) if omit_cmdsubst and ret[-1]['contents'] == 'cmdsubst': ret.pop(-1) if not ret: ret.append({ 'contents': '' }) if right_align: ret[0].update(width='auto', align='r') ret[-1]['highlight_groups'] = ['continuation:current', 'continuation'] else: ret[-1].update(width='auto', align='l', highlight_groups=['continuation:current', 'continuation']) return ret @requires_segment_info class ShellCwdSegment(CwdSegment): def get_shortened_path(self, pl, segment_info, use_shortened_path=True, **kwargs): if use_shortened_path: try: return out_u(segment_info['shortened_path']) except KeyError: pass return super(ShellCwdSegment, self).get_shortened_path(pl, segment_info, **kwargs) cwd = with_docstring(ShellCwdSegment(), '''Return the current working directory. Returns a segment list to create a breadcrumb-like effect. :param int dir_shorten_len: shorten parent directory names to this length (e.g. :file:`/long/path/to/powerline` → :file:`/l/p/t/powerline`) :param int dir_limit_depth: limit directory depth to this number (e.g. :file:`/long/path/to/powerline` → :file:`⋯/to/powerline`) :param bool use_path_separator: Use path separator in place of soft divider. :param bool use_shortened_path: Use path from shortened_path ``--renderer-arg`` argument. If this argument is present ``shorten_home`` argument is ignored. :param bool shorten_home: Shorten home directory to ``~``. :param str ellipsis: Specifies what to use in place of omitted directories. Use None to not show this subsegment at all. Divider highlight group used: ``cwd:divider``. Highlight groups used: ``cwd:current_folder`` or ``cwd``. It is recommended to define all highlight groups. ''') powerline-2.8.4/powerline/segments/tmux.py000066400000000000000000000014371466405252600207500ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.bindings.tmux import get_tmux_output def attached_clients(pl, minimum=1): '''Return the number of tmux clients attached to the currently active session :param int minimum: The minimum number of attached clients that must be present for this segment to be visible. ''' session_output = get_tmux_output(pl, 'list-panes', '-F', '#{session_name}') if not session_output: return None session_name = session_output.rstrip().split('\n')[0] attached_clients_output = get_tmux_output(pl, 'list-clients', '-t', session_name) attached_count = len(attached_clients_output.rstrip().split('\n')) return None if attached_count < minimum else str(attached_count) powerline-2.8.4/powerline/segments/vim/000077500000000000000000000000001466405252600201675ustar00rootroot00000000000000powerline-2.8.4/powerline/segments/vim/__init__.py000066400000000000000000000575341466405252600223160ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import re import csv import sys from collections import defaultdict try: import vim except ImportError: vim = object() from powerline.bindings.vim import (vim_get_func, getbufvar, vim_getbufoption, buffer_name, vim_getwinvar, register_buffer_cache, current_tabpage, list_tabpage_buffers_segment_info) from powerline.theme import requires_segment_info, requires_filesystem_watcher from powerline.lib import add_divider_highlight_group from powerline.lib.vcs import guess from powerline.lib.humanize_bytes import humanize_bytes from powerline.lib import wraps_saveargs as wraps from powerline.segments.common.vcs import BranchSegment, StashSegment from powerline.segments import with_docstring from powerline.lib.unicode import string, unicode try: from __builtin__ import xrange as range except ImportError: pass vim_funcs = { 'virtcol': vim_get_func('virtcol', rettype='int'), 'getpos': vim_get_func('getpos'), 'fnamemodify': vim_get_func('fnamemodify', rettype='bytes'), 'line2byte': vim_get_func('line2byte', rettype='int'), 'line': vim_get_func('line', rettype='int'), } vim_modes = { 'n': 'NORMAL', 'no': 'N-OPER', 'v': 'VISUAL', 'V': 'V-LINE', '^V': 'V-BLCK', 's': 'SELECT', 'S': 'S-LINE', '^S': 'S-BLCK', 'i': 'INSERT', '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 ', } # TODO Remove cache when needed def window_cached(func): cache = {} @requires_segment_info @wraps(func) def ret(segment_info, **kwargs): window_id = segment_info['window_id'] if segment_info['mode'] == 'nc': return cache.get(window_id) else: if getattr(func, 'powerline_requires_segment_info', False): r = func(segment_info=segment_info, **kwargs) else: r = func(**kwargs) cache[window_id] = r return r return ret @requires_segment_info def mode(pl, segment_info, override=None): '''Return the current vim mode. If mode (returned by ``mode()`` VimL function, see ``:h mode()`` in Vim) consists of multiple characters and necessary mode is not known to powerline then it will fall back to mode with last character(s) ignored. :param dict override: dict for overriding default mode strings, e.g. ``{ 'n': 'NORM' }`` ''' mode = segment_info['mode'] if mode == 'nc': return None while mode: try: if not override: return vim_modes[mode] try: return override[mode] except KeyError: return vim_modes[mode] except KeyError: mode = mode[:-1] return 'BUG' @window_cached @requires_segment_info def visual_range(pl, segment_info, CTRL_V_text='{rows} x {vcols}', v_text_oneline='C:{vcols}', v_text_multiline='L:{rows}', V_text='L:{rows}'): '''Return the current visual selection range. :param str CTRL_V_text: Text to display when in block visual or select mode. :param str v_text_oneline: Text to display when in charaterwise visual or select mode, assuming selection occupies only one line. :param str v_text_multiline: Text to display when in charaterwise visual or select mode, assuming selection occupies more then one line. :param str V_text: Text to display when in linewise visual or select mode. All texts are format strings which are passed the following parameters: ========= ============================================================= Parameter Description ========= ============================================================= sline Line number of the first line of the selection eline Line number of the last line of the selection scol Column number of the first character of the selection ecol Column number of the last character of the selection svcol Virtual column number of the first character of the selection secol Virtual column number of the last character of the selection rows Number of lines in the selection cols Number of columns in the selection vcols Number of virtual columns in the selection ========= ============================================================= ''' sline, scol, soff = [int(v) for v in vim_funcs['getpos']('v')[1:]] eline, ecol, eoff = [int(v) for v in vim_funcs['getpos']('.')[1:]] svcol = vim_funcs['virtcol']([sline, scol, soff]) evcol = vim_funcs['virtcol']([eline, ecol, eoff]) rows = abs(eline - sline) + 1 cols = abs(ecol - scol) + 1 vcols = abs(evcol - svcol) + 1 return { '^': CTRL_V_text, 's': v_text_oneline if rows == 1 else v_text_multiline, 'S': V_text, 'v': v_text_oneline if rows == 1 else v_text_multiline, 'V': V_text, }.get(segment_info['mode'][0], '').format( sline=sline, eline=eline, scol=scol, ecol=ecol, svcol=svcol, evcol=evcol, rows=rows, cols=cols, vcols=vcols, ) @requires_segment_info def modified_indicator(pl, segment_info, text='+'): '''Return a file modified indicator. :param string text: text to display if the current buffer is modified ''' return text if int(vim_getbufoption(segment_info, 'modified')) else None @requires_segment_info def tab_modified_indicator(pl, segment_info, text='+'): '''Return a file modified indicator for tabpages. :param string text: text to display if any buffer in the current tab is modified Highlight groups used: ``tab_modified_indicator`` or ``modified_indicator``. ''' for buf_segment_info in list_tabpage_buffers_segment_info(segment_info): if int(vim_getbufoption(buf_segment_info, 'modified')): return [{ 'contents': text, 'highlight_groups': ['tab_modified_indicator', 'modified_indicator'], }] return None @requires_segment_info def paste_indicator(pl, segment_info, text='PASTE'): '''Return a paste mode indicator. :param string text: text to display if paste mode is enabled ''' return text if int(vim.eval('&paste')) else None @requires_segment_info def readonly_indicator(pl, segment_info, text='RO'): '''Return a read-only indicator. :param string text: text to display if the current buffer is read-only ''' return text if int(vim_getbufoption(segment_info, 'readonly')) else None SCHEME_RE = re.compile(b'^\\w[\\w\\d+\\-.]*(?=:)') @requires_segment_info def file_scheme(pl, segment_info): '''Return the protocol part of the file. Protocol is the part of the full filename just before the colon which starts with a latin letter and contains only latin letters, digits, plus, period or hyphen (refer to `RFC3986 `_ for the description of URI scheme). If there is no such a thing ``None`` is returned, effectively removing segment. .. note:: Segment will not check whether there is ``//`` just after the colon or if there is at least one slash after the scheme. Reason: it is not always present. E.g. when opening file inside a zip archive file name will look like :file:`zipfile:/path/to/archive.zip::file.txt`. ``file_scheme`` segment will catch ``zipfile`` part here. ''' name = buffer_name(segment_info) if not name: return None match = SCHEME_RE.match(name) if match: return match.group(0).decode('ascii') @requires_segment_info def file_directory(pl, segment_info, remove_scheme=True, shorten_user=True, shorten_cwd=True, shorten_home=False): '''Return file directory (head component of the file path). :param bool remove_scheme: Remove scheme part from the segment name, if present. See documentation of file_scheme segment for the description of what scheme is. Also removes the colon. :param bool shorten_user: Shorten ``$HOME`` directory to :file:`~/`. Does not work for files with scheme. :param bool shorten_cwd: Shorten current directory to :file:`./`. Does not work for files with scheme present. :param bool shorten_home: Shorten all directories in :file:`/home/` to :file:`~user/` instead of :file:`/home/user/`. Does not work for files with scheme present. ''' name = buffer_name(segment_info) if not name: return None match = SCHEME_RE.match(name) if match: if remove_scheme: name = name[len(match.group(0)) + 1:] # Remove scheme and colon file_directory = vim_funcs['fnamemodify'](name, ':h') else: file_directory = vim_funcs['fnamemodify']( name, (':~' if shorten_user else '') + (':.' if shorten_cwd else '') + ':h' ) if not file_directory: return None if shorten_home and file_directory.startswith('/home/'): file_directory = b'~' + file_directory[6:] file_directory = file_directory.decode(segment_info['encoding'], 'powerline_vim_strtrans_error') return file_directory + os.sep @requires_segment_info def file_name(pl, segment_info, display_no_file=False, no_file_text='[No file]'): '''Return file name (tail component of the file path). :param bool display_no_file: display a string if the buffer is missing a file name :param str no_file_text: the string to display if the buffer is missing a file name Highlight groups used: ``file_name_no_file`` or ``file_name``, ``file_name``. ''' name = buffer_name(segment_info) if not name: if display_no_file: return [{ 'contents': no_file_text, 'highlight_groups': ['file_name_no_file', 'file_name'], }] else: return None return os.path.basename(name).decode(segment_info['encoding'], 'powerline_vim_strtrans_error') @window_cached def file_size(pl, suffix='B', si_prefix=False): '''Return file size in &encoding. :param str suffix: string appended to the file size :param bool si_prefix: use SI prefix, e.g. MB instead of MiB :return: file size or None if the file isn’t saved or if the size is too big to fit in a number ''' # Note: returns file size in &encoding, not in &fileencoding. But returned # size is updated immediately; and it is valid for any buffer file_size = vim_funcs['line2byte'](len(vim.current.buffer) + 1) - 1 if file_size < 0: file_size = 0 return humanize_bytes(file_size, suffix, si_prefix) @requires_segment_info @add_divider_highlight_group('background:divider') def file_format(pl, segment_info): '''Return file format (i.e. line ending type). :return: file format or None if unknown or missing file format Divider highlight group used: ``background:divider``. ''' return vim_getbufoption(segment_info, 'fileformat') or None @requires_segment_info @add_divider_highlight_group('background:divider') def file_encoding(pl, segment_info): '''Return file encoding/character set. :return: file encoding/character set or None if unknown or missing file encoding Divider highlight group used: ``background:divider``. ''' return vim_getbufoption(segment_info, 'fileencoding') or None @requires_segment_info @add_divider_highlight_group('background:divider') def file_bom(pl, segment_info): '''Return BOM of the current file :return: Byte order mark or None if unknown or missing BOM Divider highlight group used: ``background:divider``. ''' return 'bom' if vim_getbufoption(segment_info, 'bomb') else None @requires_segment_info @add_divider_highlight_group('background:divider') def file_type(pl, segment_info): '''Return file type. :return: file type or None if unknown file type Divider highlight group used: ``background:divider``. ''' return vim_getbufoption(segment_info, 'filetype') or None @requires_segment_info def window_title(pl, segment_info): '''Return the window title. This currently looks at the ``quickfix_title`` window variable, which is used by Syntastic and Vim itself. It is used in the quickfix theme.''' try: return vim_getwinvar(segment_info, 'quickfix_title') except KeyError: return None @requires_segment_info def line_percent(pl, segment_info, gradient=False): '''Return the cursor position in the file as a percentage. :param bool gradient: highlight the percentage with a color gradient (by default a green to red gradient) Highlight groups used: ``line_percent_gradient`` (gradient), ``line_percent``. ''' line_current = segment_info['window'].cursor[0] line_last = len(segment_info['buffer']) percentage = line_current * 100.0 / line_last if not gradient: return str(int(round(percentage))) return [{ 'contents': str(int(round(percentage))), 'highlight_groups': ['line_percent_gradient', 'line_percent'], 'gradient_level': percentage, }] @window_cached def position(pl, position_strings={'top': 'Top', 'bottom': 'Bot', 'all': 'All'}, gradient=False): '''Return the position of the current view in the file as a percentage. :param dict position_strings: dict for translation of the position strings, e.g. ``{"top":"Oben", "bottom":"Unten", "all":"Alles"}`` :param bool gradient: highlight the percentage with a color gradient (by default a green to red gradient) Highlight groups used: ``position_gradient`` (gradient), ``position``. ''' line_last = len(vim.current.buffer) winline_first = vim_funcs['line']('w0') winline_last = vim_funcs['line']('w$') if winline_first == 1 and winline_last == line_last: percentage = 0.0 content = position_strings['all'] elif winline_first == 1: percentage = 0.0 content = position_strings['top'] elif winline_last == line_last: percentage = 100.0 content = position_strings['bottom'] else: percentage = winline_first * 100.0 / (line_last - winline_last + winline_first) content = str(int(round(percentage))) + '%' if not gradient: return content return [{ 'contents': content, 'highlight_groups': ['position_gradient', 'position'], 'gradient_level': percentage, }] @requires_segment_info def line_current(pl, segment_info): '''Return the current cursor line.''' return str(segment_info['window'].cursor[0]) @requires_segment_info def line_count(pl, segment_info): '''Return the line count of the current buffer.''' return str(len(segment_info['buffer'])) @requires_segment_info def col_current(pl, segment_info): '''Return the current cursor column. ''' return str(segment_info['window'].cursor[1] + 1) @window_cached def virtcol_current(pl, gradient=True): '''Return current visual column with concealed characters ignored :param bool gradient: Determines whether it should show textwidth-based gradient (gradient level is ``virtcol * 100 / textwidth``). Highlight groups used: ``virtcol_current_gradient`` (gradient), ``virtcol_current`` or ``col_current``. ''' col = vim_funcs['virtcol']('.') r = [{'contents': str(col), 'highlight_groups': ['virtcol_current', 'col_current']}] if gradient: textwidth = int(getbufvar('%', '&textwidth')) r[-1]['gradient_level'] = min(col * 100 / textwidth, 100) if textwidth else 0 r[-1]['highlight_groups'].insert(0, 'virtcol_current_gradient') return r def modified_buffers(pl, text='+ ', join_str=','): '''Return a comma-separated list of modified buffers. :param str text: text to display before the modified buffer list :param str join_str: string to use for joining the modified buffer list ''' buffer_mod_text = join_str.join(( str(buffer.number) for buffer in vim.buffers if int(vim_getbufoption({'buffer': buffer, 'bufnr': buffer.number}, 'modified')) )) if buffer_mod_text: return text + buffer_mod_text return None @requires_filesystem_watcher @requires_segment_info class VimBranchSegment(BranchSegment): divider_highlight_group = 'branch:divider' @staticmethod def get_directory(segment_info): if vim_getbufoption(segment_info, 'buftype'): return None return buffer_name(segment_info) branch = with_docstring(VimBranchSegment(), '''Return the current working branch. :param bool status_colors: Determines whether repository status will be used to determine highlighting. Default: False. :param bool ignore_statuses: List of statuses which will not result in repo being marked as dirty. Most useful is setting this option to ``["U"]``: this will ignore repository which has just untracked files (i.e. repository with modified, deleted or removed files will be marked as dirty, while just untracked files will make segment show clean repository). Only applicable if ``status_colors`` option is True. Highlight groups used: ``branch_clean``, ``branch_dirty``, ``branch``. Divider highlight group used: ``branch:divider``. ''') @requires_filesystem_watcher @requires_segment_info class VimStashSegment(StashSegment): divider_highlight_group = 'stash:divider' @staticmethod def get_directory(segment_info): if vim_getbufoption(segment_info, 'buftype'): return None return buffer_name(segment_info) stash = with_docstring(VimStashSegment(), '''Return the number of stashes in the current working branch. Highlight groups used: ``stash``. ''') @requires_filesystem_watcher @requires_segment_info def file_vcs_status(pl, segment_info, create_watcher): '''Return the VCS status for this buffer. Highlight groups used: ``file_vcs_status``. ''' name = buffer_name(segment_info) skip = not (name and (not vim_getbufoption(segment_info, 'buftype'))) if not skip: repo = guess(path=name, create_watcher=create_watcher) if repo is not None: status = repo.status(os.path.relpath(name, repo.directory)) if not status: return None status = status.strip() ret = [] for status in status: ret.append({ 'contents': status, 'highlight_groups': ['file_vcs_status_' + status, 'file_vcs_status'], }) return ret trailing_whitespace_cache = None @requires_segment_info def trailing_whitespace(pl, segment_info): '''Return the line number for trailing whitespaces It is advised not to use this segment in insert mode: in Insert mode it will iterate over all lines in buffer each time you happen to type a character which may cause lags. It will also show you whitespace warning each time you happen to type space. Highlight groups used: ``trailing_whitespace`` or ``warning``. ''' global trailing_whitespace_cache if trailing_whitespace_cache is None: trailing_whitespace_cache = register_buffer_cache(defaultdict(lambda: (0, None))) bufnr = segment_info['bufnr'] changedtick = getbufvar(bufnr, 'changedtick') if trailing_whitespace_cache[bufnr][0] == changedtick: return trailing_whitespace_cache[bufnr][1] else: buf = segment_info['buffer'] bws = b' \t' sws = str(' \t') # Ignore unicode_literals and use native str. for i in range(len(buf)): try: line = buf[i] except UnicodeDecodeError: # May happen in Python 3 if hasattr(vim, 'bindeval'): line = vim.bindeval('getbufline({0}, {1})'.format( bufnr, i + 1)) has_trailing_ws = (line[-1] in bws) else: line = vim.eval('strtrans(getbufline({0}, {1}))'.format( bufnr, i + 1)) has_trailing_ws = (line[-1] in bws) else: has_trailing_ws = (line and line[-1] in sws) if has_trailing_ws: break if has_trailing_ws: ret = [{ 'contents': str(i + 1), 'highlight_groups': ['trailing_whitespace', 'warning'], }] else: ret = None trailing_whitespace_cache[bufnr] = (changedtick, ret) return ret @requires_segment_info def tabnr(pl, segment_info, show_current=True): '''Show tabpage number :param bool show_current: If False do not show current tabpage number. This is default because tabnr is by default only present in tabline. ''' try: tabnr = segment_info['tabnr'] except KeyError: return None if show_current or tabnr != current_tabpage().number: return str(tabnr) @requires_segment_info def bufnr(pl, segment_info, show_current=True): '''Show buffer number :param bool show_current: If False do not show current window number. ''' bufnr = segment_info['bufnr'] if show_current or bufnr != vim.current.buffer.number: return str(bufnr) @requires_segment_info def winnr(pl, segment_info, show_current=True): '''Show window number :param bool show_current: If False do not show current window number. ''' winnr = segment_info['winnr'] if show_current or winnr != vim.current.window.number: return str(winnr) csv_cache = None sniffer = csv.Sniffer() def detect_text_csv_dialect(text, display_name, header_text=None): return ( sniffer.sniff(string(text)), sniffer.has_header(string(header_text or text)) if display_name == 'auto' else display_name, ) CSV_SNIFF_LINES = 100 CSV_PARSE_LINES = 10 if sys.version_info < (2, 7): def read_csv(l, dialect, fin=next): try: return fin(csv.reader(l, dialect)) except csv.Error as e: if str(e) == 'newline inside string' and dialect.quotechar: # Maybe we are inside an unfinished quoted string. Python-2.6 # does not handle this fine return fin(csv.reader(l[:-1] + [l[-1] + dialect.quotechar])) else: raise else: def read_csv(l, dialect, fin=next): return fin(csv.reader(l, dialect)) def process_csv_buffer(pl, buffer, line, col, display_name): global csv_cache if csv_cache is None: csv_cache = register_buffer_cache(defaultdict(lambda: (None, None, None))) try: cur_first_line = buffer[0] except UnicodeDecodeError: cur_first_line = vim.eval('strtrans(getline(1))') dialect, has_header, first_line = csv_cache[buffer.number] if dialect is None or (cur_first_line != first_line and display_name == 'auto'): try: text = '\n'.join(buffer[:CSV_SNIFF_LINES]) except UnicodeDecodeError: # May happen in Python 3 text = vim.eval('join(map(getline(1, {0}), "strtrans(v:val)"), "\\n")'.format(CSV_SNIFF_LINES)) try: dialect, has_header = detect_text_csv_dialect(text, display_name) except csv.Error as e: pl.warn('Failed to detect csv format: {0}', str(e)) # Try detecting using three lines only: if line == 1: rng = (0, line + 2) elif line == len(buffer): rng = (line - 3, line) else: rng = (line - 2, line + 1) try: dialect, has_header = detect_text_csv_dialect( '\n'.join(buffer[rng[0]:rng[1]]), display_name, header_text='\n'.join(buffer[:4]), ) except csv.Error as e: pl.error('Failed to detect csv format: {0}', str(e)) return None, None if len(buffer) > 2: csv_cache[buffer.number] = dialect, has_header, cur_first_line column_number = len(read_csv( buffer[max(0, line - CSV_PARSE_LINES):line - 1] + [buffer[line - 1][:col]], dialect=dialect, fin=list, )[-1]) or 1 if has_header: try: header = read_csv(buffer[0:1], dialect=dialect) except UnicodeDecodeError: header = read_csv([vim.eval('strtrans(getline(1))')], dialect=dialect) column_name = header[column_number - 1] else: column_name = None return unicode(column_number), column_name @requires_segment_info def csv_col_current(pl, segment_info, display_name='auto', name_format=' ({column_name:.15})'): '''Display CSV column number and column name Requires filetype to be set to ``csv``. :param bool or str name: May be ``True``, ``False`` and ``"auto"``. In the first case value from the first raw will always be displayed. In the second case it will never be displayed. In the last case ``csv.Sniffer().has_header()`` will be used to detect whether current file contains header in the first column. :param str name_format: String used to format column name (in case ``display_name`` is set to ``True`` or ``"auto"``). Accepts ``column_name`` keyword argument. Highlight groups used: ``csv:column_number`` or ``csv``, ``csv:column_name`` or ``csv``. ''' if vim_getbufoption(segment_info, 'filetype') != 'csv': return None line, col = segment_info['window'].cursor column_number, column_name = process_csv_buffer(pl, segment_info['buffer'], line, col, display_name) if not column_number: return None return [{ 'contents': column_number, 'highlight_groups': ['csv:column_number', 'csv'], }] + ([{ 'contents': name_format.format(column_name=column_name), 'highlight_groups': ['csv:column_name', 'csv'], }] if column_name else []) @requires_segment_info def tab(pl, segment_info, end=False): '''Mark start of the clickable region for tabpage :param bool end: In place of starting region for the current tab end it. No highlight groups are used (literal segment). ''' try: return [{ 'contents': None, 'literal_contents': (0, '%{tabnr}T'.format(tabnr=('' if end else segment_info['tabnr']))), }] except KeyError: return None powerline-2.8.4/powerline/segments/vim/plugin/000077500000000000000000000000001466405252600214655ustar00rootroot00000000000000powerline-2.8.4/powerline/segments/vim/plugin/__init__.py000066400000000000000000000003001466405252600235670ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from pkgutil import extend_path __path__ = extend_path(__path__, __name__) powerline-2.8.4/powerline/segments/vim/plugin/ale.py000066400000000000000000000030261466405252600226010ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: import vim except ImportError: vim = object() from powerline.bindings.vim import vim_global_exists from powerline.theme import requires_segment_info @requires_segment_info def ale(segment_info, pl, err_format='ERR: ln {first_line} ({num}) ', warn_format='WARN: ln {first_line} ({num}) '): '''Show whether ALE has found any errors or warnings :param str err_format: Format string for errors. :param str warn_format: Format string for warnings. Highlight groups used: ``ale:warning`` or ``warning``, ``ale:error`` or ``error``. ''' if not (vim_global_exists('ale_enabled') and int(vim.eval('g:ale_enabled'))): return None has_errors = int(vim.eval('ale#statusline#Count(' + str(segment_info['bufnr']) + ').total')) if not has_errors: return error = None warning = None errors_count = 0 warnings_count = 0 for issue in vim.eval('ale#engine#GetLoclist(' + str(segment_info['bufnr']) + ')'): if issue['type'] == 'E': error = error or issue errors_count += 1 elif issue['type'] == 'W': warning = warning or issue warnings_count += 1 segments = [] if error: segments.append({ 'contents': err_format.format(first_line=error['lnum'], num=errors_count), 'highlight_groups': ['ale:error', 'error'], }) if warning: segments.append({ 'contents': warn_format.format(first_line=warning['lnum'], num=warnings_count), 'highlight_groups': ['ale:warning', 'warning'], }) return segments powerline-2.8.4/powerline/segments/vim/plugin/capslock.py000066400000000000000000000016541466405252600236440ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: import vim except ImportError: vim = object() from powerline.bindings.vim import vim_func_exists from powerline.theme import requires_segment_info @requires_segment_info def capslock_indicator(pl, segment_info, text='CAPS'): '''Shows the indicator if tpope/vim-capslock plugin is enabled .. note:: In the current state plugin automatically disables itself when leaving insert mode. So trying to use this segment not in insert or replace modes is useless. :param str text: String to show when software capslock presented by this plugin is active. ''' if not vim_func_exists('CapsLockStatusline'): return None # CapsLockStatusline() function returns an empty string when plugin is # disabled. If it is not then string is non-empty. return text if vim.eval('CapsLockStatusline()') else None powerline-2.8.4/powerline/segments/vim/plugin/coc.py000066400000000000000000000027031466405252600226050ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: import vim except ImportError: vim = object() from powerline.bindings.vim import vim_command_exists from powerline.theme import requires_segment_info # coc_status's format: E1 W2 def parse_coc_status(coc_status): # type(coc_status) is tuple errors_count = 0 warnings_count = 0 if len(coc_status) <= 0: return errors_count, warnings_count status_str = coc_status[0] if len(status_str) <= 0: return errors_count, warnings_count status_list = status_str.split(' ') for item in status_list: if len(item) > 0 and item[0] == 'E': errors_count = int(item[1:]) if len(item) > 0 and item[0] == 'W': warnings_count = int(item[1:]) return errors_count, warnings_count @requires_segment_info def coc(segment_info, pl): '''Show whether coc.nvim has found any errors or warnings Highlight groups used: ``coc:warning`` or ``warning``, ``coc:error`` or ``error``. ''' segments = [] if not vim_command_exists('CocCommand'): return segments coc_status = vim.eval('coc#status()'), errors_count, warnings_count = parse_coc_status(coc_status) if errors_count > 0: segments.append({ 'contents': 'E:' + str(errors_count), 'highlight_groups': ['coc:error', 'error'], }) if warnings_count > 0: segments.append({ 'contents': 'W:' + str(warnings_count), 'highlight_groups': ['coc:warning', 'warning'], }) return segments powerline-2.8.4/powerline/segments/vim/plugin/commandt.py000066400000000000000000000051001466405252600236350ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: import vim except ImportError: vim = object() from powerline.bindings.vim import create_ruby_dpowerline def initialize(): global initialized if initialized: return initialized = True create_ruby_dpowerline() vim.command(( # When using :execute (vim.command uses the same code) one should not # use << EOF. ''' ruby if (not ($command_t.respond_to? 'active_finder')) def $command_t.active_finder @active_finder and @active_finder.class.name or '' end end if (not ($command_t.respond_to? 'path')) def $command_t.path @path or '' end end def $powerline.commandt_set_active_finder ::VIM::command "let g:powerline_commandt_reply = '#{$command_t.active_finder}'" end def $powerline.commandt_set_path ::VIM::command "let g:powerline_commandt_reply = '#{($command_t.path or '').gsub(/'/, "''")}'" end ''' )) initialized = False def finder(pl): '''Display Command-T finder name Requires $command_t.active_finder and methods (code above may monkey-patch $command_t to add them). All Command-T finders have ``CommandT::`` module prefix, but it is stripped out (actually, any ``CommandT::`` substring will be stripped out). Highlight groups used: ``commandt:finder``. ''' initialize() vim.command('ruby $powerline.commandt_set_active_finder') return [{ 'highlight_groups': ['commandt:finder'], 'contents': vim.eval('g:powerline_commandt_reply').replace('CommandT::', '').replace('Finder::', '') }] FINDERS_WITHOUT_PATH = set(( 'CommandT::MRUBufferFinder', 'CommandT::BufferFinder', 'CommandT::TagFinder', 'CommandT::JumpFinder', 'CommandT::Finder::MRUBufferFinder', 'CommandT::Finder::BufferFinder', 'CommandT::Finder::TagFinder', 'CommandT::Finder::JumpFinder', )) def path(pl): '''Display path used by Command-T Requires $command_t.active_finder and .path methods (code above may monkey-patch $command_t to add them). $command_t.active_finder is required in order to omit displaying path for finders ``MRUBufferFinder``, ``BufferFinder``, ``TagFinder`` and ``JumpFinder`` (pretty much any finder, except ``FileFinder``). Highlight groups used: ``commandt:path``. ''' initialize() vim.command('ruby $powerline.commandt_set_active_finder') finder = vim.eval('g:powerline_commandt_reply') if finder in FINDERS_WITHOUT_PATH: return None vim.command('ruby $powerline.commandt_set_path') return [{ 'highlight_groups': ['commandt:path'], 'contents': vim.eval('g:powerline_commandt_reply') }] powerline-2.8.4/powerline/segments/vim/plugin/nerdtree.py000066400000000000000000000012051466405252600236450ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: import vim except ImportError: vim = object() from powerline.bindings.vim import bufvar_exists from powerline.segments.vim import window_cached @window_cached def nerdtree(pl): '''Return directory that is shown by the current buffer. Highlight groups used: ``nerdtree:path`` or ``file_name``. ''' if not bufvar_exists(None, 'NERDTreeRoot'): return None path_str = vim.eval('getbufvar("%", "NERDTreeRoot").path.str()') return [{ 'contents': path_str, 'highlight_groups': ['nerdtree:path', 'file_name'], }] powerline-2.8.4/powerline/segments/vim/plugin/syntastic.py000066400000000000000000000025211466405252600240600ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: import vim except ImportError: vim = object() from powerline.segments.vim import window_cached from powerline.bindings.vim import vim_global_exists @window_cached def syntastic(pl, err_format='ERR:  {first_line} ({num}) ', warn_format='WARN:  {first_line} ({num}) '): '''Show whether syntastic has found any errors or warnings :param str err_format: Format string for errors. :param str warn_format: Format string for warnings. Highlight groups used: ``syntastic:warning`` or ``warning``, ``syntastic:error`` or ``error``. ''' if not vim_global_exists('SyntasticLoclist'): return None has_errors = int(vim.eval('g:SyntasticLoclist.current().hasErrorsOrWarningsToDisplay()')) if not has_errors: return errors = vim.eval('g:SyntasticLoclist.current().errors()') warnings = vim.eval('g:SyntasticLoclist.current().warnings()') segments = [] if errors: segments.append({ 'contents': err_format.format(first_line=errors[0]['lnum'], num=len(errors)), 'highlight_groups': ['syntastic:error', 'error'], }) if warnings: segments.append({ 'contents': warn_format.format(first_line=warnings[0]['lnum'], num=len(warnings)), 'highlight_groups': ['syntastic:warning', 'warning'], }) return segments powerline-2.8.4/powerline/segments/vim/plugin/tagbar.py000066400000000000000000000026171466405252600233050ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: import vim except ImportError: vim = object() from powerline.bindings.vim import vim_command_exists, vim_get_autoload_func from powerline.theme import requires_segment_info currenttag = None tag_cache = {} @requires_segment_info def current_tag(segment_info, pl, flags='s'): '''Return tag that is near the cursor. :param str flags: Specifies additional properties of the displayed tag. Supported values: * s - display complete signature * f - display the full hierarchy of the tag * p - display the raw prototype More info in the `official documentation`_ (search for “tagbar#currenttag”). .. _`official documentation`: https://github.com/majutsushi/tagbar/blob/master/doc/tagbar.txt ''' global currenttag global tag_cache window_id = segment_info['window_id'] if segment_info['mode'] == 'nc': return tag_cache.get(window_id, (None,))[-1] if not currenttag: if vim_command_exists('Tagbar'): currenttag = vim_get_autoload_func('tagbar#currenttag') if not currenttag: return None else: return None prev_key, r = tag_cache.get(window_id, (None, None)) key = (int(vim.eval('b:changedtick')), segment_info['window'].cursor[0]) if prev_key and key == prev_key: return r r = currenttag('%s', '', flags) tag_cache[window_id] = (key, r) return r powerline-2.8.4/powerline/selectors/000077500000000000000000000000001466405252600175525ustar00rootroot00000000000000powerline-2.8.4/powerline/selectors/__init__.py000066400000000000000000000000001466405252600216510ustar00rootroot00000000000000powerline-2.8.4/powerline/selectors/vim.py000066400000000000000000000004461466405252600207230ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from powerline.bindings.vim import list_tabpages def single_tab(pl, segment_info, mode): '''Returns True if Vim has only one tab opened ''' return len(list_tabpages()) == 1 powerline-2.8.4/powerline/shell.py000066400000000000000000000021171466405252600172310ustar00rootroot00000000000000# 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 ShellPowerline(Powerline): def init(self, args, **kwargs): self.args = args super(ShellPowerline, self).init(args.ext[0], args.renderer_module, **kwargs) def load_main_config(self): r = super(ShellPowerline, self).load_main_config() if self.args.config_override: mergedicts(r, self.args.config_override) return r def load_theme_config(self, name): r = super(ShellPowerline, self).load_theme_config(name) if self.args.theme_override and name in self.args.theme_override: mergedicts(r, self.args.theme_override[name]) return r def get_config_paths(self): return self.args.config_path or super(ShellPowerline, self).get_config_paths() 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() )) def do_setup(self, obj): obj.powerline = self powerline-2.8.4/powerline/theme.py000066400000000000000000000124651466405252600172330ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import itertools from powerline.segment import gen_segment_getter, process_segment, get_fallback_segment from powerline.lib.unicode import u, safe_unicode def requires_segment_info(func): func.powerline_requires_segment_info = True return func def requires_filesystem_watcher(func): func.powerline_requires_filesystem_watcher = True return func def new_empty_segment_line(): return { 'left': [], 'right': [] } def add_spaces_left(pl, amount, segment): return (' ' * amount) + segment['contents'] def add_spaces_right(pl, amount, segment): return segment['contents'] + (' ' * amount) def add_spaces_center(pl, amount, segment): amount, remainder = divmod(amount, 2) return (' ' * (amount + remainder)) + segment['contents'] + (' ' * amount) expand_functions = { 'l': add_spaces_right, 'r': add_spaces_left, 'c': add_spaces_center, } class Theme(object): def __init__(self, ext, theme_config, common_config, pl, get_module_attr, top_theme, colorscheme, main_theme_config=None, run_once=False, shutdown_event=None): self.colorscheme = colorscheme self.dividers = theme_config['dividers'] self.dividers = dict(( (key, dict((k, u(v)) for k, v in val.items())) for key, val in self.dividers.items() )) try: self.cursor_space_multiplier = 1 - (theme_config['cursor_space'] / 100) except KeyError: self.cursor_space_multiplier = None self.cursor_columns = theme_config.get('cursor_columns') self.spaces = theme_config['spaces'] self.outer_padding = int(theme_config.get('outer_padding', 1)) self.segments = [] self.EMPTY_SEGMENT = { 'contents': None, 'highlight': {'fg': False, 'bg': False, 'attrs': 0} } self.pl = pl theme_configs = [theme_config] if main_theme_config: theme_configs.append(main_theme_config) get_segment = gen_segment_getter( pl, ext, common_config, theme_configs, theme_config.get('default_module'), get_module_attr, top_theme ) for segdict in itertools.chain((theme_config['segments'],), theme_config['segments'].get('above', ())): self.segments.append(new_empty_segment_line()) for side in ['left', 'right']: for segment in segdict.get(side, []): segment = get_segment(segment, side) if segment: if not run_once: if segment['startup']: try: segment['startup'](pl, shutdown_event) except Exception as e: pl.error('Exception during {0} startup: {1}', segment['name'], str(e)) continue self.segments[-1][side].append(segment) def shutdown(self): for line in self.segments: for segments in line.values(): for segment in segments: try: segment['shutdown']() except TypeError: pass def get_divider(self, side='left', type='soft'): '''Return segment divider.''' return self.dividers[side][type] def get_spaces(self): return self.spaces def get_line_number(self): return len(self.segments) def get_segments(self, side=None, line=0, segment_info=None, mode=None): '''Return all segments. Function segments are called, and all segments get their before/after and ljust/rjust properties applied. :param int line: Line number for which segments should be obtained. Is counted from zero (botmost line). ''' for side in [side] if side else ['left', 'right']: parsed_segments = [] for segment in self.segments[line][side]: if segment['display_condition'](self.pl, segment_info, mode): process_segment( self.pl, side, segment_info, parsed_segments, segment, mode, self.colorscheme, ) for segment in parsed_segments: self.pl.prefix = segment['name'] try: width = segment['width'] align = segment['align'] if width == 'auto' and segment['expand'] is None: segment['expand'] = expand_functions.get(align) if segment['expand'] is None: self.pl.error('Align argument must be “r”, “l” or “c”, not “{0}”', align) try: segment['contents'] = segment['before'] + u( segment['contents'] if segment['contents'] is not None else '' ) + segment['after'] except Exception as e: self.pl.exception('Failed to compute segment contents: {0}', str(e)) segment['contents'] = safe_unicode(segment.get('contents')) # Align segment contents if segment['width'] and segment['width'] != 'auto': if segment['align'] == 'l': segment['contents'] = segment['contents'].ljust(segment['width']) elif segment['align'] == 'r': segment['contents'] = segment['contents'].rjust(segment['width']) elif segment['align'] == 'c': segment['contents'] = segment['contents'].center(segment['width']) # We need to yield a copy of the segment, or else mode-dependent # segment contents can’t be cached correctly e.g. when caching # non-current window contents for vim statuslines yield segment.copy() except Exception as e: self.pl.exception('Failed to compute segment: {0}', str(e)) fallback = get_fallback_segment() fallback.update(side=side) yield fallback powerline-2.8.4/powerline/version.py000066400000000000000000000002621466405252600176060ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) __version__ = "2.8.4" def get_version(): return __version__ powerline-2.8.4/powerline/vim.py000066400000000000000000000266551466405252600167320ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import json import logging from itertools import count try: import vim except ImportError: vim = object() from powerline.bindings.vim import vim_get_func, vim_getvar, get_vim_encoding, python_to_vim from powerline import Powerline, FailedUnicode, finish_common_config from powerline.lib.dict import mergedicts from powerline.lib.unicode import u def _override_from(config, override_varname, key=None): try: overrides = vim_getvar(override_varname) except KeyError: return config if key is not None: try: overrides = overrides[key] except KeyError: return config mergedicts(config, overrides) return config class VimVarHandler(logging.Handler, object): '''Vim-specific handler which emits messages to Vim global variables :param str varname: Variable where ''' def __init__(self, varname): super(VimVarHandler, self).__init__() utf_varname = u(varname) self.vim_varname = utf_varname.encode('ascii') vim.command('unlet! g:' + utf_varname) vim.command('let g:' + utf_varname + ' = []') def emit(self, record): message = u(record.message) if record.exc_text: message += '\n' + u(record.exc_text) vim.eval(b'add(g:' + self.vim_varname + b', ' + python_to_vim(message) + b')') class VimPowerline(Powerline): def init(self, pyeval='PowerlinePyeval', **kwargs): super(VimPowerline, self).init('vim', **kwargs) self.last_window_id = 1 self.pyeval = pyeval self.construct_window_statusline = self.create_window_statusline_constructor() if all((hasattr(vim.current.window, attr) for attr in ('options', 'vars', 'number'))): self.win_idx = self.new_win_idx else: self.win_idx = self.old_win_idx self._vim_getwinvar = vim_get_func('getwinvar', 'bytes') self._vim_setwinvar = vim_get_func('setwinvar') if sys.version_info < (3,): def create_window_statusline_constructor(self): window_statusline = b'%!' + str(self.pyeval) + b'(\'powerline.statusline({0})\')' return window_statusline.format else: def create_window_statusline_constructor(self): startstr = b'%!' + self.pyeval.encode('ascii') + b'(\'powerline.statusline(' endstr = b')\')' return lambda idx: ( startstr + str(idx).encode('ascii') + endstr ) create_window_statusline_constructor.__doc__ = ( '''Create function which returns &l:stl value being given window index Created function must return :py:class:`bytes` instance because this is what ``window.options['statusline']`` returns (``window`` is :py:class:`vim.Window` instance). :return: Function with type ``int → bytes``. ''' ) default_log_stream = sys.stdout def add_local_theme(self, key, config): '''Add local themes at runtime (during vim session). :param str key: Matcher name (in format ``{matcher_module}.{module_attribute}`` or ``{module_attribute}`` if ``{matcher_module}`` is ``powerline.matchers.vim``). Function pointed by ``{module_attribute}`` should be hashable and accept a dictionary with information about current buffer and return boolean value indicating whether current window matched conditions. See also :ref:`local_themes key description `. :param dict config: :ref:`Theme ` dictionary. :return: ``True`` if theme was added successfully and ``False`` if theme with the same matcher already exists. ''' self.update_renderer() matcher = self.get_matcher(key) theme_config = {} for cfg_path in self.theme_levels: try: lvl_config = self.load_config(cfg_path, 'theme') except IOError: pass else: mergedicts(theme_config, lvl_config) mergedicts(theme_config, config) try: self.renderer.add_local_theme(matcher, {'config': theme_config}) except KeyError: return False else: # Hack for local themes support: when reloading modules it is not # guaranteed that .add_local_theme will be called once again, so # this function arguments will be saved here for calling from # .do_setup(). self.setup_kwargs.setdefault('_local_themes', []).append((key, config)) return True get_encoding = staticmethod(get_vim_encoding) def load_main_config(self): main_config = _override_from(super(VimPowerline, self).load_main_config(), 'powerline_config_overrides') try: use_var_handler = bool(int(vim_getvar('powerline_use_var_handler'))) except KeyError: use_var_handler = False if use_var_handler: main_config.setdefault('common', {}) main_config['common'] = finish_common_config(self.get_encoding(), main_config['common']) main_config['common']['log_file'].append(['powerline.vim.VimVarHandler', [['powerline_log_messages']]]) return main_config def load_theme_config(self, name): return _override_from( super(VimPowerline, self).load_theme_config(name), 'powerline_theme_overrides', name ) def get_local_themes(self, local_themes): if not local_themes: return {} return dict(( (matcher, {'config': self.load_theme_config(val)}) for matcher, key, val in ( ( (None if k == '__tabline__' else self.get_matcher(k)), k, v ) for k, v in local_themes.items() ) if ( matcher or key == '__tabline__' ) )) def get_matcher(self, match_name): match_module, separator, match_function = match_name.rpartition('.') if not separator: match_module = 'powerline.matchers.{0}'.format(self.ext) match_function = match_name return self.get_module_attr(match_module, match_function, prefix='matcher_generator') def get_config_paths(self): try: return vim_getvar('powerline_config_paths') except KeyError: return super(VimPowerline, self).get_config_paths() def do_setup(self, pyeval=None, pycmd=None, can_replace_pyeval=True, _local_themes=()): import __main__ if not pyeval: pyeval = 'pyeval' if sys.version_info < (3,) else 'py3eval' can_replace_pyeval = True if not pycmd: pycmd = get_default_pycmd() set_pycmd(pycmd) # pyeval() and vim.bindeval were both introduced in one patch if (not hasattr(vim, 'bindeval') and can_replace_pyeval) or pyeval == 'PowerlinePyeval': vim.command((''' function! PowerlinePyeval(e) {pycmd} powerline.do_pyeval() endfunction ''').format(pycmd=pycmd)) pyeval = 'PowerlinePyeval' self.pyeval = pyeval self.construct_window_statusline = self.create_window_statusline_constructor() self.update_renderer() __main__.powerline = self try: if ( bool(int(vim.eval('has(\'gui_running\') && argc() == 0'))) and not vim.current.buffer.name and len(vim.windows) == 1 ): # Hack to show startup screen. Problems in GUI: # - Defining local value of &statusline option while computing # global value purges startup screen. # - Defining highlight group while computing statusline purges # startup screen. # This hack removes the “while computing statusline” part: both # things are defined, but they are defined right now. # # The above condition disables this hack if no GUI is running, # Vim did not open any files and there is only one window. # Without GUI everything works, in other cases startup screen is # not shown. self.new_window() except UnicodeDecodeError: # vim.current.buffer.name may raise UnicodeDecodeError when using # Python-3*. Fortunately, this means that current buffer is not # empty buffer, so the above condition should be False. pass # Cannot have this in one line due to weird newline handling (in :execute # context newline is considered part of the command in just the same cases # when bar is considered part of the command (unless defining function # inside :execute)). vim.command is :execute equivalent regarding this case. vim.command('augroup Powerline') vim.command(' autocmd! ColorScheme * :{pycmd} powerline.reset_highlight()'.format(pycmd=pycmd)) vim.command(' autocmd! VimLeavePre * :{pycmd} powerline.shutdown()'.format(pycmd=pycmd)) vim.command('augroup END') # Hack for local themes support after reloading. for args in _local_themes: self.add_local_theme(*args) def reset_highlight(self): try: self.renderer.reset_highlight() except AttributeError: # Renderer object appears only after first `.render()` call. Thus if # ColorScheme event happens before statusline is drawn for the first # time AttributeError will be thrown for the self.renderer. It is # fine to ignore it: no renderer == no colors to reset == no need to # do anything. pass def new_win_idx(self, window_id): r = None for window in vim.windows: try: curwindow_id = window.vars['powerline_window_id'] if r is not None and curwindow_id == window_id: raise KeyError except KeyError: curwindow_id = self.last_window_id self.last_window_id += 1 window.vars['powerline_window_id'] = curwindow_id statusline = self.construct_window_statusline(curwindow_id) if window.options['statusline'] != statusline: window.options['statusline'] = statusline if curwindow_id == window_id if window_id else window is vim.current.window: r = (window, curwindow_id, window.number) return r def old_win_idx(self, window_id): r = None for winnr, window in zip(count(1), vim.windows): curwindow_id = self._vim_getwinvar(winnr, 'powerline_window_id') if curwindow_id and not (r is not None and curwindow_id == window_id): curwindow_id = int(curwindow_id) else: curwindow_id = self.last_window_id self.last_window_id += 1 self._vim_setwinvar(winnr, 'powerline_window_id', curwindow_id) statusline = self.construct_window_statusline(curwindow_id) if self._vim_getwinvar(winnr, '&statusline') != statusline: self._vim_setwinvar(winnr, '&statusline', statusline) if curwindow_id == window_id if window_id else window is vim.current.window: r = (window, curwindow_id, winnr) return r def statusline(self, window_id): window, window_id, winnr = self.win_idx(window_id) or (None, None, None) if not window: return FailedUnicode('No window {0}'.format(window_id)) return self.render(window, window_id, winnr) def tabline(self): r = self.win_idx(None) if r: return self.render(*r, is_tabline=True) else: win = vim.current.window r = ( win, win.vars.get('powerline_window_id', self.last_window_id), win.number, ) return self.render(*r, is_tabline=True) def new_window(self): return self.render(*self.win_idx(None)) @staticmethod def do_pyeval(): '''Evaluate python string passed to PowerlinePyeval Is here to reduce the number of requirements to __main__ globals to just one powerline object (previously it required as well vim and json). ''' import __main__ vim.command('return ' + json.dumps(eval(vim.eval('a:e'), __main__.__dict__))) def setup_components(self, components): if components is None: components = ('statusline', 'tabline') if 'statusline' in components: # Is immediately changed after new_window function is run. Good for # global value. vim.command('set statusline=%!{pyeval}(\'powerline.new_window()\')'.format( pyeval=self.pyeval)) if 'tabline' in components: vim.command('set tabline=%!{pyeval}(\'powerline.tabline()\')'.format( pyeval=self.pyeval)) pycmd = None def set_pycmd(new_pycmd): global pycmd pycmd = new_pycmd def get_default_pycmd(): return 'python' if sys.version_info < (3,) else 'python3' def setup(*args, **kwargs): powerline = VimPowerline() return powerline.setup(*args, **kwargs) powerline-2.8.4/scripts/000077500000000000000000000000001466405252600152325ustar00rootroot00000000000000powerline-2.8.4/scripts/.gitignore000066400000000000000000000000121466405252600172130ustar00rootroot00000000000000powerline powerline-2.8.4/scripts/powerline-config000077500000000000000000000011111466405252600204210ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) try: from powerline.commands.config import get_argparser except ImportError: import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__))))) from powerline.commands.config import get_argparser import powerline.bindings.config as config if __name__ == '__main__': parser = get_argparser() args = parser.parse_args() pl = config.create_powerline_logger(args) args.function(pl, args) powerline-2.8.4/scripts/powerline-daemon000077500000000000000000000310131466405252600204230ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import socket import os import errno import sys import fcntl import atexit import stat from argparse import ArgumentParser from select import select from signal import signal, SIGTERM from time import sleep from functools import partial from io import BytesIO from threading import Event from itertools import chain from logging import StreamHandler from powerline.shell import ShellPowerline from powerline.commands.main import finish_args, write_output from powerline.lib.monotonic import monotonic from powerline.lib.encoding import get_preferred_output_encoding, get_preferred_arguments_encoding, get_unicode_writer from powerline.bindings.wm import wm_threads from powerline.commands.main import get_argparser as get_main_argparser from powerline.commands.daemon import get_argparser as get_daemon_argparser USE_FILESYSTEM = not sys.platform.lower().startswith('linux') class NonInteractiveArgParser(ArgumentParser): def print_usage(self, file=None): raise Exception(self.format_usage()) def print_help(self, file=None): raise Exception(self.format_help()) def exit(self, status=0, message=None): pass def error(self, message): raise Exception(self.format_usage()) EOF = b'EOF\0\0' class State(object): __slots__ = ('powerlines', 'logger', 'config_loader', 'started_wm_threads', 'ts_shutdown_event') def __init__(self, **kwargs): self.logger = None self.config_loader = None self.started_wm_threads = {} self.powerlines = {} self.ts_shutdown_event = Event() HOME = os.path.expanduser('~') class NonDaemonShellPowerline(ShellPowerline): def get_log_handler(self): return StreamHandler() def start_wm(args, environ, cwd, is_daemon, state): wm_name = args.ext[0][3:] if wm_name in state.started_wm_threads: return b'' thread_shutdown_event = Event() thread = wm_threads[wm_name]( thread_shutdown_event=thread_shutdown_event, pl_shutdown_event=state.ts_shutdown_event, pl_config_loader=state.config_loader, ) thread.start() state.started_wm_threads[wm_name] = (thread, thread_shutdown_event) return b'' def render(args, environ, cwd, is_daemon, state): segment_info = { 'getcwd': lambda: cwd, 'home': environ.get('HOME', HOME), 'environ': environ, 'args': args, } key = ( args.ext[0], args.renderer_module, tuple(args.config_override) if args.config_override else None, tuple(args.theme_override) if args.theme_override else None, tuple(args.config_path) if args.config_path else None, environ.get('POWERLINE_THEME_OVERRIDES', ''), environ.get('POWERLINE_CONFIG_OVERRIDES', ''), environ.get('POWERLINE_CONFIG_PATHS', ''), ) PowerlineClass = ShellPowerline if is_daemon else NonDaemonShellPowerline powerline = None try: powerline = state.powerlines[key] except KeyError: try: powerline = state.powerlines[key] = PowerlineClass( args, logger=state.logger, config_loader=state.config_loader, run_once=False, shutdown_event=state.ts_shutdown_event, ) if state.logger is None: state.logger = powerline.logger if state.config_loader is None: state.config_loader = powerline.config_loader except SystemExit: # Somebody thought raising system exit was a good idea, return '' except Exception as e: if powerline: powerline.pl.exception('Failed to render {0}: {1}', str(key), str(e)) else: return 'Failed to render {0}: {1}'.format(str(key), str(e)) s = BytesIO() write_output(args, powerline, segment_info, get_unicode_writer(stream=s)) s.seek(0) return s.read() 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 def do_read(conn, timeout=2.0): ''' Read data from the client. If the client fails to send data within timeout seconds, abort. ''' read = [] end_time = monotonic() + timeout while not read or not read[-1].endswith(b'\0\0'): r, w, e = select((conn,), (), (conn,), timeout) if e: return if monotonic() > end_time: return if not r: continue x = eintr_retry_call(conn.recv, 4096) if x: read.append(x) else: break return b''.join(read) def do_write(conn, result): try: eintr_retry_call(conn.sendall, result) except Exception: pass def safe_bytes(o, encoding=get_preferred_output_encoding()): '''Return bytes instance without ever throwing an exception.''' try: try: # We are assuming that o is a unicode object return o.encode(encoding, 'replace') except Exception: # Object may have defined __bytes__ (python 3) or __str__ method # (python 2) # This also catches problem with non_ascii_bytes.encode('utf-8') # that first tries to decode to UTF-8 using ascii codec (and fails # in this case) and then encode to given encoding: errors= argument # is not used in the first stage. return bytes(o) except Exception as e: return safe_bytes(str(e), encoding) def parse_args(req, parser, encoding=get_preferred_arguments_encoding()): args = [x.decode(encoding) for x in req.split(b'\0') if x] numargs = int(args[0], 16) shell_args = parser.parse_args(args[1:numargs + 1]) cwd = args[numargs + 1] environ = dict(((k, v) for k, v in (x.partition('=')[0::2] for x in args[numargs + 2:]))) cwd = cwd or environ.get('PWD', '/') return shell_args, environ, cwd def get_answer(req, is_daemon, argparser, state): try: args, environ, cwd = parse_args(req, argparser) finish_args(argparser, environ, args, is_daemon=True) if args.ext[0].startswith('wm.'): return safe_bytes(start_wm(args, environ, cwd, is_daemon, state)) else: return safe_bytes(render(args, environ, cwd, is_daemon, state)) except Exception as e: return safe_bytes(str(e)) def do_one(sock, read_sockets, write_sockets, result_map, is_daemon, argparser, state): r, w, e = select( tuple(read_sockets) + (sock,), tuple(write_sockets), tuple(read_sockets) + tuple(write_sockets) + (sock,), 60.0 ) if sock in e: # We cannot accept any more connections, so we exit raise SystemExit(1) for s in e: # Discard all broken connections to clients s.close() read_sockets.discard(s) write_sockets.discard(s) for s in r: if s == sock: # A client wants to connect conn, _ = eintr_retry_call(sock.accept) read_sockets.add(conn) else: # A client has sent some data read_sockets.discard(s) req = do_read(s) if req == EOF: raise SystemExit(0) elif req: ans = get_answer(req, is_daemon, argparser, state) result_map[s] = ans write_sockets.add(s) else: s.close() for s in w: # A client is ready to receive the result write_sockets.discard(s) result = result_map.pop(s) try: do_write(s, result) finally: s.close() def shutdown(sock, read_sockets, write_sockets, state): '''Perform operations necessary for nicely shutting down daemon Specifically it #. Closes all sockets. #. Notifies segments based on :py:class:`powerline.lib.threaded.ThreadedSegment` and WM-specific threads that daemon is shutting down. #. Waits for threads to finish, but no more then 2 seconds total. #. Waits so that total execution time of this function is 2 seconds in order to allow ThreadedSegments to finish. ''' total_wait_time = 2 shutdown_start_time = monotonic() for s in chain((sock,), read_sockets, write_sockets): s.close() # Notify ThreadedSegments state.ts_shutdown_event.set() for thread, shutdown_event in state.started_wm_threads.values(): shutdown_event.set() for thread, shutdown_event in state.started_wm_threads.values(): wait_time = total_wait_time - (monotonic() - shutdown_start_time) if wait_time > 0: thread.join(wait_time) wait_time = total_wait_time - (monotonic() - shutdown_start_time) sleep(wait_time) def main_loop(sock, is_daemon): sock.listen(128) sock.setblocking(0) read_sockets, write_sockets = set(), set() result_map = {} parser = get_main_argparser(NonInteractiveArgParser) state = State() try: try: while True: do_one( sock, read_sockets, write_sockets, result_map, is_daemon=is_daemon, argparser=parser, state=state, ) except KeyboardInterrupt: raise SystemExit(0) except SystemExit as e: shutdown(sock, read_sockets, write_sockets, state) raise e return 0 def daemonize(stdin=os.devnull, stdout=os.devnull, stderr=os.devnull): try: pid = os.fork() if pid > 0: # exit first parent raise SystemExit(0) except OSError as e: sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) raise SystemExit(1) # decouple from parent environment os.chdir("/") os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent raise SystemExit(0) except OSError as e: sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) raise SystemExit(1) # Redirect standard file descriptors. si = open(stdin, 'rb') so = open(stdout, 'a+b') se = open(stderr, 'a+b', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) return True def check_existing(address): if USE_FILESYSTEM: # We cannot bind if the socket file already exists so remove it, we # already have a lock on pidfile, so this should be safe. try: os.unlink(address) except EnvironmentError: pass sock = socket.socket(family=socket.AF_UNIX) try: sock.bind(address) except socket.error as e: if getattr(e, 'errno', None) == errno.EADDRINUSE: return None raise return sock def kill_daemon(address): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: try: eintr_retry_call(sock.connect, address) except socket.error: return False else: eintr_retry_call(sock.sendall, EOF) finally: sock.close() return True def cleanup_lockfile(pidfile, fd, *args): try: # Remove the directory entry for the lock file os.unlink(pidfile) # Close the file descriptor os.close(fd) except EnvironmentError: pass if args: # Called in signal handler raise SystemExit(1) def lockpidfile(pidfile): fd = os.open( pidfile, os.O_WRONLY | os.O_CREAT, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH ) try: fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) except EnvironmentError: os.close(fd) return None os.lseek(fd, 0, os.SEEK_SET) os.ftruncate(fd, 0) os.write(fd, ('%d' % os.getpid()).encode('ascii')) os.fsync(fd) cleanup = partial(cleanup_lockfile, pidfile, fd) signal(SIGTERM, cleanup) atexit.register(cleanup) return fd def main(): parser = get_daemon_argparser() args = parser.parse_args() is_daemon = False address = None pidfile = None if args.socket: address = args.socket if not USE_FILESYSTEM: address = '\0' + address else: if USE_FILESYSTEM: address = '/tmp/powerline-ipc-%d' else: # Use the abstract namespace for sockets rather than the filesystem # (Available only in linux) address = '\0powerline-ipc-%d' address = address % os.getuid() if USE_FILESYSTEM: pidfile = address + '.pid' if args.kill: if args.foreground or args.replace: parser.error('--kill and --foreground/--replace cannot be used together') if kill_daemon(address): if not args.quiet: print ('Kill command sent to daemon, if it does not die in a couple of seconds use kill to kill it') raise SystemExit(0) else: if not args.quiet: print ('No running daemon found') raise SystemExit(1) if args.replace: while kill_daemon(address): if not args.quiet: print ('Kill command sent to daemon, waiting for daemon to exit, press Ctrl-C to terminate wait and exit') sleep(2) if USE_FILESYSTEM and not args.foreground: # We must daemonize before creating the locked pidfile, unfortunately, # this means further print statements are discarded is_daemon = daemonize() if USE_FILESYSTEM: # Create a locked pid file containing the daemon’s PID if lockpidfile(pidfile) is None: if not args.quiet: sys.stderr.write( 'The daemon is already running. Use %s -k to kill it.\n' % ( os.path.basename(sys.argv[0]))) raise SystemExit(1) # Bind to address or bail if we cannot bind sock = check_existing(address) if sock is None: if not args.quiet: sys.stderr.write( 'The daemon is already running. Use %s -k to kill it.\n' % ( os.path.basename(sys.argv[0]))) raise SystemExit(1) if not USE_FILESYSTEM and not args.foreground: # We daemonize on linux is_daemon = daemonize() return main_loop(sock, is_daemon) if __name__ == '__main__': main() powerline-2.8.4/scripts/powerline-lint000077500000000000000000000005321466405252600201300ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys from powerline.lint import check from powerline.commands.lint import get_argparser if __name__ == '__main__': args = get_argparser().parse_args() sys.exit(check(args.config_path, args.debug)) powerline-2.8.4/scripts/powerline-release.py000077500000000000000000000203521466405252600212330ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import argparse import codecs import os import re from subprocess import check_output, check_call, CalledProcessError from getpass import getpass from github import Github OVERLAY_NAME = 'raiagent' OVERLAY = 'leycec/' + OVERLAY_NAME OVERLAY_BRANCH_FORMAT = 'powerline-release-{0}' def parse_version(s): if s == ('+' * len(s)): try: last_version = next(iter(sorted([ tuple(map(int, tag.split('.'))) for tag in check_output(['git', 'tag', '-l', '[0-9]*.*']).split('\n')[:-1] ], reverse=True))) except StopIteration: raise ValueError('No existing versions found') version = [] for i in range(len(s) - 1): try: version.append(last_version[i]) except IndexError: version.append(0) try: version.append(last_version[len(s) - 1] + 1) except IndexError: version.append(1) if len(version) == 1: version.append(0) return tuple(version) else: return tuple(map(int, s.split('.'))) def setup_py_filter(filter_func): with codecs.open('.setup.py.new', 'w', encoding='utf-8') as NS: with codecs.open('setup.py', 'r', encoding='utf-8') as OS: for line in OS: line = filter_func(line) NS.write(line) os.unlink('setup.py') os.rename('.setup.py.new', 'setup.py') def setup_py_develop_filter(line, version_string): if line.startswith('\tbase_version = '): line = '\tbase_version = \'' + version_string + '\'\n' return line def setup_py_master_filter(line, version_string): if line.startswith('\tversion='): line = '\tversion=\'' + version_string + '\',\n' elif 'Development Status' in line: line = '\t\t\'Development Status :: 5 - Production/Stable\',\n' return line def merge(version_string, rev, **kwargs): check_call(['git', 'checkout', rev]) temp_branch_name = 'release-' + version_string check_call(['git', 'checkout', '-b', temp_branch_name]) setup_py_filter(lambda line: setup_py_develop_filter(line, version_string)) check_call(['git', 'add', 'setup.py']) check_call(['git', 'commit', '-m', 'Update base version']) check_call(['git', 'checkout', rev]) check_call(['git', 'merge', '--no-ff', '--strategy', 'recursive', '--strategy-option', 'theirs', '--commit', '-m', 'Merge branch \'{0}\' into {1}'.format(temp_branch_name, rev), temp_branch_name]) check_call(['git', 'branch', '-d', temp_branch_name]) rev = check_output(['git', 'rev-parse', 'HEAD']).strip() check_call(['git', 'checkout', 'master']) try: check_call(['git', 'merge', '--no-ff', '--no-commit', '--log', rev]) except CalledProcessError: check_call(['git', 'mergetool', '--tool', 'vimdiff2']) setup_py_filter(lambda line: setup_py_master_filter(line, version_string)) check_call(['git', 'add', 'setup.py']) check_call(['git', 'commit']) check_call(['git', 'tag', '-m', 'Release ' + version_string, '-a', version_string]) def push(version_string, rev, **kwargs): check_call(['git', 'push', 'upstream', 'master']) check_call(['git', 'push', 'upstream', version_string]) check_call(['git', 'push', 'upstream', rev]) def upload(**args): check_call(['python', 'setup.py', 'sdist', 'upload']) check_call(['python', 'setup.py', 'upload_docs']) gh = None def get_gh(user, password): global gh if not gh: gh = Github(user, password) return gh def create_ebuilds(version_string, overlay, user, **kwargs): overlay_url = 'git://github.com/' + OVERLAY if not os.path.isdir(overlay): check_call(['git', 'clone', overlay_url, overlay]) check_call(['git', 'checkout', 'master'], cwd=overlay) check_call(['git', 'pull', '--ff-only', overlay_url, 'master'], cwd=overlay) branch = OVERLAY_BRANCH_FORMAT.format(version_string) check_call(['git', 'branch', branch], cwd=overlay) check_call(['git', 'checkout', branch], cwd=overlay) os.environ['DISTDIR'] = '/tmp/powerline-distfiles' if not os.path.isdir(os.environ['DISTDIR']): os.mkdir(os.environ['DISTDIR']) new_files = [] for category, pn in ( ('app-misc', 'powerline'), ('app-vim', 'powerline-vim'), ): pdir = os.path.join(overlay, category, pn) live_ebuild = None for ebuild in os.listdir(pdir): if ebuild.endswith('.ebuild') and '9999' in ebuild: live_ebuild_base = ebuild live_ebuild = os.path.join(pdir, ebuild) break assert(live_ebuild) vcur = os.path.join(pdir, '{0}-{1}.ebuild'.format(pn, version_string)) if pn == 'powerline-vim': with open(live_ebuild) as LEF: with open(vcur, 'w') as F: dropnext = False for line in LEF: if line.startswith('EGIT'): # Drop all EGIT_… and the next empty line dropnext = True next_re = re.compile('^$') continue if dropnext: assert(next_re.match(line)) dropnext = False continue if line.startswith('# Note the lack of an assignment to ${S}'): next_re = re.compile('^#') dropnext = True line = 'S="${WORKDIR}/${MY_P}"\n' if line.startswith('inherit'): line = line.replace(' git-r3', '') line += '\n' line += 'MY_PN="powerline-status"\n' line += 'MY_P="${MY_PN}-${PV}"' line += '\n' elif line.startswith('HOMEPAGE'): line += 'SRC_URI="mirror://pypi/p/${MY_PN}/${MY_P}.tar.gz"\n' elif line.startswith('KEYWORDS'): line = 'KEYWORDS="~amd64 ~ppc ~x86 ~x86-fbsd"\n' F.write(line) else: os.symlink(live_ebuild_base, vcur) new_files.append(vcur) check_call(['ebuild', vcur, 'manifest']) new_files.append(os.path.join(pdir, 'Manifest')) check_call(['git', 'add', '--'] + new_files, cwd=overlay) check_call(['git', 'commit'] + new_files + ['-m', 'powerline*: Release {0}'.format(version_string)], cwd=overlay) check_call(['git', 'push', '-f', 'git@github.com:{0}/{1}'.format(user, OVERLAY_NAME), branch], cwd=overlay) def update_overlay(version_string, user, password, **kwargs): gh = get_gh(user, password) overlay = gh.get_repo(OVERLAY) overlay.create_pull( title='New powerline version: ' + version_string, body='Add ebuilds for new powerline version\n\n---\n\nCreated automatically by release script', base='master', head=user + ':' + OVERLAY_BRANCH_FORMAT.format(version_string), ) stages = ( ('merge', merge), ('push', push), ('upload', upload), ('create_ebuilds', create_ebuilds), ('update_overlay', update_overlay), ) def create_release(version, user, password=None, run_stages=None, **kwargs): version_string = '.'.join((str(v) for v in version)) if not password: password = getpass('Password for {0}: '.format(user)) for stname, stfunc in stages: if run_stages is None or stname in run_stages: stfunc(version_string=version_string, user=user, password=password, **kwargs) p = argparse.ArgumentParser(description='Powerline release script') p.add_argument('-u', '--user', type=str, metavar='USER', help='Github username.', required=True) p.add_argument('-v', '--version', type=parse_version, metavar='VERSION', help='Use given version for the release. If version contains only `+\' signs then it will increase latest version number: one `+\' increases major version number (e.g. 1.2.3 -> 2.0), `++\' increases minor version number (e.g. 1.2.3 -> 1.3), `+++\' increases patch level (e.g. 1.2.3 -> 1.2.4). Defaults to `+++\'.', default='+++') p.add_argument('-r', '--rev', metavar='COMMIT', help='Use given revision for the release. Defaults to `develop\'.', default='develop') p.add_argument('-s', '--stages', action='append', metavar='STAGE', help='Only run one of the given stages (default to all).', choices=tuple((stname for stname, stfunc in stages))) p.add_argument('-p', '--password', type=str, metavar='PASS', help='Github password. You will be prompted if it is not supplied.') p.add_argument('-o', '--overlay', type=str, metavar='PATH', help='Location of the local clone of the {0} overlay. If provided directory does not exist it will be created by “git clone”. Defaults to /tmp/powerline-{0}.'.format(OVERLAY_NAME), default='/tmp/powerline-' + OVERLAY_NAME) if __name__ == '__main__': args = p.parse_args() create_release( version=args.version, rev=args.rev, user=args.user, password=args.password, overlay=args.overlay, run_stages=args.stages, ) powerline-2.8.4/scripts/powerline-render000077500000000000000000000015711466405252600204450ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import os try: from powerline.shell import ShellPowerline except ImportError: sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__))))) from powerline.shell import ShellPowerline from powerline.commands.main import get_argparser, finish_args, write_output from powerline.lib.encoding import get_unicode_writer if sys.version_info < (3,): write = sys.stdout.write else: write = sys.stdout.buffer.write if __name__ == '__main__': parser = get_argparser() args = parser.parse_args() finish_args(parser, os.environ, args) powerline = ShellPowerline(args, run_once=True) segment_info = {'args': args, 'environ': os.environ} write_output(args, powerline, segment_info, get_unicode_writer()) powerline-2.8.4/setup.py000066400000000000000000000076501466405252600152650ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import sys import logging import shlex import subprocess from setuptools import setup, find_packages from powerline.version import get_version CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) try: README = open(os.path.join(CURRENT_DIR, 'README.rst'), 'rb').read().decode('utf-8') except IOError: README = '' OLD_PYTHON = sys.version_info < (2, 7) def compile_client(): '''Compile the C powerline-client script.''' if hasattr(sys, 'getwindowsversion'): raise NotImplementedError() else: from distutils.ccompiler import new_compiler compiler = new_compiler().compiler cflags = os.environ.get('CFLAGS', str('-O3')) # A normal split would do a split on each space which might be incorrect. The # shlex will not split if a space occurs in an arguments value. subprocess.check_call(compiler + shlex.split(cflags) + ['client/powerline.c', '-o', 'scripts/powerline']) try: compile_client() except Exception as e: print('Compiling C version of powerline-client failed') logging.exception(e) # FIXME Catch more specific exceptions import shutil if hasattr(shutil, 'which'): which = shutil.which else: sys.path.append(CURRENT_DIR) from powerline.lib.shell import which can_use_scripts = True if which('socat') and which('sed') and which('sh'): print('Using powerline.sh script instead of C version (requires socat, sed and sh)') shutil.copyfile('client/powerline.sh', 'scripts/powerline') else: print('Using powerline.py script instead of C version') shutil.copyfile('client/powerline.py', 'scripts/powerline') else: can_use_scripts = False setup( name='powerline-status', version=get_version(), description='The ultimate statusline/prompt utility.', long_description=README, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Environment :: Plugins', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ], download_url='https://github.com/powerline/powerline/archive/develop.zip', author='Kim Silkebaekken', author_email='kim.silkebaekken+vim@gmail.com', url='https://github.com/powerline/powerline', license='MIT', # XXX Python 3 doesn’t allow compiled C files to be included in the scripts # list below. This is because Python 3 distutils tries to decode the file to # ASCII, and fails when powerline-client is a binary. # # XXX Python 2 fucks up script contents*. Not using it to install scripts # any longer. # * Consider the following input: # % alias hex1=$'hexdump -e \'"" 1/1 "%02X\n"\'' # % diff <(hex1 ./scripts/powerline) <(hex1 ~/.local/bin/powerline) # This will show output like # 375c375 # < 0D # --- # > 0A # (repeated, with diff segment header numbers growing up). # # FIXME Current solution does not work with `pip install -e`. Still better # then solution that is not working at all. scripts=[ 'scripts/powerline-lint', 'scripts/powerline-daemon', 'scripts/powerline-render', 'scripts/powerline-config', ] + (['scripts/powerline'] if can_use_scripts else []), data_files=(None if can_use_scripts else (('bin', ['scripts/powerline']),)), keywords='', packages=find_packages(exclude=('tests', 'tests.*')), include_package_data=True, zip_safe=False, install_requires=['argparse'] if OLD_PYTHON else [], extras_require={ 'docs': [ 'Sphinx', 'sphinx_rtd_theme', ], }, test_suite='tests' if not OLD_PYTHON else None, ) powerline-2.8.4/tests/000077500000000000000000000000001466405252600147055ustar00rootroot00000000000000powerline-2.8.4/tests/__init__.py000066400000000000000000000000001466405252600170040ustar00rootroot00000000000000powerline-2.8.4/tests/install.sh000077500000000000000000000046471466405252600167250ustar00rootroot00000000000000#!/bin/bash set -e set -x remote_master_hex() { local url="$1" git ls-remote "$url" refs/heads/master | cut -f1 } checkout_cached_dir() { local url="$1" local target="$2" if ! test -e "$target/.version" || \ test "$(cat "$target/.version")" != "$(remote_master_hex "$url")" ; then rm -rf "$target" fi if ! test -d "$target" ; then git clone --depth=1 "$url" "$target" git rev-parse HEAD > "$target/.version" rm -rf "$target"/.git fi } checkout_cached_dir git://github.com/powerline/bot-ci tests/bot-ci checkout_cached_dir git://github.com/powerline/deps tests/bot-ci/deps . tests/bot-ci/scripts/common/main.sh mkdir -p "$HOME/opt" if test -n "$USE_UCS2_PYTHON" ; then if test "$UCS2_PYTHON_VARIANT" = "2.6" ; then pip install 'virtualenvwrapper==4.6.0' else pip install virtualenvwrapper fi set +e . virtualenvwrapper.sh set -e archive="${PWD:-$(pwd)}/tests/bot-ci/deps/cpython-ucs2/cpython-ucs2-${UCS2_PYTHON_VARIANT}.tar.gz" sh -c "cd $HOME/opt && tar xzf $archive" PYTHON="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/bin/python$UCS2_PYTHON_VARIANT" export LD_LIBRARY_PATH="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/lib${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}" set +e mkvirtualenv -p "$PYTHON" cpython-ucs2-$UCS2_PYTHON_VARIANT set -e . tests/bot-ci/scripts/common/main.sh pip install --verbose --verbose --verbose . if test "$UCS2_PYTHON_VARIANT" = "2.6" ; then rm tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/pyuv*.whl fi pip install --no-deps tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/*.whl else pip install --verbose --verbose --verbose . # FIXME Uv watcher sometimes misses events and INotify is not available in # Python-2.6, thus pyuv should be removed in order for VCS tests to # pass. if test "$PYTHON_VERSION_MAJOR" -eq 2 && test "$PYTHON_VERSION_MINOR" -lt 7 ; then rm tests/bot-ci/deps/wheels/$PYTHON_SUFFIX/pyuv*.whl fi pip install --no-deps tests/bot-ci/deps/wheels/$PYTHON_SUFFIX/*.whl fi if test "$PYTHON_IMPLEMENTATION" = "CPython" ; then archive="${PWD:-$(pwd)}/tests/bot-ci/deps/zpython/zsh-${PYTHON_MM}${USE_UCS2_PYTHON:+-ucs2}.tar.gz" sh -c "cd $HOME/opt && tar xzf $archive" fi archive="${PWD:-$(pwd)}/tests/bot-ci/deps/fish/fish.tar.gz" sh -c "cd $HOME/opt && tar xzf $archive" mkdir tests/vim-plugins for archive in "$ROOT"/tests/bot-ci/deps/vim-plugins/*.tar.gz ; do ( cd tests/vim-plugins tar -xzvf "$archive" ) done true powerline-2.8.4/tests/modules/000077500000000000000000000000001466405252600163555ustar00rootroot00000000000000powerline-2.8.4/tests/modules/__init__.py000066400000000000000000000047141466405252600204740ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import os if sys.version_info < (2, 7): from unittest2 import TestCase as _TestCase # NOQA from unittest2 import main as _main # NOQA from unittest2.case import SkipTest # NOQA else: from unittest import TestCase as _TestCase # NOQA from unittest import main as _main # NOQA from unittest.case import SkipTest # NOQA from tests.modules.lib import PowerlineSingleTest class PowerlineDummyTest(object): def __enter__(self): return self def __exit__(self, *args): pass def fail(self, *args, **kwargs): pass def exception(self, *args, **kwargs): pass class PowerlineTestSuite(object): def __init__(self, name): self.name = name self.suite = '' def __enter__(self): self.saved_current_suite = os.environ['POWERLINE_CURRENT_SUITE'] os.environ['POWERLINE_CURRENT_SUITE'] = ( self.saved_current_suite + '/' + self.name) self.suite = self.saved_current_suite + '/' + self.name return self def __exit__(self, exc_type, exc_value, traceback): if exc_type is not None: self.exception( 'suite_noexcept', 'Exception while running test suite: {0!r}'.format(exc_value), ) os.environ['POWERLINE_CURRENT_SUITE'] = self.saved_current_suite def record_test_failure(self, fail_char, test_name, message, allow_failure=False): if allow_failure: fail_char = 'A' + fail_char full_msg = '{fail_char} {suite}|{test_name} :: {message}'.format( fail_char=fail_char, suite=self.suite, test_name=test_name, message=message, ) with open(os.environ['FAILURES_FILE'], 'a') as ffd: ffd.write(full_msg + '\n') return False def exception(self, test_name, message, allow_failure=False): return self.record_test_failure('E', test_name, message, allow_failure) def fail(self, test_name, message, allow_failure=False): return self.record_test_failure('F', test_name, message, allow_failure) def test(self, name, attempts_left=0): if not attempts_left: return PowerlineSingleTest(self, name) else: return PowerlineDummyTest() def subsuite(self, name): return PowerlineTestSuite(name) suite = None def main(*args, **kwargs): global suite suite = PowerlineTestSuite(sys.argv[0]) _main(*args, **kwargs) class TestCase(_TestCase): def fail(self, msg=None): suite.fail(self.__class__.__name__, msg or 'Test failed without message') super(TestCase, self).fail(*args, **kwargs) powerline-2.8.4/tests/modules/lib/000077500000000000000000000000001466405252600171235ustar00rootroot00000000000000powerline-2.8.4/tests/modules/lib/__init__.py000066400000000000000000000262701466405252600212430ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import types import sys class Pl(object): def __init__(self): self.exceptions = [] self.errors = [] self.warns = [] self.debugs = [] self.infos = [] self.prefix = None self.use_daemon_threads = True for meth in ('error', 'warn', 'debug', 'exception', 'info'): exec(( 'def {0}(self, msg, *args, **kwargs):\n' ' self.{0}s.append((kwargs.get("prefix") or self.prefix, msg, args, kwargs))\n' ).format(meth)) def __nonzero__(self): return bool(self.exceptions or self.errors or self.warns) __bool__ = __nonzero__ class Args(object): theme_override = {} config_override = {} config_path = None ext = ['shell'] renderer_module = None def __init__(self, **kwargs): self.__dict__.update(kwargs) def urllib_read(query_url): if query_url.startswith('http://ipv'): if query_url.startswith('http://ipv4.icanhazip.com'): return '127.0.0.1' elif query_url.startswith('http://ipv6.icanhazip.com'): return '2001:4801:7818:6:abc5:ba2c:ff10:275f' elif query_url.startswith('https://freegeoip.app/json/'): return '{"ip":"82.145.55.16","country_code":"DE","country_name":"Germany","region_code":"NI","region_name":"Lower Saxony","city":"Meppen","zip_code":"49716","time_zone":"Europe/Berlin","latitude":52.6833,"longitude":7.3167,"metro_code":0}' elif query_url.startswith('http://geoip.nekudo.com/api/'): return r'{"city":"Meppen","country":{"name":"Germany", "code":"DE"},"location":{"accuracy_radius":100,"latitude":52.6833,"longitude":7.3167,"time_zone":"Europe\/Berlin"},"ip":"82.145.55.16"}' elif query_url.startswith('http://query.yahooapis.com/v1/public/'): if 'Meppen' in query_url or '52.6833' in query_url: return r'{"query":{"count":1,"created":"2016-05-13T19:43:18Z","lang":"en-US","results":{"channel":{"units":{"distance":"mi","pressure":"in","speed":"mph","temperature":"C"},"title":"Yahoo! Weather - Meppen, NI, DE","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/","description":"Yahoo! Weather for Meppen, NI, DE","language":"en-us","lastBuildDate":"Fri, 13 May 2016 09:43 PM CEST","ttl":"60","location":{"city":"Meppen","country":"Germany","region":" NI"},"wind":{"chill":"55","direction":"350","speed":"25"},"atmosphere":{"humidity":"57","pressure":"1004.0","rising":"0","visibility":"16.1"},"astronomy":{"sunrise":"5:35 am","sunset":"9:21 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Meppen, NI, DE at 08:00 PM CEST","lat":"52.68993","long":"7.29115","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/","pubDate":"Fri, 13 May 2016 08:00 PM CEST","condition":{"code":"23","date":"Fri, 13 May 2016 08:00 PM CEST","temp":"14","text":"Breezy"},"forecast":[{"code":"30","date":"13 May 2016","day":"Fri","high":"71","low":"48","text":"Partly Cloudy"},{"code":"28","date":"14 May 2016","day":"Sat","high":"54","low":"44","text":"Mostly Cloudy"},{"code":"11","date":"15 May 2016","day":"Sun","high":"55","low":"43","text":"Showers"},{"code":"28","date":"16 May 2016","day":"Mon","high":"54","low":"42","text":"Mostly Cloudy"},{"code":"28","date":"17 May 2016","day":"Tue","high":"57","low":"43","text":"Mostly Cloudy"},{"code":"12","date":"18 May 2016","day":"Wed","high":"62","low":"45","text":"Rain"},{"code":"28","date":"19 May 2016","day":"Thu","high":"63","low":"48","text":"Mostly Cloudy"},{"code":"28","date":"20 May 2016","day":"Fri","high":"67","low":"50","text":"Mostly Cloudy"},{"code":"30","date":"21 May 2016","day":"Sat","high":"71","low":"50","text":"Partly Cloudy"},{"code":"30","date":"22 May 2016","day":"Sun","high":"74","low":"54","text":"Partly Cloudy"}],"description":"\n
\nCurrent Conditions:\n
Breezy\n
\n
\nForecast:\n
Fri - Partly Cloudy. High: 71Low: 48\n
Sat - Mostly Cloudy. High: 54Low: 44\n
Sun - Showers. High: 55Low: 43\n
Mon - Mostly Cloudy. High: 54Low: 42\n
Tue - Mostly Cloudy. High: 57Low: 43\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n(provided by The Weather Channel)\n
\n]]>","guid":{"isPermaLink":"false"}}}}}}' elif 'Moscow' in query_url: return r'{"query":{"count":1,"created":"2016-05-13T19:47:01Z","lang":"en-US","results":{"channel":{"units":{"distance":"mi","pressure":"in","speed":"mph","temperature":"C"},"title":"Yahoo! Weather - Moscow, Moscow Federal City, RU","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/","description":"Yahoo! Weather for Moscow, Moscow Federal City, RU","language":"en-us","lastBuildDate":"Fri, 13 May 2016 10:47 PM MSK","ttl":"60","location":{"city":"Moscow","country":"Russia","region":" Moscow Federal City"},"wind":{"chill":"45","direction":"80","speed":"11"},"atmosphere":{"humidity":"52","pressure":"993.0","rising":"0","visibility":"16.1"},"astronomy":{"sunrise":"4:19 am","sunset":"8:34 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Moscow, Moscow Federal City, RU at 09:00 PM MSK","lat":"55.741638","long":"37.605061","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/","pubDate":"Fri, 13 May 2016 09:00 PM MSK","condition":{"code":"33","date":"Fri, 13 May 2016 09:00 PM MSK","temp":"9","text":"Mostly Clear"},"forecast":[{"code":"30","date":"13 May 2016","day":"Fri","high":"62","low":"41","text":"Partly Cloudy"},{"code":"30","date":"14 May 2016","day":"Sat","high":"64","low":"43","text":"Partly Cloudy"},{"code":"30","date":"15 May 2016","day":"Sun","high":"63","low":"44","text":"Partly Cloudy"},{"code":"12","date":"16 May 2016","day":"Mon","high":"60","low":"47","text":"Rain"},{"code":"12","date":"17 May 2016","day":"Tue","high":"64","low":"48","text":"Rain"},{"code":"28","date":"18 May 2016","day":"Wed","high":"67","low":"48","text":"Mostly Cloudy"},{"code":"12","date":"19 May 2016","day":"Thu","high":"68","low":"49","text":"Rain"},{"code":"39","date":"20 May 2016","day":"Fri","high":"66","low":"50","text":"Scattered Showers"},{"code":"39","date":"21 May 2016","day":"Sat","high":"69","low":"49","text":"Scattered Showers"},{"code":"30","date":"22 May 2016","day":"Sun","high":"73","low":"50","text":"Partly Cloudy"}],"description":"\n
\nCurrent Conditions:\n
Mostly Clear\n
\n
\nForecast:\n
Fri - Partly Cloudy. High: 62Low: 41\n
Sat - Partly Cloudy. High: 64Low: 43\n
Sun - Partly Cloudy. High: 63Low: 44\n
Mon - Rain. High: 60Low: 47\n
Tue - Rain. High: 64Low: 48\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n(provided by The Weather Channel)\n
\n]]>","guid":{"isPermaLink":"false"}}}}}}' elif query_url.startswith('https://api.openweathermap.org/data/2.5/'): if 'Meppen' in query_url or '52.6833' in query_url: return r'{"coord":{"lon":7.29,"lat":52.69},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"base":"stations","main":{"temp":293.15,"feels_like":295.16,"temp_min":293.15,"temp_max":295.37,"pressure":1018,"humidity":77},"visibility":10000,"wind":{"speed":1.12,"deg":126},"clouds":{"all":0},"dt":1600196220,"sys":{"type":1,"id":1871,"country":"DE","sunrise":1600146332,"sunset":1600191996},"timezone":7200,"id":2871845,"name":"Meppen","cod":200}' elif 'Moscow' in query_url: return r'{"coord":{"lon":37.62,"lat":55.75},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"base":"stations","main":{"temp":283.15,"feels_like":280.78,"temp_min":283.15,"temp_max":284.26,"pressure":1019,"humidity":71},"visibility":10000,"wind":{"speed":3,"deg":330},"clouds":{"all":0},"dt":1600196224,"sys":{"type":1,"id":9029,"country":"RU","sunrise":1600138909,"sunset":1600184863},"timezone":10800,"id":524901,"name":"Moscow","cod":200}' raise NotImplementedError class Process(object): def __init__(self, output, err): self.output = output self.err = err def communicate(self): return self.output, self.err class ModuleReplace(object): def __init__(self, name, new): self.name = name self.new = new def __enter__(self): self.old = sys.modules.get(self.name) if not self.old: try: self.old = __import__(self.name) except ImportError: pass sys.modules[self.name] = self.new def __exit__(self, *args): if self.old: sys.modules[self.name] = self.old else: sys.modules.pop(self.name) def replace_module(name, new=None, **kwargs): if not new: new = new_module(name, **kwargs) return ModuleReplace(name, new) def new_module(name, **kwargs): module = types.ModuleType(name) for k, v in kwargs.items(): setattr(module, k, v) return module class AttrReplace(object): def __init__(self, obj, *args): self.obj = obj self.attrs = args[::2] self.new = args[1::2] def __enter__(self): self.old = {} for i, attr in enumerate(self.attrs): try: self.old[i] = getattr(self.obj, attr) except AttributeError: pass for attr, new in zip(self.attrs, self.new): setattr(self.obj, attr, new) def __exit__(self, *args): for i, attr in enumerate(self.attrs): try: old = self.old[i] except KeyError: delattr(self.obj, attr) else: setattr(self.obj, attr, old) replace_attr = AttrReplace def replace_module_module(module, name, **kwargs): return replace_attr(module, name, new_module(name, **kwargs)) class ItemReplace(object): def __init__(self, d, key, new, r=None): self.key = key self.new = new self.d = d self.r = r def __enter__(self): self.old = self.d.get(self.key) self.d[self.key] = self.new return self.r def __exit__(self, *args): if self.old is None: try: self.d.pop(self.key) except KeyError: pass else: self.d[self.key] = self.old def replace_item(d, key, new): return ItemReplace(d, key, new, d) def replace_env(key, new, environ=None, **kwargs): r = kwargs.copy() r['environ'] = environ or {} return ItemReplace(r['environ'], key, new, r) class PowerlineSingleTest(object): def __init__(self, suite, name): self.suite = suite self.name = name def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): if exc_type is not None: self.exception('Exception while running test: {0!r}'.format( exc_value)) def fail(self, message, allow_failure=False): return self.suite.fail(self.name, message, allow_failure) def exception(self, message, allow_failure=False): return self.suite.exception(self.name, message, allow_failure) powerline-2.8.4/tests/modules/lib/config_mock.py000066400000000000000000000123061466405252600217550ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from threading import Lock from copy import deepcopy from time import sleep from functools import wraps from powerline.renderer import Renderer from powerline.lib.config import ConfigLoader from powerline import Powerline, get_default_theme from tests.modules.lib import Args, replace_attr UT = get_default_theme(is_unicode=True) AT = get_default_theme(is_unicode=False) class TestHelpers(object): def __init__(self, config): self.config = config self.access_log = [] self.access_lock = Lock() def loader_condition(self, path): return (path in self.config) and path def find_config_files(self, cfg_path, config_loader, loader_callback): if cfg_path.endswith('.json'): cfg_path = cfg_path[:-5] if cfg_path.startswith('/'): cfg_path = cfg_path.lstrip('/') with self.access_lock: self.access_log.append('check:' + cfg_path) if cfg_path in self.config: yield cfg_path else: if config_loader: config_loader.register_missing(self.loader_condition, loader_callback, cfg_path) raise IOError(('fcf:' if cfg_path.endswith('raise') else '') + cfg_path) def load_json_config(self, config_file_path, *args, **kwargs): if config_file_path.endswith('.json'): config_file_path = config_file_path[:-5] if config_file_path.startswith('/'): config_file_path = config_file_path.lstrip('/') with self.access_lock: self.access_log.append('load:' + config_file_path) try: return deepcopy(self.config[config_file_path]) except KeyError: raise IOError(config_file_path) def pop_events(self): with self.access_lock: r = self.access_log[:] self.access_log = [] return r def log_call(func): @wraps(func) def ret(self, *args, **kwargs): self._calls.append((func.__name__, args, kwargs)) return func(self, *args, **kwargs) return ret class TestWatcher(object): events = set() lock = Lock() def __init__(self): self._calls = [] @log_call def watch(self, file): pass @log_call def __call__(self, file): with self.lock: if file in self.events: self.events.remove(file) return True return False def _reset(self, files): with self.lock: self.events.clear() self.events.update(files) @log_call def unsubscribe(self): pass class Logger(object): def __init__(self): self.messages = [] self.lock = Lock() def _add_msg(self, attr, msg): with self.lock: self.messages.append(attr + ':' + msg) def _pop_msgs(self): with self.lock: r = self.messages self.messages = [] return r def __getattr__(self, attr): return lambda *args, **kwargs: self._add_msg(attr, *args, **kwargs) class SimpleRenderer(Renderer): def hlstyle(self, fg=None, bg=None, attrs=None): return '<{fg} {bg} {attrs}>'.format(fg=fg and fg[0], bg=bg and bg[0], attrs=attrs) class EvenSimplerRenderer(Renderer): def hlstyle(self, fg=None, bg=None, attrs=None): return '{{{fg}{bg}{attrs}}}'.format( fg=fg and fg[0] or '-', bg=bg and bg[0] or '-', attrs=attrs if attrs else '', ) class TestPowerline(Powerline): _created = False def __init__(self, _helpers, **kwargs): super(TestPowerline, self).__init__(**kwargs) self._helpers = _helpers self.find_config_files = _helpers.find_config_files @staticmethod def get_local_themes(local_themes): return local_themes @staticmethod def get_config_paths(): return [''] def _will_create_renderer(self): return self.cr_kwargs def _pop_events(self): return self._helpers.pop_events() renderer = EvenSimplerRenderer class TestConfigLoader(ConfigLoader): def __init__(self, _helpers, **kwargs): watcher = TestWatcher() super(TestConfigLoader, self).__init__( load=_helpers.load_json_config, watcher=watcher, watcher_type='test', **kwargs ) def get_powerline(config, **kwargs): helpers = TestHelpers(config) return get_powerline_raw( helpers, TestPowerline, _helpers=helpers, ext='test', renderer_module='tests.modules.lib.config_mock', logger=Logger(), **kwargs ) def select_renderer(simpler_renderer=False): global renderer renderer = EvenSimplerRenderer if simpler_renderer else SimpleRenderer def get_powerline_raw(helpers, PowerlineClass, replace_gcp=False, **kwargs): if not isinstance(helpers, TestHelpers): helpers = TestHelpers(helpers) select_renderer(kwargs.pop('simpler_renderer', False)) if replace_gcp: class PowerlineClass(PowerlineClass): @staticmethod def get_config_paths(): return ['/'] pl = PowerlineClass( config_loader=TestConfigLoader( _helpers=helpers, run_once=kwargs.get('run_once') ), **kwargs ) pl._watcher = pl.config_loader.watcher return pl def swap_attributes(config, powerline_module): return replace_attr(powerline_module, 'os', Args( path=Args( isfile=lambda path: path.lstrip('/').replace('.json', '') in config, join=os.path.join, expanduser=lambda path: path, realpath=lambda path: path, dirname=os.path.dirname, ), environ={}, )) def add_watcher_events(p, *args, **kwargs): if isinstance(p._watcher, TestWatcher): p._watcher._reset(args) while not p._will_create_renderer(): sleep(kwargs.get('interval', 0.1)) if not kwargs.get('wait', True): return powerline-2.8.4/tests/modules/lib/fsconfig.py000066400000000000000000000036351466405252600213020ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import json from subprocess import check_call from shutil import rmtree from itertools import chain from powerline import Powerline CONFIG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'config') class TestPowerline(Powerline): def __init__(self, _paths, *args, **kwargs): super(TestPowerline, self).__init__(*args, **kwargs) self._paths = _paths def get_config_paths(self): return self._paths def mkdir_recursive(directory): if os.path.isdir(directory): return mkdir_recursive(os.path.dirname(directory)) os.mkdir(directory) class FSTree(object): __slots__ = ('tree', 'p', 'p_kwargs', 'create_p', 'get_config_paths', 'root') def __init__( self, tree, p_kwargs={'run_once': True}, root=CONFIG_DIR, get_config_paths=lambda p: (p,), create_p=False ): self.tree = tree self.root = root self.get_config_paths = get_config_paths self.create_p = create_p self.p = None self.p_kwargs = p_kwargs def __enter__(self, *args): os.mkdir(self.root) for k, v in self.tree.items(): fname = os.path.join(self.root, k) + '.json' mkdir_recursive(os.path.dirname(fname)) with open(fname, 'w') as F: json.dump(v, F) if self.create_p: self.p = TestPowerline( _paths=self.get_config_paths(self.root), ext='test', renderer_module='tests.modules.lib.config_mock', **self.p_kwargs ) if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'): try: check_call(chain(['scripts/powerline-lint'], *[ ('-p', d) for d in ( self.p.get_config_paths() if self.p else self.get_config_paths(self.root) ) ])) except: self.__exit__() raise return self.p and self.p.__enter__(*args) def __exit__(self, *args): try: rmtree(self.root) finally: if self.p: self.p.__exit__(*args) powerline-2.8.4/tests/modules/lib/terminal.py000066400000000000000000000211371466405252600213140ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import threading import os from time import sleep from itertools import groupby from signal import SIGKILL from difflib import ndiff import pexpect from powerline.lib.unicode import u from tests.modules.lib.vterm import VTerm, Dimensions class MutableDimensions(object): def __init__(self, rows, cols): super(MutableDimensions, self).__init__() self._list = [rows, cols] def __getitem__(self, idx): return self._list[idx] def __setitem__(self, idx, val): self._list[idx] = val def __iter__(self): return iter(self._list) def __len__(self): return 2 def __nonzero__(self): return True __bool__ = __nonzero__ rows = property( fget = lambda self: self._list[0], fset = lambda self, val: self._list.__setitem__(0, val), ) cols = property( fget = lambda self: self._list[1], fset = lambda self, val: self._list.__setitem__(1, val), ) class ExpectProcess(threading.Thread): def __init__(self, lib, dim, cmd, args, cwd=None, env=None): super(ExpectProcess, self).__init__() self.vterm = VTerm(lib, dim) self.lock = threading.Lock() self.dim = Dimensions(*dim) self.cmd = cmd self.args = args self.cwd = cwd self.env = env self.buffer = [] self.child_lock = threading.Lock() self.shutdown_event = threading.Event() self.started_event = threading.Event() def run(self): with self.child_lock: child = pexpect.spawn(self.cmd, self.args, cwd=self.cwd, env=self.env) sleep(0.5) child.setwinsize(self.dim.rows, self.dim.cols) sleep(0.5) self.child = child self.started_event.set() status = None while status is None and not self.shutdown_event.is_set(): try: with self.child_lock: s = child.read_nonblocking(size=1024, timeout=0) status = child.status except pexpect.TIMEOUT: pass except pexpect.EOF: break else: with self.lock: self.vterm.push(s) self.buffer.append(s) if status is None: child.kill(SIGKILL) def kill(self): self.shutdown_event.set() def resize(self, dim): with self.child_lock: self.dim = Dimensions(*dim) self.child.setwinsize(self.dim.rows, self.dim.cols) self.vterm.resize(self.dim) def __getitem__(self, position): with self.lock: return self.vterm.vtscreen[position] def read(self): with self.lock: ret = b''.join(self.buffer) del self.buffer[:] return ret def send(self, data): with self.child_lock: self.child.send(data) def get_highlighted_text(self, text, attrs, default_props=(), use_escapes=False): ret = [] new_attrs = attrs.copy() for cell_properties, segment_text in text: if use_escapes: escapes = ('\033[38;2;{0};{1};{2};48;2;{3};{4};{5}'.format( *(cell_properties[0] + cell_properties[1]))) + ( ';1' if cell_properties[2] else '' ) + ( ';3' if cell_properties[3] else '' ) + ( ';4' if cell_properties[4] else '' ) + 'm' ret.append(escapes + segment_text + '\033[0m') else: segment_text = segment_text.translate({'{': '{{', '}': '}}'}) if cell_properties not in new_attrs: new_attrs[cell_properties] = len(new_attrs) + 1 props_name = new_attrs[cell_properties] if props_name in default_props: ret.append(segment_text) else: ret.append('{' + str(props_name) + ':' + segment_text + '}') return ''.join(ret), new_attrs def get_row(self, row, attrs, default_props=(), use_escapes=False): with self.lock: return self.get_highlighted_text(( (key, ''.join((cell.text for cell in subline))) for key, subline in groupby(( self.vterm.vtscreen[row, col] for col in range(self.dim.cols) ), lambda cell: cell.cell_properties_key) ), attrs, default_props, use_escapes) def get_screen(self, attrs, default_props=(), use_escapes=False): lines = [] for row in range(self.dim.rows): line, attrs = self.get_row(row, attrs, default_props, use_escapes) lines.append(line) return '\n'.join(lines), attrs def test_expected_result(p, test, last_attempt, last_attempt_cb, attempts): debugging_tests = not not os.environ.get('_POWERLINE_DEBUGGING_TESTS') expected_text, attrs = test['expected_result'] result = None while attempts: if 'row' in test: row = test['row'] else: row = p.dim.rows - 1 while row >= 0 and not p[row, 0].text: row -= 1 if row < 0: row = 0 actual_text, all_attrs = p.get_row(row, attrs) if actual_text == expected_text: return True attempts -= 1 print('Actual result does not match expected for row {0}. Attempts left: {1}.'.format( row, attempts)) sleep(2) print('Result (row {0}):'.format(row)) print(actual_text) print('Expected:') print(expected_text) print('Attributes:') for v, k in sorted( ((v, k) for k, v in all_attrs.items()), key=(lambda t: '%02u'.format(t[0]) if isinstance(t[0], int) else t[0]), ): print('{k!r}: {v!r},'.format(v=v, k=k)) print('Screen:') screen, screen_attrs = p.get_screen(attrs, use_escapes=debugging_tests) print(screen) print(screen_attrs) print('_' * 80) print('Diff:') print('=' * 80) print(''.join(( u(line) for line in ndiff([actual_text + '\n'], [expected_text + '\n'])) )) if last_attempt and last_attempt_cb: last_attempt_cb() return False ENV_BASE = { # Reasoning: # 1. vt* TERMs (used to be vt100 here) make tmux-1.9 use different and # identical colors for inactive windows. This is not like tmux-1.6: # foreground color is different from separator color and equal to (0, # 102, 153) for some reason (separator has correct color). tmux-1.8 is # fine, so are older versions (though tmux-1.6 and tmux-1.7 do not have # highlighting for previously active window) and my system tmux-1.9a. # 2. screen, xterm and some other non-256color terminals both have the same # issue and make libvterm emit complains like `Unhandled CSI SGR 3231`. # 3. screen-256color, xterm-256color and other -256color terminals make # libvterm emit complains about unhandled escapes to stderr. # 4. `st-256color` does not have any of the above problems, but it may be # not present on the target system because it is installed with # x11-terms/st and not with sys-libs/ncurses. # # For the given reasons decision was made: to fix tmux-1.9 tests and not # make libvterm emit any data to stderr st-256color $TERM should be used, up # until libvterm has its own terminfo database entry (if it ever will). To # make sure that relevant terminfo entry is present on the target system it # should be distributed with powerline test package. To make distribution # not require modifying anything outside of powerline test directory # TERMINFO variable is set. # # This fix propagates to non-tmux vterm tests just in case. 'TERM': 'st-256color', # Also $TERMINFO definition in get_env 'POWERLINE_CONFIG_PATHS': os.path.abspath('powerline/config_files'), 'POWERLINE_COMMAND': 'powerline-render', 'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''), 'PYTHONPATH': os.environ.get('PYTHONPATH', ''), } def get_env(vterm_path, test_dir, *args, **kwargs): env = ENV_BASE.copy() env.update({ 'TERMINFO': os.path.join(test_dir, 'terminfo'), 'PATH': vterm_path, 'SHELL': os.path.join(vterm_path, 'bash'), }) env.update(*args, **kwargs) return env def do_terminal_tests(tests, cmd, dim, args, env, suite, cwd=None, fin_cb=None, last_attempt_cb=None, attempts=None): debugging_tests = not not os.environ.get('_POWERLINE_DEBUGGING_TESTS') default_attempts = 2 if debugging_tests else 3 if attempts is None: attempts = default_attempts lib = os.environ.get('POWERLINE_LIBVTERM') if not lib: if os.path.exists('tests/bot-ci/deps/libvterm/libvterm.so'): lib = 'tests/bot-ci/deps/libvterm/libvterm.so' else: lib = 'libvterm.so' while attempts: try: p = ExpectProcess( lib=lib, dim=dim, cmd=cmd, args=args, cwd=cwd, env=env, ) p.start() p.started_event.wait() ret = True for i, test in enumerate(tests): with suite.test(test.get('name', 'test_{0}'.format(i)), attempts - 1) as ptest: try: test_prep = test['prep_cb'] except KeyError: pass else: test_prep(p) test_result = test_expected_result( p, test, attempts == 0, last_attempt_cb, test.get('attempts', default_attempts) ) if not test_result: ptest.fail('Result does not match expected') ret = ret and test_result if ret: return ret finally: if fin_cb: fin_cb(p=p, cmd=cmd, env=env) p.kill() p.join(10) assert(not p.isAlive()) attempts -= 1 return False powerline-2.8.4/tests/modules/lib/vterm.py000066400000000000000000000112671466405252600206410ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import ctypes from collections import namedtuple from powerline.lib.unicode import unicode, unichr, tointiter Dimensions = namedtuple('Dimensions', ('rows', 'cols')) class CTypesFunction(object): def __init__(self, library, name, rettype, args): self.name = name self.prototype = ctypes.CFUNCTYPE(rettype, *[ arg[1] for arg in args ]) self.args = args self.func = self.prototype((name, library), tuple(( (1, arg[0]) for arg in args ))) def __call__(self, *args, **kwargs): return self.func(*args, **kwargs) def __repr__(self): return '{cls}(, {name!r}, {rettype!r}, {args!r})'.format( cls=self.__class__.__name__, **self.__dict__ ) class CTypesLibraryFuncsCollection(object): def __init__(self, lib, **kwargs): self.lib = lib library_loader = ctypes.LibraryLoader(ctypes.CDLL) library = library_loader.LoadLibrary(lib) self.library = library for name, args in kwargs.items(): self.__dict__[name] = CTypesFunction(library, name, *args) class VTermPos_s(ctypes.Structure): _fields_ = ( ('row', ctypes.c_int), ('col', ctypes.c_int), ) class VTermColor_s(ctypes.Structure): _fields_ = ( ('red', ctypes.c_uint8), ('green', ctypes.c_uint8), ('blue', ctypes.c_uint8), ) class VTermScreenCellAttrs_s(ctypes.Structure): _fields_ = ( ('bold', ctypes.c_uint, 1), ('underline', ctypes.c_uint, 2), ('italic', ctypes.c_uint, 1), ('blink', ctypes.c_uint, 1), ('reverse', ctypes.c_uint, 1), ('strike', ctypes.c_uint, 1), ('font', ctypes.c_uint, 4), ('dwl', ctypes.c_uint, 1), ('dhl', ctypes.c_uint, 2), ) VTERM_MAX_CHARS_PER_CELL = 6 class VTermScreenCell_s(ctypes.Structure): _fields_ = ( ('chars', ctypes.ARRAY(ctypes.c_uint32, VTERM_MAX_CHARS_PER_CELL)), ('width', ctypes.c_char), ('attrs', VTermScreenCellAttrs_s), ('fg', VTermColor_s), ('bg', VTermColor_s), ) VTerm_p = ctypes.c_void_p VTermScreen_p = ctypes.c_void_p def get_functions(lib): return CTypesLibraryFuncsCollection( lib, vterm_new=(VTerm_p, ( ('rows', ctypes.c_int), ('cols', ctypes.c_int) )), vterm_obtain_screen=(VTermScreen_p, (('vt', VTerm_p),)), vterm_set_size=(None, ( ('vt', VTerm_p), ('rows', ctypes.c_int), ('cols', ctypes.c_int) )), vterm_screen_reset=(None, ( ('screen', VTermScreen_p), ('hard', ctypes.c_int) )), vterm_input_write=(ctypes.c_size_t, ( ('vt', VTerm_p), ('bytes', ctypes.POINTER(ctypes.c_char)), ('size', ctypes.c_size_t), )), vterm_screen_get_cell=(ctypes.c_int, ( ('screen', VTermScreen_p), ('pos', VTermPos_s), ('cell', ctypes.POINTER(VTermScreenCell_s)) )), vterm_free=(None, (('vt', VTerm_p),)), vterm_set_utf8=(None, (('vt', VTerm_p), ('is_utf8', ctypes.c_int))), ) class VTermColor(object): __slots__ = ('red', 'green', 'blue') def __init__(self, color): self.red = color.red self.green = color.green self.blue = color.blue @property def color_key(self): return (self.red, self.green, self.blue) class VTermScreenCell(object): def __init__(self, vtsc): for field in VTermScreenCellAttrs_s._fields_: field_name = field[0] setattr(self, field_name, getattr(vtsc.attrs, field_name)) self.text = ''.join(( unichr(vtsc.chars[i]) for i in range(VTERM_MAX_CHARS_PER_CELL) )).rstrip('\x00') self.width = next(tointiter(vtsc.width)) self.fg = VTermColor(vtsc.fg) self.bg = VTermColor(vtsc.bg) self.cell_properties_key = ( self.fg.color_key, self.bg.color_key, self.bold, self.underline, self.italic, ) class VTermScreen(object): def __init__(self, functions, screen): self.functions = functions self.screen = screen def __getitem__(self, position): pos = VTermPos_s(*position) cell = VTermScreenCell_s() ret = self.functions.vterm_screen_get_cell(self.screen, pos, cell) if ret != 1: raise ValueError('vterm_screen_get_cell returned {0}'.format(ret)) return VTermScreenCell(cell) def reset(self, hard): self.functions.vterm_screen_reset(self.screen, int(bool(hard))) class VTerm(object): def __init__(self, lib, dim): self.functions = get_functions(lib) self.vt = self.functions.vterm_new(dim.rows, dim.cols) self.functions.vterm_set_utf8(self.vt, 1) self.vtscreen = VTermScreen(self.functions, self.functions.vterm_obtain_screen(self.vt)) self.vtscreen.reset(True) def push(self, data): if isinstance(data, unicode): data = data.encode('utf-8') return self.functions.vterm_input_write(self.vt, data, len(data)) def resize(self, dim): self.functions.vterm_set_size(self.vt, dim.rows, dim.cols) def __del__(self): try: self.functions.vterm_free(self.vt) except AttributeError: pass powerline-2.8.4/tests/modules/matchers.py000066400000000000000000000002411466405252600205320ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) def always_true(matcher_info): return True powerline-2.8.4/tests/modules/vim.py000066400000000000000000000452401466405252600175270ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet _log = [] vars = {} vvars = {'version': 703} _tabpage = 0 _mode = 'n' _buf_purge_events = set() options = { 'paste': 0, 'ambiwidth': 'single', 'columns': 80, 'encoding': 'utf-8', } _last_bufnr = 0 _highlights = {} from collections import defaultdict as _defaultdict _environ = _defaultdict(lambda: '') del _defaultdict _thread_id = None def _set_thread_id(): global _thread_id from threading import current_thread _thread_id = current_thread().ident # Assuming import is done from the main thread _set_thread_id() def _print_log(): for item in _log: print (item) _log[:] = () def _vim(func): from functools import wraps from threading import current_thread @wraps(func) def f(*args, **kwargs): global _thread_id if _thread_id != current_thread().ident: raise RuntimeError('Accessing vim from separate threads is not allowed') _log.append((func.__name__, args)) return func(*args, **kwargs) return f def _unicode(func): from functools import wraps import sys if sys.version_info < (3,): return func @wraps(func) def f(*args, **kwargs): from powerline.lib.unicode import u ret = func(*args, **kwargs) if isinstance(ret, bytes): ret = u(ret) return ret return f class _Buffers(object): @_vim def __init__(self): self.d = {} @_vim def __len__(self): return len(self.d) @_vim def __getitem__(self, item): return self.d[item] @_vim def __setitem__(self, item, value): self.d[item] = value @_vim def __iter__(self): return iter(self.d.values()) @_vim def __contains__(self, item): return item in self.d @_vim def _keys(self): return self.d.keys() @_vim def _pop(self, *args, **kwargs): return self.d.pop(*args, **kwargs) buffers = _Buffers() class _ObjList(object): @_vim def __init__(self, objtype): self.l = [] self.objtype = objtype @_vim def __getitem__(self, item): return self.l[item - int(item > 0)] @_vim def __len__(self): return len(self.l) @_vim def __iter__(self): return iter(self.l) @_vim def _pop(self, idx): obj = self.l.pop(idx - 1) for moved_obj in self.l[idx - 1:]: moved_obj.number -= 1 return obj @_vim def _append(self, *args, **kwargs): return self.l.append(*args, **kwargs) @_vim def _new(self, *args, **kwargs): number = len(self) + 1 new_obj = self.objtype(number, *args, **kwargs) self._append(new_obj) return new_obj def _construct_result(r): import sys if sys.version_info < (3,): return r else: if isinstance(r, str): return r.encode('utf-8') elif isinstance(r, list): return [_construct_result(i) for i in r] elif isinstance(r, dict): return dict(( (_construct_result(k), _construct_result(v)) for k, v in r.items() )) return r def _str_func(func): from functools import wraps @wraps(func) def f(*args, **kwargs): return _construct_result(func(*args, **kwargs)) return f def _log_print(): import sys for entry in _log: sys.stdout.write(repr(entry) + '\n') _current_group = None _on_wipeout = [] @_vim def command(cmd): global _current_group cmd = cmd.lstrip() if cmd.startswith('let g:'): import re varname, value = re.compile(r'^let g:(\w+)\s*=\s*(.*)').match(cmd).groups() vars[varname] = value elif cmd.startswith('hi '): sp = cmd.split() _highlights[sp[1]] = sp[2:] elif cmd.startswith('augroup'): augroup = cmd.partition(' ')[2] if augroup.upper() == 'END': _current_group = None else: _current_group = augroup elif cmd.startswith('autocmd'): rest = cmd.partition(' ')[2] auevent, rest = rest.partition(' ')[::2] pattern, aucmd = rest.partition(' ')[::2] if auevent != 'BufWipeout' or pattern != '*': raise NotImplementedError import sys if sys.version_info < (3,): if not aucmd.startswith(':python '): raise NotImplementedError else: if not aucmd.startswith(':python3 '): raise NotImplementedError _on_wipeout.append(aucmd.partition(' ')[2]) elif cmd.startswith('set '): if cmd.startswith('set statusline='): options['statusline'] = cmd[len('set statusline='):] elif cmd.startswith('set tabline='): options['tabline'] = cmd[len('set tabline='):] else: raise NotImplementedError(cmd) else: raise NotImplementedError(cmd) @_vim @_unicode def eval(expr): if expr.startswith('g:'): return vars[expr[2:]] elif expr.startswith('v:'): return vvars[expr[2:]] elif expr.startswith('&'): return options[expr[1:]] elif expr.startswith('$'): return _environ[expr[1:]] elif expr.startswith('PowerlineRegisterCachePurgerEvent'): _buf_purge_events.add(expr[expr.find('"') + 1:expr.rfind('"') - 1]) return '0' elif expr.startswith('exists('): return '0' elif expr.startswith('getwinvar('): import re match = re.match(r'^getwinvar\((\d+), "(\w+)"\)$', expr) if not match: raise NotImplementedError(expr) winnr = int(match.group(1)) varname = match.group(2) return _emul_getwinvar(winnr, varname) elif expr.startswith('has_key('): import re match = re.match(r'^has_key\(getwinvar\((\d+), ""\), "(\w+)"\)$', expr) if match: winnr = int(match.group(1)) varname = match.group(2) return 0 + (varname in current.tabpage.windows[winnr].vars) else: match = re.match(r'^has_key\(gettabwinvar\((\d+), (\d+), ""\), "(\w+)"\)$', expr) if not match: raise NotImplementedError(expr) tabnr = int(match.group(1)) winnr = int(match.group(2)) varname = match.group(3) return 0 + (varname in tabpages[tabnr].windows[winnr].vars) elif expr == 'getbufvar("%", "NERDTreeRoot").path.str()': import os assert os.path.basename(current.buffer.name).startswith('NERD_tree_') return '/usr/include' elif expr.startswith('getbufvar('): import re match = re.match(r'^getbufvar\((\d+), ["\'](.+)["\']\)$', expr) if not match: raise NotImplementedError(expr) bufnr = int(match.group(1)) varname = match.group(2) return _emul_getbufvar(bufnr, varname) elif expr == 'tabpagenr()': return current.tabpage.number elif expr == 'tabpagenr("$")': return len(tabpages) elif expr.startswith('tabpagewinnr('): tabnr = int(expr[len('tabpagewinnr('):-1]) return tabpages[tabnr].window.number elif expr.startswith('tabpagebuflist('): import re match = re.match(r'tabpagebuflist\((\d+)\)\[(\d+)\]', expr) tabnr = int(match.group(1)) winnr = int(match.group(2)) + 1 return tabpages[tabnr].windows[winnr].buffer.number elif expr.startswith('gettabwinvar('): import re match = re.match(r'gettabwinvar\((\d+), (\d+), "(\w+)"\)', expr) tabnr = int(match.group(1)) winnr = int(match.group(2)) varname = match.group(3) return tabpages[tabnr].windows[winnr].vars[varname] elif expr.startswith('type(function('): import re match = re.match(r'^type\(function\("([^"]+)"\)\) == 2$', expr) if not match: raise NotImplementedError(expr) return 0 raise NotImplementedError(expr) @_vim def bindeval(expr): if expr == 'g:': return vars elif expr == '{}': return {} elif expr == '[]': return [] import re match = re.compile(r'^function\("([^"\\]+)"\)$').match(expr) if match: return globals()['_emul_' + match.group(1)] else: raise NotImplementedError @_vim @_str_func def _emul_mode(*args): if args and args[0]: return _mode else: return _mode[0] @_vim @_str_func def _emul_getbufvar(bufnr, varname): import re if varname[0] == '&': if bufnr == '%': bufnr = current.buffer.number if bufnr not in buffers: return '' try: return buffers[bufnr].options[varname[1:]] except KeyError: try: return options[varname[1:]] except KeyError: return '' elif re.match('^[a-zA-Z_]+$', varname): if bufnr == '%': bufnr = current.buffer.number if bufnr not in buffers: return '' return buffers[bufnr].vars[varname] raise NotImplementedError @_vim @_str_func def _emul_getwinvar(winnr, varname): return current.tabpage.windows[winnr].vars.get(varname, '') @_vim def _emul_setwinvar(winnr, varname, value): current.tabpage.windows[winnr].vars[varname] = value @_vim def _emul_virtcol(expr): if expr == '.': return current.window.cursor[1] + 1 if isinstance(expr, list) and len(expr) == 3: return expr[-2] + expr[-1] raise NotImplementedError _v_pos = None @_vim def _emul_getpos(expr): if expr == '.': return [0, current.window.cursor[0] + 1, current.window.cursor[1] + 1, 0] if expr == 'v': return _v_pos or [0, current.window.cursor[0] + 1, current.window.cursor[1] + 1, 0] raise NotImplementedError @_vim @_str_func def _emul_fnamemodify(path, modstring): import os _modifiers = { '~': lambda path: path.replace(os.environ['HOME'].encode('utf-8'), b'~') if path.startswith(os.environ['HOME'].encode('utf-8')) else path, '.': lambda path: (lambda tpath: path if tpath[:3] == b'..' + os.sep.encode() else tpath)(os.path.relpath(path)), 't': lambda path: os.path.basename(path), 'h': lambda path: os.path.dirname(path), } for mods in modstring.split(':')[1:]: path = _modifiers[mods](path) return path @_vim @_str_func def _emul_expand(expr): global _abuf if expr == '': return _abuf or current.buffer.number raise NotImplementedError @_vim def _emul_bufnr(expr): if expr == '$': return _last_bufnr raise NotImplementedError @_vim def _emul_exists(ident): if ident.startswith('g:'): return ident[2:] in vars elif ident.startswith(':'): return 0 raise NotImplementedError @_vim def _emul_line2byte(line): buflines = current.buffer._buf_lines if line == len(buflines) + 1: return sum((len(s) for s in buflines)) + 1 raise NotImplementedError @_vim def _emul_line(expr): cursorline = current.window.cursor[0] + 1 numlines = len(current.buffer._buf_lines) if expr == 'w0': return max(cursorline - 5, 1) if expr == 'w$': return min(cursorline + 5, numlines) raise NotImplementedError @_vim @_str_func def _emul_strtrans(s): # FIXME Do more replaces return s.replace(b'\xFF', b'') @_vim @_str_func def _emul_bufname(bufnr): try: return buffers[bufnr]._name or b'' except KeyError: return b'' _window_id = 0 class _Window(object): def __init__(self, number, buffer=None, cursor=(1, 0), width=80): global _window_id self.cursor = cursor self.width = width self.number = number if buffer: if type(buffer) is _Buffer: self.buffer = buffer else: self.buffer = _Buffer(**buffer) else: self.buffer = _Buffer() _window_id += 1 self._window_id = _window_id self.options = {} self.vars = { 'powerline_window_id': self._window_id, } def __repr__(self): return '' class _Tabpage(object): def __init__(self, number): self.windows = _ObjList(_Window) self.number = number def _new_window(self, **kwargs): self.window = self.windows._new(**kwargs) return self.window def _close_window(self, winnr, open_window=True): curwinnr = self.window.number win = self.windows._pop(winnr) if self.windows and winnr == curwinnr: self.window = self.windows[-1] elif open_window: current.tabpage._new_window() return win def _close(self): global _tabpage while self.windows: self._close_window(1, False) tabpages._pop(self.number) _tabpage = len(tabpages) tabpages = _ObjList(_Tabpage) _abuf = None class _Buffer(object): def __init__(self, name=None): global _last_bufnr _last_bufnr += 1 bufnr = _last_bufnr self.number = bufnr # FIXME Use unicode() for python-3 self.name = name self.vars = {'changedtick': 1} self.options = { 'modified': 0, 'readonly': 0, 'fileformat': 'unix', 'filetype': '', 'buftype': '', 'fileencoding': 'utf-8', 'textwidth': 80, } self._buf_lines = [''] self._undostate = [self._buf_lines[:]] self._undo_written = len(self._undostate) buffers[bufnr] = self @property def name(self): import sys if sys.version_info < (3,): return self._name else: return str(self._name, 'utf-8') if self._name else None @name.setter def name(self, name): if name is None: self._name = None else: import os if type(name) is not bytes: name = name.encode('utf-8') if b':/' in name: self._name = name else: self._name = os.path.abspath(name) def __getitem__(self, line): return self._buf_lines[line] def __setitem__(self, line, value): self.options['modified'] = 1 self.vars['changedtick'] += 1 self._buf_lines[line] = value from copy import copy self._undostate.append(copy(self._buf_lines)) def __setslice__(self, *args): self.options['modified'] = 1 self.vars['changedtick'] += 1 self._buf_lines.__setslice__(*args) from copy import copy self._undostate.append(copy(self._buf_lines)) def __getslice__(self, *args): return self._buf_lines.__getslice__(*args) def __len__(self): return len(self._buf_lines) def __repr__(self): return '' def __del__(self): global _abuf bufnr = self.number try: import __main__ except ImportError: pass except RuntimeError: # Module may have already been garbage-collected pass else: if _on_wipeout: _abuf = bufnr try: for event in _on_wipeout: exec(event, __main__.__dict__) finally: _abuf = None class _Current(object): @property def buffer(self): return self.window.buffer @property def window(self): return self.tabpage.window @property def tabpage(self): return tabpages[_tabpage - 1] current = _Current() _dict = None @_vim def _init(): global _dict if _dict: return _dict _dict = {} for varname, value in globals().items(): if varname[0] != '_': _dict[varname] = value _tabnew() return _dict @_vim def _get_segment_info(): mode_translations = { chr(ord('V') - 0x40): '^V', chr(ord('S') - 0x40): '^S', } mode = _mode mode = mode_translations.get(mode, mode) window = current.window buffer = current.buffer tabpage = current.tabpage return { 'window': window, 'winnr': window.number, 'buffer': buffer, 'bufnr': buffer.number, 'tabpage': tabpage, 'tabnr': tabpage.number, 'window_id': window._window_id, 'mode': mode, 'encoding': options['encoding'], } @_vim def _launch_event(event): pass @_vim def _start_mode(mode): global _mode if mode == 'i': _launch_event('InsertEnter') elif _mode == 'i': _launch_event('InsertLeave') _mode = mode @_vim def _undo(): if len(current.buffer._undostate) == 1: return buffer = current.buffer buffer._undostate.pop(-1) buffer._buf_lines = buffer._undostate[-1] if buffer._undo_written == len(buffer._undostate): buffer.options['modified'] = 0 @_vim def _edit(name=None): if current.buffer.name is None: buffer = current.buffer buffer.name = name else: buffer = _Buffer(name) current.window.buffer = buffer @_vim def _tabnew(name=None): global windows global _tabpage tabpage = tabpages._new() windows = tabpage.windows _tabpage = len(tabpages) _new(name) return tabpage @_vim def _new(name=None): current.tabpage._new_window(buffer={'name': name}) @_vim def _split(): current.tabpage._new_window(buffer=current.buffer) @_vim def _close(winnr, wipe=True): win = current.tabpage._close_window(winnr) if wipe: for w in current.tabpage.windows: if w.buffer.number == win.buffer.number: break else: _bw(win.buffer.number) @_vim def _bw(bufnr=None): bufnr = bufnr or current.buffer.number winnr = 1 for win in current.tabpage.windows: if win.buffer.number == bufnr: _close(winnr, wipe=False) winnr += 1 buffers._pop(bufnr) if not buffers: _Buffer() _b(max(buffers._keys())) @_vim def _b(bufnr): current.window.buffer = buffers[bufnr] @_vim def _set_cursor(line, col): current.window.cursor = (line, col) if _mode == 'n': _launch_event('CursorMoved') elif _mode == 'i': _launch_event('CursorMovedI') @_vim def _get_buffer(): return current.buffer @_vim def _set_bufoption(option, value, bufnr=None): buffers[bufnr or current.buffer.number].options[option] = value if option == 'filetype': _launch_event('FileType') class _WithNewBuffer(object): def __init__(self, func, *args, **kwargs): self.call = lambda: func(*args, **kwargs) def __enter__(self): self.call() self.bufnr = current.buffer.number return _get_segment_info() def __exit__(self, *args): _bw(self.bufnr) @_vim def _set_dict(d, new, setfunc=None): if not setfunc: def setfunc(k, v): d[k] = v old = {} na = [] for k, v in new.items(): try: old[k] = d[k] except KeyError: na.append(k) setfunc(k, v) return old, na class _WithBufOption(object): def __init__(self, **new): self.new = new def __enter__(self): self.buffer = current.buffer self.old = _set_dict(self.buffer.options, self.new, _set_bufoption)[0] def __exit__(self, *args): self.buffer.options.update(self.old) class _WithMode(object): def __init__(self, new): self.new = new def __enter__(self): self.old = _mode _start_mode(self.new) return _get_segment_info() def __exit__(self, *args): _start_mode(self.old) class _WithDict(object): def __init__(self, d, **new): self.new = new self.d = d def __enter__(self): self.old, self.na = _set_dict(self.d, self.new) def __exit__(self, *args): self.d.update(self.old) for k in self.na: self.d.pop(k) class _WithSplit(object): def __enter__(self): _split() def __exit__(self, *args): _close(2, wipe=False) class _WithBufName(object): def __init__(self, new): self.new = new def __enter__(self): import os buffer = current.buffer self.buffer = buffer self.old = buffer.name buffer.name = self.new def __exit__(self, *args): self.buffer.name = self.old class _WithNewTabPage(object): def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs def __enter__(self): self.tab = _tabnew(*self.args, **self.kwargs) def __exit__(self, *args): self.tab._close() class _WithGlobal(object): def __init__(self, **kwargs): self.kwargs = kwargs def __enter__(self): self.empty = object() self.old = dict(((key, globals().get(key, self.empty)) for key in self.kwargs)) globals().update(self.kwargs) def __exit__(self, *args): for k, v in self.old.items(): if v is self.empty: globals().pop(k, None) else: globals()[k] = v @_vim def _with(key, *args, **kwargs): if key == 'buffer': return _WithNewBuffer(_edit, *args, **kwargs) elif key == 'bufname': return _WithBufName(*args, **kwargs) elif key == 'mode': return _WithMode(*args, **kwargs) elif key == 'bufoptions': return _WithBufOption(**kwargs) elif key == 'options': return _WithDict(options, **kwargs) elif key == 'globals': return _WithDict(vars, **kwargs) elif key == 'wvars': return _WithDict(current.window.vars, **kwargs) elif key == 'environ': return _WithDict(_environ, **kwargs) elif key == 'split': return _WithSplit() elif key == 'tabpage': return _WithNewTabPage(*args, **kwargs) elif key == 'vpos': return _WithGlobal(_v_pos=[0, kwargs['line'], kwargs['col'], kwargs['off']]) class error(Exception): pass powerline-2.8.4/tests/shlib/000077500000000000000000000000001466405252600160065ustar00rootroot00000000000000powerline-2.8.4/tests/shlib/common.sh000066400000000000000000000065001466405252600176330ustar00rootroot00000000000000: ${USER:=`id -un`} : ${HOME:=`getent passwd $USER | cut -d: -f6`} if test -z "${PYTHON}" ; then if test -n "$USE_UCS2_PYTHON" ; then LD_LIBRARY_PATH="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/lib${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}" fi fi export LD_LIBRARY_PATH export USER export HOME if test -n "$USE_UCS2_PYTHON" ; then POWERLINE_VIRTUALENV="cpython-ucs2-$UCS2_PYTHON_VARIANT" PYTHON="$HOME/.virtualenvs/$POWERLINE_VIRTUALENV/bin/python" if test -n "$BASH_VERSION" ; then set +e . virtualenvwrapper.sh workon "$POWERLINE_VIRTUALENV" set -e fi fi . tests/bot-ci/scripts/common/main.sh silent export USER HOME if test -z "$FAILED" ; then FAILED=0 FAIL_SUMMARY="" TMP_ROOT="$ROOT/tests/tmp" export FAILURES_FILE="$ROOT/tests/status" fi ANSI_CLEAR="\033[0K" travis_fold() { local action="$1" local name="$2" name="$(echo -n "$name" | tr '\n\0' '--' | sed -r 's/[^A-Za-z0-9]+/-/g')" name="$(echo -n "$name" | sed -r 's/-$//')" echo -en "travis_fold:${action}:${name}\r${ANSI_CLEAR}" } print_environ() { echo "Using $PYTHON_IMPLEMENTATION version $PYTHON_VERSION." echo "Path to Python executable: $PYTHON." echo "Root: $ROOT." echo "Branch: $BRANCH_NAME." echo "sys.path:" "$PYTHON" -c "for path in __import__('sys').path: print(' %r' % path)" } enter_suite() { set +x local suite_name="$1" ; shift local final="$1" export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE}/$suite_name" travis_fold start "$POWERLINE_CURRENT_SUITE" print_environ if test "$final" = final ; then if test -n "$POWERLINE_SUITE_FINAL" ; then fail __suite__/enter/final E "Final suites do not allow nesting" fi export POWERLINE_SUITE_FINAL=1 # set -x fi } exit_suite() { if test "$POWERLINE_CURRENT_SUITE" = "$POWERLINE_TMP_DIR_SUITE" ; then rm_test_root fi if test $FAILED -ne 0 ; then echo "Suite ${POWERLINE_CURRENT_SUITE} failed, summary:" echo "${FAIL_SUMMARY}" fi set +x travis_fold end "$POWERLINE_CURRENT_SUITE" export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE%/*}" if test "$1" != "--continue" ; then exit $FAILED else unset POWERLINE_SUITE_FINAL fi } _fail() { local allow_failure= if test "$1" = "--allow-failure" ; then shift allow_failure=A fi local test_name="$1" ; shift local fail_char="$allow_failure$1" ; shift local message="$1" ; shift local verb="$1" ; shift local full_msg="$fail_char $POWERLINE_CURRENT_SUITE|$test_name :: $message" FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}" echo "$verb: $full_msg" echo "$full_msg" >> "$FAILURES_FILE" if test -z "$allow_failure" ; then FAILED=1 fi } fail() { _fail "$@" "Failed" } skip() { local test_name="$1" ; shift local message="$1" ; shift _fail --allow-failure "$test_name" S "$message" "Skipped" } make_test_root() { local suffix="${POWERLINE_CURRENT_SUITE##*/}" local tmpdir="$TMP_ROOT/$suffix/" export POWERLINE_TMP_DIR_SUITE="$POWERLINE_CURRENT_SUITE" if test -d "$tmpdir" ; then rm -r "$tmpdir" fi mkdir -p "$tmpdir" export TEST_ROOT="$tmpdir" } rm_test_root() { if test -e "$FAILURES_FILE" ; then return 0 fi local suffix="${POWERLINE_CURRENT_SUITE##*/}" if test -d "$TMP_ROOT/$suffix" ; then rm -r "$TMP_ROOT/$suffix" rmdir "$TMP_ROOT" &>/dev/null || true fi } if ! command -v realpath ; then realpath() { $PYTHON -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$1" } fi powerline-2.8.4/tests/shlib/vim.sh000066400000000000000000000021321466405252600171330ustar00rootroot00000000000000. tests/bot-ci/scripts/common/main.sh if test -z "$POWERLINE_VIM_EXE" ; then if test -n "$USE_UCS2_PYTHON" ; then NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$UCS2_PYTHON_VARIANT-ucs2-double/vim" OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$UCS2_PYTHON_VARIANT-ucs2/vim" opt_dir="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT" main_path="$opt_dir/lib/python$UCS2_PYTHON_VARIANT" site_path="$main_path/site-packages" venv_main_path="$VIRTUAL_ENV/lib/python$UCS2_PYTHON_VARIANT" venv_site_path="$venv_main_path/site-packages" new_paths="${main_path}:${site_path}:${venv_main_path}:${venv_site_path}" export PYTHONPATH="$new_paths${PYTHONPATH:+:}$PYTHONPATH" else if test "$PYTHON_IMPLEMENTATION" != "CPython" ; then exit 0 fi if test -d "$ROOT/tests/bot-ci/deps" ; then NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$PYTHON_MM/vim" OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$PYTHON_MM/vim" else NEW_VIM="vim" fi if test -e "$OLD_VIM" ; then VIMS="NEW_VIM OLD_VIM" else VIMS="NEW_VIM" fi fi else NEW_VIM="$POWERLINE_VIM_EXE" OLD_VIM="$POWERLINE_VIM_EXE" fi powerline-2.8.4/tests/shlib/vterm.sh000066400000000000000000000004271466405252600175020ustar00rootroot00000000000000. tests/shlib/common.sh set +x vterm_setup() { make_test_root mkdir "$TEST_ROOT/path" ln -s "$(command -v "${PYTHON}")" "$TEST_ROOT/path/python" ln -s "$(command -v bash)" "$TEST_ROOT/path" cp -r "$ROOT/tests/terminfo" "$TEST_ROOT" } vterm_shutdown() { rm_test_root } powerline-2.8.4/tests/terminfo/000077500000000000000000000000001466405252600165305ustar00rootroot00000000000000powerline-2.8.4/tests/terminfo/s/000077500000000000000000000000001466405252600167725ustar00rootroot00000000000000powerline-2.8.4/tests/terminfo/s/screen000066400000000000000000000030341466405252600201740ustar00rootroot00000000000000*+ijscreen|VT 100/ANSI X3.64 virtual terminalP@%)->@DKMY]`fjnpuz "*25>GPYbkt}(,38>DIRV` [%i%p1%d;%p2%dr[%i%p1%d;%p2%dH [?25l[?25hM[?1049h[?1049lg)0[3~OBOP[21~OQOROS[15~[17~[18~[19~[20~[1~[2~OD[6~[5~OCOA[?1l>[?1h=E[%p1%dP[%p1%dM[%p1%dB[%p1%d@[%p1%dL[%p1%dD[%p1%dC[%p1%dAc[?1000l[?25h87 M[0%?%p6%t;1%;%?%p1%t;3%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;m%?%p9%t%e%;H ++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~(B)0[4~[23~[24~[3%p1%dm[4%p1%dm. (B(%p1%cAXG0XTU8E0S0ka2kb1kb3kc2powerline-2.8.4/tests/terminfo/s/st-256color000066400000000000000000000044241466405252600207200ustar00rootroot00000000000000(ist-256color| simpleterm with 256 colorsP&*.9JLPWYfjnuy} %)/37;AGMSY^cjnsx| "%wz| #*18?GOW_gow'/7>ELS[cks{BGMQ [%i%p1%d;%p2%dr[%i%p1%dG[%i%p1%d;%p2%dH [?25l[?12l[?25h[?25h(0[?1049h[%p1%dX(B[?1049l[?5h[?5l>[?1034l[3;5~7[3;2~OB[2;2~OP[21~OQOROS[15~[17~[18~[19~[20~[1~[2~[2;5~OD[6~[5~OCOA[?1l>[?1h=[%p1%dP[%p1%dM[%p1%dB[%p1%d@[%p1%dS[%p1%dL[%p1%dD[%p1%dC[%p1%dAc>[?1034l8[%i%p1%dd7 M%?%p9%t(0%e(B%;[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;mH ]0;[1~[5~Ou[4~[6~``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~)0[4~OM[3;2~[2;2~[6;2~[5;2~[23~[24~[15;2~[17;2~[18;2~[19;2~[20;2~[21;2~[23;2~[24;2~[15;5~[17;5~[18;5~[19;5~[20;5~[21;5~[23;5~[24;5~[15;6~[17;6~[18;6~[19;6~[20;6~[21;6~[23;6~[24;6~[15;3~[17;3~[18;3~[19;3~[20;3~[21;3~[23;3~[24;3~[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;mpowerline-2.8.4/tests/test.sh000077500000000000000000000022161466405252600162240ustar00rootroot00000000000000#!/bin/bash . tests/shlib/common.sh enter_suite root if test "$TRAVIS" = true ; then export PATH="$HOME/opt/fish/bin:${PATH}" export PATH="$PWD/tests/bot-ci/deps/rc:$PATH" if test "$PYTHON_IMPLEMENTATION" = "CPython" ; then export PATH="$HOME/opt/zsh-${PYTHON_MM}${USE_UCS2_PYTHON:+-ucs2}/bin:${PATH}" fi if test -n "$USE_UCS2_PYTHON" ; then export LD_LIBRARY_PATH="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" set +e . virtualenvwrapper.sh workon cpython-ucs2-$UCS2_PYTHON_VARIANT set -e else LIBRARY_PATH="$(ldd "$(command -v python)" | grep libpython | sed 's/^.* => //;s/ .*$//')" LIBRARY_DIR="$(dirname "${LIBRARY_PATH}")" export LD_LIBRARY_PATH="$LIBRARY_DIR${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" fi fi export PYTHON="${PYTHON:=python}" export PYTHONPATH="${PYTHONPATH}${PYTHONPATH:+:}`realpath .`" for script in "$ROOT"/tests/test_*/test.sh ; do test_name="${script##*/run_}" if ! sh $script ; then fail "${test_name%_tests.sh}" F "Failed $script" fi done if test -e "$FAILURES_FILE" ; then echo "Fails and skips summary:" cat "$FAILURES_FILE" rm "$FAILURES_FILE" fi exit_suite powerline-2.8.4/tests/test_awesome/000077500000000000000000000000001466405252600174045ustar00rootroot00000000000000powerline-2.8.4/tests/test_awesome/path/000077500000000000000000000000001466405252600203405ustar00rootroot00000000000000powerline-2.8.4/tests/test_awesome/path/awesome-client000077500000000000000000000001261466405252600232010ustar00rootroot00000000000000#!/bin/sh echo "$@" >> "$TEST_ROOT/results/args" cat >> "$TEST_ROOT/results/requests" powerline-2.8.4/tests/test_awesome/powerline/000077500000000000000000000000001466405252600214105ustar00rootroot00000000000000powerline-2.8.4/tests/test_awesome/powerline/config.json000066400000000000000000000000711466405252600235460ustar00rootroot00000000000000{ "ext": { "wm": { "update_interval": 0.5 } } } powerline-2.8.4/tests/test_awesome/powerline/themes/000077500000000000000000000000001466405252600226755ustar00rootroot00000000000000powerline-2.8.4/tests/test_awesome/powerline/themes/wm/000077500000000000000000000000001466405252600233205ustar00rootroot00000000000000powerline-2.8.4/tests/test_awesome/powerline/themes/wm/default.json000066400000000000000000000003731466405252600256420ustar00rootroot00000000000000{ "segments": { "left": [ { "type": "string", "highlight_groups": ["time"], "contents": "default-left" } ], "right": [ { "type": "string", "highlight_groups": ["time"], "contents": "default-right" } ] } } powerline-2.8.4/tests/test_awesome/powerline/themes/wm/dvi.json000066400000000000000000000003631466405252600247770ustar00rootroot00000000000000{ "segments": { "left": [ { "type": "string", "highlight_groups": ["time"], "contents": "dvi-left" } ], "right": [ { "type": "string", "highlight_groups": ["time"], "contents": "dvi-right" } ] } } powerline-2.8.4/tests/test_awesome/test.sh000077500000000000000000000123451466405252600207270ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh enter_suite awesome make_test_root TEST_PATH="$TEST_ROOT/path" TEST_STATIC_ROOT="$ROOT/tests/test_awesome" cp -r "$TEST_STATIC_ROOT/path" "$TEST_ROOT" cp -r "$TEST_STATIC_ROOT/powerline" "$TEST_ROOT" export PYTHONPATH="$ROOT${PYTHONPATH:+:}$PYTHONPATH" ln -s "$(command -v "${PYTHON}")" "$TEST_PATH"/python ln -s "$(command -v cat)" "$TEST_PATH" ln -s "$(command -v sh)" "$TEST_PATH" ln -s "$(command -v env)" "$TEST_PATH" if command -v socat ; then ln -s "$(command -v socat)" "$TEST_PATH" fi for pexe in powerline powerline.sh powerline.py ; do if test -e scripts/$pexe ; then ln -s "$PWD/scripts/$pexe" $TEST_ROOT/path elif test -e client/$pexe ; then ln -s "$PWD/client/$pexe" $TEST_ROOT/path elif command -v $pexe ; then ln -s "$(command -v $pexe)" $TEST_ROOT/path else continue fi if test "$pexe" != 'powerline.sh' || test -e "$TEST_PATH/socat" ; then POWERLINE_COMMAND="$pexe" break fi done DEPRECATED_SCRIPT="$ROOT/powerline/bindings/awesome/powerline-awesome.py" POWERLINE_DAEMON="scripts/powerline-daemon" run() { env -i \ LANG=C \ PATH="$TEST_PATH" \ XDG_CONFIG_HOME="$TEST_ROOT" \ XDG_CONFIG_DIRS="$TEST_ROOT/dummy" \ PYTHONPATH="$PYTHONPATH" \ TEST_ROOT="$TEST_ROOT" \ LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ "$@" || true } display_log() { local log_file="$1" echo "$log_file:" echo '============================================================' cat -v "$log_file" echo echo '____________________________________________________________' } check_log() { local args_file="$TEST_ROOT/results/args" local log_file="$TEST_ROOT/results/requests" local line="$(head -n1 "$log_file")" local linenum="$(cat "$log_file" | wc -l)" echo "Number of runs: $linenum (expected approx 5 / 0.5 = 10 runs)" if test $linenum -lt 5 ; then fail "log:lt" F "Script was run not enough times: $linenum < 5" return 1 elif test $linenum -gt 15 ; then fail "log:gt" E "Script was run too many times: $linenum > 15" return 1 fi local expline="powerline_widget:set_markup(' default-right ')" if test "$expline" != "$line" ; then echo "Line: '$line'" echo "Expected: '$expline'" fail "log:line" F "Unexpected line" return 1 fi local ret=0 while test $linenum -gt 0 ; do echo "$line" >> "$TEST_ROOT/ok" linenum=$(( linenum - 1 )) done if ! diff "$TEST_ROOT/ok" "$log_file" ; then fail "log:diff" F "Unexpected output" ret=1 fi rm "$TEST_ROOT/ok" return $ret } killscript() { kill -KILL $1 || true } if ! test -e "$DEPRECATED_SCRIPT" ; then # TODO: uncomment when skip is available # skip "deprecated" "Missing deprecated bar bindings script" : else enter_suite "deprecated" final for args in "" "0.5"; do rm -rf "$TEST_ROOT/results" mkdir "$TEST_ROOT/results" DEPRECATED_LOG="$TEST_ROOT/deprecated.log" run env \ DEPRECATED_SCRIPT="$DEPRECATED_SCRIPT" \ args="$args" \ DEPRECATED_LOG="$DEPRECATED_LOG" \ TEST_ROOT="$TEST_ROOT" \ sh -c ' echo $$ > "$TEST_ROOT/$args-pid" exec "$DEPRECATED_SCRIPT" $args > "$DEPRECATED_LOG" 2>&1 ' & sleep 5 killscript "$(cat "$TEST_ROOT/$args-pid")" rm "$TEST_ROOT/$args-pid" if test -n "$(cat "$DEPRECATED_LOG")" ; then display_log "$DEPRECATED_LOG" fail "output" E "Nonempty $DEPRECATED_SCRIPT output" fi rm "$DEPRECATED_LOG" if ! check_log ; then display_log "$TEST_ROOT/results/args" fail "log" F "Checking log failed" fi done exit_suite --continue fi enter_suite "awesome" final ADDRESS="powerline-ipc-test-$$" echo "Powerline address: $ADDRESS" rm -rf "$TEST_ROOT/results" mkdir "$TEST_ROOT/results" run env \ POWERLINE_DAEMON="$POWERLINE_DAEMON" \ TEST_ROOT="$TEST_ROOT" \ ADDRESS="$ADDRESS" \ sh -c ' echo $$ > "$TEST_ROOT/dpid" exec python "$POWERLINE_DAEMON" --socket $ADDRESS --foreground > "$TEST_ROOT/daemon.log" 2>&1 ' & DPID=$! sleep 2 run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.1" 2>&1 run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.2" 2>&1 run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.3" 2>&1 run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.4" 2>&1 run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.5" 2>&1 for log_file in "$TEST_ROOT"/output.log.* ; do if test -n "$(cat "$log_file")" ; then display_log "$log_file" fail "output" E "Nonempty $POWERLINE_COMMAND output at run ${log_file#*.}" fi rm "$log_file" done sleep 5 run python "$POWERLINE_DAEMON" --socket $ADDRESS --quiet --kill > "$TEST_ROOT/kill.log" 2>&1 if test -n "$(cat "$TEST_ROOT/kill.log")" ; then display_log "$TEST_ROOT/kill.log" fail "daemonlog" E "Nonempty kill log" fi rm "$TEST_ROOT/kill.log" wait $DPID if test -n "$(cat "$TEST_ROOT/daemon.log")" ; then display_log "$TEST_ROOT/daemon.log" fail "daemonlog" E "Nonempty daemon log" fi rm "$TEST_ROOT/daemon.log" if ! check_log ; then display_log "$TEST_ROOT/results/args" fail "log" F "Checking log failed" fi exit_suite --continue if ! powerline-lint \ -p "$ROOT/powerline/config_files" \ -p "$TEST_STATIC_ROOT/powerline" then fail "lint" F "Checking test config failed" fi exit_suite powerline-2.8.4/tests/test_bar/000077500000000000000000000000001466405252600165105ustar00rootroot00000000000000powerline-2.8.4/tests/test_bar/path/000077500000000000000000000000001466405252600174445ustar00rootroot00000000000000powerline-2.8.4/tests/test_bar/path/lemonbar000077500000000000000000000003701466405252600211710ustar00rootroot00000000000000#!/bin/sh RES_DIR="$TEST_ROOT/results" mkdir -p "$RES_DIR" RES_FILE="$RES_DIR/$$" while test -e "$RES_FILE.log" ; do RES_FILE="$RES_FILE.${RANDOM:-`date +%N | sed s/^0*//`}" done echo $(basename $0) "$@" > "$RES_FILE.args" cat > "$RES_FILE.log" powerline-2.8.4/tests/test_bar/path/xrandr000077500000000000000000000017731466405252600207000ustar00rootroot00000000000000#!/bin/sh cat << EOF Screen 0: minimum 8 x 8, current 1920 x 1200, maximum 16384 x 16384 DVI-I-0 disconnected (normal left inverted right x axis y axis) VGA-0 connected 1920x1200+1+0 (normal left inverted right x axis y axis) 520mm x 330mm 1920x1200 59.95*+ 1920x1080 60.00 1680x1050 59.95 1600x1200 60.00 1440x900 59.89 1280x1024 75.02 60.02 1280x800 59.81 1152x864 75.00 1024x768 75.03 60.00 800x600 75.00 60.32 640x480 75.00 59.94 DVI-I-1 connected 1920x1200+0+0 (normal left inverted right x axis y axis) 520mm x 330mm 1920x1200 59.95*+ 1920x1080 60.00 1680x1050 59.95 1600x1200 60.00 1440x900 59.89 1280x1024 75.02 60.02 1280x800 59.81 1152x864 75.00 1024x768 75.03 60.00 800x600 75.00 60.32 640x480 75.00 59.94 HDMI-0 disconnected (normal left inverted right x axis y axis) EOF powerline-2.8.4/tests/test_bar/powerline/000077500000000000000000000000001466405252600205145ustar00rootroot00000000000000powerline-2.8.4/tests/test_bar/powerline/config.json000066400000000000000000000001161466405252600226520ustar00rootroot00000000000000{ "ext": { "wm": { "local_themes": { "DVI-I-1": "dvi" } } } } powerline-2.8.4/tests/test_bar/powerline/themes/000077500000000000000000000000001466405252600220015ustar00rootroot00000000000000powerline-2.8.4/tests/test_bar/powerline/themes/wm/000077500000000000000000000000001466405252600224245ustar00rootroot00000000000000powerline-2.8.4/tests/test_bar/powerline/themes/wm/default.json000066400000000000000000000003731466405252600247460ustar00rootroot00000000000000{ "segments": { "left": [ { "type": "string", "highlight_groups": ["time"], "contents": "default-left" } ], "right": [ { "type": "string", "highlight_groups": ["time"], "contents": "default-right" } ] } } powerline-2.8.4/tests/test_bar/powerline/themes/wm/dvi.json000066400000000000000000000003631466405252600241030ustar00rootroot00000000000000{ "segments": { "left": [ { "type": "string", "highlight_groups": ["time"], "contents": "dvi-left" } ], "right": [ { "type": "string", "highlight_groups": ["time"], "contents": "dvi-right" } ] } } powerline-2.8.4/tests/test_bar/test.sh000077500000000000000000000123371466405252600200340ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh enter_suite bar make_test_root TEST_PATH="$TEST_ROOT/path" TEST_STATIC_ROOT="$ROOT/tests/test_bar" cp -r "$TEST_STATIC_ROOT/path" "$TEST_ROOT" cp -r "$TEST_STATIC_ROOT/powerline" "$TEST_ROOT" export PYTHONPATH="$ROOT${PYTHONPATH:+:}$PYTHONPATH" ln -s "$(command -v "${PYTHON}")" "$TEST_PATH"/python ln -s "$(command -v sed)" "$TEST_PATH" ln -s "$(command -v cat)" "$TEST_PATH" ln -s "$(command -v mkdir)" "$TEST_PATH" ln -s "$(command -v basename)" "$TEST_PATH" ln -s "$TEST_PATH/lemonbar" "$TEST_PATH/bar-aint-recursive" DEPRECATED_SCRIPT="$ROOT/powerline/bindings/bar/powerline-bar.py" run() { env -i \ LANG=C \ PATH="$TEST_PATH" \ XDG_CONFIG_HOME="$TEST_ROOT" \ XDG_CONFIG_DIRS="$TEST_ROOT/dummy" \ PYTHONPATH="$PYTHONPATH" \ TEST_ROOT="$TEST_ROOT" \ LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ "$@" || true } display_log() { local log_file="$1" echo "$log_file:" echo '============================================================' cat -v "$log_file" echo echo '____________________________________________________________' } check_log() { local log_file="$1" local text="$2" local warns="$3" if test "$warns" = "warns" ; then local warning="$(head -n1 "$log_file" | sed 's/.*://')" local expwarning="The 'bar' bindings are deprecated, please switch to 'lemonbar'" if test "$warning" != "$expwarning" ; then echo "Got: $warning" echo "Exp: $expwarning" fail "warn" F "Expected warning" fi sed -r -i -e '1d' "$log_file" fi local line="$(head -n1 "$log_file")" local linenum="$(cat "$log_file" | wc -l)" if test $linenum -lt 5 ; then fail "log:lt" F "Script was run not enough times" return 1 elif test $linenum -gt 15 ; then fail "log:gt" E "Script was run too many times" return 1 fi local expline="%{l}%{F#ffd0d0d0}%{B#ff303030} $text-left %{F-B--u}%{F#ff303030} %{F-B--u}%{r}%{F#ff303030} %{F-B--u}%{F#ffd0d0d0}%{B#ff303030} $text-right %{F-B--u}" if test "$expline" != "$line" ; then echo "Line: '$line'" echo "Expected: '$expline'" fail "log:line" F "Unexpected line" return 1 fi local ret=0 while test $linenum -gt 0 ; do echo "$line" >> "$TEST_ROOT/ok" linenum=$(( linenum - 1 )) done if ! diff "$TEST_ROOT/ok" "$log_file" ; then fail "log:diff" F "Unexpected output" ret=1 fi rm "$TEST_ROOT/ok" return $ret } killscript() { kill -KILL $1 || true } if ! test -e "$DEPRECATED_SCRIPT" ; then # TODO: uncomment when skip is available # skip "deprecated" "Missing deprecated bar bindings script" : else enter_suite "deprecated" final run python "$DEPRECATED_SCRIPT" $args > "$TEST_ROOT/deprecated.log" 2>&1 & SPID=$! sleep 5 killscript $SPID if ! check_log "$TEST_ROOT/deprecated.log" "default" warns ; then display_log "$TEST_ROOT/deprecated.log" fail "log" F "Checking log failed" fi rm "$TEST_ROOT/deprecated.log" exit_suite --continue fi LEMONBAR_SCRIPT="$ROOT/powerline/bindings/lemonbar/powerline-lemonbar.py" if ! test -e "$LEMONBAR_SCRIPT" ; then # TODO: uncomment when skip is available # skip "lemonbar" "Missing lemonbar bindings script" : else enter_suite "lemonbar" for args in "" "-i0.5" "--interval=0.5" "-- test args" "--bar-command bar-aint-recursive" "--height=10"; do rm -rf "$TEST_ROOT/results" run python "$LEMONBAR_SCRIPT" $args > "$TEST_ROOT/lemonbar.log" 2>&1 & SPID=$! sleep 5 killscript $SPID sleep 0.5 enter_suite "args($args)" final fnum=0 for file in "$TEST_ROOT/results"/*.log ; do if ! test -e "$file" ; then fail "log" E "Log file is missing" break fi fnum=$(( fnum + 1 )) args_file="${file%.log}.args" if ! test -e "$args_file" ; then fail "args" E "$args_file is missing" else cat "$args_file" >> "$TEST_ROOT/args.log" fi text="dvi" if cat "$args_file" | grep -q +1 ; then text="default" fi if ! check_log "$file" "$text" ; then display_log "$file" fail "log" F "Checking log failed" fi rm "$file" done if test "$fnum" -ne 2 ; then fail "fnum" F "Expected two output files" fi if test "${args#--height}" != "$args" ; then height="${args#--height}" height="${height# }" height="${height#=}" height="${height%% *}" fi command="lemonbar" if test "${args#--bar-command}" != "$args" ; then command="${args#--bar-command}" command="${command# }" command="${command#=}" command="${command%% *}" fi received_args="$(cat "$TEST_ROOT/args.log" | sort)" rm "$TEST_ROOT/args.log" script_args="${args#*-- }" script_args="${script_args# }" if test "${script_args}" = "$args" ; then script_args= fi expected_args="$command -g 1920x$height+0+0${script_args:+ }$script_args${NL}$command -g 1920x$height+1+0${script_args:+ }$script_args" if test "$expected_args" != "$received_args" ; then echo "args:${NL}<$received_args>" echo "expected:${NL}<$expected_args>" fail "args" F "Expected different args" fi if ! test -z "$(cat "$TEST_ROOT/lemonbar.log")" ; then display_log "$TEST_ROOT/lemonbar.log" fail "stderr" E "Unexpected script output" fi rm "$TEST_ROOT/lemonbar.log" exit_suite --continue done exit_suite --continue fi if ! powerline-lint \ -p "$ROOT/powerline/config_files" \ -p "$TEST_STATIC_ROOT/powerline" then fail "lint" F "Checking test config failed" fi exit_suite powerline-2.8.4/tests/test_daemon/000077500000000000000000000000001466405252600172075ustar00rootroot00000000000000powerline-2.8.4/tests/test_daemon/test.sh000077500000000000000000000021331466405252600205240ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh enter_suite daemon final export ADDRESS="powerline-ipc-test-$$" echo "Powerline address: $ADDRESS" if "$PYTHON" "$ROOT/scripts/powerline-daemon" -s"$ADDRESS" ; then sleep 1 if ! ( \ "$PYTHON" "$ROOT/client/powerline.py" \ --socket "$ADDRESS" -p/dev/null shell left \ | grep "file not found" ) ; then fail "devnull" F "-p/dev/null argument ignored or not treated properly" fi if ( \ "$PYTHON" "$ROOT/client/powerline.py" --socket "$ADDRESS" \ -p"$ROOT/powerline/config_files" shell left \ | grep "file not found" ) ; then fail "nodevnull" F "-p/dev/null argument remembered while it should not" fi if ! ( \ cd "$ROOT/tests/test_daemon" \ && "$PYTHON" "$ROOT/client/powerline.py" --socket "$ADDRESS" \ -p"$ROOT/powerline/config_files" shell left \ | grep "test_daemon" ) ; then fail "segment" F "Output lacks string “tests”" fi else fail "exitcode" E "Daemon exited with status $?" fi if "$PYTHON" "$ROOT/scripts/powerline-daemon" -s"$ADDRESS" -k ; then : else fail "-k" F "powerline-daemon -k failed with exit code $?" fi exit_suite powerline-2.8.4/tests/test_in_vterm/000077500000000000000000000000001466405252600175675ustar00rootroot00000000000000powerline-2.8.4/tests/test_in_vterm/shell/000077500000000000000000000000001466405252600206765ustar00rootroot00000000000000powerline-2.8.4/tests/test_in_vterm/shell/inits/000077500000000000000000000000001466405252600220245ustar00rootroot00000000000000powerline-2.8.4/tests/test_in_vterm/shell/inits/dash000066400000000000000000000006651466405252600226750ustar00rootroot00000000000000# vim: ft=sh set_theme_option() { export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" } set_theme() { export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" } set_virtual_env() { export VIRTUAL_ENV="$HOME/.virtenvs/$1" } set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false set_theme default_leftonly . "$ROOT/powerline/bindings/shell/powerline.sh" export VIRTUAL_ENV= cd "$TEST_ROOT/3rd" powerline-2.8.4/tests/test_in_vterm/test.sh000077500000000000000000000003571466405252600211120ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh enter_suite vterm # (Disabled) #for t in "$ROOT"/tests/test_in_vterm/test_*.sh ; do # test_name="${t##*/test_}" # if ! "$t" ; then # fail "${test_name%.sh}" F "Failed running $t" # fi #done exit_suite powerline-2.8.4/tests/test_in_vterm/test_shells.py000077500000000000000000000076721466405252600225110ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import sys from time import sleep from subprocess import check_call from glob import glob1 from traceback import print_exc from argparse import ArgumentParser from powerline.lib.dict import updated from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, do_terminal_tests, get_env) from tests.modules import PowerlineTestSuite TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT']) def get_parser(): parser = ArgumentParser() parser.add_argument('--type', action='store') parser.add_argument('--client', action='store') parser.add_argument('--binding', action='store') parser.add_argument('args', action='append') return parser BINDING_OPTIONS = { 'dash': { 'cmd': 'dash', 'args': ['-i'], 'init': [ '. "$ROOT/tests/test_in_vterm/shell/inits/dash"', ], }, } def main(argv): script_args = get_parser().parse_args(argv) vterm_path = os.path.join(TEST_ROOT, 'path') env = get_env(vterm_path, TEST_ROOT) env['ROOT'] = os.path.abspath('.') env['TEST_ROOT'] = TEST_ROOT env['TEST_TYPE'] = script_args.type env['TEST_CLIENT'] = script_args.client env['LANG'] = 'en_US.UTF_8' env['_POWERLINE_RUNNING_SHELL_TESTS'] = ( 'ee5bcdc6-b749-11e7-9456-50465d597777') dim = MutableDimensions(rows=50, cols=200) binding_opts = BINDING_OPTIONS[script_args.binding] cmd = os.path.join(vterm_path, binding_opts['cmd']) args = binding_opts['args'] def gen_init(binding): def init(p): for line in binding_opts['init']: p.send(line + '\n') sleep(1) return init def gen_feed(line): def feed(p): p.send(line + '\n') sleep(0.1) return feed base_attrs = { ((255, 204,0), (204, 51, 0), 0, 0, 0): 'H', ((204, 51, 0), (0, 102, 153), 0, 0, 0): 'sHU', ((255, 255, 255), (0, 102, 153), 1, 0, 0): 'U', ((0, 102, 153), (44, 44, 44), 0, 0, 0): 'sUB', ((199, 199, 199), (44, 44, 44), 0, 0, 0): 'B', ((44, 44, 44), (88, 88, 88), 0, 0, 0): 'sBD', ((199, 199, 199), (88, 88, 88), 0, 0, 0): 'D', ((144, 144, 144), (88, 88, 88), 0, 0, 0): 'sD', ((221, 221, 221), (88, 88, 88), 1, 0, 0): 'C', ((88, 88, 88), (0, 0, 0), 0, 0, 0): 'sDN', ((240, 240, 240), (0, 0, 0), 0, 0, 0): 'N', ((0, 102, 153), (51, 153, 204), 0, 0, 0): 'sUE', ((255, 255, 255), (51, 153, 204), 0, 0, 0): 'E', ((51, 153, 204), (44, 44, 44), 0, 0, 0): 'sEB', } tests = ( { 'expected_result': ( '{H:  hostname }{sHU: }' '{U:user }{sUB: }' '{B: BRANCH }{sBD: }' '{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }' '{N:}', base_attrs, ), 'prep_cb': gen_init(script_args.binding), }, { 'expected_result': ( '{H:  hostname }{sHU: }' '{U:user }{sUB: }' '{B: BRANCH }{sBD: }' '{D:… }{sD: }{D:vshells }{sD: }{D:3rd }{sD: }{C:.git }{sDN: }' '{N:}', base_attrs ), 'prep_cb': gen_feed('cd .git'), }, { 'expected_result': ( '{H:  hostname }{sHU: }' '{U:user }{sUB: }' '{B: BRANCH }{sBD: }' '{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }' '{N:}', base_attrs, ), 'prep_cb': gen_feed('cd ..'), }, { 'expected_result': ( '{H:  hostname }{sHU: }' '{U:user }{sUE: }' '{E:(e) some-venv }{sEB: }' '{B: BRANCH }{sBD: }' '{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }' '{N:}', base_attrs, ), 'prep_cb': gen_feed('set_virtual_env some-venv'), }, ) with PowerlineTestSuite('shell') as suite: return do_terminal_tests( tests=tests, cmd=cmd, dim=dim, args=args, env=env, cwd=TEST_ROOT, suite=suite, ) if __name__ == '__main__': if main(sys.argv[1:]): raise SystemExit(0) else: raise SystemExit(1) powerline-2.8.4/tests/test_in_vterm/test_shells.sh000077500000000000000000000070021466405252600224560ustar00rootroot00000000000000#!/bin/bash . tests/shlib/common.sh . tests/shlib/vterm.sh enter_suite vshells vterm_setup HAS_SOCAT= HAS_C_CLIENT= git init "$TEST_ROOT/3rd" git --git-dir="$TEST_ROOT/3rd/.git" checkout -b BRANCH export DIR1="" export DIR2="" mkdir "$TEST_ROOT/3rd/$DIR1" mkdir "$TEST_ROOT/3rd/$DIR2" mkdir "$TEST_ROOT"/3rd/'\[\]' mkdir "$TEST_ROOT"/3rd/'%%' mkdir "$TEST_ROOT"/3rd/'#[bold]' mkdir "$TEST_ROOT"/3rd/'(echo)' mkdir "$TEST_ROOT"/3rd/'$(echo)' mkdir "$TEST_ROOT"/3rd/'`echo`' mkdir "$TEST_ROOT"/3rd/'«Unicode!»' mkdir "$TEST_ROOT/fish_home" mkdir "$TEST_ROOT/fish_home/fish" mkdir "$TEST_ROOT/fish_home/fish/generated_completions" cp -r "$ROOT/tests/test_shells/ipython_home" "$TEST_ROOT" ln -s "$(command -v env)" "$TEST_ROOT/path" ln -s "$(command -v git)" "$TEST_ROOT/path" ln -s "$(command -v sleep)" "$TEST_ROOT/path" ln -s "$(command -v cat)" "$TEST_ROOT/path" ln -s "$(command -v false)" "$TEST_ROOT/path" ln -s "$(command -v true)" "$TEST_ROOT/path" ln -s "$(command -v kill)" "$TEST_ROOT/path" ln -s "$(command -v echo)" "$TEST_ROOT/path" ln -s "$(command -v which)" "$TEST_ROOT/path" ln -s "$(command -v dirname)" "$TEST_ROOT/path" ln -s "$(command -v wc)" "$TEST_ROOT/path" ln -s "$(command -v stty)" "$TEST_ROOT/path" ln -s "$(command -v cut)" "$TEST_ROOT/path" ln -s "$(command -v bc)" "$TEST_ROOT/path" ln -s "$(command -v expr)" "$TEST_ROOT/path" ln -s "$(command -v mktemp)" "$TEST_ROOT/path" ln -s "$(command -v grep)" "$TEST_ROOT/path" ln -s "$(command -v sed)" "$TEST_ROOT/path" ln -s "$(command -v rm)" "$TEST_ROOT/path" ln -s "$(command -v tr)" "$TEST_ROOT/path" ln -s "$(command -v uname)" "$TEST_ROOT/path" ln -s "$(command -v test)" "$TEST_ROOT/path" ln -s "$(command -v pwd)" "$TEST_ROOT/path" ln -s "$(command -v hostname)" "$TEST_ROOT/path" ln -s "$ROOT/tests/test_shells/bgscript.sh" "$TEST_ROOT/path" ln -s "$ROOT/tests/test_shells/waitpid.sh" "$TEST_ROOT/path" ln -s "$ROOT/scripts/powerline-config" "$TEST_ROOT/path" ln -s "$ROOT/scripts/powerline-render" "$TEST_ROOT/path" ln -s "$ROOT/client/powerline.py" "$TEST_ROOT/path" if test -e "$ROOT/scripts/powerline" ; then ln -s "$ROOT/scripts/powerline" "$TEST_ROOT/path" elif test -e client/powerline ; then ln -s "$ROOT/client/powerline" "$TEST_ROOT/path" elif command -v powerline ; then ln -s "$(command -v powerline)" "$TEST_ROOT/path" else echo "Executable powerline was not found" exit 1 fi if test "$( file --mime-type --brief --dereference "$TEST_ROOT/path/powerline" \ | cut -d/ -f1)" = "application" ; then HAS_C_CLIENT=1 fi if command -v socat ; then HAS_SOCAT=1 ln -s "$(command -v socat)" "$TEST_ROOT/path" ln -s "$ROOT/client/powerline.sh" "$TEST_ROOT/path" fi # Test type: daemon, renderer, … # Test client: python, shell, c, none # Test binding: *sh, ipython, pdb, … test_shell() { local test_type="$1" ; shift local test_client="$1" ; shift local test_binding="$1" ; shift if test "$test_client" = shell && test -z "$HAS_SOCAT" ; then echo "Skipping test, socat not available" return fi if test "$test_client" = c && test -z "$HAS_C_CLIENT" ; then echo "Skipping test, C client not available" return fi if command -v "$test_binding" ; then ln -s "$(command -v "$test_binding")" "$TEST_ROOT/path" fi if ! "${PYTHON}" "$ROOT/tests/test_in_vterm/test_shells.py" \ --type=$test_type \ --client=$test_client \ --binding=$test_binding \ -- "$@" then local test_name="$test_type-$test_client-$test_binding" fail "$test_name" F "Failed vterm shell test" fi } test_shell renderer python dash -i || true vterm_shutdown exit_suite powerline-2.8.4/tests/test_in_vterm/test_tmux.py000077500000000000000000000166641466405252600222150ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import sys import json from time import sleep from subprocess import check_call from glob import glob1 from traceback import print_exc from powerline.lib.dict import updated from powerline.bindings.tmux import get_tmux_version from powerline import get_fallback_logger from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, do_terminal_tests, get_env) from tests.modules import PowerlineTestSuite TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT']) def tmux_logs_iter(test_dir): for tail in glob1(test_dir, '*.log'): yield os.path.join(test_dir, tail) def print_tmux_logs(): for f in tmux_logs_iter(TEST_ROOT): print('_' * 80) print(os.path.basename(f) + ':') print('=' * 80) with open(f, 'r') as fp: for line in fp: sys.stdout.write(line) os.unlink(f) def get_expected_result(tmux_version, expected_result_old, expected_result_1_7=None, expected_result_1_8=None, expected_result_2_0=None): if tmux_version >= (2, 0) and expected_result_2_0: return expected_result_2_0 elif tmux_version >= (1, 8) and expected_result_1_8: return expected_result_1_8 elif tmux_version >= (1, 7) and expected_result_1_7: return expected_result_1_7 else: return expected_result_old def tmux_fin_cb(p, cmd, env): try: check_call([ cmd, '-S', env['POWERLINE_TMUX_SOCKET_PATH'], 'kill-server' ], env=env, cwd=TEST_ROOT) except Exception: print_exc() for f in tmux_logs_iter(TEST_ROOT): os.unlink(f) def main(attempts=3): vterm_path = os.path.join(TEST_ROOT, 'path') tmux_exe = os.path.join(vterm_path, 'tmux') socket_path = os.path.abspath('tmux-socket-{0}'.format(attempts)) if os.path.exists(socket_path): os.unlink(socket_path) env = get_env(vterm_path, TEST_ROOT, { 'POWERLINE_THEME_OVERRIDES': ';'.join(( key + '=' + json.dumps(val) for key, val in ( ('default.segments.right', [{ 'type': 'string', 'name': 's1', 'highlight_groups': ['cwd'], 'priority':50, }]), ('default.segments.left', [{ 'type': 'string', 'name': 's2', 'highlight_groups': ['background'], 'priority':20, }]), ('default.segment_data.s1.contents', 'S1 string here'), ('default.segment_data.s2.contents', 'S2 string here'), ) )), 'POWERLINE_TMUX_SOCKET_PATH': socket_path, }) conf_path = os.path.abspath('powerline/bindings/tmux/powerline.conf') conf_line = 'source "' + ( conf_path.replace('\\', '\\\\').replace('"', '\\"')) + '"\n' conf_file = os.path.realpath(os.path.join(TEST_ROOT, 'tmux.conf')) with open(conf_file, 'w') as cf_fd: cf_fd.write(conf_line) tmux_version = get_tmux_version(get_fallback_logger()) dim = MutableDimensions(rows=50, cols=200) def prepare_test_1(p): sleep(5) def prepare_test_2(p): dim.cols = 40 p.resize(dim) sleep(5) base_attrs = { ((0, 0, 0), (243, 243, 243), 1, 0, 0): 'lead', ((243, 243, 243), (11, 11, 11), 0, 0, 0): 'leadsep', ((255, 255, 255), (11, 11, 11), 0, 0, 0): 'bg', ((199, 199, 199), (88, 88, 88), 0, 0, 0): 'cwd', ((88, 88, 88), (11, 11, 11), 0, 0, 0): 'cwdhsep', ((0, 0, 0), (0, 224, 0), 0, 0, 0): 'defstl', } tests = ( { 'expected_result': get_expected_result( tmux_version, expected_result_old=( '{lead: 0 }{leadsep: }{bg: S2 string here }' '{4: 0 }{cwdhsep:| }{6:bash }' '{bg: }{4: 1- }{cwdhsep:| }{6:bash }' '{bg: }{7: }{8:2* | }{9:bash }{10: }' '{bg:' + (' ' * 124) + '}' '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, { ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4, ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6, ((11, 11, 11), (0, 102, 153), 0, 0, 0): 7, ((102, 204, 255), (0, 102, 153), 0, 0, 0): 8, ((255, 255, 255), (0, 102, 153), 1, 0, 0): 9, ((0, 102, 153), (11, 11, 11), 0, 0, 0): 10, })), expected_result_1_8=( '{lead: 0 }{leadsep: }{bg: S2 string here }' '{4: 0 }{cwdhsep:| }{6:bash }' '{bg: }{4: 1- }{cwdhsep:| }{7:bash }' '{bg: }{8: }{9:2* | }{10:bash }{7: }' '{bg:' + (' ' * 124) + '}' '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, { ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4, ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6, ((0, 102, 153), (11, 11, 11), 0, 0, 0): 7, ((11, 11, 11), (0, 102, 153), 0, 0, 0): 8, ((102, 204, 255), (0, 102, 153), 0, 0, 0): 9, ((255, 255, 255), (0, 102, 153), 1, 0, 0): 10, })), expected_result_2_0=( '{lead: 0 }{leadsep: }{bg: S2 string here }' '{4: 0 }{cwdhsep:| }{6:bash }' '{bg: }{4: 1- }{cwdhsep:| }{7:bash }' '{bg: }{8: }{9:2* | }{10:bash }{7: }' '{bg:' + (' ' * 125) + '}' '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, { ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4, ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6, ((0, 102, 153), (11, 11, 11), 0, 0, 0): 7, ((11, 11, 11), (0, 102, 153), 0, 0, 0): 8, ((102, 204, 255), (0, 102, 153), 0, 0, 0): 9, ((255, 255, 255), (0, 102, 153), 1, 0, 0): 10, })), ), 'prep_cb': prepare_test_1, 'row': dim.rows - 1, }, { 'expected_result': get_expected_result( tmux_version, expected_result_old=('{bg:' + (' ' * 40) + '}', base_attrs), expected_result_1_7=( '{lead: 0 }' '{leadsep: }{bg: <}{4:h }{bg: }{5: }' '{6:2* | }{7:bash }{8: }{bg: }{cwdhsep: }' '{cwd: S1 string here }', updated(base_attrs, { ((188, 188, 188), (11, 11, 11), 0, 0, 0): 4, ((11, 11, 11), (0, 102, 153), 0, 0, 0): 5, ((102, 204, 255), (0, 102, 153), 0, 0, 0): 6, ((255, 255, 255), (0, 102, 153), 1, 0, 0): 7, ((0, 102, 153), (11, 11, 11), 0, 0, 0): 8, })), expected_result_1_8=( '{lead: 0 }' '{leadsep: }{bg: <}{4:h }{bg: }{5: }' '{6:2* | }{7:bash }{4: }{bg: }{cwdhsep: }' '{cwd: S1 string here }', updated(base_attrs, { ((0, 102, 153), (11, 11, 11), 0, 0, 0): 4, ((11, 11, 11), (0, 102, 153), 0, 0, 0): 5, ((102, 204, 255), (0, 102, 153), 0, 0, 0): 6, ((255, 255, 255), (0, 102, 153), 1, 0, 0): 7, })), expected_result_2_0=( '{lead: 0 }' '{leadsep: }{bg:<}{4:ash }{bg: }{5: }' '{6:2* | }{7:bash }{4: }{cwdhsep: }' '{cwd: S1 string here }', updated(base_attrs, { ((0, 102, 153), (11, 11, 11), 0, 0, 0): 4, ((11, 11, 11), (0, 102, 153), 0, 0, 0): 5, ((102, 204, 255), (0, 102, 153), 0, 0, 0): 6, ((255, 255, 255), (0, 102, 153), 1, 0, 0): 7, })), ), 'prep_cb': prepare_test_2, 'row': dim.rows - 1, } ) args = [ # Specify full path to tmux socket (testing tmux instance must not # interfere with user one) '-S', socket_path, # Force 256-color mode '-2', # Request verbose logging just in case '-v', # Specify configuration file '-f', conf_file, # Run bash three times 'new-session', 'bash --norc --noprofile -i', ';', 'new-window', 'bash --norc --noprofile -i', ';', 'new-window', 'bash --norc --noprofile -i', ';', ] with PowerlineTestSuite('tmux') as suite: return do_terminal_tests( tests=tests, cmd=tmux_exe, dim=dim, args=args, env=env, cwd=TEST_ROOT, fin_cb=tmux_fin_cb, last_attempt_cb=print_tmux_logs, suite=suite, ) if __name__ == '__main__': if main(): raise SystemExit(0) else: raise SystemExit(1) powerline-2.8.4/tests/test_in_vterm/test_tmux.sh000077500000000000000000000021241466405252600221610ustar00rootroot00000000000000#!/bin/bash . tests/shlib/common.sh . tests/shlib/vterm.sh enter_suite tmux final vterm_setup ln -s "$(command -v env)" "$TEST_ROOT/path" ln -s "$(command -v cut)" "$TEST_ROOT/path" ln -s "$ROOT/scripts/powerline-render" "$TEST_ROOT/path" ln -s "$ROOT/scripts/powerline-config" "$TEST_ROOT/path" test_tmux() { if test "$PYTHON_IMPLEMENTATION" = PyPy; then # FIXME PyPy3 segfaults for some reason, PyPy does it as well, but # occasionally. return 0 fi if ! command -v "${POWERLINE_TMUX_EXE}" ; then return 0 fi ln -sf "$(command -v "${POWERLINE_TMUX_EXE}")" "$TEST_ROOT/path/tmux" f="$ROOT/tests/test_in_vterm/test_tmux.py" if ! "${PYTHON}" "$f" ; then local test_name="$("$POWERLINE_TMUX_EXE" -V 2>&1 | cut -d' ' -f2)" fail "$test_name" F "Failed vterm test $f" fi } if test -z "$POWERLINE_TMUX_EXE" && test -d "$ROOT/tests/bot-ci/deps/tmux" then for tmux in "$ROOT"/tests/bot-ci/deps/tmux/tmux-*/tmux ; do export POWERLINE_TMUX_EXE="$tmux" test_tmux || true done else export POWERLINE_TMUX_EXE="${POWERLINE_TMUX_EXE:-tmux}" test_tmux || true fi vterm_shutdown exit_suite powerline-2.8.4/tests/test_in_vterm/test_vim.py000077500000000000000000000027561466405252600220100ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import sys from time import sleep from subprocess import check_call from glob import glob1 from traceback import print_exc from powerline.lib.dict import updated from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, do_terminal_tests, get_env) from tests.modules import PowerlineTestSuite TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT']) def main(attempts=3): vterm_path = os.path.join(TEST_ROOT, 'path') vim_exe = os.path.join(vterm_path, 'vim') env = get_env(vterm_path, TEST_ROOT) env['ROOT'] = os.path.abspath('.') dim = MutableDimensions(rows=50, cols=200) vimrc = os.path.join(TEST_ROOT, 'init.vim') vimrc_contents = ''' set laststatus=2 set runtimepath=$ROOT/powerline/bindings/vim ''' with open(vimrc, 'w') as vd: vd.write(vimrc_contents) base_attrs = { (( 64, 64, 255), (0, 0, 0), 0, 0, 0): 'NT', # NonText ((240, 240, 240), (0, 0, 0), 0, 0, 0): 'N', # Normal } args = [ '-u', vimrc, '-i', 'NONE', ] def feed(p): p.send(':echo strtrans(eval(&statusline[2:]))\n') tests = ( ) with PowerlineTestSuite('vim') as suite: return do_terminal_tests( tests=tests, cmd=vim_exe, dim=dim, args=args, env=env, cwd=TEST_ROOT, suite=suite, ) if __name__ == '__main__': if main(): raise SystemExit(0) else: raise SystemExit(1) powerline-2.8.4/tests/test_in_vterm/test_vim.sh000077500000000000000000000015361466405252600217650ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh . tests/shlib/vterm.sh . tests/shlib/vim.sh enter_suite vvim final vterm_setup test_vim() { if test "$PYTHON_IMPLEMENTATION" != CPython ; then # Can only link with cpython return 0 fi if ! command -v "$POWERLINE_VIM_EXE" ; then return 0 fi ln -sf "$(command -v "${POWERLINE_VIM_EXE}")" "$TEST_ROOT/path/vim" f="$ROOT/tests/test_in_vterm/test_vim.py" if ! "${PYTHON}" "$f" ; then local test_name="$(LANG=C "$POWERLINE_VIM_EXE" --cmd 'echo version' --cmd qa 2>&1 | tail -n2)" fail "$test_name" F "Failed vterm test $f" fi } if test -z "$POWERLINE_VIM_EXE" && test -d "$ROOT/tests/bot-ci/deps/vim" then for vim in "$OLD_VIM" "$NEW_VIM" ; do export POWERLINE_VIM_EXE="$vim" test_vim || true done else export POWERLINE_VIM_EXE="${POWERLINE_VIM_EXE:-vim}" test_vim || true fi vterm_shutdown exit_suite powerline-2.8.4/tests/test_lint/000077500000000000000000000000001466405252600167125ustar00rootroot00000000000000powerline-2.8.4/tests/test_lint/test.sh000077500000000000000000000003201466405252600202230ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh enter_suite lint final if ! "$PYTHON" "$ROOT/scripts/powerline-lint" -p "$ROOT/powerline/config_files" ; then fail "test" F "Running powerline-lint failed" fi exit_suite powerline-2.8.4/tests/test_python/000077500000000000000000000000001466405252600172655ustar00rootroot00000000000000powerline-2.8.4/tests/test_python/empty000066400000000000000000000000001466405252600203340ustar00rootroot00000000000000powerline-2.8.4/tests/test_python/test.sh000077500000000000000000000004161466405252600206040ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh enter_suite python final for file in "$ROOT"/tests/test_python/test_*.py ; do test_name="${file##*/test_}" if ! "$PYTHON" "$file" --verbose --catch ; then fail "${test_name%.py}" F "Failed test(s) from $file" fi done exit_suite powerline-2.8.4/tests/test_python/test_cmdline.py000066400000000000000000000115451466405252600223170ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet '''Tests for shell.py parser''' from __future__ import (unicode_literals, division, absolute_import, print_function) import sys if sys.version_info < (3,): from io import BytesIO as StrIO else: from io import StringIO as StrIO from powerline.commands.main import get_argparser, finish_args from tests.modules import TestCase from tests.modules.lib import replace_attr class TestParser(TestCase): def test_main_err(self): parser = get_argparser() out = StrIO() err = StrIO() def flush(): out.truncate(0) err.truncate(0) with replace_attr(sys, 'stdout', out, 'stderr', err): for raising_args, raising_reg in [ ([], 'too few arguments|the following arguments are required: ext'), (['-r'], 'expected one argument'), (['shell', '-r'], 'expected one argument'), (['shell', '-w'], 'expected one argument'), (['shell', '-c'], 'expected one argument'), (['shell', '-t'], 'expected one argument'), (['shell', '-p'], 'expected one argument'), (['shell', '-R'], 'expected one argument'), (['shell', '--renderer-module'], 'expected one argument'), (['shell', '--width'], 'expected one argument'), (['shell', '--last-exit-code'], 'expected one argument'), (['shell', '--last-pipe-status'], 'expected one argument'), (['shell', '--config-override'], 'expected one argument'), (['shell', '--theme-override'], 'expected one argument'), (['shell', '--config-path'], 'expected one argument'), (['shell', '--renderer-arg'], 'expected one argument'), (['shell', '--jobnum'], 'expected one argument'), (['-r', '.zsh'], 'too few arguments|the following arguments are required: ext'), (['shell', '--last-exit-code', 'i'], 'invalid int_or_sig value'), (['shell', '--last-pipe-status', '1 i'], 'invalid value'), ]: self.assertRaises(SystemExit, parser.parse_args, raising_args) self.assertFalse(out.getvalue()) self.assertRegexpMatches(err.getvalue(), raising_reg) flush() def test_main_normal(self): parser = get_argparser() out = StrIO() err = StrIO() with replace_attr(sys, 'stdout', out, 'stderr', err): for argv, expargs in [ (['shell', 'left'], {'ext': ['shell'], 'side': 'left'}), (['shell', 'left', '-r', '.zsh'], {'ext': ['shell'], 'renderer_module': '.zsh', 'side': 'left'}), ([ 'shell', 'left', '-r', '.zsh', '--last-exit-code', '10', '--last-pipe-status', '10 20 30', '--jobnum=10', '-w', '100', '-c', 'common.term_truecolor=true', '-c', 'common.spaces=4', '-t', 'default.segment_data.hostname.before=H:', '-p', '.', '-p', '..', '-R', 'smth={"abc":"def"}', ], { 'ext': ['shell'], 'side': 'left', 'renderer_module': '.zsh', 'last_exit_code': 10, 'last_pipe_status': [10, 20, 30], 'jobnum': 10, 'width': 100, 'config_override': {'common': {'term_truecolor': True, 'spaces': 4}}, 'theme_override': { 'default': { 'segment_data': { 'hostname': { 'before': 'H:' } } } }, 'config_path': ['.', '..'], 'renderer_arg': {'smth': {'abc': 'def'}}, }), (['shell', 'left', '-R', 'arg=true'], { 'ext': ['shell'], 'side': 'left', 'renderer_arg': {'arg': True}, }), (['shell', 'left', '-R', 'arg=true', '-R', 'arg='], { 'ext': ['shell'], 'side': 'left', 'renderer_arg': {}, }), (['shell', 'left', '-R', 'arg='], {'ext': ['shell'], 'renderer_arg': {}, 'side': 'left'}), (['shell', 'left', '-t', 'default.segment_info={"hostname": {}}'], { 'ext': ['shell'], 'side': 'left', 'theme_override': { 'default': { 'segment_info': { 'hostname': {} } } }, }), (['shell', 'left', '-c', 'common={ }'], { 'ext': ['shell'], 'side': 'left', 'config_override': {'common': {}}, }), (['shell', 'left', '--last-pipe-status='], { 'ext': ['shell'], 'side': 'left', 'last_pipe_status': [], }), ]: args = parser.parse_args(argv) finish_args(parser, {}, args) for key, val in expargs.items(): self.assertEqual(getattr(args, key), val) for key, val in args.__dict__.items(): if key not in expargs: self.assertFalse(val, msg='key {0} is {1} while it should be something false'.format(key, val)) self.assertFalse(err.getvalue() + out.getvalue(), msg='unexpected output: {0!r} {1!r}'.format( err.getvalue(), out.getvalue(), )) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_config_merging.py000066400000000000000000000117651466405252600236650ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import json from subprocess import check_call from operator import add from shutil import rmtree from powerline.lib.dict import mergedicts_copy as mdc from powerline import Powerline from tests.modules import TestCase from tests.modules.lib.config_mock import select_renderer, UT CONFIG_DIR = 'tests/config' root_config = lambda: { 'common': { 'interval': None, 'watcher': 'auto', }, 'ext': { 'test': { 'theme': 'default', 'colorscheme': 'default', }, }, } colors_config = lambda: { 'colors': { 'c1': 1, 'c2': 2, }, 'gradients': { }, } colorscheme_config = lambda: { 'groups': { 'g': {'fg': 'c1', 'bg': 'c2', 'attrs': []}, } } theme_config = lambda: { 'segment_data': { 's': { 'before': 'b', }, }, 'segments': { 'left': [ { 'type': 'string', 'name': 's', 'contents': 't', 'highlight_groups': ['g'], }, ], 'right': [], } } top_theme_config = lambda: { 'dividers': { 'left': { 'hard': '#>', 'soft': '|>', }, 'right': { 'hard': '<#', 'soft': '<|', }, }, 'spaces': 0, } main_tree = lambda: { '1/config': root_config(), '1/colors': colors_config(), '1/colorschemes/default': colorscheme_config(), '1/themes/test/default': theme_config(), '1/themes/' + UT: top_theme_config(), '1/themes/other1': mdc(top_theme_config(), { 'dividers': { 'left': { 'hard': '!>', } } }), '1/themes/other2': mdc(top_theme_config(), { 'dividers': { 'left': { 'hard': '>>', } } }), } def mkdir_recursive(directory): if os.path.isdir(directory): return mkdir_recursive(os.path.dirname(directory)) os.mkdir(directory) class TestPowerline(Powerline): def get_config_paths(self): return tuple(sorted([ os.path.join(CONFIG_DIR, d) for d in os.listdir(CONFIG_DIR) ])) class WithConfigTree(object): __slots__ = ('tree', 'p', 'p_kwargs') def __init__(self, tree, p_kwargs={'run_once': True}): self.tree = tree self.p = None self.p_kwargs = p_kwargs def __enter__(self, *args): os.mkdir(CONFIG_DIR) for k, v in self.tree.items(): fname = os.path.join(CONFIG_DIR, k) + '.json' mkdir_recursive(os.path.dirname(fname)) with open(fname, 'w') as F: json.dump(v, F) select_renderer(simpler_renderer=True) self.p = TestPowerline( ext='test', renderer_module='tests.modules.lib.config_mock', **self.p_kwargs ) if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'): try: check_call(['scripts/powerline-lint'] + reduce(add, ( ['-p', d] for d in self.p.get_config_paths() ))) except: self.__exit__() raise return self.p.__enter__(*args) def __exit__(self, *args): try: rmtree(CONFIG_DIR) finally: if self.p: self.p.__exit__(*args) class TestMerging(TestCase): def assertRenderEqual(self, p, output, **kwargs): self.assertEqual(p.render(**kwargs).replace(' ', ' '), output) def test_not_merged_config(self): with WithConfigTree(main_tree()) as p: self.assertRenderEqual(p, '{12} bt{2-}#>{--}') def test_root_config_merging(self): with WithConfigTree(mdc(main_tree(), { '2/config': { 'common': { 'default_top_theme': 'other1', } }, })) as p: self.assertRenderEqual(p, '{12} bt{2-}!>{--}') with WithConfigTree(mdc(main_tree(), { '2/config': { 'common': { 'default_top_theme': 'other1', } }, '3/config': { 'common': { 'default_top_theme': 'other2', } }, })) as p: self.assertRenderEqual(p, '{12} bt{2-}>>{--}') def test_top_theme_merging(self): with WithConfigTree(mdc(main_tree(), { '2/themes/' + UT: { 'spaces': 1, }, '3/themes/' + UT: { 'dividers': { 'left': { 'hard': '>>', } } }, })) as p: self.assertRenderEqual(p, '{12} bt {2-}>>{--}') def test_colors_config_merging(self): with WithConfigTree(mdc(main_tree(), { '2/colors': { 'colors': { 'c1': 3, } }, })) as p: self.assertRenderEqual(p, '{32} bt{2-}#>{--}') with WithConfigTree(mdc(main_tree(), { '2/colors': { 'colors': { 'c1': 3, } }, '3/colors': { 'colors': { 'c1': 4, } }, })) as p: self.assertRenderEqual(p, '{42} bt{2-}#>{--}') with WithConfigTree(mdc(main_tree(), { '2/colors': { 'colors': { 'c1': 3, } }, '3/colors': { 'colors': { 'c2': 4, } }, })) as p: self.assertRenderEqual(p, '{34} bt{4-}#>{--}') def test_colorschemes_merging(self): with WithConfigTree(mdc(main_tree(), { '2/colorschemes/default': { 'groups': { 'g': {'fg': 'c2', 'bg': 'c1', 'attrs': []}, } }, })) as p: self.assertRenderEqual(p, '{21} bt{1-}#>{--}') def test_theme_merging(self): with WithConfigTree(mdc(main_tree(), { '2/themes/test/default': { 'segment_data': { 's': { 'after': 'a', } } }, })) as p: self.assertRenderEqual(p, '{12} bta{2-}#>{--}') if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_config_reload.py000066400000000000000000000325141466405252600234760ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) from time import sleep from copy import deepcopy from functools import wraps from tests.modules import TestCase from tests.modules.lib.config_mock import get_powerline, add_watcher_events, UT config = { 'config': { 'common': { 'interval': 0, 'watcher': 'test', }, 'ext': { 'test': { 'theme': 'default', 'colorscheme': 'default', }, }, }, 'colors': { 'colors': { "col1": 1, "col2": 2, "col3": 3, "col4": 4, }, 'gradients': { }, }, 'colorschemes/test/default': { 'groups': { 'str1': {'fg': 'col1', 'bg': 'col2', 'attrs': ['bold']}, 'str2': {'fg': 'col3', 'bg': 'col4', 'attrs': ['underline']}, }, }, 'colorschemes/test/2': { 'groups': { 'str1': {'fg': 'col2', 'bg': 'col3', 'attrs': ['bold']}, 'str2': {'fg': 'col1', 'bg': 'col4', 'attrs': ['underline']}, }, }, 'themes/test/default': { 'segments': { "left": [ { "type": "string", "contents": "s", "highlight_groups": ["str1"], }, { "type": "string", "contents": "g", "highlight_groups": ["str2"], }, ], "right": [ ], }, }, 'themes/' + UT: { 'dividers': { "left": { "hard": ">>", "soft": ">", }, "right": { "hard": "<<", "soft": "<", }, }, 'spaces': 0, }, 'themes/other': { 'dividers': { "left": { "hard": ">>", "soft": ">", }, "right": { "hard": "<<", "soft": "<", }, }, 'spaces': 1, }, 'themes/test/2': { 'segments': { "left": [ { "type": "string", "contents": "t", "highlight_groups": ["str1"], }, { "type": "string", "contents": "b", "highlight_groups": ["str2"], }, ], "right": [ ], }, }, } def with_new_config(func): @wraps(func) def f(self): return func(self, deepcopy(config)) return f class TestConfigReload(TestCase): def assertAccessEvents(self, p, *args): events = set() for event in args: if ':' not in event: events.add('check:' + event) events.add('load:' + event) else: events.add(event) self.assertEqual(set(p._pop_events()), events) @with_new_config def test_noreload(self, config): with get_powerline(config, run_once=True) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['config']['common']['spaces'] = 1 add_watcher_events(p, 'config', wait=False, interval=0.05) # When running once thread should not start self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p) self.assertEqual(p.logger._pop_msgs(), []) @with_new_config def test_reload_main(self, config): with get_powerline(config, run_once=False) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['config']['common']['default_top_theme'] = 'other' add_watcher_events(p, 'config') p.render() self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') self.assertAccessEvents(p, 'config', 'themes/other', 'check:themes/test/__main__', 'themes/test/default') self.assertEqual(p.logger._pop_msgs(), []) config['config']['ext']['test']['theme'] = 'nonexistent' add_watcher_events(p, 'config') self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') self.assertAccessEvents(p, 'config', 'check:themes/test/nonexistent', 'themes/other', 'check:themes/test/__main__') # It should normally handle file missing error self.assertEqual(p.logger._pop_msgs(), [ 'exception:test:powerline:Failed to load theme: themes/test/__main__', 'exception:test:powerline:Failed to load theme: themes/test/nonexistent', 'exception:test:powerline:Failed to create renderer: themes/test/nonexistent' ]) config['config']['ext']['test']['theme'] = 'default' add_watcher_events(p, 'config') self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') self.assertAccessEvents(p, 'config', 'themes/test/default', 'themes/other', 'check:themes/test/__main__') self.assertEqual(p.logger._pop_msgs(), []) config['config']['ext']['test']['colorscheme'] = 'nonexistent' add_watcher_events(p, 'config') self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') self.assertAccessEvents(p, 'config', 'check:colorschemes/nonexistent', 'check:colorschemes/test/__main__', 'check:colorschemes/test/nonexistent') # It should normally handle file missing error self.assertEqual(p.logger._pop_msgs(), [ 'exception:test:powerline:Failed to load colorscheme: colorschemes/nonexistent', 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/__main__', 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/nonexistent', 'exception:test:powerline:Failed to create renderer: colorschemes/test/nonexistent' ]) config['config']['ext']['test']['colorscheme'] = '2' add_watcher_events(p, 'config') self.assertEqual(p.render(), '<2 3 1> s <3 4 False>>><1 4 4>g <4 False False>>>') self.assertAccessEvents(p, 'config', 'check:colorschemes/2', 'check:colorschemes/test/__main__', 'colorschemes/test/2') self.assertEqual(p.logger._pop_msgs(), []) config['config']['ext']['test']['theme'] = '2' add_watcher_events(p, 'config') self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>>') self.assertAccessEvents(p, 'config', 'themes/test/2', 'themes/other', 'check:themes/test/__main__') self.assertEqual(p.logger._pop_msgs(), []) self.assertEqual(p.renderer.local_themes, None) config['config']['ext']['test']['local_themes'] = 'something' add_watcher_events(p, 'config') self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>>') self.assertAccessEvents(p, 'config') self.assertEqual(p.logger._pop_msgs(), []) self.assertEqual(p.renderer.local_themes, 'something') @with_new_config def test_reload_unexistent(self, config): with get_powerline(config, run_once=False) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['config']['ext']['test']['colorscheme'] = 'nonexistentraise' add_watcher_events(p, 'config') # It may appear that p.logger._pop_msgs() is called after given # exception is added to the mesagges, but before config_loader # exception was added (this one: # “exception:test:config_loader:Error while running condition # function for key colorschemes/test/nonexistentraise: # fcf:colorschemes/test/nonexistentraise”). # sleep(0.1) self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') # For colorschemes/{test/,}*raise find_config_file raises # IOError, but it does not do so for check:colorschemes/test/__main__, # so powerline is trying to load this, but not other # colorschemes/* self.assertAccessEvents(p, 'config', 'check:colorschemes/test/__main__', 'check:colorschemes/nonexistentraise', 'check:colorschemes/test/nonexistentraise') self.assertIn('exception:test:powerline:Failed to create renderer: fcf:colorschemes/test/nonexistentraise', p.logger._pop_msgs()) config['colorschemes/nonexistentraise'] = {} config['colorschemes/test/nonexistentraise'] = { 'groups': { 'str1': {'fg': 'col1', 'bg': 'col3', 'attrs': ['bold']}, 'str2': {'fg': 'col2', 'bg': 'col4', 'attrs': ['underline']}, }, } while not p._will_create_renderer(): sleep(0.1) self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><2 4 4>g<4 False False>>>') # Same as above self.assertAccessEvents(p, 'colorschemes/nonexistentraise', 'colorschemes/test/nonexistentraise', 'check:colorschemes/test/__main__') self.assertEqual(p.logger._pop_msgs(), []) @with_new_config def test_reload_colors(self, config): with get_powerline(config, run_once=False) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['colors']['colors']['col1'] = 5 add_watcher_events(p, 'colors') self.assertEqual(p.render(), '<5 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'colors') self.assertEqual(p.logger._pop_msgs(), []) @with_new_config def test_reload_colorscheme(self, config): with get_powerline(config, run_once=False) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['colorschemes/test/default']['groups']['str1']['bg'] = 'col3' add_watcher_events(p, 'colorschemes/test/default') self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default') self.assertEqual(p.logger._pop_msgs(), []) @with_new_config def test_reload_theme(self, config): with get_powerline(config, run_once=False) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' add_watcher_events(p, 'themes/test/default') self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') self.assertEqual(p.logger._pop_msgs(), []) @with_new_config def test_reload_top_theme(self, config): with get_powerline(config, run_once=False) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['themes/' + UT]['dividers']['left']['hard'] = '|>' add_watcher_events(p, 'themes/' + UT) self.assertEqual(p.render(), '<1 2 1> s<2 4 False>|><3 4 4>g<4 False False>|>') self.assertAccessEvents(p, 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') self.assertEqual(p.logger._pop_msgs(), []) @with_new_config def test_reload_theme_main(self, config): config['config']['common']['interval'] = None with get_powerline(config, run_once=False) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' add_watcher_events(p, 'themes/test/default', wait=False) self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') self.assertEqual(p.logger._pop_msgs(), []) self.assertTrue(p._watcher._calls) @with_new_config def test_run_once_no_theme_reload(self, config): config['config']['common']['interval'] = None with get_powerline(config, run_once=True) as p: self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default', 'themes/' + UT, 'check:themes/test/__main__') config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' add_watcher_events(p, 'themes/test/default', wait=False) self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') self.assertAccessEvents(p) self.assertEqual(p.logger._pop_msgs(), []) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_configuration.py000066400000000000000000000721371466405252600235570ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import os from functools import wraps from copy import deepcopy import tests.modules.vim as vim_module from tests.modules import TestCase from tests.modules.lib.config_mock import (get_powerline, get_powerline_raw, swap_attributes, UT) from tests.modules.lib import Args, replace_item def highlighted_string(s, group, **kwargs): ret = { 'type': 'string', 'contents': s, 'highlight_groups': [group], } ret.update(kwargs) return ret config = { 'config': { 'common': { 'interval': 0, 'watcher': 'test', }, 'ext': { 'test': { 'theme': 'default', 'colorscheme': 'default', }, 'vim': { 'theme': 'default', 'colorscheme': 'default', }, 'shell': { 'theme': 'default', 'colorscheme': 'default', }, 'wm': { 'theme': 'default', 'colorscheme': 'default', }, }, }, 'colors': { 'colors': { 'col1': 1, 'col2': 2, 'col3': 3, 'col4': 4, 'col5': 5, 'col6': 6, 'col7': 7, 'col8': 8, 'col9': 9, 'col10': 10, 'col11': 11, 'col12': 12, }, 'gradients': { }, }, 'colorschemes/test/__main__': { 'groups': { 'm1': 'g1', 'm2': 'g3', 'm3': {'fg': 'col11', 'bg': 'col12', 'attrs': []}, } }, 'colorschemes/default': { 'groups': { 'g1': {'fg': 'col5', 'bg': 'col6', 'attrs': []}, 'g2': {'fg': 'col7', 'bg': 'col8', 'attrs': []}, 'g3': {'fg': 'col9', 'bg': 'col10', 'attrs': []}, } }, 'colorschemes/test/default': { 'groups': { 'str1': {'fg': 'col1', 'bg': 'col2', 'attrs': ['bold']}, 'str2': {'fg': 'col3', 'bg': 'col4', 'attrs': ['underline']}, 'd1': 'g2', 'd2': 'm2', 'd3': 'm3', }, }, 'colorschemes/vim/default': { 'groups': { 'environment': {'fg': 'col3', 'bg': 'col4', 'attrs': ['underline']}, }, }, 'colorschemes/wm/default': { 'groups': { 'hl1': {'fg': 'col1', 'bg': 'col2', 'attrs': ['underline']}, 'hl2': {'fg': 'col2', 'bg': 'col1', 'attrs': []}, 'hl3': {'fg': 'col3', 'bg': 'col1', 'attrs': ['underline']}, 'hl4': {'fg': 'col2', 'bg': 'col4', 'attrs': []}, }, }, 'themes/test/default': { 'segments': { 'left': [ highlighted_string('s', 'str1', width='auto'), highlighted_string('g', 'str2'), ], 'right': [ highlighted_string('f', 'str2', width='auto', align='r'), ], }, }, 'themes/' + UT: { 'dividers': { 'left': { 'hard': '>>', 'soft': '>', }, 'right': { 'hard': '<<', 'soft': '<', }, }, 'spaces': 0, }, 'themes/test/__main__': { 'dividers': { 'right': { 'soft': '|', }, }, }, 'themes/vim/default': { 'segments': { 'left': [ { 'function': 'powerline.segments.common.env.environment', 'args': { 'variable': 'TEST', }, }, ], }, }, 'themes/shell/default': { 'default_module': 'powerline.segments.common', 'segments': { 'left': [ highlighted_string('s', 'g1', width='auto'), ], }, }, 'themes/wm/default': { 'default_module': 'powerline.segments.common', 'segments': { 'left': [ highlighted_string('A', 'hl1'), highlighted_string('B', 'hl2'), ], 'right': [ highlighted_string('C', 'hl3'), highlighted_string('D', 'hl4'), ], }, }, } def with_new_config(func): @wraps(func) def f(self): return func(self, deepcopy(config)) return f def add_args(func): @wraps(func) def f(self): new_config = deepcopy(config) with get_powerline(new_config, run_once=True, simpler_renderer=True) as p: func(self, p, new_config) return f class TestRender(TestCase): def assertRenderEqual(self, p, output, **kwargs): self.assertEqual(p.render(**kwargs).replace(' ', ' '), output) def assertRenderLinesEqual(self, p, output, **kwargs): self.assertEqual([l.replace(' ', ' ') for l in p.render_above_lines(**kwargs)], output) class TestLines(TestRender): @add_args def test_without_above(self, p, config): self.assertRenderEqual(p, '{121} s{24}>>{344}g{34}>{34}|{344}f {--}') self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', width=10) # self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}|{344} f {--}', width=11) self.assertEqual(list(p.render_above_lines()), []) @with_new_config def test_with_above(self, config): old_segments = deepcopy(config['themes/test/default']['segments']) config['themes/test/default']['segments']['above'] = [old_segments] with get_powerline(config, run_once=True, simpler_renderer=True) as p: self.assertRenderLinesEqual(p, [ '{121} s{24}>>{344}g{34}>{34}|{344}f {--}', ]) self.assertRenderLinesEqual(p, [ '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', ], width=10) config['themes/test/default']['segments']['above'] = [old_segments] * 2 with get_powerline(config, run_once=True, simpler_renderer=True) as p: self.assertRenderLinesEqual(p, [ '{121} s{24}>>{344}g{34}>{34}|{344}f {--}', '{121} s{24}>>{344}g{34}>{34}|{344}f {--}', ]) self.assertRenderLinesEqual(p, [ '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', '{121} s {24}>>{344}g{34}>{34}|{344}f {--}', ], width=10) class TestSegments(TestRender): @add_args def test_display(self, p, config): config['themes/test/default']['segments']['left'][0]['display'] = False config['themes/test/default']['segments']['left'][1]['display'] = True config['themes/test/default']['segments']['right'][0]['display'] = False self.assertRenderEqual(p, '{344} g{4-}>>{--}') class TestColorschemesHierarchy(TestRender): @add_args def test_group_redirects(self, p, config): config['themes/test/default']['segments'] = { 'left': [ highlighted_string('a', 'd1', draw_hard_divider=False), highlighted_string('b', 'd2', draw_hard_divider=False), highlighted_string('c', 'd3', draw_hard_divider=False), highlighted_string('A', 'm1', draw_hard_divider=False), highlighted_string('B', 'm2', draw_hard_divider=False), highlighted_string('C', 'm3', draw_hard_divider=False), highlighted_string('1', 'g1', draw_hard_divider=False), highlighted_string('2', 'g2', draw_hard_divider=False), highlighted_string('3', 'g3', draw_hard_divider=False), ], 'right': [], } self.assertRenderEqual(p, '{78} a{910}b{1112}c{56}A{910}B{1112}C{56}1{78}2{910}3{--}') self.assertEqual(p.logger._pop_msgs(), []) @add_args def test_group_redirects_no_main(self, p, config): del config['colorschemes/test/__main__'] config['themes/test/default']['segments'] = { 'left': [ highlighted_string('a', 'd1', draw_hard_divider=False), highlighted_string('1', 'g1', draw_hard_divider=False), highlighted_string('2', 'g2', draw_hard_divider=False), highlighted_string('3', 'g3', draw_hard_divider=False), ], 'right': [], } self.assertRenderEqual(p, '{78} a{56}1{78}2{910}3{--}') self.assertEqual(p.logger._pop_msgs(), []) @add_args def test_group_redirects_no_top_default(self, p, config): del config['colorschemes/default'] config['themes/test/default']['segments'] = { 'left': [ highlighted_string('c', 'd3', draw_soft_divider=False), highlighted_string('C', 'm3', draw_hard_divider=False), ], 'right': [], } self.assertRenderEqual(p, '{1112} c{1112}C{--}') self.assertEqual(p.logger._pop_msgs(), []) @add_args def test_group_redirects_no_test_default(self, p, config): del config['colorschemes/test/default'] config['themes/test/default']['segments'] = { 'left': [ highlighted_string('A', 'm1', draw_hard_divider=False), highlighted_string('B', 'm2', draw_hard_divider=False), highlighted_string('C', 'm3', draw_hard_divider=False), highlighted_string('1', 'g1', draw_hard_divider=False), highlighted_string('2', 'g2', draw_hard_divider=False), highlighted_string('3', 'g3', draw_hard_divider=False), ], 'right': [], } self.assertRenderEqual(p, '{56} A{910}B{1112}C{56}1{78}2{910}3{--}') self.assertEqual(p.logger._pop_msgs(), []) @add_args def test_group_redirects_only_main(self, p, config): del config['colorschemes/default'] del config['colorschemes/test/default'] config['themes/test/default']['segments'] = { 'left': [ highlighted_string('C', 'm3', draw_hard_divider=False), ], 'right': [], } # Powerline is not able to work without default colorscheme # somewhere, thus it will output error string self.assertRenderEqual(p, 'colorschemes/test/default') self.assertEqual(p.logger._pop_msgs(), [ 'exception:test:powerline:Failed to load colorscheme: colorschemes/default', 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/default', 'exception:test:powerline:Failed to create renderer: colorschemes/test/default', 'exception:test:powerline:Failed to render: colorschemes/test/default', ]) @add_args def test_group_redirects_only_top_default(self, p, config): del config['colorschemes/test/__main__'] del config['colorschemes/test/default'] config['themes/test/default']['segments'] = { 'left': [ highlighted_string('1', 'g1', draw_hard_divider=False), highlighted_string('2', 'g2', draw_hard_divider=False), highlighted_string('3', 'g3', draw_hard_divider=False), ], 'right': [], } self.assertRenderEqual(p, '{56} 1{78}2{910}3{--}') self.assertEqual(p.logger._pop_msgs(), []) @add_args def test_group_redirects_only_test_default(self, p, config): del config['colorschemes/default'] del config['colorschemes/test/__main__'] config['themes/test/default']['segments'] = { 'left': [ highlighted_string('s', 'str1', draw_hard_divider=False), ], 'right': [], } self.assertRenderEqual(p, '{121} s{--}') self.assertEqual(p.logger._pop_msgs(), []) class TestThemeHierarchy(TestRender): @add_args def test_hierarchy(self, p, config): self.assertRenderEqual(p, '{121} s{24}>>{344}g{34}>{34}|{344}f {--}') @add_args def test_no_main(self, p, config): del config['themes/test/__main__'] self.assertRenderEqual(p, '{121} s{24}>>{344}g{34}>{34}<{344}f {--}') self.assertEqual(p.logger._pop_msgs(), []) @add_args def test_no_powerline(self, p, config): config['themes/test/__main__']['dividers'] = config['themes/' + UT]['dividers'] config['themes/test/__main__']['spaces'] = 1 del config['themes/' + UT] self.assertRenderEqual(p, '{121} s {24}>>{344}g {34}>{34}<{344} f {--}') self.assertEqual(p.logger._pop_msgs(), []) @add_args def test_no_default(self, p, config): del config['themes/test/default'] self.assertRenderEqual(p, 'themes/test/default') self.assertEqual(p.logger._pop_msgs(), [ 'exception:test:powerline:Failed to load theme: themes/test/default', 'exception:test:powerline:Failed to create renderer: themes/test/default', 'exception:test:powerline:Failed to render: themes/test/default', ]) @add_args def test_only_default(self, p, config): config['themes/test/default']['dividers'] = config['themes/' + UT]['dividers'] config['themes/test/default']['spaces'] = 1 del config['themes/test/__main__'] del config['themes/' + UT] self.assertRenderEqual(p, '{121} s {24}>>{344}g {34}>{34}<{344} f {--}') @add_args def test_only_main(self, p, config): del config['themes/test/default'] del config['themes/' + UT] self.assertRenderEqual(p, 'themes/test/default') self.assertEqual(p.logger._pop_msgs(), [ 'exception:test:powerline:Failed to load theme: themes/' + UT, 'exception:test:powerline:Failed to load theme: themes/test/default', 'exception:test:powerline:Failed to create renderer: themes/test/default', 'exception:test:powerline:Failed to render: themes/test/default', ]) @add_args def test_only_powerline(self, p, config): del config['themes/test/default'] del config['themes/test/__main__'] self.assertRenderEqual(p, 'themes/test/default') self.assertEqual(p.logger._pop_msgs(), [ 'exception:test:powerline:Failed to load theme: themes/test/__main__', 'exception:test:powerline:Failed to load theme: themes/test/default', 'exception:test:powerline:Failed to create renderer: themes/test/default', 'exception:test:powerline:Failed to render: themes/test/default', ]) @add_args def test_nothing(self, p, config): del config['themes/test/default'] del config['themes/' + UT] del config['themes/test/__main__'] self.assertRenderEqual(p, 'themes/test/default') self.assertEqual(p.logger._pop_msgs(), [ 'exception:test:powerline:Failed to load theme: themes/' + UT, 'exception:test:powerline:Failed to load theme: themes/test/__main__', 'exception:test:powerline:Failed to load theme: themes/test/default', 'exception:test:powerline:Failed to create renderer: themes/test/default', 'exception:test:powerline:Failed to render: themes/test/default', ]) class TestDisplayCondition(TestRender): @add_args def test_include_modes(self, p, config): config['themes/test/default']['segments'] = { 'left': [ highlighted_string('s1', 'g1', include_modes=['m1']), highlighted_string('s2', 'g1', include_modes=['m1', 'm2']), highlighted_string('s3', 'g1', include_modes=['m3']), ] } self.assertRenderEqual(p, '{--}') self.assertRenderEqual(p, '{56} s1{56}>{56}s2{6-}>>{--}', mode='m1') self.assertRenderEqual(p, '{56} s2{6-}>>{--}', mode='m2') self.assertRenderEqual(p, '{56} s3{6-}>>{--}', mode='m3') @add_args def test_exclude_modes(self, p, config): config['themes/test/default']['segments'] = { 'left': [ highlighted_string('s1', 'g1', exclude_modes=['m1']), highlighted_string('s2', 'g1', exclude_modes=['m1', 'm2']), highlighted_string('s3', 'g1', exclude_modes=['m3']), ] } self.assertRenderEqual(p, '{56} s1{56}>{56}s2{56}>{56}s3{6-}>>{--}') self.assertRenderEqual(p, '{56} s3{6-}>>{--}', mode='m1') self.assertRenderEqual(p, '{56} s1{56}>{56}s3{6-}>>{--}', mode='m2') self.assertRenderEqual(p, '{56} s1{56}>{56}s2{6-}>>{--}', mode='m3') @add_args def test_exinclude_modes(self, p, config): config['themes/test/default']['segments'] = { 'left': [ highlighted_string('s1', 'g1', exclude_modes=['m1'], include_modes=['m2']), highlighted_string('s2', 'g1', exclude_modes=['m1', 'm2'], include_modes=['m3']), highlighted_string('s3', 'g1', exclude_modes=['m3'], include_modes=['m3']), ] } self.assertRenderEqual(p, '{--}') self.assertRenderEqual(p, '{--}', mode='m1') self.assertRenderEqual(p, '{56} s1{6-}>>{--}', mode='m2') self.assertRenderEqual(p, '{56} s2{6-}>>{--}', mode='m3') @add_args def test_exinclude_function_nonexistent_module(self, p, config): config['themes/test/default']['segments'] = { 'left': [ highlighted_string('s1', 'g1', exclude_function='xxx_nonexistent_module.foo'), highlighted_string('s2', 'g1', exclude_function='xxx_nonexistent_module.foo', include_function='xxx_nonexistent_module.bar'), highlighted_string('s3', 'g1', include_function='xxx_nonexistent_module.bar'), ] } self.assertRenderEqual(p, '{56} s1{56}>{56}s2{56}>{56}s3{6-}>>{--}') @add_args def test_exinclude_function(self, p, config): config['themes/test/default']['segments'] = { 'left': [ highlighted_string('s1', 'g1', exclude_function='mod.foo'), highlighted_string('s2', 'g1', exclude_function='mod.foo', include_function='mod.bar'), highlighted_string('s3', 'g1', include_function='mod.bar'), ] } launched = set() fool = [None] barl = [None] def foo(*args, **kwargs): launched.add('foo') self.assertEqual(set(kwargs.keys()), set(('pl', 'segment_info', 'mode'))) self.assertEqual(args, ()) return fool[0] def bar(*args, **kwargs): launched.add('bar') self.assertEqual(set(kwargs.keys()), set(('pl', 'segment_info', 'mode'))) self.assertEqual(args, ()) return barl[0] with replace_item(sys.modules, 'mod', Args(foo=foo, bar=bar)): fool[0] = True barl[0] = True self.assertRenderEqual(p, '{56} s3{6-}>>{--}') self.assertEqual(launched, set(('foo', 'bar'))) fool[0] = False barl[0] = True self.assertRenderEqual(p, '{56} s1{56}>{56}s2{56}>{56}s3{6-}>>{--}') self.assertEqual(launched, set(('foo', 'bar'))) fool[0] = False barl[0] = False self.assertRenderEqual(p, '{56} s1{6-}>>{--}') self.assertEqual(launched, set(('foo', 'bar'))) fool[0] = True barl[0] = False self.assertRenderEqual(p, '{--}') self.assertEqual(launched, set(('foo', 'bar'))) @add_args def test_exinclude_modes_override_functions(self, p, config): config['themes/test/default']['segments'] = { 'left': [ highlighted_string('s1', 'g1', exclude_function='mod.foo', exclude_modes=['m2']), highlighted_string('s2', 'g1', exclude_function='mod.foo', include_modes=['m2']), highlighted_string('s3', 'g1', include_function='mod.foo', exclude_modes=['m2']), highlighted_string('s4', 'g1', include_function='mod.foo', include_modes=['m2']), ] } fool = [None] def foo(*args, **kwargs): return fool[0] with replace_item(sys.modules, 'mod', Args(foo=foo)): fool[0] = True self.assertRenderEqual(p, '{56} s4{6-}>>{--}', mode='m2') self.assertRenderEqual(p, '{56} s3{56}>{56}s4{6-}>>{--}', mode='m1') fool[0] = False self.assertRenderEqual(p, '{56} s2{56}>{56}s4{6-}>>{--}', mode='m2') self.assertRenderEqual(p, '{56} s1{6-}>>{--}', mode='m1') class TestOuterPadding(TestRender): @add_args def test_outer_padding_left(self, p, config): config['themes/' + UT]['outer_padding'] = 5 self.assertRenderEqual(p, '{121} s{24}>>{344}g{4-}>>{--}', side='left') @add_args def test_outer_padding_right(self, p, config): config['themes/' + UT]['outer_padding'] = 5 self.assertRenderEqual(p, '{4-}<<{344}f {--}', side='right') @add_args def test_outer_padding_ten(self, p, config): config['themes/' + UT]['outer_padding'] = 10 self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}|{344} f {--}', width=30) @add_args def test_outer_padding_zero(self, p, config): config['themes/' + UT]['outer_padding'] = 0 self.assertRenderEqual(p, '{121}s {24}>>{344}g{34}>{34}|{344} f{--}', width=30) class TestSegmentAttributes(TestRender): @add_args def test_no_attributes(self, p, config): def m1(divider=',', **kwargs): return divider.join(kwargs.keys()) + divider config['themes/test/default']['segments'] = { 'left': [ { 'function': 'bar.m1' } ] } with replace_item(sys.modules, 'bar', Args(m1=m1)): self.assertRenderEqual(p, '{56} pl,{6-}>>{--}') @add_args def test_segment_datas(self, p, config): def m1(divider=',', **kwargs): return divider.join(kwargs.keys()) + divider m1.powerline_segment_datas = { UT: { 'args': { 'divider': ';' } }, 'ascii': { 'args': { 'divider': '--' } } } config['themes/test/default']['segments'] = { 'left': [ { 'function': 'bar.m1' } ] } with replace_item(sys.modules, 'bar', Args(m1=m1)): self.assertRenderEqual(p, '{56} pl;{6-}>>{--}') @add_args def test_expand(self, p, config): def m1(divider=',', **kwargs): return divider.join(kwargs.keys()) + divider def expand(pl, amount, segment, **kwargs): return ('-' * amount) + segment['contents'] m1.expand = expand config['themes/test/default']['segments'] = { 'left': [ { 'function': 'bar.m1', 'width': 'auto' } ] } with replace_item(sys.modules, 'bar', Args(m1=m1)): self.assertRenderEqual(p, '{56} ----pl,{6-}>>{--}', width=10) @add_args def test_truncate(self, p, config): def m1(divider=',', **kwargs): return divider.join(kwargs.keys()) + divider def truncate(pl, amount, segment, **kwargs): return segment['contents'][:-amount] m1.truncate = truncate config['themes/test/default']['segments'] = { 'left': [ { 'function': 'bar.m1' } ] } with replace_item(sys.modules, 'bar', Args(m1=m1)): self.assertRenderEqual(p, '{56} p{6-}>>{--}', width=4) class TestSegmentData(TestRender): @add_args def test_segment_data(self, p, config): def m1(**kwargs): return 'S' def m2(**kwargs): return 'S' sys.modules['bar'] = Args(m1=m1, m2=m2) config['themes/' + UT]['segment_data'] = { 'm1': { 'before': '1' }, 'bar.m2': { 'before': '2' }, 'n': { 'before': '3' }, 'm2': { 'before': '4' }, } config['themes/test/default']['segments'] = { 'left': [ { 'function': 'bar.m1' }, { 'function': 'bar.m1', 'name': 'n' }, { 'function': 'bar.m2', 'name': 'n' }, { 'function': 'bar.m2' } ] } self.assertRenderEqual(p, '{56} 1S{56}>{56}3S{610}>>{910}3S{910}>{910}2S{10-}>>{--}') class TestShellEscapes(TestCase): @with_new_config def test_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0;38;5;5;48;5;6m\xa0s\x1b[0;38;5;6;49;22m>>\x1b[0m') @with_new_config def test_tmux_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['additional_escapes'] = 'tmux' with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0;38;5;5;48;5;6m\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0;38;5;6;49;22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\') @with_new_config def test_screen_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['additional_escapes'] = 'screen' with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0;38;5;5;48;5;6m\x1b\\\xa0s\x1bP\x1b\x1b[0;38;5;6;49;22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\') @with_new_config def test_fbterm_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['term_escape_style'] = 'fbterm' with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0m\x1b[1;5}\x1b[2;6}\xa0s\x1b[0m\x1b[1;6}\x1b[49m\x1b[22m>>\x1b[0m') @with_new_config def test_fbterm_tmux_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['term_escape_style'] = 'fbterm' config['config']['common']['additional_escapes'] = 'tmux' with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0m\x1b\x1b[1;5}\x1b\x1b[2;6}\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0m\x1b\x1b[1;6}\x1b\x1b[49m\x1b\x1b[22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\') @with_new_config def test_fbterm_screen_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['term_escape_style'] = 'fbterm' config['config']['common']['additional_escapes'] = 'screen' with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0m\x1b\x1b[1;5}\x1b\x1b[2;6}\x1b\\\xa0s\x1bP\x1b\x1b[0m\x1b\x1b[1;6}\x1b\x1b[49m\x1b\x1b[22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\') @with_new_config def test_term_truecolor_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['term_truecolor'] = True with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0;38;2;192;0;192;48;2;0;128;128m\xa0s\x1b[0;38;2;0;128;128;49;22m>>\x1b[0m') @with_new_config def test_term_truecolor_fbterm_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['term_escape_style'] = 'fbterm' config['config']['common']['term_truecolor'] = True with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0m\x1b[1;5}\x1b[2;6}\xa0s\x1b[0m\x1b[1;6}\x1b[49m\x1b[22m>>\x1b[0m') @with_new_config def test_term_truecolor_tmux_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['term_truecolor'] = True config['config']['common']['additional_escapes'] = 'tmux' with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0;38;2;192;0;192;48;2;0;128;128m\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0;38;2;0;128;128;49;22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\') @with_new_config def test_term_truecolor_screen_escapes(self, config): from powerline.shell import ShellPowerline import powerline as powerline_module config['config']['common']['term_truecolor'] = True config['config']['common']['additional_escapes'] = 'screen' with swap_attributes(config, powerline_module): with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline: self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0;38;2;192;0;192;48;2;0;128;128m\x1b\\\xa0s\x1bP\x1b\x1b[0;38;2;0;128;128;49;22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\') class TestVim(TestCase): def test_environ_update(self): # Regression test: test that segment obtains environment from vim, not # from os.environ. with vim_module._with('globals', powerline_config_paths=['/']): from powerline.vim import VimPowerline import powerline as powerline_module with swap_attributes(config, powerline_module): with vim_module._with('environ', TEST='abc'): with get_powerline_raw(config, VimPowerline) as powerline: window = vim_module.current.window window_id = 1 winnr = window.number self.assertEqual(powerline.render(window, window_id, winnr), b'%#Pl_3_8404992_4_192_underline#\xc2\xa0abc%#Pl_4_192_NONE_None_NONE#>>') vim_module._environ['TEST'] = 'def' self.assertEqual(powerline.render(window, window_id, winnr), b'%#Pl_3_8404992_4_192_underline#\xc2\xa0def%#Pl_4_192_NONE_None_NONE#>>') def test_local_themes(self): # Regression test: VimPowerline.add_local_theme did not work properly. from powerline.vim import VimPowerline import powerline as powerline_module with swap_attributes(config, powerline_module): with get_powerline_raw(config, VimPowerline, replace_gcp=True) as powerline: powerline.add_local_theme('tests.modules.matchers.always_true', { 'segment_data': { 'foo': { 'contents': '“bar”' } }, 'segments': { 'left': [ { 'type': 'string', 'name': 'foo', 'highlight_groups': ['g1'] } ] } }) window = vim_module.current.window window_id = 1 winnr = window.number self.assertEqual(powerline.render(window, window_id, winnr), b'%#Pl_5_12583104_6_32896_NONE#\xc2\xa0\xe2\x80\x9cbar\xe2\x80\x9d%#Pl_6_32896_NONE_None_NONE#>>') @classmethod def setUpClass(cls): sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) @classmethod def tearDownClass(cls): sys.path.pop(0) class TestLemonbar(TestRender): def test_lemonbar(self): import powerline as powerline_module with swap_attributes(config, powerline_module): with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline: self.assertRenderEqual( powerline, '%{l}%{F#ffc00000}%{B#ff008000}%{+u} A%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}B%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}' ) @with_new_config def test_lemonbar_escape(self, config): import powerline as powerline_module config['themes/wm/default']['segments']['left'] = ( highlighted_string('%{asd}', 'hl1'), highlighted_string('10% %', 'hl2'), ) with swap_attributes(config, powerline_module): with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline: self.assertRenderEqual( powerline, '%{l}%{F#ffc00000}%{B#ff008000}%{+u} %%{}{asd}%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}10%%{} %%{}%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}' ) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_lib.py000066400000000000000000000555011466405252600214520ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import threading import os import sys import re import shutil import unicodedata from time import sleep from subprocess import call, PIPE from powerline.lib import add_divider_highlight_group from powerline.lib.dict import mergedicts, REMOVE_THIS_KEY from powerline.lib.humanize_bytes import humanize_bytes from powerline.lib.vcs import guess, get_fallback_create_watcher from powerline.lib.threaded import ThreadedSegment, KwThreadedSegment from powerline.lib.monotonic import monotonic from powerline.lib.vcs.git import git_directory from powerline.lib.shell import run_cmd import powerline.lib.unicode as plu from tests.modules.lib import Pl, replace_attr from tests.modules import TestCase, SkipTest try: __import__('bzrlib') except ImportError: use_bzr = False else: use_bzr = True try: __import__('hglib') except ImportError: use_mercurial = False else: use_mercurial = True GIT_REPO = 'git_repo' HG_REPO = 'hg_repo' BZR_REPO = 'bzr_repo' def thread_number(): return len(threading.enumerate()) class TestShell(TestCase): def test_run_cmd(self): pl = Pl() self.assertEqual(run_cmd(pl, ['xxx_nonexistent_command_xxx']), None) self.assertEqual(len(pl.exceptions), 1) pl = Pl() self.assertEqual(run_cmd(pl, ['echo', ' test ']), 'test') self.assertFalse(pl) self.assertEqual(run_cmd(pl, ['echo', ' test '], strip=True), 'test') self.assertFalse(pl) self.assertEqual(run_cmd(pl, ['echo', ' test '], strip=False), ' test \n') self.assertFalse(pl) self.assertEqual(run_cmd(pl, ['cat'], stdin='test'), 'test') self.assertFalse(pl) self.assertEqual(run_cmd(pl, ['sh', '-c', 'cat >&2'], stdin='test'), '') self.assertFalse(pl) class TestThreaded(TestCase): def test_threaded_segment(self): log = [] pl = Pl() updates = [(None,)] lock = threading.Lock() event = threading.Event() block_event = threading.Event() class TestSegment(ThreadedSegment): interval = 10 def set_state(self, **kwargs): event.clear() log.append(('set_state', kwargs)) return super(TestSegment, self).set_state(**kwargs) def update(self, update_value): block_event.wait() event.set() # Make sleep first to prevent some race conditions log.append(('update', update_value)) with lock: ret = updates[0] if isinstance(ret, Exception): raise ret else: return ret[0] def render(self, update, **kwargs): log.append(('render', update, kwargs)) if isinstance(update, Exception): raise update else: return update # Non-threaded tests segment = TestSegment() block_event.set() updates[0] = (None,) self.assertEqual(segment(pl=pl), None) self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('set_state', {}), ('update', None), ('render', None, {'pl': pl, 'update_first': True}), ]) log[:] = () segment = TestSegment() block_event.set() updates[0] = ('abc',) self.assertEqual(segment(pl=pl), 'abc') self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('set_state', {}), ('update', None), ('render', 'abc', {'pl': pl, 'update_first': True}), ]) log[:] = () segment = TestSegment() block_event.set() updates[0] = ('abc',) self.assertEqual(segment(pl=pl, update_first=False), 'abc') self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('set_state', {}), ('update', None), ('render', 'abc', {'pl': pl, 'update_first': False}), ]) log[:] = () segment = TestSegment() block_event.set() updates[0] = ValueError('abc') self.assertEqual(segment(pl=pl), None) self.assertEqual(thread_number(), 1) self.assertEqual(len(pl.exceptions), 1) self.assertEqual(log, [ ('set_state', {}), ('update', None), ]) log[:] = () pl.exceptions[:] = () segment = TestSegment() block_event.set() updates[0] = (TypeError('def'),) self.assertRaises(TypeError, segment, pl=pl) self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('set_state', {}), ('update', None), ('render', updates[0][0], {'pl': pl, 'update_first': True}), ]) log[:] = () # Threaded tests segment = TestSegment() block_event.clear() kwargs = {'pl': pl, 'update_first': False, 'other': 1} with lock: updates[0] = ('abc',) segment.startup(**kwargs) ret = segment(**kwargs) self.assertEqual(thread_number(), 2) block_event.set() event.wait() segment.shutdown_event.set() segment.thread.join() self.assertEqual(ret, None) self.assertEqual(log, [ ('set_state', {'update_first': False, 'other': 1}), ('render', None, {'pl': pl, 'update_first': False, 'other': 1}), ('update', None), ]) log[:] = () segment = TestSegment() block_event.set() kwargs = {'pl': pl, 'update_first': True, 'other': 1} with lock: updates[0] = ('def',) segment.startup(**kwargs) ret = segment(**kwargs) self.assertEqual(thread_number(), 2) segment.shutdown_event.set() segment.thread.join() self.assertEqual(ret, 'def') self.assertEqual(log, [ ('set_state', {'update_first': True, 'other': 1}), ('update', None), ('render', 'def', {'pl': pl, 'update_first': True, 'other': 1}), ]) log[:] = () segment = TestSegment() block_event.set() kwargs = {'pl': pl, 'update_first': True, 'interval': 0.2} with lock: updates[0] = ('abc',) segment.startup(**kwargs) start = monotonic() ret1 = segment(**kwargs) with lock: updates[0] = ('def',) self.assertEqual(thread_number(), 2) sleep(0.5) ret2 = segment(**kwargs) segment.shutdown_event.set() segment.thread.join() end = monotonic() duration = end - start self.assertEqual(ret1, 'abc') self.assertEqual(ret2, 'def') self.assertEqual(log[:5], [ ('set_state', {'update_first': True, 'interval': 0.2}), ('update', None), ('render', 'abc', {'pl': pl, 'update_first': True, 'interval': 0.2}), ('update', 'abc'), ('update', 'def'), ]) num_runs = len([e for e in log if e[0] == 'update']) self.assertAlmostEqual(duration / 0.2, num_runs, delta=1) log[:] = () segment = TestSegment() block_event.set() kwargs = {'pl': pl, 'update_first': True, 'interval': 0.2} with lock: updates[0] = ('ghi',) segment.startup(**kwargs) start = monotonic() ret1 = segment(**kwargs) with lock: updates[0] = TypeError('jkl') self.assertEqual(thread_number(), 2) sleep(0.5) ret2 = segment(**kwargs) segment.shutdown_event.set() segment.thread.join() end = monotonic() duration = end - start self.assertEqual(ret1, 'ghi') self.assertEqual(ret2, None) self.assertEqual(log[:5], [ ('set_state', {'update_first': True, 'interval': 0.2}), ('update', None), ('render', 'ghi', {'pl': pl, 'update_first': True, 'interval': 0.2}), ('update', 'ghi'), ('update', 'ghi'), ]) num_runs = len([e for e in log if e[0] == 'update']) self.assertAlmostEqual(duration / 0.2, num_runs, delta=1) self.assertEqual(num_runs - 1, len(pl.exceptions)) log[:] = () def test_kw_threaded_segment(self): log = [] pl = Pl() event = threading.Event() class TestSegment(KwThreadedSegment): interval = 10 @staticmethod def key(_key=(None,), **kwargs): log.append(('key', _key, kwargs)) return _key def compute_state(self, key): event.set() sleep(0.1) log.append(('compute_state', key)) ret = key if isinstance(ret, Exception): raise ret else: return ret[0] def render_one(self, state, **kwargs): log.append(('render_one', state, kwargs)) if isinstance(state, Exception): raise state else: return state # Non-threaded tests segment = TestSegment() event.clear() self.assertEqual(segment(pl=pl), None) self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('key', (None,), {'pl': pl}), ('compute_state', (None,)), ('render_one', None, {'pl': pl}), ]) log[:] = () segment = TestSegment() kwargs = {'pl': pl, '_key': ('abc',), 'update_first': False} event.clear() self.assertEqual(segment(**kwargs), 'abc') kwargs.update(_key=('def',)) self.assertEqual(segment(**kwargs), 'def') self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('key', ('abc',), {'pl': pl}), ('compute_state', ('abc',)), ('render_one', 'abc', {'pl': pl, '_key': ('abc',)}), ('key', ('def',), {'pl': pl}), ('compute_state', ('def',)), ('render_one', 'def', {'pl': pl, '_key': ('def',)}), ]) log[:] = () segment = TestSegment() kwargs = {'pl': pl, '_key': ValueError('xyz'), 'update_first': False} event.clear() self.assertEqual(segment(**kwargs), None) self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('key', kwargs['_key'], {'pl': pl}), ('compute_state', kwargs['_key']), ]) log[:] = () segment = TestSegment() kwargs = {'pl': pl, '_key': (ValueError('abc'),), 'update_first': False} event.clear() self.assertRaises(ValueError, segment, **kwargs) self.assertEqual(thread_number(), 1) self.assertEqual(log, [ ('key', kwargs['_key'], {'pl': pl}), ('compute_state', kwargs['_key']), ('render_one', kwargs['_key'][0], {'pl': pl, '_key': kwargs['_key']}), ]) log[:] = () # Threaded tests segment = TestSegment() kwargs = {'pl': pl, 'update_first': False, '_key': ('_abc',)} event.clear() segment.startup(**kwargs) ret = segment(**kwargs) self.assertEqual(thread_number(), 2) segment.shutdown_event.set() segment.thread.join() self.assertEqual(ret, None) self.assertEqual(log[:2], [ ('key', kwargs['_key'], {'pl': pl}), ('render_one', None, {'pl': pl, '_key': kwargs['_key']}), ]) self.assertLessEqual(len(log), 3) if len(log) > 2: self.assertEqual(log[2], ('compute_state', kwargs['_key'])) log[:] = () segment = TestSegment() kwargs = {'pl': pl, 'update_first': True, '_key': ('_abc',)} event.clear() segment.startup(**kwargs) ret1 = segment(**kwargs) kwargs.update(_key=('_def',)) ret2 = segment(**kwargs) self.assertEqual(thread_number(), 2) segment.shutdown_event.set() segment.thread.join() self.assertEqual(ret1, '_abc') self.assertEqual(ret2, '_def') self.assertEqual(log, [ ('key', ('_abc',), {'pl': pl}), ('compute_state', ('_abc',)), ('render_one', '_abc', {'pl': pl, '_key': ('_abc',)}), ('key', ('_def',), {'pl': pl}), ('compute_state', ('_def',)), ('render_one', '_def', {'pl': pl, '_key': ('_def',)}), ]) log[:] = () class TestLib(TestCase): def test_mergedicts(self): d = {} mergedicts(d, {'abc': {'def': 'ghi'}}) self.assertEqual(d, {'abc': {'def': 'ghi'}}) mergedicts(d, {'abc': {'def': {'ghi': 'jkl'}}}) self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}}}) mergedicts(d, {}) self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}}}) mergedicts(d, {'abc': {'mno': 'pqr'}}) self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}, 'mno': 'pqr'}}) mergedicts(d, {'abc': {'def': REMOVE_THIS_KEY}}) self.assertEqual(d, {'abc': {'mno': 'pqr'}}) def test_add_divider_highlight_group(self): def decorated_function_name(**kwargs): return str(kwargs) func = add_divider_highlight_group('hl_group')(decorated_function_name) self.assertEqual(func.__name__, 'decorated_function_name') self.assertEqual(func(kw={}), [{'contents': repr({str('kw'): {}}), 'divider_highlight_group': 'hl_group'}]) def test_humanize_bytes(self): self.assertEqual(humanize_bytes(0), '0 B') self.assertEqual(humanize_bytes(1), '1 B') self.assertEqual(humanize_bytes(1, suffix='bit'), '1 bit') self.assertEqual(humanize_bytes(1000, si_prefix=True), '1 kB') self.assertEqual(humanize_bytes(1024, si_prefix=True), '1 kB') self.assertEqual(humanize_bytes(1000000000, si_prefix=True), '1.00 GB') self.assertEqual(humanize_bytes(1000000000, si_prefix=False), '953.7 MiB') width_data = { 'N': 1, # Neutral 'Na': 1, # Narrow 'A': 1, # Ambiguous 'H': 1, # Half-width 'W': 2, # Wide 'F': 2, # Fullwidth } class TestUnicode(TestCase): def assertStringsIdentical(self, s1, s2): self.assertTrue(type(s1) is type(s2), msg='string types differ') self.assertEqual(s1, s2) def test_unicode(self): self.assertTrue(type('abc') is plu.unicode) def test_unichr(self): self.assertStringsIdentical('\U0010FFFF', plu.unichr(0x10FFFF)) self.assertStringsIdentical('\uFFFF', plu.unichr(0xFFFF)) self.assertStringsIdentical('\x20', plu.unichr(0x20)) def test_u(self): self.assertStringsIdentical('Test', plu.u('Test')) self.assertStringsIdentical('Test', plu.u(b'Test')) self.assertStringsIdentical('«»', plu.u(b'\xC2\xAB\xC2\xBB')) self.assertRaises(UnicodeDecodeError, plu.u, b'\xFF') def test_tointiter(self): self.assertEqual([1, 2, 3], list(plu.tointiter(b'\x01\x02\x03'))) def test_decode_error(self): self.assertStringsIdentical('', b'\xFF'.decode('utf-8', 'powerline_decode_error')) self.assertStringsIdentical('abc', b'abc'.decode('utf-8', 'powerline_decode_error')) def test_register_strwidth_error(self): ename = plu.register_strwidth_error(lambda s: 3) self.assertStringsIdentical(b'???', 'A'.encode('latin1', ename)) self.assertStringsIdentical(b'abc', 'abc'.encode('latin1', ename)) def test_out_u(self): self.assertStringsIdentical('abc', plu.out_u('abc')) self.assertStringsIdentical('abc', plu.out_u(b'abc')) self.assertRaises(TypeError, plu.out_u, None) def test_safe_unicode(self): self.assertStringsIdentical('abc', plu.safe_unicode('abc')) self.assertStringsIdentical('abc', plu.safe_unicode(b'abc')) self.assertStringsIdentical('«»', plu.safe_unicode(b'\xc2\xab\xc2\xbb')) with replace_attr(plu, 'get_preferred_output_encoding', lambda: 'latin1'): self.assertStringsIdentical('ÿ', plu.safe_unicode(b'\xFF')) self.assertStringsIdentical('None', plu.safe_unicode(None)) class FailingStr(object): def __str__(self): raise NotImplementedError('Fail!') self.assertStringsIdentical('Fail!', plu.safe_unicode(FailingStr())) def test_FailedUnicode(self): self.assertTrue(isinstance(plu.FailedUnicode('abc'), plu.unicode)) self.assertEqual('abc', plu.FailedUnicode('abc')) def test_string(self): self.assertStringsIdentical(str('abc'), plu.string('abc')) self.assertStringsIdentical(str('abc'), plu.string(b'abc')) def test_surrogate_pair_to_character(self): self.assertEqual(0x1F48E, plu.surrogate_pair_to_character(0xD83D, 0xDC8E)) def test_strwidth_ucs_4(self): self.assertEqual(4, plu.strwidth_ucs_4(width_data, 'abcd')) self.assertEqual(4, plu.strwidth_ucs_4(width_data, 'AB')) if sys.maxunicode < 0x10FFFF: raise SkipTest('Can only test strwidth_ucs_4 in UCS-4 Pythons') self.assertEqual(1, plu.strwidth_ucs_4(width_data, '\U0001F063')) def test_strwidth_ucs_2(self): self.assertEqual(4, plu.strwidth_ucs_2(width_data, 'abcd')) self.assertEqual(4, plu.strwidth_ucs_2(width_data, 'AB')) if not sys.maxunicode < 0x10FFFF: raise SkipTest('Can only test strwidth_ucs_2 in UCS-2 Pythons') self.assertEqual(1, plu.strwidth_ucs_2(width_data, '\ud83c\udc30')) class TestVCS(TestCase): def do_branch_rename_test(self, repo, q): st = monotonic() while monotonic() - st < 1: # Give inotify time to deliver events ans = repo.branch() if hasattr(q, '__call__'): if q(ans): break else: if ans == q: break sleep(0.01) if hasattr(q, '__call__'): self.assertTrue(q(ans)) else: self.assertEqual(ans, q) def test_git(self): create_watcher = get_fallback_create_watcher() repo = guess(path=GIT_REPO, create_watcher=create_watcher) self.assertNotEqual(repo, None) self.assertEqual(repo.branch(), 'master') self.assertEqual(repo.status(), None) self.assertEqual(repo.status('file'), None) with open(os.path.join(GIT_REPO, 'file'), 'w') as f: f.write('abc') f.flush() self.assertEqual(repo.status(), ' U') self.assertEqual(repo.status('file'), '??') call(['git', 'add', '.'], cwd=GIT_REPO) self.assertEqual(repo.status(), ' I ') self.assertEqual(repo.status('file'), 'A ') f.write('def') f.flush() self.assertEqual(repo.status(), 'DI ') self.assertEqual(repo.status('file'), 'AM') os.remove(os.path.join(GIT_REPO, 'file')) # Test changing branch self.assertEqual(repo.branch(), 'master') try: call(['git', 'branch', 'branch1'], cwd=GIT_REPO) call(['git', 'checkout', '-q', 'branch1'], cwd=GIT_REPO) self.do_branch_rename_test(repo, 'branch1') call(['git', 'branch', 'branch2'], cwd=GIT_REPO) call(['git', 'checkout', '-q', 'branch2'], cwd=GIT_REPO) self.do_branch_rename_test(repo, 'branch2') call(['git', 'checkout', '-q', '--detach', 'branch1'], cwd=GIT_REPO) self.do_branch_rename_test(repo, lambda b: re.match(r'^[a-f0-9]+$', b)) finally: call(['git', 'checkout', '-q', 'master'], cwd=GIT_REPO) # Test stashing self.assertEqual(repo.stash(), 0) def stash_save(): with open(os.path.join(GIT_REPO, 'file'), 'w') as f: f.write('abc') return call(['git', 'stash', '-u'], cwd=GIT_REPO, stdout=PIPE) def stash_drop(): return call(['git', 'stash', 'drop'], cwd=GIT_REPO, stdout=PIPE) def stash_list(): return call(['git', 'stash', 'list'], cwd=GIT_REPO, stdout=PIPE) try: stash_save() self.assertEqual(repo.stash(), 1) stash_save() self.assertEqual(repo.stash(), 2) stash_drop() self.assertEqual(repo.stash(), 1) stash_drop() self.assertEqual(repo.stash(), 0) finally: while stash_list(): stash_drop() def test_git_sym(self): create_watcher = get_fallback_create_watcher() dotgit = os.path.join(GIT_REPO, '.git') spacegit = os.path.join(GIT_REPO, ' .git ') os.rename(dotgit, spacegit) try: with open(dotgit, 'w') as F: F.write('gitdir: .git \n') gitdir = git_directory(GIT_REPO) self.assertTrue(os.path.isdir(gitdir)) self.assertEqual(gitdir, os.path.abspath(spacegit)) repo = guess(path=GIT_REPO, create_watcher=create_watcher) self.assertEqual(repo.branch(), 'master') finally: os.remove(dotgit) os.rename(spacegit, dotgit) def test_mercurial(self): if not use_mercurial: raise SkipTest('Mercurial is not available') create_watcher = get_fallback_create_watcher() repo = guess(path=HG_REPO, create_watcher=create_watcher) self.assertNotEqual(repo, None) self.assertEqual(repo.branch(), 'default') self.assertEqual(repo.status(), None) with open(os.path.join(HG_REPO, 'file'), 'w') as f: f.write('abc') f.flush() self.assertEqual(repo.status(), ' U') self.assertEqual(repo.status('file'), 'U') call(['hg', 'add', '.'], cwd=HG_REPO, stdout=PIPE) self.assertEqual(repo.status(), 'D ') self.assertEqual(repo.status('file'), 'A') os.remove(os.path.join(HG_REPO, 'file')) def test_bzr(self): if not use_bzr: raise SkipTest('Bazaar is not available') create_watcher = get_fallback_create_watcher() repo = guess(path=BZR_REPO, create_watcher=create_watcher) self.assertNotEqual(repo, None, 'No bzr repo found. Do you have bzr installed?') self.assertEqual(repo.branch(), 'test_powerline') self.assertEqual(repo.status(), None) with open(os.path.join(BZR_REPO, 'file'), 'w') as f: f.write('abc') self.assertEqual(repo.status(), ' U') self.assertEqual(repo.status('file'), '? ') call(['bzr', 'add', '-q', '.'], cwd=BZR_REPO, stdout=PIPE) self.assertEqual(repo.status(), 'D ') self.assertEqual(repo.status('file'), '+N') call(['bzr', 'commit', '-q', '-m', 'initial commit'], cwd=BZR_REPO) self.assertEqual(repo.status(), None) with open(os.path.join(BZR_REPO, 'file'), 'w') as f: f.write('def') self.assertEqual(repo.status(), 'D ') self.assertEqual(repo.status('file'), ' M') self.assertEqual(repo.status('notexist'), None) with open(os.path.join(BZR_REPO, 'ignored'), 'w') as f: f.write('abc') self.assertEqual(repo.status('ignored'), '? ') # Test changing the .bzrignore file should update status with open(os.path.join(BZR_REPO, '.bzrignore'), 'w') as f: f.write('ignored') self.assertEqual(repo.status('ignored'), None) # Test changing the dirstate file should invalidate the cache for # all files in the repo with open(os.path.join(BZR_REPO, 'file2'), 'w') as f: f.write('abc') call(['bzr', 'add', 'file2'], cwd=BZR_REPO, stdout=PIPE) call(['bzr', 'commit', '-q', '-m', 'file2 added'], cwd=BZR_REPO) with open(os.path.join(BZR_REPO, 'file'), 'a') as f: f.write('hello') with open(os.path.join(BZR_REPO, 'file2'), 'a') as f: f.write('hello') self.assertEqual(repo.status('file'), ' M') self.assertEqual(repo.status('file2'), ' M') call(['bzr', 'commit', '-q', '-m', 'multi'], cwd=BZR_REPO) self.assertEqual(repo.status('file'), None) self.assertEqual(repo.status('file2'), None) # Test changing branch call(['bzr', 'nick', 'branch1'], cwd=BZR_REPO, stdout=PIPE, stderr=PIPE) self.do_branch_rename_test(repo, 'branch1') # Test branch name/status changes when swapping repos for x in ('b1', 'b2'): d = os.path.join(BZR_REPO, x) os.mkdir(d) call(['bzr', 'init', '-q'], cwd=d) call(['bzr', 'nick', '-q', x], cwd=d) repo = guess(path=d, create_watcher=create_watcher) self.assertEqual(repo.branch(), x) self.assertFalse(repo.status()) if x == 'b1': open(os.path.join(d, 'dirty'), 'w').close() self.assertTrue(repo.status()) os.rename(os.path.join(BZR_REPO, 'b1'), os.path.join(BZR_REPO, 'b')) os.rename(os.path.join(BZR_REPO, 'b2'), os.path.join(BZR_REPO, 'b1')) os.rename(os.path.join(BZR_REPO, 'b'), os.path.join(BZR_REPO, 'b2')) for x, y in (('b1', 'b2'), ('b2', 'b1')): d = os.path.join(BZR_REPO, x) repo = guess(path=d, create_watcher=create_watcher) self.do_branch_rename_test(repo, y) if x == 'b1': self.assertFalse(repo.status()) else: self.assertTrue(repo.status()) @classmethod def setUpClass(cls): cls.powerline_old_cwd = os.getcwd() os.chdir(os.path.dirname(os.path.dirname(__file__))) call(['git', 'init', '--quiet', GIT_REPO]) assert os.path.isdir(GIT_REPO) call(['git', 'config', '--local', 'user.name', 'Foo'], cwd=GIT_REPO) call(['git', 'config', '--local', 'user.email', 'bar@example.org'], cwd=GIT_REPO) call(['git', 'commit', '--allow-empty', '--message', 'Initial commit', '--quiet'], cwd=GIT_REPO) if use_mercurial: cls.powerline_old_HGRCPATH = os.environ.get('HGRCPATH') os.environ['HGRCPATH'] = '' call(['hg', 'init', HG_REPO]) with open(os.path.join(HG_REPO, '.hg', 'hgrc'), 'w') as hgrc: hgrc.write('[ui]\n') hgrc.write('username = Foo \n') if use_bzr: call(['bzr', 'init', '--quiet', BZR_REPO]) call(['bzr', 'config', 'email=Foo '], cwd=BZR_REPO) call(['bzr', 'config', 'nickname=test_powerline'], cwd=BZR_REPO) call(['bzr', 'config', 'create_signatures=0'], cwd=BZR_REPO) @classmethod def tearDownClass(cls): for repo_dir in [GIT_REPO] + ([HG_REPO] if use_mercurial else []) + ([BZR_REPO] if use_bzr else []): shutil.rmtree(repo_dir) if use_mercurial: if cls.powerline_old_HGRCPATH is None: os.environ.pop('HGRCPATH') else: os.environ['HGRCPATH'] = cls.powerline_old_HGRCPATH os.chdir(cls.powerline_old_cwd) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_lib_config.py000066400000000000000000000021651466405252600227750ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os from powerline.lib.config import ConfigLoader from tests.modules import TestCase from tests.modules.lib.fsconfig import FSTree FILE_ROOT = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'cfglib') class LoadedList(list): def pop_all(self): try: return self[:] finally: self[:] = () loaded = LoadedList() def on_load(key): loaded.append(key) def check_file(path): if os.path.exists(path): return path else: raise IOError class TestLoaderCondition(TestCase): def test_update_missing(self): loader = ConfigLoader(run_once=True) fpath = os.path.join(FILE_ROOT, 'file.json') self.assertRaises(IOError, loader.load, fpath) loader.register_missing(check_file, on_load, fpath) loader.update() # This line must not raise IOError with FSTree({'file': {'test': 1}}, root=FILE_ROOT): loader.update() self.assertEqual(loader.load(fpath), {'test': 1}) self.assertEqual(loaded.pop_all(), [fpath]) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_listers.py000066400000000000000000000074241466405252600223720ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import powerline.listers.i3wm as i3wm from tests.modules.lib import Args, replace_attr, Pl from tests.modules import TestCase class TestI3WM(TestCase): workspaces = [ Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False), Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True), Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True), Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True), ] @staticmethod def get_workspaces(): return iter(TestI3WM.workspaces) @staticmethod def get_outputs(pl): return iter([ {'name': 'LVDS1'}, {'name': 'HDMI1'}, {'name': 'DVI01'}, ]) def test_output_lister(self): pl = Pl() with replace_attr(i3wm, 'get_connected_xrandr_outputs', self.get_outputs): self.assertEqual( list(i3wm.output_lister(pl=pl, segment_info={'a': 1})), [ ({'a': 1, 'output': 'LVDS1'}, {'draw_inner_divider': None}), ({'a': 1, 'output': 'HDMI1'}, {'draw_inner_divider': None}), ({'a': 1, 'output': 'DVI01'}, {'draw_inner_divider': None}), ] ) def test_workspace_lister(self): pl = Pl() with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)): self.assertEqual( list(i3wm.workspace_lister(pl=pl, segment_info={'a': 1})), [ ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[0], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[1], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'HDMI1', 'workspace': self.workspaces[2], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'DVI01', 'workspace': self.workspaces[3], }, {'draw_inner_divider': None}), ] ) self.assertEqual( list(i3wm.workspace_lister(pl=pl, segment_info={'a': 1}, output='LVDS1')), [ ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[0], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[1], }, {'draw_inner_divider': None}), ] ) self.assertEqual( list(i3wm.workspace_lister( pl=pl, segment_info={'a': 1, 'output': 'LVDS1'} )), [ ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[0], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[1], }, {'draw_inner_divider': None}), ] ) self.assertEqual( list(i3wm.workspace_lister( pl=pl, segment_info={'a': 1, 'output': 'LVDS1'}, output=False )), [ ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[0], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'LVDS1', 'workspace': self.workspaces[1], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'HDMI1', 'workspace': self.workspaces[2], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'DVI01', 'workspace': self.workspaces[3], }, {'draw_inner_divider': None}), ] ) self.assertEqual( list(i3wm.workspace_lister( pl=pl, segment_info={'a': 1}, only_show=['focused', 'urgent'] )), [ ({ 'a': 1, 'output': 'HDMI1', 'workspace': self.workspaces[2], }, {'draw_inner_divider': None}), ({ 'a': 1, 'output': 'DVI01', 'workspace': self.workspaces[3], }, {'draw_inner_divider': None}), ] ) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_logging.py000066400000000000000000000361041466405252600223300ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet '''Tests for various logging features''' from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import re import codecs import os from io import StringIO from shutil import rmtree from powerline import finish_common_config, create_logger from tests.modules import TestCase from tests.modules.lib import replace_attr TIMESTAMP_RE = r'\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d{3}' class TestRE(TestCase): def assertMatches(self, text, regexp): self.assertTrue( re.match(regexp, text), '{0!r} did not match {1!r}'.format(text, regexp), ) def close_handlers(logger): for handler in logger.handlers: handler.close() class TestHandlers(TestRE): def test_stderr_handler_is_default(self): out = StringIO() err = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {}) logger, pl, get_module_attr = create_logger(common_config) pl.error('Foo') close_handlers(logger) self.assertMatches(err.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') self.assertEqual(out.getvalue(), '') def test_stream_override(self): out = StringIO() err = StringIO() stream = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_explicit_none(self): out = StringIO() err = StringIO() stream = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [None]}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_explicit_stream_handler(self): out = StringIO() err = StringIO() stream = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [['logging.StreamHandler', [[]]]]}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) self.assertEqual(stream.getvalue(), '') self.assertMatches(err.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') self.assertEqual(out.getvalue(), '') def test_explicit_stream_handler_implicit_stream(self): out = StringIO() err = StringIO() stream = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [['logging.StreamHandler', []]]}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_file_handler(self): out = StringIO() err = StringIO() stream = StringIO() file_name = 'test_logging-test_file_handler' with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': file_name}) try: logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) with codecs.open(file_name, encoding='utf-8') as fp: self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') finally: os.unlink(file_name) self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_file_handler_create_dir(self): out = StringIO() err = StringIO() stream = StringIO() file_name = 'test_logging-test_file_handler_create_dir/file' self.assertFalse(os.path.isdir(os.path.dirname(file_name))) with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': file_name}) try: logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) self.assertTrue(os.path.isdir(os.path.dirname(file_name))) with codecs.open(file_name, encoding='utf-8') as fp: self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') finally: rmtree(os.path.dirname(file_name)) self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_multiple_files(self): out = StringIO() err = StringIO() stream = StringIO() file_name_1 = 'test_logging-test_multiple_files-1' file_name_2 = file_name_1[:-1] + '2' with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [file_name_1, file_name_2]}) try: try: logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) for file_name in (file_name_1, file_name_2): with codecs.open(file_name, encoding='utf-8') as fp: self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') finally: os.unlink(file_name_1) finally: os.unlink(file_name_2) self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_multiple_files_and_stream(self): out = StringIO() err = StringIO() stream = StringIO() file_name_1 = 'test_logging-test_multiple_files_and_stream-1' file_name_2 = file_name_1[:-1] + '2' with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [file_name_1, file_name_2, None]}) try: try: logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) for file_name in (file_name_1, file_name_2): with codecs.open(file_name, encoding='utf-8') as fp: self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') finally: os.unlink(file_name_1) finally: os.unlink(file_name_2) self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_handler_args(self): out = StringIO() err = StringIO() stream = StringIO() file_name = 'test_logging-test_handler_args' with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [ ['RotatingFileHandler', [[file_name]]] ]}) try: logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') close_handlers(logger) with codecs.open(file_name, encoding='utf-8') as fp: self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') finally: os.unlink(file_name) self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_handler_args_kwargs(self): out = StringIO() err = StringIO() stream = StringIO() file_name = 'test_logging-test_handler_args_kwargs' with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [ ['RotatingFileHandler', [[file_name], {'maxBytes': 1, 'backupCount': 1}]] ]}) try: try: logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.error('Foo') pl.error('Bar') close_handlers(logger) with codecs.open(file_name, encoding='utf-8') as fp: self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$') with codecs.open(file_name + '.1', encoding='utf-8') as fp: self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$') finally: os.unlink(file_name + '.1') finally: os.unlink(file_name) self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_logger_level(self): out = StringIO() err = StringIO() stream = StringIO() stream1 = StringIO() stream2 = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [ ['logging.StreamHandler', [[stream1]], 'WARNING'], ['logging.StreamHandler', [[stream2]], 'ERROR'], ]}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.warn('Foo') pl.error('Bar') close_handlers(logger) self.assertMatches(stream1.getvalue(), ( '^' + TIMESTAMP_RE + ':WARNING:__unknown__:Foo\n' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$' )) self.assertMatches(stream2.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$') self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_logger_level_not_overriding_default(self): out = StringIO() err = StringIO() stream = StringIO() stream1 = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [ ['logging.StreamHandler', [[stream1]], 'DEBUG'], ]}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.debug('Foo') pl.error('Bar') close_handlers(logger) self.assertMatches(stream1.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$') self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_top_log_level(self): out = StringIO() err = StringIO() stream = StringIO() stream1 = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [ ['logging.StreamHandler', [[stream1]], 'DEBUG'], ], 'log_level': 'DEBUG'}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.debug('Foo') pl.error('Bar') close_handlers(logger) self.assertMatches(stream1.getvalue(), ( '^' + TIMESTAMP_RE + ':DEBUG:__unknown__:Foo\n' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$' )) self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_logger_format(self): out = StringIO() err = StringIO() stream = StringIO() stream1 = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [ ['logging.StreamHandler', [[stream1]], 'WARNING', 'FOO'], ]}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.warn('Foo') pl.error('Bar') close_handlers(logger) self.assertEqual(stream1.getvalue(), 'FOO\nFOO\n') self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') def test_top_log_format(self): out = StringIO() err = StringIO() stream = StringIO() stream1 = StringIO() stream2 = StringIO() with replace_attr(sys, 'stdout', out, 'stderr', err): common_config = finish_common_config('utf-8', {'log_file': [ ['logging.StreamHandler', [[stream1]], 'WARNING', 'FOO'], ['logging.StreamHandler', [[stream2]], 'WARNING'], ], 'log_format': 'BAR'}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.warn('Foo') pl.error('Bar') close_handlers(logger) self.assertEqual(stream2.getvalue(), 'BAR\nBAR\n') self.assertEqual(stream1.getvalue(), 'FOO\nFOO\n') self.assertEqual(stream.getvalue(), '') self.assertEqual(err.getvalue(), '') self.assertEqual(out.getvalue(), '') class TestPowerlineLogger(TestRE): def test_args_formatting(self): stream = StringIO() common_config = finish_common_config('utf-8', {}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.warn('foo {0}', 'Test') pl.warn('bar {0!r}', 'Test') close_handlers(logger) self.assertMatches(stream.getvalue(), ( '^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo Test\n' + TIMESTAMP_RE + ':WARNING:__unknown__:bar u?\'Test\'\n$' )) def test_prefix_formatting(self): stream = StringIO() common_config = finish_common_config('utf-8', {}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.prefix = '1' pl.warn('foo') pl.prefix = '2' pl.warn('bar') close_handlers(logger) self.assertMatches(stream.getvalue(), ( '^' + TIMESTAMP_RE + ':WARNING:__unknown__:1:foo\n' + TIMESTAMP_RE + ':WARNING:__unknown__:2:bar\n$' )) def test_kwargs_formatting(self): stream = StringIO() common_config = finish_common_config('utf-8', {}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.warn('foo {arg}', arg='Test') pl.warn('bar {arg!r}', arg='Test') close_handlers(logger) self.assertMatches(stream.getvalue(), ( '^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo Test\n' + TIMESTAMP_RE + ':WARNING:__unknown__:bar u?\'Test\'\n$' )) def test_args_kwargs_formatting(self): stream = StringIO() common_config = finish_common_config('utf-8', {}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.warn('foo {0!r} {arg}', 'Test0', arg='Test') pl.warn('bar {0} {arg!r}', 'Test0', arg='Test') close_handlers(logger) self.assertMatches(stream.getvalue(), ( '^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo u?\'Test0\' Test\n' + TIMESTAMP_RE + ':WARNING:__unknown__:bar Test0 u?\'Test\'\n$' )) def test_exception_formatting(self): stream = StringIO() common_config = finish_common_config('utf-8', {}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) try: raise ValueError('foo') except ValueError: pl.exception('Message') close_handlers(logger) self.assertMatches(stream.getvalue(), ( '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Message\n' + 'Traceback \\(most recent call last\\):\n' + '(?: File ".*?", line \\d+, in \\w+\n [^\n]*\n)+' + 'ValueError: foo\n$' )) def test_levels(self): stream = StringIO() common_config = finish_common_config('utf-8', {'log_level': 'DEBUG'}) logger, pl, get_module_attr = create_logger(common_config, stream=stream) pl.debug('1') pl.info('2') pl.warn('3') pl.error('4') pl.critical('5') close_handlers(logger) self.assertMatches(stream.getvalue(), ( '^' + TIMESTAMP_RE + ':DEBUG:__unknown__:1\n' + TIMESTAMP_RE + ':INFO:__unknown__:2\n' + TIMESTAMP_RE + ':WARNING:__unknown__:3\n' + TIMESTAMP_RE + ':ERROR:__unknown__:4\n' + TIMESTAMP_RE + ':CRITICAL:__unknown__:5\n$' )) old_cwd = None def setUpModule(): global old_cwd global __file__ old_cwd = os.getcwd() __file__ = os.path.abspath(__file__) os.chdir(os.path.dirname(os.path.dirname(__file__))) def tearDownModule(): global old_cwd os.chdir(old_cwd) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_provided_config_files.py000066400000000000000000000160771466405252600252340ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet '''Dynamic configuration files tests.''' from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import os import json import logging import tests.modules.vim as vim_module from tests.modules.lib import Args, urllib_read, replace_attr from tests.modules import TestCase from powerline import NotInterceptedError from powerline.segments.common import wthr VBLOCK = chr(ord('V') - 0x40) SBLOCK = chr(ord('S') - 0x40) class FailingLogger(logging.Logger): def exception(self, *args, **kwargs): super(FailingLogger, self).exception(*args, **kwargs) raise NotInterceptedError('Unexpected exception occurred') def get_logger(stream=None): 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 = FailingLogger('powerline') logger.setLevel(level) logger.addHandler(handler) return logger class TestVimConfig(TestCase): def test_vim(self): from powerline.vim import VimPowerline cfg_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'powerline', 'config_files') buffers = ( (('bufoptions',), {'buftype': 'help'}), (('bufname', '[Command Line]'), {}), (('bufoptions',), {'buftype': 'quickfix'}), (('bufname', 'NERD_tree_1'), {}), (('bufname', '__Gundo__'), {}), (('bufname', '__Gundo_Preview__'), {}), # No Command-T tests here: requires +ruby or emulation # No tabline here: tablines are tested separately ) with open(os.path.join(cfg_path, 'config.json'), 'r') as f: local_themes_raw = json.load(f)['ext']['vim']['local_themes'] # Don’t run tests on external/plugin segments local_themes = dict((k, v) for (k, v) in local_themes_raw.items()) # See end of the buffers definition above for `- 2` self.assertEqual(len(buffers), len(local_themes) - 2) outputs = {} i = 0 with vim_module._with('split'): with VimPowerline(logger=get_logger()) as powerline: def check_output(mode, args, kwargs): if mode == 'nc': window = vim_module.windows[0] window_id = 2 else: vim_module._start_mode(mode) window = vim_module.current.window window_id = 1 winnr = window.number out = powerline.render(window, window_id, winnr) if out in outputs: self.fail('Duplicate in set #{0} ({1}) for mode {2!r} (previously defined in set #{3} ({4!r}) for mode {5!r})'.format(i, (args, kwargs), mode, *outputs[out])) outputs[out] = (i, (args, kwargs), mode) with vim_module._with('bufname', '/tmp/foo.txt'): out = powerline.render(vim_module.current.window, 1, vim_module.current.window.number, is_tabline=True) outputs[out] = (-1, (None, None), 'tab') with vim_module._with('globals', powerline_config_paths=[cfg_path]): exclude = set(('no', 'v', 'V', VBLOCK, 's', 'S', SBLOCK, 'R', 'Rv', 'c', 'cv', 'ce', 'r', 'rm', 'r?', '!')) try: for mode in ['n', 'nc', 'no', 'v', 'V', VBLOCK, 's', 'S', SBLOCK, 'i', 'R', 'Rv', 'c', 'cv', 'ce', 'r', 'rm', 'r?', '!']: check_output(mode, None, None) for args, kwargs in buffers: i += 1 if mode in exclude: continue with vim_module._with(*args, **kwargs): check_output(mode, args, kwargs) finally: vim_module._start_mode('n') @classmethod def setUpClass(cls): sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) @classmethod def tearDownClass(cls): sys.path.pop(0) class TestConfig(TestCase): def test_tmux(self): from powerline.segments import common from importlib import reload reload(common) from powerline.shell import ShellPowerline with replace_attr(common, 'urllib_read', urllib_read): with ShellPowerline(Args(ext=['tmux']), logger=get_logger(), run_once=False) as powerline: powerline.render() with ShellPowerline(Args(ext=['tmux']), logger=get_logger(), run_once=False) as powerline: powerline.render() def test_zsh(self): from powerline.shell import ShellPowerline args = Args(last_pipe_status=[1, 0], jobnum=0, ext=['shell'], renderer_module='.zsh') segment_info = {'args': args} with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: powerline.render(segment_info=segment_info) with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: powerline.render(segment_info=segment_info) segment_info['local_theme'] = 'select' with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: powerline.render(segment_info=segment_info) segment_info['local_theme'] = 'continuation' segment_info['parser_state'] = 'if cmdsubst' with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: powerline.render(segment_info=segment_info) def test_bash(self): from powerline.shell import ShellPowerline args = Args(last_exit_code=1, last_pipe_status=[], jobnum=0, ext=['shell'], renderer_module='.bash', config_override={'ext': {'shell': {'theme': 'default_leftonly'}}}) with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: powerline.render(segment_info={'args': args}) with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: powerline.render(segment_info={'args': args}) def test_ipython(self): from powerline.ipython import IPythonPowerline class IpyPowerline(IPythonPowerline): config_paths = None config_overrides = None theme_overrides = {} segment_info = Args(prompt_count=1) with IpyPowerline(logger=get_logger(), renderer_module='.pre_5') as powerline: for prompt_type in ['in', 'in2']: powerline.render(is_prompt=True, matcher_info=prompt_type, segment_info=segment_info) powerline.render(is_prompt=True, matcher_info=prompt_type, segment_info=segment_info) with IpyPowerline(logger=get_logger(), renderer_module='.pre_5') as powerline: for prompt_type in ['out', 'rewrite']: powerline.render(is_prompt=False, matcher_info=prompt_type, segment_info=segment_info) powerline.render(is_prompt=False, matcher_info=prompt_type, segment_info=segment_info) def test_wm(self): from powerline.segments import common from importlib import reload reload(common) from powerline import Powerline with replace_attr(wthr, 'urllib_read', urllib_read): Powerline(logger=get_logger(), ext='wm', renderer_module='pango_markup', run_once=True).render() reload(common) old_cwd = None saved_get_config_paths = None def setUpModule(): global old_cwd global saved_get_config_paths import powerline saved_get_config_paths = powerline.get_config_paths path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'powerline', 'config_files') powerline.get_config_paths = lambda: [path] old_cwd = os.getcwd() def tearDownModule(): global old_cwd global saved_get_config_paths import powerline powerline.get_config_paths = saved_get_config_paths os.chdir(old_cwd) old_cwd = None if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_segments.py000066400000000000000000002724511466405252600225360ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import os from functools import partial from collections import namedtuple from time import sleep from platform import python_implementation from powerline.segments import shell, tmux, pdb, i3wm from powerline.lib.vcs import get_fallback_create_watcher from powerline.lib.unicode import out_u import tests.modules.vim as vim_module from tests.modules.lib import (Args, urllib_read, replace_attr, new_module, replace_module_module, replace_env, Pl) from tests.modules import TestCase, SkipTest def get_dummy_guess(**kwargs): if 'directory' in kwargs: def guess(path, create_watcher): return Args(branch=lambda: out_u(os.path.basename(path)), **kwargs) else: def guess(path, create_watcher): return Args(branch=lambda: out_u(os.path.basename(path)), directory=path, **kwargs) return guess class TestShell(TestCase): def test_last_status(self): pl = Pl() segment_info = {'args': Args(last_exit_code=10)} self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ {'contents': '10', 'highlight_groups': ['exit_fail']} ]) segment_info['args'].last_exit_code = 137 self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ {'contents': 'SIGKILL', 'highlight_groups': ['exit_fail']} ]) self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info, signal_names=False), [ {'contents': '137', 'highlight_groups': ['exit_fail']} ]) segment_info['args'].last_exit_code = 0 self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), None) segment_info['args'].last_exit_code = None self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), None) segment_info['args'].last_exit_code = 'sigsegv' self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ {'contents': 'sigsegv', 'highlight_groups': ['exit_fail']} ]) segment_info['args'].last_exit_code = 'sigsegv+core' self.assertEqual(shell.last_status(pl=pl, segment_info=segment_info), [ {'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail']} ]) def test_last_pipe_status(self): pl = Pl() segment_info = {'args': Args(last_pipe_status=[], last_exit_code=0)} self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) segment_info['args'].last_pipe_status = [0, 0, 0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) segment_info['args'].last_pipe_status = [0, 0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) segment_info['args'].last_pipe_status = [0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) segment_info['args'].last_pipe_status = [0, 2, 0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, ]) segment_info['args'].last_pipe_status = [2, 0, 0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, ]) segment_info['args'].last_pipe_status = [137, 0, 0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': 'SIGKILL', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, ]) self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info, signal_names=False), [ {'contents': '137', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, ]) segment_info['args'].last_pipe_status = [0, 0, 2] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, ]) segment_info['args'].last_pipe_status = [2] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, ]) segment_info['args'].last_pipe_status = [0, 'sigsegv', 'sigsegv+core'] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': 'sigsegv', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True} ]) segment_info['args'].last_pipe_status = [0, 'sigsegv', 0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': 'sigsegv', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True} ]) segment_info['args'].last_pipe_status = [0, 'sigsegv+core', 0] self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True} ]) segment_info['args'].last_pipe_status = [] segment_info['args'].last_exit_code = 5 self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ {'contents': '5', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, ]) def test_jobnum(self): pl = Pl() segment_info = {'args': Args(jobnum=0)} self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info), None) self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=False), None) self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=True), '0') segment_info = {'args': Args(jobnum=1)} self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info), '1') self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=False), '1') self.assertEqual(shell.jobnum(pl=pl, segment_info=segment_info, show_zero=True), '1') def test_continuation(self): pl = Pl() self.assertEqual(shell.continuation(pl=pl, segment_info={}), [{ 'contents': '', 'width': 'auto', 'highlight_groups': ['continuation:current', 'continuation'], }]) segment_info = {'parser_state': 'if cmdsubst'} self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info), [ { 'contents': 'if', 'draw_inner_divider': True, 'highlight_groups': ['continuation:current', 'continuation'], 'width': 'auto', 'align': 'l', }, ]) self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, right_align=True), [ { 'contents': 'if', 'draw_inner_divider': True, 'highlight_groups': ['continuation:current', 'continuation'], 'width': 'auto', 'align': 'r', }, ]) self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=False), [ { 'contents': 'if', 'draw_inner_divider': True, 'highlight_groups': ['continuation'], }, { 'contents': 'cmdsubst', 'draw_inner_divider': True, 'highlight_groups': ['continuation:current', 'continuation'], 'width': 'auto', 'align': 'l', }, ]) self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=False, right_align=True), [ { 'contents': 'if', 'draw_inner_divider': True, 'highlight_groups': ['continuation'], 'width': 'auto', 'align': 'r', }, { 'contents': 'cmdsubst', 'draw_inner_divider': True, 'highlight_groups': ['continuation:current', 'continuation'], }, ]) self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=True, right_align=True), [ { 'contents': 'if', 'draw_inner_divider': True, 'highlight_groups': ['continuation:current', 'continuation'], 'width': 'auto', 'align': 'r', }, ]) self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=True, right_align=True, renames={'if': 'IF'}), [ { 'contents': 'IF', 'draw_inner_divider': True, 'highlight_groups': ['continuation:current', 'continuation'], 'width': 'auto', 'align': 'r', }, ]) self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info, omit_cmdsubst=True, right_align=True, renames={'if': None}), [ { 'contents': '', 'highlight_groups': ['continuation:current', 'continuation'], 'width': 'auto', 'align': 'r', }, ]) segment_info = {'parser_state': 'then then then cmdsubst'} self.assertEqual(shell.continuation(pl=pl, segment_info=segment_info), [ { 'contents': 'then', 'draw_inner_divider': True, 'highlight_groups': ['continuation'], }, { 'contents': 'then', 'draw_inner_divider': True, 'highlight_groups': ['continuation'], }, { 'contents': 'then', 'draw_inner_divider': True, 'highlight_groups': ['continuation:current', 'continuation'], 'width': 'auto', 'align': 'l', }, ]) def test_cwd(self): new_os = new_module('os', path=os.path, sep='/') pl = Pl() cwd = [None] def getcwd(): wd = cwd[0] if isinstance(wd, Exception): raise wd else: return wd segment_info = {'getcwd': getcwd, 'home': None} with replace_attr(shell, 'os', new_os): cwd[0] = '/abc/def/ghi/foo/bar' self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'abc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'def', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) segment_info['home'] = '/abc/def/ghi' self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) segment_info.update(shortened_path='~foo/ghi') self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info), [ {'contents': '~foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_shortened_path=False), [ {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) segment_info.pop('shortened_path') self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3), [ {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3, shorten_home=False), [ {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1), [ {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis='---'), [ {'contents': '---', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis=None), [ {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True), [ {'contents': '.../', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis='---'), [ {'contents': '---/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis=None), [ {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'fo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2, use_path_separator=True), [ {'contents': '~/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'fo/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) cwd[0] = '/etc' self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) cwd[0] = '/' self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) ose = OSError() ose.errno = 2 cwd[0] = ose self.assertEqual(shell.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ {'contents': '[not found]', 'divider_highlight_group': 'cwd:divider', 'highlight_groups': ['cwd:current_folder', 'cwd'], 'draw_inner_divider': True} ]) cwd[0] = OSError() self.assertRaises(OSError, shell.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) cwd[0] = ValueError() self.assertRaises(ValueError, shell.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) class TestTmux(TestCase): def test_attached_clients(self): def get_tmux_output(pl, cmd, *args): if cmd == 'list-panes': return 'session_name\n' elif cmd == 'list-clients': return '/dev/pts/2: 0 [191x51 xterm-256color] (utf8)\n/dev/pts/3: 0 [191x51 xterm-256color] (utf8)' pl = Pl() with replace_attr(tmux, 'get_tmux_output', get_tmux_output): self.assertEqual(tmux.attached_clients(pl=pl), '2') self.assertEqual(tmux.attached_clients(pl=pl, minimum=3), None) class TestCommon(TestCase): @classmethod def setUpClass(cls): module = __import__(str('powerline.segments.common.{0}'.format(cls.module_name))) cls.module = getattr(module.segments.common, str(cls.module_name)) class TestNet(TestCommon): module_name = 'net' def test_hostname(self): pl = Pl() with replace_env('SSH_CLIENT', '192.168.0.12 40921 22') as segment_info: with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc'): self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc') self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True), 'abc') with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc.mydomain'): self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc.mydomain') self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, exclude_domain=True), 'abc') self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True), 'abc.mydomain') self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True, exclude_domain=True), 'abc') segment_info['environ'].pop('SSH_CLIENT') with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc'): self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc') self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True), None) with replace_module_module(self.module, 'socket', gethostname=lambda: 'abc.mydomain'): self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info), 'abc.mydomain') self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, exclude_domain=True), 'abc') self.assertEqual(self.module.hostname(pl=pl, segment_info=segment_info, only_if_ssh=True, exclude_domain=True), None) def test_external_ip(self): pl = Pl() with replace_attr(self.module, 'urllib_read', urllib_read): self.assertEqual(self.module.external_ip(pl=pl), [{'contents': '127.0.0.1', 'divider_highlight_group': 'background:divider'}]) def test_internal_ip(self): try: import netifaces except ImportError: raise SkipTest('netifaces module is not available') pl = Pl() addr = { 'enp2s0': { netifaces.AF_INET: [{'addr': '192.168.100.200'}], netifaces.AF_INET6: [{'addr': 'feff::5446:5eff:fe5a:7777%enp2s0'}] }, 'lo': { netifaces.AF_INET: [{'addr': '127.0.0.1'}], netifaces.AF_INET6: [{'addr': '::1'}] }, 'teredo': { netifaces.AF_INET6: [{'addr': 'feff::5446:5eff:fe5a:7777'}] }, } interfaces = ['lo', 'enp2s0', 'teredo'] with replace_module_module( self.module, 'netifaces', interfaces=(lambda: interfaces), ifaddresses=(lambda interface: addr[interface]), AF_INET=netifaces.AF_INET, AF_INET6=netifaces.AF_INET6, ): self.assertEqual(self.module.internal_ip(pl=pl), '192.168.100.200') self.assertEqual(self.module.internal_ip(pl=pl, interface='auto'), '192.168.100.200') self.assertEqual(self.module.internal_ip(pl=pl, interface='lo'), '127.0.0.1') self.assertEqual(self.module.internal_ip(pl=pl, interface='teredo'), None) self.assertEqual(self.module.internal_ip(pl=pl, ipv=4), '192.168.100.200') self.assertEqual(self.module.internal_ip(pl=pl, interface='auto', ipv=4), '192.168.100.200') self.assertEqual(self.module.internal_ip(pl=pl, interface='lo', ipv=4), '127.0.0.1') self.assertEqual(self.module.internal_ip(pl=pl, interface='teredo', ipv=4), None) self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0') self.assertEqual(self.module.internal_ip(pl=pl, interface='auto', ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0') self.assertEqual(self.module.internal_ip(pl=pl, interface='lo', ipv=6), '::1') self.assertEqual(self.module.internal_ip(pl=pl, interface='teredo', ipv=6), 'feff::5446:5eff:fe5a:7777') interfaces[1:2] = () self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), 'feff::5446:5eff:fe5a:7777') interfaces[1:2] = () self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), '::1') interfaces[:] = () self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), None) gateways = { 'default': { netifaces.AF_INET: ('192.168.100.1', 'enp2s0'), netifaces.AF_INET6: ('feff::5446:5eff:fe5a:0001', 'enp2s0') } } with replace_module_module( self.module, 'netifaces', interfaces=(lambda: interfaces), ifaddresses=(lambda interface: addr[interface]), gateways=(lambda: gateways), AF_INET=netifaces.AF_INET, AF_INET6=netifaces.AF_INET6, ): # default gateway has specified address family self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), '192.168.100.200') self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0') # default gateway doesn't have specified address family gateways['default'] = {} self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), None) self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), None) # TODO: fix network load #def test_network_load(self): # def gb(interface): # return None # # f = [gb] # # def _get_bytes(interface): # return f[0](interface) # # pl = Pl() # # with replace_attr(self.module, '_get_bytes', _get_bytes): # self.module.network_load.startup(pl=pl) # try: # self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), None) # sleep(self.module.network_load.interval) # self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), None) # while 'prev' not in self.module.network_load.interfaces.get('eth0', {}): # sleep(0.1) # self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), None) # # l = [0, 0] # # def gb2(interface): # l[0] += 1200 # l[1] += 2400 # return tuple(l) # f[0] = gb2 # # while not self.module.network_load.interfaces.get('eth0', {}).get('prev', (None, None))[1]: # sleep(0.1) # self.assertEqual(self.module.network_load(pl=pl, interface='eth0'), [ # {'divider_highlight_group': 'network_load:divider', 'contents': 'DL 1 KiB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, # {'divider_highlight_group': 'network_load:divider', 'contents': 'UL 2 KiB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, # ]) # self.assertEqual(self.module.network_load(pl=pl, interface='eth0', recv_format='r {value}', sent_format='s {value}'), [ # {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 KiB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, # {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 KiB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, # ]) # self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', suffix='bps', interface='eth0'), [ # {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 Kibps', 'highlight_groups': ['network_load_recv', 'network_load']}, # {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 Kibps', 'highlight_groups': ['network_load_sent', 'network_load']}, # ]) # self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', si_prefix=True, interface='eth0'), [ # {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 kB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, # {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 kB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, # ]) # self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', recv_max=0, interface='eth0'), [ # {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 KiB/s', 'highlight_groups': ['network_load_recv_gradient', 'network_load_gradient', 'network_load_recv', 'network_load'], 'gradient_level': 100}, # {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 KiB/s', 'highlight_groups': ['network_load_sent', 'network_load']}, # ]) # # class ApproxEqual(object): # def __eq__(self, i): # return abs(i - 50.0) < 1 # # self.assertEqual(self.module.network_load(pl=pl, recv_format='r {value}', sent_format='s {value}', sent_max=4800, interface='eth0'), [ # {'divider_highlight_group': 'network_load:divider', 'contents': 'r 1 KiB/s', 'highlight_groups': ['network_load_recv', 'network_load']}, # {'divider_highlight_group': 'network_load:divider', 'contents': 's 2 KiB/s', 'highlight_groups': ['network_load_sent_gradient', 'network_load_gradient', 'network_load_sent', 'network_load'], 'gradient_level': ApproxEqual()}, # ]) # finally: # self.module.network_load.shutdown() class TestEnv(TestCommon): module_name = 'env' def test_user(self): new_os = new_module('os', getpid=lambda: 1) class Process(object): def __init__(self, pid): pass def username(self): return 'def@DOMAIN.COM' if hasattr(self.module, 'psutil') and not callable(self.module.psutil.Process.username): username = property(username) segment_info = {'environ': {}} def user(*args, **kwargs): return self.module.user(pl=pl, segment_info=segment_info, *args, **kwargs) struct_passwd = namedtuple('struct_passwd', ('pw_name',)) new_psutil = new_module('psutil', Process=Process) new_pwd = new_module('pwd', getpwuid=lambda uid: struct_passwd(pw_name='def@DOMAIN.COM')) new_getpass = new_module('getpass', getuser=lambda: 'def@DOMAIN.COM') pl = Pl() with replace_attr(self.module, 'pwd', new_pwd): with replace_attr(self.module, 'getpass', new_getpass): with replace_attr(self.module, 'os', new_os): with replace_attr(self.module, 'psutil', new_psutil): with replace_attr(self.module, '_geteuid', lambda: 5): self.assertEqual(user(), [ {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} ]) self.assertEqual(user(hide_user='abc'), [ {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} ]) self.assertEqual(user(hide_domain=False), [ {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} ]) self.assertEqual(user(hide_user='def@DOMAIN.COM'), None) self.assertEqual(user(hide_domain=True), [ {'contents': 'def', 'highlight_groups': ['user']} ]) with replace_attr(self.module, '_geteuid', lambda: 0): self.assertEqual(user(), [ {'contents': 'def', 'highlight_groups': ['superuser', 'user']} ]) def test_cwd(self): new_os = new_module('os', path=os.path, sep='/') pl = Pl() cwd = [None] def getcwd(): wd = cwd[0] if isinstance(wd, Exception): raise wd else: return wd segment_info = {'getcwd': getcwd, 'home': None} with replace_attr(self.module, 'os', new_os): cwd[0] = '/abc/def/ghi/foo/bar' self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'abc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'def', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) segment_info['home'] = '/abc/def/ghi' self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info), [ {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3), [ {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=3, shorten_home=False), [ {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'ghi', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'foo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1), [ {'contents': '...', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis='---'), [ {'contents': '---', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, ellipsis=None), [ {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True), [ {'contents': '.../', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis='---'), [ {'contents': '---/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=1, use_path_separator=True, ellipsis=None), [ {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ {'contents': '~', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'fo', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2, use_path_separator=True), [ {'contents': '~/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'fo/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'bar', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']} ]) cwd[0] = '/etc' self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True}, {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False}, {'contents': 'etc', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) cwd[0] = '/' self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=False), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': True, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, use_path_separator=True), [ {'contents': '/', 'divider_highlight_group': 'cwd:divider', 'draw_inner_divider': False, 'highlight_groups': ['cwd:current_folder', 'cwd']}, ]) ose = OSError() ose.errno = 2 cwd[0] = ose self.assertEqual(self.module.cwd(pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2), [ {'contents': '[not found]', 'divider_highlight_group': 'cwd:divider', 'highlight_groups': ['cwd:current_folder', 'cwd'], 'draw_inner_divider': True} ]) cwd[0] = OSError() self.assertRaises(OSError, self.module.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) cwd[0] = ValueError() self.assertRaises(ValueError, self.module.cwd, pl=pl, segment_info=segment_info, dir_limit_depth=2, dir_shorten_len=2) def test_virtualenv(self): pl = Pl() with replace_env('VIRTUAL_ENV', '/abc/def/ghi') as segment_info: self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignored_names=["aaa"]), "ghi") self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignored_names=["ghi"]), "def") self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignored_names=["def", "ghi"]), "abc") self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignored_names=["abc", "def", "ghi"]), None) segment_info['environ'].pop('VIRTUAL_ENV') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) with replace_env('CONDA_DEFAULT_ENV', 'foo') as segment_info: self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'foo') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignored_names=["foo"]), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), 'foo') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) segment_info['environ'].pop('CONDA_DEFAULT_ENV') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) with replace_env('CONDA_DEFAULT_ENV', 'foo', environ={'VIRTUAL_ENV': '/sbc/def/ghi'}) as segment_info: self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), 'foo') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) segment_info['environ'].pop('CONDA_DEFAULT_ENV') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None) with replace_env('VIRTUAL_ENV', '/abc/def/venv') as segment_info: self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'def') def test_environment(self): pl = Pl() variable = 'FOO' value = 'bar' with replace_env(variable, value) as segment_info: self.assertEqual(self.module.environment(pl=pl, segment_info=segment_info, variable=variable), value) segment_info['environ'].pop(variable) self.assertEqual(self.module.environment(pl=pl, segment_info=segment_info, variable=variable), None) class TestVcs(TestCommon): module_name = 'vcs' def test_branch(self): pl = Pl() create_watcher = get_fallback_create_watcher() segment_info = {'getcwd': os.getcwd} branch = partial(self.module.branch, pl=pl, create_watcher=create_watcher) with replace_attr(self.module, 'guess', get_dummy_guess(status=lambda: None, directory='/tmp/tests')): with replace_attr(self.module, 'tree_status', lambda repo, pl: None): self.assertEqual(branch(segment_info=segment_info, status_colors=False), [{ 'highlight_groups': ['branch'], 'contents': 'tests', 'divider_highlight_group': None }]) self.assertEqual(branch(segment_info=segment_info, status_colors=True), [{ 'contents': 'tests', 'highlight_groups': ['branch_clean', 'branch'], 'divider_highlight_group': None }]) with replace_attr(self.module, 'guess', get_dummy_guess(status=lambda: 'D ', directory='/tmp/tests')): with replace_attr(self.module, 'tree_status', lambda repo, pl: 'D '): self.assertEqual(branch(segment_info=segment_info, status_colors=False), [{ 'highlight_groups': ['branch'], 'contents': 'tests', 'divider_highlight_group': None }]) self.assertEqual(branch(segment_info=segment_info, status_colors=True), [{ 'contents': 'tests', 'highlight_groups': ['branch_dirty', 'branch'], 'divider_highlight_group': None }]) self.assertEqual(branch(segment_info=segment_info, status_colors=False), [{ 'highlight_groups': ['branch'], 'contents': 'tests', 'divider_highlight_group': None }]) with replace_attr(self.module, 'guess', lambda path, create_watcher: None): self.assertEqual(branch(segment_info=segment_info, status_colors=False), None) with replace_attr(self.module, 'guess', get_dummy_guess(status=lambda: 'U')): with replace_attr(self.module, 'tree_status', lambda repo, pl: 'U'): self.assertEqual(branch(segment_info=segment_info, status_colors=False, ignore_statuses=['U']), [{ 'highlight_groups': ['branch'], 'contents': 'tests', 'divider_highlight_group': None }]) self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['DU']), [{ 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'tests', 'divider_highlight_group': None }]) self.assertEqual(branch(segment_info=segment_info, status_colors=True), [{ 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'tests', 'divider_highlight_group': None }]) self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['U']), [{ 'highlight_groups': ['branch_clean', 'branch'], 'contents': 'tests', 'divider_highlight_group': None }]) def test_stash(self): pl = Pl() create_watcher = get_fallback_create_watcher() stash = partial(self.module.stash, pl=pl, create_watcher=create_watcher, segment_info={'getcwd': os.getcwd}) def forge_stash(n): return replace_attr(self.module, 'guess', get_dummy_guess(stash=lambda: n, directory='/tmp/tests')) with forge_stash(0): self.assertEqual(stash(), None) with forge_stash(1): self.assertEqual(stash(), [{ 'highlight_groups': ['stash'], 'contents': '1', 'divider_highlight_group': None }]) with forge_stash(2): self.assertEqual(stash(), [{ 'highlight_groups': ['stash'], 'contents': '2', 'divider_highlight_group': None }]) class TestTime(TestCommon): module_name = 'time' def test_date(self): pl = Pl() with replace_attr(self.module, 'datetime', Args(strptime=lambda timezone, fmt: Args(tzinfo=timezone), now=lambda tz:Args(strftime=lambda fmt: fmt + (tz if tz else '')))): self.assertEqual(self.module.date(pl=pl), [{'contents': '%Y-%m-%d', 'highlight_groups': ['date'], 'divider_highlight_group': None}]) self.assertEqual(self.module.date(pl=pl, timezone='+0900'), [{'contents': '%Y-%m-%d+0900', 'highlight_groups': ['date'], 'divider_highlight_group': None}]) self.assertEqual(self.module.date(pl=pl, format='%H:%M', istime=True), [{'contents': '%H:%M', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}]) self.assertEqual(self.module.date(pl=pl, format='%H:%M', istime=True, timezone='-0900'), [{'contents': '%H:%M-0900', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}]) unicode_date = self.module.date(pl=pl, format='\u231a', istime=True) expected_unicode_date = [{'contents': '\u231a', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}] if python_implementation() == 'PyPy' and sys.version_info >= (3,): if unicode_date != expected_unicode_date: raise SkipTest('Dates do not match, see https://bitbucket.org/pypy/pypy/issues/2161/pypy3-strftime-does-not-accept-unicode') self.assertEqual(unicode_date, expected_unicode_date) def test_fuzzy_time(self): time = Args(hour=0, minute=45) pl = Pl() hour_str = ['12', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven'] minute_str = {'0': '{hour_str} o\'clock', '5': 'five past {hour_str}', '10': 'ten past {hour_str}', '15': 'quarter past {hour_str}', '20': 'twenty past {hour_str}', '25': 'twenty-five past {hour_str}', '30': 'half past {hour_str}', '35': 'twenty-five to {hour_str}', '40': 'twenty to {hour_str}', '45': 'quarter to {hour_str}', '50': 'ten to {hour_str}', '55': 'five to {hour_str}'} special_case_str = { '(23, 58)': '~ midnight', '(23, 59)': '~ midnight', '(0, 0)': 'midnight', '(0, 1)': '~ midnight', '(0, 2)': '~ midnight'} with replace_attr(self.module, 'datetime', Args(strptime=lambda timezone, fmt: Args(tzinfo=timezone), now=lambda tz: time)): self.assertEqual(self.module.fuzzy_time(pl=pl, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str), 'quarter to one') self.assertEqual(self.module.fuzzy_time(pl=pl), 'quarter to one') time.hour = 23 time.minute = 59 self.assertEqual(self.module.fuzzy_time(pl=pl, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str), '~ midnight') self.assertEqual(self.module.fuzzy_time(pl=pl), 'round about midnight') time.hour = 11 time.minute = 33 self.assertEqual(self.module.fuzzy_time(pl=pl, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str),'twenty-five to 12') self.assertEqual(self.module.fuzzy_time(pl=pl), 'twenty-five to twelve') time.hour = 12 time.minute = 0 self.assertEqual(self.module.fuzzy_time(pl=pl, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str), '12 o\'clock') self.assertEqual(self.module.fuzzy_time(pl=pl), 'noon') time.hour = 11 time.minute = 33 self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=False, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str), 'twenty-five to 12') self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=False), 'twenty-five to twelve') time.hour = 12 time.minute = 0 self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=False, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str), '12 o\'clock') self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=False), 'noon') time.hour = 11 time.minute = 33 self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=True, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str), 'twenty‐five to 12') self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=True), 'twenty‐five to twelve') time.hour = 12 time.minute = 0 self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=True, hour_str=hour_str, minute_str=minute_str, special_case_str=special_case_str), '12 o’clock') self.assertEqual(self.module.fuzzy_time(pl=pl, unicode_text=True),'noon') class TestSys(TestCommon): module_name = 'sys' def test_uptime(self): pl = Pl() with replace_attr(self.module, '_get_uptime', lambda: 259200): self.assertEqual(self.module.uptime(pl=pl), [{'contents': '3d 0h 00m', 'divider_highlight_group': 'background:divider'}]) with replace_attr(self.module, '_get_uptime', lambda: 93784): self.assertEqual(self.module.uptime(pl=pl), [{'contents': '1d 2h 03m', 'divider_highlight_group': 'background:divider'}]) self.assertEqual(self.module.uptime(pl=pl, shorten_len=4), [{'contents': '1d 2h 03m 04s', 'divider_highlight_group': 'background:divider'}]) with replace_attr(self.module, '_get_uptime', lambda: 65536): self.assertEqual(self.module.uptime(pl=pl), [{'contents': '18h 12m 16s', 'divider_highlight_group': 'background:divider'}]) self.assertEqual(self.module.uptime(pl=pl, shorten_len=2), [{'contents': '18h 12m', 'divider_highlight_group': 'background:divider'}]) self.assertEqual(self.module.uptime(pl=pl, shorten_len=1), [{'contents': '18h', 'divider_highlight_group': 'background:divider'}]) def _get_uptime(): raise NotImplementedError with replace_attr(self.module, '_get_uptime', _get_uptime): self.assertEqual(self.module.uptime(pl=pl), None) def test_system_load(self): pl = Pl() with replace_module_module(self.module, 'os', getloadavg=lambda: (7.5, 3.5, 1.5)): with replace_attr(self.module, '_cpu_count', lambda: 2): self.assertEqual(self.module.system_load(pl=pl), [ {'contents': '7.5 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, {'contents': '3.5 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 75.0}, {'contents': '1.5', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 0} ]) self.assertEqual(self.module.system_load(pl=pl, format='{avg:.0f}', threshold_good=0, threshold_bad=1), [ {'contents': '8 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, {'contents': '4 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, {'contents': '2', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 75.0} ]) self.assertEqual(self.module.system_load(pl=pl, short=True), [ {'contents': '7.5', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, ]) self.assertEqual(self.module.system_load(pl=pl, format='{avg:.0f}', threshold_good=0, threshold_bad=1, short=True), [ {'contents': '8', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100}, ]) def test_cpu_load_percent(self): try: __import__('psutil') except ImportError as e: raise SkipTest('Failed to import psutil: {0}'.format(e)) pl = Pl() with replace_module_module(self.module, 'psutil', cpu_percent=lambda **kwargs: 52.3): self.assertEqual(self.module.cpu_load_percent(pl=pl), [{ 'contents': '52%', 'gradient_level': 52.3, 'highlight_groups': ['cpu_load_percent_gradient', 'cpu_load_percent'], }]) self.assertEqual(self.module.cpu_load_percent(pl=pl, format='{0:.1f}%'), [{ 'contents': '52.3%', 'gradient_level': 52.3, 'highlight_groups': ['cpu_load_percent_gradient', 'cpu_load_percent'], }]) class TestWthr(TestCommon): module_name = 'wthr' def test_weather(self): pl = Pl() with replace_attr(self.module, 'urllib_read', urllib_read): self.assertEqual(self.module.weather(pl=pl), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '20°C', 'gradient_level': 71.42857142857143} ]) self.assertEqual(self.module.weather(pl=pl, temp_coldest=0, temp_hottest=100), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '20°C', 'gradient_level': 20} ]) self.assertEqual(self.module.weather(pl=pl, temp_coldest=-100, temp_hottest=-50), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '20°C', 'gradient_level': 100} ]) self.assertEqual(self.module.weather(pl=pl, icons={'sunny': 'o'}), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'o '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '20°C', 'gradient_level': 71.42857142857143} ]) # Test is disabled as no request has more than 1 weather condition associated currently # self.assertEqual(self.module.weather(pl=pl, icons={'windy': 'x'}), [ # {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'x '}, # {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854} # ]) self.assertEqual(self.module.weather(pl=pl, unit='F'), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '68°F', 'gradient_level': 100} ]) self.assertEqual(self.module.weather(pl=pl, unit='K'), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '293K', 'gradient_level': 100} ]) self.assertEqual(self.module.weather(pl=pl, temp_format='{temp:.1e}C'), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '2.0e+01C', 'gradient_level': 71.42857142857143} ]) with replace_attr(self.module, 'urllib_read', urllib_read): self.module.weather.startup(pl=pl, location_query='Meppen,06,DE') self.assertEqual(self.module.weather(pl=pl), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '20°C', 'gradient_level': 71.42857142857143} ]) self.assertEqual(self.module.weather(pl=pl, location_query='Moscow,RU'), [ {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_sunny', 'weather_conditions', 'weather'], 'contents': 'SUN '}, {'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '10°C', 'gradient_level': 57.142857142857146} ]) self.module.weather.shutdown() class TestI3WM(TestCase): def test_workspaces(self): class Conn(object): def get_tree(self): return self def descendents(self): nodes_unfocused = [Args(focused = False)] nodes_focused = [Args(focused = True)] workspace_scratch = lambda: Args(name='__i3_scratch') workspace_noscratch = lambda: Args(name='2: w2') return [ Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), Args(scratchpad_state='changed', urgent=True, workspace=workspace_noscratch, nodes=nodes_focused), Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), Args(scratchpad_state=None, urgent=False, workspace=workspace_noscratch, nodes=nodes_unfocused), Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_focused), Args(scratchpad_state=None, urgent=True, workspace=workspace_noscratch, nodes=nodes_unfocused), ] def workspaces(self): return iter([ Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []), Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []), Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []), Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: []) ]) def get_workspaces(self): return iter([ Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []), Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []), Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []), Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: []) ]) def get_outputs(self): return iter([ Args(name='LVDS1', active=True), Args(name='HDMI1', active=True), Args(name='DVI01', active=True), Args(name='HDMI2', active=False), ]) pl = Pl() with replace_attr(i3wm, 'get_i3_connection', lambda: Conn()): segment_info = {} self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info), [ {'contents': '1: w1', 'highlight_groups': ['workspace']}, {'contents': '2: w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']}, {'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, {'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=None), [ {'contents': '1: w1', 'highlight_groups': ['workspace']}, {'contents': '2: w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']}, {'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, {'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent']), [ {'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, {'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible']), [ {'contents': '2: w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']}, {'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, {'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [ {'contents': 'w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']}, {'contents': 'w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, {'contents': 'w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent'], output='DVI01'), [ {'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [ {'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3, output='LVDS1'), [ {'contents': 'w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']}, ]) segment_info['output'] = 'LVDS1' self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [ {'contents': '3: w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [ {'contents': 'w2', 'highlight_groups': ['workspace:visible', 'w_visible', 'workspace']}, ]) def test_workspace(self): class Conn(object): def get_tree(self): return self def descendents(self): nodes_unfocused = [Args(focused = False)] nodes_focused = [Args(focused = True)] workspace_scratch = lambda: Args(name='__i3_scratch') workspace_noscratch = lambda: Args(name='2: w2') return [ Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), Args(scratchpad_state='changed', urgent=True, workspace=workspace_noscratch, nodes=nodes_focused), Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), Args(scratchpad_state=None, urgent=False, workspace=workspace_noscratch, nodes=nodes_unfocused), Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_focused), Args(scratchpad_state=None, urgent=True, workspace=workspace_noscratch, nodes=nodes_unfocused), ] def workspaces(self): return iter([ Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []), Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []), Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []), Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: []) ]) def get_workspaces(self): return iter([ Args(name='1: w1', output='LVDS1', focused=False, urgent=False, visible=False, num=1, leaves=lambda: []), Args(name='2: w2', output='LVDS1', focused=False, urgent=False, visible=True, num=2, leaves=lambda: []), Args(name='3: w3', output='HDMI1', focused=False, urgent=True, visible=True, num=3, leaves=lambda: []), Args(name='4: w4', output='DVI01', focused=True, urgent=True, visible=True, num=None, leaves=lambda: []) ]) def get_outputs(self): return iter([ Args(name='LVDS1', active=True), Args(name='HDMI1', active=True), Args(name='DVI01', active=True), Args(name='HDMI2', active=False), ]) pl = Pl() with replace_attr(i3wm, 'get_i3_connection', lambda: Conn()): segment_info = {} self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='1: w1'), [ {'contents': '1: w1', 'highlight_groups': ['workspace']}, ]) self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='3: w3', strip=True), [ {'contents': 'w3', 'highlight_groups': ['workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='9: w9'), None) self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info), [ {'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) segment_info['workspace'] = next(Conn().get_workspaces()) self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='4: w4'), [ {'contents': '4: w4', 'highlight_groups': ['workspace:focused', 'w_focused', 'workspace:urgent', 'w_urgent', 'workspace:visible', 'w_visible', 'workspace']}, ]) self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, strip=True), [ {'contents': 'w1', 'highlight_groups': ['workspace']}, ]) def test_mode(self): pl = Pl() self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'default'}), None) self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'test'}), 'test') self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'default'}, names={'default': 'test'}), 'test') self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'test'}, names={'default': 'test', 'test': 't'}), 't') def test_scratchpad(self): class Conn(object): def get_tree(self): return self def descendants(self): nodes_unfocused = [Args(focused = False)] nodes_focused = [Args(focused = True)] workspace_scratch = lambda: Args(name='__i3_scratch') workspace_noscratch = lambda: Args(name='2: www') return [ Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), Args(scratchpad_state='changed', urgent=True, workspace=workspace_noscratch, nodes=nodes_focused), Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused), Args(scratchpad_state=None, urgent=False, workspace=workspace_noscratch, nodes=nodes_unfocused), Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_focused), Args(scratchpad_state=None, urgent=True, workspace=workspace_noscratch, nodes=nodes_unfocused), ] pl = Pl() with replace_attr(i3wm, 'get_i3_connection', lambda: Conn()): self.assertEqual(i3wm.scratchpad(pl=pl), [ {'contents': 'O', 'highlight_groups': ['scratchpad']}, {'contents': 'X', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:focused', 'scratchpad:visible', 'scratchpad']}, {'contents': 'O', 'highlight_groups': ['scratchpad']}, {'contents': 'X', 'highlight_groups': ['scratchpad:visible', 'scratchpad']}, {'contents': 'O', 'highlight_groups': ['scratchpad:focused', 'scratchpad']}, {'contents': 'X', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:visible', 'scratchpad']}, ]) self.assertEqual(i3wm.scratchpad(pl=pl, icons={'changed': '-', 'fresh': 'o'}), [ {'contents': 'o', 'highlight_groups': ['scratchpad']}, {'contents': '-', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:focused', 'scratchpad:visible', 'scratchpad']}, {'contents': 'o', 'highlight_groups': ['scratchpad']}, {'contents': '-', 'highlight_groups': ['scratchpad:visible', 'scratchpad']}, {'contents': 'o', 'highlight_groups': ['scratchpad:focused', 'scratchpad']}, {'contents': '-', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:visible', 'scratchpad']}, ]) class TestMail(TestCommon): module_name = 'mail' def test_email_imap_alert(self): # TODO pass class TestPlayers(TestCommon): module_name = 'players' def test_now_playing(self): # TODO pass class TestBat(TestCommon): module_name = 'bat' def test_battery(self): pl = Pl() def _get_battery_status(pl): return 86, False with replace_attr(self.module, '_get_battery_status', _get_battery_status): self.assertEqual(self.module.battery(pl=pl), [{ 'contents': ' 86%', 'highlight_groups': ['battery_gradient', 'battery'], 'gradient_level': 14, }]) self.assertEqual(self.module.battery(pl=pl, format='{capacity:.2f}'), [{ 'contents': '0.86', 'highlight_groups': ['battery_gradient', 'battery'], 'gradient_level': 14, }]) self.assertEqual(self.module.battery(pl=pl, steps=7), [{ 'contents': ' 86%', 'highlight_groups': ['battery_gradient', 'battery'], 'gradient_level': 14, }]) self.assertEqual(self.module.battery(pl=pl, gamify=True), [ { 'contents': ' ', 'draw_inner_divider': False, 'highlight_groups': ['battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'], 'gradient_level': 0 }, { 'contents': 'OOOO', 'draw_inner_divider': False, 'highlight_groups': ['battery_full', 'battery_gradient', 'battery'], 'gradient_level': 0 }, { 'contents': 'O', 'draw_inner_divider': False, 'highlight_groups': ['battery_empty', 'battery_gradient', 'battery'], 'gradient_level': 100 } ]) self.assertEqual(self.module.battery(pl=pl, gamify=True, full_heart='+', empty_heart='-', steps='10'), [ { 'contents': ' ', 'draw_inner_divider': False, 'highlight_groups': ['battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'], 'gradient_level': 0 }, { 'contents': '++++++++', 'draw_inner_divider': False, 'highlight_groups': ['battery_full', 'battery_gradient', 'battery'], 'gradient_level': 0 }, { 'contents': '--', 'draw_inner_divider': False, 'highlight_groups': ['battery_empty', 'battery_gradient', 'battery'], 'gradient_level': 100 } ]) def test_battery_with_ac_online(self): pl = Pl() def _get_battery_status(pl): return 86, True with replace_attr(self.module, '_get_battery_status', _get_battery_status): self.assertEqual(self.module.battery(pl=pl, online='C', offline=' '), [ { 'contents': 'C 86%', 'highlight_groups': ['battery_gradient', 'battery'], 'gradient_level': 14, }]) def test_battery_with_ac_offline(self): pl = Pl() def _get_battery_status(pl): return 86, False with replace_attr(self.module, '_get_battery_status', _get_battery_status): self.assertEqual(self.module.battery(pl=pl, online='C', offline=' '), [ { 'contents': ' 86%', 'highlight_groups': ['battery_gradient', 'battery'], 'gradient_level': 14, }]) class TestVim(TestCase): def test_mode(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'NORMAL') self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'i': 'INS'}), 'NORMAL') self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'n': 'NORM'}), 'NORM') with vim_module._with('mode', 'i') as segment_info: self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'INSERT') with vim_module._with('mode', 'i\0') as segment_info: self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'INSERT') with vim_module._with('mode', chr(ord('V') - 0x40)) as segment_info: self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'V-BLCK') self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'^V': 'VBLK'}), 'VBLK') def test_visual_range(self): pl = Pl() vr = partial(self.vim.visual_range, pl=pl) vim_module.current.window.cursor = [0, 0] try: with vim_module._with('mode', 'i') as segment_info: self.assertEqual(vr(segment_info=segment_info), '') with vim_module._with('mode', '^V') as segment_info: self.assertEqual(vr(segment_info=segment_info), '1 x 1') with vim_module._with('vpos', line=5, col=5, off=0): self.assertEqual(vr(segment_info=segment_info), '5 x 5') with vim_module._with('vpos', line=5, col=4, off=0): self.assertEqual(vr(segment_info=segment_info), '5 x 4') with vim_module._with('mode', '^S') as segment_info: self.assertEqual(vr(segment_info=segment_info), '1 x 1') with vim_module._with('vpos', line=5, col=5, off=0): self.assertEqual(vr(segment_info=segment_info), '5 x 5') with vim_module._with('vpos', line=5, col=4, off=0): self.assertEqual(vr(segment_info=segment_info), '5 x 4') with vim_module._with('mode', 'V') as segment_info: self.assertEqual(vr(segment_info=segment_info), 'L:1') with vim_module._with('vpos', line=5, col=5, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') with vim_module._with('vpos', line=5, col=4, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') with vim_module._with('mode', 'S') as segment_info: self.assertEqual(vr(segment_info=segment_info), 'L:1') with vim_module._with('vpos', line=5, col=5, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') with vim_module._with('vpos', line=5, col=4, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') with vim_module._with('mode', 'v') as segment_info: self.assertEqual(vr(segment_info=segment_info), 'C:1') with vim_module._with('vpos', line=5, col=5, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') with vim_module._with('vpos', line=5, col=4, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') with vim_module._with('mode', 's') as segment_info: self.assertEqual(vr(segment_info=segment_info), 'C:1') with vim_module._with('vpos', line=5, col=5, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') with vim_module._with('vpos', line=5, col=4, off=0): self.assertEqual(vr(segment_info=segment_info), 'L:5') finally: vim_module._close(1) def test_modified_indicator(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info), None) segment_info['buffer'][0] = 'abc' try: self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info), '+') self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info, text='-'), '-') finally: vim_module._bw(segment_info['bufnr']) def test_paste_indicator(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.paste_indicator(pl=pl, segment_info=segment_info), None) with vim_module._with('options', paste=1): self.assertEqual(self.vim.paste_indicator(pl=pl, segment_info=segment_info), 'PASTE') self.assertEqual(self.vim.paste_indicator(pl=pl, segment_info=segment_info, text='P'), 'P') def test_readonly_indicator(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.readonly_indicator(pl=pl, segment_info=segment_info), None) with vim_module._with('bufoptions', readonly=1): self.assertEqual(self.vim.readonly_indicator(pl=pl, segment_info=segment_info), 'RO') self.assertEqual(self.vim.readonly_indicator(pl=pl, segment_info=segment_info, text='L'), 'L') def test_file_scheme(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.file_scheme(pl=pl, segment_info=segment_info), None) with vim_module._with('buffer', '/tmp/’’/abc') as segment_info: self.assertEqual(self.vim.file_scheme(pl=pl, segment_info=segment_info), None) with vim_module._with('buffer', 'zipfile:/tmp/abc.zip::abc/abc.vim') as segment_info: self.assertEqual(self.vim.file_scheme(pl=pl, segment_info=segment_info), 'zipfile') def test_file_directory(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), None) with replace_env('HOME', '/home/foo', os.environ): with vim_module._with('buffer', '/tmp/’’/abc') as segment_info: self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/’’/') with vim_module._with('buffer', b'/tmp/\xFF\xFF/abc') as segment_info: self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp//') with vim_module._with('buffer', '/tmp/abc') as segment_info: self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/') os.environ['HOME'] = '/tmp' self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '~/') with vim_module._with('buffer', 'zipfile:/tmp/abc.zip::abc/abc.vim') as segment_info: self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=False), 'zipfile:/tmp/abc.zip::abc/') self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=True), '/tmp/abc.zip::abc/') self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/abc.zip::abc/') os.environ['HOME'] = '/tmp' self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=False), 'zipfile:/tmp/abc.zip::abc/') self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info, remove_scheme=True), '/tmp/abc.zip::abc/') self.assertEqual(self.vim.file_directory(pl=pl, segment_info=segment_info), '/tmp/abc.zip::abc/') def test_file_name(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), None) self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info, display_no_file=True), [ {'contents': '[No file]', 'highlight_groups': ['file_name_no_file', 'file_name']} ]) self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info, display_no_file=True, no_file_text='X'), [ {'contents': 'X', 'highlight_groups': ['file_name_no_file', 'file_name']} ]) with vim_module._with('buffer', '/tmp/abc') as segment_info: self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), 'abc') with vim_module._with('buffer', '/tmp/’’') as segment_info: self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), '’’') with vim_module._with('buffer', b'/tmp/\xFF\xFF') as segment_info: self.assertEqual(self.vim.file_name(pl=pl, segment_info=segment_info), '') def test_file_size(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B') with vim_module._with( 'buffer', os.path.join( os.path.dirname(os.path.dirname(__file__)), 'empty') ) as segment_info: self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B') def test_file_opts(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.file_format(pl=pl, segment_info=segment_info), [ {'divider_highlight_group': 'background:divider', 'contents': 'unix'} ]) self.assertEqual(self.vim.file_encoding(pl=pl, segment_info=segment_info), [ {'divider_highlight_group': 'background:divider', 'contents': 'utf-8'} ]) self.assertEqual(self.vim.file_type(pl=pl, segment_info=segment_info), None) with vim_module._with('bufoptions', filetype='python'): self.assertEqual(self.vim.file_type(pl=pl, segment_info=segment_info), [ {'divider_highlight_group': 'background:divider', 'contents': 'python'} ]) def test_window_title(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.window_title(pl=pl, segment_info=segment_info), None) with vim_module._with('wvars', quickfix_title='Abc'): self.assertEqual(self.vim.window_title(pl=pl, segment_info=segment_info), 'Abc') def test_line_percent(self): pl = Pl() segment_info = vim_module._get_segment_info() segment_info['buffer'][0:-1] = [str(i) for i in range(100)] try: self.assertEqual(self.vim.line_percent(pl=pl, segment_info=segment_info), '1') vim_module._set_cursor(50, 0) self.assertEqual(self.vim.line_percent(pl=pl, segment_info=segment_info), '50') self.assertEqual(self.vim.line_percent(pl=pl, segment_info=segment_info, gradient=True), [ {'contents': '50', 'highlight_groups': ['line_percent_gradient', 'line_percent'], 'gradient_level': 50 * 100.0 / 101} ]) finally: vim_module._bw(segment_info['bufnr']) def test_line_count(self): pl = Pl() segment_info = vim_module._get_segment_info() segment_info['buffer'][0:-1] = [str(i) for i in range(99)] try: self.assertEqual(self.vim.line_count(pl=pl, segment_info=segment_info), '100') vim_module._set_cursor(50, 0) self.assertEqual(self.vim.line_count(pl=pl, segment_info=segment_info), '100') finally: vim_module._bw(segment_info['bufnr']) def test_position(self): pl = Pl() segment_info = vim_module._get_segment_info() try: segment_info['buffer'][0:-1] = [str(i) for i in range(99)] vim_module._set_cursor(49, 0) self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info), '50%') self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, gradient=True), [ {'contents': '50%', 'highlight_groups': ['position_gradient', 'position'], 'gradient_level': 50.0} ]) vim_module._set_cursor(0, 0) self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info), 'Top') vim_module._set_cursor(97, 0) self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, position_strings={'top': 'Comienzo', 'bottom': 'Final', 'all': 'Todo'}), 'Final') segment_info['buffer'][0:-1] = [str(i) for i in range(2)] vim_module._set_cursor(0, 0) self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, position_strings={'top': 'Comienzo', 'bottom': 'Final', 'all': 'Todo'}), 'Todo') self.assertEqual(self.vim.position(pl=pl, segment_info=segment_info, gradient=True), [ {'contents': 'All', 'highlight_groups': ['position_gradient', 'position'], 'gradient_level': 0.0} ]) finally: vim_module._bw(segment_info['bufnr']) def test_cursor_current(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.line_current(pl=pl, segment_info=segment_info), '1') self.assertEqual(self.vim.col_current(pl=pl, segment_info=segment_info), '1') self.assertEqual(self.vim.virtcol_current(pl=pl, segment_info=segment_info), [{ 'highlight_groups': ['virtcol_current_gradient', 'virtcol_current', 'col_current'], 'contents': '1', 'gradient_level': 100.0 / 80, }]) self.assertEqual(self.vim.virtcol_current(pl=pl, segment_info=segment_info, gradient=False), [{ 'highlight_groups': ['virtcol_current', 'col_current'], 'contents': '1', }]) def test_modified_buffers(self): pl = Pl() self.assertEqual(self.vim.modified_buffers(pl=pl), None) def test_branch(self): pl = Pl() create_watcher = get_fallback_create_watcher() branch = partial(self.vim.branch, pl=pl, create_watcher=create_watcher) with vim_module._with('buffer', '/foo') as segment_info: with replace_attr(self.vcs, 'guess', get_dummy_guess(status=lambda: None)): with replace_attr(self.vcs, 'tree_status', lambda repo, pl: None): self.assertEqual(branch(segment_info=segment_info, status_colors=False), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch'], 'contents': 'foo'} ]) self.assertEqual(branch(segment_info=segment_info, status_colors=True), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_clean', 'branch'], 'contents': 'foo'} ]) with replace_attr(self.vcs, 'guess', get_dummy_guess(status=lambda: 'DU')): with replace_attr(self.vcs, 'tree_status', lambda repo, pl: 'DU'): self.assertEqual(branch(segment_info=segment_info, status_colors=False), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch'], 'contents': 'foo'} ]) self.assertEqual(branch(segment_info=segment_info, status_colors=True), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'foo'} ]) with replace_attr(self.vcs, 'guess', get_dummy_guess(status=lambda: 'U')): with replace_attr(self.vcs, 'tree_status', lambda repo, pl: 'U'): self.assertEqual(branch(segment_info=segment_info, status_colors=False, ignore_statuses=['U']), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch'], 'contents': 'foo'} ]) self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['DU']), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'foo'} ]) self.assertEqual(branch(segment_info=segment_info, status_colors=True), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_dirty', 'branch'], 'contents': 'foo'} ]) self.assertEqual(branch(segment_info=segment_info, status_colors=True, ignore_statuses=['U']), [ {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_clean', 'branch'], 'contents': 'foo'} ]) def test_stash(self): pl = Pl() create_watcher = get_fallback_create_watcher() with vim_module._with('buffer', '/foo') as segment_info: stash = partial(self.vim.stash, pl=pl, create_watcher=create_watcher, segment_info=segment_info) def forge_stash(n): return replace_attr(self.vcs, 'guess', get_dummy_guess(stash=lambda: n)) with forge_stash(0): self.assertEqual(stash(), None) with forge_stash(1): self.assertEqual(stash(), [{ 'divider_highlight_group': 'stash:divider', 'highlight_groups': ['stash'], 'contents': '1' }]) with forge_stash(2): self.assertEqual(stash(), [{ 'divider_highlight_group': 'stash:divider', 'highlight_groups': ['stash'], 'contents': '2' }]) def test_file_vcs_status(self): pl = Pl() create_watcher = get_fallback_create_watcher() file_vcs_status = partial(self.vim.file_vcs_status, pl=pl, create_watcher=create_watcher) with vim_module._with('buffer', '/foo') as segment_info: with replace_attr(self.vim, 'guess', get_dummy_guess(status=lambda file: 'M')): self.assertEqual(file_vcs_status(segment_info=segment_info), [ {'highlight_groups': ['file_vcs_status_M', 'file_vcs_status'], 'contents': 'M'} ]) with replace_attr(self.vim, 'guess', get_dummy_guess(status=lambda file: None)): self.assertEqual(file_vcs_status(segment_info=segment_info), None) with vim_module._with('buffer', '/bar') as segment_info: with vim_module._with('bufoptions', buftype='nofile'): with replace_attr(self.vim, 'guess', get_dummy_guess(status=lambda file: 'M')): self.assertEqual(file_vcs_status(segment_info=segment_info), None) def test_trailing_whitespace(self): pl = Pl() with vim_module._with('buffer', 'tws') as segment_info: trailing_whitespace = partial(self.vim.trailing_whitespace, pl=pl, segment_info=segment_info) self.assertEqual(trailing_whitespace(), None) self.assertEqual(trailing_whitespace(), None) vim_module.current.buffer[0] = ' ' self.assertEqual(trailing_whitespace(), [{ 'highlight_groups': ['trailing_whitespace', 'warning'], 'contents': '1', }]) self.assertEqual(trailing_whitespace(), [{ 'highlight_groups': ['trailing_whitespace', 'warning'], 'contents': '1', }]) vim_module.current.buffer[0] = '' self.assertEqual(trailing_whitespace(), None) self.assertEqual(trailing_whitespace(), None) def test_tabnr(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.tabnr(pl=pl, segment_info=segment_info, show_current=True), '1') self.assertEqual(self.vim.tabnr(pl=pl, segment_info=segment_info, show_current=False), None) def test_tab(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.tab(pl=pl, segment_info=segment_info), [{ 'contents': None, 'literal_contents': (0, '%1T'), }]) self.assertEqual(self.vim.tab(pl=pl, segment_info=segment_info, end=True), [{ 'contents': None, 'literal_contents': (0, '%T'), }]) def test_bufnr(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.bufnr(pl=pl, segment_info=segment_info, show_current=True), str(segment_info['bufnr'])) self.assertEqual(self.vim.bufnr(pl=pl, segment_info=segment_info, show_current=False), None) def test_winnr(self): pl = Pl() segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.winnr(pl=pl, segment_info=segment_info, show_current=True), str(segment_info['winnr'])) self.assertEqual(self.vim.winnr(pl=pl, segment_info=segment_info, show_current=False), None) def test_segment_info(self): pl = Pl() with vim_module._with('tabpage'): with vim_module._with('buffer', '1') as segment_info: self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None) vim_module.current.buffer[0] = ' ' self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), [{ 'contents': '+', 'highlight_groups': ['tab_modified_indicator', 'modified_indicator'], }]) vim_module._undo() self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None) old_buffer = vim_module.current.buffer vim_module._new('2') segment_info = vim_module._get_segment_info() self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None) old_buffer[0] = ' ' self.assertEqual(self.vim.modified_indicator(pl=pl, segment_info=segment_info), None) self.assertEqual(self.vim.tab_modified_indicator(pl=pl, segment_info=segment_info), [{ 'contents': '+', 'highlight_groups': ['tab_modified_indicator', 'modified_indicator'], }]) def test_csv_col_current(self): pl = Pl() segment_info = vim_module._get_segment_info() def csv_col_current(**kwargs): self.vim.csv_cache and self.vim.csv_cache.clear() return self.vim.csv_col_current(pl=pl, segment_info=segment_info, **kwargs) buffer = segment_info['buffer'] try: self.assertEqual(csv_col_current(), None) buffer.options['filetype'] = 'csv' self.assertEqual(csv_col_current(), None) buffer[:] = ['1;2;3', '4;5;6'] vim_module._set_cursor(1, 1) self.assertEqual(csv_col_current(), [{ 'contents': '1', 'highlight_groups': ['csv:column_number', 'csv'] }]) vim_module._set_cursor(2, 3) self.assertEqual(csv_col_current(), [{ 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] }]) vim_module._set_cursor(2, 3) self.assertEqual(csv_col_current(display_name=True), [{ 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] }, { 'contents': ' (2)', 'highlight_groups': ['csv:column_name', 'csv'] }]) buffer[:0] = ['Foo;Bar;Baz'] vim_module._set_cursor(2, 3) self.assertEqual(csv_col_current(), [{ 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] }, { 'contents': ' (Bar)', 'highlight_groups': ['csv:column_name', 'csv'] }]) if sys.version_info < (2, 7): raise SkipTest('csv module in Python-2.6 does not handle multiline csv files well') buffer[len(buffer):] = ['1;"bc', 'def', 'ghi', 'jkl";3'] vim_module._set_cursor(5, 1) self.assertEqual(csv_col_current(), [{ 'contents': '2', 'highlight_groups': ['csv:column_number', 'csv'] }, { 'contents': ' (Bar)', 'highlight_groups': ['csv:column_name', 'csv'] }]) vim_module._set_cursor(7, 6) self.assertEqual(csv_col_current(), [{ 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] }, { 'contents': ' (Baz)', 'highlight_groups': ['csv:column_name', 'csv'] }]) self.assertEqual(csv_col_current(name_format=' ({column_name:.1})'), [{ 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] }, { 'contents': ' (B)', 'highlight_groups': ['csv:column_name', 'csv'] }]) self.assertEqual(csv_col_current(display_name=True, name_format=' ({column_name:.1})'), [{ 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] }, { 'contents': ' (B)', 'highlight_groups': ['csv:column_name', 'csv'] }]) self.assertEqual(csv_col_current(display_name=False, name_format=' ({column_name:.1})'), [{ 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] }]) self.assertEqual(csv_col_current(display_name=False), [{ 'contents': '3', 'highlight_groups': ['csv:column_number', 'csv'] }]) finally: vim_module._bw(segment_info['bufnr']) @classmethod def setUpClass(cls): sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) from powerline.segments import vim cls.vim = vim from powerline.segments.common import vcs cls.vcs = vcs @classmethod def tearDownClass(cls): sys.path.pop(0) class TestPDB(TestCase): def test_current_line(self): pl = Pl() self.assertEqual(pdb.current_line(pl=pl, segment_info={'curframe': Args(f_lineno=10)}), '10') def test_current_file(self): pl = Pl() cf = lambda **kwargs: pdb.current_file( pl=pl, segment_info={'curframe': Args(f_code=Args(co_filename='/tmp/abc.py'))}, **kwargs ) self.assertEqual(cf(), 'abc.py') self.assertEqual(cf(basename=True), 'abc.py') self.assertEqual(cf(basename=False), '/tmp/abc.py') def test_current_code_name(self): pl = Pl() ccn = lambda **kwargs: pdb.current_code_name( pl=pl, segment_info={'curframe': Args(f_code=Args(co_name=''))}, **kwargs ) self.assertEqual(ccn(), '') def test_current_context(self): pl = Pl() cc = lambda **kwargs: pdb.current_context( pl=pl, segment_info={'curframe': Args(f_code=Args(co_name='', co_filename='/tmp/abc.py'))}, **kwargs ) self.assertEqual(cc(), 'abc.py') def test_stack_depth(self): pl = Pl() sd = lambda **kwargs: pdb.stack_depth( pl=pl, segment_info={'pdb': Args(stack=[1, 2, 3]), 'initial_stack_length': 1}, **kwargs ) self.assertEqual(sd(), '2') self.assertEqual(sd(full_stack=False), '2') self.assertEqual(sd(full_stack=True), '3') old_cwd = None def setUpModule(): global old_cwd global __file__ old_cwd = os.getcwd() __file__ = os.path.abspath(__file__) os.chdir(os.path.dirname(os.path.dirname(__file__))) def tearDownModule(): global old_cwd os.chdir(old_cwd) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_selectors.py000066400000000000000000000015471466405252600227100ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import sys from functools import partial import tests.modules.vim as vim_module from tests.modules.lib import Pl from tests.modules import TestCase class TestVim(TestCase): def test_single_tab(self): pl = Pl() single_tab = partial(self.vim.single_tab, pl=pl, segment_info=None, mode=None) with vim_module._with('tabpage'): self.assertEqual(single_tab(), False) self.assertEqual(single_tab(), True) @classmethod def setUpClass(cls): sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path'))) from powerline.selectors import vim cls.vim = vim @classmethod def tearDownClass(cls): sys.path.pop(0) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_python/test_watcher.py000066400000000000000000000164731466405252600223460ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import shutil import os from time import sleep from functools import partial from errno import ENOENT from powerline.lib.watcher import create_file_watcher, create_tree_watcher, INotifyError from powerline.lib.watcher.uv import UvNotFound from powerline import get_fallback_logger from powerline.lib.monotonic import monotonic from tests.modules import TestCase, SkipTest INOTIFY_DIR = 'inotify' + os.path.basename(os.environ.get('PYTHON', '')) def clear_dir(dir): for root, dirs, files in list(os.walk(dir, topdown=False)): for f in files: os.remove(os.path.join(root, f)) for d in dirs: os.rmdir(os.path.join(root, d)) def set_watcher_tests(l): byte_tests = (('bytes', True), ('unicode', False)) for btn, use_bytes in byte_tests: def test_inotify_file_watcher(self, use_bytes=use_bytes): try: w = create_file_watcher(pl=get_fallback_logger(), watcher_type='inotify') except INotifyError: raise SkipTest('This test is not suitable for a stat based file watcher') self.do_test_file_watcher(w, use_bytes) def test_uv_file_watcher(self, use_bytes=use_bytes): raise SkipTest('Uv watcher tests are not stable') try: w = create_file_watcher(pl=get_fallback_logger(), watcher_type='uv') except UvNotFound: raise SkipTest('Pyuv is not available') self.do_test_file_watcher(w, use_bytes) def test_inotify_tree_watcher(self, use_bytes=use_bytes): try: tw = create_tree_watcher(get_fallback_logger(), watcher_type='inotify') except INotifyError: raise SkipTest('INotify is not available') self.do_test_tree_watcher(tw, use_bytes) def test_uv_tree_watcher(self, use_bytes=use_bytes): raise SkipTest('Uv watcher tests are not stable') try: tw = create_tree_watcher(get_fallback_logger(), 'uv') except UvNotFound: raise SkipTest('Pyuv is not available') self.do_test_tree_watcher(tw, use_bytes) def test_inotify_file_watcher_is_watching(self, use_bytes=use_bytes): try: w = create_file_watcher(pl=get_fallback_logger(), watcher_type='inotify') except INotifyError: raise SkipTest('INotify is not available') self.do_test_file_watcher_is_watching(w, use_bytes) def test_stat_file_watcher_is_watching(self, use_bytes=use_bytes): w = create_file_watcher(pl=get_fallback_logger(), watcher_type='stat') self.do_test_file_watcher_is_watching(w, use_bytes) def test_uv_file_watcher_is_watching(self, use_bytes=use_bytes): try: w = create_file_watcher(pl=get_fallback_logger(), watcher_type='uv') except UvNotFound: raise SkipTest('Pyuv is not available') self.do_test_file_watcher_is_watching(w, use_bytes) for wt in ('uv', 'inotify'): l['test_{0}_file_watcher_{1}'.format(wt, btn)] = locals()['test_{0}_file_watcher'.format(wt)] l['test_{0}_tree_watcher_{1}'.format(wt, btn)] = locals()['test_{0}_tree_watcher'.format(wt)] l['test_{0}_file_watcher_is_watching_{1}'.format(wt, btn)] = ( locals()['test_{0}_file_watcher_is_watching'.format(wt)]) l['test_{0}_file_watcher_is_watching_{1}'.format('stat', btn)] = ( locals()['test_{0}_file_watcher_is_watching'.format('stat')]) class TestFilesystemWatchers(TestCase): def do_test_for_change(self, watcher, path): st = monotonic() while monotonic() - st < 1: if watcher(path): return sleep(0.1) self.fail('The change to {0} was not detected'.format(path)) def do_test_file_watcher(self, w, use_bytes=False): try: f1, f2, f3 = map(lambda x: os.path.join(INOTIFY_DIR, 'file%d' % x), (1, 2, 3)) ne = os.path.join(INOTIFY_DIR, 'notexists') if use_bytes: f1 = f1.encode('utf-8') f2 = f2.encode('utf-8') f3 = f3.encode('utf-8') ne = ne.encode('utf-8') with open(f1, 'wb'): with open(f2, 'wb'): with open(f3, 'wb'): pass self.assertRaises(OSError, w, ne) self.assertTrue(w(f1)) self.assertTrue(w(f2)) os.utime(f1, None), os.utime(f2, None) self.do_test_for_change(w, f1) self.do_test_for_change(w, f2) # Repeat once os.utime(f1, None), os.utime(f2, None) self.do_test_for_change(w, f1) self.do_test_for_change(w, f2) # Check that no false changes are reported self.assertFalse(w(f1), 'Spurious change detected') self.assertFalse(w(f2), 'Spurious change detected') # Check that open the file with 'w' triggers a change with open(f1, 'wb'): with open(f2, 'wb'): pass self.do_test_for_change(w, f1) self.do_test_for_change(w, f2) # Check that writing to a file with 'a' triggers a change with open(f1, 'ab') as f: f.write(b'1') self.do_test_for_change(w, f1) # Check that deleting a file registers as a change os.unlink(f1) self.do_test_for_change(w, f1) # Test that changing the inode of a file does not cause it to stop # being watched os.rename(f3, f2) self.do_test_for_change(w, f2) self.assertFalse(w(f2), 'Spurious change detected') os.utime(f2, None) self.do_test_for_change(w, f2) finally: clear_dir(INOTIFY_DIR) def do_test_tree_watcher(self, tw, use_bytes=False): try: inotify_dir = INOTIFY_DIR subdir = os.path.join(inotify_dir, 'subdir') t1 = os.path.join(inotify_dir, 'tree1') ts1 = os.path.join(subdir, 'tree1') suffix = '1' f = os.path.join(subdir, 'f') if use_bytes: inotify_dir = inotify_dir.encode('utf-8') subdir = subdir.encode('utf-8') t1 = t1.encode('utf-8') ts1 = ts1.encode('utf-8') suffix = suffix.encode('utf-8') f = f.encode('utf-8') os.mkdir(subdir) try: if tw.watch(inotify_dir).is_dummy: raise SkipTest('No tree watcher available') except UvNotFound: raise SkipTest('Pyuv is not available') except INotifyError: raise SkipTest('INotify is not available') self.assertTrue(tw(inotify_dir)) self.assertFalse(tw(inotify_dir)) changed = partial(self.do_test_for_change, tw, inotify_dir) open(t1, 'w').close() changed() open(ts1, 'w').close() changed() os.unlink(ts1) changed() os.rmdir(subdir) changed() os.mkdir(subdir) changed() os.rename(subdir, subdir + suffix) changed() shutil.rmtree(subdir + suffix) changed() os.mkdir(subdir) open(f, 'w').close() changed() with open(f, 'a') as s: s.write(' ') changed() os.rename(f, f + suffix) changed() finally: clear_dir(inotify_dir) def do_test_file_watcher_is_watching(self, w, use_bytes=False): try: f1, f2, f3 = map(lambda x: os.path.join(INOTIFY_DIR, 'file%d' % x), (1, 2, 3)) ne = os.path.join(INOTIFY_DIR, 'notexists') if use_bytes: f1 = f1.encode('utf-8') f2 = f2.encode('utf-8') f3 = f3.encode('utf-8') ne = ne.encode('utf-8') with open(f1, 'wb'): with open(f2, 'wb'): with open(f3, 'wb'): pass self.assertRaises(OSError, w, ne) try: w(ne) except OSError as e: self.assertEqual(e.errno, ENOENT) self.assertTrue(w(f1)) self.assertFalse(w.is_watching(ne)) self.assertTrue(w.is_watching(f1)) self.assertFalse(w.is_watching(f2)) finally: clear_dir(INOTIFY_DIR) set_watcher_tests(locals()) old_cwd = None def setUpModule(): global old_cwd old_cwd = os.getcwd() os.chdir(os.path.dirname(os.path.dirname(__file__))) os.mkdir(INOTIFY_DIR) def tearDownModule(): shutil.rmtree(INOTIFY_DIR) os.chdir(old_cwd) if __name__ == '__main__': from tests.modules import main main() powerline-2.8.4/tests/test_shells/000077500000000000000000000000001466405252600172365ustar00rootroot00000000000000powerline-2.8.4/tests/test_shells/bgscript.sh000077500000000000000000000000711466405252600214100ustar00rootroot00000000000000#!/bin/sh echo $$ > pid while true ; do sleep 0.1s done powerline-2.8.4/tests/test_shells/inputs/000077500000000000000000000000001466405252600205605ustar00rootroot00000000000000powerline-2.8.4/tests/test_shells/inputs/bash000066400000000000000000000035311466405252600214220ustar00rootroot00000000000000set_theme_option() { export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" } set_theme() { export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" } set_theme_option default.segment_data.hostname.args.only_if_ssh false set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false ABOVE_LEFT='[{ "left": [ { "function": "powerline.segments.common.env.environment", "args": {"variable": "DISPLAYED_ENV_VAR"} } ] }]' ABOVE_FULL='[{ "left": [ { "type": "string", "name": "background", "draw_hard_divider": false, "width": "auto" } ], "right": [ { "function": "powerline.segments.common.env.environment", "args": {"variable": "DISPLAYED_ENV_VAR"} } ] }]' set_theme default_leftonly export VIRTUAL_ENV= source powerline/bindings/bash/powerline.sh cd "$TEST_ROOT"/3rd cd .git cd .. VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV= bgscript.sh & waitpid.sh false kill `cat pid` ; sleep 1s set_theme_option default.segment_data.hostname.display false set_theme_option default_leftonly.segment_data.hostname.display false set_theme_option default.segment_data.user.display false set_theme_option default_leftonly.segment_data.user.display false echo ' abc def ' cd "$DIR1" cd ../"$DIR2" cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode!»' (exit 42)|(exit 43) set_theme default set_theme_option default.segments.above "$ABOVE_LEFT" export DISPLAYED_ENV_VAR=foo unset DISPLAYED_ENV_VAR set_theme_option default.segments.above "$ABOVE_FULL" export DISPLAYED_ENV_VAR=foo unset DISPLAYED_ENV_VAR set_theme_option default.segments.above set_theme_option default.dividers.left.hard \$ABC false true is the last line exit powerline-2.8.4/tests/test_shells/inputs/busybox000066400000000000000000000015441466405252600222020ustar00rootroot00000000000000set_theme_option() { export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" } set_theme() { export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" } set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false set_theme default_leftonly . powerline/bindings/shell/powerline.sh export VIRTUAL_ENV= cd "$TEST_ROOT"/3rd cd .git cd .. VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV= bgscript.sh & waitpid.sh false kill `cat pid` ; sleep 1s set_theme_option default_leftonly.segment_data.hostname.display false set_theme_option default_leftonly.segment_data.user.display false echo ' abc def ' cd "$DIR1" cd ../"$DIR2" cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode!»' set_theme_option default_leftonly.dividers.left.hard \$ABC false true is the last line exit powerline-2.8.4/tests/test_shells/inputs/dash000066400000000000000000000015441466405252600214260ustar00rootroot00000000000000set_theme_option() { export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" } set_theme() { export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" } set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false set_theme default_leftonly . powerline/bindings/shell/powerline.sh export VIRTUAL_ENV= cd "$TEST_ROOT"/3rd cd .git cd .. VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV= bgscript.sh & waitpid.sh false kill `cat pid` ; sleep 1s set_theme_option default_leftonly.segment_data.hostname.display false set_theme_option default_leftonly.segment_data.user.display false echo ' abc def ' cd "$DIR1" cd ../"$DIR2" cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode!»' set_theme_option default_leftonly.dividers.left.hard \$ABC false true is the last line exit powerline-2.8.4/tests/test_shells/inputs/fish000066400000000000000000000030771466405252600214430ustar00rootroot00000000000000function set_theme_option set -g -x POWERLINE_THEME_OVERRIDES "$POWERLINE_THEME_OVERRIDES;$argv[1]=$argv[2]" end function set_theme set -g -x POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=$argv" end set -g -x POWERLINE_ set -g ABOVE_LEFT '[{ "left": [ { "function": "powerline.segments.common.env.environment", "args": {"variable": "DISPLAYED_ENV_VAR"} } ] }]' set -g ABOVE_FULL '[{ "left": [ { "type": "string", "name": "background", "draw_hard_divider": false, "width": "auto" } ], "right": [ { "function": "powerline.segments.common.env.environment", "args": {"variable": "DISPLAYED_ENV_VAR"} } ] }]' set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false set_theme default_leftonly set fish_function_path "$PWD/powerline/bindings/fish" $fish_function_path while jobs | grep fish_update_completions sleep 1 end powerline-setup setenv VIRTUAL_ENV cd "$TEST_ROOT"/3rd cd .git cd .. setenv VIRTUAL_ENV "$HOME/.virtenvs/some-virtual-environment" setenv VIRTUAL_ENV bgscript.sh & waitpid.sh false kill (cat pid) ; sleep 1s cd "$DIR1" cd ../"$DIR2" cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode!»' set_theme default set_theme_option default.segments.above "$ABOVE_LEFT" set -g -x DISPLAYED_ENV_VAR foo set -g -x -e DISPLAYED_ENV_VAR set_theme_option default.segments.above "$ABOVE_FULL" set -g -x DISPLAYED_ENV_VAR foo set -g -x -e DISPLAYED_ENV_VAR set_theme_option default.segments.above '' set -g fish_key_bindings fish_vi_key_bindings ii false true is the last line exit powerline-2.8.4/tests/test_shells/inputs/ipython000066400000000000000000000001561466405252600221770ustar00rootroot00000000000000print ('cd ' + '"$TEST_ROOT"/3rd') # Start of the test marker bool 42 bool 44 class Test(object): pass exit powerline-2.8.4/tests/test_shells/inputs/mksh000066400000000000000000000015531466405252600214510ustar00rootroot00000000000000set_theme_option() { export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" } set_theme() { export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" } set_theme default_leftonly set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false . powerline/bindings/shell/powerline.sh export VIRTUAL_ENV= cd "$TEST_ROOT"/3rd cd .git cd .. VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV= bgscript.sh & waitpid.sh false kill `cat pid` ; sleep 1 set_theme_option default_leftonly.segment_data.hostname.display false set_theme_option default_leftonly.segment_data.user.display false echo -n echo ' abc def ' cd "$DIR1" cd ../"$DIR2" cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode!»' set_theme_option default_leftonly.dividers.left.hard \$ABC false true is the last line exit powerline-2.8.4/tests/test_shells/inputs/pdb000066400000000000000000000001361466405252600212500ustar00rootroot00000000000000s  powerline-2.8.4/tests/test_shells/inputs/rc000066400000000000000000000014771466405252600211200ustar00rootroot00000000000000fn set_theme_option { POWERLINE_THEME_OVERRIDES = $POWERLINE_THEME_OVERRIDES';'$1'='$2 } set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false POWERLINE_CONFIG_OVERRIDES = 'ext.shell.theme=default_leftonly' . powerline/bindings/rc/powerline.rc VIRTUAL_ENV = () cd $TEST_ROOT/3rd true cd "$TEST_ROOT"/3rd # Test start marker cd .git cd .. VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment' VIRTUAL_ENV = () bgscript.sh & waitpid.sh false kill `{cat pid} ; sleep 1s cd $DIR1 cd ../$DIR2 cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode!»' false set_theme_option default_leftonly.segment_data.hostname.display false set_theme_option default_leftonly.segment_data.user.display false echo `{ echo Continuation! } true is the last line exit powerline-2.8.4/tests/test_shells/inputs/tcsh000066400000000000000000000011751466405252600214500ustar00rootroot00000000000000setenv POWERLINE_THEME_OVERRIDES "default_leftonly.segment_data.hostname.args.only_if_ssh=false" setenv POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=default_leftonly" source powerline/bindings/tcsh/powerline.tcsh unsetenv VIRTUAL_ENV cd "$TEST_ROOT"/3rd cd .git cd .. setenv VIRTUAL_ENV "/home/foo/.virtenvs/some-virtual-environment" unsetenv VIRTUAL_ENV bgscript.sh & waitpid.sh false # Warning: currently tcsh bindings do not support job count kill `cat pid` ; sleep 1s cd $DIR1:q cd ../$DIR2:q cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode\!»' false true is the last line exit powerline-2.8.4/tests/test_shells/inputs/zsh000066400000000000000000000036711466405252600213160ustar00rootroot00000000000000unset HOME unsetopt promptsp notransientrprompt setopt interactivecomments setopt autonamedirs setopt warncreateglobal function set_theme_option() { export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2" powerline-reload-config } function set_theme() { export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1" powerline-reload-config } if test -n "$POWERLINE_NO_ZSH_ZPYTHON" ; then powerline-reload-config(): fi source powerline/bindings/zsh/powerline.zsh set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false set_theme_option default.segment_data.hostname.args.only_if_ssh false ABOVE_LEFT='[{ "left": [ { "function": "powerline.segments.common.env.environment", "args": {"variable": "DISPLAYED_ENV_VAR"} } ] }]' ABOVE_FULL='[{ "left": [ { "type": "string", "name": "background", "draw_hard_divider": false, "width": "auto" } ], "right": [ { "function": "powerline.segments.common.env.environment", "args": {"variable": "DISPLAYED_ENV_VAR"} } ] }]' set_theme default_leftonly export VIRTUAL_ENV= cd "$TEST_ROOT"/3rd cd .git cd .. VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment" VIRTUAL_ENV= bgscript.sh & waitpid.sh false kill `cat pid` ; sleep 1s cd "$DIR1" cd ../"$DIR2" cd ../'\[\]' cd ../'%%' cd ../'#[bold]' cd ../'(echo)' cd ../'$(echo)' cd ../'`echo`' cd ../'«Unicode!»' cd .. bindkey -v ; set_theme default  echo abc false set_theme_option default.segment_data.hostname.display false set_theme_option default.segment_data.user.display false select abc in def ghi jkl do echo $abc break done 1 cd . cd . set_theme_option default.segments.above "$ABOVE_LEFT" export DISPLAYED_ENV_VAR=foo unset DISPLAYED_ENV_VAR set_theme_option default.segments.above "$ABOVE_FULL" export DISPLAYED_ENV_VAR=foo unset DISPLAYED_ENV_VAR set_theme_option default.segments.above hash -d foo=$PWD:h ; cd . set_theme_option default.dividers.left.hard \$ABC true true is the last line exit powerline-2.8.4/tests/test_shells/ipython_home/000077500000000000000000000000001466405252600217405ustar00rootroot00000000000000powerline-2.8.4/tests/test_shells/ipython_home/profile_default/000077500000000000000000000000001466405252600251045ustar00rootroot00000000000000powerline-2.8.4/tests/test_shells/ipython_home/profile_default/ipython_config.py000066400000000000000000000010501466405252600304710ustar00rootroot00000000000000from powerline.bindings.ipython.since_7 import PowerlinePrompts import os c = get_config() c.TerminalInteractiveShell.simple_prompt = False c.TerminalIPythonApp.display_banner = False c.TerminalInteractiveShell.prompts_class = PowerlinePrompts c.TerminalInteractiveShell.autocall = 1 c.Powerline.config_paths = [os.path.abspath('powerline/config_files')] c.Powerline.theme_overrides = { 'in': { 'segment_data': { 'virtualenv': { 'display': False } } } } c.Powerline.config_overrides = { 'common': { 'default_top_theme': 'ascii' } } powerline-2.8.4/tests/test_shells/outputs/000077500000000000000000000000001466405252600207615ustar00rootroot00000000000000powerline-2.8.4/tests/test_shells/outputs/bash.daemon.ok000066400000000000000000000344631466405252600235050ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh [1] PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1]+ Terminated bgscript.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo '                                    abc                                    def                                    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)   BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme default  …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_LEFT"  …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo  foo    …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR  …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_FULL"                                                                                                                                                                                                                                                                                                               …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo                                                                                                                                                                                                                                                                                                        foo   …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR                                                                                                                                                                                                                                                                                                               …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above  …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.dividers.left.hard \$ABC  …  shell  3rd  «Unicode!» $ABC   BRANCH false powerline-2.8.4/tests/test_shells/outputs/bash.nodaemon.ok000066400000000000000000000341631466405252600240370ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh [1] PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1]+ Terminated bgscript.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo '    abc    def    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)   BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme default  …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_LEFT"  …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo  foo    …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR  …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above "$ABOVE_FULL"                                                                                                                                                                                                                                                                                                               …  shell  3rd  «Unicode!»     BRANCH export DISPLAYED_ENV_VAR=foo                                                                                                                                                                                                                                                                                                        foo   …  shell  3rd  «Unicode!»     BRANCH unset DISPLAYED_ENV_VAR                                                                                                                                                                                                                                                                                                               …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.segments.above  …  shell  3rd  «Unicode!»     BRANCH set_theme_option default.dividers.left.hard \$ABC  …  shell  3rd  «Unicode!» $ABC   BRANCH false powerline-2.8.4/tests/test_shells/outputs/busybox.daemon.ok000066400000000000000000000205111466405252600242500ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1]+ Terminated bgscript.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo '                                    abc                                    def                                    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC   BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse powerline-2.8.4/tests/test_shells/outputs/busybox.nodaemon.ok000066400000000000000000000202111466405252600246020ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1]+ Terminated bgscript.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo '    abc    def    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC   BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse powerline-2.8.4/tests/test_shells/outputs/dash.daemon.ok000066400000000000000000000204341466405252600235000ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s set_theme_option default_leftonly.segment_data.hostname.display false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1   USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo '                                    abc                                    def                                    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC   BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse powerline-2.8.4/tests/test_shells/outputs/dash.nodaemon.ok000066400000000000000000000201341466405252600240320ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s set_theme_option default_leftonly.segment_data.hostname.display false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1   USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo '    abc    def    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC   BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse powerline-2.8.4/tests/test_shells/outputs/fish.ok000066400000000000000000000335241466405252600222540ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  shell  3rd  .git     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m     HOSTNAME  USER   BRANCH  …  shell  3rd  ^H     HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]     HOSTNAME  USER   BRANCH  …  shell  3rd  %%     HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]     HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)     HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)     HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`     HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»    USER  …  shell  3rd  «Unicode!»      BRANCH     BRANCH     BRANCH   USER  …  shell  3rd  «Unicode!»      BRANCH     BRANCH     BRANCH   foo    USER  …  shell  3rd  «Unicode!»      BRANCH     BRANCH     BRANCH                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    foo                                                                                                                                                                                                                                                                                                               USER  …  shell  3rd  «Unicode!»      BRANCH     BRANCH     BRANCH   INSERT  USER  …  shell  3rd  «Unicode!»      BRANCH   DEFAULT  USER  …  shell  3rd  «Unicode!»      BRANCH   INSERT  USER  …  shell  3rd  «Unicode!»      BRANCH   DEFAULT  USER  …  shell  3rd  «Unicode!»      BRANCH   INSERT  USER  …  shell  3rd  «Unicode!»      BRANCH     BRANCH   INSERT  USER  …  shell  3rd  «Unicode!»      BRANCH     BRANCH     BRANCH  powerline-2.8.4/tests/test_shells/outputs/ipython.ok000066400000000000000000000017171466405252600230140ustar00rootroot00000000000000  In [2]  bool 42  2>  bool(42)  Out[2]  True  In [3]  bool 44  3>  bool(44)  Out[3]  True  In [4]  class Test(object):    pass     In [5]  exit powerline-2.8.4/tests/test_shells/outputs/mksh.daemon.ok000066400000000000000000000210731466405252600235230ustar00rootroot00000000000000   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh [1] PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1 [1] + Terminated bash -c ...   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo -n   BRANCH  …  tmp  shell  3rd  echo '                                    abc                                    def                                    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC   BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse powerline-2.8.4/tests/test_shells/outputs/mksh.nodaemon.ok000066400000000000000000000205731466405252600240640ustar00rootroot00000000000000   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh [1] PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1 [1] + Terminated bash -c ...   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  tmp  shell  3rd  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  tmp  shell  3rd  echo -n   BRANCH  …  tmp  shell  3rd  echo '    abc    def    ' abc def   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.dividers.left.hard \$ABC   BRANCH $ABC…  shell  3rd  «Unicode!» $ABCfalse powerline-2.8.4/tests/test_shells/outputs/pdb.module.ok000066400000000000000000000774441466405252600233650ustar00rootroot00000000000000 1  pdb-script.py:6    --Call-- -> class Foo(object):  2  pdb-script.py:6   pdb-script.py:6 Foo   -> class Foo(object):  2  pdb-script.py:6   pdb-script.py:6 Foo   -> def __init__(self):  2  pdb-script.py:6   pdb-script.py:7 Foo   -> @classmethod  2  pdb-script.py:6   pdb-script.py:13 Foo   -> @staticmethod  2  pdb-script.py:6   pdb-script.py:17 Foo   -> def bra(self):  2  pdb-script.py:6   pdb-script.py:21 Foo   --Return-- -> def bra(self):  2  pdb-script.py:6   pdb-script.py:21 Foo   -> def brah():  1  pdb-script.py:25    -> f = Foo()  1  pdb-script.py:29    --Call-- -> def __init__(self):  2  pdb-script.py:29   pdb-script.py:7 __init__   -> nop('__init__')  2  pdb-script.py:29   pdb-script.py:8 __init__   --Call-- -> def nop(_):  3  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:2 nop   -> pass  3  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   -> self.bar()  2  pdb-script.py:29   pdb-script.py:9 __init__   --Call-- -> @classmethod  3  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:13 bar   -> nop(cls.__name__)  3  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:15 bar   --Call-- -> def nop(_):  4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:2 nop   -> pass  4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> nop(cls.__name__)  3  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:15 bar   -> self.baz()  2  pdb-script.py:29   pdb-script.py:10 __init__   --Call-- -> @staticmethod  3  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:17 baz   -> nop(1)  3  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:19 baz   --Call-- -> def nop(_):  4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:2 nop   -> pass  4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> nop(1)  3  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:19 baz   -> self.bra()  2  pdb-script.py:29   pdb-script.py:11 __init__   --Call-- -> def bra(self):  3  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:21 bra   -> nop(self.__class__.__name__)  3  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:22 bra   --Call-- -> def nop(_):  4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:2 nop   -> pass  4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> nop(self.__class__.__name__)  3  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:22 bra   --Return-- -> self.bra()  2  pdb-script.py:29   pdb-script.py:11 __init__   -> Foo.bar()  1  pdb-script.py:30    --Call-- -> @classmethod  2  pdb-script.py:30   pdb-script.py:13 bar   -> nop(cls.__name__)  2  pdb-script.py:30   pdb-script.py:15 bar   --Call-- -> def nop(_):  3  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:2 nop   -> pass  3  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> nop(cls.__name__)  2  pdb-script.py:30   pdb-script.py:15 bar   -> Foo.baz()  1  pdb-script.py:31    --Call-- -> @staticmethod  2  pdb-script.py:31   pdb-script.py:17 baz   -> nop(1)  2  pdb-script.py:31   pdb-script.py:19 baz   --Call-- -> def nop(_):  3  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:2 nop   -> pass  3  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> nop(1)  2  pdb-script.py:31   pdb-script.py:19 baz   -> Foo.bra(f)  1  pdb-script.py:32    --Call-- -> def bra(self):  2  pdb-script.py:32   pdb-script.py:21 bra   -> nop(self.__class__.__name__)  2  pdb-script.py:32   pdb-script.py:22 bra   --Call-- -> def nop(_):  3  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:2 nop   -> pass  3  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> nop(self.__class__.__name__)  2  pdb-script.py:32   pdb-script.py:22 bra   -> f.bar()  1  pdb-script.py:34    --Call-- -> @classmethod  2  pdb-script.py:34   pdb-script.py:13 bar   -> nop(cls.__name__)  2  pdb-script.py:34   pdb-script.py:15 bar   --Call-- -> def nop(_):  3  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:2 nop   -> pass  3  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> nop(cls.__name__)  2  pdb-script.py:34   pdb-script.py:15 bar   -> f.baz()  1  pdb-script.py:35    --Call-- -> @staticmethod  2  pdb-script.py:35   pdb-script.py:17 baz   -> nop(1)  2  pdb-script.py:35   pdb-script.py:19 baz   --Call-- -> def nop(_):  3  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:2 nop   -> pass  3  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> nop(1)  2  pdb-script.py:35   pdb-script.py:19 baz   -> f.bra()  1  pdb-script.py:36    --Call-- -> def bra(self):  2  pdb-script.py:36   pdb-script.py:21 bra   -> nop(self.__class__.__name__)  2  pdb-script.py:36   pdb-script.py:22 bra   --Call-- -> def nop(_):  3  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:2 nop   -> pass  3  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> nop(self.__class__.__name__)  2  pdb-script.py:36   pdb-script.py:22 bra   -> brah()  1  pdb-script.py:38    --Call-- -> def brah():  2  pdb-script.py:38   pdb-script.py:25 brah   -> nop('brah')  2  pdb-script.py:38   pdb-script.py:26 brah   --Call-- -> def nop(_):  3  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:2 nop   -> pass  3  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   --Return-- -> pass  3  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   --Return-- -> nop('brah')  2  pdb-script.py:38   pdb-script.py:26 brah   --Return-- -> brah()  1  pdb-script.py:38    --Return--  0   powerline-2.8.4/tests/test_shells/outputs/pdb.subclass.ok000066400000000000000000001114101466405252600236750ustar00rootroot00000000000000 2  :1   pdb-script.py:6    --Call-- -> class Foo(object):  3  :1   pdb-script.py:6   pdb-script.py:6 Foo   -> class Foo(object):  3  :1   pdb-script.py:6   pdb-script.py:6 Foo   -> def __init__(self):  3  :1   pdb-script.py:6   pdb-script.py:7 Foo   -> @classmethod  3  :1   pdb-script.py:6   pdb-script.py:13 Foo   -> @staticmethod  3  :1   pdb-script.py:6   pdb-script.py:17 Foo   -> def bra(self):  3  :1   pdb-script.py:6   pdb-script.py:21 Foo   --Return-- -> def bra(self):  3  :1   pdb-script.py:6   pdb-script.py:21 Foo   -> def brah():  2  :1   pdb-script.py:25    -> f = Foo()  2  :1   pdb-script.py:29    --Call-- -> def __init__(self):  3  :1   pdb-script.py:29   pdb-script.py:7 __init__   -> nop('__init__')  3  :1   pdb-script.py:29   pdb-script.py:8 __init__   --Call-- -> def nop(_):  4  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:2 nop   -> pass  4  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   -> self.bar()  3  :1   pdb-script.py:29   pdb-script.py:9 __init__   --Call-- -> @classmethod  4  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:13 bar   -> nop(cls.__name__)  4  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:15 bar   --Call-- -> def nop(_):  5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:2 nop   -> pass  5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> pass  5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> nop(cls.__name__)  4  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:15 bar   -> self.baz()  3  :1   pdb-script.py:29   pdb-script.py:10 __init__   --Call-- -> @staticmethod  4  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:17 baz   -> nop(1)  4  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:19 baz   --Call-- -> def nop(_):  5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:2 nop   -> pass  5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> pass  5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> nop(1)  4  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:19 baz   -> self.bra()  3  :1   pdb-script.py:29   pdb-script.py:11 __init__   --Call-- -> def bra(self):  4  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:21 bra   -> nop(self.__class__.__name__)  4  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:22 bra   --Call-- -> def nop(_):  5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:2 nop   -> pass  5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> pass  5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> nop(self.__class__.__name__)  4  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:22 bra   --Return-- -> self.bra()  3  :1   pdb-script.py:29   pdb-script.py:11 __init__   -> Foo.bar()  2  :1   pdb-script.py:30    --Call-- -> @classmethod  3  :1   pdb-script.py:30   pdb-script.py:13 bar   -> nop(cls.__name__)  3  :1   pdb-script.py:30   pdb-script.py:15 bar   --Call-- -> def nop(_):  4  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:2 nop   -> pass  4  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> nop(cls.__name__)  3  :1   pdb-script.py:30   pdb-script.py:15 bar   -> Foo.baz()  2  :1   pdb-script.py:31    --Call-- -> @staticmethod  3  :1   pdb-script.py:31   pdb-script.py:17 baz   -> nop(1)  3  :1   pdb-script.py:31   pdb-script.py:19 baz   --Call-- -> def nop(_):  4  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:2 nop   -> pass  4  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> nop(1)  3  :1   pdb-script.py:31   pdb-script.py:19 baz   -> Foo.bra(f)  2  :1   pdb-script.py:32    --Call-- -> def bra(self):  3  :1   pdb-script.py:32   pdb-script.py:21 bra   -> nop(self.__class__.__name__)  3  :1   pdb-script.py:32   pdb-script.py:22 bra   --Call-- -> def nop(_):  4  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:2 nop   -> pass  4  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> nop(self.__class__.__name__)  3  :1   pdb-script.py:32   pdb-script.py:22 bra   -> f.bar()  2  :1   pdb-script.py:34    --Call-- -> @classmethod  3  :1   pdb-script.py:34   pdb-script.py:13 bar   -> nop(cls.__name__)  3  :1   pdb-script.py:34   pdb-script.py:15 bar   --Call-- -> def nop(_):  4  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:2 nop   -> pass  4  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   --Return-- -> nop(cls.__name__)  3  :1   pdb-script.py:34   pdb-script.py:15 bar   -> f.baz()  2  :1   pdb-script.py:35    --Call-- -> @staticmethod  3  :1   pdb-script.py:35   pdb-script.py:17 baz   -> nop(1)  3  :1   pdb-script.py:35   pdb-script.py:19 baz   --Call-- -> def nop(_):  4  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:2 nop   -> pass  4  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   --Return-- -> nop(1)  3  :1   pdb-script.py:35   pdb-script.py:19 baz   -> f.bra()  2  :1   pdb-script.py:36    --Call-- -> def bra(self):  3  :1   pdb-script.py:36   pdb-script.py:21 bra   -> nop(self.__class__.__name__)  3  :1   pdb-script.py:36   pdb-script.py:22 bra   --Call-- -> def nop(_):  4  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:2 nop   -> pass  4  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   --Return-- -> nop(self.__class__.__name__)  3  :1   pdb-script.py:36   pdb-script.py:22 bra   -> brah()  2  :1   pdb-script.py:38    --Call-- -> def brah():  3  :1   pdb-script.py:38   pdb-script.py:25 brah   -> nop('brah')  3  :1   pdb-script.py:38   pdb-script.py:26 brah   --Call-- -> def nop(_):  4  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:2 nop   -> pass  4  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   --Return-- -> pass  4  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   --Return-- -> nop('brah')  3  :1   pdb-script.py:38   pdb-script.py:26 brah   powerline-2.8.4/tests/test_shells/outputs/rc.daemon.ok000066400000000000000000000221441466405252600231650ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment'   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = ()   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `{cat pid} ; sleep 1s   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd $DIR1   HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../$DIR2   HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  false   HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  1  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  shell  3rd  «Unicode!»  echo `{                                            echo Continuation!                                           } Continuation! powerline-2.8.4/tests/test_shells/outputs/rc.nodaemon.ok000066400000000000000000000217101466405252600235200ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment'   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV = ()   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `{cat pid} ; sleep 1s   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd $DIR1   HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../$DIR2   HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  false   HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  1  set_theme_option default_leftonly.segment_data.hostname.display false  USER   BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segment_data.user.display false   BRANCH  …  shell  3rd  «Unicode!»  echo `{     echo Continuation!    } Continuation! powerline-2.8.4/tests/test_shells/outputs/tcsh.ok000066400000000000000000000162441466405252600222640ustar00rootroot00000000000000  HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  shell  3rd  .git     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1     HOSTNAME  USER   BRANCH  …  tmp  shell  3rd     HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m     HOSTNAME  USER   BRANCH  …  shell  3rd  ^H     HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]     HOSTNAME  USER   BRANCH  …  shell  3rd  %%     HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]     HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)     HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)     HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`     HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»   powerline-2.8.4/tests/test_shells/outputs/zsh.daemon.ok000066400000000000000000000424721466405252600233730ustar00rootroot00000000000000   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh [1] PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1] + terminated bgscript.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bindkey -v ; set_theme default  INSERT   HOSTNAME  USER  …  tmp  shell  3rd   COMMND   HOSTNAME  USER  …  tmp  shell  3rd    INSERT   HOSTNAME  USER  …  tmp  shell  3rd    INSERT   HOSTNAME  USER  …  tmp  shell  3rd  echo abc abc  INSERT   HOSTNAME  USER  …  tmp  shell  3rd  false  INSERT   HOSTNAME  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false  INSERT  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false  INSERT  …  tmp  shell  3rd  select abc in def ghi jkl  select                          do  select                           echo $abc  select                           break  select                          done 1) def 2) ghi 3) jkl                  Select variant  1 def  INSERT  …  tmp  shell  3rd  cd .  INSERT  …  tmp  shell  3rd  cd .  INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"  INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo  foo    INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR  INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"                                                                                                                                                                                                                                                                                                              INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo                                                                                                                                                                                                                                                                                                       foo   INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR                                                                                                                                                                                                                                                                                                              INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above  INSERT  …  tmp  shell  3rd  hash -d foo=$PWD:h ; cd .  INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC  INSERT $ABC~foo  3rd $ABCtrue powerline-2.8.4/tests/test_shells/outputs/zsh.nodaemon.ok000066400000000000000000000421321466405252600237210ustar00rootroot00000000000000   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh [1] PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1] + terminated bgscript.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bindkey -v ; set_theme default  INSERT   HOSTNAME  USER  …  tmp  shell  3rd   COMMND   HOSTNAME  USER  …  tmp  shell  3rd    INSERT   HOSTNAME  USER  …  tmp  shell  3rd    INSERT   HOSTNAME  USER  …  tmp  shell  3rd  echo abc abc  INSERT   HOSTNAME  USER  …  tmp  shell  3rd  false  INSERT   HOSTNAME  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false  INSERT  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false  INSERT  …  tmp  shell  3rd  select abc in def ghi jkl  select  do  select   echo $abc  select   break  select  done 1) def 2) ghi 3) jkl  Select variant  1 def  INSERT  …  tmp  shell  3rd  cd .  INSERT  …  tmp  shell  3rd  cd .  INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"  INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo  foo    INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR  INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"                                                                                                                                                                                                                                                                                                              INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo                                                                                                                                                                                                                                                                                                       foo   INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR                                                                                                                                                                                                                                                                                                              INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above  INSERT  …  tmp  shell  3rd  hash -d foo=$PWD:h ; cd .  INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC  INSERT $ABC~foo  3rd $ABCtrue powerline-2.8.4/tests/test_shells/outputs/zsh.zpython.ok000066400000000000000000000424721466405252600236430ustar00rootroot00000000000000   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  …  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"   HOSTNAME  USER  (e) some-virtual-environment   BRANCH  …  tmp  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bgscript.sh & waitpid.sh [1] PID   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  false   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1] + terminated bgscript.sh   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  cd "$DIR1"   HOSTNAME  USER   BRANCH  …  shell  3rd  ^[[32m  cd ../"$DIR2"   HOSTNAME  USER   BRANCH  …  shell  3rd  ^H  cd ../'\[\]'   HOSTNAME  USER   BRANCH  …  shell  3rd  \[\]  cd ../'%%'   HOSTNAME  USER   BRANCH  …  shell  3rd  %%  cd ../'#[bold]'   HOSTNAME  USER   BRANCH  …  shell  3rd  #[bold]  cd ../'(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   HOSTNAME  USER   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   HOSTNAME  USER   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   HOSTNAME  USER   BRANCH  …  shell  3rd  «Unicode!»  cd ..   HOSTNAME  USER   BRANCH  …  tmp  shell  3rd  bindkey -v ; set_theme default  INSERT   HOSTNAME  USER  …  tmp  shell  3rd   COMMND   HOSTNAME  USER  …  tmp  shell  3rd    INSERT   HOSTNAME  USER  …  tmp  shell  3rd    INSERT   HOSTNAME  USER  …  tmp  shell  3rd  echo abc abc  INSERT   HOSTNAME  USER  …  tmp  shell  3rd  false  INSERT   HOSTNAME  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.hostname.display false  INSERT  USER  …  tmp  shell  3rd  set_theme_option default.segment_data.user.display false  INSERT  …  tmp  shell  3rd  select abc in def ghi jkl  select                          do  select                           echo $abc  select                           break  select                          done 1) def 2) ghi 3) jkl                  Select variant  1 def  INSERT  …  tmp  shell  3rd  cd .  INSERT  …  tmp  shell  3rd  cd .  INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"  INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo  foo    INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR  INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"                                                                                                                                                                                                                                                                                                              INSERT  …  tmp  shell  3rd  export DISPLAYED_ENV_VAR=foo                                                                                                                                                                                                                                                                                                       foo   INSERT  …  tmp  shell  3rd  unset DISPLAYED_ENV_VAR                                                                                                                                                                                                                                                                                                              INSERT  …  tmp  shell  3rd  set_theme_option default.segments.above  INSERT  …  tmp  shell  3rd  hash -d foo=$PWD:h ; cd .  INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC  INSERT $ABC~foo  3rd $ABCtrue powerline-2.8.4/tests/test_shells/pdb-main.py000066400000000000000000000007061466405252600213020ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import pdb import os import sys from powerline.bindings.pdb import use_powerline_prompt @use_powerline_prompt class Pdb(pdb.Pdb): pass p = Pdb() script = os.path.join(os.path.dirname(__file__), 'pdb-script.py') with open(script, 'r') as fd: code = compile(fd.read(), script, 'exec') p.run('exec(code)', globals={'code': code}) powerline-2.8.4/tests/test_shells/pdb-script.py000066400000000000000000000006011466405252600216540ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet def nop(_): pass class Foo(object): def __init__(self): nop('__init__') self.bar() self.baz() self.bra() @classmethod def bar(cls): nop(cls.__name__) @staticmethod def baz(): nop(1) def bra(self): nop(self.__class__.__name__) def brah(): nop('brah') f = Foo() Foo.bar() Foo.baz() Foo.bra(f) f.bar() f.baz() f.bra() brah() powerline-2.8.4/tests/test_shells/postproc.py000077500000000000000000000071341466405252600214710ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import os import socket import sys import codecs import platform import re test_root = os.environ['TEST_ROOT'] test_type = sys.argv[1] test_client = sys.argv[2] shell = sys.argv[3] fname = os.path.join(test_root, '.'.join((shell, test_type, test_client, 'full.log'))) new_fname = os.path.join(test_root, '.'.join((shell, test_type, test_client, 'log'))) pid_fname = os.path.join(test_root, '3rd', 'pid') is_pypy = platform.python_implementation() == 'PyPy' try: with open(pid_fname, 'r') as P: pid = P.read().strip() except IOError: pid = None hostname = socket.gethostname() user = os.environ['USER'] REFS_RE = re.compile(r'^\[\d+ refs\]\n') IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>])') ZSH_HL_RE = re.compile(r'\033\[\?\d+[hl]') start_str = 'cd "$TEST_ROOT"/3rd' if shell == 'pdb': start_str = 'class Foo(object):' with codecs.open(fname, 'r', encoding='utf-8') as R: with codecs.open(new_fname, 'w', encoding='utf-8') as W: found_cd = False i = -1 for line in (R if shell != 'fish' else R.read().split('\n')): i += 1 if not found_cd: found_cd = (start_str in line) continue if 'true is the last line' in line: break line = line.translate({ ord('\r'): None }) if REFS_RE.match(line): continue line = line.replace(hostname, 'HOSTNAME') line = line.replace(user, 'USER') if pid is not None: line = line.replace(pid, 'PID') if shell == 'zsh': line = line.replace('\033[0m\033[23m\033[24m\033[J', '') line = ZSH_HL_RE.subn('', line)[0] elif shell == 'fish': res = '' try: while line.index('\033[0;'): start = line.index('\033[0;') end = line.index('\033[0m', start) res += line[start:end + 4] + '\n' line = line[end + 4:] except ValueError: pass line = res elif shell == 'tcsh': try: start = line.index('\033[0;') end = line.index(' ', start) line = line[start:end] + '\n' except ValueError: line = '' elif shell == 'mksh': # Output is different in travis: on my machine I see full # command, in travis it is truncated just after `true`. if line.startswith('[1] + Terminated'): line = '[1] + Terminated bash -c ...\n' elif shell == 'dash': # Position of this line is not stable: it may go both before and # after the next line if line.startswith('[1] + Terminated'): continue elif shell == 'ipython' and is_pypy: try: end_idx = line.rindex('\033[0m') try: idx = line[:end_idx].rindex('\033[1;1H') except ValueError: idx = line[:end_idx].rindex('\033[?25h') line = line[idx + len('\033[1;1H'):] except ValueError: pass try: data_end_idx = line.rindex('\033[1;1H') line = line[:data_end_idx] + '\n' except ValueError: pass if line == '\033[1;1H\n': continue was_empty = line == '\n' line = IPYPY_DEANSI_RE.subn('', line)[0] if line == '\n' and not was_empty: line = '' elif shell == 'rc': if line == 'read() failed: Connection reset by peer\n': line = '' elif shell == 'pdb': if is_pypy: if line == '\033[?1h\033=\033[?25l\033[1A\n': line = '' line = IPYPY_DEANSI_RE.subn('', line)[0] if line == '\n': line = '' if line.startswith(('>',)): line = '' elif line == '-> self.quitting = 1\n': line = '-> self.quitting = True\n' elif line == '\n': line = '' if line == '-> self.quitting = True\n': break W.write(line) powerline-2.8.4/tests/test_shells/run_script.py000077500000000000000000000071051466405252600220060ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import argparse import os import re from time import sleep from subprocess import check_call from io import BytesIO import pexpect def get_argparser(ArgumentParser=argparse.ArgumentParser): parser = ArgumentParser(description='Run powerline shell test using pexpect') parser.add_argument('--wait-for-echo', action='store_true', help='Wait until the input is echoed back.') parser.add_argument('--type', metavar='TYPE', help='Test type (daemon, nodaemon, …).') parser.add_argument('--client', metavar='CLIENT', help='Type of the client used (C, shell, zpython, …).') parser.add_argument('--shell', metavar='SHELL', help='Shell name.') parser.add_argument('command', nargs=argparse.REMAINDER, metavar='COMMAND', help='Command to run and its argument.') return parser def main(): test_root = os.environ['TEST_ROOT'] parser = get_argparser() args = parser.parse_args() shell = args.shell or args.command[0] test_type = args.type or shell test_client = args.client or test_type log_file_base = '{0}.{1}.{2}'.format(shell, test_type, test_client) full_log_file_name = os.path.join(test_root, '{0}.full.log'.format(log_file_base)) local_paths = [ os.path.abspath(os.path.join(test_root, 'path')), os.path.abspath('scripts'), ] if test_type == 'fish': local_paths += ['/usr/bin', '/bin'] python_paths = os.environ.get('PYTHONPATH', '') if python_paths: python_paths = ':' + python_paths python_paths = os.path.abspath('.') + python_paths environ = { 'LANG': 'en_US.UTF-8', 'PATH': os.pathsep.join(local_paths), 'TERM': 'screen-256color', 'DIR1': os.environ['DIR1'], 'DIR2': os.environ['DIR2'], 'XDG_CONFIG_HOME': os.path.abspath(os.path.join(test_root, 'fish_home')), 'IPYTHONDIR': os.path.abspath(os.path.join(test_root, 'ipython_home')), 'PYTHONPATH': python_paths, 'POWERLINE_CONFIG_OVERRIDES': os.environ.get('POWERLINE_CONFIG_OVERRIDES', ''), 'POWERLINE_THEME_OVERRIDES': os.environ.get('POWERLINE_THEME_OVERRIDES', ''), 'POWERLINE_CONFIG_PATHS': os.path.abspath(os.path.join('powerline', 'config_files')), 'POWERLINE_COMMAND_ARGS': os.environ.get('POWERLINE_COMMAND_ARGS', ''), 'POWERLINE_COMMAND': os.environ.get('POWERLINE_COMMAND', ''), 'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''), 'TEST_ROOT': test_root, } os.environ['PATH'] = environ['PATH'] if test_type == 'daemon': environ['POWERLINE_SHELL_CONTINUATION'] = '1' environ['POWERLINE_SHELL_SELECT'] = '1' if test_type != 'zpython' and shell == 'zsh': environ['POWERLINE_NO_ZSH_ZPYTHON'] = '1' sio = BytesIO() child = pexpect.spawn( args.command[0], args.command[1:], env=environ, logfile=sio, timeout=30, ) child.expect(re.compile(b'.*')) sleep(0.5) child.setwinsize(1, 300) with open(os.path.join('tests', 'test_shells', 'inputs', shell), 'rb') as F: if not args.wait_for_echo: child.send(F.read()) else: for line in F: child.send(line) sleep(1) # TODO Implement something more smart with open(full_log_file_name, 'wb') as LF: while True: try: s = child.read_nonblocking(1000) except pexpect.TIMEOUT: break except pexpect.EOF: break else: LF.write(s) child.close(force=True) check_call([ os.path.join(test_root, 'path', 'python'), os.path.join('tests', 'test_shells', 'postproc.py'), test_type, test_client, shell ]) pidfile = os.path.join(test_root, '3rd', 'pid') if os.path.exists(pidfile): os.unlink(pidfile) if __name__ == '__main__': main() powerline-2.8.4/tests/test_shells/test.sh000077500000000000000000000333601466405252600205610ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh enter_suite shell final if test $# -eq 0 ; then FAST=1 fi ONLY_SHELL="$1" ONLY_TEST_TYPE="$2" ONLY_TEST_CLIENT="$3" export PYTHON if test "$ONLY_SHELL" = "--help" ; then cat << EOF Usage: $0 [[[ONLY_SHELL | ""] (ONLY_TEST_TYPE | "")] (ONLY_TEST_CLIENT | "")] ONLY_SHELL: execute only tests for given shell ONLY_TEST_TYPE: execute only "daemon" or "nodaemon" tests ONLY_TEST_CLIENT: use only given test client (one of C, python, render, shell) EOF exit 0 fi check_screen_log() { TEST_TYPE="$1" TEST_CLIENT="$2" SH="$3" if test -e "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" ; then diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.${TEST_TYPE}.ok" \ "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" return $? elif test -e "$ROOT/tests/test_shells/outputs/${SH}.ok" ; then diff -a -u "$ROOT/tests/test_shells/outputs/${SH}.ok" \ "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" return $? else cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" return 1 fi } # HACK: get newline for use in strings given that "\n" and $'' do not work. NL="$(printf '\nE')" NL="${NL%E}" print_full_output() { TEST_TYPE="$1" TEST_CLIENT="$2" SH="$3" echo "Full output:" echo '============================================================' cat "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log" echo echo '____________________________________________________________' if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then echo "Full output (cat -v):" echo '============================================================' cat -v "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log" echo echo '____________________________________________________________' fi } do_run_test() { TEST_TYPE="$1" shift TEST_CLIENT="$1" shift SH="$1" local wait_for_echo_arg= if ( \ test "${SH}" = "dash" \ || ( \ test "${SH}" = "pdb" \ && ( \ ( \ test "$PYTHON_VERSION_MAJOR" -eq 3 \ && test "$PYTHON_VERSION_MINOR" -eq 2 \ && test "$PYTHON_IMPLEMENTATION" = "CPython" \ ) \ || test "$PYTHON_IMPLEMENTATION" = "PyPy" \ ) \ ) \ || ( \ test "${SH}" = "ipython" \ && test "$("${PYTHON}" -mIPython --version | head -n1 | cut -d. -f1)" -ge 5 \ ) \ ) ; then wait_for_echo_arg="--wait-for-echo" fi "${PYTHON}" tests/test_shells/run_script.py \ $wait_for_echo_arg --type=${TEST_TYPE} --client=${TEST_CLIENT} --shell=${SH} \ "$@" if ! check_screen_log ${TEST_TYPE} ${TEST_CLIENT} ${SH} ; then echo '____________________________________________________________' if test "$POWERLINE_TEST_NO_CAT_V" != "1" ; then # Repeat the diff to make it better viewable in travis output echo "Diff (cat -v):" echo '============================================================' check_screen_log ${TEST_TYPE} ${TEST_CLIENT} ${SH} | cat -v echo '____________________________________________________________' fi echo -n "Failed ${SH}. " print_full_output ${TEST_TYPE} ${TEST_CLIENT} ${SH} case "${SH}" in *ksh) "$TEST_ROOT/path/${SH}" -c 'echo ${KSH_VERSION}' ;; dash) # ? ;; busybox) busybox --help ;; *) "$TEST_ROOT/path/${SH}" --version ;; esac if which dpkg >/dev/null ; then dpkg -s ${SH} fi return 1 fi return 0 } run_test() { TEST_TYPE="$1" TEST_CLIENT="$2" SH="$3" local attempts=3 if test -n "$ONLY_SHELL$ONLY_TEST_TYPE$ONLY_TEST_CLIENT" ; then attempts=1 fi while test $attempts -gt 0 ; do rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log" rm -f "$TEST_ROOT/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log" do_run_test "$@" && return 0 attempts=$(( attempts - 1 )) done return 1 } make_test_root git init "$TEST_ROOT/3rd" git --git-dir="$TEST_ROOT/3rd/.git" checkout -b BRANCH export DIR1="" export DIR2="" mkdir "$TEST_ROOT/3rd/$DIR1" mkdir "$TEST_ROOT/3rd/$DIR2" mkdir "$TEST_ROOT"/3rd/'\[\]' mkdir "$TEST_ROOT"/3rd/'%%' mkdir "$TEST_ROOT"/3rd/'#[bold]' mkdir "$TEST_ROOT"/3rd/'(echo)' mkdir "$TEST_ROOT"/3rd/'$(echo)' mkdir "$TEST_ROOT"/3rd/'`echo`' mkdir "$TEST_ROOT"/3rd/'«Unicode!»' mkdir "$TEST_ROOT/fish_home" mkdir "$TEST_ROOT/fish_home/fish" mkdir "$TEST_ROOT/fish_home/fish/generated_completions" cp -r "$ROOT/tests/test_shells/ipython_home" "$TEST_ROOT" mkdir "$TEST_ROOT/path" ln -s "$(which "${PYTHON}")" "$TEST_ROOT/path/python" ln -s "$(which env)" "$TEST_ROOT/path" ln -s "$(which git)" "$TEST_ROOT/path" ln -s "$(which sleep)" "$TEST_ROOT/path" ln -s "$(which cat)" "$TEST_ROOT/path" ln -s "$(which false)" "$TEST_ROOT/path" ln -s "$(which true)" "$TEST_ROOT/path" ln -s "$(which kill)" "$TEST_ROOT/path" ln -s "$(which echo)" "$TEST_ROOT/path" ln -s "$(which which)" "$TEST_ROOT/path" ln -s "$(which dirname)" "$TEST_ROOT/path" ln -s "$(which wc)" "$TEST_ROOT/path" ln -s "$(which stty)" "$TEST_ROOT/path" ln -s "$(which cut)" "$TEST_ROOT/path" ln -s "$(which bc)" "$TEST_ROOT/path" ln -s "$(which expr)" "$TEST_ROOT/path" ln -s "$(which mktemp)" "$TEST_ROOT/path" ln -s "$(which grep)" "$TEST_ROOT/path" ln -s "$(which sed)" "$TEST_ROOT/path" ln -s "$(which rm)" "$TEST_ROOT/path" ln -s "$(which tr)" "$TEST_ROOT/path" ln -s "$(which uname)" "$TEST_ROOT/path" ln -s "$(which test)" "$TEST_ROOT/path" ln -s "$(which pwd)" "$TEST_ROOT/path" ln -s "$(which hostname)" "$TEST_ROOT/path" ln -s "$ROOT/tests/test_shells/bgscript.sh" "$TEST_ROOT/path" ln -s "$ROOT/tests/test_shells/waitpid.sh" "$TEST_ROOT/path" if which socat ; then ln -s "$(which socat)" "$TEST_ROOT/path" fi for pexe in powerline powerline-config powerline-render powerline.sh powerline.py ; do if test -e "$ROOT/scripts/$pexe" ; then ln -s "$ROOT/scripts/$pexe" "$TEST_ROOT/path" elif test -e client/$pexe ; then ln -s "$ROOT/client/$pexe" "$TEST_ROOT/path" elif which $pexe ; then ln -s "$(which $pexe)" "$TEST_ROOT/path" else echo "Executable $pexe was not found" exit 1 fi done ln -s python "$TEST_ROOT/path/pdb" PDB_PYTHON=pdb ln -s python "$TEST_ROOT/path/ipython" IPYTHON_PYTHON=ipython if test -z "$POWERLINE_RC_EXE" ; then if which rc-status >/dev/null ; then # On Gentoo `rc` executable is from OpenRC. Thus app-shells/rc instals # `rcsh` executable. POWERLINE_RC_EXE=rcsh else POWERLINE_RC_EXE=rc fi fi if which "$POWERLINE_RC_EXE" >/dev/null ; then ln -s "$(which $POWERLINE_RC_EXE)" "$TEST_ROOT/path/rc" fi exes="bash zsh busybox tcsh mksh" if test "$TRAVIS" != "true" ; then # For some reason fish does not work on travis exes="$exes fish" fi # dash has some problems with job control #exes="$exes dash" for exe in $exes ; do if which $exe >/dev/null ; then if test "$exe" = "fish" ; then fish_version="$(fish --version 2>&1)" fish_version="${fish_version##* }" fish_version_major="${fish_version%%.*}" if test "$fish_version_major" != "$fish_version" ; then # No dot is in development version compiled by bot-ci fish_version_minor="${fish_version#*.}" fish_version_patch="${fish_version_minor#*.}" fish_version_dev="${fish_version_patch#*-}" if test "$fish_version_dev" = "$fish_version_patch" ; then fish_version_dev="" fi fish_version_minor="${fish_version_minor%%.*}" fish_version_patch="${fish_version_patch%%-*}" if test $fish_version_major -lt 2 || ( \ test $fish_version_major -eq 2 && (\ test $fish_version_minor -lt 1 || (\ test $fish_version_minor -eq 1 && test $fish_version_patch -lt 2 && \ test -z "$fish_version_dev" ) \ ) \ ) ; then continue fi fi fi ln -s "$(which $exe)" "$TEST_ROOT/path" fi done mkdir "$TEST_ROOT/home" export HOME="$TEST_ROOT/home" unset ENV export ADDRESS="powerline-ipc-test-$$" export PYTHON echo "Powerline address: $ADDRESS" check_test_client() { local executable="$1" local client_type="$2" local actual_mime_type="$( file --mime-type --brief --dereference "$TEST_ROOT/path/$executable" \ | cut -d/ -f1 )" local expected_mime_type case "$client_type" in C) expected_mime_type="application/x-executable" ;; python) expected_mime_type="text/x-python" ;; render) expected_mime_type="text/x-python" ;; shell) expected_mime_type="text/x-shellscript" ;; esac expected_mime_type="${expected_mime_type%/*}" if test "$expected_mime_type" != "$actual_mime_type" ; then fail "MIME-$executable" "M" "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type" fi } if ( \ test -z "${ONLY_SHELL}" \ || test "${ONLY_SHELL%sh}" != "${ONLY_SHELL}" \ || test "${ONLY_SHELL}" = "busybox" \ || test "${ONLY_SHELL}" = "rc" \ ) ; then scripts/powerline-config shell command for TEST_TYPE in "daemon" "nodaemon" ; do if test -n "$ONLY_TEST_TYPE" && test "$ONLY_TEST_TYPE" != "$TEST_TYPE" then continue fi if test "$FAST" = 1 ; then if test $TEST_TYPE = daemon ; then VARIANTS=3 else VARIANTS=4 fi EXETEST="$(( ${RANDOM:-`date +%N | sed s/^0*//`} % $VARIANTS ))" echo "Execute tests: $EXETEST" fi if test $TEST_TYPE = daemon ; then sh -c ' echo $$ > "$TEST_ROOT/daemon_pid" exec "$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -f >"$TEST_ROOT/daemon_log" 2>&1 ' & fi echo "> Testing $TEST_TYPE" I=-1 for POWERLINE_COMMAND in \ powerline \ powerline-render \ powerline.py \ powerline.sh do case "$POWERLINE_COMMAND" in powerline) TEST_CLIENT=C ;; powerline-render) TEST_CLIENT=render ;; powerline.py) TEST_CLIENT=python ;; powerline.sh) TEST_CLIENT=shell ;; esac check_test_client "$POWERLINE_COMMAND" $TEST_CLIENT if test "$TEST_CLIENT" = render && test "$TEST_TYPE" = daemon ; then continue fi I="$(( I + 1 ))" if test "$TEST_CLIENT" = "C" && ! test -x "$ROOT/scripts/powerline" then if which powerline >/dev/null ; then POWERLINE_COMMAND=powerline else continue fi fi if ( \ test "$TEST_CLIENT" = "shell" \ && ! test -x "$TEST_ROOT/path/socat" \ ) ; then continue fi if ( \ test -n "$ONLY_TEST_CLIENT" \ && test "$TEST_CLIENT" != "$ONLY_TEST_CLIENT" \ ) ; then continue fi export POWERLINE_COMMAND_ARGS="--socket $ADDRESS" export POWERLINE_COMMAND="$POWERLINE_COMMAND" echo ">> powerline command is ${POWERLINE_COMMAND:-empty}" J=-1 for TEST_COMMAND in \ "bash --norc --noprofile -i" \ "zsh -f -i" \ "fish -i" \ "tcsh -f -i" \ "busybox ash -i" \ "mksh -i" \ "dash -i" \ "rc -i -p" do J="$(( J + 1 ))" if test "$FAST" = 1 ; then if test $(( (I + J) % $VARIANTS )) -ne $EXETEST ; then continue fi fi SH="${TEST_COMMAND%% *}" if test -n "$ONLY_SHELL" && test "$ONLY_SHELL" != "$SH" ; then continue fi if ! test -x "$TEST_ROOT/path/$SH" ; then continue fi echo ">>> $(readlink "$TEST_ROOT/path/$SH")" if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then fail "$SH-$TEST_TYPE-$TEST_CLIENT:test" F \ "Failed checking $TEST_COMMAND" fi done done if test $TEST_TYPE = daemon ; then "$PYTHON" ./scripts/powerline-daemon -s"$ADDRESS" -k wait $(cat "$TEST_ROOT/daemon_pid") if ! test -z "$(cat "$TEST_ROOT/daemon_log")" ; then echo '____________________________________________________________' echo "Daemon log:" echo '============================================================' cat "$TEST_ROOT/daemon_log" fail "$SH-$TEST_TYPE-$TEST_CLIENT:log" E \ "Non-empty daemon log for ${TEST_COMMAND}" fi fi done fi if "$PYTHON" scripts/powerline-daemon -s"$ADDRESS" \ > "$TEST_ROOT/daemon_log_2" 2>&1 then sleep 1 "$PYTHON" scripts/powerline-daemon -s"$ADDRESS" -k else fail "daemon:run" F "Daemon exited with status $?" fi if ! test -z "$(cat "$TEST_ROOT/daemon_log_2")" ; then echo '____________________________________________________________' echo "Daemon log (2nd):" echo '============================================================' cat "$TEST_ROOT/daemon_log_2" fail "daemon:log" E "Daemon run with non-empty log" fi if ( test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "zsh" ) \ && ( test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "zpython" ) \ && "$TEST_ROOT/path/zsh" "$ROOT/tests/test_shells/zsh_test_script.zsh" then echo "> zpython" if ! run_test zpython zpython zsh -f -i ; then fail "zsh-zpython:test" F "Failed checking zsh -f -i" fi fi if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "pdb" ; then if test "$PYTHON_IMPLEMENTATION" != "PyPy" ; then if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "subclass" then echo "> pdb subclass" if ! run_test subclass python $PDB_PYTHON \ "$ROOT/tests/test_shells/pdb-main.py" then fail --allow-failure "pdb-subclass:test" F \ "Failed checking $PDB_PYTHON $ROOT/tests/test_shells/pdb-main.py" fi fi if test -z "${ONLY_TEST_TYPE}" || test "${ONLY_TEST_TYPE}" = "module" ; then echo "> pdb module" MODULE="powerline.bindings.pdb" if test "$PYTHON_MM" = "2.6" ; then MODULE="powerline.bindings.pdb.__main__" fi if ! run_test module python "$PDB_PYTHON" -m"$MODULE" \ "$ROOT/tests/test_shells/pdb-script.py" then fail --allow-failure "pdb-module:test" F \ "Failed checking $PDB_PYTHON -m$MODULE $ROOT/tests/test_shells/pdb-script" fi fi fi fi if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "ipython" ; then if "${PYTHON}" -c "try: import IPython${NL}except ImportError: raise SystemExit(1)" ; then # Define some overrides which should be ignored by IPython. export POWERLINE_CONFIG_OVERRIDES='common.term_escape_style=fbterm' export POWERLINE_THEME_OVERRIDES='in.segments.left=[]' echo "> ipython" if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then # Do not allow ipython tests to spoil the build fail --allow-failure "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython" fi unset POWERLINE_THEME_OVERRIDES unset POWERLINE_CONFIG_OVERRIDES fi fi exit_suite powerline-2.8.4/tests/test_shells/waitpid.sh000077500000000000000000000000641466405252600212360ustar00rootroot00000000000000#!/bin/sh while ! test -e pid ; do sleep 0.1s done powerline-2.8.4/tests/test_shells/zsh_test_script.zsh000066400000000000000000000006201466405252600232110ustar00rootroot00000000000000set -e set -x . tests/bot-ci/scripts/common/main.sh zmodload zpython || zmodload libzpython zpython 'import zsh' zpython 'import platform' zpython 'zsh.setvalue("ZSH_PYTHON_VERSION", platform.python_version())' zpython 'zsh.setvalue("ZSH_PYTHON_IMPLEMENTATION", platform.python_implementation())' [[ $ZSH_PYTHON_IMPLEMENTATION = $PYTHON_IMPLEMENTATION ]] [[ $ZSH_PYTHON_VERSION = $PYTHON_VERSION ]] powerline-2.8.4/tests/test_vim/000077500000000000000000000000001466405252600165375ustar00rootroot00000000000000powerline-2.8.4/tests/test_vim/pyfiles/000077500000000000000000000000001466405252600202125ustar00rootroot00000000000000powerline-2.8.4/tests/test_vim/pyfiles/setup_statusline_catcher.py000066400000000000000000000005741466405252600256760ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet import json import vim from powerline.lib.unicode import u _powerline_old_render = powerline.render # NOQA def _powerline_test_render_function(*args, **kwargs): ret = _powerline_old_render(*args, **kwargs) vim.eval('add(g:statusline_values, %s)' % json.dumps(u(ret))) return ret powerline.render = _powerline_test_render_function # NOQA powerline-2.8.4/tests/test_vim/test.sh000077500000000000000000000025071466405252600200610ustar00rootroot00000000000000#!/bin/sh . tests/shlib/common.sh . tests/shlib/vterm.sh . tests/shlib/vim.sh enter_suite vim final vterm_setup vim # Define some overrides. These ones must be ignored and do not affect Vim # status/tab lines. export POWERLINE_CONFIG_OVERRIDES='common.default_top_theme=ascii' export POWERLINE_THEME_OVERRIDES='default.segments.left=[]' test_script() { local vim="$1" ; shift local script="$1" ; shift local allow_failure_arg="$1" ; shift echo "Running script $script with $vim" if ! test -e "$vim" ; then return 0 fi if ! script="$script" "$vim" -u NONE -c 'source $script' \ || test -f message.fail then local test_name="${script##*/}" fail $allow_failure_arg "${test_name%.vim}" \ F "Failed script $script run with $vim" if test -e message.fail ; then cat message.fail >&2 rm message.fail fi fi } TEST_SCRIPT_ROOT="$ROOT/tests/test_vim/tests" cd "$TEST_ROOT" for script in "$TEST_SCRIPT_ROOT"/*.vim ; do if test "${script%.old.vim}" = "${script}" ; then test_script "$NEW_VIM" "$script" "" fi done if test "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR" = "2.7" ; then ALLOW_FAILURE_ARG=--allow-failure else ALLOW_FAILURE_ARG= fi if test -e "$OLD_VIM" ; then for script in "$TEST_SCRIPT_ROOT"/*.old.vim ; do test_script "$OLD_VIM" "$script" "$ALLOW_FAILURE_ARG" done fi vterm_shutdown exit_suite powerline-2.8.4/tests/test_vim/tests/000077500000000000000000000000001466405252600177015ustar00rootroot00000000000000powerline-2.8.4/tests/test_vim/tests/commandt_plugin.vim000077500000000000000000000015611466405252600236040ustar00rootroot00000000000000#!/usr/bin/vim -S set nocompatible set columns=80 execute 'source' fnameescape(expand(':p:h:h').'/vim_utils.vim') call EnablePlugins('command-t') call SourcePowerline() let g:statusline_values = [] call PyFile('setup_statusline_catcher') execute 'CommandTBuffer'|call feedkeys("\") call RunPython('powerline.render = _powerline_old_render') let g:expected_statusline = '%#Pl_231_16777215_240_5789784_bold# Command-T %#Pl_231_16777215_240_5789784_NONE# %#Pl_231_16777215_240_5789784_bold#BufferFinder %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE#                                                    ' call CheckMessages() if index(g:statusline_values, g:expected_statusline) == -1 call CheckStatuslineValue(get(g:statusline_values, -1, ''), g:expected_statusline) cquit endif qall powerline-2.8.4/tests/test_vim/tests/empty_encoding.old.vim000077500000000000000000000014261466405252600242050ustar00rootroot00000000000000#!/usr/bin/vim -S if has('multi_byte') if empty(&encoding) call writefile(['&encoding option value is empty, even though Vim has +multibyte'], 'message.fail') cquit endif qall endif if !empty(&encoding) call writefile(['&encoding option value is not empty, even though Vim does not have +multibyte'], 'message.fail') cquit endif let g:powerline_config_paths = [expand(':p:h:h:h:h') . '/powerline/config_files'] try source :p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim catch call writefile(['Unexpected exception:', v:exception], 'message.fail') cquit endtry set ls=2 redrawstatus! redir => g:messages messages redir END let mess=split(g:messages, "\n") if len(mess)>1 call writefile(['Unexpected message(s):']+mess, 'message.fail') cquit endif qall! powerline-2.8.4/tests/test_vim/tests/foreign_stl_override.vim000066400000000000000000000010611466405252600246260ustar00rootroot00000000000000scriptencoding utf-8 set encoding=utf-8 let g:powerline_config_paths = [expand(':p:h:h:h:h') . '/powerline/config_files'] set laststatus=2 redir => g:messages try source :p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim redrawstatus! vsplit redrawstatus! setlocal statusline=«» redrawstatus! catch call writefile(['Unexpected exception', v:exception], 'message.fail') cquit endtry redir END if g:messages =~# '\v\S' call writefile(['Unexpected messages'] + split(g:messages, "\n", 1), 'message.fail') cquit endif qall! powerline-2.8.4/tests/test_vim/tests/invalid_unicode.vim000066400000000000000000000007711466405252600235570ustar00rootroot00000000000000set encoding=utf-8 let g:powerline_config_paths = [expand(':p:h:h:h:h') . '/powerline/config_files'] set laststatus=2 set showtabline=2 edit `="\xFF"` redir => g:messages try source :p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim redrawstatus! catch call writefile(['Unexpected exception', v:exception], 'message.fail') cquit endtry redir END if g:messages =~# '\v\S' call writefile(['Unexpected messages'] + split(g:messages, "\n", 1), 'message.fail') cquit endif qall! powerline-2.8.4/tests/test_vim/tests/local_overrides.vim000077500000000000000000000030151466405252600235740ustar00rootroot00000000000000#!/usr/bin/vim -S set encoding=utf-8 let g:powerline_config_paths = [expand(':p:h:h:h:h') . '/powerline/config_files'] let g:powerline_config_overrides = {'common': {'default_top_theme': 'ascii'}} let g:powerline_theme_overrides = {'default': {'segment_data': {'line_current_symbol': {'contents': 'LN '}, 'branch': {'before': 'B '}}}} redir => g:messages try python import powerline.vim let pycmd = 'python' catch try python3 import powerline.vim let pycmd = 'python3' catch call writefile(['Unable to determine python version', v:exception], 'message.fail') cquit endtry endtry try execute pycmd 'powerline.vim.setup()' catch call writefile(['Failed to run setup function', v:exception], 'message.fail') cquit endtry try let &columns = 80 let result = eval(&statusline[2:]) catch call writefile(['Exception while evaluating &stl', v:exception], 'message.fail') cquit endtry if result isnot# '%#Pl_22_24320_148_11523840_bold# NORMAL %#Pl_148_11523840_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#unix%#Pl_240_5789784_236_3158064_NONE# %#Pl_247_10329757_240_5789784_NONE# 100%%%#Pl_252_13684944_240_5789784_NONE# %#Pl_235_2500134_252_13684944_NONE# LN %#Pl_235_2500134_252_13684944_bold# 1%#Pl_22_24576_252_13684944_NONE#:1 ' call writefile(['Unexpected result', result], 'message.fail') cquit endif redir END if g:messages =~ '\S' call writefile(['Non-empty messages:', g:messages], 'message.fail') cquit endif qall! powerline-2.8.4/tests/test_vim/tests/nerdtree_plugin.vim000077500000000000000000000006471466405252600236160ustar00rootroot00000000000000#!/usr/bin/vim -S set nocompatible set columns=80 execute 'source' fnameescape(expand(':p:h:h').'/vim_utils.vim') call EnablePlugins('nerdtree') call SourcePowerline() NERDTree /home redrawstatus call CheckCurrentStatusline('%#Pl_231_16777215_240_5789784_bold# /home %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE#                      ') call CheckMessages() qall powerline-2.8.4/tests/test_vim/tests/plugin_file.vim000077500000000000000000000006741466405252600227250ustar00rootroot00000000000000#!/usr/bin/vim -S set encoding=utf-8 let g:powerline_config_paths = [expand(':p:h:h:h:h') . '/powerline/config_files'] tabedit abc tabedit def try source :p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim catch call writefile([v:exception], 'message.fail') cquit endtry set ls=2 redrawstatus! redir =>mes messages redir END let mess=split(mes, "\n") if len(mess)>1 call writefile(mess, 'message.fail') cquit endif qall! powerline-2.8.4/tests/test_vim/tests/tabline.vim000077500000000000000000000051011466405252600220340ustar00rootroot00000000000000#!/usr/bin/vim -S set encoding=utf-8 let g:powerline_config_paths = [expand(':p:h:h:h:h') . '/powerline/config_files'] source :p:h:h:h:h/powerline/bindings/vim/plugin/powerline.vim edit abc tabedit def tabedit ghi redir => g:messages try let &columns = 80 let result = eval(&tabline[2:]) catch call writefile(['Exception while evaluating &tabline', v:exception], 'message.fail') cquit endtry if result isnot# '%1T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %2T%#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %3T%#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %T%#Pl_231_16777215_236_3158064_NONE#                                         %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Tabs ' call writefile(['Unexpected tabline', result], 'message.fail') cquit endif tabonly! try let result = eval(&tabline[2:]) catch call writefile(['Exception while evaluating &tabline (2)', v:exception], 'message.fail') cquit endtry if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE#                                         %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs ' call writefile(['Unexpected tabline (2)', result], 'message.fail') cquit endif try vsplit let result = eval(&tabline[2:]) catch call writefile(['Exception while evaluating &tabline (3)', v:exception], 'message.fail') endtry if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE#                                         %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs ' call writefile(['Unexpected tabline (3)', result], 'message.fail') cquit endif redir END if g:messages =~ '\S' call writefile(['Non-empty messages:', g:messages], 'message.fail') cquit endif qall! powerline-2.8.4/tests/test_vim/vim_utils.vim000066400000000000000000000051061466405252600212710ustar00rootroot00000000000000let g:powerline_use_var_handler = 1 let g:pyfiles_root=expand(':p:h').'/pyfiles' let g:root=expand(':p:h:h:h') let g:mf=fnamemodify('message.fail', ':p') command -nargs=1 LST :call writefile(, g:mf, 'a') | cquit command -nargs=1 ERR :LST [] command -nargs=1 EXC :ERR 'Unexpected exception', , v:exception, v:throwpoint function EnablePlugins(...) let &runtimepath = join(map(copy(a:000), 'escape(g:root."/tests/vim-plugins/".v:val, "\\,")'), ',') try runtime! plugin/*.vim silent doautocmd BufWinEnter silent doautocmd BufEnter silent doautocmd VimEnter catch EXC EnablePlugins endtry endfunction function RecordStatusline() let g:statusline = &l:statusline if g:statusline[:1] is# '%!' let g:statusline_value=eval(g:statusline[2:]) else ERR 'Statusline does not start with %!', g:statusline endif return '' endfunction function SourcePowerline() let g:powerline_config_paths = [g:root . '/powerline/config_files'] try execute 'source' fnameescape(g:root . '/powerline/bindings/vim/plugin/powerline.vim') catch EXC SourcePowerline endtry endfunction function NDiff(actual, expected) return systemlist(shellescape(g:root.'/tests/bot-ci/scripts/ndiff-strings.py').' '.shellescape(a:actual).' '.shellescape(a:expected)) endfunction function CheckStatuslineValue(actual, expected) if a:actual isnot# a:expected LST ['Expected different statusline value', a:actual, a:expected] + NDiff(a:actual, a:expected) endif endfunction function CheckRecordedStatuslineValue(expected) return CheckStatuslineValue(g:statusline_value, a:expected) endfunction function GetCurrentStatusline() if &l:statusline[:1] isnot# '%!' ERR 'Statusline does not start with %!', &l:statusline endif return eval(&l:statusline[2:]) endfunction function CheckCurrentStatusline(expected) return CheckStatuslineValue(GetCurrentStatusline(), a:expected) endfunction function CheckMessages() if !empty(g:powerline_log_messages) LST ['Unexpected messages in log'] + g:powerline_log_messages endif redir => mes messages redir END let mesl = split(mes, "\n")[1:] if !empty(mesl) LST ['Unexpected messages'] + split(mes, "\n", 1) endif endfunction function RunPython(s) if has('python') execute 'python' a:s else execute 'python3' a:s endif endfunction function PyFile(f) if has('python') execute 'pyfile' fnameescape(g:pyfiles_root.'/'.a:f.'.py') else execute 'py3file' fnameescape(g:pyfiles_root.'/'.a:f.'.py') endif endfunction for s:c in ['noremap', 'noremap!'] execute s:c '' '(PowerlineTestRecordStatusline)' 'RecordStatusline()' endfor powerline-2.8.4/tests/vim_sys_path/000077500000000000000000000000001466405252600174125ustar00rootroot00000000000000powerline-2.8.4/tests/vim_sys_path/vim.py000066400000000000000000000002641466405252600205610ustar00rootroot00000000000000# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import tests.modules.vim as vim globals().update(vim._init()) powerline-2.8.4/tools/000077500000000000000000000000001466405252600147035ustar00rootroot00000000000000powerline-2.8.4/tools/colors.map000066400000000000000000000255371466405252600167170ustar00rootroot00000000000000Grey 545454 Grey, Silver C0C0C0 grey BEBEBE LightGray D3D3D3 LightSlateGrey 778899 SlateGray 708090 SlateGray1 C6E2FF SlateGray2 B9D3EE SlateGray3 9FB6CD SlateGray4 6C7B8B black 000000 grey0 000000 grey1 030303 grey2 050505 grey3 080808 grey4 0A0A0A grey5 0D0D0D grey6 0F0F0F grey7 121212 grey8 141414 grey9 171717 grey10 1A1A1A grey11 1C1C1C grey12 1F1F1F grey13 212121 grey14 242424 grey15 262626 grey16 292929 grey17 2B2B2B grey18 2E2E2E grey19 303030 grey20 333333 grey21 363636 grey22 383838 grey23 3B3B3B grey24 3D3D3D grey25 404040 grey26 424242 grey27 454545 grey28 474747 grey29 4A4A4A grey30 4D4D4D grey31 4F4F4F grey32 525252 grey33 545454 grey34 575757 grey35 595959 grey36 5C5C5C grey37 5E5E5E grey38 616161 grey39 636363 grey40 666666 grey41, DimGrey 696969 grey42 6B6B6B grey43 6E6E6E grey44 707070 grey45 737373 grey46 757575 grey47 787878 grey48 7A7A7A grey49 7D7D7D grey50 7F7F7F grey51 828282 grey52 858585 grey53 878787 grey54 8A8A8A grey55 8C8C8C grey56 8F8F8F grey57 919191 grey58 949494 grey59 969696 grey60 999999 grey61 9C9C9C grey62 9E9E9E grey63 A1A1A1 grey64 A3A3A3 grey65 A6A6A6 grey66 A8A8A8 grey67 ABABAB grey68 ADADAD grey69 B0B0B0 grey70 B3B3B3 grey71 B5B5B5 grey72 B8B8B8 grey73 BABABA grey74 BDBDBD grey75 BFBFBF grey76 C2C2C2 grey77 C4C4C4 grey78 C7C7C7 grey79 C9C9C9 grey80 CCCCCC grey81 CFCFCF grey82 D1D1D1 grey83 D4D4D4 grey84 D6D6D6 grey85 D9D9D9 grey86 DBDBDB grey87 DEDEDE grey88 E0E0E0 grey89 E3E3E3 grey90 E5E5E5 grey91 E8E8E8 grey92 EBEBEB grey93 EDEDED grey94 F0F0F0 grey95 F2F2F2 grey96 F5F5F5 grey97 F7F7F7 grey98 FAFAFA grey99 FCFCFC grey100, White FFFFFF Dark Slate Grey 2F4F4F Dim Grey 545454 Very Light Grey CDCDCD Free Speech Grey 635688 AliceBlue F0F8FF BlueViolet 8A2BE2 Cadet Blue 5F9F9F CadetBlue 5F9EA0 CadetBlue 5F9EA0 CadetBlue1 98F5FF CadetBlue2 8EE5EE CadetBlue3 7AC5CD CadetBlue4 53868B Corn Flower Blue 42426F CornflowerBlue 6495ED DarkSlateBlue 483D8B DarkTurquoise 00CED1 DeepSkyBlue 00BFFF DeepSkyBlue1 00BFFF DeepSkyBlue2 00B2EE DeepSkyBlue3 009ACD DeepSkyBlue4 00688B DodgerBlue 1E90FF DodgerBlue1 1E90FF DodgerBlue2 1C86EE DodgerBlue3 1874CD DodgerBlue4 104E8B LightBlue ADD8E6 LightBlue1 BFEFFF LightBlue2 B2DFEE LightBlue3 9AC0CD LightBlue4 68838B LightCyan E0FFFF LightCyan1 E0FFFF LightCyan2 D1EEEE LightCyan3 B4CDCD LightCyan4 7A8B8B LightSkyBlue 87CEFA LightSkyBlue1 B0E2FF LightSkyBlue2 A4D3EE LightSkyBlue3 8DB6CD LightSkyBlue4 607B8B LightSlateBlue 8470FF LightSteelBlue B0C4DE LightSteelBlue1 CAE1FF LightSteelBlue2 BCD2EE LightSteelBlue3 A2B5CD LightSteelBlue4 6E7B8B Aquamarine 70DB93 MediumBlue 0000CD MediumSlateBlue 7B68EE MediumTurquoise 48D1CC MidnightBlue 191970 NavyBlue 000080 PaleTurquoise AFEEEE PaleTurquoise1 BBFFFF PaleTurquoise2 AEEEEE PaleTurquoise3 96CDCD PaleTurquoise4 668B8B PowderBlue B0E0E6 RoyalBlue 4169E1 RoyalBlue1 4876FF RoyalBlue2 436EEE RoyalBlue3 3A5FCD RoyalBlue4 27408B RoyalBlue5 002266 SkyBlue 87CEEB SkyBlue1 87CEFF SkyBlue2 7EC0EE SkyBlue3 6CA6CD SkyBlue4 4A708B SlateBlue 6A5ACD SlateBlue1 836FFF SlateBlue2 7A67EE SlateBlue3 6959CD SlateBlue4 473C8B SteelBlue 4682B4 SteelBlue1 63B8FF SteelBlue2 5CACEE SteelBlue3 4F94CD SteelBlue4 36648B aquamarine 7FFFD4 aquamarine1 7FFFD4 aquamarine2 76EEC6 aquamarine3, MediumAquamarine 66CDAA aquamarine4 458B74 azure F0FFFF azure1 F0FFFF azure2 E0EEEE azure3 C1CDCD azure4 838B8B blue 0000FF blue1 0000FF blue2 0000EE blue3 0000CD blue4 00008B aqua 00FFFF True Iris Blue 03B4CC cyan 00FFFF cyan1 00FFFF cyan2 00EEEE cyan3 00CDCD cyan4 008B8B navy 000080 teal 008080 turquoise 40E0D0 turquoise1 00F5FF turquoise2 00E5EE turquoise3 00C5CD turquoise4 00868B DarkSlateGray 2F4F4F DarkSlateGray1 97FFFF DarkSlateGray2 8DEEEE DarkSlateGray3 79CDCD DarkSlateGray4 528B8B Dark Slate Blue 241882 Dark Turquoise 7093DB Medium Slate Blue 7F00FF Medium Turquoise 70DBDB Midnight Blue 2F2F4F Navy Blue 23238E Neon Blue 4D4DFF New Midnight Blue 00009C Rich Blue 5959AB Sky Blue 3299CC Slate Blue 007FFF Summer Sky 38B0DE Iris Blue 03B4C8 Free Speech Blue 4156C5 RosyBrown BC8F8F RosyBrown1 FFC1C1 RosyBrown2 EEB4B4 RosyBrown3 CD9B9B RosyBrown4 8B6969 SaddleBrown 8B4513 SandyBrown F4A460 beige F5F5DC brown A52A2A brown A62A2A brown1 FF4040 brown2 EE3B3B brown3 CD3333 brown4 8B2323 dark brown 5C4033 burlywood DEB887 burlywood1 FFD39B burlywood2 EEC591 burlywood3 CDAA7D burlywood4 8B7355 baker's chocolate 5C3317 chocolate D2691E chocolate1 FF7F24 chocolate2 EE7621 chocolate3 CD661D chocolate4 8B4513 peru CD853F tan D2B48C tan1 FFA54F tan2 EE9A49 tan3 CD853F tan4 8B5A2B Dark Tan 97694F Dark Wood 855E42 Light Wood 856363 Medium Wood A68064 New Tan EBC79E Semi-Sweet Chocolate 6B4226 Sienna 8E6B23 Tan DB9370 Very Dark Brown 5C4033 Dark Green 2F4F2F DarkGreen 006400 dark green copper 4A766E DarkKhaki BDB76B DarkOliveGreen 556B2F DarkOliveGreen1 CAFF70 DarkOliveGreen2 BCEE68 DarkOliveGreen3 A2CD5A DarkOliveGreen4 6E8B3D olive 808000 DarkSeaGreen 8FBC8F DarkSeaGreen1 C1FFC1 DarkSeaGreen2 B4EEB4 DarkSeaGreen3 9BCD9B DarkSeaGreen4 698B69 ForestGreen 228B22 GreenYellow ADFF2F LawnGreen 7CFC00 LightSeaGreen 20B2AA LimeGreen 32CD32 MediumSeaGreen 3CB371 MediumSpringGreen 00FA9A MintCream F5FFFA OliveDrab 6B8E23 OliveDrab1 C0FF3E OliveDrab2 B3EE3A OliveDrab3 9ACD32 OliveDrab4 698B22 PaleGreen 98FB98 PaleGreen1 9AFF9A PaleGreen2 90EE90 PaleGreen3 7CCD7C PaleGreen4 548B54 SeaGreen, SeaGreen4 2E8B57 SeaGreen1 54FF9F SeaGreen2 4EEE94 SeaGreen3 43CD80 SpringGreen 00FF7F SpringGreen1 00FF7F SpringGreen2 00EE76 SpringGreen3 00CD66 SpringGreen4 008B45 YellowGreen 9ACD32 chartreuse 7FFF00 chartreuse1 7FFF00 chartreuse2 76EE00 chartreuse3 66CD00 chartreuse4 458B00 green 00FF00 green 008000 lime 00FF00 green1 00FF00 green2 00EE00 green3 00CD00 green4 008B00 khaki F0E68C khaki1 FFF68F khaki2 EEE685 khaki3 CDC673 khaki4 8B864E Dark Olive Green 4F4F2F Green Yellow [sic] D19275 Hunter Green [sic] 8E2323 Forest Green, Khaki, Medium Aquamarine 238E23 Medium Forest Green DBDB70 Medium Sea Green 426F42 Medium Spring Green 7FFF00 Pale Green 8FBC8F Sea Green 238E68 Spring Green 00FF7F Free Speech Green 09F911 Free Speech Aquamarine 029D74 DarkOrange FF8C00 DarkOrange1 FF7F00 DarkOrange2 EE7600 DarkOrange3 CD6600 DarkOrange4 8B4500 DarkSalmon E9967A LightCoral F08080 LightSalmon FFA07A LightSalmon1 FFA07A LightSalmon2 EE9572 LightSalmon3 CD8162 LightSalmon4 8B5742 PeachPuff FFDAB9 PeachPuff1 FFDAB9 PeachPuff2 EECBAD PeachPuff3 CDAF95 PeachPuff4 8B7765 bisque FFE4C4 bisque1 FFE4C4 bisque2 EED5B7 bisque3 CDB79E bisque4 8B7D6B coral FF7F00 coral FF7F50 coral1 FF7256 coral2 EE6A50 coral3 CD5B45 coral4 8B3E2F honeydew F0FFF0 honeydew1 F0FFF0 honeydew2 E0EEE0 honeydew3 C1CDC1 honeydew4 838B83 orange FFA500 orange1 FFA500 orange2 EE9A00 orange3 CD8500 orange4 8B5A00 salmon FA8072 salmon1 FF8C69 salmon2 EE8262 salmon3 CD7054 salmon4 8B4C39 sienna A0522D sienna1 FF8247 sienna2 EE7942 sienna3 CD6839 sienna4 8B4726 Mandarian Orange 8E2323 Orange FF7F00 Orange Red FF2400 DeepPink FF1493 DeepPink1 FF1493 DeepPink2 EE1289 DeepPink3 CD1076 DeepPink4 8B0A50 HotPink FF69B4 HotPink1 FF6EB4 HotPink2 EE6AA7 HotPink3 CD6090 HotPink4 8B3A62 IndianRed CD5C5C IndianRed1 FF6A6A IndianRed2 EE6363 IndianRed3 CD5555 IndianRed4 8B3A3A LightPink FFB6C1 LightPink1 FFAEB9 LightPink2 EEA2AD LightPink3 CD8C95 LightPink4 8B5F65 MediumVioletRed C71585 MistyRose FFE4E1 MistyRose1 FFE4E1 MistyRose2 EED5D2 MistyRose3 CDB7B5 MistyRose4 8B7D7B OrangeRed FF4500 OrangeRed1 FF4500 OrangeRed2 EE4000 OrangeRed3 CD3700 OrangeRed4 8B2500 PaleVioletRed DB7093 PaleVioletRed1 FF82AB PaleVioletRed2 EE799F PaleVioletRed3 CD6889 PaleVioletRed4 8B475D VioletRed D02090 VioletRed1 FF3E96 VioletRed2 EE3A8C VioletRed3 CD3278 VioletRed4 8B2252 firebrick B22222 firebrick1 FF3030 firebrick2 EE2C2C firebrick3 CD2626 firebrick4 8B1A1A pink FFC0CB pink1 FFB5C5 pink2 EEA9B8 pink3 CD919E pink4 8B636C Flesh F5CCB0 Feldspar D19275 red FF0000 red1 FF0000 red2 EE0000 red3 CD0000 red4 8B0000 tomato FF6347 tomato1 FF6347 tomato2 EE5C42 tomato3 CD4F39 tomato4 8B3626 Dusty Rose 856363 Firebrick 8E2323 Indian Red F5CCB0 Pink BC8F8F Salmon 6F4242 Scarlet 8C1717 Spicy Pink FF1CAE Free Speech Magenta E35BD8 Free Speech Red C00000 DarkOrchid 9932CC DarkOrchid1 BF3EFF DarkOrchid2 B23AEE DarkOrchid3 9A32CD DarkOrchid4 68228B DarkViolet 9400D3 LavenderBlush FFF0F5 LavenderBlush1 FFF0F5 LavenderBlush2 EEE0E5 LavenderBlush3 CDC1C5 LavenderBlush4 8B8386 MediumOrchid BA55D3 MediumOrchid1 E066FF MediumOrchid2 D15FEE MediumOrchid3 B452CD MediumOrchid4 7A378B MediumPurple 9370DB Medium Orchid 9370DB MediumPurple1 AB82FF Dark Orchid 9932CD MediumPurple2 9F79EE MediumPurple3 8968CD MediumPurple4 5D478B lavender E6E6FA magenta FF00FF fuchsia FF00FF magenta1 FF00FF magenta2 EE00EE magenta3 CD00CD magenta4 8B008B maroon B03060 maroon1 FF34B3 maroon2 EE30A7 maroon3 CD2990 maroon4 8B1C62 orchid DA70D6 Orchid DB70DB orchid1 FF83FA orchid2 EE7AE9 orchid3 CD69C9 orchid4 8B4789 plum DDA0DD plum1 FFBBFF plum2 EEAEEE plum3 CD96CD plum4 8B668B purple A020F0 purple 800080 purple1 9B30FF purple2 912CEE purple3 7D26CD purple4 551A8B thistle D8BFD8 thistle1 FFE1FF thistle2 EED2EE thistle3 CDB5CD thistle4 8B7B8B violet EE82EE violet blue 9F5F9F Dark Purple 871F78 Maroon 800000 Medium Violet Red DB7093 Neon Pink FF6EC7 Plum EAADEA Thistle D8BFD8 Turquoise ADEAEA Violet 4F2F4F Violet Red CC3299 AntiqueWhite FAEBD7 AntiqueWhite1 FFEFDB AntiqueWhite2 EEDFCC AntiqueWhite3 CDC0B0 AntiqueWhite4 8B8378 FloralWhite FFFAF0 GhostWhite F8F8FF NavajoWhite FFDEAD NavajoWhite1 FFDEAD NavajoWhite2 EECFA1 NavajoWhite3 CDB38B NavajoWhite4 8B795E OldLace FDF5E6 WhiteSmoke F5F5F5 gainsboro DCDCDC ivory FFFFF0 ivory1 FFFFF0 ivory2 EEEEE0 ivory3 CDCDC1 ivory4 8B8B83 linen FAF0E6 seashell FFF5EE seashell1 FFF5EE seashell2 EEE5DE seashell3 CDC5BF seashell4 8B8682 snow FFFAFA snow1 FFFAFA snow2 EEE9E9 snow3 CDC9C9 snow4 8B8989 wheat F5DEB3 wheat1 FFE7BA wheat2 EED8AE wheat3 CDBA96 wheat4 8B7E66 white FFFFFF Quartz D9D9F3 Wheat D8D8BF BlanchedAlmond FFEBCD DarkGoldenrod B8860B DarkGoldenrod1 FFB90F DarkGoldenrod2 EEAD0E DarkGoldenrod3 CD950C DarkGoldenrod4 8B6508 LemonChiffon FFFACD LemonChiffon1 FFFACD LemonChiffon2 EEE9BF LemonChiffon3 CDC9A5 LemonChiffon4 8B8970 LightGoldenrod EEDD82 LightGoldenrod1 FFEC8B LightGoldenrod2 EEDC82 LightGoldenrod3 CDBE70 LightGoldenrod4 8B814C LightGoldenrodYellow FAFAD2 LightYellow FFFFE0 LightYellow1 FFFFE0 LightYellow2 EEEED1 LightYellow3 CDCDB4 LightYellow4 8B8B7A PaleGoldenrod EEE8AA PapayaWhip FFEFD5 cornsilk FFF8DC cornsilk1 FFF8DC cornsilk2 EEE8CD cornsilk3 CDC8B1 cornsilk4 8B8878 goldenrod DAA520 goldenrod1 FFC125 goldenrod2 EEB422 goldenrod3 CD9B1D goldenrod4 8B6914 moccasin FFE4B5 yellow FFFF00 yellow1 FFFF00 yellow2 EEEE00 yellow3 CDCD00 yellow4 8B8B00 gold FFD700 gold1 FFD700 gold2 EEC900 gold3 CDAD00 gold4 8B7500 Goldenrod DBDB70 Medium Goldenrod EAEAAE Yellow Green 99CC32 copper B87333 cool copper D98719 Green Copper 856363 brass B5A642 bronze 8C7853 bronze II A67D3D bright gold D9D919 Old Gold CFB53B CSS Gold CC9900 gold CD7F32 silver E6E8FA Silver, Grey C0C0C0 Light Steel Blue 545454 Steel Blue 236B8E powerline-2.8.4/tools/colors_find.py000077500000000000000000000032071466405252600175630ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import os from colormath.color_objects import sRGBColor, LabColor from colormath.color_conversions import convert_color from colormath.color_diff import delta_e_cie2000 def get_lab(name, rgb): rgb = sRGBColor( int(rgb[:2], 16), int(rgb[2:4], 16), int(rgb[4:6], 16), is_upscaled=True ) lab = convert_color(rgb, LabColor) return name, lab with open(os.path.join(os.path.dirname(__file__), 'colors.map'), 'r') as f: colors = [get_lab(*line.split('\t')) for line in f] ulab = get_lab(None, sys.argv[1])[1] def find_color(urgb, colors): cur_distance = 3 * (255 ** 2 + 1) cur_color = None for color, clab in colors: dist = delta_e_cie2000(ulab, clab) if dist < cur_distance: cur_distance = dist cur_color = (color, clab) return cur_color cur_color = find_color(ulab, colors) def lab_to_csi(lab): rgb = convert_color(lab, sRGBColor) colstr = ';2;' + ';'.join((str(i) for i in get_upscaled_values(rgb))) return colstr + 'm' def get_upscaled_values(rgb): return [min(max(0, i), 255) for i in rgb.get_upscaled_value_tuple()] def get_rgb(lab): rgb = convert_color(lab, sRGBColor) rgb = sRGBColor(*get_upscaled_values(rgb), is_upscaled=True) return rgb.get_rgb_hex()[1:] print(get_rgb(ulab), ':', cur_color[0], ':', get_rgb(cur_color[1])) col_1 = lab_to_csi(ulab) col_2 = lab_to_csi(cur_color[1]) sys.stdout.write('\033[48' + col_1 + '\033[38' + col_2 + 'abc\033[0m <-- bg:urgb, fg:crgb\n') sys.stdout.write('\033[48' + col_2 + '\033[38' + col_1 + 'abc\033[0m <-- bg:crgb, fg:urgb\n') powerline-2.8.4/tools/generate_gradients.py000077500000000000000000000135541466405252600211220ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet '''Gradients generator ''' from __future__ import (unicode_literals, division, absolute_import, print_function) import sys import json import argparse from itertools import groupby from colormath.color_objects import sRGBColor, LabColor from colormath.color_conversions import convert_color from colormath.color_diff import delta_e_cie2000 from powerline.colorscheme import cterm_to_hex def num2(s): try: return (True, [int(v) for v in s.partition(' ')[::2]]) except TypeError: return (False, [float(v) for v in s.partition(' ')[::2]]) def rgbint_to_lab(rgbint): rgb = sRGBColor( (rgbint >> 16) & 0xFF, (rgbint >> 8) & 0xFF, rgbint & 0xFF, is_upscaled=True ) return convert_color(rgb, LabColor) cterm_to_lab = tuple((rgbint_to_lab(v) for v in cterm_to_hex)) def color(s): if len(s) <= 3: return cterm_to_lab[int(s)] else: return rgbint_to_lab(int(s, 16)) def nums(s): return [int(i) for i in s.split()] def linear_gradient(start_value, stop_value, start_offset, stop_offset, offset): return start_value + ((offset - start_offset) * (stop_value - start_value) / (stop_offset - start_offset)) def lab_gradient(slab, elab, soff, eoff, off): svals = slab.get_value_tuple() evals = elab.get_value_tuple() return LabColor(*[ linear_gradient(start_value, end_value, soff, eoff, off) for start_value, end_value in zip(svals, evals) ]) def generate_gradient_function(DATA): def gradient_function(y): initial_offset = 0 for offset, start, end in DATA: if y <= offset: return lab_gradient(start, end, initial_offset, offset, y) initial_offset = offset return gradient_function def get_upscaled_values(rgb): return [min(max(0, i), 255) for i in rgb.get_upscaled_value_tuple()] def get_rgb(lab): rgb = convert_color(lab, sRGBColor) rgb = sRGBColor(*get_upscaled_values(rgb), is_upscaled=True) return rgb.get_rgb_hex()[1:] def find_color(ulab, colors, ctrans): cur_distance = float('inf') cur_color = None i = 0 for clab in colors: dist = delta_e_cie2000(ulab, clab) if dist < cur_distance: cur_distance = dist cur_color = (ctrans(i), clab) i += 1 return cur_color def print_color(color): if type(color) is int: colstr = '5;' + str(color) else: rgb = convert_color(color, sRGBColor) colstr = '2;' + ';'.join((str(i) for i in get_upscaled_values(rgb))) sys.stdout.write('\033[48;' + colstr + 'm ') def print_colors(colors, num): for i in range(num): color = colors[int(round(i * (len(colors) - 1) / num))] print_color(color) sys.stdout.write('\033[0m\n') def dec_scale_generator(num): j = 0 r = '' while num: r += '\033[{0}m'.format(j % 2) for i in range(10): r += str(i) num -= 1 if not num: break j += 1 r += '\033[0m\n' return r def compute_steps(gradient, weights): maxweight = len(gradient) - 1 if weights: weight_sum = sum(weights) norm_weights = [100.0 * weight / weight_sum for weight in weights] steps = [0] for weight in norm_weights: steps.append(steps[-1] + weight) steps.pop(0) steps.pop(0) else: step = m / maxweight steps = [i * step for i in range(1, maxweight + 1)] return steps palettes = { '16': (cterm_to_lab[:16], lambda c: c), '256': (cterm_to_lab, lambda c: c), None: (cterm_to_lab[16:], lambda c: c + 16), } def show_scale(rng, num_output): if not rng and num_output >= 32 and (num_output - 1) // 10 >= 4 and (num_output - 1) % 10 == 0: sys.stdout.write('0') sys.stdout.write(''.join(('%*u' % (num_output // 10, i) for i in range(10, 101, 10)))) sys.stdout.write('\n') else: if rng: vmin, vmax = rng[1] isint = rng[0] else: isint = True vmin = 0 vmax = 100 s = '' lasts = ' ' + str(vmax) while len(s) + len(lasts) < num_output: curpc = len(s) + 1 if s else 0 curval = vmin + curpc * (vmax - vmin) / num_output if isint: curval = int(round(curval)) s += str(curval) + ' ' sys.stdout.write(s[:-1] + lasts + '\n') sys.stdout.write(dec_scale_generator(num_output) + '\n') if __name__ == '__main__': p = argparse.ArgumentParser(description=__doc__) p.add_argument('gradient', nargs='*', metavar='COLOR', type=color, help='List of colors (either indexes from 8-bit palette or 24-bit RGB in hexadecimal notation)') p.add_argument('-n', '--num_items', metavar='INT', type=int, help='Number of items in resulting list', default=101) p.add_argument('-N', '--num_output', metavar='INT', type=int, help='Number of characters in sample', default=101) p.add_argument('-r', '--range', metavar='V1 V2', type=num2, help='Use this range when outputting scale') p.add_argument('-s', '--show', action='store_true', help='If present output gradient sample') p.add_argument('-p', '--palette', choices=('16', '256'), help='Use this palette. Defaults to 240-color palette (256 colors without first 16)') p.add_argument('-w', '--weights', metavar='INT INT ...', type=nums, help='Adjust weights of colors. Number of weights must be equal to number of colors') p.add_argument('-C', '--omit-terminal', action='store_true', help='If present do not compute values for terminal') args = p.parse_args() m = args.num_items steps = compute_steps(args.gradient, args.weights) data = [ (weight, args.gradient[i - 1], args.gradient[i]) for weight, i in zip(steps, range(1, len(args.gradient))) ] gr_func = generate_gradient_function(data) gradient = [gr_func(y) for y in range(0, m)] r = [get_rgb(lab) for lab in gradient] if not args.omit_terminal: r2 = [find_color(lab, *palettes[args.palette])[0] for lab in gradient] r3 = [i[0] for i in groupby(r2)] if not args.omit_terminal: print(json.dumps(r3) + ',') print(json.dumps(r2) + ',') print(json.dumps(r)) if args.show: print_colors(args.gradient, args.num_output) if not args.omit_terminal: print_colors(r3, args.num_output) print_colors(r2, args.num_output) print_colors(gradient, args.num_output) show_scale(args.range, args.num_output) powerline-2.8.4/tools/purge-PRs.py000077500000000000000000000017051466405252600171070ustar00rootroot00000000000000#!/usr/bin/env python # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import argparse from getpass import getpass from github import Github p = argparse.ArgumentParser(description='Powerline release script') p.add_argument('-u', '--user', type=str, metavar='USER', help='Github username.', required=True) p.add_argument('-p', '--password', type=str, metavar='PASS', help='Github password. You will be prompted if it is not supplied.') if __name__ == '__main__': args = p.parse_args() user = args.user password = args.password or getpass('Password for {0}: '.format(user)) gh = Github(user, password) grepo = gh.get_repo('powerline/powerline') for pr in grepo.get_pulls(): if pr.base.ref != 'develop': issue = grepo.get_issue(pr.number) issue.create_comment('PRs to any branch, but develop, are not accepted.', ) issue.add_to_labels('s:invalid') issue.edit(state='closed')