highlighter.py 3.7 KB

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