19 |
19 |
20 |
20 |
21 __all__ = ['HtmlFormatter'] |
21 __all__ = ['HtmlFormatter'] |
22 |
22 |
23 |
23 |
24 def escape_html(text): |
24 _escape_html_table = { |
|
25 ord('&'): '&', |
|
26 ord('<'): '<', |
|
27 ord('>'): '>', |
|
28 ord('"'): '"', |
|
29 ord("'"): ''', |
|
30 } |
|
31 |
|
32 def escape_html(text, table=_escape_html_table): |
25 """Escape &, <, > as well as single and double quotes for HTML.""" |
33 """Escape &, <, > as well as single and double quotes for HTML.""" |
26 return text.replace('&', '&'). \ |
34 return text.translate(table) |
27 replace('<', '<'). \ |
|
28 replace('>', '>'). \ |
|
29 replace('"', '"'). \ |
|
30 replace("'", ''') |
|
31 |
|
32 |
35 |
33 def get_random_id(): |
36 def get_random_id(): |
34 """Return a random id for javascript fields.""" |
37 """Return a random id for javascript fields.""" |
35 from random import random |
38 from random import random |
36 from time import time |
39 from time import time |
369 try: |
372 try: |
370 self.hl_lines.add(int(lineno)) |
373 self.hl_lines.add(int(lineno)) |
371 except ValueError: |
374 except ValueError: |
372 pass |
375 pass |
373 |
376 |
374 self._class_cache = {} |
|
375 self._create_stylesheet() |
377 self._create_stylesheet() |
376 |
378 |
377 def _get_css_class(self, ttype): |
379 def _get_css_class(self, ttype): |
378 """Return the css class of this token type prefixed with |
380 """Return the css class of this token type prefixed with |
379 the classprefix option.""" |
381 the classprefix option.""" |
380 if ttype in self._class_cache: |
382 ttypeclass = _get_ttype_class(ttype) |
381 return self._class_cache[ttype] |
383 if ttypeclass: |
382 return self.classprefix + _get_ttype_class(ttype) |
384 return self.classprefix + ttypeclass |
|
385 return '' |
383 |
386 |
384 def _create_stylesheet(self): |
387 def _create_stylesheet(self): |
385 t2c = self.ttype2class = {Token: ''} |
388 t2c = self.ttype2class = {Token: ''} |
386 c2s = self.class2style = {} |
389 c2s = self.class2style = {} |
387 cp = self.classprefix |
|
388 for ttype, ndef in self.style: |
390 for ttype, ndef in self.style: |
389 name = cp + _get_ttype_class(ttype) |
391 name = self._get_css_class(ttype) |
390 style = '' |
392 style = '' |
391 if ndef['color']: |
393 if ndef['color']: |
392 style += 'color: #%s; ' % ndef['color'] |
394 style += 'color: #%s; ' % ndef['color'] |
393 if ndef['bold']: |
395 if ndef['bold']: |
394 style += 'font-weight: bold; ' |
396 style += 'font-weight: bold; ' |
506 mw = len(str(lncount + fl - 1)) |
508 mw = len(str(lncount + fl - 1)) |
507 sp = self.linenospecial |
509 sp = self.linenospecial |
508 st = self.linenostep |
510 st = self.linenostep |
509 la = self.lineanchors |
511 la = self.lineanchors |
510 aln = self.anchorlinenos |
512 aln = self.anchorlinenos |
|
513 nocls = self.noclasses |
511 if sp: |
514 if sp: |
512 lines = [] |
515 lines = [] |
513 |
516 |
514 for i in range(fl, fl+lncount): |
517 for i in range(fl, fl+lncount): |
515 if i % st == 0: |
518 if i % st == 0: |
540 ls = '\n'.join(lines) |
543 ls = '\n'.join(lines) |
541 |
544 |
542 # in case you wonder about the seemingly redundant <div> here: since the |
545 # in case you wonder about the seemingly redundant <div> here: since the |
543 # content in the other cell also is wrapped in a div, some browsers in |
546 # content in the other cell also is wrapped in a div, some browsers in |
544 # some configurations seem to mess up the formatting... |
547 # some configurations seem to mess up the formatting... |
545 yield 0, ('<table class="%stable">' % self.cssclass + |
548 if nocls: |
546 '<tr><td class="linenos"><div class="linenodiv"><pre>' + |
549 yield 0, ('<table class="%stable">' % self.cssclass + |
547 ls + '</pre></div></td><td class="code">') |
550 '<tr><td><div class="linenodiv" ' |
|
551 'style="background-color: #f0f0f0; padding-right: 10px">' |
|
552 '<pre style="line-height: 125%">' + |
|
553 ls + '</pre></div></td><td class="code">') |
|
554 else: |
|
555 yield 0, ('<table class="%stable">' % self.cssclass + |
|
556 '<tr><td class="linenos"><div class="linenodiv"><pre>' + |
|
557 ls + '</pre></div></td><td class="code">') |
548 yield 0, dummyoutfile.getvalue() |
558 yield 0, dummyoutfile.getvalue() |
549 yield 0, '</td></tr></table>' |
559 yield 0, '</td></tr></table>' |
550 |
560 |
551 def _wrap_inlinelinenos(self, inner): |
561 def _wrap_inlinelinenos(self, inner): |
552 # need a list of lines since we need the width of a single number :( |
562 # need a list of lines since we need the width of a single number :( |
554 sp = self.linenospecial |
564 sp = self.linenospecial |
555 st = self.linenostep |
565 st = self.linenostep |
556 num = self.linenostart |
566 num = self.linenostart |
557 mw = len(str(len(lines) + num - 1)) |
567 mw = len(str(len(lines) + num - 1)) |
558 |
568 |
559 if sp: |
569 if self.noclasses: |
|
570 if sp: |
|
571 for t, line in lines: |
|
572 if num%sp == 0: |
|
573 style = 'background-color: #ffffc0; padding: 0 5px 0 5px' |
|
574 else: |
|
575 style = 'background-color: #f0f0f0; padding: 0 5px 0 5px' |
|
576 yield 1, '<span style="%s">%*s</span> ' % ( |
|
577 style, mw, (num%st and ' ' or num)) + line |
|
578 num += 1 |
|
579 else: |
|
580 for t, line in lines: |
|
581 yield 1, ('<span style="background-color: #f0f0f0; ' |
|
582 'padding: 0 5px 0 5px">%*s</span> ' % ( |
|
583 mw, (num%st and ' ' or num)) + line) |
|
584 num += 1 |
|
585 elif sp: |
560 for t, line in lines: |
586 for t, line in lines: |
561 yield 1, '<span class="lineno%s">%*s</span> ' % ( |
587 yield 1, '<span class="lineno%s">%*s</span> ' % ( |
562 num%sp == 0 and ' special' or '', mw, |
588 num%sp == 0 and ' special' or '', mw, |
563 (num%st and ' ' or num)) + line |
589 (num%st and ' ' or num)) + line |
564 num += 1 |
590 num += 1 |
614 nocls = self.noclasses |
640 nocls = self.noclasses |
615 lsep = self.lineseparator |
641 lsep = self.lineseparator |
616 # for <span style=""> lookup only |
642 # for <span style=""> lookup only |
617 getcls = self.ttype2class.get |
643 getcls = self.ttype2class.get |
618 c2s = self.class2style |
644 c2s = self.class2style |
|
645 escape_table = _escape_html_table |
619 |
646 |
620 lspan = '' |
647 lspan = '' |
621 line = '' |
648 line = '' |
622 for ttype, value in tokensource: |
649 for ttype, value in tokensource: |
623 if nocls: |
650 if nocls: |
628 cspan = cclass and '<span style="%s">' % c2s[cclass][0] or '' |
655 cspan = cclass and '<span style="%s">' % c2s[cclass][0] or '' |
629 else: |
656 else: |
630 cls = self._get_css_class(ttype) |
657 cls = self._get_css_class(ttype) |
631 cspan = cls and '<span class="%s">' % cls or '' |
658 cspan = cls and '<span class="%s">' % cls or '' |
632 |
659 |
633 parts = escape_html(value).split('\n') |
660 parts = value.translate(escape_table).split('\n') |
634 |
661 |
635 # for all but the last line |
662 # for all but the last line |
636 for part in parts[:-1]: |
663 for part in parts[:-1]: |
637 if line: |
664 if line: |
638 if lspan != cspan: |
665 if lspan != cspan: |