From 16c9fa190a905f9c64fec84597530888b07e802d Mon Sep 17 00:00:00 2001 From: rakima Date: Mon, 17 Aug 2026 22:09:16 +0900 Subject: [PATCH 1/3] =?UTF-8?q?add:=20=E8=A7=A3=E6=9E=90=E7=B5=90=E6=9E=9C?= =?UTF-8?q?=E3=82=92=E5=8F=B3=E5=81=B4=E3=81=AB=E8=A1=A8=E7=A4=BA=E3=81=99?= =?UTF-8?q?=E3=82=8B=E5=AE=9F=E9=A8=93=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6?= =?UTF-8?q?=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- syntax_helper/gui.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/syntax_helper/gui.py b/syntax_helper/gui.py index 7237c1c..e68d8a2 100644 --- a/syntax_helper/gui.py +++ b/syntax_helper/gui.py @@ -98,8 +98,8 @@ class SyntaxErrorHelperApp(TkinterDnD.Tk): def __init__(self) -> None: super().__init__() self.title("構文エラー解析ツール") - self.geometry("1000x720") - self.minsize(720, 520) + self.geometry("1200x720") + self.minsize(900, 520) self.service = SyntaxAnalyzerService() self._build_ui() @@ -117,7 +117,7 @@ def _build_ui(self) -> None: self.status = tk.StringVar(value="対応ファイルをエディタへドラッグ&ドロップして読み込めます。") ttk.Label(self, textvariable=self.status, foreground="#555555", padding=(10, 0, 10, 6)).pack(fill="x") - pane = ttk.Panedwindow(self, orient="vertical") + pane = ttk.Panedwindow(self, orient="horizontal") pane.pack(fill="both", expand=True, padx=10, pady=(0, 10)) editor_frame = ttk.LabelFrame(pane, text="ソースコード", padding=4) self.editor = LineNumberedEditor(editor_frame) @@ -128,7 +128,7 @@ def _build_ui(self) -> None: pane.add(editor_frame, weight=3) result_frame = ttk.LabelFrame(pane, text="解析結果・修正候補", padding=4) - self.result = tk.Text(result_frame, wrap="word", height=12, state="disabled", + self.result = tk.Text(result_frame, wrap="word", width=42, state="disabled", background="#fafafa", font=("Yu Gothic UI", 10)) result_scroll = ttk.Scrollbar(result_frame, orient="vertical", command=self.result.yview) self.result.configure(yscrollcommand=result_scroll.set) From 5e1ea102d1041b9ad563a0f3487667238283efea Mon Sep 17 00:00:00 2001 From: rakima Date: Mon, 17 Aug 2026 22:13:54 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E8=A7=A3=E6=9E=90=E7=B5=90=E6=9E=9C?= =?UTF-8?q?=E3=81=AE=E5=8C=BA=E5=88=87=E3=82=8A=E7=B7=9A=E3=82=92=E7=9F=AD?= =?UTF-8?q?=E7=B8=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- syntax_helper/gui.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/syntax_helper/gui.py b/syntax_helper/gui.py index e68d8a2..d2655e5 100644 --- a/syntax_helper/gui.py +++ b/syntax_helper/gui.py @@ -9,6 +9,9 @@ from .service import SyntaxAnalyzerService +RESULT_SEPARATOR = "─" * 20 + + class LineNumberedEditor(ttk.Frame): def __init__(self, master: tk.Misc) -> None: super().__init__(master) @@ -163,7 +166,7 @@ def _analyze(self) -> None: results = self.service.analyze(self.language.get(), self.editor.get()) self.editor.highlight(results) if results: - content = "\n\n" + ("\n\n" + "─" * 40 + "\n\n").join( + content = "\n\n" + ("\n\n" + RESULT_SEPARATOR + "\n\n").join( result.to_japanese_text() for result in results ) else: From fbf2423d4660a0166b65e5ba0dc166dc22aa0b31 Mon Sep 17 00:00:00 2001 From: rakima Date: Mon, 17 Aug 2026 22:14:43 +0900 Subject: [PATCH 3/3] =?UTF-8?q?add:=20=E8=A7=A3=E6=9E=90=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E3=81=A8=E4=BF=AE=E6=AD=A3=E5=80=99=E8=A3=9C=E3=82=92=E8=83=8C?= =?UTF-8?q?=E6=99=AF=E8=89=B2=E3=81=A7=E5=8C=BA=E5=88=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- syntax_helper/gui.py | 34 +++++++++++++++++++++++++++------- syntax_helper/model.py | 16 +++++++++++----- tests/test_model.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 tests/test_model.py diff --git a/syntax_helper/gui.py b/syntax_helper/gui.py index d2655e5..c43b861 100644 --- a/syntax_helper/gui.py +++ b/syntax_helper/gui.py @@ -133,6 +133,24 @@ def _build_ui(self) -> None: result_frame = ttk.LabelFrame(pane, text="解析結果・修正候補", padding=4) self.result = tk.Text(result_frame, wrap="word", width=42, state="disabled", background="#fafafa", font=("Yu Gothic UI", 10)) + self.result.tag_configure( + "analysis", + background="#ffe8e8", + lmargin1=6, + lmargin2=6, + rmargin=6, + spacing1=4, + spacing3=4, + ) + self.result.tag_configure( + "suggestion", + background="#e8f5e9", + lmargin1=6, + lmargin2=6, + rmargin=6, + spacing1=4, + spacing3=4, + ) result_scroll = ttk.Scrollbar(result_frame, orient="vertical", command=self.result.yview) self.result.configure(yscrollcommand=result_scroll.set) self.result.pack(side="left", fill="both", expand=True) @@ -165,15 +183,17 @@ def _clear_results(self) -> None: def _analyze(self) -> None: results = self.service.analyze(self.language.get(), self.editor.get()) self.editor.highlight(results) - if results: - content = "\n\n" + ("\n\n" + RESULT_SEPARATOR + "\n\n").join( - result.to_japanese_text() for result in results - ) - else: - content = "構文エラー候補は見つかりませんでした。" self.result.configure(state="normal") self.result.delete("1.0", "end") - self.result.insert("1.0", content.strip()) + if not results: + self.result.insert("1.0", "構文エラー候補は見つかりませんでした。") + else: + for index, result in enumerate(results): + if index: + self.result.insert("end", f"\n{RESULT_SEPARATOR}\n\n") + self.result.insert("end", result.analysis_text() + "\n", "analysis") + self.result.insert("end", "\n") + self.result.insert("end", result.suggestion_text() + "\n", "suggestion") self.result.configure(state="disabled") diff --git a/syntax_helper/model.py b/syntax_helper/model.py index 8fd3b79..37758a2 100644 --- a/syntax_helper/model.py +++ b/syntax_helper/model.py @@ -17,11 +17,17 @@ class AnalysisResult: reason: str suggestion: str - def to_japanese_text(self) -> str: + def location_text(self) -> str: location = f"{self.error_line}行目付近に問題がある可能性があります。" if self.suspected_line != self.error_line: location += f"\n原因候補は{self.suspected_line}行目です。" - return ( - f"{location}\n\n{self.message}\n\n" - f"理由: {self.reason}\n\n修正候補:\n{self.suggestion}" - ) + return location + + def analysis_text(self) -> str: + return f"{self.location_text()}\n\n{self.message}\n\n理由: {self.reason}" + + def suggestion_text(self) -> str: + return f"修正候補:\n{self.suggestion}" + + def to_japanese_text(self) -> str: + return f"{self.analysis_text()}\n\n{self.suggestion_text()}" diff --git a/tests/test_model.py b/tests/test_model.py new file mode 100644 index 0000000..0be34aa --- /dev/null +++ b/tests/test_model.py @@ -0,0 +1,32 @@ +import unittest + +from syntax_helper.model import AnalysisResult, Severity + + +class AnalysisResultTest(unittest.TestCase): + def setUp(self) -> None: + self.result = AnalysisResult( + severity=Severity.ERROR, + language="C", + error_line=2, + suspected_line=1, + message="セミコロンが不足している可能性があります。", + reason="次の行でエラーになることがあります。", + suggestion="int value = 10;", + ) + + def test_analysis_and_suggestion_are_separate_sections(self) -> None: + self.assertIn("原因候補は1行目です。", self.result.analysis_text()) + self.assertIn("理由:", self.result.analysis_text()) + self.assertNotIn("修正候補:", self.result.analysis_text()) + self.assertEqual("修正候補:\nint value = 10;", self.result.suggestion_text()) + + def test_combined_text_keeps_existing_format(self) -> None: + self.assertEqual( + f"{self.result.analysis_text()}\n\n{self.result.suggestion_text()}", + self.result.to_japanese_text(), + ) + + +if __name__ == "__main__": + unittest.main()