Wrap results printed in terminal

A port from @zmwangx monkeypatch for textwrap
This commit is contained in:
Arun Prakash Jana 2021-05-14 21:35:10 +05:30
parent 6e959d7b85
commit a4ee497819
No known key found for this signature in database
GPG Key ID: A75979F35C080412

164
buku
View File

@ -22,9 +22,11 @@ from itertools import chain
import argparse
import calendar
import cgi
import codecs
import collections
import contextlib
import json
import locale
import logging
import os
import platform
@ -37,9 +39,11 @@ import subprocess
from subprocess import Popen, PIPE, DEVNULL
import sys
import tempfile
import textwrap
import threading
import time
from typing import Any, Dict, Iterable, List, Optional, Tuple
import unicodedata
import webbrowser
import certifi
import urllib3
@ -73,7 +77,9 @@ ID_DB_STR = '%d. %s'
MUTE_STR = '%s (L)\n'
URL_STR = ' > %s\n'
DESC_STR = ' + %s\n'
DESC_WRAP = '%s%s'
TAG_STR = ' # %s\n'
TAG_WRAP = '%s%s'
# Colormap for color output from "googler" project
COLORMAP = {k: '\x1b[%sm' % v for k, v in {
@ -3929,11 +3935,16 @@ def prompt(obj, results, noninteractive=False, deep=False, listtags=False, sugge
if listtags:
show_taglist(obj)
try:
columns, _ = os.get_terminal_size()
except OSError:
columns = 0
if noninteractive:
try:
for row in results:
count += 1
print_single_rec(row, count)
print_single_rec(row, count, columns)
except Exception:
pass
finally:
@ -3951,7 +3962,7 @@ def prompt(obj, results, noninteractive=False, deep=False, listtags=False, sugge
print()
for row in results[cur_index:next_index]:
count += 1
print_single_rec(row, count)
print_single_rec(row, count, columns)
print('%d-%d/%d' % (cur_index + 1, next_index, total_results))
else:
print('No more results')
@ -4222,7 +4233,11 @@ def print_rec_with_filter(records, field_filter=0):
try:
if field_filter == 0:
for row in records:
print_single_rec(row)
try:
columns, _ = os.get_terminal_size()
except OSError:
columns = 0
print_single_rec(row, columns=columns)
elif field_filter == 1:
for row in records:
print('%s\t%s' % (row[0], row[1]))
@ -4258,7 +4273,7 @@ def print_rec_with_filter(records, field_filter=0):
sys.exit(1)
def print_single_rec(row: BookmarkVar, idx: Optional[int] = 0): # NOQA
def print_single_rec(row: BookmarkVar, idx: Optional[int]=0, columns: Optional[int]=0): # NOQA
"""Print a single DB record.
Handles both search results and individual record.
@ -4270,6 +4285,9 @@ def print_single_rec(row: BookmarkVar, idx: Optional[int] = 0): # NOQA
idx : int, optional
Search result index. If 0, print with DB index.
Default is 0.
columns : int, optional
Number of columns to wrap comments to.
Default is 0.
"""
str_list = []
@ -4285,16 +4303,44 @@ def print_single_rec(row: BookmarkVar, idx: Optional[int] = 0): # NOQA
else:
id_title_res += '\n'
try:
print(id_title_res, end='')
print(URL_STR % (row[1]), end='')
if columns == 0:
if row[4]:
print(DESC_STR % (row[4]), end='')
if row[3] != DELIM:
print(TAG_STR % (row[3][1:-1]), end='')
print()
return
INDENT = 5
ln_num = 1
fillwidth = columns - INDENT
for line in textwrap.wrap(row[4].replace('\n', ''), width=fillwidth):
if ln_num == 1:
print(DESC_STR % line, end='')
ln_num += 1
else:
print(DESC_WRAP % (' ' * INDENT, line))
ln_num = 1
for line in textwrap.wrap(row[3][1:-1].replace('\n', ''), width=fillwidth):
if ln_num == 1:
print(TAG_STR % line, end='')
ln_num += 1
else:
print(TAG_WRAP % (' ' * INDENT, line))
print()
except UnicodeEncodeError:
str_list = []
str_list.append(id_title_res)
str_list.append(URL_STR % (row[1]))
if row[4]:
str_list.append(DESC_STR % (row[4]))
if row[3] != DELIM:
str_list.append(TAG_STR % (row[3][1:-1]))
try:
print(''.join(str_list))
except UnicodeEncodeError:
sys.stdout.buffer.write((''.join(str_list) + '\n').encode('utf-8'))
except BrokenPipeError:
sys.stdout = os.fdopen(1)
@ -4891,10 +4937,105 @@ def setcolors(args):
result = [id_col, id_str_col, url_col, desc_col, tag_col]
return result
def unwrap(text):
"""Unwrap text."""
lines = text.split('\n')
result = ''
for i in range(len(lines) - 1):
result += lines[i]
if not lines[i]:
# Paragraph break
result += '\n\n'
elif lines[i + 1]:
# Next line is not paragraph break, add space
result += ' '
# Handle last line
result += lines[-1] if lines[-1] else '\n'
return result
def check_stdout_encoding():
"""Make sure stdout encoding is utf-8.
If not, print error message and instructions, then exit with
status 1.
This function is a no-op on win32 because encoding on win32 is
messy, and let's just hope for the best. /s
"""
if sys.platform == 'win32':
return
# Use codecs.lookup to resolve text encoding alias
encoding = codecs.lookup(sys.stdout.encoding).name
if encoding != 'utf-8':
locale_lang, locale_encoding = locale.getlocale()
if locale_lang is None:
locale_lang = '<unknown>'
if locale_encoding is None:
locale_encoding = '<unknown>'
ioencoding = os.getenv('PYTHONIOENCODING', 'not set')
sys.stderr.write(unwrap(textwrap.dedent("""\
stdout encoding '{encoding}' detected. ddgr requires utf-8 to
work properly. The wrong encoding may be due to a non-UTF-8
locale or an improper PYTHONIOENCODING. (For the record, your
locale language is {locale_lang} and locale encoding is
{locale_encoding}; your PYTHONIOENCODING is {ioencoding}.)
Please set a UTF-8 locale (e.g., en_US.UTF-8) or set
PYTHONIOENCODING to utf-8.
""".format(
encoding=encoding,
locale_lang=locale_lang,
locale_encoding=locale_encoding,
ioencoding=ioencoding,
))))
sys.exit(1)
def monkeypatch_textwrap_for_cjk():
"""Monkeypatch textwrap for CJK wide characters.
"""
try:
if textwrap.wrap.patched:
return
except AttributeError:
pass
psl_textwrap_wrap = textwrap.wrap
def textwrap_wrap(text, width=70, **kwargs):
width = max(width, 2)
# We first add a U+0000 after each East Asian Fullwidth or East
# Asian Wide character, then fill to width - 1 (so that if a NUL
# character ends up on a new line, we still have one last column
# to spare for the preceding wide character). Finally we strip
# all the NUL characters.
#
# East Asian Width: https://www.unicode.org/reports/tr11/
return [
line.replace('\0', '')
for line in psl_textwrap_wrap(
''.join(
ch + '\0' if unicodedata.east_asian_width(ch) in ('F', 'W') else ch
for ch in unicodedata.normalize('NFC', text)
),
width=width - 1,
**kwargs
)
]
def textwrap_fill(text, width=70, **kwargs):
return '\n'.join(textwrap_wrap(text, width=width, **kwargs))
textwrap.wrap = textwrap_wrap
textwrap.fill = textwrap_fill
textwrap.wrap.patched = True
textwrap.fill.patched = True
# main starts here
def main():
"""Main."""
global ID_STR, ID_DB_STR, MUTE_STR, URL_STR, DESC_STR, TAG_STR, PROMPTMSG
global ID_STR, ID_DB_STR, MUTE_STR, URL_STR, DESC_STR, DESC_WRAP, TAG_STR, TAG_WRAP, PROMPTMSG
title_in = None
tags_in = None
@ -5130,7 +5271,9 @@ POSITIONAL ARGUMENTS:
MUTE_STR = '%s \x1b[2m(L)\x1b[0m\n'
URL_STR = COLORMAP['j'] + ' > ' + setcolors(colorstr)[2] + '%s\n' + COLORMAP['x']
DESC_STR = COLORMAP['j'] + ' + ' + setcolors(colorstr)[3] + '%s\n' + COLORMAP['x']
DESC_WRAP = COLORMAP['j'] + setcolors(colorstr)[3] + '%s%s' + COLORMAP['x']
TAG_STR = COLORMAP['j'] + ' # ' + setcolors(colorstr)[4] + '%s\n' + COLORMAP['x']
TAG_WRAP = COLORMAP['j'] + setcolors(colorstr)[4] + '%s%s' + COLORMAP['x']
# Enable color in logs
setup_logger(LOGGER)
@ -5384,6 +5527,9 @@ POSITIONAL ARGUMENTS:
except Exception:
pass
check_stdout_encoding()
monkeypatch_textwrap_for_cjk()
if search_results:
oneshot = args.np
update_search_results = False