晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。 林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。 见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝) 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。 南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。
|
Server : Apache System : Linux srv.rainic.com 4.18.0-553.47.1.el8_10.x86_64 #1 SMP Wed Apr 2 05:45:37 EDT 2025 x86_64 User : rainic ( 1014) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /proc/thread-self/root/usr/lib/python3.6/site-packages/dnf/cli/ |
Upload File : |
# Copyright (C) 2013-2014 Red Hat, Inc.
# Terminal routines.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details. You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
from __future__ import absolute_import
from __future__ import unicode_literals
import curses
import dnf.pycomp
import fcntl
import re
import struct
import sys
import termios
def _real_term_width(fd=1):
""" Get the real terminal width """
try:
buf = 'abcdefgh'
buf = fcntl.ioctl(fd, termios.TIOCGWINSZ, buf)
ret = struct.unpack(b'hhhh', buf)[1]
return ret
except IOError:
return None
def _term_width(fd=1):
""" Compute terminal width falling to default 80 in case of trouble"""
tw = _real_term_width(fd=1)
if not tw:
return 80
elif tw < 20:
return 20
else:
return tw
class Term(object):
"""A class to provide some terminal "UI" helpers based on curses."""
# From initial search for "terminfo and python" got:
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116
# ...it's probably not copyrightable, but if so ASPN says:
#
# Except where otherwise noted, recipes in the Python Cookbook are
# published under the Python license.
__enabled = True
real_columns = property(lambda self: _real_term_width())
columns = property(lambda self: _term_width())
__cap_names = {
'underline' : 'smul',
'reverse' : 'rev',
'normal' : 'sgr0',
}
__colors = {
'black' : 0,
'blue' : 1,
'green' : 2,
'cyan' : 3,
'red' : 4,
'magenta' : 5,
'yellow' : 6,
'white' : 7
}
__ansi_colors = {
'black' : 0,
'red' : 1,
'green' : 2,
'yellow' : 3,
'blue' : 4,
'magenta' : 5,
'cyan' : 6,
'white' : 7
}
__ansi_forced_MODE = {
'bold' : '\x1b[1m',
'blink' : '\x1b[5m',
'dim' : '',
'reverse' : '\x1b[7m',
'underline' : '\x1b[4m',
'normal' : '\x1b(B\x1b[m'
}
__ansi_forced_FG_COLOR = {
'black' : '\x1b[30m',
'red' : '\x1b[31m',
'green' : '\x1b[32m',
'yellow' : '\x1b[33m',
'blue' : '\x1b[34m',
'magenta' : '\x1b[35m',
'cyan' : '\x1b[36m',
'white' : '\x1b[37m'
}
__ansi_forced_BG_COLOR = {
'black' : '\x1b[40m',
'red' : '\x1b[41m',
'green' : '\x1b[42m',
'yellow' : '\x1b[43m',
'blue' : '\x1b[44m',
'magenta' : '\x1b[45m',
'cyan' : '\x1b[46m',
'white' : '\x1b[47m'
}
def __forced_init(self):
self.MODE = self.__ansi_forced_MODE
self.FG_COLOR = self.__ansi_forced_FG_COLOR
self.BG_COLOR = self.__ansi_forced_BG_COLOR
def reinit(self, term_stream=None, color='auto'):
"""Reinitializes the :class:`Term`.
:param term_stream: the terminal stream that the
:class:`Term` should be initialized to use. If
*term_stream* is not given, :attr:`sys.stdout` is used.
:param color: when to colorize output. Valid values are
'always', 'auto', and 'never'. 'always' will use ANSI codes
to always colorize output, 'auto' will decide whether do
colorize depending on the terminal, and 'never' will never
colorize.
"""
self.__enabled = True
self.lines = 24
if color == 'always':
self.__forced_init()
return
# Output modes:
self.MODE = {
'bold' : '',
'blink' : '',
'dim' : '',
'reverse' : '',
'underline' : '',
'normal' : ''
}
# Colours
self.FG_COLOR = {
'black' : '',
'blue' : '',
'green' : '',
'cyan' : '',
'red' : '',
'magenta' : '',
'yellow' : '',
'white' : ''
}
self.BG_COLOR = {
'black' : '',
'blue' : '',
'green' : '',
'cyan' : '',
'red' : '',
'magenta' : '',
'yellow' : '',
'white' : ''
}
if color == 'never':
self.__enabled = False
return
assert color == 'auto'
# If the stream isn't a tty, then assume it has no capabilities.
if not term_stream:
term_stream = sys.stdout
if not term_stream.isatty():
self.__enabled = False
return
# Check the terminal type. If we fail, then assume that the
# terminal has no capabilities.
try:
curses.setupterm(fd=term_stream.fileno())
except Exception:
self.__enabled = False
return
self._ctigetstr = curses.tigetstr
self.lines = curses.tigetnum('lines')
# Look up string capabilities.
for cap_name in self.MODE:
mode = cap_name
if cap_name in self.__cap_names:
cap_name = self.__cap_names[cap_name]
self.MODE[mode] = self._tigetstr(cap_name)
# Colors
set_fg = self._tigetstr('setf').encode('utf-8')
if set_fg:
for (color, val) in self.__colors.items():
self.FG_COLOR[color] = curses.tparm(set_fg, val).decode() or ''
set_fg_ansi = self._tigetstr('setaf').encode('utf-8')
if set_fg_ansi:
for (color, val) in self.__ansi_colors.items():
fg_color = curses.tparm(set_fg_ansi, val).decode() or ''
self.FG_COLOR[color] = fg_color
set_bg = self._tigetstr('setb').encode('utf-8')
if set_bg:
for (color, val) in self.__colors.items():
self.BG_COLOR[color] = curses.tparm(set_bg, val).decode() or ''
set_bg_ansi = self._tigetstr('setab').encode('utf-8')
if set_bg_ansi:
for (color, val) in self.__ansi_colors.items():
bg_color = curses.tparm(set_bg_ansi, val).decode() or ''
self.BG_COLOR[color] = bg_color
def __init__(self, term_stream=None, color='auto'):
self.reinit(term_stream, color)
def _tigetstr(self, cap_name):
# String capabilities can include "delays" of the form "$<2>".
# For any modern terminal, we should be able to just ignore
# these, so strip them out.
cap = self._ctigetstr(cap_name) or ''
if dnf.pycomp.is_py3bytes(cap):
cap = cap.decode()
return re.sub(r'\$<\d+>[/*]?', '', cap)
def color(self, color, s):
"""Colorize string with color"""
return (self.MODE[color] + str(s) + self.MODE['normal'])
def bold(self, s):
"""Make string bold."""
return self.color('bold', s)
def sub(self, haystack, beg, end, needles, escape=None, ignore_case=False):
"""Search the string *haystack* for all occurrences of any
string in the list *needles*. Prefix each occurrence with
*beg*, and postfix each occurrence with *end*, then return the
modified string. For example::
>>> yt = Term()
>>> yt.sub('spam and eggs', 'x', 'z', ['and'])
'spam xandz eggs'
This is particularly useful for emphasizing certain words
in output: for example, calling :func:`sub` with *beg* =
MODE['bold'] and *end* = MODE['normal'] will return a string
that when printed to the terminal will appear to be *haystack*
with each occurrence of the strings in *needles* in bold
face. Note, however, that the :func:`sub_mode`,
:func:`sub_bold`, :func:`sub_fg`, and :func:`sub_bg` methods
provide convenient ways to access this same emphasizing functionality.
:param haystack: the string to be modified
:param beg: the string to be prefixed onto matches
:param end: the string to be postfixed onto matches
:param needles: a list of strings to add the prefixes and
postfixes to
:param escape: a function that accepts a string and returns
the same string with problematic characters escaped. By
default, :func:`re.escape` is used.
:param ignore_case: whether case should be ignored when
searching for matches
:return: *haystack* with *beg* prefixing, and *end*
postfixing, occurrences of the strings in *needles*
"""
if not self.__enabled:
return haystack
if not escape:
escape = re.escape
render = lambda match: beg + match.group() + end
for needle in needles:
pat = escape(needle)
if ignore_case:
pat = re.template(pat, re.I)
haystack = re.sub(pat, render, haystack)
return haystack
def sub_norm(self, haystack, beg, needles, **kwds):
"""Search the string *haystack* for all occurrences of any
string in the list *needles*. Prefix each occurrence with
*beg*, and postfix each occurrence with self.MODE['normal'],
then return the modified string. If *beg* is an ANSI escape
code, such as given by self.MODE['bold'], this method will
return *haystack* with the formatting given by the code only
applied to the strings in *needles*.
:param haystack: the string to be modified
:param beg: the string to be prefixed onto matches
:param end: the string to be postfixed onto matches
:param needles: a list of strings to add the prefixes and
postfixes to
:return: *haystack* with *beg* prefixing, and self.MODE['normal']
postfixing, occurrences of the strings in *needles*
"""
return self.sub(haystack, beg, self.MODE['normal'], needles, **kwds)
def sub_mode(self, haystack, mode, needles, **kwds):
"""Search the string *haystack* for all occurrences of any
string in the list *needles*. Prefix each occurrence with
self.MODE[*mode*], and postfix each occurrence with
self.MODE['normal'], then return the modified string. This
will return a string that when printed to the terminal will
appear to be *haystack* with each occurrence of the strings in
*needles* in the given *mode*.
:param haystack: the string to be modified
:param mode: the mode to set the matches to be in. Valid
values are given by self.MODE.keys().
:param needles: a list of strings to add the prefixes and
postfixes to
:return: *haystack* with self.MODE[*mode*] prefixing, and
self.MODE['normal'] postfixing, occurrences of the strings
in *needles*
"""
return self.sub_norm(haystack, self.MODE[mode], needles, **kwds)
def sub_bold(self, haystack, needles, **kwds):
"""Search the string *haystack* for all occurrences of any
string in the list *needles*. Prefix each occurrence with
self.MODE['bold'], and postfix each occurrence with
self.MODE['normal'], then return the modified string. This
will return a string that when printed to the terminal will
appear to be *haystack* with each occurrence of the strings in
*needles* in bold face.
:param haystack: the string to be modified
:param needles: a list of strings to add the prefixes and
postfixes to
:return: *haystack* with self.MODE['bold'] prefixing, and
self.MODE['normal'] postfixing, occurrences of the strings
in *needles*
"""
return self.sub_mode(haystack, 'bold', needles, **kwds)
def sub_fg(self, haystack, color, needles, **kwds):
"""Search the string *haystack* for all occurrences of any
string in the list *needles*. Prefix each occurrence with
self.FG_COLOR[*color*], and postfix each occurrence with
self.MODE['normal'], then return the modified string. This
will return a string that when printed to the terminal will
appear to be *haystack* with each occurrence of the strings in
*needles* in the given color.
:param haystack: the string to be modified
:param color: the color to set the matches to be in. Valid
values are given by self.FG_COLOR.keys().
:param needles: a list of strings to add the prefixes and
postfixes to
:return: *haystack* with self.FG_COLOR[*color*] prefixing, and
self.MODE['normal'] postfixing, occurrences of the strings
in *needles*
"""
return self.sub_norm(haystack, self.FG_COLOR[color], needles, **kwds)
def sub_bg(self, haystack, color, needles, **kwds):
"""Search the string *haystack* for all occurrences of any
string in the list *needles*. Prefix each occurrence with
self.BG_COLOR[*color*], and postfix each occurrence with
self.MODE['normal'], then return the modified string. This
will return a string that when printed to the terminal will
appear to be *haystack* with each occurrence of the strings in
*needles* highlighted in the given background color.
:param haystack: the string to be modified
:param color: the background color to set the matches to be in. Valid
values are given by self.BG_COLOR.keys().
:param needles: a list of strings to add the prefixes and
postfixes to
:return: *haystack* with self.BG_COLOR[*color*] prefixing, and
self.MODE['normal'] postfixing, occurrences of the strings
in *needles*
"""
return self.sub_norm(haystack, self.BG_COLOR[color], needles, **kwds)