#!/usr/bin/python # -*- coding: utf-8 -*- # @Author: Bachir Soussi Chiadmi # @Date: 02-06-2017 # @Email: bachir@figureslibres.io # @Filename: highlighter.py # @Last modified by: bach # @Last modified time: 03-06-2017 # @License: GPL-V3 # based on code from : # Copyright (C) 2008 Christophe Kibleur # TODO : see pyQode for more features https://github.com/pyQode from __future__ import absolute_import, print_function, division, unicode_literals import sys import re # from PyQt5 import QtCore from PyQt5.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter from pygments import highlight from pygments.lexers import * from pygments.formatter import Formatter from pygments.styles import get_all_styles, get_style_by_name # import time def hex2QColor(c): r=int(c[0:2],16) g=int(c[2:4],16) b=int(c[4:6],16) return QColor(r,g,b) class QFormatter(Formatter): def __init__(self, linenos=True, style="default"): #, style Formatter.__init__(self) self.data=[] self.style = get_style_by_name(style) # self.linenos = linenos # Create a dictionary of text styles, indexed # by pygments token names, containing QTextCharFormat # instances according to pygments' description # of each style self.styles={} for token, style in self.style: qtf=QTextCharFormat() if style['color']: qtf.setForeground(hex2QColor(style['color'])) if style['bgcolor']: qtf.setBackground(hex2QColor(style['bgcolor'])) if style['bold']: qtf.setFontWeight(QFont.Bold) if style['italic']: qtf.setFontItalic(True) if style['underline']: qtf.setFontUnderline(True) self.styles[str(token)]=qtf def format(self, tokensource, outfile): global styles # We ignore outfile, keep output in a buffer self.data=[] # Just store a list of styles, one for each character # in the input. Obviously a smarter thing with # offsets and lengths is a good idea! for ttype, value in tokensource: l=len(value) t=str(ttype) self.data.extend([self.styles[t],]*l) class Highlighter(QSyntaxHighlighter): def __init__(self, parent, mode): QSyntaxHighlighter.__init__(self, parent) styles = list(get_all_styles()) # print(styles) # Keep the formatter and lexer, initializing them # may be costly. if not mode == "md": self.formatter=QFormatter(linenos=True, style="monokai") else: self.formatter=QFormatter(linenos=False, style="default") self.lexer=get_lexer_by_name(mode) def highlightBlock(self, text): """Takes a block, applies format to the document. according to what's in it. """ # I need to know where in the document we are, # because our formatting info is global to # the document cb = self.currentBlock() p = cb.position() # The \n is not really needed, but sometimes # you are in an empty last block, so your position is # **after** the end of the document. text=str(self.document().toPlainText())+'\n' # Yes, re-highlight the whole document. # There **must** be some optimizacion possibilities # but it seems fast enough. highlight(text,self.lexer,self.formatter) # Just apply the formatting to this block. # For titles, it may be necessary to backtrack # and format a couple of blocks **earlier**. for i in range(len(str(text))): try: self.setFormat(i,1,self.formatter.data[p+i]) except IndexError: pass