Exemplo n.º 1
0
    def extract_end():
        """
        Display a summary of warnings and errors if any.
        """
        has_warnings = False
        has_errors = False
        summary = []
        for xev in extract_results:
            has_errors = has_errors or bool(xev.errors)
            has_warnings = has_warnings or bool(xev.warnings)
            source = as_posixpath(xev.source)
            source = utils.get_relative_path(original_input, abs_input, source)
            for e in xev.errors:
                summary.append(
                    style('ERROR extracting: %(source)s: %(e)r' % locals(),
                          fg='red',
                          reset=False))
            for warn in xev.warnings:
                summary.append(
                    style('WARNING extracting: %(source)s: %(warn)r' %
                          locals(),
                          fg='yellow',
                          reset=False))

        summary_color = 'green'
        if has_warnings:
            summary_color = 'yellow'
        if has_errors:
            summary_color = 'red'

        summary.append(style('Extracting done.', fg=summary_color, reset=True))
        return '\n'.join(summary)
Exemplo n.º 2
0
    def extract_end():
        """
        Display a summary of warnings and errors if any.
        """
        has_warnings = False
        has_errors = False
        summary = []
        for xev in extract_results:
            has_errors = has_errors or bool(xev.errors)
            has_warnings = has_warnings or bool(xev.warnings)
            source = as_posixpath(xev.source)
            source = utils.get_relative_path(original_input, abs_input, source)
            for e in xev.errors:
                summary.append(style('ERROR extracting: %(source)s: %(e)r' % locals(), fg='red', reset=False))
            for warn in xev.warnings:
                summary.append(style('WARNING extracting: %(source)s: %(warn)r' % locals(), fg='yellow', reset=False))

        summary_color = 'green'
        if has_warnings:
            summary_color = 'yellow'
        if has_errors:
            summary_color = 'red'

        summary.append(style('Extracting done.', fg=summary_color, reset=True))
        return '\n'.join(summary)
Exemplo n.º 3
0
 def scan_event(item):
     """Progress event displayed each time a file is scanned"""
     if quiet:
         return ''
     if item:
         _scan_success, _scanned_path = item
         _progress_line = verbose and _scanned_path or fixed_width_file_name(_scanned_path)
         save_logs('Scanned: '+_progress_line,output_file)
         return style('Scanned: ') + style(_progress_line, fg=_scan_success and 'green' or 'red')
Exemplo n.º 4
0
 def scan_event(item):
     """Progress event displayed each time a file is scanned"""
     if quiet or not item or not display_fn:
         return ''
     _scan_success, _scanned_path = item
     _scanned_path = unicode(toascii(_scanned_path))
     if verbose:
         _progress_line = _scanned_path
     else:
         _progress_line = fixed_width_file_name(_scanned_path, max_file_name_len)
     return style('Scanned: ') + style(_progress_line, fg=_scan_success and 'green' or 'red')
Exemplo n.º 5
0
 def dl_style_word(self, word):
     if len(word) == 0:
         return word
     elif word[:1] == '-':
         return style(word, fg='white', bold=True)
     elif self._kngsection == 'Options':
         # for the options definiton list, we make non-hyphenated
         # words yellow; otherwise, we stick to white
         return style(word, fg='yellow', bold=True)
     else:
         return style(word, fg='white', bold=True)
Exemplo n.º 6
0
 def write_heading(self, heading):
     """
     Writes a heading into the buffer, applying some styling if the heading
     matches the current section name.
     """
     if self._kngsection is not None and heading == self._kngsection:
         if heading == 'Commands':
             heading = 'Subcommand'
         self.write('%*s%s%s\n' % (self.current_indent, '',
             style(heading, fg='cyan', bold=True), style(':', fg='white', bold=True)))
     else:
         super(KNGHelpFormatter, self).write_heading(heading)
Exemplo n.º 7
0
 def scan_event(item):
     """Progress event displayed each time a file is scanned"""
     if quiet or not item or not display_fn:
         return ''
     _scan_success, _scanned_path = item
     if verbose:
         _progress_line = _scanned_path
     else:
         _progress_line = fixed_width_file_name(
             _scanned_path, max_file_name_len)
     return style('Scanned: ') + style(
         _progress_line, fg=_scan_success and 'green' or 'red')
Exemplo n.º 8
0
def echo_next_step(desc: str, cmd: str) -> None:
    """
    Echoes a 'next step' to perform, with styling.

    E.g.

      ◦ To archive results, run $ bento archive

    :param desc: The step description
    :param cmd: The command that the user should run
    """
    echo_styles("◦ ", style(f"{desc}, run $ ", dim=True), cmd,
                style(".", dim=True))
Exemplo n.º 9
0
def init_pipeline(program, config, questions):
    """Initializes a config object by interactively asking questions."""
    if config.user_data:
        # Some existing user settings were found, warn about overwriting them
        message = "{program} {note}\tThe existing {file} will be updated"
        segments = dict(program=program, note=style('existing', fg='yellow'),
                        file=style(config.config_path.basename(), fg='white'))
        echo(message.format(**segments))

    # Launch questionnaire
    user_defaults = questionnaire(questions)
    # Set the selected user defaults
    for dot_key, value in user_defaults.items():
        config.set(dot_key, value, scope=config.user_data)
Exemplo n.º 10
0
def init_pipeline(program, config, questions):
    """Initializes a config object by interactively asking questions."""
    if config.user_data:
        # Some existing user settings were found, warn about overwriting them
        message = "{program} {note}\tThe existing {file} will be updated"
        segments = dict(program=program,
                        note=style('existing', fg='yellow'),
                        file=style(config.config_path.basename(), fg='white'))
        echo(message.format(**segments))

    # Launch questionnaire
    user_defaults = questionnaire(questions)
    # Set the selected user defaults
    for dot_key, value in user_defaults.items():
        config.set(dot_key, value, scope=config.user_data)
Exemplo n.º 11
0
def wrap_link(text: str, extra: int, *links: Tuple[str, str],
              **kwargs: Any) -> str:
    """
    Wraps text. Text may include one or more links.

    :param text: Unlinked text
    :param links: Tuples of (anchor text, target)
    :param extra: Any extra width to apply
    :param kwargs: Styling rules passed to text
    """

    wrapped = wrap(text, extra)

    def find_loc(anchor: str) -> Tuple[int, str]:
        """
        Finds the position of the anchor string in the wrapped text

        Note that the anchor string itself may be wrapped, so we return
        both the position, and the value of the (possibly wrapped) anchor string.
        """
        pos = wrapped.find(anchor)
        if pos < 0:
            # Text was likely wrapped
            anchor_it = [
                f"{anchor[:ix].rstrip()}\n{anchor[ix:]}"
                for ix in range(len(anchor))
            ]
            pos_it = ((wrapped.find(a), a) for a in anchor_it)
            pos, anchor = next(((p, a) for p, a in pos_it if p > 0),
                               (-1, anchor))
            if pos < 0:
                raise ValueError(f"'{anchor}' does not appear in '{text}'")
        return pos, anchor

    with_locs = sorted([(find_loc(anchor), href) for anchor, href in links],
                       key=(lambda t: t[0][0]))
    out = ""
    current = 0
    for loc_anchor, href in with_locs:
        loc, anchor = loc_anchor
        out += style(wrapped[current:loc], **kwargs)
        out += render_link(anchor,
                           href,
                           print_alternative=False,
                           pipe=sys.stderr)
        current = loc + len(anchor)
    out += style(wrapped[current:], **kwargs)
    return out
Exemplo n.º 12
0
def render_link(
    text: str,
    href: Optional[str],
    print_alternative: bool = True,
    width: Optional[int] = None,
    pipe: TextIO = sys.stdout,
) -> str:
    """
    Prints a clickable hyperlink output if in a tty; otherwise just prints a text link

    :param text: The link anchor text
    :param href: The href, if exists
    :param print_alternative: If true, only emits link if OSC8 links are supported, otherwise prints href after text
    :param width: Minimum link width
    :param pipe: The text IO via which this link will be emitted
    :return: The rendered link
    """
    is_rendered = False
    if href:  # Don't render if href is None or empty
        if pipe.isatty() and DO_PRINT_LINKS:
            text = f"{OSC_8}{href}{BEL}{text}{OSC_8}{BEL}"
            is_rendered = True
            if width:
                width += LINK_WIDTH + len(href)
        elif print_alternative:
            text = f"{text} {href}"

    if width:
        text = text.ljust(width)

    # Coloring has to occur after justification
    if is_rendered:
        text = style(text, fg=Colors.LINK)

    return text
