Skip to content

Commit afae7db

Browse files
authored
Merge pull request #115 from Integration-Automation/dev
Dev
2 parents 0156418 + 6800e53 commit afae7db

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1749
-738
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,5 @@ dmypy.json
150150
**/.jeditor
151151
**/user_setting.*
152152
bing_cookies.*
153-
**/output
153+
**/output
154+
.claude/settings.local.json

PLUGIN_GUIDE.md

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# PyBreeze Plugin Guide / 插件開發指南
2+
3+
PyBreeze (jeditor) supports external plugins for adding **syntax highlighting** and **UI translations**.
4+
5+
PyBreeze (jeditor) 支援外部插件,可用於新增**語法高亮****UI 翻譯**
6+
7+
---
8+
9+
## Quick Start / 快速開始
10+
11+
1. Create a `.py` file in the `jeditor_plugins/` directory (under your working directory).
12+
2. Define a `register()` function.
13+
3. Optionally define `PLUGIN_NAME`, `PLUGIN_AUTHOR`, `PLUGIN_VERSION` for the Plugins menu.
14+
15+
<!-- -->
16+
17+
1. 在工作目錄下的 `jeditor_plugins/` 建立一個 `.py` 檔案。
18+
2. 定義一個 `register()` 函式。
19+
3. 可選:定義 `PLUGIN_NAME``PLUGIN_AUTHOR``PLUGIN_VERSION`,會顯示在插件選單中。
20+
21+
---
22+
23+
## Plugin Metadata / 插件元資料
24+
25+
```python
26+
PLUGIN_NAME = "My Plugin" # Display name in the Plugins menu / 插件選單顯示名稱
27+
PLUGIN_AUTHOR = "Your Name" # Author / 作者
28+
PLUGIN_VERSION = "1.0.0" # Version / 版本號
29+
```
30+
31+
All three are optional. If omitted, the filename is used as the plugin name.
32+
33+
三者皆為可選。若未定義,則以檔名作為插件名稱。
34+
35+
---
36+
37+
## Syntax Highlighting Plugin / 語法高亮插件
38+
39+
Use `register_programming_language()` to add syntax highlighting for file types.
40+
41+
使用 `register_programming_language()` 為檔案類型新增語法高亮。
42+
43+
### API
44+
45+
```python
46+
from je_editor.plugins import register_programming_language
47+
48+
register_programming_language(
49+
suffix=".ext", # File extension / 副檔名
50+
syntax_words={...}, # Keyword groups / 關鍵字群組
51+
syntax_rules={...}, # Regex rules (optional) / 正則規則(可選)
52+
)
53+
```
54+
55+
### syntax_words format / syntax_words 格式
56+
57+
```python
58+
from PySide6.QtGui import QColor
59+
60+
syntax_words = {
61+
"group_name": {
62+
"words": ("keyword1", "keyword2", ...), # Tuple or set of keywords / 關鍵字元組或集合
63+
"color": QColor(r, g, b), # Highlight color / 高亮顏色
64+
},
65+
# More groups...
66+
}
67+
```
68+
69+
### syntax_rules format / syntax_rules 格式
70+
71+
```python
72+
syntax_rules = {
73+
"rule_name": {
74+
"rules": (r"regex_pattern", ...), # Tuple of regex patterns / 正則表達式元組
75+
"color": QColor(r, g, b), # Highlight color / 高亮顏色
76+
},
77+
}
78+
```
79+
80+
### Full Example / 完整範例
81+
82+
```python
83+
"""Go syntax highlighting plugin."""
84+
from PySide6.QtGui import QColor
85+
from je_editor.plugins import register_programming_language
86+
87+
PLUGIN_NAME = "Go Syntax Highlighting"
88+
PLUGIN_AUTHOR = "Your Name"
89+
PLUGIN_VERSION = "1.0.0"
90+
91+
go_syntax_words = {
92+
"keywords": {
93+
"words": (
94+
"break", "case", "chan", "const", "continue",
95+
"default", "defer", "else", "fallthrough", "for",
96+
"func", "go", "goto", "if", "import",
97+
"interface", "map", "package", "range", "return",
98+
"select", "struct", "switch", "type", "var",
99+
),
100+
"color": QColor(86, 156, 214),
101+
},
102+
"types": {
103+
"words": (
104+
"bool", "byte", "complex64", "complex128",
105+
"float32", "float64", "int", "int8", "int16",
106+
"int32", "int64", "rune", "string", "uint",
107+
"uint8", "uint16", "uint32", "uint64", "uintptr",
108+
"error", "nil", "true", "false", "iota",
109+
),
110+
"color": QColor(78, 201, 176),
111+
},
112+
}
113+
114+
go_syntax_rules = {
115+
"single_line_comment": {
116+
"rules": (r"//[^\n]*",),
117+
"color": QColor(106, 153, 85),
118+
},
119+
}
120+
121+
122+
def register() -> None:
123+
register_programming_language(
124+
suffix=".go",
125+
syntax_words=go_syntax_words,
126+
syntax_rules=go_syntax_rules,
127+
)
128+
```
129+
130+
### Multiple Suffixes / 多個副檔名
131+
132+
If a language uses multiple file extensions, register each suffix with the same `syntax_words`:
133+
134+
若一個語言使用多個副檔名,用相同的 `syntax_words` 分別註冊每個副檔名:
135+
136+
```python
137+
def register() -> None:
138+
for suffix in (".cpp", ".cxx", ".cc", ".h", ".hpp", ".hxx"):
139+
register_programming_language(
140+
suffix=suffix,
141+
syntax_words=cpp_syntax_words,
142+
syntax_rules=cpp_syntax_rules,
143+
)
144+
```
145+
146+
They will be grouped under one submenu in the Plugins menu.
147+
148+
它們會在插件選單中合併顯示在同一個子選單下。
149+
150+
---
151+
152+
## Translation Plugin / 翻譯插件
153+
154+
Use `register_natural_language()` to add a new UI language.
155+
156+
使用 `register_natural_language()` 新增 UI 語言。
157+
158+
### API
159+
160+
```python
161+
from je_editor.plugins import register_natural_language
162+
163+
register_natural_language(
164+
language_key="French", # Internal key / 內部鍵值
165+
display_name="Francais", # Shown in Language menu / 語言選單顯示名稱
166+
word_dict={...}, # Translation dictionary / 翻譯字典
167+
)
168+
```
169+
170+
### word_dict keys / word_dict 鍵值
171+
172+
The `word_dict` should contain the same keys as jeditor's built-in `english_word_dict`.
173+
Common keys include:
174+
175+
`word_dict` 應包含與 jeditor 內建 `english_word_dict` 相同的鍵值。
176+
常用鍵值包括:
177+
178+
| Key | Description / 說明 |
179+
|---|---|
180+
| `application_name` | Window title / 視窗標題 |
181+
| `file_menu_label` | File menu / 檔案選單 |
182+
| `run_menu_label` | Run menu / 執行選單 |
183+
| `tab_name_editor` | Editor tab / 編輯器分頁 |
184+
| `language_menu_label` | Language menu / 語言選單 |
185+
| `help_menu_label` | Help menu / 幫助選單 |
186+
187+
For a complete list, refer to `je_editor.utils.multi_language.english.english_word_dict`
188+
or see the example plugin `exe/jeditor_plugins/french.py`.
189+
190+
完整鍵值列表請參考 `je_editor.utils.multi_language.english.english_word_dict`
191+
或參考範例插件 `exe/jeditor_plugins/french.py`
192+
193+
### Full Example / 完整範例
194+
195+
```python
196+
"""Japanese translation plugin."""
197+
from je_editor.plugins import register_natural_language
198+
199+
PLUGIN_NAME = "Japanese Translation"
200+
PLUGIN_AUTHOR = "Your Name"
201+
PLUGIN_VERSION = "1.0.0"
202+
203+
japanese_word_dict = {
204+
"application_name": "JEditor",
205+
"file_menu_label": "ファイル",
206+
"run_menu_label": "実行",
207+
"tab_name_editor": "エディタ",
208+
"language_menu_label": "言語",
209+
"language_menu_bar_english": "英語",
210+
"language_menu_bar_traditional_chinese": "繁体字中国語",
211+
"language_menu_bar_please_restart_messagebox": "アプリケーションを再起動してください",
212+
# ... more keys
213+
}
214+
215+
216+
def register() -> None:
217+
register_natural_language(
218+
language_key="Japanese",
219+
display_name="日本語",
220+
word_dict=japanese_word_dict,
221+
)
222+
```
223+
224+
---
225+
226+
## Run Config (Execute Files) / 執行設定
227+
228+
Plugins can register a `PLUGIN_RUN_CONFIG` to enable running files from the **Run with...** menu.
229+
230+
插件可定義 `PLUGIN_RUN_CONFIG`,讓使用者可以從 **以...執行** 選單執行檔案。
231+
232+
### Interpreted Languages / 直譯式語言
233+
234+
For languages that run directly (Go, Java 11+, Python):
235+
236+
直接執行的語言(Go、Java 11+、Python):
237+
238+
```python
239+
PLUGIN_RUN_CONFIG = {
240+
"name": "Go", # Display name in menu / 選單顯示名稱
241+
"suffixes": (".go",), # Supported file types / 支援的副檔名
242+
"compiler": "go", # Executable / 執行檔
243+
"args": ("run",), # Args before file path / 檔案路徑前的參數
244+
}
245+
# Runs: go run file.go
246+
```
247+
248+
### Compiled Languages / 編譯式語言
249+
250+
For languages that need compile-then-run (C, C++, Rust):
251+
252+
需要先編譯再執行的語言(C、C++、Rust):
253+
254+
```python
255+
PLUGIN_RUN_CONFIG = {
256+
"name": "C (GCC)",
257+
"suffixes": (".c",),
258+
"compiler": "gcc",
259+
"args": (),
260+
"compile_then_run": True, # Compile first, then run output / 先編譯再執行
261+
"output_flag": "-o", # Flag for output binary / 輸出檔案的旗標
262+
}
263+
# Compiles: gcc file.c -o file
264+
# Then runs: ./file (Linux/Mac) or file.exe (Windows)
265+
```
266+
267+
### Config Keys / 設定鍵值
268+
269+
| Key | Required | Description |
270+
|---|---|---|
271+
| `name` | Yes | Display name / 顯示名稱 |
272+
| `suffixes` | Yes | Tuple of file extensions / 副檔名元組 |
273+
| `compiler` | Yes | Compiler/interpreter executable / 編譯器或直譯器 |
274+
| `args` | No | Extra args before file path / 檔案路徑前的額外參數 |
275+
| `compile_then_run` | No | If `True`, compile first / 若為 `True` 則先編譯 |
276+
| `output_flag` | No | Output file flag (default `"-o"`) / 輸出旗標 |
277+
278+
---
279+
280+
## Directory Structure / 目錄結構
281+
282+
```
283+
working_directory/
284+
jeditor_plugins/
285+
my_syntax.py # Single-file plugin / 單檔插件
286+
my_language.py
287+
my_package/ # Package plugin / 套件插件
288+
__init__.py
289+
```
290+
291+
- Plugins are auto-discovered from `jeditor_plugins/` under the current working directory.
292+
- Files starting with `_` or `.` are ignored.
293+
- Each plugin must have a `register()` function.
294+
295+
<!-- -->
296+
297+
- 插件會從工作目錄下的 `jeditor_plugins/` 自動載入。
298+
-`_``.` 開頭的檔案會被忽略。
299+
- 每個插件必須有 `register()` 函式。
300+
301+
---
302+
303+
## Existing Plugins / 現有插件
304+
305+
| Plugin | File | Type | Run Support |
306+
|---|---|---|---|
307+
| C Syntax Highlighting | `c_syntax.py` | Syntax (`.c`) | GCC compile & run |
308+
| C++ Syntax Highlighting | `cpp_syntax.py` | Syntax (`.cpp`, `.cxx`, `.cc`, `.h`, `.hpp`, `.hxx`) | G++ compile & run |
309+
| Go Syntax Highlighting | `go_syntax.py` | Syntax (`.go`) | `go run` |
310+
| Java Syntax Highlighting | `java_syntax.py` | Syntax (`.java`) | `java` |
311+
| Rust Syntax Highlighting | `rust_syntax.py` | Syntax (`.rs`) | rustc compile & run |
312+
| French Translation | `french.py` | Language | - |
313+
314+
All plugins are located in `exe/jeditor_plugins/`.

