⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 util.py

📁 Urwid is a Python library for making text console applications. It has many features including fluid
💻 PY
📖 第 1 页 / 共 2 页
字号:
#!/usr/bin/python# -*- coding: utf-8 -*-## Urwid utility functions#    Copyright (C) 2004-2006  Ian Ward##    This library is free software; you can redistribute it and/or#    modify it under the terms of the GNU Lesser General Public#    License as published by the Free Software Foundation; either#    version 2.1 of the License, or (at your option) any later version.##    This library is distributed in the hope that it will be useful,#    but WITHOUT ANY WARRANTY; without even the implied warranty of#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU#    Lesser General Public License for more details.##    You should have received a copy of the GNU Lesser General Public#    License along with this library; if not, write to the Free Software#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA## Urwid web site: http://excess.org/urwid/from __future__ import nested_scopesimport escapeimport encodingsimport weakreftry:	import str_utilexcept ImportError:	import old_str_util as str_util# bring str_util functions into our namespacecalc_text_pos = str_util.calc_text_poscalc_width = str_util.calc_widthis_wide_char = str_util.is_wide_charmove_next_char = str_util.move_next_charmove_prev_char = str_util.move_prev_charwithin_double_byte = str_util.within_double_bytetry: enumerateexcept: enumerate = lambda x: zip(range(len(x)),x) # old python# Try to determine if using a supported double-byte encodingimport localetry:	try:		locale.setlocale( locale.LC_ALL, "" )	except locale.Error:		pass	detected_encoding = locale.getlocale()[1]	if not detected_encoding:		detected_encoding = ""except ValueError, e:	# with invalid LANG value python will throw ValueError	if e.args and e.args[0].startswith("unknown locale"):		detected_encoding = ""	else:		raise_target_encoding = None_use_dec_special = Truedef set_encoding( encoding ):	"""	Set the byte encoding to assume when processing strings and the	encoding to use when converting unicode strings.	"""	encoding = encoding.lower()	global _target_encoding, _use_dec_special	if encoding in ( 'utf-8', 'utf8', 'utf' ):		str_util.set_byte_encoding("utf8")					_use_dec_special = False	elif encoding in ( 'euc-jp' # JISX 0208 only			, 'euc-kr', 'euc-cn', 'euc-tw' # CNS 11643 plain 1 only			, 'gb2312', 'gbk', 'big5', 'cn-gb', 'uhc'			# these shouldn't happen, should they?			, 'eucjp', 'euckr', 'euccn', 'euctw', 'cncb' ):		str_util.set_byte_encoding("wide")					_use_dec_special = True	else:		str_util.set_byte_encoding("narrow")		_use_dec_special = True	# if encoding is valid for conversion from unicode, remember it	_target_encoding = 'ascii'	try:			if encoding:			u"".encode(encoding)			_target_encoding = encoding	except LookupError: passdef get_encoding_mode():	"""	Get the mode Urwid is using when processing text strings.	Returns 'narrow' for 8-bit encodings, 'wide' for CJK encodings	or 'utf8' for UTF-8 encodings.	"""	return str_util.get_byte_encoding()def apply_target_encoding( s ):	"""	Return (encoded byte string, character set rle).	"""	if _use_dec_special and type(s) == type(u""):		# first convert drawing characters		try:			s = s.translate( escape.DEC_SPECIAL_CHARMAP )		except NotImplementedError:			# python < 2.4 needs to do this the hard way..			for c, alt in zip(escape.DEC_SPECIAL_CHARS, 					escape.ALT_DEC_SPECIAL_CHARS):				s = s.replace( c, escape.SO+alt+escape.SI )		if type(s) == type(u""):		s = s.replace( escape.SI+escape.SO, u"" ) # remove redundant shifts		s = s.encode( _target_encoding )	sis = s.split( escape.SO )	sis0 = sis[0].replace( escape.SI, "" )	sout = []	cout = []	if sis0:		sout.append( sis0 )		cout.append( (None,len(sis0)) )		if len(sis)==1:		return sis0, cout		for sn in sis[1:]:		sl = sn.split( escape.SI, 1 ) 		if len(sl) == 1:			sin = sl[0]			sout.append(sin)			rle_append_modify(cout, (escape.DEC_TAG, len(sin)))			continue		sin, son = sl		son = son.replace( escape.SI, "" )		if sin:			sout.append(sin)			rle_append_modify(cout, (escape.DEC_TAG, len(sin)))		if son:			sout.append(son)			rle_append_modify(cout, (None, len(son)))		return "".join(sout), cout		####################################################################### Try to set the encoding using the one detected by the locale moduleset_encoding( detected_encoding )######################################################################def supports_unicode():	"""	Return True if python is able to convert non-ascii unicode strings	to the current encoding.	"""	return _target_encoding and _target_encoding != 'ascii'class TextLayout:	def supports_align_mode(self, align):		"""Return True if align is a supported align mode."""		return True	def supports_wrap_mode(self, wrap):		"""Return True if wrap is a supported wrap mode."""		return True	def layout(self, text, width, align, wrap ):		"""		Return a layout structure for text.				text -- string in current encoding or unicode string		width -- number of screen columns available		align -- align mode for text		wrap -- wrap mode for text		Layout structure is a list of line layouts, one per output line.		Line layouts are lists than may contain the following tuples:		  ( column width of text segment, start offset, end offset )		  ( number of space characters to insert, offset or None)		  ( column width of insert text, offset, "insert text" )		The offset in the last two tuples is used to determine the		attribute used for the inserted spaces or text respectively.  		The attribute used will be the same as the attribute at that 		text offset.  If the offset is None when inserting spaces		then no attribute will be used.		"""		assert 0, ("This function must be overridden by a real"			" text layout class. (see StandardTextLayout)")		return [[]]class StandardTextLayout(TextLayout):	def __init__(self):#, tab_stops=(), tab_stop_every=8):		pass		#"""		#tab_stops -- list of screen column indexes for tab stops		#tab_stop_every -- repeated interval for following tab stops		#"""		#assert tab_stop_every is None or type(tab_stop_every)==type(0)		#if not tab_stops and tab_stop_every:		#	self.tab_stops = (tab_stop_every,)		#self.tab_stops = tab_stops		#self.tab_stop_every = tab_stop_every	def supports_align_mode(self, align):		"""Return True if align is 'left', 'center' or 'right'."""		return align in ('left', 'center', 'right')	def supports_wrap_mode(self, wrap):		"""Return True if wrap is 'any', 'space' or 'clip'."""		return wrap in ('any', 'space', 'clip')	def layout(self, text, width, align, wrap ):		"""Return a layout structure for text."""		segs = self.calculate_text_segments( text, width, wrap )		return self.align_layout( text, width, segs, wrap, align )	def pack(self, maxcol, layout):		"""		Return a minimal maxcol value that would result in the same		number of lines for layout.  layout must be a layout structure		returned by self.layout().		"""		maxwidth = 0		assert layout, "huh? empty layout?: "+`layout`		for l in layout:			lw = line_width(l)			if lw >= maxcol:				return maxcol			maxwidth = max(maxwidth, lw)		return maxwidth				def align_layout( self, text, width, segs, wrap, align ):		"""Convert the layout segs to an aligned layout."""		out = []		for l in segs:			sc = line_width(l)			if sc == width or align=='left':				out.append(l)				continue			if align == 'right':				out.append([(width-sc, None)] + l)				continue			assert align == 'center'			out.append([((width-sc+1)/2, None)] + l)		return out			def calculate_text_segments( self, text, width, wrap ):		"""		Calculate the segments of text to display given width screen 		columns to display them.  				text - text to display		width - number of available screen columns		wrap - wrapping mode used				Returns a layout structure without aligmnent applied.		"""		b = []		p = 0		if wrap == 'clip':			# no wrapping to calculate, so it's easy.			while p<=len(text):				n_cr = text.find("\n", p)				if n_cr == -1: 					n_cr = len(text)				sc = calc_width(text, p, n_cr)				l = [(0,n_cr)]				if p!=n_cr:					l = [(sc, p, n_cr)] + l				b.append(l)				p = n_cr+1			return b				while p<=len(text):			# look for next eligible line break			n_cr = text.find("\n", p)			if n_cr == -1: 				n_cr = len(text)			sc = calc_width(text, p, n_cr)			if sc == 0:				# removed character hint				b.append([(0,n_cr)])				p = n_cr+1				continue			if sc <= width:				# this segment fits				b.append([(sc,p,n_cr),					# removed character hint					(0,n_cr)])								p = n_cr+1				continue			pos, sc = calc_text_pos( text, p, n_cr, width )			# FIXME: handle pathological width=1 double-byte case			if wrap == 'any':				b.append([(sc,p,pos)])				p = pos				continue			assert wrap == 'space'			if text[pos] == " ":				# perfect space wrap				b.append([(sc,p,pos),					# removed character hint					(0,pos)])				p = pos+1				continue			if is_wide_char(text, pos):				# perfect next wide				b.append([(sc,p,pos)])				p = pos				continue			prev = pos				while prev > p:				prev = move_prev_char(text, p, prev)				if text[prev] == " ":					sc = calc_width(text,p,prev)					l = [(0,prev)]					if p!=prev:						l = [(sc,p,prev)] + l					b.append(l)					p = prev+1 					break				if is_wide_char(text,prev):					# wrap after wide char					next = move_next_char(text, prev, pos)					sc = calc_width(text,p,next)					b.append([(sc,p,next)])					p = next					break			else:				# unwrap previous line space if possible to				# fit more text (we're breaking a word anyway)				if b and (len(b[-1]) == 2 or ( len(b[-1])==1 						and len(b[-1][0])==2 )):					# look for removed space above					if len(b[-1]) == 1:						[(h_sc, h_off)] = b[-1]						p_sc = 0						p_off = p_end = h_off					else:						[(p_sc, p_off, p_end),				       		(h_sc, h_off)] = b[-1]					if (p_sc < width and h_sc==0 and						text[h_off] == " "):						# combine with previous line						del b[-1]						p = p_off						pos, sc = calc_text_pos( 							text, p, n_cr, width )						b.append([(sc,p,pos)])						# check for trailing " " or "\n"						p = pos						if p < len(text) and (							text[p] in (" ","\n")):							# removed character hint							b[-1].append((0,p))							p += 1						continue																# force any char wrap				b.append([(sc,p,pos)])				p = pos		return b####################################### default layout object to usedefault_layout = StandardTextLayout()######################################	class LayoutSegment:	def __init__(self, seg):		"""Create object from line layout segment structure"""				assert type(seg) == type(()), `seg`		assert len(seg) in (2,3), `seg`				self.sc, self.offs = seg[:2]				assert type(self.sc) == type(0), `self.sc`				if len(seg)==3:			assert type(self.offs) == type(0), `self.offs`			assert self.sc > 0, `seg`			t = seg[2]			if type(t) == type(""):				self.text = t				self.end = None			else:				assert type(t) == type(0), `t`				self.text = None				self.end = t		else:			assert len(seg) == 2, `seg`			if self.offs is not None:				assert self.sc >= 0, `seg`				assert type(self.offs)==type(0)			self.text = self.end = None				def subseg(self, text, start, end):		"""		Return a "sub-segment" list containing segment structures 		that make up a portion of this segment.		A list is returned to handle cases where wide characters		need to be replaced with a space character at either edge		so two or three segments will be returned.		"""		if start < 0: start = 0		if end > self.sc: end = self.sc		if start >= end:			return [] # completely gone		if self.text:			# use text stored in segment (self.text)			spos, epos, pad_left, pad_right = calc_trim_text(				self.text, 0, len(self.text), start, end )			return [ (end-start, self.offs, " "*pad_left + 				self.text[spos:epos] + " "*pad_right) ]		elif self.end:			# use text passed as parameter (text)			spos, epos, pad_left, pad_right = calc_trim_text(				text, self.offs, self.end, start, end )			l = []			if pad_left:				l.append((1,spos-1))			l.append((end-start-pad_left-pad_right, spos, epos))			if pad_right:				l.append((1,epos))			return l		else:			# simple padding adjustment			return [(end-start,self.offs)]def line_width( segs ):	"""	Return the screen column width of one line of a text layout structure.	This function ignores any existing shift applied to the line,	represended by an (amount, None) tuple at the start of the line.	"""	sc = 0	seglist = segs	if segs and len(segs[0])==2 and segs[0][1]==None:		seglist = segs[1:]	for s in seglist:		sc += s[0]	return scdef shift_line( segs, amount ):	"""	Return a shifted line from a layout structure to the left or right.	segs -- line of a layout structure	amount -- screen columns to shift right (+ve) or left (-ve)	"""	assert type(amount)==type(0), `amount`		if segs and len(segs[0])==2 and segs[0][1]==None:		# existing shift		amount += segs[0][0]		if amount:			return [(amount,None)]+segs[1:]		return segs[1:]				if amount:		return [(amount,None)]+segs	return segs	def trim_line( segs, text, start, end ):	"""	Return a trimmed line of a text layout structure.	text -- text to which this layout structre applies	start -- starting screen column	end -- ending screen column

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -