X7ROOT File Manager
Current Path:
/opt/cloudlinux/venv/lib/python3.11/site-packages/guppy/gsl
opt
/
cloudlinux
/
venv
/
lib
/
python3.11
/
site-packages
/
guppy
/
gsl
/
??
..
??
Document.py
(57.55 KB)
??
DottedTree.py
(8.58 KB)
??
Exceptions.py
(402 B)
??
FileIO.py
(2.6 KB)
??
Filer.py
(3.83 KB)
??
Gsml.py
(2.69 KB)
??
Help.py
(1018 B)
??
Html.py
(17.46 KB)
??
Latex.py
(25.16 KB)
??
Main.py
(66.91 KB)
??
SpecNodes.py
(18.48 KB)
??
Tester.py
(23.99 KB)
??
Text.py
(31.13 KB)
??
XHTML.py
(18.38 KB)
??
__init__.py
(53 B)
??
__pycache__
Editing: Text.py
# Convert a node representation to text # in some different forms # o output to an object with an interface subset of Tk Text # o output to ascii-only - best attempt w.o. different fonts # o output to man-page text # Parameterized on out # I have to define the roles of responsibility. # out is a thin layer above something Tk text-like # it isolates some details but doesn't provide real new functionality # Node2Inter takes care of the general formatting # It needs to know about # o the size of out, i.e. width and height # o the fonts and sizes available # o the special characters available # o the size of the fonts # o we restrict to fixed size fonts # otherwise it would have to ask for size of strings? # # to be able to do # o line wrapping # o paragraphs # o headers # o item and bullet lists # o tables # The out can 'record' its commands # and play them on an actual Tk text window. # with a simple translation # o it can operate stack-free # -- so after eg a font change, there is a font change back # Does the out has a configuration table # such as, # o the fonts to choose # o for different sizes # o whether to make items bold # In any case there may be default here.. class Node2Inter: def __init__(self, mod, node, out, cnf, width=None): self.mod = mod self.out = out self.cnf = cnf self.width = width self.span_stack = [] self.attrs_stack = [{}] self.atparbegin = 1 self.inpre = 0 self.ul_level = 0 self.prev_margin_bottom = 0 self.sizescale = cnf.sizescale if node is not None: self._visit_outer_node(node) def _visit_outer_node(self, node): cnf = self.cnf self.span_begin(font_family=cnf.textfamily, font_size=cnf.sizeindex) node, attrs = node.split_attrs() for k, v in attrs: k = k.strip() v = v.strip() setattr(self.out, '_gsl_%s' % k, v) node.accept(self) self.span_end() def _visit_node(self): node, attrs = node.split_attrs() if attrs: self.attrs_stack def append(self, x): self.out.insert('end', x, self.tags) def div(self, node, margin_bottom=0, **kwds): self.div_begin(**kwds) node.arg_accept(self) self.div_end(margin_bottom) def div_begin(self, margin_top=0, **kwds): if self.span_stack: d = self.span_stack[-1] if 'spacing1' in d: if self.atparbegin: margin_top = max(margin_top, d['spacing1']) self.tag_config(self.tag, **d) del d['spacing1'] margin_top = max(margin_top, self.prev_margin_bottom) self.prev_margin_bottom = 0 if not self.atparbegin: self.nl() self.atparbegin = 1 if margin_top: kwds['spacing1'] = margin_top self.span_begin(**kwds) def div_end(self, margin_bottom=0): if not self.atparbegin: self.nl() self.span_end() self.atparbegin = 1 self.prev_margin_bottom = margin_bottom def getopt(self, name, default=0): if self.span_stack and name in self.span_stack[-1]: return self.span_stack[-1][name] else: return getattr(self, name, default) def nl(self): self.append('\n') def set_default_tag(self): if self.span_stack: tag = 't%s' % self.mod._root.pickle.dumps(self.span_stack[-1]) else: tag = 'tag' self.tag = tag self.tags = (tag,) def span(self, node, **kwds): self.span_begin(**kwds) node.arg_accept(self) self.span_end() def span_begin(self, **kwds): if self.span_stack: d = self.span_stack[-1].copy() d.update(kwds) else: d = kwds self.span_stack.append(d) self.set_default_tag() def span_end(self): tag = self.tag self.tag_config(tag, **self.span_stack[-1]) self.span_stack.pop() self.set_default_tag() def tag_config(self, tag, **kwds): okwds = {} fontspecs = [] for k, v in list(kwds.items()): if not k.startswith('font_'): okwds[k] = v continue else: fontspecs.append((k[5:], v)) if fontspecs: font = [None, None, ''] for k, v in fontspecs: if k == 'size': v = max(0, min(len(self.sizescale)-1, v)) font[1] = self.sizescale[v] elif k == 'family': font[0] = v else: if font[2]: font[2] += ' ' font[2] += k if not font[2]: font.pop() okwds['font'] = tuple(font) self.out.tag_config(tag, **okwds) def text(self, text): if not self.inpre: if self.atparbegin: text = text.lstrip() if not text: return text = text.replace('\n', ' ') text = text.replace('\t', ' ') while ' ' in text: text = text.replace(' ', ' ') if self.atparbegin and self.prev_margin_bottom: self.tag_config(self.tag, **self.span_stack[-1]) self.span_stack[-1]['spacing1'] = self.prev_margin_bottom self.set_default_tag() self.prev_margin_bottom = 0 self.append(text) else: text = text.expandtabs() idx = text.find('\n') if idx != -1 and 'spacing1' in self.span_stack[-1]: self.append(text[:idx+1]) self.tag_config(self.tag, **self.span_stack[-1]) del self.span_stack[-1]['spacing1'] self.set_default_tag() text = text[idx+1:] if text: self.append(text) self.atparbegin = 0 def _visit_children(self, node): E = self.mod.ReportedError for ch in node.children: try: ch.accept(self) except E: pass def _visit_hx(self, node): n = int(node.tag[1:]) font_size = 7 - n margin_top = 12 - 1 * n margin_bottom = 12 - 1 * n self.div(node, font_size=font_size, font_bold=1, margin_top=margin_top, margin_bottom=margin_bottom) def visit_big(self, node): self.span(node, font_size=self.getopt('font_size') + 1) def visit_blockquote(self, node): lmargin = self.getopt('lmargin1') + 36 rmargin = self.getopt('rmargin') + 36 self.div(node, lmargin1=lmargin, lmargin2=lmargin, rmargin=rmargin, margin_top=6, margin_bottom=6, ) def visit_char(self, node): code = node.arg.strip() if code == 'nbsp': self.span_begin(invisible=1) self.append('x') self.span_end() else: self.error( 'I do not know how to render this character code: %r.' % code, node) def visit_code(self, node): self.span(node, font_family=self.cnf.codefamily) def visit_comment(self, node): pass def visit_dl(self, node): self.div(node) def visit_dt(self, node): self.div(node) def visit_dd(self, node): lmargin = self.getopt('lmargin1') + 36 self.div(node, lmargin1=lmargin, lmargin2=lmargin) def visit_define(self, node): # xxx self._visit_children(node) def visit_div(self, node): self.div(node) def visit_document(self, node): self._visit_children(node) def visit_document_lang(self, node): if self.document_lang is not None: self.error('Duplicate document lang directive.', node) self.document_lang = node def visit_document_title(self, node): if self.document_title is not None: self.error('Duplicate document title directive.', node) self.document_title = node def visit_em(self, node): self.span(node, font_italic=1) def visit_file(self, node): self._visit_children(node) def visit_gsl_title(self, node): self.out._gsl_title = node.arg def visit_gsl_width(self, node): self.out._gsl_width = int(node.arg) def visit_gsl_height(self, node): self.out._gsl_height = int(node.arg) def visit_h1(self, node): self._visit_hx(node) def visit_h2(self, node): self._visit_hx(node) def visit_h3(self, node): self._visit_hx(node) def visit_h4(self, node): self._visit_hx(node) def visit_h5(self, node): self._visit_hx(node) def visit_h6(self, node): self._visit_hx(node) def visit_li(self, node): indent = self.getopt('lmargin1') + 18 self.div_begin( lmargin1=indent, lmargin2=indent ) mode = ['disc', 'square', 'circle'][self.ul_level % 3] char = {'disc': '*', 'circle': 'O', 'square': '[]'}[mode] self.span_begin() self.text('%s ' % char) self.span_end() self.span_begin( lmargin1=indent, lmargin2=indent+12 ) node.arg_accept(self) self.span_end() self.div_end() def visit_p(self, node): self.div(node, margin_top=6, margin_bottom=6) def visit_pre(self, node): self.inpre += 1 self.div(node, font_family=self.cnf.codefamily, margin_top=6, margin_bottom=6) self.inpre -= 1 def visit_small(self, node): self.span(node, font_size=self.getopt('font_size') - 1) def visit_span(self, node): self.span(node) def visit_string(self, node): self._visit_children(node) def visit_strong(self, node): self.span(node, font_bold=1) def visit_sub(self, node): self.span(node, font_size=self.getopt('font_size') - 1, offset=self.getopt('offset') - 2 ) def visit_sup(self, node): self.span(node, font_size=self.getopt('font_size') - 1, offset=self.getopt('offset') + 2 ) def visit_table(self, node): Table(self, node) pass def visit_td(self, node): pass def visit_th(self, node): pass def visit_tr(self, node): pass def visit_text(self, node): self.text(node.arg) self._visit_children(node) def visit_u(self, node): self.span(node, underline=1) def visit_ul(self, node): self.ul_level += 1 self.div(node) self.ul_level -= 1 def visit_var(self, node): self.span(node, font_italic=1) class SimulText: def __init__(self, mod, width=None): self.mod = mod self.width = width self.lines = [[]] self.tags = {} self.textntags = [] self.fonts = {} def insert(self, pos, text, tags): assert pos == 'end' lines = text.split('\n') self.lines[-1].append((lines[0], tags)) for line in lines[1:]: self.lines.append([(line, tags)]) self.textntags.append((text, tags)) def tag_config(self, tag, **kwds): if tag in self.tags and kwds == self.tags[tag]: return self.tags[tag] = kwds ## def finalize(self): if len(self.lines[-1]) == 1 and not self.lines[-1][0][0]: self.lines.pop() if self.width is not None: self.wrap_lines() def get_width(self): width = 0 for line in self.lines: w = self.text_width(line) if w > width: width = w return width def replay(self, out, lineidx): if lineidx >= len(self.lines): return line = self.lines[lineidx] for (ch, tags) in line: out.insert('end', ch, tags) for tag in tags: out.tag_config(tag, **self.tags[tag]) def split_word(self, line): words = [[]] for text, tags in line: wtext = text.split(' ') for wt in wtext: if wt: words[-1].append((wt, tags)) if words[-1]: words.append([]) return words def text_width(self, textntags): font = None subline = None subfonts = [] for ch, tags in textntags: for tag in tags: if tag in self.tags and 'font' in self.tags[tag]: newfont = self.tags[tag]['font'] break else: assert 0 if newfont != font: if subline: subfonts.append((subline, font)) font = newfont subline = [] subline.append(ch) if subline: subfonts.append((subline, font)) width = 0 for (subline, font) in subfonts: f = self.mod.makefont(font) m = f.measure(''.join(subline)) width += m return width def width_to(self, char): # distance from left margin to first occurence of char # or the width of longest line, if char not found for line in self.lines: w = 0 found = 0 for (text, tags) in line: if char in text: text = text[:text.index(char)] found = 1 w += self.text_width([(text, tags)]) if found: break if found: break if not found: w = self.get_width() return w def wrap_line(self, line): w = self.text_width(line) if w <= self.width: self.lines.append(line) return words = self.split_word(line) i = 0 while i < len(words): pre = list(words[i]) w = self.text_width(pre) while w > self.width: # The word is too long to fit. # I have to cut it off. # xxx this may be somewhat slow # measuring after every character j = 0 # Position j at the chunk that is going to be split while j + 1 < len(pre): w = self.text_width(pre[:j+1]) if w > self.width: break j += 1 # Split this chunk # Allow at least one character k = 2 while k <= len(pre[j][0]): w = self.text_width( pre[:j-1] + [(pre[j][0][:k], pre[j][1])]) if w > self.width: break k += 1 self.lines.append(pre[:j-1] + [(pre[j][0][:k-1], pre[j][1])]) assert self.text_width(self.lines[-1]) <= self.width pre = [(pre[j][0][k-1:], pre[j][1])] w = self.text_width(pre) i += 1 while i < len(words): space = [(' ', pre[-1][1])] word = words[i] w = self.text_width(pre + space + word) if w > self.width: break else: pre.extend(space + word) i += 1 self.lines.append(pre) def wrap_lines(self): lines = self.lines self.lines = [] for line in lines: self.wrap_line(line) class TableCell: def __init__(self, row, node): self.row = row self.table = row.table self.parent = self.table.parent self.cnf = self.parent.cnf self.mod = self.parent.mod self.attrs = {} self.node = self.set_attributes(node) self.gen_out() def align(self, pos, width): align = self.attrs['align'] if align == 'center': self.tabstop = (pos + 0.5*width, 'center') elif align == 'left': self.tabstop = (pos, 'left') elif align == 'right': self.tabstop = (pos+width, 'right') elif align == 'char': w = self.out.width_to(self.attrs['char']) co = float(self.attrs['charoff'].rstrip('%'))/100.0 self.tabstop = (pos + co*width-w, 'left') elif align == 'justify': # XXX I don't know how this works self.tabstop = (pos + 0.5*width, 'center') else: raise ValueError('Invalid align: %s' % align) def get_edges(self, width): align = self.attrs['align'] mywidth = self.width if align == 'center': l, r = 0.5 * width - 0.5 * mywidth, 0.5 * width + 0.5 * mywidth elif align == 'left': l, r = 0, mywidth elif align == 'right': l, r = width - mywidth, width elif align == 'char': w = self.out.width_to(self.attrs['char']) co = float(self.attrs['charoff'].rstrip('%'))/100.0 l = co * width - w r = l + mywidth elif align == 'justify': # XXX I don't know how this works l, r = 0, width else: raise ValueError('Invalid align: %s' % align) return l, r def get_width(self): self.width = self.out.get_width() self.numlines = len(self.out.lines) return self.width def set_attributes(self, node): a = self.attrs if node.tag == 'th': align = 'center' else: align = 'left' a['align'] = align a['char'] = self.cnf.decimal_point a['charoff'] = '50%' node, attrs = node.split_attrs() for k, v in attrs: a[k] = v return node def gen_out(self, width=None): self.out = SimulText(self.mod, width=width) n2i = Node2Inter(self.mod, None, self.out, self.cnf, width=width) kwds = self.parent.span_stack[-1].copy() if self.node.tag == 'th': kwds['font_bold'] = 1 n2i.span_begin(**kwds) self.node.arg_accept(n2i) n2i.span_end() self.out.finalize() self.get_width() def wrap_to_width(self, width): if width >= self.width: return self.gen_out(width) class TableRow: def __init__(self, table, node): self.table = table self.node = node self.numlines = 1 self.cells = [] node, attrs = node.split_attrs() self.attrs = attrs node.children_accept(self) def new_cell(self, node): cell = TableCell(self, node) self.cells.append(cell) def visit_td(self, node): self.new_cell(node) def visit_th(self, node): self.new_cell(node) class Table: def __init__(self, parent, node): self.parent = parent self.node = node self.caption = None self.rows = [] parent.div_begin(margin_top=6) self.lmargin = parent.getopt('lmargin1') node.children_accept(self) Width = 400 w = self.columnify() widths = self.widths spacings = self.spacings if w > Width: # Which one to wrap? # The longest? # All? gw = [Width / len(self.widths)]*len(self.widths) extra = 0 others = list(range(len(self.widths))) for i, w in enumerate(self.widths): if w < gw[i]: extra += gw[i] - w gw[i] = w others.remove(i) extra = int(extra / len(others)) for i in others: gw[i] += extra widths = self.widths = gw for row in self.rows: col = 0 for cell in row.cells: cell.wrap_to_width(gw[col]) col += 1 for row in self.rows: col = 0 pos = 0 for cell in row.cells: w = widths[col] cell.align(pos+self.lmargin, w) pos += w + spacings[col] col += 1 row.numlines = max(row.numlines, cell.numlines) for row in self.rows: for i in range(row.numlines): tabstops = [] for cell in row.cells: tabstops.extend(cell.tabstop) tabstops = tuple(tabstops) if i == 0 and row is self.rows[0]: tabkwds = row.cells[0].out.tags[row.cells[0].out.lines[0][0][1][0]] else: tabkwds = {} if row is not self.rows[0] and i == 0: tabkwds['spacing1'] = 6 tabtag = str(tabstops)+str(tabkwds) for cell in row.cells: parent.out.insert('end', '\t', (tabtag,)) cell.out.replay(parent.out, i) parent.out.tag_config(tabtag, tabs=tabstops, **tabkwds) parent.nl() parent.div_end() def columnify(self): # Make the cells aligned in columns widths = self.widths = [] for row in self.rows: col = 0 for cell in row.cells: w = cell.get_width() if col >= len(widths): widths.append(w) else: widths[col] = max(w, widths[col]) row.numlines = max(row.numlines, cell.numlines) col += 1 # Extra spacing after column i spacings = self.spacings = [0] * len(widths) MINSPACING = 10 for row in self.rows: col = 0 for cell in row.cells[:-1]: rcell = row.cells[col+1] ledge = cell.get_edges(widths[col])[1] redge = rcell.get_edges(widths[col+1])[0]+widths[col] spacing = MINSPACING - (redge - ledge) spacings[col] = max(spacing, spacings[col]) col += 1 width = 0 for row in self.rows: col = 0 pos = 0 for cell in row.cells: w = widths[col] cell.align(pos+self.lmargin, w) pos += w + spacings[col] col += 1 if pos > width: width = pos self.width = width return width def visit_tfoot(self, node): node.children_accept(self) def visit_thead(self, node): node.children_accept(self) def visit_tr(self, node): row = TableRow(self, node) self.rows.append(row) class RecordingInter: FLATTEXT = 1 FLATKWDS = 0 lasttext = () lasttag = None def __init__(self): self.appends = [] self.tag_configs = {} self.lasttext = [] self.clearmemo() def __str__(self): return 'APPENDS: %s TAG_CONFIGS: %s' % (self.appends, self.tag_configs) def clearmemo(self): self.memo = {} # Maps any value to it self self.tagmemo = {} # Maps tag to integer tag number def flush(self): if self.lasttext: tag = self.tagmemo.setdefault(self.lasttag, len(self.tagmemo)) text = ''.join(self.lasttext) text = self.memo.setdefault(text, text) if self.FLATTEXT: self.appends.append(tag) self.appends.append(text) else: tt = tag, text tt = self.memo.setdefault(tt, tt) self.appends.append(tt) self.lasttext = [] def insert(self, pos, text, tags): assert pos == 'end' assert len(tags) == 1 tag = tags[0] if tag != self.lasttag: self.flush() self.lasttag = tag self.lasttext.append(text) def play(self, out): self.flush() if self.FLATTEXT: i = 0 while i < len(self.appends): tag = self.appends[i] text = self.appends[i+1] out.insert('end', text, (tag,)) i += 2 else: for tag, text in self.appends: out.insert('end', text, (tag,)) for (tag, kwdlist) in list(self.tag_configs.items()): if self.FLATKWDS: kwds = {} i = 0 while i < len(kwdlist): kwds[kwdlist[i]] = kwdlist[i+1] i += 2 out.tag_config(tag, **kwds) else: out.tag_config(tag, **dict(kwdlist)) for k in self.__dict__: if k.startswith('_gsl_'): setattr(out, k, getattr(self, k)) def prepare_for_pickle(self): # Call this before pickling to reduce space usage. self.flush() for k in list(self.__dict__.keys()): if k not in ('appends', 'tag_configs') and not k.startswith('_gsl_'): delattr(self, k) def tag_config(self, tag, **kwds): kwdlist = [] for k, v in list(kwds.items()): k = self.memo.setdefault(k, k) v = self.memo.setdefault(v, v) if self.FLATKWDS: kwdlist.append(k) kwdlist.append(v) else: kv = k, v kv = self.memo.setdefault(kv, kv) kwdlist.append(kv) kwdlist = tuple(kwdlist) kwdlist = self.memo.setdefault(kwdlist, kwdlist) tag = self.tagmemo.setdefault(tag, len(self.tagmemo)) if tag in self.tag_configs: assert self.tag_configs[tag] == kwdlist else: self.tag_configs[tag] = kwdlist class TextInter: def __init__(self, mod, wid): self.mod = mod self.wid = wid for name in ( 'config', 'insert', 'tag_delete', ): setattr(self, name, getattr(wid, name)) def tag_config(self, tag, **kwds): if 'invisible' in kwds: del kwds['invisible'] kwds['foreground'] = kwds['background'] = kwds.get( 'background', self.wid['background']) self.wid.tag_config(tag, **kwds) class TkConfig: sizeindex = 3 sizescale = (6, 8, 10, 12, 16, 20, 24, 28) textfamily = 'times' codefamily = 'courier' decimal_point = '.' # default CHAR attribute class _GLUECLAMP_: _imports_ = ( '_parent:SpecNodes', '_parent.SpecNodes:node_of_taci', '_parent.SpecNodes:node_of_string', '_parent.Main:ReportedError', '_parent:Html', '_root:pickle', '_root.md5:md5', '_root:os', '_root:re', '_root:string', '_root:tkinter', ) def _get_makefont(self): fonts = {} root = self.tkinter.Tk() root.withdraw() def makefont(font): if font in fonts: return fonts[font] weight = 'normal' slant = 'roman' if len(font) > 2: if 'bold' in font[2]: weight = 'bold' if 'italic' in font[2]: slant = 'italic' f = self.tkinter.font.Font(family=font[0], size=font[1], weight=weight, slant=slant) fonts[font] = f return f return makefont def _get_tkconfig(self): return TkConfig() def node2inter(self, node, inter, tkconfig=None): if tkconfig is None: tkconfig = self.tkconfig Node2Inter(self, node, inter, tkconfig) def gsltextviewer(self, parent=None, filename=None, text=None, node=None, htmloutfile=None, inpickle=0, inrecorder=0, outrecorder=0 ): # It seems they dont want we mix data and py files in the dist sigh # so these are last minute hacks pickle = self.pickle if inpickle: inrecorder = pickle.loads(inpickle) if node is None: if text is None: if filename is not None: with open(filename) as f: text = f.read() node = self.node_of_string(text, nostrip=1) if htmloutfile is not None: self.Html.node2file(node, htmloutfile) if outrecorder: r = RecordingInter() self.node2inter(node, r) r.prepare_for_pickle() return r cache = None if filename is not None: sp = self.os.path.splitext(filename) if sp[1] == '.gsl': cache = sp[0] + '.gsc' m = self._root.guppy.etc.textView.TextViewer( parent, 'Untitled', data='') v = m.textView v['state'] = 'normal' v['font'] = 'Times -12' v.bind('<Destroy>', lambda event: m.quit()) if cache or inrecorder: if inrecorder: r = inrecorder else: r = None textdigest = self.md5(text.encode('utf-8')).digest() try: f = open(cache) except IOError: pass else: td = f.read(len(textdigest)) if td == textdigest: r = pickle.load(f) f.close() if r is None: r = RecordingInter() self.node2inter(node, r) r.prepare_for_pickle() f = open(cache, 'w') try: try: f.write(textdigest) except IOError: pass # maybe write protected just ignore for now XXX else: pickle.dump(r, f, 0) finally: f.close() r.play(v) else: self.node2inter(node, v) title = getattr(v, '_gsl_title', None) if title: m.title(title) m.iconname(title) geometry = getattr(v, '_gsl_tk_geometry', None) if geometry: m.geometry(geometry) v['state'] = 'disabled' return m def test_string(s=None, name=None): from guppy import Root gsl = Root().guppy.gsl me = gsl.Text if s is None: s = getattr(me._parent.test.testdata, name) T = me.tkinter node = me.node_of_string(s, nostrip=1) me._parent.Html.node2file(node, '/tmp/x.html') t = RecordingInter() me.node2inter(node, t) t.prepare_for_pickle() root = T.Tk() root.withdraw() text = me._root.guppy.etc.textView.TextViewer( root, 'test', data='').textView text['state'] = 'normal' text['font'] = 'Times -12' text.bind('<Destroy>', lambda event: root.quit()) ti = TextInter(me, text) t.play(ti) text.mainloop() def test(): name = 'long_wrapping_tables' name = 'html_tables' test_string(name=name)
Upload File
Create Folder