Exemplo n.º 13
0
def echo_progress(text: str,
                  extra: int = 0,
                  skip: bool = False) -> Callable[[], None]:
    """
    Prints a binary in-progress / done bar

    Usage example:
      mark_done = echo_progress("Installing foo")
      install_foo()
      mark_done()

    :param extra: Number of unprinted characters in text (each ANSI code point is 4 characters)
    :param skip: If true, "Skipped" is printed instead, and callback is a no-op
    """
    width = PRINT_WIDTH - 3 - SETUP_WIDTH + ANSI_WIDTH + extra
    logging.info(text)
    leader = style("".ljust(width - len(text), LEADER_CHAR), dim=True)

    if skip:
        secho(f"{text}{leader} {style(SKIP_TEXT, dim=True)}",
              err=True,
              dim=True)
        return lambda: None
    else:
        secho(f"{text}{leader} {SETUP_TEXT}", nl=False, err=True, dim=True)
        return lambda: secho(f"{RESET_TEXT}{DONE_TEXT}", err=True, dim=True)
Exemplo n.º 14
0
 def scan_end():
     """Progress event displayed at end of scan"""
     has_warnings = False
     has_errors = False
     summary = []
     summary_color = 'green'
     summary_color = has_warnings and 'yellow' or summary_color
     summary_color = has_errors and 'red' or summary_color
     summary.append(style('Scanning done.', fg=summary_color, reset=True))
     return '\n'.join(summary)
Exemplo n.º 15
0
 def scan_end():
     """Progress event displayed at end of scan"""
     has_warnings = False
     has_errors = False
     summary = []
     summary_color = 'green'
     summary_color = has_warnings and 'yellow' or summary_color
     summary_color = has_errors and 'red' or summary_color
     summary.append(style('Scanning done.', fg=summary_color, reset=True))
     return '\n'.join(summary)
Exemplo n.º 16
0
def ask(prompt, default=None, color='cyan'):
    """Ask a question, waits for user input.

    Replacement for "input". Updates the same line by replacing "default".

    .. code-block:: python

        >>> my_name = ask('Say my name: %s ', 'Heisenberg')
        # Wait for user input
        Say my name: (Heisenberg) Walter
        # Updates *the same* line with 'Walter' in green
        Say my name: Walter
        >>> print(my_name)
        Walter

    Inspired by 'bower_ init' which confirms user input by replacing the
    default option in line (ref_).

    Args:
        prompt (str): Question to print, '%s' will be replaced by default
        default (str, optional): Default option unless replaced by user
        color (str, optional): Some common color like 'red', 'green', 'yellow'

    Returns:
        str: User input or default

    .. _bower: http://bower.io/
    .. _ref: http://stackoverflow.com/questions/12586601
    """
    # helper variables
    MOVE_CURSOR_UP = '\x1b[1A'
    ERASE_LINE = '\x1b[2K'

    # determine if a default was submitted
    if default:
        # prepare the default-part of the prompt
        default_string = "(%s)" % default
    else:
        # not relevant since ``promt`` shouldn't include a '%s'
        default_string = ''

    # pass question to user and wait for response
    # write default option in parentheses, use it as response if nothing
    # was submitted by user.
    response = input(build_prompt(prompt, default_string)) or default
    if isinstance(default, list) and isinstance(response, str):
        sep = ',' if ',' in response else None
        response = [int(item) for item in response.split(sep)]

    # print the updated confirmation line by replacing the previous
    echo(MOVE_CURSOR_UP + ERASE_LINE +
         build_prompt(prompt, style(str(response) or '', fg=color)))

    return response
