mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
	
	
		
			441 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			441 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | import W | |||
|  | import Wkeys | |||
|  | import struct | |||
|  | import string | |||
|  | import types | |||
|  | import regex | |||
|  | 
 | |||
|  | nullid = '\0\0' | |||
|  | closedid = struct.pack('h', 468) | |||
|  | openid = struct.pack('h', 469) | |||
|  | closedsolidid = struct.pack('h', 470) | |||
|  | opensolidid = struct.pack('h', 471) | |||
|  | 
 | |||
|  | arrows = (nullid, closedid, openid, closedsolidid, opensolidid) | |||
|  | 
 | |||
|  | has_ctlcharsRE = regex.compile('[\000-\037\177-\377]') | |||
|  | 
 | |||
|  | def double_repr(key, value, truncvalue = 0,  | |||
|  | 			type = type, StringType = types.StringType, | |||
|  | 			has_ctlchars = has_ctlcharsRE.search, _repr = repr, str = str): | |||
|  | 	if type(key) == StringType and has_ctlchars(key) < 0: | |||
|  | 		key = str(key) | |||
|  | 	else: | |||
|  | 		key = _repr(key) | |||
|  | 	if type(value) == StringType and has_ctlchars(value) < 0: | |||
|  | 		value = str(value) | |||
|  | 	elif key == '__builtins__': | |||
|  | 		value = "<" + type(value).__name__ + " '__builtin__'>" | |||
|  | 	elif key == '__return__': | |||
|  | 		# bleh, when returning from a class codeblock we get infinite recursion in repr.  | |||
|  | 		# Use safe repr instead. | |||
|  | 		import repr | |||
|  | 		value = repr.repr(value) | |||
|  | 	else: | |||
|  | 		try: | |||
|  | 			value = _repr(value) | |||
|  | 			'' + value	# test to see if it is a string, in case a __repr__ method is buggy | |||
|  | 		except: | |||
|  | 			value = '<EFBFBD><EFBFBD><EFBFBD> exception in repr()' | |||
|  | 	if truncvalue: | |||
|  | 		return key + '\t' + value[:255] | |||
|  | 	return key + '\t' + value | |||
|  | 
 | |||
|  | 
 | |||
