refactor
This commit is contained in:
parent
d14dcb6818
commit
ccde42f988
3 changed files with 231 additions and 205 deletions
src
161
src/EditorOther/ClochurLexer.py
Normal file
161
src/EditorOther/ClochurLexer.py
Normal file
|
@ -0,0 +1,161 @@
|
|||
|
||||
import re
|
||||
from PyQt5.Qsci import QsciLexerCustom, QsciScintilla
|
||||
from PyQt5.QtGui import *
|
||||
|
||||
|
||||
|
||||
class ClochurLexer(QsciLexerCustom):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QsciLexerCustom.__init__(self, parent)
|
||||
self._styles = {
|
||||
0: 'Default',
|
||||
1: 'Keyword',
|
||||
2: 'Comment',
|
||||
3: 'String',
|
||||
4: 'Rainbow0',
|
||||
5: 'Rainbow1',
|
||||
6: 'Rainbow2',
|
||||
7: 'Rainbow3',
|
||||
8: 'Rainbow4',
|
||||
9: 'Rainbow5',
|
||||
10: 'Rainbow6',
|
||||
}
|
||||
|
||||
for (k,v) in self._styles.items():
|
||||
setattr(self, v, k)
|
||||
|
||||
self.QUOTES = ['"', "'"]
|
||||
self.PARENTHESIS = ["[", "]"]
|
||||
|
||||
self.PRIMARY = ['define', 'let' , '#t', '#f', 'lambda', '@', 'cond', 'if', 'docu']
|
||||
|
||||
font = QFont()
|
||||
font.setFamily(parent.font_family)
|
||||
font.setPointSize(parent.font_size)
|
||||
self.setDefaultFont(font)
|
||||
|
||||
# set indent style
|
||||
self.setAutoIndentStyle(QsciScintilla.AiMaintain)
|
||||
|
||||
def language(self):
|
||||
return "Clochur"
|
||||
|
||||
def description(self, style):
|
||||
ret = "Lexer for Clochur - a S-expression-like" + \
|
||||
"typesetting Language. %s, %s" % (style, self._styles.get(style, ''))
|
||||
return ret
|
||||
|
||||
def defaultColor(self, style):
|
||||
if style == self.Default:
|
||||
return QColor("#000000")
|
||||
elif style == self.Keyword:
|
||||
return QColor("#0000ff")
|
||||
elif style == self.Comment:
|
||||
return QColor("#005500")
|
||||
elif style == self.String:
|
||||
return QColor("#ce5c00")
|
||||
elif style == self.Rainbow0:
|
||||
return QColor("#ff5500")
|
||||
elif style == self.Rainbow1:
|
||||
return QColor("#ffaa00")
|
||||
elif style == self.Rainbow2:
|
||||
return QColor("#dede00")
|
||||
elif style == self.Rainbow3:
|
||||
return QColor("#00ff00")
|
||||
elif style == self.Rainbow4:
|
||||
return QColor("#00aaff")
|
||||
elif style == self.Rainbow5:
|
||||
return QColor("#0000ff")
|
||||
elif style == self.Rainbow6:
|
||||
return QColor("#aa00ff")
|
||||
|
||||
else:
|
||||
return QsciLexerCustom.defaultColor(self, style)
|
||||
|
||||
|
||||
|
||||
|
||||
def styleText(self, start, end):
|
||||
editor = self.editor()
|
||||
if editor is None:
|
||||
return
|
||||
|
||||
SCI = editor.SendScintilla
|
||||
set_style = self.setStyling
|
||||
|
||||
source = ''
|
||||
if end > editor.length():
|
||||
end = editor.length()
|
||||
if end > start:
|
||||
source = bytearray(end - start)
|
||||
SCI(QsciScintilla.SCI_GETTEXTRANGE, start, end, source)
|
||||
if not source:
|
||||
return
|
||||
|
||||
|
||||
self.startStyling(start, 0x1f)
|
||||
rainbow_state = 0
|
||||
|
||||
index = SCI(QsciScintilla.SCI_LINEFROMPOSITION, start)
|
||||
|
||||
for line in source.splitlines(True):
|
||||
#print("%s, %d" % (line, rainbow_state))
|
||||
length = len(line)
|
||||
|
||||
i = 0
|
||||
|
||||
new_state = self.Default
|
||||
|
||||
line_utf8 = line.decode('utf-8')
|
||||
|
||||
split_pattern = re.compile(r'(\s+|\\%|%|\\\[|\\\]|[[]|[]])')
|
||||
|
||||
line_utf8_splitted = split_pattern.split(line_utf8)
|
||||
|
||||
line_utf8_splitted_len_pair = [{"str": item, "len" : len(bytearray(item, "utf-8"))} for item in line_utf8_splitted]
|
||||
|
||||
|
||||
#print(line_utf8_splitted_len_pair)
|
||||
|
||||
is_comment = False
|
||||
|
||||
i = 0
|
||||
if index > 0:
|
||||
# pos = SCI(QsciScintilla.SCI_GETLINEENDPOSITION, index - 1)
|
||||
rainbow_state = SCI(QsciScintilla.SCI_GETLINESTATE, index - 1)
|
||||
# print(rainbow_state)
|
||||
|
||||
for item in line_utf8_splitted_len_pair:
|
||||
|
||||
'''comment'''
|
||||
if item["str"] == "%":
|
||||
is_comment = True
|
||||
if is_comment == True:
|
||||
new_state = self.Comment # end of comment
|
||||
elif item["str"] in self.PRIMARY: # keywords
|
||||
new_state = self.Keyword
|
||||
# string
|
||||
elif re.match(r'^["]([^"]|\\\")*["]$' ,item["str"]) or re.match(r"^[']([^']|\\\')*[']$" ,item["str"]):
|
||||
new_state = self.String
|
||||
#parenthesis: rainbow mode
|
||||
elif item["str"] == "[":
|
||||
new_state = getattr(self, "Rainbow" + str(rainbow_state))
|
||||
rainbow_state = (rainbow_state + 1) % 7
|
||||
elif item["str"] == "]":
|
||||
rainbow_state = (rainbow_state - 1) % 7
|
||||
new_state = getattr(self, "Rainbow" + str(rainbow_state))
|
||||
else:
|
||||
pass
|
||||
|
||||
word_length = item["len"]
|
||||
i += word_length
|
||||
set_style(word_length, new_state)
|
||||
|
||||
if new_state != self.Comment:
|
||||
new_state = self.Default
|
||||
|
||||
SCI(QsciScintilla.SCI_SETLINESTATE, index, rainbow_state)
|
||||
|
||||
index += 1
|
54
src/EditorOther/CustomQsciEditor.py
Normal file
54
src/EditorOther/CustomQsciEditor.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
from PyQt5.QtGui import *
|
||||
from PyQt5.Qsci import QsciScintilla
|
||||
|
||||
from EditorOther.ClochurLexer import ClochurLexer
|
||||
|
||||
class CustomQsciEditor(QsciScintilla):
|
||||
def __init__(self, parent=None):
|
||||
super(CustomQsciEditor, self).__init__(parent)
|
||||
|
||||
self.font_family = parent.font_family
|
||||
self.font_size = parent.font_size
|
||||
|
||||
self.tab_width = 4
|
||||
|
||||
lexer = ClochurLexer(self)
|
||||
self.setLexer(lexer)
|
||||
|
||||
# Margin 0 for line numbers
|
||||
font = QFont()
|
||||
font.setFamily(self.font_family)
|
||||
font.setPointSize(self.font_size)
|
||||
fontMetrics = QFontMetrics(font)
|
||||
self.setMarginsFont(font)
|
||||
self.setMarginWidth(0, fontMetrics.width("00") + 6)
|
||||
self.setMarginLineNumbers(0, True)
|
||||
self.setMarginsBackgroundColor(QColor("#cccccc"))
|
||||
|
||||
# brace matching
|
||||
|
||||
self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
|
||||
|
||||
# current line color
|
||||
|
||||
self.setCaretLineVisible(True)
|
||||
self.setCaretLineBackgroundColor(QColor("#fdffce"))
|
||||
|
||||
# set word wrap
|
||||
self.set_word_wrap()
|
||||
|
||||
# set encoding
|
||||
self.SendScintilla(QsciScintilla.SCI_SETCODEPAGE, QsciScintilla.SC_CP_UTF8)
|
||||
self.setUtf8(True)
|
||||
|
||||
# set Auto indent
|
||||
self.setAutoIndent(True)
|
||||
self.setIndentationWidth(self.tab_width)
|
||||
self.setIndentationsUseTabs(False)
|
||||
self.setTabWidth(4)
|
||||
self.setBackspaceUnindents(True)
|
||||
|
||||
def set_word_wrap(self):
|
||||
self.setWrapMode(QsciScintilla.WrapMode.WrapWord)
|
||||
def set_no_word_wrap(self):
|
||||
self.setWrapMode(QsciScintilla.WrapMode.WrapNone)
|
221
src/main.py
221
src/main.py
|
@ -3,16 +3,15 @@
|
|||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5 import QtWebEngineWidgets
|
||||
from PyQt5.QtWidgets import *
|
||||
from PyQt5.Qsci import QsciScintilla, QsciLexerPython, QsciLexerCustom
|
||||
from PyQt5.Qsci import QsciScintilla
|
||||
|
||||
import qrc_resources
|
||||
from EditorOther import FindReplace
|
||||
from EditorOther import FindReplace, CustomQsciEditor
|
||||
|
||||
filename = None
|
||||
|
||||
|
@ -21,10 +20,7 @@ dirname = os.path.abspath(os.path.dirname(__file__)) #os.path.dirname('__file__'
|
|||
PDFJS = os.path.join(dirname, '../thirdparty/pdfjs/web/viewer.html')
|
||||
PDF = os.path.join(dirname, 'example.pdf')
|
||||
|
||||
tab_width = 4
|
||||
|
||||
font_family = 'Noto Sans Mono'
|
||||
font_size = 11
|
||||
|
||||
'''Widget for PDF file viewer'''
|
||||
class PDFJSWidget(QtWebEngineWidgets.QWebEngineView):
|
||||
|
@ -33,51 +29,7 @@ class PDFJSWidget(QtWebEngineWidgets.QWebEngineView):
|
|||
self.load(QUrl.fromUserInput("file://%s?file=file://%s" % (PDFJS, PDF)))
|
||||
print((dirname,PDFJS, PDF))
|
||||
|
||||
class CustomQsciEditor(QsciScintilla):
|
||||
|
||||
def set_word_wrap(self):
|
||||
self.setWrapMode(QsciScintilla.WrapMode.WrapWord)
|
||||
def set_no_word_wrap(self):
|
||||
self.setWrapMode(QsciScintilla.WrapMode.WrapNone)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(CustomQsciEditor, self).__init__(parent)
|
||||
|
||||
lexer = ClochurLexer(self)
|
||||
self.setLexer(lexer)
|
||||
|
||||
# Margin 0 for line numbers
|
||||
font = QFont()
|
||||
font.setFamily(font_family)
|
||||
font.setPointSize(font_size)
|
||||
fontMetrics = QFontMetrics(font)
|
||||
self.setMarginsFont(font)
|
||||
self.setMarginWidth(0, fontMetrics.width("00") + 6)
|
||||
self.setMarginLineNumbers(0, True)
|
||||
self.setMarginsBackgroundColor(QColor("#cccccc"))
|
||||
|
||||
# brace matching
|
||||
|
||||
self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
|
||||
|
||||
# current line color
|
||||
|
||||
self.setCaretLineVisible(True)
|
||||
self.setCaretLineBackgroundColor(QColor("#fdffce"))
|
||||
|
||||
# set word wrap
|
||||
self.set_word_wrap()
|
||||
|
||||
# set encoding
|
||||
self.SendScintilla(QsciScintilla.SCI_SETCODEPAGE, QsciScintilla.SC_CP_UTF8)
|
||||
self.setUtf8(True)
|
||||
|
||||
# set Auto indent
|
||||
self.setAutoIndent(True)
|
||||
self.setIndentationWidth(tab_width)
|
||||
self.setIndentationsUseTabs(False)
|
||||
self.setTabWidth(4)
|
||||
self.setBackspaceUnindents(True)
|
||||
|
||||
|
||||
class Window(QMainWindow):
|
||||
|
@ -85,6 +37,8 @@ class Window(QMainWindow):
|
|||
super(QMainWindow, self).__init__()
|
||||
self.file = None
|
||||
self.filename = None
|
||||
self.font_family = 'Noto Sans Mono'
|
||||
self.font_size = 11
|
||||
|
||||
self.tmp_folder = '/tmp'
|
||||
self.tmp_file = 'clochur_tmp.json'
|
||||
|
@ -97,6 +51,8 @@ class Window(QMainWindow):
|
|||
self._createEditToolBar()
|
||||
self._createFormatToolBar()
|
||||
|
||||
self.setWindowIcon(QIcon(':logo.svg'))
|
||||
|
||||
def _createActions(self):
|
||||
self.new_action = QAction(QIcon(":new.svg"), "&New", self)
|
||||
self.new_action.setShortcut('Ctrl+N')
|
||||
|
@ -149,6 +105,7 @@ class Window(QMainWindow):
|
|||
self.convert_action = QAction(QIcon(":convert.svg"), "Con&vert", self)
|
||||
|
||||
self.about_action = QAction("&About", self)
|
||||
self.about_action.triggered.connect(self.about_call)
|
||||
|
||||
self.bold_action = QAction(QIcon(":text-bold.svg"), "&Bold", self)
|
||||
self.italic_action = QAction(QIcon(":text-italic.svg"), "&Italic", self)
|
||||
|
@ -306,6 +263,13 @@ class Window(QMainWindow):
|
|||
|
||||
def select_all_call(self):
|
||||
self.editor.selectAll()
|
||||
|
||||
def about_call(self):
|
||||
about_content = '''A S-expression-like typesetting language powered by SILE engine with a simple text text editor.
|
||||
http://yoxem.github.com
|
||||
(c) 2021 Yoxem Chen <yoxem.tem98@nctu.edu.tw>'''
|
||||
|
||||
self.about_dialog = QMessageBox.about(self, "About Clochur", about_content)
|
||||
|
||||
|
||||
def _createEditToolBar(self):
|
||||
|
@ -396,169 +360,17 @@ class Window(QMainWindow):
|
|||
|
||||
|
||||
|
||||
class ClochurLexer(QsciLexerCustom):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QsciLexerCustom.__init__(self, parent)
|
||||
self._styles = {
|
||||
0: 'Default',
|
||||
1: 'Keyword',
|
||||
2: 'Comment',
|
||||
3: 'String',
|
||||
4: 'Rainbow0',
|
||||
5: 'Rainbow1',
|
||||
6: 'Rainbow2',
|
||||
7: 'Rainbow3',
|
||||
8: 'Rainbow4',
|
||||
9: 'Rainbow5',
|
||||
10: 'Rainbow6',
|
||||
}
|
||||
|
||||
for (k,v) in self._styles.items():
|
||||
setattr(self, v, k)
|
||||
|
||||
self.QUOTES = ['"', "'"]
|
||||
self.PARENTHESIS = ["[", "]"]
|
||||
|
||||
self.PRIMARY = ['define', 'let' , '#t', '#f', 'lambda', '@', 'cond', 'if', 'docu']
|
||||
|
||||
font = QFont()
|
||||
font.setFamily(font_family)
|
||||
font.setPointSize(font_size)
|
||||
self.setDefaultFont(font)
|
||||
|
||||
# set indent style
|
||||
self.setAutoIndentStyle(QsciScintilla.AiMaintain)
|
||||
|
||||
def language(self):
|
||||
return "Clochur"
|
||||
|
||||
def description(self, style):
|
||||
ret = "Lexer for Clochur - a S-expression-like" + \
|
||||
"typesetting Language. %s, %s" % (style, self._styles.get(style, ''))
|
||||
return ret
|
||||
|
||||
def defaultColor(self, style):
|
||||
if style == self.Default:
|
||||
return QColor("#000000")
|
||||
elif style == self.Keyword:
|
||||
return QColor("#0000ff")
|
||||
elif style == self.Comment:
|
||||
return QColor("#005500")
|
||||
elif style == self.String:
|
||||
return QColor("#ce5c00")
|
||||
elif style == self.Rainbow0:
|
||||
return QColor("#ff5500")
|
||||
elif style == self.Rainbow1:
|
||||
return QColor("#ffaa00")
|
||||
elif style == self.Rainbow2:
|
||||
return QColor("#dede00")
|
||||
elif style == self.Rainbow3:
|
||||
return QColor("#00ff00")
|
||||
elif style == self.Rainbow4:
|
||||
return QColor("#00aaff")
|
||||
elif style == self.Rainbow5:
|
||||
return QColor("#0000ff")
|
||||
elif style == self.Rainbow6:
|
||||
return QColor("#aa00ff")
|
||||
|
||||
else:
|
||||
return QsciLexerCustom.defaultColor(self, style)
|
||||
|
||||
|
||||
|
||||
|
||||
def styleText(self, start, end):
|
||||
editor = self.editor()
|
||||
if editor is None:
|
||||
return
|
||||
|
||||
SCI = editor.SendScintilla
|
||||
set_style = self.setStyling
|
||||
|
||||
source = ''
|
||||
if end > editor.length():
|
||||
end = editor.length()
|
||||
if end > start:
|
||||
source = bytearray(end - start)
|
||||
SCI(QsciScintilla.SCI_GETTEXTRANGE, start, end, source)
|
||||
if not source:
|
||||
return
|
||||
|
||||
|
||||
self.startStyling(start, 0x1f)
|
||||
rainbow_state = 0
|
||||
|
||||
index = SCI(QsciScintilla.SCI_LINEFROMPOSITION, start)
|
||||
|
||||
for line in source.splitlines(True):
|
||||
#print("%s, %d" % (line, rainbow_state))
|
||||
length = len(line)
|
||||
|
||||
i = 0
|
||||
|
||||
new_state = self.Default
|
||||
|
||||
line_utf8 = line.decode('utf-8')
|
||||
|
||||
split_pattern = re.compile(r'(\s+|\\%|%|\\\[|\\\]|[[]|[]])')
|
||||
|
||||
line_utf8_splitted = split_pattern.split(line_utf8)
|
||||
|
||||
line_utf8_splitted_len_pair = [{"str": item, "len" : len(bytearray(item, "utf-8"))} for item in line_utf8_splitted]
|
||||
|
||||
|
||||
#print(line_utf8_splitted_len_pair)
|
||||
|
||||
is_comment = False
|
||||
|
||||
i = 0
|
||||
if index > 0:
|
||||
# pos = SCI(QsciScintilla.SCI_GETLINEENDPOSITION, index - 1)
|
||||
rainbow_state = SCI(QsciScintilla.SCI_GETLINESTATE, index - 1)
|
||||
# print(rainbow_state)
|
||||
|
||||
for item in line_utf8_splitted_len_pair:
|
||||
|
||||
'''comment'''
|
||||
if item["str"] == "%":
|
||||
is_comment = True
|
||||
if is_comment == True:
|
||||
new_state = self.Comment # end of comment
|
||||
elif item["str"] in self.PRIMARY: # keywords
|
||||
new_state = self.Keyword
|
||||
# string
|
||||
elif re.match(r'^["]([^"]|\\\")*["]$' ,item["str"]) or re.match(r"^[']([^']|\\\')*[']$" ,item["str"]):
|
||||
new_state = self.String
|
||||
#parenthesis: rainbow mode
|
||||
elif item["str"] == "[":
|
||||
new_state = getattr(self, "Rainbow" + str(rainbow_state))
|
||||
rainbow_state = (rainbow_state + 1) % 7
|
||||
elif item["str"] == "]":
|
||||
rainbow_state = (rainbow_state - 1) % 7
|
||||
new_state = getattr(self, "Rainbow" + str(rainbow_state))
|
||||
else:
|
||||
pass
|
||||
|
||||
word_length = item["len"]
|
||||
i += word_length
|
||||
set_style(word_length, new_state)
|
||||
|
||||
if new_state != self.Comment:
|
||||
new_state = self.Default
|
||||
|
||||
SCI(QsciScintilla.SCI_SETLINESTATE, index, rainbow_state)
|
||||
|
||||
index += 1
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication([])
|
||||
window = Window()
|
||||
|
||||
|
||||
editor = CustomQsciEditor()
|
||||
editor = CustomQsciEditor.CustomQsciEditor(window)
|
||||
editor.setMinimumWidth(200)
|
||||
#editor.resize(QSize(500, 2000))
|
||||
|
||||
|
@ -579,7 +391,6 @@ if __name__ == '__main__':
|
|||
#main_layout.addWidget(pdf_viewer)
|
||||
|
||||
|
||||
window = Window()
|
||||
window.editor = editor
|
||||
|
||||
untitled_title = window.generate_untitled_title()
|
||||
|
|
Loading…
Reference in a new issue