je-editor 0.0.62__tar.gz → 0.0.64__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. {je_editor-0.0.62 → je_editor-0.0.64}/PKG-INFO +1 -1
  2. je_editor-0.0.62/je_editor/utils/file/save/save_file.py → je_editor-0.0.64/je_editor/pyside_ui/auto_save/auto_save_thread.py +2 -27
  3. je_editor-0.0.64/je_editor/pyside_ui/code_process/code_exec.py +171 -0
  4. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/file_dialog/save_file_dialog.py +3 -1
  5. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/main_ui/editor_main_ui/main_editor.py +30 -2
  6. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/main_ui_setting/ui_setting.py +9 -3
  7. je_editor-0.0.64/je_editor/pyside_ui/menu/menu_bar/run_menu/build_run_menu.py +56 -0
  8. je_editor-0.0.64/je_editor/pyside_ui/shell_process/shell_exec.py +147 -0
  9. je_editor-0.0.64/je_editor/pyside_ui/syntax/python_syntax.py +97 -0
  10. je_editor-0.0.64/je_editor/pyside_ui/treeview/project_treeview/__init__.py +0 -0
  11. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/treeview/project_treeview/set_project_treeview.py +4 -1
  12. je_editor-0.0.64/je_editor/utils/file/__init__.py +0 -0
  13. je_editor-0.0.64/je_editor/utils/file/save/save_file.py +31 -0
  14. je_editor-0.0.64/je_editor/utils/project/__init__.py +0 -0
  15. je_editor-0.0.64/je_editor/utils/redirect_manager/__init__.py +0 -0
  16. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor.egg-info/PKG-INFO +1 -1
  17. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor.egg-info/SOURCES.txt +8 -0
  18. {je_editor-0.0.62 → je_editor-0.0.64}/pyproject.toml +1 -1
  19. je_editor-0.0.62/je_editor/pyside_ui/menu/menu_bar/run_menu/build_run_menu.py +0 -25
  20. {je_editor-0.0.62 → je_editor-0.0.64}/LICENSE +0 -0
  21. {je_editor-0.0.62 → je_editor-0.0.64}/README.md +0 -0
  22. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/__init__.py +0 -0
  23. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/__main__.py +0 -0
  24. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/__init__.py +0 -0
  25. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/actions/__init__.py +0 -0
  26. {je_editor-0.0.62/je_editor/pyside_ui/file_dialog → je_editor-0.0.64/je_editor/pyside_ui/auto_save}/__init__.py +0 -0
  27. {je_editor-0.0.62/je_editor/pyside_ui/main_ui → je_editor-0.0.64/je_editor/pyside_ui/code_process}/__init__.py +0 -0
  28. {je_editor-0.0.62/je_editor/pyside_ui/main_ui/editor_main_ui → je_editor-0.0.64/je_editor/pyside_ui/file_dialog}/__init__.py +0 -0
  29. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/file_dialog/open_file_dialog.py +0 -0
  30. {je_editor-0.0.62/je_editor/pyside_ui/main_ui_setting → je_editor-0.0.64/je_editor/pyside_ui/main_ui}/__init__.py +0 -0
  31. {je_editor-0.0.62/je_editor/pyside_ui/menu → je_editor-0.0.64/je_editor/pyside_ui/main_ui/editor_main_ui}/__init__.py +0 -0
  32. {je_editor-0.0.62/je_editor/pyside_ui/menu/menu_bar → je_editor-0.0.64/je_editor/pyside_ui/main_ui_setting}/__init__.py +0 -0
  33. {je_editor-0.0.62/je_editor/pyside_ui/menu/menu_bar/file_menu → je_editor-0.0.64/je_editor/pyside_ui/menu}/__init__.py +0 -0
  34. {je_editor-0.0.62/je_editor/pyside_ui/menu/menu_bar/run_menu → je_editor-0.0.64/je_editor/pyside_ui/menu/menu_bar}/__init__.py +0 -0
  35. {je_editor-0.0.62/je_editor/pyside_ui/treeview → je_editor-0.0.64/je_editor/pyside_ui/menu/menu_bar/file_menu}/__init__.py +0 -0
  36. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/menu/menu_bar/file_menu/build_file_menu.py +0 -0
  37. {je_editor-0.0.62/je_editor/pyside_ui/treeview/project_treeview → je_editor-0.0.64/je_editor/pyside_ui/menu/menu_bar/run_menu}/__init__.py +0 -0
  38. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/pyside_ui/menu/menu_bar/set_menu_bar.py +0 -0
  39. {je_editor-0.0.62/je_editor/utils/file → je_editor-0.0.64/je_editor/pyside_ui/shell_process}/__init__.py +0 -0
  40. {je_editor-0.0.62/je_editor/utils/project → je_editor-0.0.64/je_editor/pyside_ui/syntax}/__init__.py +0 -0
  41. {je_editor-0.0.62/je_editor/utils/redirect_manager → je_editor-0.0.64/je_editor/pyside_ui/treeview}/__init__.py +0 -0
  42. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/start_editor.py +0 -0
  43. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/__init__.py +0 -0
  44. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/exception/__init__.py +0 -0
  45. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/exception/exception_tags.py +0 -0
  46. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/exception/exceptions.py +0 -0
  47. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/file/open/__init__.py +0 -0
  48. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/file/open/open_file.py +0 -0
  49. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/file/save/__init__.py +0 -0
  50. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/json_format/__init__.py +0 -0
  51. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/json_format/json_process.py +0 -0
  52. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/project/create_project.py +0 -0
  53. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor/utils/redirect_manager/redirect_manager_class.py +0 -0
  54. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor.egg-info/dependency_links.txt +0 -0
  55. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor.egg-info/requires.txt +0 -0
  56. {je_editor-0.0.62 → je_editor-0.0.64}/je_editor.egg-info/top_level.txt +0 -0
  57. {je_editor-0.0.62 → je_editor-0.0.64}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: je_editor