|  | class BrowserWidget(W.List): | |||
|  | 	 | |||
|  | 	LDEF_ID = 471 | |||
|  | 	 | |||
|  | 	def __init__(self, possize, object = None, col = 100, closechildren = 0): | |||
|  | 		W.List.__init__(self, possize, callback = self.listhit) | |||
|  | 		self.object = (None,) | |||
|  | 		self.indent = 16 | |||
|  | 		self.lastmaxindent = 0 | |||
|  | 		self.closechildren = closechildren | |||
|  | 		self.children = [] | |||
|  | 		self.mincol = 64 | |||
|  | 		self.setcolumn(col) | |||
|  | 		self.bind('return', self.openselection) | |||
|  | 		self.bind('enter', self.openselection) | |||
|  | 		if object is not None: | |||
|  | 			self.set(object) | |||
|  | 	 | |||
|  | 	def set(self, object): | |||
|  | 		if self.object[0] is not object: | |||
|  | 			self.object = object, | |||
|  | 			self[:] = self.unpack(object, 0) | |||
|  | 		elif self._parentwindow is not None and self._parentwindow.wid: | |||
|  | 			self.update() | |||
|  | 	 | |||
|  | 	def unpack(self, object, indent): | |||
|  | 		return unpack_object(object, indent) | |||
|  | 	 | |||
|  | 	def update(self): | |||
|  | 		# for now... | |||
|  | 		W.SetCursor('watch') | |||
|  | 		self.setdrawingmode(0) | |||
|  | 		sel = self.getselectedobjects() | |||
|  | 		fold = self.getunfoldedobjects() | |||
|  | 		topcell = self.gettopcell() | |||
|  | 		self[:] = self.unpack(self.object[0], 0) | |||
|  | 		self.unfoldobjects(fold) | |||
|  | 		self.setselectedobjects(sel) | |||
|  | 		self.settopcell(topcell) | |||
|  | 		self.setdrawingmode(1) | |||
|  | 	 | |||
|  | 	def setcolumn(self, col): | |||
|  | 		self.col = col | |||
|  | 		self.colstr = struct.pack('h', col) | |||
|  | 		if self._list: | |||
|  | 			sel = self.getselection() | |||
|  | 			self.setitems(self.items) | |||
|  | 			self.setselection(sel) | |||
|  | 	 | |||
|  | 	def key(self, char, event): | |||
|  | 		if char in (Wkeys.leftarrowkey, Wkeys.rightarrowkey): | |||
|  | 			sel = self.getselection() | |||
|  | 			sel.reverse() | |||
|  | 			self.setdrawingmode(0) | |||
|  | 			for index in sel: | |||
|  | 				self.fold(index, char == Wkeys.rightarrowkey) | |||
|  | 			self.setdrawingmode(1) | |||
|  | 		else: | |||
|  | 			W.List.key(self, char, event) | |||
|  | 	 | |||
|  | 	def rollover(self, (x, y), onoff): | |||
|  | 		if onoff: | |||
|  | 			if self.incolumn((x, y)): | |||
|  | 				W.SetCursor('hmover') | |||
|  | 			else: | |||
|  | 				W.SetCursor('arrow') | |||
|  | 	 | |||
|  | 	def inarrow(self, (x, y)): | |||
|  | 		cl, ct, cr, cb = self._list.LRect((0, 0)) | |||
|  | 		l, t, r, b = self._bounds | |||
|  | 		if (x - cl) < 16: | |||
|  | 			cellheight = cb - ct | |||
|  | 			index = (y - ct) / cellheight | |||
|  | 			if index < len(self.items): | |||
|  | 				return 1, index | |||
|  | 		return None, None | |||
|  | 	 | |||
|  | 	def incolumn(self, (x, y)): | |||
|  | 		l, t, r, b = self._list.LRect((0, 0)) | |||
|  | 		abscol = l + self.col | |||
|  | 		return abs(abscol - x) < 3 | |||
|  | 	 | |||
|  | 	def trackcolumn(self, (x, y)): | |||
|  | 		import Qd, QuickDraw, Evt | |||
|  | 		self.SetPort() | |||
|  | 		l, t, r, b = self._bounds | |||
|  | 		bounds = l, t, r, b = l + 1, t + 1, r - 16, b - 1 | |||
|  | 		abscol = l + self.col | |||
|  | 		mincol = l + self.mincol | |||
|  | 		maxcol = r - 10 | |||
|  | 		diff = abscol - x | |||
|  | 		Qd.PenPat('\000\377\000\377\000\377\000\377') | |||
|  | 		Qd.PenMode(QuickDraw.srcXor) | |||
|  | 		rect = abscol - 1, t, abscol, b | |||
|  | 		Qd.PaintRect(rect) | |||
|  | 		lastpoint = (x, y) | |||
|  | 		newcol = -1 | |||
|  | 		#W.SetCursor('fist') | |||
|  | 		while Evt.Button(): | |||
|  | 			(x, y) = Evt.GetMouse() | |||
|  | 			if (x, y) <> lastpoint: | |||
|  | 				newcol = x + diff | |||
|  | 				newcol = max(newcol, mincol) | |||
|  | 				newcol = min(newcol, maxcol) | |||
|  | 				Qd.PaintRect(rect) | |||
|  | 				rect = newcol - 1, t, newcol, b | |||
|  | 				Qd.PaintRect(rect) | |||
|  | 				lastpoint = (x, y) | |||
|  | 		Qd.PaintRect(rect) | |||
|  | 		Qd.PenPat(Qd.qd.black) | |||
|  | 		Qd.PenNormal() | |||
|  | 		if newcol > 0 and newcol <> abscol: | |||
|  | 			self.setcolumn(newcol - l) | |||
|  | 	 | |||
|  | 	def click(self, point, modifiers): | |||
|  | 		if point == (-1, -1):	# gross. | |||
|  | 			W.List.click(self, point ,modifiers) | |||
|  | 			return | |||
|  | 		hit, index = self.inarrow(point) | |||
|  | 		if hit: | |||
|  | 			(key, value, arrow, indent) = self.items[index] | |||
|  | 			self.fold(index, arrow == 1) | |||
|  | 		elif self.incolumn(point): | |||
|  | 			self.trackcolumn(point) | |||
|  | 		else: | |||
|  | 			W.List.click(self, point, modifiers) | |||
|  | 	 | |||
|  | 	# for W.List.key | |||
|  | 	def findmatch(self, tag): | |||
|  | 		lower = string.lower | |||
|  | 		items = self.items | |||
|  | 		taglen = len(tag) | |||
|  | 		match = '\377' * 100 | |||
|  | 		match_i = -1 | |||
|  | 		for i in range(len(items)): | |||
|  | 			item = lower(str(items[i][0])) | |||
|  | 			if tag <= item < match: | |||
|  | 				match = item | |||
|  | 				match_i = i | |||
|  | 		if match_i >= 0: | |||
|  | 			return match_i | |||
|  | 		else: | |||
|  | 			return len(items) - 1 | |||
|  | 	 | |||
|  | 	def close(self): | |||
|  | 		if self.closechildren: | |||
|  | 			for window in self.children: | |||
|  | 				window.close() | |||
|  | 		self.children = [] | |||
|  | 		W.List.close(self) | |||
|  | 	 | |||
|  | 	def fold(self, index, onoff): | |||
|  | 		(key, value, arrow, indent) = self.items[index] | |||
|  | 		if arrow == 0 or (onoff and arrow == 2) or (not onoff and arrow == 1): | |||
|  | 			return | |||
|  | 		W.SetCursor('watch') | |||
|  | 		topcell = self.gettopcell() | |||
|  | 		if onoff: | |||
|  | 			self[index] = (key, value, 4, indent) | |||
|  | 			self.setdrawingmode(0) | |||
|  | 			self[index+1:index+1] = self.unpack(value, indent + 1) | |||
|  | 			self[index] = (key, value, 2, indent) | |||
|  | 		else: | |||
|  | 			self[index] = (key, value, 3, indent) | |||
|  | 			self.setdrawingmode(0) | |||
|  | 			count = 0 | |||
|  | 			for i in range(index + 1, len(self.items)): | |||
|  | 				(dummy, dummy, dummy, subindent) = self.items[i] | |||
|  | 				if subindent <= indent: | |||
|  | 					break | |||
|  | 				count = count + 1 | |||
|  | 			self[index+1:index+1+count] = [] | |||
|  | 			self[index] = (key, value, 1, indent) | |||
|  | 		maxindent = self.getmaxindent() | |||
|  | 		if maxindent <> self.lastmaxindent: | |||
|  | 			newabsindent = self.col + (maxindent - self.lastmaxindent) * self.indent | |||
|  | 			if newabsindent >= self.mincol: | |||
|  | 				self.setcolumn(newabsindent) | |||
|  | 			self.lastmaxindent = maxindent | |||
|  | 		self.settopcell(topcell) | |||
|  | 		self.setdrawingmode(1) | |||
|  | 	 | |||
|  | 	def unfoldobjects(self, objects): | |||
|  | 		for obj in objects: | |||
|  | 			try: | |||
|  | 				index = self.items.index(obj) | |||
|  | 			except ValueError: | |||
|  | 				pass | |||
|  | 			else: | |||
|  | 				self.fold(index, 1) | |||
|  | 	 | |||
|  | 	def getunfoldedobjects(self): | |||
|  | 		curindent = 0 | |||
|  | 		objects = [] | |||
|  | 		for index in range(len(self.items)): | |||
|  | 			(key, value, arrow, indent) = self.items[index] | |||
|  | 			if indent > curindent: | |||
|  | 				(k, v, a, i) = self.items[index - 1] | |||
|  | 				objects.append((k, v, 1, i)) | |||
|  | 				curindent = indent | |||
|  | 			elif indent < curindent: | |||
|  | 				curindent = indent | |||
|  | 		return objects | |||
|  | 	 | |||
|  | 	def listhit(self, isdbl): | |||
|  | 		if isdbl: | |||
|  | 			self.openselection() | |||
|  | 	 | |||
|  | 	def openselection(self): | |||
|  | 		import os | |||
|  | 		sel = self.getselection() | |||
|  | 		for index in sel: | |||
|  | 			(key, value, arrow, indent) = self[index] | |||
|  | 			if arrow: | |||
|  | 				self.children.append(Browser(value)) | |||
|  | 			elif type(value) == types.StringType and '\0' not in value: | |||
|  | 				editor = self._parentwindow.parent.getscript(value) | |||
|  | 				if editor: | |||
|  | 					editor.select() | |||
|  | 					return | |||
|  | 				elif os.path.exists(value) and os.path.isfile(value): | |||
|  | 					import macfs | |||
|  | 					fss = macfs.FSSpec(value) | |||
|  | 					if fss.GetCreatorType()[1] == 'TEXT': | |||
|  | 						W.getapplication().openscript(value) | |||
|  | 	 | |||
|  | 	def itemrepr(self, (key, value, arrow, indent), str = str, double_repr = double_repr,  | |||
|  | 			arrows = arrows, pack = struct.pack): | |||
|  | 		arrow = arrows[arrow] | |||
|  | 		return arrow + pack('h', self.indent * indent) + self.colstr + \ | |||
|  | 				double_repr(key, value, 1) | |||
|  | 	 | |||
|  | 	def getmaxindent(self, max = max): | |||
|  | 		maxindent = 0 | |||
|  | 		for item in self.items: | |||
|  | 			maxindent = max(maxindent, item[3]) | |||
|  | 		return maxindent | |||
|  | 	 | |||
|  | 	def domenu_copy(self, *args): | |||
|  | 		sel = self.getselectedobjects() | |||
|  | 		selitems = [] | |||
|  | 		for key, value, dummy, dummy in sel: | |||
|  | 			selitems.append(double_repr(key, value)) | |||
|  | 		text = string.join(selitems, '\r') | |||
|  | 		if text: | |||
|  | 			import Scrap | |||
|  | 			Scrap.ZeroScrap() | |||
|  | 			Scrap.PutScrap('TEXT', text) | |||
|  | 
 | |||
