Source code for pkgbuilder.ui

# -*- encoding: utf-8 -*-
# PKGBUILDer v4.3.2
# An AUR helper (and library) in Python 3.
# Copyright © 2011-2023, Chris Warrick.
# See /LICENSE for licensing information.

"""
The User Interface.

:Copyright: © 2011-2023, Chris Warrick.
:License: BSD (see /LICENSE).
"""

import sys
import time
import threading
import textwrap
import shutil

__all__ = ('get_termwidth', 'hanging_indent', 'mlist',
           'Progress', 'Throbber', 'ProgressThrobber')


[docs]def get_termwidth(default=None): """Get the width of this terminal. .. versionadded:: 3.3.0 .. versionchanged:: 4.2.9 """ return shutil.get_terminal_size((default, default)).columns
[docs]def hanging_indent(text, intro, termwidth=None, change_spaces=True, introwidth=None): """Produce text with a hanging indent. .. versionadded:: 3.3.0 .. versionchanged:: 4.0.0 """ if termwidth is None: termwidth = get_termwidth(9001) if introwidth is None: introwidth = len(intro) nowrap = intro + text if intro: wrapv = textwrap.wrap(nowrap, termwidth, break_on_hyphens=False) else: wrapv = textwrap.wrap(nowrap, termwidth - introwidth, break_on_hyphens=False) wrap0 = wrapv[0] wraprest = textwrap.wrap('\n'.join(wrapv[1:]), termwidth - introwidth, break_on_hyphens=False) if change_spaces: wraprest = [i.replace(' ', ' ').replace(' ', ' ') for i in wraprest] buf = wrap0 for i in wraprest: buf += '\n' + introwidth * ' ' + i return buf
[docs]def mlist(items, sep=' ', change_spaces=True, termwidth=None, indentwidth=17): """Output a list of strings, complete with a hanging indent. .. versionadded:: 3.3.0 .. versionchanged:: 4.0.0 """ if termwidth is None: termwidth = get_termwidth(9001) if items: if sep == '\n': buf = [hanging_indent(items[0], '', termwidth, change_spaces, indentwidth)] for i in items[1:]: buf.append(hanging_indent(i, indentwidth * ' ', termwidth, change_spaces)) return '\n'.join(buf) else: return hanging_indent(sep.join(items), '', termwidth, change_spaces, indentwidth) else: return 'None'
[docs]class Progress(object): """A static progress indicator with numbers. Usage:: pm = Progress(total=2) pm.msg('Doing step 1...') step1() pm.msg('Doing step 2...') step2() """ current = 0 total = 1 _pml = 0 def __init__(self, total=1): """Initialize a Progress message.""" self.total = total
[docs] def msg(self, msg, single=False): """Print a progress message.""" self.current += 1 ln = len(str(self.total)) sys.stdout.write('\r' + ((ln * 2 + 4 + self._pml) * ' ')) self._pml = len(msg) sys.stdout.write('\r') sys.stdout.flush() sys.stdout.write(('({0:>' + str(ln) + '}/{1}) ').format(self.current, self.total)) sys.stdout.write(msg) sys.stdout.write('\r') sys.stdout.flush() if single: print() if self.current == self.total: self.total = 0 self.current = 0
[docs]class Throbber(object): """A nice animated throbber. Usage:: with Throbber('Doing important stuff...'): dostuff() """ throb = False states = ('|', '/', '-', '\\') _tt = None def __init__(self, msg, finalthrob='*', printback=True): """Initialize.""" self.msg = msg self.finalthrob = finalthrob self.printback = printback def __enter__(self): """Run the throbber in a thread.""" self._tt = threading.Thread(target=self._throb, args=( self.msg, self.finalthrob, self.printback)) self._tt.start() return self def __exit__(self, *args, **kwargs): """Clean stuff up.""" self.throb = False while self.throbber_alive: time.sleep(0.1) def _throb(self, msg, finalthrob='*', printback=True): """Display a throbber.""" self.throb = True i = 0 while self.throb: sys.stdout.write('\r({0}) {1}'.format(self.states[i], msg)) sys.stdout.flush() time.sleep(0.1) i += 1 if i == len(self.states): i = 0 if not self.throb and printback: sys.stdout.write('\r({0}) {1}'.format(finalthrob, msg)) sys.stdout.flush() time.sleep(0.1) print() @property def throbber_alive(self): """Check the status of a throbber.""" if self._tt: return self._tt.is_alive() else: return False
[docs]class ProgressThrobber(Progress, Throbber): """An animated progress throbber. Similar to Progress, but the / is animated. Usage:: with ProgressThrobber('Working...', total=2) as pt: dostuff() pt.bump('Cleaning up...') cleanup() """ current = 0 finalthrob = '/' printback = True def __init__(self, msg, total=1): """Initialize a ProgressThrobber message.""" self.total = total self.ln = len(str(self.total)) self.bump(msg) def _throb(self, msg, finalthrob='/', printback=True): """Display a throbber.""" self.throb = True i = 0 while self.throb: sys.stdout.write(('\r({0:>' + str(self.ln) + '}{1}{2}) {3}').format(self.current, self.states[i], self.total, self.msg)) sys.stdout.write('\r') sys.stdout.flush() time.sleep(0.1) i += 1 if i == len(self.states): i = 0 sys.stdout.write('\r({0}{1}{2}) {3}'.format(self.current, self.finalthrob, self.total, self.msg)) sys.stdout.flush() time.sleep(0.1) if self.printback: print()
[docs] def bump(self, msg): """Change the displayed message.""" sys.stdout.write('\r' + ((self.ln * 2 + 4 + self._pml) * ' ')) self._pml = len(msg) self.current += 1 self.msg = msg