dev.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
66

77
[project]
88
name = "pybreeze_dev"
9-
version = "1.0.10"
9+
version = "1.0.12"
1010
authors = [
1111
{ name = "JE-Chen", email = "jechenmailman@gmail.com" },
1212
]

pybreeze/__init__.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1-
from pybreeze.pybreeze_ui.editor_main.main_ui import PyBreezeMainWindow
21
from pybreeze.pybreeze_ui.editor_main.main_ui import EDITOR_EXTEND_TAB
2+
from pybreeze.pybreeze_ui.editor_main.main_ui import PyBreezeMainWindow
33
from pybreeze.pybreeze_ui.editor_main.main_ui import start_editor
44

5+
# Re-export jeditor plugin API for convenience
6+
from je_editor import (
7+
load_external_plugins,
8+
register_natural_language,
9+
register_programming_language,
10+
)
11+
512
__all__ = [
6-
"start_editor", "PyBreezeMainWindow", "EDITOR_EXTEND_TAB"
13+
"EDITOR_EXTEND_TAB",
14+
"PyBreezeMainWindow",
15+
"load_external_plugins",
16+
"register_natural_language",
17+
"register_programming_language",
18+
"start_editor",
719
]

pybreeze/__main__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from pybreeze import start_editor
2+
3+
start_editor()