|  | 
 | |||
|  | class Browser: | |||
|  | 	 | |||
|  | 	def __init__(self, object = None, title = None, closechildren = 0): | |||
|  | 		if hasattr(object, '__name__'): | |||
|  | 			name = object.__name__ | |||
|  | 		else: | |||
|  | 			name = '' | |||
|  | 		if title is None: | |||
|  | 			title = 'Object browser' | |||
|  | 			if name: | |||
|  | 				title = title + ': ' + name | |||
|  | 		self.w = w = W.Window((300, 400), title, minsize = (100, 100)) | |||
|  | 		w.info = W.TextBox((18, 8, -70, 15)) | |||
|  | 		w.updatebutton = W.Button((-64, 4, 50, 16), 'Update', self.update) | |||
|  | 		w.browser = BrowserWidget((-1, 24, 1, -14), None) | |||
|  | 		w.bind('cmdu', w.updatebutton.push) | |||
|  | 		w.open() | |||
|  | 		self.set(object, name) | |||
|  | 	 | |||
|  | 	def close(self): | |||
|  | 		if self.w.wid: | |||
|  | 			self.w.close() | |||
|  | 	 | |||
|  | 	def set(self, object, name = ''): | |||
|  | 		W.SetCursor('watch') | |||
|  | 		tp = type(object).__name__ | |||
|  | 		try: | |||
|  | 			length = len(object) | |||
|  | 		except: | |||
|  | 			length = -1 | |||
|  | 		if not name and hasattr(object, '__name__'): | |||
|  | 			name = object.__name__ | |||
|  | 		if name: | |||
|  | 			info = name + ': ' + tp | |||
|  | 		else: | |||
|  | 			info = tp | |||
|  | 		if length >= 0: | |||
|  | 			if length == 1: | |||
|  | 				info = info + ' (%d element)' % length | |||
|  | 			else: | |||
|  | 				info = info + ' (%d elements)' % length | |||
|  | 		self.w.info.set(info) | |||
|  | 		self.w.browser.set(object) | |||
|  | 	 | |||
|  | 	def update(self): | |||
|  | 		self.w.browser.update() | |||
|  | 
 | |||