3
- Version: 0.0.62
3
+ Version: 0.0.64
4
4
  Summary: Simple editor for ITE
5
5
  Author-email: JE-Chen <zenmailman@gmail.com>
6
6
  License: MIT
@@ -1,33 +1,8 @@
1
1
  import time
2
2
  from pathlib import Path
3
- from threading import Lock
4
3
  from threading import Thread
5
4
 
6
- from je_editor.utils.exception.exceptions import JEditorSaveFileException
7
-
8
-
9
- def write_file(file, content):
10
- """
11
- :param file: file we want to write
12
- :param content: content write in file
13
- try
14
- lock thread
15
- if file not empty string
16
- write content to file
17
- finally
18
- release lock
19
- """
20
- lock = Lock()
21
- content = str(content)
22
- try:
23
- lock.acquire()
24
- if file != "" and file is not None:
25
- with open(file, "w+") as file_to_write:
26
- file_to_write.write(content)
27
- except JEditorSaveFileException:
28
- raise JEditorSaveFileException
29
- finally:
30
- lock.release()
5
+ from je_editor.utils.file.save.save_file import write_file
31
6
 
32
7
 
33
8
  class SaveThread(Thread):
@@ -52,7 +27,7 @@ class SaveThread(Thread):
52
27
  self.auto_save = True
53
28
  self.path = Path(self.file)
54
29
  while self.auto_save and self.file is not None:
55
- time.sleep(15)
30
+ time.sleep(5)
56
31
  if self.path.exists() and self.path.is_file():
57
32
  write_file(self.file, self.text_to_write)
58
33
  else:
