Wrap results printed in terminal
A port from @zmwangx monkeypatch for textwrap
This commit is contained in:
parent
6e959d7b85
commit
a4ee497819
172
buku
172
buku
@ -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'
|
||||
|
||||
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))
|
||||
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]))
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user