1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
| #!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Classe Editscripts héritant de QTextEdit
Colorisation de syntaxe de codes de langages informatiques
Pour Python 3:
pygments.lexers.python.PythonLexer
Pour Python 3 console interactive:
pygments.lexers.python.PythonConsoleLexer
Pour Cython:
pygments.lexers.python.CythonLexer
Pour batch Windows (fichiers .bat):
pygments.lexers.shell.BatchLexer
Pour shell:
pygments.lexers.shell.BashSessionLexer
"""
import sys
import os
try:
from pygments import highlight
from pygments.lexers import get_lexer_for_filename
from pygments.formatters import HtmlFormatter
pygments_present = True
except Exception:
pygments_present = False
print("Manque le module 'pygments' (colorisation syntaxe)")
from PyQt5 import (QtWidgets, QtGui, QtCore)
#############################################################################
class EditScripts(QtWidgets.QTextEdit):
#========================================================================
def __init__(self, parent=None):
super().__init__(parent)
self.configuration()
#========================================================================
def configuration(self, script="", ext=""):
# activer les modifications du texte
self.setReadOnly(False)
# les longues lignes pourront dépasser la fenêtre
self.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
# Change la police de caractères
font = QtGui.QFont()
font.setStyleHint(QtGui.QFont.Monospace)
font.setFamily("DejaVu Sans Mono")
font.setPointSize(10)
self.setFont(font)
# Initialise les variables utilisées après
self.lexer = None
self.formatter = None
# initialise la colorisation de la syntaxe
script = self.initcolorize(script, ext)
# charge le script la première fois
self.setText(script)
# chaque modif de texte lancera la colorisation
#self.textChanged.connect(self.highlighter)
#=========================================================================
def initcolorize(self, script, ext=""):
"""Initialise le lexer en fonction de l'extension du fichier chargé
Convertit et retourne le code en html colorisé
- script: le code du script
- ext: l'extension du fichier chargé, avec un point devant (ex: ".py")
"""
if pygments_present:
# Prend le bon lexer en fonction de l'extension du fichier chargé
try:
self.lexer = get_lexer_for_filename(ext, stripall=False)
except Exception:
return script # aucun lexer n'a été trouvé pour l'extension donnée
# définit le formatter html
self.formatter = HtmlFormatter(linenos=False, style="default")
# le fichier 'html' ne doit pas avoir de fichier 'css' séparé
self.formatter.noclasses = True
# Retourne le code colorisé et formaté selon html
return highlight(script, self.lexer, self.formatter)
else:
return script # pygments absent
#=========================================================================
def highlighter(self):
"""Met à jour le code colorisé à chaque caractère modifié
"""
if pygments_present and self.lexer is not None:
# bloque les signaux du QTextEdit
self.blockSignals(True)
# enregistre la position verticale du texte dans la fenêtre
posvert = self.verticalScrollBar().value()
# enregistre la position du curseur
poscur = self.textCursor().position()
# prend le texte en cours d'édition
script = self.toPlainText()
# évite un warnong du curseur pour un ajout en fin de texte
if poscur==len(script):
text += " " # ajoute un espace en fin de texte
# colorise le texte en cours d'édition
result = highlight(script, self.lexer, self.formatter)
#charge le html result dans le QTextEdit
#self.setHtml(result)
self.setText(result)
# prend le curseur du QTextEdit
cursor = self.textCursor()
# Lui affecte la position précédente
cursor.setPosition(poscur, QtGui.QTextCursor.MoveAnchor)
# affecte le curseur au QTextEdit de nouveau
self.setTextCursor(cursor)
# remet le texte à la même position verticale
self.verticalScrollBar().setValue(posvert)
# dit que le texte a été modifié
self.document().setModified(True)
# débloque les signaux du QTextEdit
self.blockSignals(False)
# =======================================================================
def keyPressEvent(self, event):
"""raccourcis clavier
"""
#--------------------------------------------------------------------
# Alt-C => déclenche l'affichage du script colorisé
if event.key() == QtCore.Qt.Key_C and (event.modifiers() & QtCore.Qt.AltModifier):
self.highlighter()
#--------------------------------------------------------------------
# autres touches: renvoi au QTextEdit pour traitement normal
else:
super().keyPressEvent(event)
##############################################################################
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
# charge le script à afficher et l'extension du fichier
fichier = "datetime.py"
ext = os.path.splitext(fichier)[1]
with open(fichier, "r", encoding="utf-8") as fs:
#lscript = [ligne.rstrip() for ligne in fs.readlines()]
script = fs.read()
# lance la fenêtre
fen = EditScripts()
fen.configuration(script, ext)
fen.resize(800, 800)
fen.show()
sys.exit(app.exec_()) |