From fc587431dff462d8717960d2953c9ccd05248682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E6=B3=A2?= Date: Sat, 14 Dec 2024 16:53:56 +0800 Subject: [PATCH 1/5] Delete CNAME --- CNAME | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CNAME diff --git a/CNAME b/CNAME deleted file mode 100644 index 8ea31073..00000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -www.luoboduner.com \ No newline at end of file From 5fdd73d7901946b23073cc2a33bfe9e03da4c5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E6=B3=A2?= Date: Sat, 14 Dec 2024 16:55:16 +0800 Subject: [PATCH 2/5] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..23e59220 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +mootool.luoboduner.com \ No newline at end of file From a5699da134a80d4d21b16954d154cfc972707033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E6=B3=A2?= Date: Sat, 14 Dec 2024 16:55:58 +0800 Subject: [PATCH 3/5] Delete CNAME --- CNAME | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CNAME diff --git a/CNAME b/CNAME deleted file mode 100644 index 23e59220..00000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -mootool.luoboduner.com \ No newline at end of file From 7ac7756f39148eac1e46d41a1761edef23c9f034 Mon Sep 17 00:00:00 2001 From: Cassian Florin Date: Sat, 27 Sep 2025 21:11:55 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(text-diff):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E5=B7=AE=E5=BC=82=E5=AF=B9=E6=AF=94=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增文本对比模块,支持并排对比与统一差异两种视图 - 实现基于java-diff-utils的行级与字符级差异计算 - 提供高亮显示差异内容的功能,包括删除、新增与修改 - 支持忽略空白字符的对比选项 - 添加数据库表结构用于存储文档及其版本信息 - 引入相关Java类以支持差异计算与UI展示 - 增加文本对比功能的界面设计与交互逻辑 - 支持实时对比及手动触发对比两种模式 - 实现滚动同步功能以便于并排查看差异 - 提供差异导航功能,可在差异点间快速切换 - 保存用户输入内容至本地数据库 - 更新readme文档,增加文本对比功能截图展示 - 添加文本对比功能图标与菜单项 - 引入java-diff-utils依赖库用于差异算法实现 --- pom.xml | 9 + readme.md | 3 + screen_shoot/textdiff_side_by_side.png | Bin 0 -> 127716 bytes screen_shoot/textdiff_unified.png | Bin 0 -> 114280 bytes .../moo/tool/bean/textdiff/DiffInfo.java | 12 + .../moo/tool/bean/textdiff/DiffResult.java | 11 + .../moo/tool/bean/textdiff/Span.java | 11 + .../tool/bean/textdiff/TextDiffSegment.java | 18 + .../moo/tool/bean/textdiff/UIDiff.java | 12 + .../moo/tool/bean/textdiff/UnifiedView.java | 11 + .../moo/tool/enums/DiffTypeEnum.java | 15 + .../moo/tool/enums/UnifiedSpanTypeEnum.java | 18 + .../moo/tool/service/DiffService.java | 344 +++++++ .../luoboduner/moo/tool/ui/FuncConsts.java | 5 + .../java/com/luoboduner/moo/tool/ui/Init.java | 1 + .../moo/tool/ui/form/MainWindow.form | 9 + .../moo/tool/ui/form/MainWindow.java | 7 +- .../moo/tool/ui/form/func/TextDiffForm.java | 966 ++++++++++++++++++ .../ui/listener/func/TextDiffListener.java | 133 +++ src/main/resources/db_init.sql | 26 + 20 files changed, 1610 insertions(+), 1 deletion(-) create mode 100644 screen_shoot/textdiff_side_by_side.png create mode 100644 screen_shoot/textdiff_unified.png create mode 100644 src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffInfo.java create mode 100644 src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffResult.java create mode 100644 src/main/java/com/luoboduner/moo/tool/bean/textdiff/Span.java create mode 100644 src/main/java/com/luoboduner/moo/tool/bean/textdiff/TextDiffSegment.java create mode 100644 src/main/java/com/luoboduner/moo/tool/bean/textdiff/UIDiff.java create mode 100644 src/main/java/com/luoboduner/moo/tool/bean/textdiff/UnifiedView.java create mode 100644 src/main/java/com/luoboduner/moo/tool/enums/DiffTypeEnum.java create mode 100644 src/main/java/com/luoboduner/moo/tool/enums/UnifiedSpanTypeEnum.java create mode 100644 src/main/java/com/luoboduner/moo/tool/service/DiffService.java create mode 100644 src/main/java/com/luoboduner/moo/tool/ui/form/func/TextDiffForm.java create mode 100644 src/main/java/com/luoboduner/moo/tool/ui/listener/func/TextDiffListener.java diff --git a/pom.xml b/pom.xml index f99e125a..b2acf1b4 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ 1.70 3.0.0 2.13.3 + 4.16 @@ -77,6 +78,14 @@ + + + + io.github.java-diff-utils + java-diff-utils + ${java-diff.version} + + junit junit diff --git a/readme.md b/readme.md index 08cfeb78..20269da5 100644 --- a/readme.md +++ b/readme.md @@ -53,6 +53,9 @@ Windows • Linux • macOS ![Overview](screen_shoot/theme.png) +- 并排对比:![TextDiff-并排](/screen_shoot/textdiff_side_by_side.png) +- 统一差异:![TextDiff-统一差异](/screen_shoot/textdiff_unified.png) + ## 下载 [https://github.com/rememberber/MooTool/releases](https://github.com/rememberber/MooTool/releases) diff --git a/screen_shoot/textdiff_side_by_side.png b/screen_shoot/textdiff_side_by_side.png new file mode 100644 index 0000000000000000000000000000000000000000..f97505a216da154ab30a7a1a1f018ed4263f23ac GIT binary patch literal 127716 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 M;Qn3N{^J+_8v*kWQ2+n{ literal 0 HcmV?d00001 diff --git a/src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffInfo.java b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffInfo.java new file mode 100644 index 00000000..38048e87 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffInfo.java @@ -0,0 +1,12 @@ +package com.luoboduner.moo.tool.bean.textdiff; + +import com.luoboduner.moo.tool.enums.DiffTypeEnum; + +/** + * 差异信息类,用于UI高亮显示 + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:37 + */ +public record DiffInfo(int lineNumber, String content, DiffTypeEnum type) { +} diff --git a/src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffResult.java b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffResult.java new file mode 100644 index 00000000..3aa58220 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/DiffResult.java @@ -0,0 +1,11 @@ +package com.luoboduner.moo.tool.bean.textdiff; + +import java.util.List; + +/** + * 差异结果类 + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:57 + */ +public record DiffResult(List leftDiffs, List rightDiffs) {} diff --git a/src/main/java/com/luoboduner/moo/tool/bean/textdiff/Span.java b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/Span.java new file mode 100644 index 00000000..453d3b1d --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/Span.java @@ -0,0 +1,11 @@ +package com.luoboduner.moo.tool.bean.textdiff; + +import com.luoboduner.moo.tool.enums.UnifiedSpanTypeEnum; + +/** + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:54 + */ +public record Span(int start, int end, UnifiedSpanTypeEnum type) { +} diff --git a/src/main/java/com/luoboduner/moo/tool/bean/textdiff/TextDiffSegment.java b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/TextDiffSegment.java new file mode 100644 index 00000000..3f98b9b5 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/TextDiffSegment.java @@ -0,0 +1,18 @@ +package com.luoboduner.moo.tool.bean.textdiff; + +import com.luoboduner.moo.tool.enums.DiffTypeEnum; + +/** + * 用于 UI 的精细化段(按字符区间) + * + * @param leftStart -1 表示无 + * @param leftEnd -1 表示无 + * @param rightStart -1 表示无 + * @param rightEnd -1 表示无 + * + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:52 + */ +public record TextDiffSegment(DiffTypeEnum type, int leftStart, int leftEnd, int rightStart, int rightEnd) { +} diff --git a/src/main/java/com/luoboduner/moo/tool/bean/textdiff/UIDiff.java b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/UIDiff.java new file mode 100644 index 00000000..ecbf6c67 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/UIDiff.java @@ -0,0 +1,12 @@ +package com.luoboduner.moo.tool.bean.textdiff; + + +import java.util.List; + +/** + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:31 + */ +public record UIDiff(List segments) { +} diff --git a/src/main/java/com/luoboduner/moo/tool/bean/textdiff/UnifiedView.java b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/UnifiedView.java new file mode 100644 index 00000000..0e271f40 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/bean/textdiff/UnifiedView.java @@ -0,0 +1,11 @@ +package com.luoboduner.moo.tool.bean.textdiff; + +import java.util.List; + +/** + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:54 + */ +public record UnifiedView(String text, List lineSpans, List charSpans, int charEventCount) { +} diff --git a/src/main/java/com/luoboduner/moo/tool/enums/DiffTypeEnum.java b/src/main/java/com/luoboduner/moo/tool/enums/DiffTypeEnum.java new file mode 100644 index 00000000..8d40a779 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/enums/DiffTypeEnum.java @@ -0,0 +1,15 @@ +package com.luoboduner.moo.tool.enums; + +/** + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:42 + */ +public enum DiffTypeEnum { + + EQUAL, // 相同 + INSERT, // 插入 + DELETE, // 删除 + CHANGE // 修改 + +} diff --git a/src/main/java/com/luoboduner/moo/tool/enums/UnifiedSpanTypeEnum.java b/src/main/java/com/luoboduner/moo/tool/enums/UnifiedSpanTypeEnum.java new file mode 100644 index 00000000..95e9121e --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/enums/UnifiedSpanTypeEnum.java @@ -0,0 +1,18 @@ +package com.luoboduner.moo.tool.enums; + +/** + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 18:55 + */ +public enum UnifiedSpanTypeEnum { + + ADD_LINE, + DEL_LINE, + HUNK_LINE, + HEADER_LINE, + ADD_CHAR, + DEL_CHAR, + CHANGE_CHAR + +} diff --git a/src/main/java/com/luoboduner/moo/tool/service/DiffService.java b/src/main/java/com/luoboduner/moo/tool/service/DiffService.java new file mode 100644 index 00000000..24fdfa09 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/service/DiffService.java @@ -0,0 +1,344 @@ +package com.luoboduner.moo.tool.service; + +import com.github.difflib.DiffUtils; +import com.github.difflib.UnifiedDiffUtils; +import com.github.difflib.patch.AbstractDelta; +import com.github.difflib.patch.DeltaType; +import com.github.difflib.patch.Patch; +import com.luoboduner.moo.tool.bean.textdiff.Span; +import com.luoboduner.moo.tool.bean.textdiff.TextDiffSegment; +import com.luoboduner.moo.tool.bean.textdiff.UIDiff; +import com.luoboduner.moo.tool.bean.textdiff.UnifiedView; +import com.luoboduner.moo.tool.enums.DiffTypeEnum; +import com.luoboduner.moo.tool.enums.UnifiedSpanTypeEnum; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; + +/** + *
+ *     差异服务
+ *     计算 diff 并生成 unified diff(行级)
+ * 
+ * + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 10:51 + */ +@Slf4j +public class DiffService { + + /** + * 简单行切分器 + * + * @param text 文本 + * @return 行列表 + */ + private static List toLines(String text) { + // -1 保留末尾空格 + return List.of(text.split("\\R", -1)); + } + + public static UIDiff getSegmentsForUI(String oldText, String newText, boolean ignoreWhitespace) { + return getSegmentsForUI(oldText, newText, ignoreWhitespace, false); + } + + public static UIDiff getSegmentsForUI(String oldText, String newText, boolean ignoreWhitespace, boolean charOnly) { + List oldLines = toLines(oldText); + List newLines = toLines(newText); + Patch patch = DiffUtils.diff(oldLines, newLines); + + // 计算每一行的起始字符偏移(含换行) + int[] leftLineStarts = computeLineStartOffsets(oldText); + int[] rightLineStarts = computeLineStartOffsets(newText); + + List textDiffSegments = new ArrayList<>(); + + for (AbstractDelta delta : patch.getDeltas()) { + int leftPos = delta.getSource().getPosition(); + int rightPos = delta.getTarget().getPosition(); + List leftLines = delta.getSource().getLines(); + List rightLines = delta.getTarget().getLines(); + DeltaType type = delta.getType(); + + switch (type) { + case DELETE: { + if (charOnly) { + // 仅字符模式:整行删除不计入字符级差异 + break; + } + for (int i = 0; i < leftLines.size(); i++) { + int lineIdx = leftPos + i; + int start = safeLineStart(leftLineStarts, lineIdx); + int end = start + leftLines.get(i).length(); + if (!(ignoreWhitespace && isAllWhitespace(leftLines.get(i)))) + textDiffSegments.add(new TextDiffSegment(DiffTypeEnum.DELETE, start, end, -1, -1)); + } + break; + } + case INSERT: { + if (charOnly) { + // 仅字符模式:整行插入不计入字符级差异 + break; + } + for (int i = 0; i < rightLines.size(); i++) { + int lineIdx = rightPos + i; + int start = safeLineStart(rightLineStarts, lineIdx); + int end = start + rightLines.get(i).length(); + if (!(ignoreWhitespace && isAllWhitespace(rightLines.get(i)))) + textDiffSegments.add(new TextDiffSegment(DiffTypeEnum.INSERT, -1, -1, start, end)); + } + break; + } + case CHANGE: { + int pairCount = Math.min(leftLines.size(), rightLines.size()); + // 对应行做字符级 diff + for (int i = 0; i < pairCount; i++) { + String a = leftLines.get(i); + String b = rightLines.get(i); + int aLineStart = safeLineStart(leftLineStarts, leftPos + i); + int bLineStart = safeLineStart(rightLineStarts, rightPos + i); + // 使用 DiffUtils 在字符层面做 diff + List ac = toChars(a); + List bc = toChars(b); + Patch charPatch = DiffUtils.diff(ac, bc); + for (AbstractDelta cDelta : charPatch.getDeltas()) { + int aStart = aLineStart + cDelta.getSource().getPosition(); + int aEnd = aStart + cDelta.getSource().getLines().size(); + int bStart = bLineStart + cDelta.getTarget().getPosition(); + int bEnd = bStart + cDelta.getTarget().getLines().size(); + if (cDelta.getType() == DeltaType.DELETE) { + if (!(ignoreWhitespace && isAllWhitespace(a.substring( + Math.min(a.length(), Math.max(0, cDelta.getSource().getPosition())), + Math.min(a.length(), Math.max(0, cDelta.getSource().getPosition() + cDelta.getSource().getLines().size())) + )))) { + textDiffSegments.add(new TextDiffSegment(DiffTypeEnum.DELETE, aStart, aEnd, -1, -1)); + } + } else if (cDelta.getType() == DeltaType.INSERT) { + if (!(ignoreWhitespace && isAllWhitespace(b.substring( + Math.min(b.length(), Math.max(0, cDelta.getTarget().getPosition())), + Math.min(b.length(), Math.max(0, cDelta.getTarget().getPosition() + cDelta.getTarget().getLines().size())) + )))) { + textDiffSegments.add(new TextDiffSegment(DiffTypeEnum.INSERT, -1, -1, bStart, bEnd)); + } + } else { // CHANGE + String aSub = a.substring( + Math.min(a.length(), Math.max(0, cDelta.getSource().getPosition())), + Math.min(a.length(), Math.max(0, cDelta.getSource().getPosition() + cDelta.getSource().getLines().size()))); + String bSub = b.substring( + Math.min(b.length(), Math.max(0, cDelta.getTarget().getPosition())), + Math.min(b.length(), Math.max(0, cDelta.getTarget().getPosition() + cDelta.getTarget().getLines().size()))); + if (!(ignoreWhitespace && equalsIgnoreWhitespace(aSub, bSub))) { + textDiffSegments.add(new TextDiffSegment(DiffTypeEnum.CHANGE, aStart, aEnd, bStart, bEnd)); + } + } + } + } + if (!charOnly) { + // 左侧多余:视为整行删除 + for (int i = pairCount; i < leftLines.size(); i++) { + int aLineStart = safeLineStart(leftLineStarts, leftPos + i); + if (!(ignoreWhitespace && isAllWhitespace(leftLines.get(i)))) + textDiffSegments.add(new TextDiffSegment(DiffTypeEnum.DELETE, aLineStart, aLineStart + leftLines.get(i).length(), -1, -1)); + } + // 右侧多余:视为整行插入 + for (int i = pairCount; i < rightLines.size(); i++) { + int bLineStart = safeLineStart(rightLineStarts, rightPos + i); + if (!(ignoreWhitespace && isAllWhitespace(rightLines.get(i)))) + textDiffSegments.add(new TextDiffSegment(DiffTypeEnum.INSERT, -1, -1, bLineStart, bLineStart + rightLines.get(i).length())); + } + } + break; + } + case EQUAL: + // 不产生片段 + break; + } + } + + return new UIDiff(textDiffSegments); + } + + private static int[] computeLineStartOffsets(String text) { + int n = 1; // 至少一行 + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (c == '\n') n++; + } + int[] starts = new int[n]; + int idx = 0; + starts[idx++] = 0; + for (int i = 0; i < text.length(); i++) { + if (text.charAt(i) == '\n') { + if (idx < n) starts[idx++] = i + 1; + } + } + return starts; + } + + private static int safeLineStart(int[] starts, int lineIndex) { + if (lineIndex < 0) { + return 0; + } + if (lineIndex >= starts.length) { + return (starts.length == 0 ? 0 : starts[starts.length - 1]); + } + return starts[lineIndex]; + } + + public static List toChars(String s) { + List list = new ArrayList<>(s.length()); + for (int i = 0; i < s.length(); i++) { + list.add(String.valueOf(s.charAt(i))); + } + return list; + } + + public static boolean isAllWhitespace(String s) { + for (int i = 0; i < s.length(); i++) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } + + public static boolean equalsIgnoreWhitespace(String a, String b) { + int i = 0, j = 0; + while (i < a.length() && j < b.length()) { + char ca = a.charAt(i); + char cb = b.charAt(j); + if (Character.isWhitespace(ca)) { + i++; + continue; + } + if (Character.isWhitespace(cb)) { + j++; + continue; + } + if (ca != cb) return false; + i++; + j++; + } + while (i < a.length()) { + if (!Character.isWhitespace(a.charAt(i++))) return false; + } + while (j < b.length()) { + if (!Character.isWhitespace(b.charAt(j++))) return false; + } + return true; + } + + /** + * 构建统一差异视图(包含文本与高亮区间) + */ + public static UnifiedView buildUnifiedView(String oldText, String newText, int context, boolean ignoreWhitespace) { + List oldLines = toLines(oldText); + List newLines = toLines(newText); + Patch patch = DiffUtils.diff(oldLines, newLines); + List unifiedLines = UnifiedDiffUtils.generateUnifiedDiff("old", "new", oldLines, patch, context); + + String unifiedText = String.join("\n", unifiedLines); + List lineSpans = new ArrayList<>(); + List charSpans = new ArrayList<>(); + int charEvents = 0; + + int offset = 0; + List minusStarts = new ArrayList<>(); + List minusTexts = new ArrayList<>(); + List plusStarts = new ArrayList<>(); + List plusTexts = new ArrayList<>(); + + for (int i = 0; i < unifiedLines.size(); i++) { + String line = unifiedLines.get(i); + int lineStart = offset; + int lineLen = line.length(); + int lineEnd = lineStart + lineLen; + + if (line.startsWith("@@")) { + lineSpans.add(new Span(lineStart, lineEnd, UnifiedSpanTypeEnum.HUNK_LINE)); + charEvents += addIntralineSpans(minusStarts, minusTexts, plusStarts, plusTexts, charSpans, ignoreWhitespace); + minusStarts.clear(); + minusTexts.clear(); + plusStarts.clear(); + plusTexts.clear(); + } else if (line.startsWith("+")) { + if (!(ignoreWhitespace && isAllWhitespace(line.substring(1)))) { + lineSpans.add(new Span(lineStart, lineEnd, UnifiedSpanTypeEnum.ADD_LINE)); + } + plusStarts.add(lineStart); + plusTexts.add(line.substring(1)); + } else if (line.startsWith("-")) { + if (!(ignoreWhitespace && isAllWhitespace(line.substring(1)))) { + lineSpans.add(new Span(lineStart, lineEnd, UnifiedSpanTypeEnum.DEL_LINE)); + } + minusStarts.add(lineStart); + minusTexts.add(line.substring(1)); + } else if (line.startsWith("---") || line.startsWith("+++")) { + lineSpans.add(new Span(lineStart, lineEnd, UnifiedSpanTypeEnum.HEADER_LINE)); + } + + offset = (i < unifiedLines.size() - 1) ? (lineEnd + 1) : lineEnd; + } + + charEvents += addIntralineSpans(minusStarts, minusTexts, plusStarts, plusTexts, charSpans, ignoreWhitespace); + + return new UnifiedView(unifiedText, lineSpans, charSpans, charEvents); + } + + private static int addIntralineSpans(List minusStarts, List minusTexts, + List plusStarts, List plusTexts, + List out, boolean ignoreWhitespace) { + int events = 0; + int pairs = Math.min(minusTexts.size(), plusTexts.size()); + for (int i = 0; i < pairs; i++) { + String a = minusTexts.get(i); + String b = plusTexts.get(i); + int aBase = minusStarts.get(i) + 1; // 跳过前缀符号 + int bBase = plusStarts.get(i) + 1; + Patch charPatch = DiffUtils.diff(toChars(a), toChars(b)); + for (AbstractDelta d : charPatch.getDeltas()) { + int aStart = aBase + d.getSource().getPosition(); + int aEnd = aStart + d.getSource().getLines().size(); + int bStart = bBase + d.getTarget().getPosition(); + int bEnd = bStart + d.getTarget().getLines().size(); + switch (d.getType()) { + case DELETE: + if (ignoreWhitespace && isAllWhitespace(safeSub(a, d.getSource().getPosition(), d.getSource().getLines().size()))) + continue; + out.add(new Span(aStart, aEnd, UnifiedSpanTypeEnum.DEL_CHAR)); + events++; + break; + case INSERT: + if (ignoreWhitespace && isAllWhitespace(safeSub(b, d.getTarget().getPosition(), d.getTarget().getLines().size()))) + continue; + out.add(new Span(bStart, bEnd, UnifiedSpanTypeEnum.ADD_CHAR)); + events++; + break; + case CHANGE: + String aSub = safeSub(a, d.getSource().getPosition(), d.getSource().getLines().size()); + String bSub = safeSub(b, d.getTarget().getPosition(), d.getTarget().getLines().size()); + if (ignoreWhitespace && equalsIgnoreWhitespace(aSub, bSub)) continue; + if (!aSub.isEmpty()) out.add(new Span(aStart, aEnd, UnifiedSpanTypeEnum.CHANGE_CHAR)); + if (!bSub.isEmpty()) out.add(new Span(bStart, bEnd, UnifiedSpanTypeEnum.CHANGE_CHAR)); + events++; + break; + case EQUAL: + break; + } + } + } + return events; + } + + private static String safeSub(String s, int pos, int len) { + int start = Math.max(0, Math.min(pos, s.length())); + int end = Math.max(0, Math.min(pos + len, s.length())); + if (end < start) { + end = start; + } + return s.substring(start, end); + } + +} diff --git a/src/main/java/com/luoboduner/moo/tool/ui/FuncConsts.java b/src/main/java/com/luoboduner/moo/tool/ui/FuncConsts.java index 4a4ea98d..bb334281 100644 --- a/src/main/java/com/luoboduner/moo/tool/ui/FuncConsts.java +++ b/src/main/java/com/luoboduner/moo/tool/ui/FuncConsts.java @@ -26,4 +26,9 @@ public class FuncConsts { * 二维码 */ public static final String QR_CODE = "QrCode"; + + /** + * 文本对比 + */ + public static final String TEXT_DIFF = "TextDiff"; } diff --git a/src/main/java/com/luoboduner/moo/tool/ui/Init.java b/src/main/java/com/luoboduner/moo/tool/ui/Init.java index 5632d6bf..9b049501 100644 --- a/src/main/java/com/luoboduner/moo/tool/ui/Init.java +++ b/src/main/java/com/luoboduner/moo/tool/ui/Init.java @@ -214,6 +214,7 @@ public class Init { ThreadUtil.execute(ImageForm::init); ThreadUtil.execute(VariablesForm::init); ThreadUtil.execute(YmlPropertiesForm::init); + ThreadUtil.execute(TextDiffForm::init); ThreadUtil.execute(FileReformattingForm::init); // 检查新版版 diff --git a/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.form b/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.form index 5c157982..dfba9cf1 100644 --- a/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.form +++ b/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.form @@ -210,6 +210,15 @@ + + + + + + + + + diff --git a/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.java b/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.java index f580fb0f..4067fbae 100644 --- a/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.java +++ b/src/main/java/com/luoboduner/moo/tool/ui/form/MainWindow.java @@ -47,11 +47,12 @@ public class MainWindow { private JPanel pdfPanel; private JPanel variablesPanel; private JPanel ymlProperties; + private JPanel textDiffPanel; private JPanel aboutPanel; private static MainWindow mainWindow; - private static final String[] ICON_PATH = {"icon/smile.svg", "icon/edit.svg", "icon/time.svg", "icon/json.svg", "icon/translate.svg", "icon/check.svg", "icon/global.svg", "icon/exchange.svg", "icon/QRcode.svg", "icon/method.svg", "icon/calculate.svg", "icon/network.svg", "icon/color.svg", "icon/image.svg", "icon/schedule.svg", "icon/reg.svg", "icon/java.svg", "icon/format_painter.svg", "icon/pdf.svg", "icon/fx.svg", "icon/suffix-yml.svg"}; + private static final String[] ICON_PATH = {"icon/smile.svg", "icon/edit.svg", "icon/time.svg", "icon/json.svg", "icon/translate.svg", "icon/check.svg", "icon/global.svg", "icon/exchange.svg", "icon/QRcode.svg", "icon/method.svg", "icon/calculate.svg", "icon/network.svg", "icon/color.svg", "icon/image.svg", "icon/schedule.svg", "icon/reg.svg", "icon/java.svg", "icon/format_painter.svg", "icon/pdf.svg", "icon/fx.svg", "icon/suffix-yml.svg", "icon/find.svg"}; private MainWindow() { } @@ -96,6 +97,7 @@ public class MainWindow { mainWindow.getPdfPanel().add(PdfForm.getInstance().getPdfPanel(), gridConstraints); mainWindow.getVariablesPanel().add(VariablesForm.getInstance().getVariablesPanel(), gridConstraints); mainWindow.getYmlProperties().add(YmlPropertiesForm.getInstance().getYmlPropertiesPanel(), gridConstraints); + mainWindow.getTextDiffPanel().add(TextDiffForm.getInstance().getTextDiffPanel(), gridConstraints); mainWindow.getMainPanel().updateUI(); TabListener.addListeners(); @@ -285,6 +287,9 @@ public class MainWindow { ymlProperties = new JPanel(); ymlProperties.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); tabbedPane.addTab("配置文件转换", ymlProperties); + textDiffPanel = new JPanel(); + textDiffPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + tabbedPane.addTab("文本差异比对", textDiffPanel); } /** diff --git a/src/main/java/com/luoboduner/moo/tool/ui/form/func/TextDiffForm.java b/src/main/java/com/luoboduner/moo/tool/ui/form/func/TextDiffForm.java new file mode 100644 index 00000000..8f007578 --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/ui/form/func/TextDiffForm.java @@ -0,0 +1,966 @@ +package com.luoboduner.moo.tool.ui.form.func; + +import cn.hutool.log.Log; +import cn.hutool.log.LogFactory; +import com.formdev.flatlaf.extras.FlatSVGIcon; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.luoboduner.moo.tool.bean.textdiff.UIDiff; +import com.luoboduner.moo.tool.bean.textdiff.UnifiedView; +import com.luoboduner.moo.tool.dao.TFuncContentMapper; +import com.luoboduner.moo.tool.domain.TFuncContent; +import com.luoboduner.moo.tool.service.DiffService; +import com.luoboduner.moo.tool.ui.FuncConsts; +import com.luoboduner.moo.tool.ui.listener.func.TextDiffListener; +import com.luoboduner.moo.tool.util.MybatisUtil; +import com.luoboduner.moo.tool.util.ScrollUtil; +import com.luoboduner.moo.tool.util.SqliteUtil; +import com.luoboduner.moo.tool.util.UndoUtil; +import lombok.Getter; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.fife.ui.rtextarea.RTextScrollPane; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.border.TitledBorder; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Highlighter; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.Toolkit; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + *
+ * TextDiffForm - 文本对比功能界面
+ * 
+ * + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 10:51 + */ +@Getter +public class TextDiffForm { + private JPanel textDiffPanel; + private JPanel leftPanel; + private JPanel rightPanel; + private JPanel toolBarPanel; + private JButton compareButton; + private JButton clearButton; + private JButton swapButton; + private JButton copyDiffButton; + private JButton prevDiffButton; + private JButton nextDiffButton; + private JComboBox highlightModeComboBox; + private JLabel statusLabel; + private JCheckBox realTimeCheckBox; + private JCheckBox ignoreWhitespaceCheckBox; + private JComboBox displayModeComboBox; + private JSplitPane mainSplitPane; + private JScrollPane leftScrollPane; + private JScrollPane rightScrollPane; + private JScrollPane unifiedScrollPane; + private JPanel unifiedPanel; + + private RSyntaxTextArea leftTextArea; + private RSyntaxTextArea rightTextArea; + private RSyntaxTextArea unifiedTextArea; + + // Diff highlight painters + private final DefaultHighlighter.DefaultHighlightPainter delPainter = + new DefaultHighlighter.DefaultHighlightPainter(new Color(255, 204, 204)); // light red for deletions + private final DefaultHighlighter.DefaultHighlightPainter insPainter = + new DefaultHighlighter.DefaultHighlightPainter(new Color(204, 255, 204)); // light green for insertions + private final DefaultHighlighter.DefaultHighlightPainter changePainter = + new DefaultHighlighter.DefaultHighlightPainter(new Color(255, 249, 196)); // light yellow for modifications + + // 滚动同步状态标记,避免循环触发 + private boolean syncingScroll = false; + + // 行级高亮(带透明度) + private final DefaultHighlighter.DefaultHighlightPainter delLinePainter = + new DefaultHighlighter.DefaultHighlightPainter(new Color(255, 102, 102, 60)); + private final DefaultHighlighter.DefaultHighlightPainter insLinePainter = + new DefaultHighlighter.DefaultHighlightPainter(new Color(0, 153, 0, 60)); + private final DefaultHighlighter.DefaultHighlightPainter changeLinePainter = + new DefaultHighlighter.DefaultHighlightPainter(new Color(255, 193, 7, 60)); + + // 统一视图:hunk 或标题行高亮 + private final DefaultHighlighter.DefaultHighlightPainter headerLinePainter = + new DefaultHighlighter.DefaultHighlightPainter(new Color(230, 230, 230)); + + // 差异导航锚点与索引(按左/右侧段的中点行) + private final List leftNavOffsets = new ArrayList<>(); + private final List rightNavOffsets = new ArrayList<>(); + private int navIndex = -1; + + private enum HighlightMode { CHAR_ONLY, LINE_ONLY, BOTH } + private HighlightMode highlightMode = HighlightMode.BOTH; + + private static TextDiffForm textDiffForm; + + private static final Log logger = LogFactory.get(); + + private static final TFuncContentMapper funcContentMapper = MybatisUtil.getSqlSession().getMapper(TFuncContentMapper.class); + + private TextDiffForm() { + UndoUtil.register(this); + initTextAreas(); + } + + public static TextDiffForm getInstance() { + if (textDiffForm == null) { + textDiffForm = new TextDiffForm(); + } + return textDiffForm; + } + + public static void init() { + textDiffForm = getInstance(); + textDiffForm.initForm(); + } + + /** + * 初始化文本区域 + */ + private void initTextAreas() { + // 左侧文本区域 + leftTextArea = new RSyntaxTextArea(); + leftTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE); + leftTextArea.setCodeFoldingEnabled(true); + leftTextArea.setAntiAliasingEnabled(true); + leftTextArea.setAutoIndentEnabled(true); + leftTextArea.setMarkOccurrences(true); + leftTextArea.setPaintMarkOccurrencesBorder(true); + leftTextArea.setTabSize(4); + leftTextArea.setCaretPosition(0); + + // 右侧文本区域 + rightTextArea = new RSyntaxTextArea(); + rightTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE); + rightTextArea.setCodeFoldingEnabled(true); + rightTextArea.setAntiAliasingEnabled(true); + rightTextArea.setAutoIndentEnabled(true); + rightTextArea.setMarkOccurrences(true); + rightTextArea.setPaintMarkOccurrencesBorder(true); + rightTextArea.setTabSize(4); + rightTextArea.setCaretPosition(0); + + // 统一diff显示区域 + unifiedTextArea = new RSyntaxTextArea(); + unifiedTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); + unifiedTextArea.setCodeFoldingEnabled(true); + unifiedTextArea.setAntiAliasingEnabled(true); + unifiedTextArea.setEditable(false); + unifiedTextArea.setTabSize(4); + unifiedTextArea.setCaretPosition(0); + + // 创建滚动面板 + leftScrollPane = new RTextScrollPane(leftTextArea); + rightScrollPane = new RTextScrollPane(rightTextArea); + unifiedScrollPane = new RTextScrollPane(unifiedTextArea); + + ScrollUtil.smoothPane(leftScrollPane); + ScrollUtil.smoothPane(rightScrollPane); + ScrollUtil.smoothPane(unifiedScrollPane); + + // 同步左右滚动(便于并排对比时直观比照) + setupScrollSync(); + + // 将滚动面板添加到相应的面板中 + if (leftPanel != null) { + leftPanel.add( + leftScrollPane, + new GridConstraints( + 0, + 0, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_BOTH, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + null, + null, + null, + 0, + false + ) + ); + } + if (rightPanel != null) { + rightPanel.add( + rightScrollPane, + new GridConstraints( + 0, + 0, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_BOTH, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + null, + null, + null, + 0, + false + ) + ); + } + if (unifiedPanel != null) { + unifiedPanel.add(unifiedScrollPane, + new GridConstraints(0, + 0, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_BOTH, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + null, + null, + null, + 0, + false + ) + ); + } + } + + /** + * 左右窗口竖向滚动同步 + */ + private void setupScrollSync() { + if (!(leftScrollPane instanceof RTextScrollPane) || !(rightScrollPane instanceof RTextScrollPane)) { + return; + } + // 获取滚动条 + JScrollBar leftBar = leftScrollPane.getVerticalScrollBar(); + JScrollBar rightBar = rightScrollPane.getVerticalScrollBar(); + if (leftBar == null || rightBar == null) { + return; + } + + // 滚动条滚动时,同步滚动 + leftBar.addAdjustmentListener(e -> { + if (syncingScroll) return; + syncingScroll = true; + rightBar.setValue(e.getValue()); + syncingScroll = false; + }); + rightBar.addAdjustmentListener(e -> { + if (syncingScroll) return; + syncingScroll = true; + leftBar.setValue(e.getValue()); + syncingScroll = false; + }); + } + + /** + * 初始化 + */ + public void initForm() { + TextDiffListener.addListeners(); + + // 设置默认显示模式 + displayModeComboBox.addItem("并排对比"); + displayModeComboBox.addItem("统一差异"); + displayModeComboBox.setSelectedIndex(0); + + // 高亮模式(默认仅字符,避免把相同部分也高亮) + highlightModeComboBox.addItem("双层高亮"); + highlightModeComboBox.addItem("仅字符"); + highlightModeComboBox.addItem("仅整行"); + highlightModeComboBox.setSelectedIndex(1); + highlightModeComboBox.addActionListener(e -> { + switch ((String) Objects.requireNonNull(highlightModeComboBox.getSelectedItem())) { + case "仅字符": + highlightMode = HighlightMode.CHAR_ONLY; break; + case "仅整行": + highlightMode = HighlightMode.LINE_ONLY; break; + default: + highlightMode = HighlightMode.BOTH; + } + if (realTimeCheckBox.isSelected()) { + performDiff(); + } + }); + + // 默认开启实时对比 + realTimeCheckBox.setSelected(true); + + // 初始化布局 + updateDisplayMode(); + + // 恢复上次的内容 + initContent(); + } + + /** + * 初始化内容 + */ + private void initContent() { + try { + TFuncContent tFuncContent = funcContentMapper.selectByFunc(FuncConsts.TEXT_DIFF + "_left"); + if (tFuncContent != null) { + leftTextArea.setText(tFuncContent.getContent()); + } + + tFuncContent = funcContentMapper.selectByFunc(FuncConsts.TEXT_DIFF + "_right"); + if (tFuncContent != null) { + rightTextArea.setText(tFuncContent.getContent()); + } + } catch (Exception e) { + logger.error("初始化文本对比内容失败", e); + } + } + + /** + * 保存内容 + */ + public void save() { + try { + saveLeftContent(); + saveRightContent(); + } catch (Exception e) { + logger.error("保存文本对比内容失败", e); + } + } + + /** + * 保存左侧内容 + */ + private void saveLeftContent() { + String text = leftTextArea.getText(); + String now = SqliteUtil.nowDateForSqlite(); + String funcKey = FuncConsts.TEXT_DIFF + "_left"; + + saveContent(text, now, funcKey); + } + + /** + * 保存内容 + * @param text 文本 + * @param now 时间 + * @param funcKey 函数 + */ + private void saveContent(String text, String now, String funcKey) { + TFuncContent tFuncContent = funcContentMapper.selectByFunc(funcKey); + if (tFuncContent == null) { + tFuncContent = new TFuncContent(); + tFuncContent.setFunc(funcKey); + tFuncContent.setContent(text); + tFuncContent.setCreateTime(now); + tFuncContent.setModifiedTime(now); + funcContentMapper.insert(tFuncContent); + } else { + tFuncContent.setContent(text); + tFuncContent.setModifiedTime(now); + funcContentMapper.updateByPrimaryKeySelective(tFuncContent); + } + } + + /** + * 保存右侧内容 + */ + private void saveRightContent() { + String text = rightTextArea.getText(); + String now = SqliteUtil.nowDateForSqlite(); + String funcKey = FuncConsts.TEXT_DIFF + "_right"; + + saveContent(text, now, funcKey); + } + + /** + * 更新显示模式 + */ + public void updateDisplayMode() { + String selectedMode = (String) displayModeComboBox.getSelectedItem(); + + if ("并排对比".equals(selectedMode)) { + // 显示并排对比模式 + mainSplitPane.setLeftComponent(leftScrollPane); + mainSplitPane.setRightComponent(rightScrollPane); + mainSplitPane.setDividerLocation(0.5); + unifiedPanel.setVisible(false); + } else { + // 显示统一差异模式 + mainSplitPane.setLeftComponent(leftScrollPane); + mainSplitPane.setRightComponent(rightScrollPane); + mainSplitPane.setDividerLocation(0.5); + unifiedPanel.setVisible(true); + } + + textDiffPanel.revalidate(); + textDiffPanel.repaint(); + } + + /** + * 执行文本对比 + */ + public void performDiff() { + String leftText = leftTextArea.getText(); + String rightText = rightTextArea.getText(); + + if (leftText.isEmpty() && rightText.isEmpty()) { + statusLabel.setText("请输入要对比的文本"); + return; + } + + try { + // 统一差异视图(文本 + 高亮区间) + boolean ignoreWs = ignoreWhitespaceCheckBox != null && ignoreWhitespaceCheckBox.isSelected(); + var unifiedView = DiffService.buildUnifiedView(leftText, rightText, 3, ignoreWs); + unifiedTextArea.setText(unifiedView.text()); + + // 获取用于UI高亮的差异信息(基于字符区间) + boolean charOnlyNav = (highlightMode == HighlightMode.CHAR_ONLY); + var diffResult = DiffService.getSegmentsForUI(leftText, rightText, ignoreWs, charOnlyNav); + + // 构建导航锚点:每个差异段恰好追加一项(左/右没有则为 -1) + leftNavOffsets.clear(); + rightNavOffsets.clear(); + navIndex = -1; + if (diffResult.segments() != null) { + for (var seg : diffResult.segments()) { + int lMid = (seg.leftStart() >= 0 && seg.leftEnd() >= 0) + ? (seg.leftStart() + seg.leftEnd()) / 2 : -1; + int rMid = (seg.rightStart() >= 0 && seg.rightEnd() >= 0) + ? (seg.rightStart() + seg.rightEnd()) / 2 : -1; + leftNavOffsets.add(lMid); + rightNavOffsets.add(rMid); + } + } + + // 左右并排的字符/行高亮 + applyDiffHighlight(diffResult); + // 统一差异视图的行级/字符级高亮 + applyUnifiedSpans(unifiedView); + + // 更新状态:与可跳转点一致 + int changes = (diffResult.segments() != null) ? diffResult.segments().size() : 0; + if (highlightMode == HighlightMode.CHAR_ONLY) { + statusLabel.setText("字符差异 " + changes + " 处"); + } else { + statusLabel.setText("对比完成,共发现 " + changes + " 处差异"); + } + + } catch (Exception e) { + logger.error("执行文本对比失败", e); + statusLabel.setText("对比失败:" + e.getMessage()); + } + } + + /** + * 清除两侧与统一视图上的所有高亮 + */ + private void clearHighlights() { + if (leftTextArea != null && leftTextArea.getHighlighter() != null) { + leftTextArea.getHighlighter().removeAllHighlights(); + } + if (rightTextArea != null && rightTextArea.getHighlighter() != null) { + rightTextArea.getHighlighter().removeAllHighlights(); + } + if (unifiedTextArea != null && unifiedTextArea.getHighlighter() != null) { + unifiedTextArea.getHighlighter().removeAllHighlights(); + } + } + + /** + * 应用差异高亮显示 + */ + private void applyDiffHighlight(UIDiff diffResult) { + clearHighlights(); + if (diffResult == null || diffResult.segments() == null) { + return; + } + + // 删除、插入、修改 + for (var seg : diffResult.segments()) { + switch (seg.type()) { + case DELETE: { + if (highlightMode != HighlightMode.LINE_ONLY && seg.leftStart() >= 0 && seg.leftEnd() >= 0) + safeAddHighlight(leftTextArea, seg.leftStart(), seg.leftEnd(), delPainter); + if (highlightMode != HighlightMode.CHAR_ONLY && seg.leftStart() >= 0 && seg.leftEnd() >= 0) + safeAddLineHighlights(leftTextArea, seg.leftStart(), seg.leftEnd(), delLinePainter); + break; + } + case INSERT: { + if (highlightMode != HighlightMode.LINE_ONLY && seg.rightStart() >= 0 && seg.rightEnd() >= 0) + safeAddHighlight(rightTextArea, seg.rightStart(), seg.rightEnd(), insPainter); + if (highlightMode != HighlightMode.CHAR_ONLY && seg.rightStart() >= 0 && seg.rightEnd() >= 0) + safeAddLineHighlights(rightTextArea, seg.rightStart(), seg.rightEnd(), insLinePainter); + break; + } + case CHANGE: { + if (highlightMode != HighlightMode.LINE_ONLY) { + if (seg.leftStart() >= 0 && seg.leftEnd() >= 0) + safeAddHighlight(leftTextArea, seg.leftStart(), seg.leftEnd(), changePainter); + if (seg.rightStart() >= 0 && seg.rightEnd() >= 0) + safeAddHighlight(rightTextArea, seg.rightStart(), seg.rightEnd(), changePainter); + } + if (highlightMode != HighlightMode.CHAR_ONLY) { + if (seg.leftStart() >= 0 && seg.leftEnd() >= 0) + safeAddLineHighlights(leftTextArea, seg.leftStart(), seg.leftEnd(), changeLinePainter); + if (seg.rightStart() >= 0 && seg.rightEnd() >= 0) + safeAddLineHighlights(rightTextArea, seg.rightStart(), seg.rightEnd(), changeLinePainter); + } + break; + } + default: + break; + } + } + } + + /** + * 在给定 TextArea 上安全添加高亮(自动裁剪区间并捕获异常) + */ + private void safeAddHighlight(RSyntaxTextArea ta, int start, int end, Highlighter.HighlightPainter painter) { + if (ta == null || painter == null) { + return; + } + try { + int docLen = ta.getDocument().getLength(); + int s = Math.max(0, Math.min(start, docLen)); + int e = Math.max(0, Math.min(end, docLen)); + if (e > s) { + ta.getHighlighter().addHighlight(s, e, painter); + } + } catch (BadLocationException ex) { + logger.warn("添加高亮失败: {}", ex.getMessage()); + } + } + + /** + * 以行为单位添加高亮:把 [start, end) 覆盖到完整的行区间并逐行高亮 + */ + private void safeAddLineHighlights(RSyntaxTextArea ta, int start, int end, Highlighter.HighlightPainter painter) { + if (ta == null || painter == null) return; + try { + int docLen = ta.getDocument().getLength(); + int s = Math.max(0, Math.min(start, docLen)); + int e = Math.max(0, Math.min(end, docLen)); + if (e <= s) return; + + int startLine = ta.getLineOfOffset(s); + int endLine = ta.getLineOfOffset(Math.max(s, e - 1)); + for (int line = startLine; line <= endLine; line++) { + int ls = ta.getLineStartOffset(line); + int le = ta.getLineEndOffset(line); + // 为整行添加一层半透明底色,便于两侧比照 + ta.getHighlighter().addHighlight(ls, le, painter); + } + } catch (BadLocationException ex) { + logger.warn("添加行级高亮失败: {}", ex.getMessage()); + } + } + + private void gotoDiff(int index) { + if (leftNavOffsets.isEmpty() && rightNavOffsets.isEmpty()) { + return; + } + int max = Math.max(leftNavOffsets.size(), rightNavOffsets.size()); + navIndex = ((index % max) + max) % max; // 环绕 + int lOff = (navIndex < leftNavOffsets.size()) ? leftNavOffsets.get(navIndex) : -1; + int rOff = (navIndex < rightNavOffsets.size()) ? rightNavOffsets.get(navIndex) : -1; + if (lOff >= 0) { + centerOnOffset(leftTextArea, lOff); + } + if (rOff >= 0) { + centerOnOffset(rightTextArea, rOff); + } + statusLabel.setText("跳至第 " + (navIndex + 1) + "/" + max + " 处差异"); + } + + private void centerOnOffset(RSyntaxTextArea ta, int offset) { + try { + int line = ta.getLineOfOffset(Math.max(0, Math.min(offset, ta.getDocument().getLength()))); + int start = ta.getLineStartOffset(line); + ta.setCaretPosition(start); + ta.requestFocusInWindow(); + } catch (BadLocationException ignore) { } + } + + private void gotoNextDiff() { gotoDiff(navIndex + 1); } + private void gotoPrevDiff() { gotoDiff(navIndex - 1); } + + /** + * 统一差异视图高亮: + * - 行级:+ 绿色, - 红色, @@ hunk 行黄色, 文件头灰色 + * - 字符级:对同一 hunk 中的 +/- 行按序配对做字符级 diff,仅高亮变更范围 + * 渲染统一差异视图的高亮(使用服务层返回的区间) + */ + private void applyUnifiedSpans(UnifiedView view) { + if (view == null) return; + // 行级底色 + if (view.lineSpans() != null) { + for (var sp : view.lineSpans()) { + switch (sp.type()) { + case ADD_LINE -> safeAddLineHighlights(unifiedTextArea, sp.start(), sp.end(), insLinePainter); + case DEL_LINE -> safeAddLineHighlights(unifiedTextArea, sp.start(), sp.end(), delLinePainter); + case HUNK_LINE -> safeAddLineHighlights(unifiedTextArea, sp.start(), sp.end(), changeLinePainter); + case HEADER_LINE -> safeAddLineHighlights(unifiedTextArea, sp.start(), sp.end(), headerLinePainter); + default -> {} + } + } + } + // 字符级高亮 + if (view.charSpans() != null && highlightMode != HighlightMode.LINE_ONLY) { + for (var sp : view.charSpans()) { + switch (sp.type()) { + case ADD_CHAR -> safeAddHighlight(unifiedTextArea, sp.start(), sp.end(), insPainter); + case DEL_CHAR -> safeAddHighlight(unifiedTextArea, sp.start(), sp.end(), delPainter); + case CHANGE_CHAR -> safeAddHighlight(unifiedTextArea, sp.start(), sp.end(), changePainter); + default -> {} + } + } + } + } + + /** + * 清空所有文本 + */ + public void clearAll() { + clearHighlights(); + leftTextArea.setText(""); + rightTextArea.setText(""); + unifiedTextArea.setText(""); + statusLabel.setText("已清空"); + } + + /** + * 交换左右文本 + */ + public void swapTexts() { + String leftText = leftTextArea.getText(); + String rightText = rightTextArea.getText(); + + leftTextArea.setText(rightText); + rightTextArea.setText(leftText); + + // 交换后也做一次对比,确保高亮与内容同步 + performDiff(); + + statusLabel.setText("已交换文本"); + } + + /** + * 复制差异结果 + */ + public void copyDiffResult() { + String diffText = unifiedTextArea.getText(); + if (!diffText.isEmpty()) { + Toolkit.getDefaultToolkit().getSystemClipboard() + .setContents(new java.awt.datatransfer.StringSelection(diffText), null); + statusLabel.setText("差异结果已复制到剪贴板"); + } else { + statusLabel.setText("没有差异结果可复制"); + } + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + prevDiffButton.addActionListener(e -> gotoPrevDiff()); + nextDiffButton.addActionListener(e -> gotoNextDiff()); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + textDiffPanel = new JPanel(); + textDiffPanel.setLayout(new GridLayoutManager(3, 1, new Insets(10, 10, 10, 10), -1, -1)); + + // 工具栏面板 + toolBarPanel = new JPanel(); + toolBarPanel.setLayout(new GridLayoutManager(1, 12, new Insets(0, 0, 10, 0), -1, -1)); + textDiffPanel.add(toolBarPanel, new GridConstraints(0, + 0, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_BOTH, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + compareButton = new JButton(); + compareButton.setText("对比"); + compareButton.setIcon(new FlatSVGIcon("icon/find.svg")); + toolBarPanel.add(compareButton, new GridConstraints(0, + 0, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + clearButton = new JButton(); + clearButton.setText("清空"); + clearButton.setIcon(new FlatSVGIcon("icon/remove.svg")); + toolBarPanel.add(clearButton, new GridConstraints(0, + 1, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + swapButton = new JButton(); + swapButton.setText("交换"); + swapButton.setIcon(new FlatSVGIcon("icon/exchange.svg")); + toolBarPanel.add(swapButton, new GridConstraints(0, + 2, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + copyDiffButton = new JButton(); + copyDiffButton.setText("复制差异"); + copyDiffButton.setIcon(new FlatSVGIcon("icon/copy.svg")); + toolBarPanel.add(copyDiffButton, new GridConstraints(0, + 3, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + prevDiffButton = new JButton(); + prevDiffButton.setText("上一处"); + toolBarPanel.add(prevDiffButton, new GridConstraints(0, + 4, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + nextDiffButton = new JButton(); + nextDiffButton.setText("下一处"); + toolBarPanel.add(nextDiffButton, + new GridConstraints(0, + 5, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + realTimeCheckBox = new JCheckBox(); + realTimeCheckBox.setText("实时对比"); + toolBarPanel.add(realTimeCheckBox, new GridConstraints(0, + 6, + 1, + 1, + GridConstraints.ANCHOR_WEST, + GridConstraints.FILL_NONE, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + ignoreWhitespaceCheckBox = new JCheckBox(); + ignoreWhitespaceCheckBox.setText("忽略空白"); + toolBarPanel.add(ignoreWhitespaceCheckBox, new GridConstraints(0, + 7, + 1, + 1, + GridConstraints.ANCHOR_WEST, + GridConstraints.FILL_NONE, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + highlightModeComboBox = new JComboBox<>(); + toolBarPanel.add(highlightModeComboBox, new GridConstraints(0, + 8, + 1, + 1, + GridConstraints.ANCHOR_WEST, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + displayModeComboBox = new JComboBox<>(); + toolBarPanel.add(displayModeComboBox, new GridConstraints(0, + 9, + 1, + 1, + GridConstraints.ANCHOR_WEST, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + final Spacer spacer1 = new Spacer(); + toolBarPanel.add(spacer1, new GridConstraints(0, + 10, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_HORIZONTAL, + GridConstraints.SIZEPOLICY_WANT_GROW, + 1, + null, + null, + null, + 0, + false)); + + statusLabel = new JLabel(); + statusLabel.setText("准备就绪"); + toolBarPanel.add(statusLabel, new GridConstraints(0, + 11, + 1, + 1, + GridConstraints.ANCHOR_WEST, + GridConstraints.FILL_NONE, + GridConstraints.SIZEPOLICY_FIXED, + GridConstraints.SIZEPOLICY_FIXED, + null, + null, + null, + 0, + false)); + + // 主分割面板 + mainSplitPane = new JSplitPane(); + mainSplitPane.setDividerLocation(400); + mainSplitPane.setResizeWeight(0.5); + textDiffPanel.add(mainSplitPane, new GridConstraints(1, + 0, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_BOTH, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + null, + new Dimension(200, 200), + null, + 0, + false)); + + // 左侧面板 + leftPanel = new JPanel(); + leftPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 5), -1, -1)); + leftPanel.setBorder(BorderFactory.createTitledBorder(null, "原文本", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + + // 右侧面板 + rightPanel = new JPanel(); + rightPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 5, 0, 0), -1, -1)); + rightPanel.setBorder(BorderFactory.createTitledBorder(null, "新文本", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + + // 设置分割面板的左右组件 + mainSplitPane.setLeftComponent(leftPanel); + mainSplitPane.setRightComponent(rightPanel); + + // 统一差异面板 + unifiedPanel = new JPanel(); + unifiedPanel.setLayout(new GridLayoutManager(1, 1, new Insets(10, 0, 0, 0), -1, -1)); + unifiedPanel.setBorder(BorderFactory.createTitledBorder(null, "统一差异格式", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + unifiedPanel.setVisible(false); + textDiffPanel.add(unifiedPanel, new GridConstraints(2, + 0, + 1, + 1, + GridConstraints.ANCHOR_CENTER, + GridConstraints.FILL_BOTH, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, + null, + new Dimension(-1, 200), + null, + 0, + false)); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return textDiffPanel; + } +} diff --git a/src/main/java/com/luoboduner/moo/tool/ui/listener/func/TextDiffListener.java b/src/main/java/com/luoboduner/moo/tool/ui/listener/func/TextDiffListener.java new file mode 100644 index 00000000..3bbc2cce --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/ui/listener/func/TextDiffListener.java @@ -0,0 +1,133 @@ +package com.luoboduner.moo.tool.ui.listener.func; + +import com.luoboduner.moo.tool.ui.form.func.TextDiffForm; +import lombok.extern.slf4j.Slf4j; + +import javax.swing.SwingUtilities; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +/** + *
+ * TextDiffListener - 文本对比功能事件监听器
+ * 
+ * + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 10:51 + */ +@Slf4j +public class TextDiffListener { + + /** + * 添加事件监听器 + */ + public static void addListeners() { + TextDiffForm textDiffForm = TextDiffForm.getInstance(); + + // 对比按钮事件 + textDiffForm.getCompareButton().addActionListener(e -> { + textDiffForm.performDiff(); + }); + + // 清空按钮事件 + textDiffForm.getClearButton().addActionListener(e -> { + textDiffForm.clearAll(); + }); + + // 交换按钮事件 + textDiffForm.getSwapButton().addActionListener(e -> { + textDiffForm.swapTexts(); + }); + + // 复制差异按钮事件 + textDiffForm.getCopyDiffButton().addActionListener(e -> { + textDiffForm.copyDiffResult(); + }); + + // 显示模式切换事件 + textDiffForm.getDisplayModeComboBox().addActionListener(e -> { + textDiffForm.updateDisplayMode(); + // 如果当前有内容,重新执行对比 + if (!textDiffForm.getLeftTextArea().getText().isEmpty() || + !textDiffForm.getRightTextArea().getText().isEmpty()) { + textDiffForm.performDiff(); + } + }); + + // 实时对比复选框事件 + textDiffForm.getRealTimeCheckBox().addActionListener(e -> { + if (textDiffForm.getRealTimeCheckBox().isSelected()) { + // 开启实时对比时立即执行一次对比 + textDiffForm.performDiff(); + } + }); + + // 忽略空白差异复选框事件:切换时立即重算 + textDiffForm.getIgnoreWhitespaceCheckBox().addActionListener(e -> { + textDiffForm.performDiff(); + }); + + // 文本变化监听器 - 实时对比 + DocumentListener realTimeDocumentListener = new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + if (textDiffForm.getRealTimeCheckBox().isSelected()) { + // 延迟执行,避免频繁对比 + javax.swing.SwingUtilities.invokeLater(textDiffForm::performDiff); + } + } + + @Override + public void removeUpdate(DocumentEvent e) { + if (textDiffForm.getRealTimeCheckBox().isSelected()) { + javax.swing.SwingUtilities.invokeLater(textDiffForm::performDiff); + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + if (textDiffForm.getRealTimeCheckBox().isSelected()) { + javax.swing.SwingUtilities.invokeLater(textDiffForm::performDiff); + } + } + }; + + // 为左右文本区域添加文档监听器 + textDiffForm.getLeftTextArea().getDocument().addDocumentListener(realTimeDocumentListener); + textDiffForm.getRightTextArea().getDocument().addDocumentListener(realTimeDocumentListener); + + // 内容保存监听器 + DocumentListener saveDocumentListener = new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + saveContent(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + saveContent(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + saveContent(); + } + + private void saveContent() { + // 延迟保存,避免频繁IO操作 + SwingUtilities.invokeLater(() -> { + try { + textDiffForm.save(); + } catch (Exception ex) { + log.error("保存文本对比内容失败", ex); + } + }); + } + }; + + // 为左右文本区域添加保存监听器 + textDiffForm.getLeftTextArea().getDocument().addDocumentListener(saveDocumentListener); + textDiffForm.getRightTextArea().getDocument().addDocumentListener(saveDocumentListener); + } +} diff --git a/src/main/resources/db_init.sql b/src/main/resources/db_init.sql index 00faacf1..ddead61e 100644 --- a/src/main/resources/db_init.sql +++ b/src/main/resources/db_init.sql @@ -111,4 +111,30 @@ create table if not exists t_func_content remark text, create_time datetime, modified_time datetime +); + +-- text diff +-- 文档主表 +CREATE TABLE IF NOT EXISTS doc ( + doc_id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE +); + +-- 版本表 +CREATE TABLE IF NOT EXISTS doc_revision ( + rev_id INTEGER PRIMARY KEY AUTOINCREMENT, + doc_id INTEGER NOT NULL, + created_at DATETIME NOT NULL DEFAULT (datetime('now')), + content TEXT NOT NULL, + FOREIGN KEY (doc_id) REFERENCES doc(doc_id) +); + +-- 缓存行级 unified diff(从前一版本到本版本) +CREATE TABLE IF NOT EXISTS doc_diff_cache ( + from_rev_id INTEGER NOT NULL, + to_rev_id INTEGER NOT NULL, + unified TEXT NOT NULL, + PRIMARY KEY (from_rev_id, to_rev_id), + FOREIGN KEY (from_rev_id) REFERENCES doc_revision(rev_id), + FOREIGN KEY (to_rev_id) REFERENCES doc_revision(rev_id) ); \ No newline at end of file From a056dd902e71d3b756f85c5252b1caff96aad810 Mon Sep 17 00:00:00 2001 From: Cassian Florin Date: Sat, 27 Sep 2025 22:19:00 +0800 Subject: [PATCH 5/5] =?UTF-8?q?refactor(xml):=20=E4=BC=98=E5=8C=96XML?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E9=80=BB=E8=BE=91=E4=BB=A5=E6=8F=90?= =?UTF-8?q?=E9=AB=98=E5=AE=89=E5=85=A8=E6=80=A7=E4=B8=8E=E5=8F=AF=E7=BB=B4?= =?UTF-8?q?=E6=8A=A4=E6=80=A7=20(#139)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入新的XmlFormatting工具类统一处理XML格式化 - 移除旧有的直接DOM操作代码,改用更安全的解析方式 - 添加对JSoup和JAXP两种格式化方式的支持,并设置安全特性 - 更新FileReformatUtil和XmlReformatUtil中的调用逻辑 - 在QuickNoteListener中优化异步执行及错误提示机制 - 增强XML解析的安全配置,防止外部实体注入等风险 --- .../ui/listener/func/QuickNoteListener.java | 128 +++++++++------- .../moo/tool/util/FileReformatUtil.java | 137 ++++++------------ .../moo/tool/util/XmlReformatUtil.java | 115 ++++----------- .../tool/util/codeformatter/XmlFormatter.java | 30 +--- .../util/codeformatter/XmlFormatting.java | 137 ++++++++++++++++++ 5 files changed, 283 insertions(+), 264 deletions(-) create mode 100644 src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatting.java diff --git a/src/main/java/com/luoboduner/moo/tool/ui/listener/func/QuickNoteListener.java b/src/main/java/com/luoboduner/moo/tool/ui/listener/func/QuickNoteListener.java index b6d7f455..b65a45da 100644 --- a/src/main/java/com/luoboduner/moo/tool/ui/listener/func/QuickNoteListener.java +++ b/src/main/java/com/luoboduner/moo/tool/ui/listener/func/QuickNoteListener.java @@ -1063,76 +1063,94 @@ public class QuickNoteListener { public static void format() { try { QuickNoteForm quickNoteForm = QuickNoteForm.getInstance(); - String text = QuickNoteForm.quickNoteRSyntaxTextViewerManager.getTextByName(selectedName); - - String format; - String selectedSyntax = (String) quickNoteForm.getSyntaxComboBox().getSelectedItem(); + final String text = QuickNoteForm.quickNoteRSyntaxTextViewerManager.getTextByName(selectedName); + final String selectedSyntax = (String) quickNoteForm.getSyntaxComboBox().getSelectedItem(); if (StringUtils.isBlank(text) || StringUtils.isEmpty(selectedSyntax)) { return; } - switch ("text/" + selectedSyntax) { - case SyntaxConstants.SYNTAX_STYLE_SQL: - switch (App.config.getSqlDialect()) { - case "MariaDB": - format = SqlFormatter.of(Dialect.MariaDb).format(text, " "); + executorService.submit(() -> { + try { + String formatted; + switch ("text/" + selectedSyntax) { + case SyntaxConstants.SYNTAX_STYLE_SQL: + switch (App.config.getSqlDialect()) { + case "MariaDB": + formatted = SqlFormatter.of(Dialect.MariaDb).format(text, " "); + break; + case "MySQL": + formatted = SqlFormatter.of(Dialect.MySql).format(text, " "); + break; + case "PostgreSQL": + formatted = SqlFormatter.of(Dialect.PostgreSql).format(text, " "); + break; + case "IBM DB2": + formatted = SqlFormatter.of(Dialect.Db2).format(text, " "); + break; + case "Oracle PL/SQL": + formatted = SqlFormatter.of(Dialect.PlSql).format(text, " "); + break; + case "Couchbase N1QL": + formatted = SqlFormatter.of(Dialect.N1ql).format(text, " "); + break; + case "Amazon Redshift": + formatted = SqlFormatter.of(Dialect.Redshift).format(text, " "); + break; + case "Spark": + formatted = SqlFormatter.of(Dialect.SparkSql).format(text, " "); + break; + case "SQL Server Transact-SQL": + formatted = SqlFormatter.of(Dialect.TSql).format(text, " "); + break; + default: + formatted = SqlFormatter.of(Dialect.StandardSql).format(text, " "); + } break; - case "MySQL": - format = SqlFormatter.of(Dialect.MySql).format(text, " "); + case SyntaxConstants.SYNTAX_STYLE_JSON: + case SyntaxConstants.SYNTAX_STYLE_JSON_WITH_COMMENTS: + try { + formatted = JSONUtil.toJsonPrettyStr(text); + } catch (Exception e1) { + log.error(ExceptionUtils.getStackTrace(e1)); + formatted = JSONUtil.formatJsonStr(text); + } break; - case "PostgreSQL": - format = SqlFormatter.of(Dialect.PostgreSql).format(text, " "); + + case SyntaxConstants.SYNTAX_STYLE_XML: + formatted = CodeFormatterFactory.getFormatter(CodeFormatterFactory.FormatterType.XML).format(text); break; - case "IBM DB2": - format = SqlFormatter.of(Dialect.Db2).format(text, " "); - break; - case "Oracle PL/SQL": - format = SqlFormatter.of(Dialect.PlSql).format(text, " "); - break; - case "Couchbase N1QL": - format = SqlFormatter.of(Dialect.N1ql).format(text, " "); - break; - case "Amazon Redshift": - format = SqlFormatter.of(Dialect.Redshift).format(text, " "); - break; - case "Spark": - format = SqlFormatter.of(Dialect.SparkSql).format(text, " "); - break; - case "SQL Server Transact-SQL": - format = SqlFormatter.of(Dialect.TSql).format(text, " "); + + case SyntaxConstants.SYNTAX_STYLE_JAVA: + formatted = CodeFormatterFactory.getFormatter(CodeFormatterFactory.FormatterType.JAVA).format(text); break; default: - format = SqlFormatter.of(Dialect.StandardSql).format(text, " "); + SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(App.mainFrame, "尚不支持对该语言格式化!\n", "不支持该语言", + JOptionPane.INFORMATION_MESSAGE)); + return; } - break; - case SyntaxConstants.SYNTAX_STYLE_JSON: - case SyntaxConstants.SYNTAX_STYLE_JSON_WITH_COMMENTS: - try { - format = JSONUtil.toJsonPrettyStr(text); - } catch (Exception e1) { - log.error(ExceptionUtils.getStackTrace(e1)); - format = JSONUtil.formatJsonStr(text); - } - break; - case SyntaxConstants.SYNTAX_STYLE_JAVA: - format = CodeFormatterFactory.getFormatter(CodeFormatterFactory.FormatterType.JAVA).format(text); - break; - default: - JOptionPane.showMessageDialog(App.mainFrame, "尚不支持对该语言格式化!\n", "不支持该语言", - JOptionPane.INFORMATION_MESSAGE); - return; - } - - QuickNoteForm.quickNoteRSyntaxTextViewerManager.getCurrentRSyntaxTextArea().setText(format); - QuickNoteForm.quickNoteRSyntaxTextViewerManager.getCurrentRSyntaxTextArea().setCaretPosition(0); - - QuickNoteIndicatorTools.showTips("已格式化:" + selectedName, QuickNoteIndicatorTools.TipsLevel.SUCCESS); + final String result = formatted; + SwingUtilities.invokeLater(() -> { + try { + QuickNoteForm.quickNoteRSyntaxTextViewerManager.getCurrentRSyntaxTextArea().setText(result); + QuickNoteForm.quickNoteRSyntaxTextViewerManager.getCurrentRSyntaxTextArea().setCaretPosition(0); + QuickNoteIndicatorTools.showTips("已格式化:" + selectedName, QuickNoteIndicatorTools.TipsLevel.SUCCESS); + } catch (Exception ex) { + JOptionPane.showMessageDialog(App.mainFrame, "格式化失败!\n\n" + ex.getMessage(), "失败", + JOptionPane.ERROR_MESSAGE); + log.error(ExceptionUtils.getStackTrace(ex)); + } + }); + } catch (Exception e) { + SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(App.mainFrame, "格式化失败!\n\n" + e.getMessage(), "失败", + JOptionPane.ERROR_MESSAGE)); + log.error(ExceptionUtils.getStackTrace(e)); + } + }); } catch (Exception e) { JOptionPane.showMessageDialog(App.mainFrame, "格式化失败!\n\n" + e.getMessage(), "失败", JOptionPane.ERROR_MESSAGE); log.error(ExceptionUtils.getStackTrace(e)); } - } } diff --git a/src/main/java/com/luoboduner/moo/tool/util/FileReformatUtil.java b/src/main/java/com/luoboduner/moo/tool/util/FileReformatUtil.java index 5f8f8b0d..6b3c1c49 100755 --- a/src/main/java/com/luoboduner/moo/tool/util/FileReformatUtil.java +++ b/src/main/java/com/luoboduner/moo/tool/util/FileReformatUtil.java @@ -1,92 +1,45 @@ -package com.luoboduner.moo.tool.util; - -import de.hunsicker.jalopy.Jalopy; -import de.hunsicker.jalopy.storage.Convention; -import de.hunsicker.jalopy.storage.ConventionKeys; -import org.jsoup.Jsoup; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.File; -import java.io.StringWriter; - -public class FileReformatUtil { - - private static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - private static TransformerFactory transformerFactory = TransformerFactory.newInstance(); - private static Jalopy jalopy = new Jalopy(); - - public static String reformatXML(File file, int spaceNum) throws Exception { - StringWriter res = new StringWriter(); - try { - // 创建DocumentBuilder对象 - DocumentBuilder builder = factory.newDocumentBuilder(); - - // 解析XML文件并返回Document对象 - Document document = builder.parse(file); - // 获取文档的根元素 - Element rootElement = document.getDocumentElement(); - - // 设置格式化属性,这里使用缩进和换行 - document.setXmlStandalone(true); - document.setXmlVersion("1.0"); - rootElement.normalize(); - - // 创建Transformer对象 - Transformer transformer = transformerFactory.newTransformer(); - - // 设置输出格式化属性,这里使用缩进和换行 - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(spaceNum)); - - // 创建DOMSource对象 - DOMSource source = new DOMSource(document); - - // 创建StreamResult对象,指定输出位置 - StreamResult result = new StreamResult(res); - - // 格式化XML并输出结果 - transformer.transform(source, result); - - return res.toString(); - } catch (Exception e) { - throw e; - } finally { - res.close(); - } - } - - public static String reformatHTML(File file, int spaceNum) throws Exception { - return Jsoup.parse(file, "UTF-8") - .outputSettings(new org.jsoup.nodes.Document.OutputSettings().indentAmount(spaceNum)) - .outerHtml(); - } - - public static String reformatJAVA(File file, int spaceNum) throws Exception { - Convention instance = Convention.getInstance(); - instance.put(ConventionKeys.SPACE_BEFORE_BRACES, "true"); - instance.put(ConventionKeys.SPACE_BEFORE_BRACKETS, "true"); - instance.put(ConventionKeys.INDENT_SIZE, String.valueOf(spaceNum)); - - try (StringWriter stringWriter = new StringWriter()) { - jalopy.setInput(file); - jalopy.setOutput(stringWriter); - boolean result = jalopy.format(); - if (!result) { - throw new Exception("格式化失败!"); - } - - return stringWriter.toString(); - } catch (Exception e) { - throw e; - } - } -} +package com.luoboduner.moo.tool.util; + +import com.luoboduner.moo.tool.util.codeformatter.XmlFormatting; +import de.hunsicker.jalopy.Jalopy; +import de.hunsicker.jalopy.storage.Convention; +import de.hunsicker.jalopy.storage.ConventionKeys; +import org.jsoup.Jsoup; + +import java.io.File; +import java.io.StringWriter; + +public class FileReformatUtil { + + private static Jalopy jalopy = new Jalopy(); + + public static String reformatXML(File file, int spaceNum) throws Exception { + return XmlFormatting.formatFile(file, spaceNum); + } + + public static String reformatHTML(File file, int spaceNum) throws Exception { + return Jsoup.parse(file, "UTF-8") + .outputSettings(new org.jsoup.nodes.Document.OutputSettings().indentAmount(spaceNum)) + .outerHtml(); + } + + public static String reformatJAVA(File file, int spaceNum) throws Exception { + Convention instance = Convention.getInstance(); + instance.put(ConventionKeys.SPACE_BEFORE_BRACES, "true"); + instance.put(ConventionKeys.SPACE_BEFORE_BRACKETS, "true"); + instance.put(ConventionKeys.INDENT_SIZE, String.valueOf(spaceNum)); + + try (StringWriter stringWriter = new StringWriter()) { + jalopy.setInput(file); + jalopy.setOutput(stringWriter); + boolean result = jalopy.format(); + if (!result) { + throw new Exception("格式化失败!"); + } + + return stringWriter.toString(); + } catch (Exception e) { + throw e; + } + } +} diff --git a/src/main/java/com/luoboduner/moo/tool/util/XmlReformatUtil.java b/src/main/java/com/luoboduner/moo/tool/util/XmlReformatUtil.java index d2b9f37a..60df2671 100755 --- a/src/main/java/com/luoboduner/moo/tool/util/XmlReformatUtil.java +++ b/src/main/java/com/luoboduner/moo/tool/util/XmlReformatUtil.java @@ -1,90 +1,25 @@ -package com.luoboduner.moo.tool.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.StringWriter; - -public class XmlReformatUtil { - // log - private static final Logger logger = LoggerFactory.getLogger(XmlReformatUtil.class); - - private static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - private static TransformerFactory transformerFactory = TransformerFactory.newInstance(); - - public static String reformat(File file, int spaceNum) throws Exception { - StringWriter res = new StringWriter(); - try { - // 创建DocumentBuilder对象 - DocumentBuilder builder = factory.newDocumentBuilder(); - - // 解析XML文件并返回Document对象 - Document document = builder.parse(file); - // 获取文档的根元素 - Element rootElement = document.getDocumentElement(); - - // 设置格式化属性,这里使用缩进和换行 - document.setXmlStandalone(true); - document.setXmlVersion("1.0"); - rootElement.normalize(); - - // 创建Transformer对象 - Transformer transformer = transformerFactory.newTransformer(); - - // 设置输出格式化属性,这里使用缩进和换行 - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(spaceNum)); - - // 创建DOMSource对象 - DOMSource source = new DOMSource(document); - - // 创建StreamResult对象,指定输出位置 - StreamResult result = new StreamResult(res); - - // 格式化XML并输出结果 - transformer.transform(source, result); - - return res.toString(); - } catch (Exception e) { - throw e; - } finally { - res.close(); - } - } - - public static String format(String xmlStr) { - try { - DocumentBuilder builder = factory.newDocumentBuilder(); - Document document = builder.parse(new InputSource(new ByteArrayInputStream(xmlStr.getBytes("utf-8")))); - Element rootElement = document.getDocumentElement(); - document.setXmlStandalone(true); - document.setXmlVersion("1.0"); - rootElement.normalize(); - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); - DOMSource source = new DOMSource(document); - StringWriter res = new StringWriter(); - StreamResult result = new StreamResult(res); - transformer.transform(source, result); - return res.toString(); - } catch (Exception e) { - logger.error("XML格式化失败", e); - return xmlStr; - } - } -} +package com.luoboduner.moo.tool.util; + +import com.luoboduner.moo.tool.util.codeformatter.XmlFormatting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class XmlReformatUtil { + // log + private static final Logger logger = LoggerFactory.getLogger(XmlReformatUtil.class); + + public static String reformat(File file, int spaceNum) throws Exception { + return XmlFormatting.formatFile(file, spaceNum); + } + + public static String format(String xmlStr) { + try { + return XmlFormatting.formatString(xmlStr, 4); + } catch (Exception e) { + logger.error("XML格式化失败", e); + return xmlStr; + } + } +} diff --git a/src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatter.java b/src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatter.java index 0a7cccb6..86a57cc1 100644 --- a/src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatter.java +++ b/src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatter.java @@ -1,38 +1,14 @@ package com.luoboduner.moo.tool.util.codeformatter; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.StringReader; -import java.io.StringWriter; - public class XmlFormatter implements CodeFormatter { public String format(String input) { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document document = builder.parse(new InputSource(new StringReader(input))); - - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - Transformer transformer = transformerFactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); - - StringWriter writer = new StringWriter(); - transformer.transform(new DOMSource(document), new StreamResult(writer)); - return writer.toString(); + // Delegate to centralized safe XML formatter with default indent 4 + return XmlFormatting.formatString(input, 4); } catch (Exception e) { throw new RuntimeException("Error formatting XML", e); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatting.java b/src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatting.java new file mode 100644 index 00000000..6206ef8f --- /dev/null +++ b/src/main/java/com/luoboduner/moo/tool/util/codeformatter/XmlFormatting.java @@ -0,0 +1,137 @@ +package com.luoboduner.moo.tool.util.codeformatter; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.parser.Parser; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.StringWriter; + +/** + * XML格式化工具 + * + * @author CassianFlorin + * @email flowercard591@gmail.com + * @date 2025/9/27 22:15 + */ +public final class XmlFormatting { + + private XmlFormatting() { + } + + public static String formatString(String xml, int indent) throws Exception { + try { + return formatWithJsoup(xml, indent); + } catch (Exception ignore) { + // fallback to JAXP secure DOM formatting + org.w3c.dom.Document document = parseString(xml); + return transform(document, indent); + } + } + + public static String formatFile(File file, int indent) throws Exception { + try { + String content = readFileUtf8(file); + return formatWithJsoup(content, indent); + } catch (Exception ignore) { + org.w3c.dom.Document document = parseFile(file); + return transform(document, indent); + } + } + + private static String formatWithJsoup(String xml, int indent) throws Exception { + Document doc = Jsoup.parse(xml, "", Parser.xmlParser()); + doc.outputSettings(new Document.OutputSettings() + .prettyPrint(true) + .indentAmount(indent) + .syntax(Document.OutputSettings.Syntax.xml)); + return doc.outerHtml(); + } + + private static org.w3c.dom.Document parseString(String xml) throws Exception { + DocumentBuilderFactory factory = secureDocumentBuilderFactory(); + DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource source = new InputSource(new ByteArrayInputStream(xml.getBytes("UTF-8"))); + org.w3c.dom.Document document = builder.parse(source); + normalize(document); + return document; + } + + private static org.w3c.dom.Document parseFile(File file) throws Exception { + DocumentBuilderFactory factory = secureDocumentBuilderFactory(); + DocumentBuilder builder = factory.newDocumentBuilder(); + org.w3c.dom.Document document = builder.parse(file); + normalize(document); + return document; + } + + private static void normalize(org.w3c.dom.Document document) { + Element rootElement = document.getDocumentElement(); + document.setXmlStandalone(true); + document.setXmlVersion("1.0"); + if (rootElement != null) { + rootElement.normalize(); + } + } + + private static String transform(org.w3c.dom.Document document, int indent) throws Exception { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + try { + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (Throwable ignore) { + // Some TransformerFactory implementations may not support this feature; ignore to keep compatibility + } + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(indent)); + + StringWriter res = new StringWriter(); + transformer.transform(new DOMSource(document), new StreamResult(res)); + return res.toString(); + } + + private static String readFileUtf8(File file) throws Exception { + byte[] bytes = java.nio.file.Files.readAllBytes(file.toPath()); + return new String(bytes, "UTF-8"); + } + + private static DocumentBuilderFactory secureDocumentBuilderFactory() throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setXIncludeAware(false); + try { + // Enable secure processing + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (Throwable ignore) { + // keep going for max compatibility with various parsers + } + try { + // Disallow loading external DTDs and external entities to avoid blocking/XXE + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + } catch (Throwable ignore) { + } + try { + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (Throwable ignore) { + } + try { + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } catch (Throwable ignore) { + } + // Do not expand entity references automatically + factory.setExpandEntityReferences(false); + return factory; + } +}