@@ -0,0 +1,171 @@
1
+ import os.path
2
+ import queue
3
+ import shutil
4
+ import subprocess
5
+ from pathlib import Path
6
+ from threading import Thread
7
+
8
+ from PySide6.QtCore import QTimer
9
+ from PySide6.QtWidgets import QMainWindow, QTextEdit
10
+
11
+ from je_editor.utils.exception.exception_tags import compiler_not_found_error
12
+ from je_editor.utils.exception.exception_tags import file_not_fond_error
13
+ from je_editor.utils.exception.exceptions import JEditorExecException
14
+
15
+
16
+ class ExecManager(object):
17
+
18
+ def __init__(
19
+ self,
20
+ main_window=None,
21
+ program_language="python",
22
+ program_encoding="utf-8",
23
+ program_buffer=10240000,
24
+ ):
25
+ """
26
+ :param main_window: tkinter main window
27
+ :param program_language: which program language
28
+ :param program_encoding: which encoding
29
+ """
30
+ self.read_program_error_output_from_thread = None
31
+ self.read_program_output_from_thread = None
32
+ self.main_window: QMainWindow = main_window
33
+ self.code_result: [QTextEdit, None] = None
34
+ self.timer: [QTimer, None] = None
35
+ self.still_run_program = True
36
+ self.process = None
37
+ self.run_output_queue = queue.Queue()
38
+ self.run_error_queue = queue.Queue()
39
+ self.program_language = program_language
40
+ self.program_encoding = program_encoding
41
+ self.program_buffer = program_buffer
42
+
43
+ def later_init(self):
44
+ if self.main_window is not None:
45
+ self.code_result: QTextEdit = self.main_window.code_result
46
+ self.timer = QTimer(self.main_window)
47
+ else:
48
+ # TODO Exception
49
+ raise Exception
50
+
51
+ def exec_code(self, exec_file_name):
52
+ """
53
+ :param exec_file_name: string file will open to run
54
+ :return: if error return result and True else return result and False
55
+ """
56
+ try:
57
+ self.exit_program()
58
+ self.code_result.setPlainText("")
59
+ reformat_os_file_path = os.path.abspath(exec_file_name)
60
+ # detect file is exist
61
+ try:
62
+ if not Path(exec_file_name).exists():
63
+ raise JEditorExecException(file_not_fond_error)
64
+ except OSError as error:
65
+ raise JEditorExecException(error)
66
+ compiler_path = shutil.which(self.program_language)
67
+ if compiler_path is None and self.program_language == "python":
68
+ compiler_path = shutil.which("python3")
69
+ elif compiler_path is None and self.program_language == "python3":
70
+ compiler_path = shutil.which("python")
71
+ if compiler_path is None:
72
+ raise JEditorExecException(compiler_not_found_error)
73
+ exec_file = reformat_os_file_path
74
+ # run program
75
+ execute_program_list = [compiler_path, exec_file]
76
+ self.process = subprocess.Popen(
77
+ execute_program_list,
78
+ stdout=subprocess.PIPE,
79
+ stderr=subprocess.PIPE,
80
+ shell=False
81
+ )
82
+ self.still_run_program = True
83
+ # program output message queue thread
84
+ self.read_program_output_from_thread = Thread(
85
+ target=self.read_program_output_from_process,
86
+ daemon=True
87
+ ).start()
88
+ # program error message queue thread
89
+ self.read_program_error_output_from_thread = Thread(
90
+ target=self.read_program_error_output_from_process,
91
+ daemon=True
92
+ ).start()
93
+ # show which file execute
94
+ self.code_result.append(compiler_path + " " + reformat_os_file_path)
95
+ # start tkinter_ui update
96
+ # start timer
97
+ self.timer = QTimer(self.main_window)
98
+ self.timer.setInterval(1)
99
+ self.timer.timeout.connect(self.pull_text)
100
+ self.timer.start()
101
+ except Exception as error:
102
+ self.code_result.setTextColor(self.main_window.red_color)
103
+ self.code_result.append(str(error))
104
+ self.code_result.setTextColor(self.main_window.black_color)
105
+
106
+ # tkinter_ui update method
107
+ def pull_text(self):
108
+ try:
109
+ self.code_result.setTextColor(self.main_window.red_color)
110
+ if not self.run_error_queue.empty():
111
+ error_message = self.run_error_queue.get_nowait()
112
+ error_message = str(error_message).strip()
113
+ if error_message:
114
+ self.code_result.append(error_message)
115
+ self.code_result.setTextColor(self.main_window.black_color)
116
+ if not self.run_output_queue.empty():
117
+ output_message = self.run_output_queue.get_nowait()
118
+ output_message = str(output_message).strip()
119
+ if output_message:
120
+ self.code_result.append(output_message)
121
+ except queue.Empty:
122
+ pass
123
+ if self.process.returncode == 0:
124
+ self.exit_program()
125
+ elif self.process.returncode is not None:
126
+ self.exit_program()
127
+ self.timer.stop()
128
+ if self.still_run_program:
129
+ # poll return code
130
+ self.process.poll()
131
+
132
+ # exit program change run flag to false and clean read thread and queue and process
133
+ def exit_program(self):
134
+ self.still_run_program = False
135
+ if self.read_program_output_from_thread is not None:
136
+ self.read_program_output_from_thread = None
137
+ if self.read_program_error_output_from_thread is not None:
138
+ self.read_program_error_output_from_thread = None
139
+ self.print_and_clear_queue()
140
+ if self.process is not None:
141
+ self.process.terminate()
142
+
143
+ def print_and_clear_queue(self):
144
+ try:
145
+ for std_output in iter(self.run_output_queue.get_nowait, None):
146
+ std_output = str(std_output).strip()
147
+ if std_output:
148
+ self.code_result.append(std_output)
149
+ self.code_result.setTextColor(self.main_window.red_color)
150
+ for std_err in iter(self.run_error_queue.get_nowait, None):
151
+ std_err = str(std_err).strip()
152
+ if std_err:
153
+ self.code_result.append(std_err)
154
+ self.code_result.setTextColor(self.main_window.black_color)
155
+ except queue.Empty:
156
+ pass
157
+ self.run_output_queue = queue.Queue()
158
+ self.run_error_queue = queue.Queue()
159
+
160
+ def read_program_output_from_process(self):
161
+ while self.still_run_program:
162
+ program_output_data = self.process.stdout.raw.read(self.program_buffer).decode(self.program_encoding)
163
+ self.run_output_queue.put_nowait(program_output_data)
164
+
165
+ def read_program_error_output_from_process(self):
166
+ while self.still_run_program:
167
+ program_error_output_data = self.process.stderr.raw.read(self.program_buffer).decode(self.program_encoding)
168
+ self.run_error_queue.put_nowait(program_error_output_data)
169
+
170
+
171
+ exec_manage = ExecManager()
@@ -2,7 +2,8 @@ import os
2
2
 
