Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line-breaks and other improvements for the terminal output #66

Merged
merged 7 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions autohooks/precommit/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,17 @@ def run() -> int:
if plugins.is_dir():
sys.path.append(plugins_dir_name)

term.print('autohooks => pre-commit')
term.bold_info('autohooks => pre-commit')

with autohooks_module_path(), term.indent():
for name in config.get_pre_commit_script_names():
term.print('Running {}'.format(name))
term.info('Running {}'.format(name))

with term.indent():
try:
plugin = load_plugin(name)
if not has_precommit_function(plugin):
term.error(
term.fail(
'No precommit function found in plugin {}. '
'Your autohooks settings may be invalid.'.format(
name
Expand Down
85 changes: 53 additions & 32 deletions autohooks/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,32 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import shutil

from contextlib import contextmanager

from enum import Enum
from shutil import get_terminal_size
from typing import Callable, Generator

import colorful as cf

TERMINAL_SIZE_FALLBACK = (80, 24) # use a small standard size as fallback


class Signs(Enum):
FAIL = u'\N{HEAVY MULTIPLICATION X}'
ERROR = u'\N{MULTIPLICATION SIGN}'
WARNING = u'\N{WARNING SIGN}'
OK = u'\N{CHECK MARK}'
INFO = u'\N{INFORMATION SOURCE}'
NONE = ' '

def __str__(self):
return '{}'.format(self.value)


STATUS_LEN = 2


class Terminal:
def __init__(self):
self._indent = 0
Expand All @@ -35,23 +50,29 @@ def get_width() -> int:
"""
Get the width of the terminal window
"""
width, _ = shutil.get_terminal_size(TERMINAL_SIZE_FALLBACK)
width, _ = get_terminal_size(TERMINAL_SIZE_FALLBACK)
return width

def _print_end(self, message: str, status: str, color: Callable) -> None:
extra = 4 # '[ ' and ' ]'

if self._indent > 0:
message = ' ' * self._indent + message

def _print_status(
self, message: str, status: Signs, color: Callable, style: Callable,
) -> None:
first_line = ''
output = ''
width = self.get_width()

if width > 0:
message += ' ' * (int(width) - len(message) - extra - len(status))

print(
message + '[', color(status), ']',
)
if status == Signs.NONE:
first_line += ' '
else:
first_line += '{} '.format(color(status))
if self._indent > 0:
first_line += ' ' * self._indent
usable_width = width - STATUS_LEN - self._indent
while usable_width < len(message):
part_line = ' ' * (self._indent + STATUS_LEN)
part = message[:usable_width]
message = message[usable_width:]
output += '{}{}\n'.format(part_line, part)
output += '{}{}'.format(first_line, message)
print(style(output))

@contextmanager
def indent(self, indentation: int = 4) -> Generator:
Expand All @@ -68,24 +89,24 @@ def add_indent(self, indentation: int = 4) -> None:
def reset_indent(self) -> None:
self._indent = 0

def print(self, *messages: str) -> None:
msg = ''
if self._indent > 0:
msg = ' ' * (self._indent)
msg += ' '.join(messages)
print(msg)
def print(self, *messages: str, style: Callable = cf.reset) -> None:
message = ''.join(messages)
self._print_status(message, Signs.NONE, cf.white, style)

def ok(self, message: str, style: Callable = cf.reset) -> None:
self._print_status(message, Signs.OK, cf.green, style)

def ok(self, message: str) -> None:
self._print_end(message, 'ok', cf.green)
def fail(self, message: str, style: Callable = cf.reset) -> None:
self._print_status(message, Signs.FAIL, cf.red, style)

def fail(self, message: str) -> None:
self._print_end(message, 'fail', cf.red)
def error(self, message: str, style: Callable = cf.reset) -> None:
self._print_status(message, Signs.ERROR, cf.red, style)

def error(self, message: str) -> None:
self._print_end(message, 'error', cf.red)
def warning(self, message: str, style: Callable = cf.reset) -> None:
self._print_status(message, Signs.WARNING, cf.yellow, style)

def warning(self, message: str) -> None:
self._print_end(message, 'warning', cf.yellow)
def info(self, message: str, style: Callable = cf.reset) -> None:
self._print_status(message, Signs.INFO, cf.cyan, style)

def info(self, message: str) -> None:
self._print_end(message, 'info', cf.cyan)
def bold_info(self, message: str, style: Callable = cf.bold) -> None:
self._print_status(message, Signs.INFO, cf.cyan, style)