pybreeze/extend/mail_thunder_extend/mail_thunder_setting.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1+
from __future__ import annotations
2+
13
import sys
24
from email.mime.multipart import MIMEMultipart
35

46
from pybreeze.utils.exception.exception_tags import send_html_exception_tag
57
from pybreeze.utils.exception.exceptions import ITESendHtmlReportException
68

79

8-
def send_after_test(html_report_path: str = None) -> None:
10+
def send_after_test(html_report_path: str | None = None) -> None:
911
try:
1012
from je_mail_thunder import SMTPWrapper
1113
mail_thunder_smtp: SMTPWrapper = SMTPWrapper()
12-
if html_report_path is None and mail_thunder_smtp.login_state is True:
14+
if html_report_path is None and mail_thunder_smtp.login_state:
1315
user: str = mail_thunder_smtp.user
14-
with open("default_name.html", "r+") as file:
16+
with open("default_name.html") as file:
1517
html_string: str = file.read()
1618
message = mail_thunder_smtp.create_message_with_attach(
1719
html_string,
1820
{"Subject": "Test Report", "To": user, "From": user},
1921
"default_name.html", use_html=True)
2022
mail_thunder_smtp.send_message(message)
2123
mail_thunder_smtp.quit()
22-
elif mail_thunder_smtp.login_state is True:
24+
elif mail_thunder_smtp.login_state:
2325
user: str = mail_thunder_smtp.user
24-
with open(html_report_path, "r+") as file:
26+
with open(html_report_path) as file:
2527
html_string: str = file.read()
2628
message: MIMEMultipart = mail_thunder_smtp.create_message_with_attach(
2729
html_string,

0 commit comments

Comments
 (0)