3
3
  from PySide6.QtWidgets import QFileDialog
4
4
 
5
- from je_editor.utils.file.save.save_file import write_file, SaveThread
5
+ from je_editor.utils.file.save.save_file import write_file
6
+ from je_editor.pyside_ui.auto_save.auto_save_thread import SaveThread
6
7
 
7
8
 
8
9
  def choose_file_get_save_filename(parent_qt_instance):
@@ -18,5 +19,6 @@ def choose_file_get_save_filename(parent_qt_instance):
18
19
  parent_qt_instance.current_file,
19
20
  parent_qt_instance.code_edit.toPlainText()
20
21
  )
22
+ parent_qt_instance.auto_save_thread.start()
21
23
  elif parent_qt_instance.auto_save_thread is not None:
22
24
  parent_qt_instance.auto_save_thread.file = parent_qt_instance.current_file
@@ -1,12 +1,14 @@
1
1
  import os
2
2
 
3
- from PySide6.QtGui import QFontDatabase, QAction
3
+ from PySide6.QtCore import QTimer
4
+ from PySide6.QtGui import QFontDatabase, QAction, QColor
4
5
  from PySide6.QtWidgets import QMainWindow
5
6
 
6
7
  from je_editor.pyside_ui.main_ui_setting.ui_setting import set_ui
7
8
  from je_editor.pyside_ui.menu.menu_bar.set_menu_bar import set_menu_bar
8
9
  from je_editor.pyside_ui.treeview.project_treeview.set_project_treeview import set_project_treeview
9
- from je_editor.utils.file.save.save_file import SaveThread
10
+ from je_editor.pyside_ui.auto_save.auto_save_thread import SaveThread
11
+ from je_editor.utils.redirect_manager.redirect_manager_class import redirect_manager_instance
10
12
 
11
13
 
12
14
  class EditorMain(QMainWindow):
@@ -21,6 +23,14 @@ class EditorMain(QMainWindow):
21
23
  self.current_file = None
22
24
  # Font
23
25
  self.font_database = QFontDatabase()
26
+ # Color
27
+ self.red_color: QColor = QColor(255, 0, 0)
28
+ self.black_color: QColor = QColor(0, 0, 0)
29
+ # Timer to redirect error or message
30
+ self.redirect_timer = QTimer(self)
31
+ self.redirect_timer.setInterval(1)
32
+ self.redirect_timer.timeout.connect(self.redirect)
33
+ self.redirect_timer.start()
24
34
  set_ui(self)
25
35
  set_project_treeview(self)
26
36
  set_menu_bar(self)
@@ -33,6 +43,8 @@ class EditorMain(QMainWindow):
33
43
  self.current_file,
34
44
  self.code_edit.code_edit.toPlainText()
35
45
  )
46
+ self.auto_save_thread.start()
47
+ redirect_manager_instance.set_redirect(self, True)
36
48
 
37
49
  def add_font_menu(self):
38
50
  self.font_menu = self.text_menu.addMenu("Font")
@@ -67,3 +79,19 @@ class EditorMain(QMainWindow):
67
79
  int(self.sender().text())
68
80
  )
69
81
  )
82
+
83
+ def redirect(self):
84
+ if self.auto_save_thread is not None:
85
+ self.auto_save_thread.text_to_write = self.code_edit.toPlainText()
86
+ if not redirect_manager_instance.std_out_queue.empty():
87
+ output_message = redirect_manager_instance.std_out_queue.get_nowait()
88
+ output_message = str(output_message).strip()
89
+ if output_message:
90
+ self.code_result.append(output_message)
91
+ self.code_result.setTextColor(self.red_color)
92
+ if not redirect_manager_instance.std_err_queue.empty():
93
+ error_message = redirect_manager_instance.std_err_queue.get_nowait()
94
+ error_message = str(error_message).strip()
95
+ if error_message:
96
+ self.code_result.append(error_message)
97
+ self.code_result.setTextColor(self.black_color)
@@ -1,4 +1,7 @@
1
- from PySide6.QtWidgets import QMainWindow, QScrollArea, QPlainTextEdit, QGridLayout, QWidget
1
+ from PySide6 import QtGui
2
+ from PySide6.QtWidgets import QMainWindow, QScrollArea, QPlainTextEdit, QGridLayout, QWidget, QTextEdit
3
+
4
+ from je_editor.pyside_ui.syntax.python_syntax import PythonHighlighter
2
5
 
3
6
 
4
7
  def set_ui(ui_we_want_to_set: QMainWindow):