|  | 
 | |||
|  | SIMPLE_TYPES = ( | |||
|  | 	types.NoneType, | |||
|  | 	types.IntType, | |||
|  | 	types.LongType, | |||
|  | 	types.FloatType, | |||
|  | 	types.ComplexType, | |||
|  | 	types.StringType | |||
|  | ) | |||
|  | 
 | |||
|  | INDEXING_TYPES = ( | |||
|  | 	types.TupleType, | |||
|  | 	types.ListType, | |||
|  | 	types.DictionaryType | |||
|  | ) | |||
|  | 
 | |||
|  | def unpack_object(object, indent = 0): | |||
|  | 	tp = type(object) | |||
|  | 	if tp in SIMPLE_TYPES and tp is not types.NoneType: | |||
|  | 		raise TypeError, 'can<EFBFBD>t browse simple type: %s' % tp.__name__ | |||
|  | 	elif tp == types.DictionaryType: | |||
|  | 		return unpack_dict(object, indent) | |||
|  | 	elif tp in (types.TupleType, types.ListType): | |||
|  | 		return unpack_sequence(object, indent) | |||
|  | 	elif tp == types.InstanceType: | |||
|  | 		return unpack_instance(object, indent) | |||
|  | 	elif tp == types.ClassType: | |||
|  | 		return unpack_class(object, indent) | |||
|  | 	elif tp == types.ModuleType: | |||
|  | 		return unpack_dict(object.__dict__, indent) | |||
|  | 	else: | |||
|  | 		return unpack_other(object, indent) | |||
|  | 
 | |||
