mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
feat: basic text editor + running terminal output
This commit is contained in:
184
bec_widgets/widgets/editor/editor.py
Normal file
184
bec_widgets/widgets/editor/editor.py
Normal file
@ -0,0 +1,184 @@
|
||||
import sys
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
import qdarktheme
|
||||
from PyQt6.QtCore import QFile, QTextStream, pyqtSignal
|
||||
from PyQt6.QtGui import QColor, QFont, QAction
|
||||
from PyQt6.QtWidgets import (
|
||||
QApplication,
|
||||
QMainWindow,
|
||||
QFileDialog,
|
||||
QPushButton,
|
||||
QTextEdit,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from PyQt6.Qsci import QsciScintilla, QsciLexerPython
|
||||
|
||||
|
||||
class PythonEditor(QMainWindow):
|
||||
# outputSignal = pyqtSignal(str)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# Initialize the editor and terminal
|
||||
self.editor = QsciScintilla()
|
||||
self.terminal = QTextEdit()
|
||||
self.terminal.setReadOnly(True)
|
||||
self.runButton = QPushButton("Run Script")
|
||||
|
||||
# Layout
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.editor)
|
||||
layout.addWidget(self.runButton)
|
||||
layout.addWidget(self.terminal)
|
||||
# Container widget
|
||||
container = QWidget()
|
||||
container.setLayout(layout)
|
||||
self.setCentralWidget(container)
|
||||
|
||||
self.setupEditor()
|
||||
|
||||
# Connect the run button
|
||||
self.runButton.clicked.connect(self.runScript)
|
||||
|
||||
# self.outputSignal.connect(self.updateTerminal)
|
||||
|
||||
def setupEditor(self):
|
||||
# Set the lexer for Python
|
||||
self.lexer = QsciLexerPython()
|
||||
self.editor.setLexer(self.lexer)
|
||||
|
||||
# Enable features
|
||||
self.editor.setAutoIndent(True)
|
||||
self.editor.setIndentationsUseTabs(False)
|
||||
self.editor.setIndentationWidth(4)
|
||||
self.editor.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAll)
|
||||
self.editor.setAutoCompletionThreshold(1)
|
||||
|
||||
# Enable line numbers in the margin
|
||||
self.editor.setMarginType(0, QsciScintilla.MarginType.NumberMargin)
|
||||
self.editor.setMarginWidth(0, "0000") # Adjust the width as needed
|
||||
|
||||
# Additional UI elements like menu for load/save can be added here
|
||||
self.setEditorStyle()
|
||||
self.createActions()
|
||||
self.createMenus()
|
||||
|
||||
def setEditorStyle(self):
|
||||
# Dracula Theme Colors
|
||||
backgroundColor = QColor("#282a36")
|
||||
textColor = QColor("#f8f8f2")
|
||||
keywordColor = QColor("#8be9fd")
|
||||
stringColor = QColor("#f1fa8c")
|
||||
commentColor = QColor("#6272a4")
|
||||
classFunctionColor = QColor("#50fa7b")
|
||||
|
||||
# Set Font
|
||||
font = QFont()
|
||||
font.setFamily("Consolas")
|
||||
font.setPointSize(10)
|
||||
self.editor.setFont(font)
|
||||
self.editor.setMarginsFont(font)
|
||||
|
||||
# Set Editor Colors
|
||||
self.editor.setMarginsBackgroundColor(backgroundColor)
|
||||
self.editor.setMarginsForegroundColor(textColor)
|
||||
self.editor.setCaretForegroundColor(textColor)
|
||||
self.editor.setCaretLineBackgroundColor(QColor("#44475a"))
|
||||
self.editor.setPaper(backgroundColor)
|
||||
self.editor.setColor(textColor)
|
||||
|
||||
# Syntax Highlighting Colors
|
||||
lexer = self.editor.lexer()
|
||||
if lexer:
|
||||
lexer.setDefaultPaper(backgroundColor)
|
||||
lexer.setDefaultColor(textColor)
|
||||
lexer.setColor(keywordColor, QsciLexerPython.Keyword)
|
||||
lexer.setColor(stringColor, QsciLexerPython.DoubleQuotedString)
|
||||
lexer.setColor(stringColor, QsciLexerPython.SingleQuotedString)
|
||||
lexer.setColor(commentColor, QsciLexerPython.Comment)
|
||||
lexer.setColor(classFunctionColor, QsciLexerPython.ClassName)
|
||||
lexer.setColor(classFunctionColor, QsciLexerPython.FunctionMethodName)
|
||||
|
||||
def runScript(self):
|
||||
# Use threading to run the script
|
||||
# thread = threading.Thread(target=self.executeScript)
|
||||
# thread.start()
|
||||
|
||||
# Save the current script to a temporary file or use the existing file
|
||||
script = self.editor.text()
|
||||
with open("temp_script.py", "w") as file:
|
||||
file.write(script)
|
||||
|
||||
# Run the script and capture output
|
||||
process = subprocess.Popen(
|
||||
["python", "temp_script.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
|
||||
)
|
||||
output, error = process.communicate()
|
||||
|
||||
# Display output and error in the terminal
|
||||
self.terminal.clear()
|
||||
if output:
|
||||
self.terminal.append(output)
|
||||
if error:
|
||||
self.terminal.append(error)
|
||||
|
||||
# def executeScript(self):
|
||||
# # Save the current script to a temporary file or use the existing file
|
||||
# script = self.editor.text()
|
||||
# with open("temp_script.py", "w") as file:
|
||||
# file.write(script)
|
||||
#
|
||||
# # Run the script and capture output
|
||||
# process = subprocess.Popen(
|
||||
# ["python", "temp_script.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
|
||||
# )
|
||||
# output, error = process.communicate()
|
||||
#
|
||||
# # Emit the signal with the output
|
||||
# if output:
|
||||
# self.outputSignal.emit(output)
|
||||
# if error:
|
||||
# self.outputSignal.emit(error)
|
||||
#
|
||||
# def updateTerminal(self, text):
|
||||
# # Update the terminal with output
|
||||
# self.terminal.append(text)
|
||||
#
|
||||
def createMenus(self):
|
||||
self.fileMenu = self.menuBar().addMenu("&File")
|
||||
self.fileMenu.addAction(self.openAct)
|
||||
self.fileMenu.addAction(self.saveAct)
|
||||
|
||||
def createActions(self):
|
||||
self.openAct = QAction("&Open...", self, shortcut="Ctrl+O", triggered=self.openFile)
|
||||
self.saveAct = QAction("&Save", self, shortcut="Ctrl+S", triggered=self.saveFile)
|
||||
|
||||
def openFile(self):
|
||||
path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Python files (*.py)")
|
||||
if path:
|
||||
file = QFile(path)
|
||||
if file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text):
|
||||
text = QTextStream(file).readAll()
|
||||
self.editor.setText(text)
|
||||
file.close()
|
||||
|
||||
def saveFile(self):
|
||||
path, _ = QFileDialog.getSaveFileName(self, "Save file", "", "Python files (*.py)")
|
||||
if path:
|
||||
file = QFile(path)
|
||||
if file.open(QFile.OpenModeFlag.WriteOnly | QFile.OpenModeFlag.Text):
|
||||
text = self.editor.text()
|
||||
QTextStream(file) << text
|
||||
file.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication([])
|
||||
qdarktheme.setup_theme()
|
||||
mainWin = PythonEditor()
|
||||
mainWin.show()
|
||||
app.exec()
|
Reference in New Issue
Block a user