Exemplo n.º 17
0
def ask(prompt, default=None, color='cyan'):
    """Ask a question, waits for user input.

    Replacement for "input". Updates the same line by replacing "default".

    .. code-block:: python

        >>> my_name = ask('Say my name: %s ', 'Heisenberg')
        # Wait for user input
        Say my name: (Heisenberg) Walter
        # Updates *the same* line with 'Walter' in green
        Say my name: Walter
        >>> print(my_name)
        Walter

    Inspired by 'bower_ init' which confirms user input by replacing the
    default option in line (ref_).

    Args:
        prompt (str): Question to print, '%s' will be replaced by default
        default (str, optional): Default option unless replaced by user
        color (str, optional): Some common color like 'red', 'green', 'yellow'

    Returns:
        str: User input or default

    .. _bower: http://bower.io/
    .. _ref: http://stackoverflow.com/questions/12586601
    """
    # helper variables
    MOVE_CURSOR_UP = '\x1b[1A'
    ERASE_LINE = '\x1b[2K'

    # determine if a default was submitted
    if default:
        # prepare the default-part of the prompt
        default_string = "(%s)" % default
    else:
        # not relevant since ``promt`` shouldn't include a '%s'
        default_string = ''

    # pass question to user and wait for response
    # write default option in parentheses, use it as response if nothing
    # was submitted by user.
    response = input(build_prompt(prompt, default_string)) or default
    if isinstance(default, list) and isinstance(response, str):
        sep = ',' if ',' in response else None
        response = [int(item) for item in response.split(sep)]

    # print the updated confirmation line by replacing the previous
    echo(MOVE_CURSOR_UP + ERASE_LINE
         + build_prompt(prompt, style(str(response) or '', fg=color)))

    return response
Exemplo n.º 18
0
def path_progress_message(item, verbose=False, prefix='Scanned: '):
    """
    Return a styled message suitable for progress display when processing a path
    for an `item` tuple of (location, rid, scan_errors, *other items)
    """
    if not item:
        return ''
    location = item[0]
    errors = item[2]
    location = compat.unicode(toascii(location))
    progress_line = location
    if not verbose:
        max_file_name_len = file_name_max_len()
        # do not display a file name in progress bar if there is no space available
        if max_file_name_len <= 10:
            return ''
        progress_line = fixed_width_file_name(location, max_file_name_len)

    color = 'red' if errors else 'green'
    return style(prefix) + style(progress_line, fg=color)
Exemplo n.º 19
0
def log_in_terminal(message: str, *args, **kwargs) -> None:
    """This function logs in the terminal a message with a specific color

    Args:
        message (str): Message to log on the console
        foreground(str): Foreground color see click.style for options

    """
    if args:
        message = message + "\n" + "\n".join(args)
    click.echo(style(message, **kwargs))
Exemplo n.º 20
0
 def link(self,
          ctx: Context,
          url: str,
          file: str = None,
          *,
          way: SyncWays = SyncWays.twoway):
     'link a remote file to local.'
     try:
         link_id = self._api.add_link(url, file, way)
         self._logger.info('link id: {}'.format(style(link_id, fg='green')))
         if click.confirm('sync now?', default=True, show_default=True):
             self._api.sync_one(link_id)
     except GLinkError as ge:
         ctx.fail(ge.message)
Exemplo n.º 21
0
 def push(self,
          ctx: Context,
          file: str,
          user: str = None,
          public: flag = False):
     'push the file as a new gist.'
     if not os.path.isfile(file):
         self._logger.error(f'{file} is not a file.')
     try:
         link_id = self._api.push_new_gist(file, user=user, public=public)
     except GLinkError as ge:
         ctx.fail(ge.message)
     else:
         self._logger.info('link id: {}'.format(style(link_id, fg='green')))
Exemplo n.º 22
0
def echo_box(text: str) -> None:
    """
    Prints text bold, in a header box

    By default, the box is PRINT_WIDTH characters wide, unless the text is too
    long for the box, in which case the box is extended to fit.
    """
    lines = text.split("\n")
    max_len = max(len(l) for l in lines)
    max_len = max(PRINT_WIDTH - 4, max_len)
    hrule = "".ljust(max_len + 2, "─")
    echo_newline()
    secho(f"╭{hrule}╮", err=True)
    for l in lines:
        p = style(f"{l:^{max_len}s}", bold=True)
        secho(f"│ {p} │", err=True)
    secho(f"╰{hrule}╯", err=True)