@@ -11,8 +14,11 @@ def set_ui(ui_we_want_to_set: QMainWindow):
11
14
  # code edit and code result plaintext
12
15
  ui_we_want_to_set.code_edit = QPlainTextEdit()
13
16
  ui_we_want_to_set.code_edit.setLineWrapMode(ui_we_want_to_set.code_edit.LineWrapMode.NoWrap)
14
- ui_we_want_to_set.code_result = QPlainTextEdit()
15
- ui_we_want_to_set.code_result.setLineWrapMode(ui_we_want_to_set.code_edit.LineWrapMode.NoWrap)
17
+ ui_we_want_to_set.code_edit.setTabStopDistance(
18
+ QtGui.QFontMetricsF(ui_we_want_to_set.code_edit.font()).horizontalAdvance(' ') * 4)
19
+ PythonHighlighter(ui_we_want_to_set.code_edit.document())
20
+ ui_we_want_to_set.code_result = QTextEdit()
21
+ ui_we_want_to_set.code_result.setLineWrapMode(ui_we_want_to_set.code_result.LineWrapMode.NoWrap)
16
22
  ui_we_want_to_set.code_result.setReadOnly(True)
17
23
  ui_we_want_to_set.code_edit_scroll_area = QScrollArea()
18
24
  ui_we_want_to_set.code_edit_scroll_area.setWidgetResizable(True)
