Word counting and Syntax Highlighting added
This commit is contained in:
parent
cc8aaca206
commit
998fd28691
326
main.py
326
main.py
@ -12,21 +12,22 @@ Author: Isaak Buslovich
|
|||||||
Date: 2024-01-13
|
Date: 2024-01-13
|
||||||
Version: 0.1
|
Version: 0.1
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import yaml
|
import yaml
|
||||||
from PyQt6.QtCore import QFileSystemWatcher, Qt, QTimer
|
from PyQt6.QtCore import QFileSystemWatcher, Qt, QTimer, QSize, QRegularExpression
|
||||||
from PyQt6.QtGui import QAction, QStandardItem, QStandardItemModel, QIcon, QPalette
|
from PyQt6.QtGui import QAction, QStandardItem, QStandardItemModel, QIcon, QPalette, QSyntaxHighlighter, \
|
||||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
QTextCharFormat, QColor, QFont
|
||||||
from PyQt6.QtWebEngineCore import QWebEngineSettings
|
from PyQt6.QtWebEngineCore import QWebEngineSettings
|
||||||
|
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||||
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QHBoxLayout, QWidget, QToolBar, QStatusBar, \
|
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QHBoxLayout, QWidget, QToolBar, QStatusBar, \
|
||||||
QMessageBox, QTreeView, QFileDialog, QAbstractItemView, QLineEdit, QVBoxLayout
|
QMessageBox, QTreeView, QFileDialog, QAbstractItemView, QLineEdit, QVBoxLayout, QStyle, QTabWidget, QLabel
|
||||||
|
from fuzzywuzzy import fuzz
|
||||||
from markdown2 import markdown
|
from markdown2 import markdown
|
||||||
from fuzzywuzzy import process, fuzz
|
|
||||||
import logging
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
@ -46,9 +47,15 @@ class MarkdownEditor(QMainWindow):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.config_path = pathlib.Path(__file__).parent / 'config.yaml'
|
||||||
|
self.config = self.load_config()
|
||||||
|
self.setup_ui()
|
||||||
|
QTimer.singleShot(0, self.post_init)
|
||||||
|
|
||||||
|
def post_init(self):
|
||||||
""" Initializes the Markdown editor application with UI setup and configuration management. """
|
""" Initializes the Markdown editor application with UI setup and configuration management. """
|
||||||
logging.info("Initializing the Markdown Editor...")
|
logging.info("Initializing the Markdown Editor...")
|
||||||
super().__init__()
|
|
||||||
self.dataDirectory = None
|
self.dataDirectory = None
|
||||||
self.preview = None
|
self.preview = None
|
||||||
self.editor = None
|
self.editor = None
|
||||||
@ -71,15 +78,44 @@ class MarkdownEditor(QMainWindow):
|
|||||||
self.searchTimer.setSingleShot(True)
|
self.searchTimer.setSingleShot(True)
|
||||||
self.searchTimer.timeout.connect(self.perform_search)
|
self.searchTimer.timeout.connect(self.perform_search)
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
""" Sets up the minimal UI components necessary for initial display. """
|
||||||
|
self.setWindowTitle("Markdown Editor")
|
||||||
|
|
||||||
|
# Basic window geometry
|
||||||
|
width = self.config.get('window', {}).get('width', 800)
|
||||||
|
height = self.config.get('window', {}).get('height', 600)
|
||||||
|
self.setGeometry(100, 100, width, height)
|
||||||
|
|
||||||
|
# Central widget and layout
|
||||||
|
central_widget = QWidget()
|
||||||
|
layout = QVBoxLayout(central_widget)
|
||||||
|
layout.setContentsMargins(5, 5, 5, 5)
|
||||||
|
|
||||||
|
# Placeholder for main content
|
||||||
|
placeholder_label = QLabel("Loading...", alignment=Qt.AlignmentFlag.AlignCenter)
|
||||||
|
layout.addWidget(placeholder_label)
|
||||||
|
|
||||||
|
# Set the central widget
|
||||||
|
central_widget.setLayout(layout)
|
||||||
|
self.setCentralWidget(central_widget)
|
||||||
|
|
||||||
|
# Status bar (optional)
|
||||||
|
self.setStatusBar(QStatusBar(self))
|
||||||
|
|
||||||
def initialize_ui(self):
|
def initialize_ui(self):
|
||||||
""" Sets up the application's user interface components. """
|
""" Sets up the application's user interface components, now with a ribbon interface. """
|
||||||
logging.info("Setting up the user interface...")
|
logging.info("Setting up the user interface with a ribbon...")
|
||||||
self.setWindowTitle("Markdown Editor")
|
self.setWindowTitle("Markdown Editor")
|
||||||
width = self.config['window']['width']
|
width = self.config['window']['width']
|
||||||
height = self.config['window']['height']
|
height = self.config['window']['height']
|
||||||
self.setGeometry(100, 100, width, height)
|
self.setGeometry(100, 100, width, height)
|
||||||
icon_path = self.dataDirectory / 'data' / 'smile.png'
|
icon_path = self.dataDirectory / 'data' / 'smile.png'
|
||||||
self.setWindowIcon(QIcon(str(icon_path)))
|
self.setWindowIcon(QIcon(str(icon_path)))
|
||||||
|
central_widget = QWidget()
|
||||||
|
layout = QVBoxLayout(central_widget)
|
||||||
|
layout.setContentsMargins(5, 5, 5, 5)
|
||||||
|
layout.addWidget(self.create_ribbon_interface())
|
||||||
self.directoryTree = QTreeView()
|
self.directoryTree = QTreeView()
|
||||||
self.directoryTree.setHeaderHidden(True)
|
self.directoryTree.setHeaderHidden(True)
|
||||||
self.directoryTree.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
self.directoryTree.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
||||||
@ -91,20 +127,20 @@ class MarkdownEditor(QMainWindow):
|
|||||||
directory_layout.addWidget(self.searchBox)
|
directory_layout.addWidget(self.searchBox)
|
||||||
directory_layout.addWidget(self.directoryTree)
|
directory_layout.addWidget(self.directoryTree)
|
||||||
self.editor = QTextEdit()
|
self.editor = QTextEdit()
|
||||||
|
self.editor.textChanged.connect(self.update_word_count)
|
||||||
self.editor.textChanged.connect(self.update_preview)
|
self.editor.textChanged.connect(self.update_preview)
|
||||||
|
self.highlighter = MarkdownHighlighter(self.editor.document())
|
||||||
self.preview = QWebEngineView()
|
self.preview = QWebEngineView()
|
||||||
web_engine_settings = self.preview.page().settings()
|
web_engine_settings = self.preview.page().settings()
|
||||||
web_engine_settings.setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls, True)
|
web_engine_settings.setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls, True)
|
||||||
web_engine_settings.setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, True)
|
web_engine_settings.setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, True)
|
||||||
layout = QHBoxLayout()
|
split_layout = QHBoxLayout()
|
||||||
layout.addLayout(directory_layout, 0)
|
split_layout.addLayout(directory_layout, 0)
|
||||||
layout.addWidget(self.editor, 1)
|
split_layout.addWidget(self.editor, 1)
|
||||||
layout.addWidget(self.preview, 1)
|
split_layout.addWidget(self.preview, 1)
|
||||||
container = QWidget()
|
layout.addLayout(split_layout)
|
||||||
container.setLayout(layout)
|
central_widget.setLayout(layout)
|
||||||
self.setCentralWidget(container)
|
self.setCentralWidget(central_widget)
|
||||||
self.create_tool_bar()
|
|
||||||
self.create_menu_bar()
|
|
||||||
self.setStatusBar(QStatusBar(self))
|
self.setStatusBar(QStatusBar(self))
|
||||||
|
|
||||||
def initialize_data_directory(self):
|
def initialize_data_directory(self):
|
||||||
@ -124,6 +160,93 @@ class MarkdownEditor(QMainWindow):
|
|||||||
QMessageBox.critical(self, "Directory Error", str(e))
|
QMessageBox.critical(self, "Directory Error", str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def create_ribbon_interface(self):
|
||||||
|
""" Creates the ribbon interface with tabs for File, Edit, View, Window, and Help. """
|
||||||
|
ribbon = QTabWidget()
|
||||||
|
ribbon.setTabPosition(QTabWidget.TabPosition.North)
|
||||||
|
ribbon.addTab(self.create_file_tab(), "File")
|
||||||
|
ribbon.addTab(self.create_edit_tab(), "Edit")
|
||||||
|
ribbon.addTab(self.create_view_tab(), "View")
|
||||||
|
ribbon.addTab(self.create_window_tab(), "Window")
|
||||||
|
ribbon.addTab(self.create_help_tab(), "Help")
|
||||||
|
ribbon.setMaximumHeight(ribbon.sizeHint().height())
|
||||||
|
return ribbon
|
||||||
|
|
||||||
|
def create_file_tab(self):
|
||||||
|
""" Creates the File tab for the ribbon. """
|
||||||
|
toolbar = QToolBar()
|
||||||
|
toolbar.setIconSize(QSize(16, 16))
|
||||||
|
toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||||
|
toolbar.addAction(self.create_action("New", QStyle.StandardPixmap.SP_FileIcon, self.new_file))
|
||||||
|
toolbar.addAction(self.create_action("Open", QStyle.StandardPixmap.SP_DirOpenIcon, self.open_file))
|
||||||
|
toolbar.addAction(self.create_action("Save", QStyle.StandardPixmap.SP_DialogSaveButton, self.save_entry))
|
||||||
|
toolbar.addAction(
|
||||||
|
self.create_action("Open Data Directory", QStyle.StandardPixmap.SP_DirIcon, self.open_data_directory))
|
||||||
|
toolbar.addAction(self.create_action("Change Data Directory", QStyle.StandardPixmap.SP_FileDialogDetailedView,
|
||||||
|
self.change_data_directory))
|
||||||
|
toolbar.addAction(
|
||||||
|
self.create_action("Settings", QStyle.StandardPixmap.SP_FileDialogInfoView, self.open_settings))
|
||||||
|
toolbar.addAction(self.create_action("Exit", QStyle.StandardPixmap.SP_DialogCloseButton, self.close))
|
||||||
|
return toolbar
|
||||||
|
|
||||||
|
def create_edit_tab(self):
|
||||||
|
""" Creates the Edit tab for the ribbon. """
|
||||||
|
toolbar = QToolBar()
|
||||||
|
toolbar.setIconSize(QSize(16, 16))
|
||||||
|
toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||||
|
toolbar.addAction(self.create_action("Undo", QStyle.StandardPixmap.SP_ArrowBack, self.undo_action))
|
||||||
|
toolbar.addAction(self.create_action("Redo", QStyle.StandardPixmap.SP_ArrowForward, self.redo_action))
|
||||||
|
return toolbar
|
||||||
|
|
||||||
|
def create_view_tab(self):
|
||||||
|
""" Creates the View tab for the ribbon. """
|
||||||
|
toolbar = QToolBar()
|
||||||
|
toolbar.setIconSize(QSize(16, 16))
|
||||||
|
toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||||
|
toolbar.addAction(self.create_action("Toggle Split View", QStyle.StandardPixmap.SP_FileDialogListView,
|
||||||
|
self.toggle_split_view))
|
||||||
|
toolbar.addAction(
|
||||||
|
self.create_action("Toggle Toolbar", QStyle.StandardPixmap.SP_ToolBarHorizontalExtensionButton,
|
||||||
|
self.toggle_toolbar))
|
||||||
|
return toolbar
|
||||||
|
|
||||||
|
def create_window_tab(self):
|
||||||
|
""" Creates the Window tab for the ribbon. """
|
||||||
|
toolbar = QToolBar()
|
||||||
|
toolbar.setIconSize(QSize(16, 16))
|
||||||
|
toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||||
|
toolbar.addAction(self.create_action("Close", QStyle.StandardPixmap.SP_DialogCloseButton, self.close))
|
||||||
|
toolbar.addAction(self.create_action("Minimize", QStyle.StandardPixmap.SP_TitleBarMinButton, self.minimize))
|
||||||
|
toolbar.addAction(self.create_action("Search", QStyle.StandardPixmap.SP_FileDialogContentsView, self.search))
|
||||||
|
return toolbar
|
||||||
|
|
||||||
|
def create_help_tab(self):
|
||||||
|
""" Creates the Help tab for the ribbon. """
|
||||||
|
toolbar = QToolBar()
|
||||||
|
toolbar.setIconSize(QSize(16, 16))
|
||||||
|
toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||||
|
toolbar.addAction(self.create_action("About", QStyle.StandardPixmap.SP_MessageBoxInformation, self.about))
|
||||||
|
toolbar.addAction(
|
||||||
|
self.create_action("View Cheatsheet", QStyle.StandardPixmap.SP_FileDialogInfoView, self.view_cheatsheet))
|
||||||
|
toolbar.addAction(self.create_action("GitHub", QStyle.StandardPixmap.SP_DriveNetIcon, self.open_git_hub))
|
||||||
|
return toolbar
|
||||||
|
|
||||||
|
def create_action(self, text, icon, callback):
|
||||||
|
""" Creates an action for the toolbar in the ribbon interface. """
|
||||||
|
action = QAction(self.style().standardIcon(icon), text, self)
|
||||||
|
action.triggered.connect(callback)
|
||||||
|
return action
|
||||||
|
|
||||||
|
def create_toolbar(self):
|
||||||
|
""" Creates a toolbar for the ribbon interface. """
|
||||||
|
toolbar = QToolBar()
|
||||||
|
toolbar.setIconSize(QSize(16, 16))
|
||||||
|
toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||||
|
toolbar.addAction(self.create_action("New", QStyle.StandardPixmap.SP_FileIcon, self.new_file))
|
||||||
|
toolbar.addAction(self.create_action("Open", QStyle.StandardPixmap.SP_DirOpenIcon, self.open_file))
|
||||||
|
toolbar.addAction(self.create_action("Save", QStyle.StandardPixmap.SP_DialogSaveButton, self.save_entry))
|
||||||
|
return toolbar
|
||||||
|
|
||||||
def on_search_text_changed(self, text):
|
def on_search_text_changed(self, text):
|
||||||
self.searchText = text
|
self.searchText = text
|
||||||
if not text:
|
if not text:
|
||||||
@ -166,6 +289,11 @@ class MarkdownEditor(QMainWindow):
|
|||||||
dir_added = True
|
dir_added = True
|
||||||
return dir_added
|
return dir_added
|
||||||
|
|
||||||
|
def update_word_count(self):
|
||||||
|
text = self.editor.toPlainText()
|
||||||
|
word_count = len(text.split())
|
||||||
|
self.statusBar().showMessage(f"Word Count: {word_count}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_match(filename, text, fuzziness):
|
def is_match(filename, text, fuzziness):
|
||||||
if not text:
|
if not text:
|
||||||
@ -290,58 +418,9 @@ class MarkdownEditor(QMainWindow):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "File Open Error", f"An error occurred: {e}")
|
QMessageBox.critical(self, "File Open Error", f"An error occurred: {e}")
|
||||||
|
|
||||||
def create_menu_bar(self):
|
|
||||||
"""
|
|
||||||
Create the menu bar for the application. It adds various menus like File, Edit, View, Window, and Help
|
|
||||||
with their respective actions.
|
|
||||||
"""
|
|
||||||
menu_bar = self.menuBar()
|
|
||||||
file_menu = menu_bar.addMenu("&File")
|
|
||||||
self.add_actions_to_menu(file_menu, [
|
|
||||||
("&New", self.new_file),
|
|
||||||
("&Open", self.open_file),
|
|
||||||
("&Save", self.save_entry),
|
|
||||||
("Open Data Directory", self.open_data_directory),
|
|
||||||
("Change Data Directory", self.change_data_directory),
|
|
||||||
("Theme", self.change_theme),
|
|
||||||
("Settings", self.open_settings),
|
|
||||||
("E&xit", self.close)
|
|
||||||
])
|
|
||||||
|
|
||||||
edit_menu = menu_bar.addMenu("&Edit")
|
|
||||||
self.add_actions_to_menu(edit_menu, [
|
|
||||||
("Undo", self.undo_action),
|
|
||||||
("Redo", self.redo_action)
|
|
||||||
])
|
|
||||||
|
|
||||||
view_menu = menu_bar.addMenu("&View")
|
|
||||||
self.add_actions_to_menu(view_menu, [
|
|
||||||
("Toggle Split View Mode", self.toggle_split_view),
|
|
||||||
("Toggle Toolbar", self.toggle_toolbar),
|
|
||||||
("Theme", [
|
|
||||||
("Dark", lambda: self.change_theme("dark")),
|
|
||||||
("Light", lambda: self.change_theme("light")),
|
|
||||||
("System", lambda: self.change_theme("system"))
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
window_menu = menu_bar.addMenu("&Window")
|
|
||||||
self.add_actions_to_menu(window_menu, [
|
|
||||||
("Close", self.close),
|
|
||||||
("Minimize", self.minimize),
|
|
||||||
("Search", self.search)
|
|
||||||
])
|
|
||||||
|
|
||||||
help_menu = menu_bar.addMenu("&Help")
|
|
||||||
self.add_actions_to_menu(help_menu, [
|
|
||||||
("&About", self.about),
|
|
||||||
("View Cheatsheet", self.view_cheatsheet),
|
|
||||||
("GitHub", self.open_git_hub)
|
|
||||||
])
|
|
||||||
|
|
||||||
def add_actions_to_menu(self, menu, actions):
|
def add_actions_to_menu(self, menu, actions):
|
||||||
for action_text, action_func in actions:
|
for action_text, action_func in actions:
|
||||||
if isinstance(action_func, list): # Submenu
|
if isinstance(action_func, list):
|
||||||
submenu = menu.addMenu(action_text)
|
submenu = menu.addMenu(action_text)
|
||||||
for sub_action_text, sub_action_func in action_func:
|
for sub_action_text, sub_action_func in action_func:
|
||||||
sub_action = QAction(sub_action_text, self)
|
sub_action = QAction(sub_action_text, self)
|
||||||
@ -540,15 +619,16 @@ class MarkdownEditor(QMainWindow):
|
|||||||
"""
|
"""
|
||||||
if depth > self.depth:
|
if depth > self.depth:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for entry in sorted(directory.iterdir(), key=lambda e: (e.is_file(), e.name.lower())):
|
directory_entries = sorted(directory.iterdir(),
|
||||||
|
key=lambda dir_entry: (dir_entry.is_file(), dir_entry.name.lower()))
|
||||||
|
for entry in directory_entries:
|
||||||
if entry.is_dir():
|
if entry.is_dir():
|
||||||
self.process_directory(entry, parent_item, depth)
|
self.process_directory(entry, parent_item, depth)
|
||||||
elif entry.suffix == '.md':
|
elif entry.suffix == '.md':
|
||||||
self.add_file_item(entry, parent_item)
|
self.add_file_item(entry, parent_item)
|
||||||
except PermissionError as e:
|
except PermissionError as permission_error:
|
||||||
logging.error(f"Permission error accessing {directory}: {e}")
|
logging.error(f"Permission error accessing {directory}: {permission_error}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_file_item(file_path, parent_item):
|
def add_file_item(file_path, parent_item):
|
||||||
@ -671,65 +751,6 @@ class MarkdownEditor(QMainWindow):
|
|||||||
else:
|
else:
|
||||||
QMessageBox.critical(self, "Directory Selection Error", "Invalid directory path")
|
QMessageBox.critical(self, "Directory Selection Error", "Invalid directory path")
|
||||||
|
|
||||||
def change_theme(self, theme):
|
|
||||||
if theme == "dark":
|
|
||||||
self.apply_dark_theme()
|
|
||||||
elif theme == "light":
|
|
||||||
self.apply_light_theme()
|
|
||||||
elif theme == "system":
|
|
||||||
self.apply_system_theme()
|
|
||||||
|
|
||||||
def apply_dark_theme(self):
|
|
||||||
dark_stylesheet = """
|
|
||||||
QMainWindow {
|
|
||||||
background-color: #282c34; /* Dark gray background */
|
|
||||||
color: #abb2bf; /* Light gray text */
|
|
||||||
}
|
|
||||||
QMenuBar {
|
|
||||||
background-color: #21252b; /* Slightly darker gray for menu bar */
|
|
||||||
color: #abb2bf;
|
|
||||||
}
|
|
||||||
QMenuBar::item {
|
|
||||||
background-color: #21252b;
|
|
||||||
color: #abb2bf;
|
|
||||||
}
|
|
||||||
QMenuBar::item:selected { /* when selected using mouse or keyboard */
|
|
||||||
background-color: #282c34;
|
|
||||||
}
|
|
||||||
QTextEdit, QTreeView {
|
|
||||||
background-color: #282c34;
|
|
||||||
color: #abb2bf;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
self.setStyleSheet(dark_stylesheet)
|
|
||||||
|
|
||||||
def apply_light_theme(self):
|
|
||||||
light_stylesheet = """
|
|
||||||
QMainWindow {
|
|
||||||
background-color: #fafafa; /* Very light gray, almost white */
|
|
||||||
color: #383a42; /* Dark gray text */
|
|
||||||
}
|
|
||||||
QMenuBar {
|
|
||||||
background-color: #f0f0f0; /* Light gray for menu bar */
|
|
||||||
color: #383a42;
|
|
||||||
}
|
|
||||||
QMenuBar::item {
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
color: #383a42;
|
|
||||||
}
|
|
||||||
QMenuBar::item:selected {
|
|
||||||
background-color: #fafafa;
|
|
||||||
}
|
|
||||||
QTextEdit, QTreeView {
|
|
||||||
background-color: #fafafa;
|
|
||||||
color: #383a42;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
self.setStyleSheet(light_stylesheet)
|
|
||||||
|
|
||||||
def apply_system_theme(self):
|
|
||||||
self.setStyleSheet("")
|
|
||||||
|
|
||||||
def open_settings(self):
|
def open_settings(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -768,6 +789,49 @@ class MarkdownEditor(QMainWindow):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SyntaxColors:
|
||||||
|
COMMENT = "#6272a4"
|
||||||
|
CYAN = "#8be9fd"
|
||||||
|
GREEN = "#50fa7b"
|
||||||
|
ORANGE = "#ffb86c"
|
||||||
|
PINK = "#ff79c6"
|
||||||
|
PURPLE = "#9f74b3"
|
||||||
|
RED = "#ff5555"
|
||||||
|
YELLOW = "#f1fa8c"
|
||||||
|
|
||||||
|
|
||||||
|
class MarkdownHighlighter(QSyntaxHighlighter):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setupRules()
|
||||||
|
|
||||||
|
def setupRules(self):
|
||||||
|
heading_format = QTextCharFormat()
|
||||||
|
heading_format.setForeground(QColor(SyntaxColors.PURPLE))
|
||||||
|
|
||||||
|
italic_format = QTextCharFormat()
|
||||||
|
italic_format.setFontItalic(True)
|
||||||
|
italic_format.setForeground(QColor(SyntaxColors.GREEN))
|
||||||
|
|
||||||
|
bold_format = QTextCharFormat()
|
||||||
|
bold_format.setFontWeight(QFont.Weight.Bold)
|
||||||
|
bold_format.setForeground(QColor(SyntaxColors.ORANGE))
|
||||||
|
|
||||||
|
self.highlightingRules = [
|
||||||
|
(QRegularExpression("^#.*"), heading_format),
|
||||||
|
(QRegularExpression("\*{1}[^*]+\*{1}"), italic_format),
|
||||||
|
(QRegularExpression("\*{2}[^*]+\*{2}"), bold_format),
|
||||||
|
]
|
||||||
|
|
||||||
|
def highlightBlock(self, text):
|
||||||
|
for pattern, format in self.highlightingRules:
|
||||||
|
match_iterator = pattern.globalMatch(text)
|
||||||
|
while match_iterator.hasNext():
|
||||||
|
match = match_iterator.next()
|
||||||
|
self.setFormat(match.capturedStart(), match.capturedLength(), format)
|
||||||
|
self.setCurrentBlockState(0)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
""" Main function to run the Markdown Editor application. """
|
""" Main function to run the Markdown Editor application. """
|
||||||
logging.info("Launching the application...")
|
logging.info("Launching the application...")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user