|  | def unpack_sequence(seq, indent = 0): | |||
|  | 	items = map(None, range(len(seq)), seq) | |||
|  | 	items = map(lambda (k, v), type = type, simp = SIMPLE_TYPES, indent = indent:  | |||
|  | 				(k, v, not type(v) in simp, indent), items) | |||
|  | 	return items | |||
|  | 
 | |||
|  | def unpack_dict(dict, indent = 0): | |||
|  | 	items = dict.items() | |||
|  | 	return pack_items(items, indent) | |||
|  | 
 | |||
|  | def unpack_instance(inst, indent = 0): | |||
|  | 	if hasattr(inst, '__pybrowse_unpack__'): | |||
|  | 		return unpack_object(inst.__pybrowse_unpack__(), indent) | |||
|  | 	else: | |||
|  | 		items = [('__class__', inst.__class__)] + inst.__dict__.items() | |||
|  | 		return pack_items(items, indent) | |||
|  | 
 | |||
|  | def unpack_class(clss, indent = 0): | |||
|  | 	items = [('__bases__', clss.__bases__), ('__name__', clss.__name__)] + clss.__dict__.items() | |||
|  | 	return pack_items(items, indent) | |||
|  | 
 | |||
|  | def unpack_other(object, indent = 0): | |||
|  | 	attrs = [] | |||
|  | 	if hasattr(object, '__members__'): | |||
|  | 		attrs = attrs + object.__members__ | |||
|  | 	if hasattr(object, '__methods__'): | |||
|  | 		attrs = attrs + object.__methods__ | |||
|  | 	items = [] | |||
|  | 	for attr in attrs: | |||
|  | 		items.append((attr, getattr(object, attr))) | |||
|  | 	return pack_items(items, indent) | |||
|  | 
 | |||
|  | def pack_items(items, indent = 0): | |||
|  | 	items = map(lambda (k, v), type = type, simp = SIMPLE_TYPES, indent = indent:  | |||
|  | 				(k, v, not type(v) in simp, indent),  | |||
|  | 			items) | |||
|  | 	return tuple_caselesssort(items) | |||
|  | 
 | |||
|  | def caselesssort(alist): | |||
|  | 	"""Return a sorted copy of a list. If there are only strings in the list, 
 | |||
|  | 	it will not consider case"""
 | |||
|  | 	 | |||
|  | 	try: | |||
|  | 		# turn ['FOO',  'aaBc', 'ABcD'] into [('foo', 'FOO'), ('aabc', 'aaBc'), ('abcd', 'ABcD')], if possible | |||
|  | 		tupledlist = map(lambda item, lower = string.lower: (lower(item), item), alist) | |||
|  | 	except TypeError: | |||
|  | 		# at least one element in alist is not a string, proceed the normal way... | |||
|  | 		alist = alist[:] | |||
|  | 		alist.sort() | |||
|  | 		return alist | |||
|  | 	else: | |||
|  | 		tupledlist.sort() | |||
|  | 		# turn [('aabc', 'aaBc'), ('abcd', 'ABcD'), ('foo', 'FOO')] into ['aaBc', 'ABcD', 'FOO'] | |||
|  | 		return map(lambda x: x[1], tupledlist) | |||
|  | 
 | |||
|  | def tuple_caselesssort(items): | |||
|  | 	try: | |||
|  | 		tupledlist = map(lambda tuple, lower = string.lower: (lower(tuple[0]), tuple), items) | |||
|  | 	except TypeError: | |||
|  | 		items = items[:] | |||
|  | 		items.sort() | |||
|  | 		return items | |||
|  | 	else: | |||
|  | 		tupledlist.sort() | |||
|  | 		return map(lambda (low, tuple): tuple, tupledlist) | |||
|  | 
 |