@@ -0,0 +1,56 @@
1
+ from PySide6.QtGui import QAction
2
+ from PySide6.QtWidgets import QMainWindow
3
+
4
+ from je_editor.pyside_ui.code_process.code_exec import exec_manage
5
+ from je_editor.pyside_ui.file_dialog.save_file_dialog import choose_file_get_save_filename
6
+ from je_editor.pyside_ui.shell_process.shell_exec import shell_manager
7
+
8
+
9
+ def set_run_menu(ui_we_want_to_set: QMainWindow):
10
+
11
+ ui_we_want_to_set.run_program_action = QAction("Run Program")
12
+ ui_we_want_to_set.run_program_action.triggered.connect(
13
+ lambda: run_program(ui_we_want_to_set)
14
+ )
15
+ ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.run_program_action)
16
+ ui_we_want_to_set.run_on_shell_action = QAction("Run On Shell")
17
+ ui_we_want_to_set.run_on_shell_action.triggered.connect(
18
+ lambda: shell_exec(ui_we_want_to_set)
19
+ )
20
+ ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.run_on_shell_action)
21
+ ui_we_want_to_set.clean_result_action = QAction("Clean Result")
22
+ ui_we_want_to_set.clean_result_action.triggered.connect(
23
+ lambda: clean_result(ui_we_want_to_set)
24
+ )
25
+ ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.clean_result_action)
26
+
27
+ ui_we_want_to_set.stop_program_action = QAction("Stop Program")
28
+ ui_we_want_to_set.stop_program_action.triggered.connect(
29
+ stop_program
30
+ )
31
+ ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.stop_program_action)
32
+
33
+
34
+ def run_program(ui_we_want_to_set):
35
+ choose_file_get_save_filename(ui_we_want_to_set)
36
+ exec_manage.main_window = ui_we_want_to_set
37
+ exec_manage.later_init()
38
+ exec_manage.exec_code(
39
+ ui_we_want_to_set.current_file
40
+ )
41
+
42
+
43
+ def shell_exec(ui_we_want_to_set):
44
+ shell_manager.main_window = ui_we_want_to_set
45
+ shell_manager.later_init()
46
+ shell_manager.exec_shell(
47
+ ui_we_want_to_set.code_edit.toPlainText()
48
+ )
49
+
50
+
51
+ def stop_program():
52
+ exec_manage.exit_program()
53
+
54
+
55
+ def clean_result(ui_we_want_to_set):
56
+ ui_we_want_to_set.code_result.setPlainText("")
@@ -0,0 +1,147 @@
1
+ import queue
2
+ import shlex
3
+ import subprocess
4
+ from threading import Thread
5
+
6
+ from PySide6.QtCore import QTimer
7
+ from PySide6.QtGui import QColor
8
+ from PySide6.QtWidgets import QMainWindow, QTextEdit
9
+
10
+
11
+ class ShellManager(object):
12
+
13
+ def __init__(
14
+ self,
15
+ main_window: QMainWindow = None,
16
+ shell_encoding: str = "utf-8",
17
+ program_buffer: int = 10240000,
18
+ ):
19
+ """
20
+ :param main_window: tkinter main window
21
+ """
22
+ self.read_program_error_output_from_thread = None
23
+ self.read_program_output_from_thread = None
24
+ self.main_window: QMainWindow = main_window
25
+ self.code_result: [QTextEdit, None] = None
26
+ self.timer: [QTimer, None] = None
27
+ self.still_run_shell: bool = True
28
+ self.process = None
29
+ self.run_output_queue: queue = queue.Queue()
30
+ self.run_error_queue: queue = queue.Queue()
31
+ self.program_encoding: str = shell_encoding
32
+ self.program_buffer: int = program_buffer
33
+
34
+ def later_init(self):
35
+ if self.main_window is not None:
36
+ self.code_result: QTextEdit = self.main_window.code_result
37
+ else:
38
+ # TODO Exception
39
+ raise Exception
40
+
41
+ def exec_shell(self, shell_command: str):
42
+ """
43
+ :param shell_command: shell command will run
44
+ :return: if error return result and True else return result and False
45
+ """
46
+ try:
47
+ self.exit_program()
48
+ self.code_result.setPlainText("")
49
+ # run shell command
50
+ args = shlex.split(shell_command)
51
+ self.process = subprocess.Popen(
52
+ args,
53
+ stdout=subprocess.PIPE,
54
+ stderr=subprocess.PIPE,
55
+ shell=False,
56
+ )
57
+ self.still_run_shell = True
58
+ # program output message queue thread
59
+ self.read_program_output_from_thread = Thread(
60
+ target=self.read_program_output_from_process,
61
+ daemon=True
62
+ ).start()
63
+ # program error message queue thread
64
+ self.read_program_error_output_from_thread = Thread(
65
+ target=self.read_program_error_output_from_process,
66
+ daemon=True
67
+ ).start()
68
+ # start timer
69
+ self.timer = QTimer(self.main_window)
70
+ self.timer.setInterval(1)
71
+ self.timer.timeout.connect(self.pull_text)
72
+ self.timer.start()
73
+ except Exception as error:
74
+ self.code_result.setTextColor(self.main_window.red_color)
75
+ self.code_result.append(str(error))
76
+ self.code_result.setTextColor(self.main_window.black_color)
77
+
78
+ # tkinter_ui update method
79
+ def pull_text(self):
80
+ try:
81
+ self.code_result.setTextColor(self.main_window.red_color)
82
+ if not self.run_error_queue.empty():
83
+ error_message = self.run_error_queue.get_nowait()
84
+ error_message = str(error_message).strip()
85
+ if error_message:
86
+ self.code_result.append(error_message)
87
+ self.code_result.setTextColor(self.main_window.black_color)
88
+ if not self.run_output_queue.empty():
89
+ output_message = self.run_output_queue.get_nowait()
90
+ output_message = str(output_message).strip()
91
+ if output_message:
92
+ self.code_result.append(output_message)
93
+ except queue.Empty:
94
+ pass
95
+ if self.process.returncode == 0:
96
+ self.exit_program()
97
+ elif self.process.returncode is not None:
98
+ self.exit_program()
99
+ self.timer.stop()
100
+ if self.still_run_shell:
101
+ # poll return code
102
+ self.process.poll()
103
+
104
+ # exit program change run flag to false and clean read thread and queue and process
105
+ def exit_program(self):
106
+ self.still_run_shell = False
107
+ if self.read_program_output_from_thread is not None:
108
+ self.read_program_output_from_thread = None
109
+ if self.read_program_error_output_from_thread is not None:
110
+ self.read_program_error_output_from_thread = None
111
+ self.print_and_clear_queue()
112
+ if self.process is not None:
113
+ self.process.terminate()
114
+
115
+ def print_and_clear_queue(self):
116
+ try:
117
+ for std_output in iter(self.run_output_queue.get_nowait, None):
118
+ std_output = str(std_output).strip()
119
+ if std_output:
120
+ self.code_result.append(std_output)
121
+ self.code_result.setTextColor(self.main_window.red_color)
122
+ for std_err in iter(self.run_error_queue.get_nowait, None):
123
+ std_err = str(std_err).strip()
124
+ if std_err:
125
+ self.code_result.append(std_err)
126
+ self.code_result.setTextColor(self.main_window.black_color)
127
+ except queue.Empty:
128
+ pass
129
+ self.run_output_queue = queue.Queue()
130
+ self.run_error_queue = queue.Queue()
131
+
132
+ def read_program_output_from_process(self):
133
+ while self.still_run_shell:
134
+ program_output_data = self.process.stdout.raw.read(
135
+ self.program_buffer) \
136
+ .decode(self.program_encoding)
137
+ self.run_output_queue.put_nowait(program_output_data)
138
+
139
+ def read_program_error_output_from_process(self):
140
+ while self.still_run_shell:
141
+ program_error_output_data = self.process.stderr.raw.read(
142
+ self.program_buffer) \
143
+ .decode(self.program_encoding)
144
+ self.run_error_queue.put_nowait(program_error_output_data)
145
+
146
+
147
+ shell_manager = ShellManager()
@@ -0,0 +1,97 @@
1
+ from PySide6.QtCore import QRegularExpression
2
+ from PySide6.QtGui import QColor
3
+ from PySide6.QtGui import QFont
4
+ from PySide6.QtGui import QSyntaxHighlighter
5
+ from PySide6.QtGui import QTextCharFormat
6
+
7
+ keywords = [
8
+ "False", "None", "True", "and", "as", "assert", "async",
9
+ "await", "break", "class", "continue", "def", "del",
10
+ "elif", "else", "except", "finally", "for", "from",
11
+ "global", "if", "import", "in", "is", "lambda", "nonlocal",
12
+ "not", "or", "pass", "raise", "return", "try", "while", "with", "yield"
13
+ ]
14
+
15
+ builtins_keyword = [
16
+ "abs", "aiter", "all", "any", "anext", "ascii",
17
+ "bin", "bool", "breakpoint", "bytearray", "bytes",
18
+ "callable", "chr", "classmethod", "compile", "complex",
19
+ "delattr", "dict", "dir", "divmod",
20
+ "enumerate", "eval", "exec",
21
+ "filter", "float", "format", "frozenset",
22
+ "getattr", "globals",
23
+ "hasattr", "hash", "help", "hex",
24
+ "id", "input", "int", "isinstance", "issubclass", "iter",
25
+ "len", "list", "locals",
26
+ "map", "max", "memoryview", "min",
27
+ "next",
28
+ "object", "oct", "open", "ord",
29
+ "pow", "print", "property",
30
+ "range", "repr", "reversed", "round",
31
+ "set", "setattr", "slice", "sorted", "staticmethod",
32
+ "str", "sum", "super",
33
+ "tuple", "type",
34
+ "vars",
35
+ "zip",
36
+ "__import__"
37
+ ]
38
+
39
+ string_rule = [
40
+ r"'[^'\\]*(\\.[^'\\]*)*'", # Singel
41
+ r'"[^"\\]*(\\.[^"\\]*)*"' # Double
42
+ ]
43
+
44
+ number_rule = [
45
+ r"\b[+-]?[0-9]+[lL]?\b",
46
+ r"\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b",
47
+ r"\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b"
48
+ ]
49
+
50
+
51
+ class PythonHighlighter(QSyntaxHighlighter):
52
+ def __init__(self, parent=None):
53
+ super().__init__(parent)
54
+
55
+ self.highlight_rules = []
56
+
57
+ text_char_format = QTextCharFormat()
58
+ text_char_format.setForeground(QColor(255, 212, 102))
59
+ text_char_format.setFontWeight(QFont.Bold)
60
+ for word in keywords:
61
+ pattern = QRegularExpression(rf"\b{word}\b")
62
+ self.highlight_rules.append((pattern, text_char_format))
63
+
64
+ text_char_format = QTextCharFormat()
65
+ text_char_format.setForeground(QColor(0, 153, 0))
66
+ for rule in string_rule:
67
+ pattern = QRegularExpression(rule)
68
+ self.highlight_rules.append((pattern, text_char_format))
69
+
70
+ text_char_format = QTextCharFormat()
71
+ text_char_format.setForeground(QColor(0, 128, 255))
72
+ for rule in number_rule:
73
+ pattern = QRegularExpression(rule)
74
+ self.highlight_rules.append((pattern, text_char_format))
75
+
76
+ text_char_format = QTextCharFormat()
77
+ text_char_format.setForeground(QColor(0, 0, 255))
78
+ for rule in builtins_keyword:
79
+ pattern = QRegularExpression(rule)
80
+ self.highlight_rules.append((pattern, text_char_format))
81
+
82
+ text_char_format = QTextCharFormat()
83
+ text_char_format.setForeground(QColor(80, 80, 80))
84
+ pattern = QRegularExpression(r"#[^\n]*")
85
+ self.highlight_rules.append((pattern, text_char_format))
86
+
87
+ text_char_format = QTextCharFormat()
88
+ text_char_format.setForeground(QColor(204, 0, 204))
89
+ pattern = QRegularExpression(r"\bself\b")
90
+ self.highlight_rules.append((pattern, text_char_format))
91
+
92
+ def highlightBlock(self, text):
93
+ for pattern, format in self.highlight_rules:
94
+ match_iterator = pattern.globalMatch(text)
95
+ while match_iterator.hasNext():
96
+ match = match_iterator.next()
97
+ self.setFormat(match.capturedStart(), match.capturedLength(), format)
@@ -27,7 +27,10 @@ def treeview_click(ui_we_want_to_set):
27
27
  model = clicked_item.model()
28
28
  path = pathlib.Path(os.getcwd() + "/" + model.data(clicked_item))
29
29
  if path.is_file():
30
- file_content = read_file(path)[1]
30
+ file, file_content = read_file(path)
31
31
  ui_we_want_to_set.code_edit.setPlainText(
32
32
  file_content
33
33
  )
34
+ ui_we_want_to_set.current_file = file
35
+ if ui_we_want_to_set.auto_save_thread is not None:
36
+ ui_we_want_to_set.auto_save_thread.file = ui_we_want_to_set.current_file
File without changes
@@ -0,0 +1,31 @@
1
+ import time
2
+ from pathlib import Path
3
+ from threading import Lock
4
+ from threading import Thread
5
+
6
+ from je_editor.utils.exception.exceptions import JEditorSaveFileException
7
+
8
+
9
+ def write_file(file, content):
10
+ """
11
+ :param file: file we want to write
12
+ :param content: content write in file
13
+ try
14
+ lock thread
15
+ if file not empty string
16
+ write content to file
17
+ finally
18
+ release lock
19
+ """
20
+ lock = Lock()
21
+ content = str(content)
22
+ try:
23
+ lock.acquire()
24
+ if file != "" and file is not None:
25
+ with open(file, "w+") as file_to_write:
26
+ file_to_write.write(content)
27
+ except JEditorSaveFileException:
28
+ raise JEditorSaveFileException
29
+ finally:
30
+ lock.release()
31
+
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: je-editor
3
- Version: 0.0.62
3
+ Version: 0.0.64
4
4
  Summary: Simple editor for ITE
