highlighter.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # @Author: Bachir Soussi Chiadmi <bach>
  4. # @Date: 02-06-2017
  5. # @Email: bachir@figureslibres.io
  6. # @Filename: highlighter.py
  7. # @Last modified by: bach
  8. # @Last modified time: 03-06-2017
  9. # @License: GPL-V3
  10. # based on code from :
  11. # Copyright (C) 2008 Christophe Kibleur <kib2@free.fr>
  12. # TODO : see pyQode for more features https://github.com/pyQode
  13. from __future__ import absolute_import, print_function, division, unicode_literals
  14. import sys
  15. import re
  16. # from PyQt5 import QtCore
  17. from PyQt5.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter
  18. from pygments import highlight
  19. from pygments.lexers import *
  20. from pygments.formatter import Formatter
  21. from pygments.styles import get_all_styles, get_style_by_name
  22. # import time
  23. def hex2QColor(c):
  24. r=int(c[0:2],16)
  25. g=int(c[2:4],16)
  26. b=int(c[4:6],16)
  27. return QColor(r,g,b)
  28. class QFormatter(Formatter):
  29. def __init__(self, linenos=True, style="default"): #, style
  30. Formatter.__init__(self)
  31. self.data=[]
  32. self.style = get_style_by_name(style)
  33. # self.linenos = linenos
  34. # Create a dictionary of text styles, indexed
  35. # by pygments token names, containing QTextCharFormat
  36. # instances according to pygments' description
  37. # of each style
  38. self.styles={}
  39. for token, style in self.style:
  40. qtf=QTextCharFormat()
  41. if style['color']:
  42. qtf.setForeground(hex2QColor(style['color']))
  43. if style['bgcolor']:
  44. qtf.setBackground(hex2QColor(style['bgcolor']))
  45. if style['bold']:
  46. qtf.setFontWeight(QFont.Bold)
  47. if style['italic']:
  48. qtf.setFontItalic(True)
  49. if style['underline']:
  50. qtf.setFontUnderline(True)
  51. self.styles[str(token)]=qtf
  52. def format(self, tokensource, outfile):
  53. global styles
  54. # We ignore outfile, keep output in a buffer
  55. self.data=[]
  56. # Just store a list of styles, one for each character
  57. # in the input. Obviously a smarter thing with
  58. # offsets and lengths is a good idea!
  59. for ttype, value in tokensource:
  60. l=len(value)
  61. t=str(ttype)
  62. self.data.extend([self.styles[t],]*l)
  63. class Highlighter(QSyntaxHighlighter):
  64. def __init__(self, parent, mode):
  65. QSyntaxHighlighter.__init__(self, parent)
  66. # styles = list(get_all_styles())
  67. # print(styles)
  68. # Keep the formatter and lexer, initializing them
  69. # may be costly.
  70. if not mode == "md":
  71. self.formatter=QFormatter(linenos=True, style="monokai")
  72. else:
  73. self.formatter=QFormatter(linenos=False, style="github")
  74. self.lexer=get_lexer_by_name(mode)
  75. def highlightBlock(self, text):
  76. """Takes a block, applies format to the document.
  77. according to what's in it.
  78. """
  79. # I need to know where in the document we are,
  80. # because our formatting info is global to
  81. # the document
  82. cb = self.currentBlock()
  83. p = cb.position()
  84. # The \n is not really needed, but sometimes
  85. # you are in an empty last block, so your position is
  86. # **after** the end of the document.
  87. text=str(self.document().toPlainText())+'\n'
  88. # Yes, re-highlight the whole document.
  89. # There **must** be some optimizacion possibilities
  90. # but it seems fast enough.
  91. highlight(text,self.lexer,self.formatter)
  92. # Just apply the formatting to this block.
  93. # For titles, it may be necessary to backtrack
  94. # and format a couple of blocks **earlier**.
  95. for i in range(len(str(text))):
  96. try:
  97. self.setFormat(i,1,self.formatter.data[p+i])
  98. except IndexError:
  99. pass