Exemplo n.º 23
0
def build_prompt(prompt, replacement=''):
    """Craft a prompt to ask a question.

  Provides a few modifications that should make it as simple as possible
  to ask questions.

  .. code-block:: python

    >>> build_prompt('name', '(Heisenberg)')
    'name: (Heisenberg)'
    >>> build_prompt('What is your name?', '(Heisenberg)')
    'What is your name? (Heisenberg)'
    >>> build_prompt('I %sed to China', '[style(walk, fg='red')]')
    'I [walk]ed to China'

  Args:
    prompt (str): Base prompt, ``%s`` will be substituted with 'replacement'
    replacement (str, optional): String to substitute ``%s`` with

  Returns:
    str: The full, modified prompt string
  """
    # prefix the question-prefix
    prompt = ("[%s] " % style('?', fg='green')) + prompt

    # determine whether it seems user has tried to format the prompt
    if '%s' not in prompt:
        # automate some formatting for the sake of convenience
        if not prompt.endswith(' '):
            if not prompt.endswith('?') or prompt.endswith(':'):
                prompt += ':'

        # add the default option to the end of prompt unless specified elsewhere
        prompt += " %s"

    # make the default-substitution and ensure an empty space at the end
    return (prompt % replacement).rstrip() + ' '
Exemplo n.º 24
0
def build_prompt(prompt, replacement=''):
  """Craft a prompt to ask a question.

  Provides a few modifications that should make it as simple as possible
  to ask questions.

  .. code-block:: python

    >>> build_prompt('name', '(Heisenberg)')
    'name: (Heisenberg)'
    >>> build_prompt('What is your name?', '(Heisenberg)')
    'What is your name? (Heisenberg)'
    >>> build_prompt('I %sed to China', '[style(walk, fg='red')]')
    'I [walk]ed to China'

  Args:
    prompt (str): Base prompt, ``%s`` will be substituted with 'replacement'
    replacement (str, optional): String to substitute ``%s`` with

  Returns:
    str: The full, modified prompt string
  """
  # prefix the question-prefix
  prompt = ("[%s] " % style('?', fg='green')) + prompt

  # determine whether it seems user has tried to format the prompt
  if '%s' not in prompt:
    # automate some formatting for the sake of convenience
    if not prompt.endswith(' '):
      if not prompt.endswith('?') or prompt.endswith(':'):
        prompt += ':'

    # add the default option to the end of prompt unless specified elsewhere
    prompt += " %s"

  # make the default-substitution and ensure an empty space at the end
  return (prompt % replacement).rstrip() + ' '
Exemplo n.º 25
0
 def scan_start():
     """Progress event displayed at start of scan"""
     return style('Scanning files...', fg='green')
Exemplo n.º 26
0
 def extract_start():
     return style('Extracting archives...', fg='green')
Exemplo n.º 27
0
 def scan_start():
     """Progress event displayed at start of scan"""
     return style('Scanning files...', fg='green')
Exemplo n.º 28
0
 def write_usage(self, prog, args='', prefix='Usage: '):
     prog = style(prog, fg='white', bold=True)
     super(KNGHelpFormatter, self).write_usage(prog, args=args, prefix=prefix)
Exemplo n.º 29
0
 def extract_start():
     return style('Extracting archives...', fg='green')
Exemplo n.º 30
0
from contextlib import contextmanager

from click.core import Context, Command, Group
from click.termui import style, get_terminal_size
from click.formatting import HelpFormatter
from click.decorators import command, option, version_option
import click

from .kngclicktextwrapper import KNGClickTextWrapper
from .kngtextwrapper import kngterm_len, kngexpandtabs
from .version import version
from .output import set_verbose_level, trace

KNG_OPTIONS_METAVAR = ''.join((
    style('[', fg='blue'),
    style('OPTIONS', fg='cyan', bold=True),
    style(']', fg='blue')))

SUBCOMMAND_METAVAR = ''.join((
    style('SUBCOMMAND', fg='cyan', bold=True),
    ' ',
    style('[', fg='blue'),
    style('ARGS', fg='cyan', bold=True),
    style(']...', fg='blue')))

SUBCOMMANDS_METAVAR = ''.join((
    style('SUBCOMMAND1', fg='cyan', bold=True),
    ' ',
    style('[', fg='blue'),
    style('ARGS', fg='cyan', bold=True),