5
5
  Author-email: JE-Chen <zenmailman@gmail.com>
6
6
  License: MIT
@@ -11,6 +11,10 @@ je_editor.egg-info/requires.txt
11
11
  je_editor.egg-info/top_level.txt
12
12
  je_editor/pyside_ui/__init__.py
13
13
  je_editor/pyside_ui/actions/__init__.py
14
+ je_editor/pyside_ui/auto_save/__init__.py
15
+ je_editor/pyside_ui/auto_save/auto_save_thread.py
16
+ je_editor/pyside_ui/code_process/__init__.py
17
+ je_editor/pyside_ui/code_process/code_exec.py
14
18
  je_editor/pyside_ui/file_dialog/__init__.py
15
19
  je_editor/pyside_ui/file_dialog/open_file_dialog.py
16
20
  je_editor/pyside_ui/file_dialog/save_file_dialog.py
@@ -26,6 +30,10 @@ je_editor/pyside_ui/menu/menu_bar/file_menu/__init__.py
26
30
  je_editor/pyside_ui/menu/menu_bar/file_menu/build_file_menu.py
27
31
  je_editor/pyside_ui/menu/menu_bar/run_menu/__init__.py
28
32
  je_editor/pyside_ui/menu/menu_bar/run_menu/build_run_menu.py
33
+ je_editor/pyside_ui/shell_process/__init__.py
34
+ je_editor/pyside_ui/shell_process/shell_exec.py
35
+ je_editor/pyside_ui/syntax/__init__.py
36
+ je_editor/pyside_ui/syntax/python_syntax.py
29
37
  je_editor/pyside_ui/treeview/__init__.py
30
38
  je_editor/pyside_ui/treeview/project_treeview/__init__.py
31
39
  je_editor/pyside_ui/treeview/project_treeview/set_project_treeview.py
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "je_editor"
9
- version = "0.0.62"
9
+ version = "0.0.64"
10
10
  authors = [
11
11
  { name = "JE-Chen", email = "zenmailman@gmail.com" },
12
12
  ]
@@ -1,25 +0,0 @@
1
- from PySide6.QtGui import QAction
2
- from PySide6.QtWidgets import QMainWindow
3
-
4
-
5
- def set_run_menu(ui_we_want_to_set: QMainWindow):
6
- # TODO run
7
- ui_we_want_to_set.run_program_action = QAction("Run Program")
8
- ui_we_want_to_set.run_program_action.triggered.connect(temp)
9
- ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.run_program_action)
10
- # TODO run on shell
11
- ui_we_want_to_set.run_on_shell_action = QAction("Run On Shell")
12
- ui_we_want_to_set.run_on_shell_action.triggered.connect(temp)
13
- ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.run_on_shell_action)
14
- # TODO clean result
15
- ui_we_want_to_set.clean_result_action = QAction("Clean Result")
16
- ui_we_want_to_set.clean_result_action.triggered.connect(temp)
17
- ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.clean_result_action)
18
- # TODO stop program
19
- ui_we_want_to_set.stop_program_action = QAction("Stop Program")
20
- ui_we_want_to_set.stop_program_action.triggered.connect(temp)
21
- ui_we_want_to_set.run_menu.addAction(ui_we_want_to_set.stop_program_action)
22
-
23
-
24
- def temp():
25
- print("temp")
File without changes
File without changes
File without changes