From 5697cbd2517b1e4e4ee3cb57506097b8e3007a73 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 7 Sep 2025 15:47:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20Gradle=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3=E5=86=85=E5=AE=B9?= =?UTF-8?q?=20(#4403)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- build.gradle.kts | 7 + .../jackhuang/hmcl/gradle/docs/Document.java | 151 ++++++++++++++++++ .../hmcl/gradle/docs/DocumentFileTree.java | 112 +++++++++++++ .../hmcl/gradle/docs/DocumentLocale.java | 118 ++++++++++++++ .../hmcl/gradle/docs/LocalizedDocument.java | 62 +++++++ .../hmcl/gradle/docs/MacroProcessor.java | 144 +++++++++++++++++ .../hmcl/gradle/docs/UpdateDocuments.java | 131 +++++++++++++++ docs/PLATFORM.md | 4 +- docs/PLATFORM_zh.md | 4 +- docs/PLATFORM_zh_Hant.md | 4 +- docs/README.md | 5 +- docs/README_es.md | 7 +- docs/README_ja.md | 5 +- docs/README_lzh.md | 5 +- docs/README_ru.md | 5 +- docs/README_uk.md | 5 +- docs/README_zh.md | 5 +- docs/README_zh_Hant.md | 5 +- 18 files changed, 759 insertions(+), 20 deletions(-) create mode 100644 buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/Document.java create mode 100644 buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/DocumentFileTree.java create mode 100644 buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/DocumentLocale.java create mode 100644 buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/LocalizedDocument.java create mode 100644 buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/MacroProcessor.java create mode 100644 buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/UpdateDocuments.java diff --git a/build.gradle.kts b/build.gradle.kts index fbf39b95d..d68432856 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jackhuang.hmcl.gradle.docs.UpdateDocuments + plugins { id("checkstyle") } @@ -60,3 +62,8 @@ subprojects { org.jackhuang.hmcl.gradle.javafx.JavaFXUtils.register(rootProject) defaultTasks("clean", "build") + + +tasks.register("updateDocuments") { + documentsDir.set(layout.projectDirectory.dir("docs")) +} \ No newline at end of file diff --git a/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/Document.java b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/Document.java new file mode 100644 index 000000000..223fa9cb9 --- /dev/null +++ b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/Document.java @@ -0,0 +1,151 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.gradle.docs; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/// @author Glavo +public record Document(DocumentFileTree directory, + Path file, + String name, DocumentLocale locale, + List items) { + + private static final Pattern MACRO_BEGIN = Pattern.compile( + "" + ); + + private static final Pattern MACRO_PROPERTY_LINE = Pattern.compile( + "" + ); + + private static String parsePropertyValue(String value) { + int i = 0; + while (i < value.length()) { + char ch = value.charAt(i); + if (ch == '\\') + break; + i++; + } + + if (i == value.length()) + return value; + + StringBuilder builder = new StringBuilder(value.length()); + builder.append(value, 0, i); + for (; i < value.length(); i++) { + char ch = value.charAt(i); + if (ch == '\\' && i < value.length() - 1) { + char next = value.charAt(++i); + switch (next) { + case 'n' -> builder.append('\n'); + case 'r' -> builder.append('\r'); + case '\\' -> builder.append('\\'); + default -> builder.append(next); + } + } else { + builder.append(ch); + } + } + return builder.toString(); + } + + static void writePropertyValue(StringBuilder builder, String value) { + for (int i = 0; i < value.length(); i++) { + char ch = value.charAt(i); + + switch (ch) { + case '\\' -> builder.append("\\\\"); + case '\r' -> builder.append("\\r"); + case '\n' -> builder.append("\\n"); + default -> builder.append(ch); + } + } + } + + public static Document load(DocumentFileTree directory, Path file, String name, DocumentLocale locale) throws IOException { + var items = new ArrayList(); + try (var reader = Files.newBufferedReader(file)) { + String line; + + while ((line = reader.readLine()) != null) { + if (!line.startsWith(""; + var properties = new LinkedHashMap>(); + var lines = new ArrayList(); + + // Handle properties + while ((line = reader.readLine()) != null) { + if (!line.startsWith("\n"); + } + + private static void writeEnd(StringBuilder builder, Document.MacroBlock macroBlock) throws IOException { + builder.append("\n"); + } + + private static void writeProperties(StringBuilder builder, Document.MacroBlock macroBlock) throws IOException { + macroBlock.properties().forEach((key, values) -> { + for (String value : values) { + builder.append("\n"); + } + }); + } + + public abstract void apply(Document document, + Document.MacroBlock macroBlock, + StringBuilder outputBuilder) throws IOException; +} diff --git a/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/UpdateDocuments.java b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/UpdateDocuments.java new file mode 100644 index 000000000..5997965a2 --- /dev/null +++ b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/docs/UpdateDocuments.java @@ -0,0 +1,131 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.gradle.docs; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.TaskAction; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.regex.Pattern; + +/// @author Glavo +public abstract class UpdateDocuments extends DefaultTask { + + @InputDirectory + public abstract DirectoryProperty getDocumentsDir(); + + // --- + + private static final Pattern LINK_PATTERN = Pattern.compile( + "(?<=]\\()[a-zA-Z0-9_\\-./]+\\.md(?=\\))" + ); + + private void processLine(StringBuilder outputBuilder, String line, Document document) { + outputBuilder.append(LINK_PATTERN.matcher(line).replaceAll(matchResult -> { + String rawLink = matchResult.group(); + String[] splitPath = rawLink.split("/"); + + if (splitPath.length == 0) + return rawLink; + + String fileName = splitPath[splitPath.length - 1]; + if (!fileName.endsWith(".md")) + return rawLink; + + DocumentFileTree current = document.directory(); + for (int i = 0; i < splitPath.length - 1; i++) { + String name = splitPath[i]; + switch (name) { + case "" -> { + return rawLink; + } + case "." -> { + continue; + } + case ".." -> { + current = current.getParent(); + if (current == null) + return rawLink; + } + default -> { + current = current.getChildren().get(name); + if (current == null) + return rawLink; + } + } + } + + DocumentLocale.LocaleAndName currentLocaleAndName = DocumentLocale.parseFileName(fileName.substring(0, fileName.length() - ".md".length())); + LocalizedDocument localizedDocument = current.getFiles().get(currentLocaleAndName.name()); + if (localizedDocument != null) { + List candidateLocales = document.locale().getCandidates(); + for (DocumentLocale candidateLocale : candidateLocales) { + if (candidateLocale == currentLocaleAndName.locale()) + return rawLink; + + Document targetDoc = localizedDocument.getDocuments().get(candidateLocale); + if (targetDoc != null) { + splitPath[splitPath.length - 1] = targetDoc.file().getFileName().toString(); + return String.join("/", splitPath); + } + } + } + + return rawLink; + })).append('\n'); + } + + private void updateDocument(Document document) throws IOException { + StringBuilder outputBuilder = new StringBuilder(8192); + + for (Document.Item item : document.items()) { + if (item instanceof Document.Line line) { + processLine(outputBuilder, line.content(), document); + } else if (item instanceof Document.MacroBlock macro) { + var processor = MacroProcessor.valueOf(macro.name()); + processor.apply(document, macro, outputBuilder); + } else + throw new IllegalArgumentException("Unknown item type: " + item.getClass()); + } + + Files.writeString(document.file(), outputBuilder.toString()); + } + + private void processDocuments(DocumentFileTree tree) throws IOException { + for (LocalizedDocument localizedDocument : tree.getFiles().values()) { + for (Document document : localizedDocument.getDocuments().values()) { + updateDocument(document); + } + } + + for (DocumentFileTree subTree : tree.getChildren().values()) { + processDocuments(subTree); + } + } + + @TaskAction + public void run() throws IOException { + Path rootDir = getDocumentsDir().get().getAsFile().toPath(); + processDocuments(DocumentFileTree.load(rootDir)); + } +} diff --git a/docs/PLATFORM.md b/docs/PLATFORM.md index cd8790e47..4d23c7f2d 100644 --- a/docs/PLATFORM.md +++ b/docs/PLATFORM.md @@ -1,6 +1,8 @@ # Platform Support Status + **English** | 中文 ([简体](PLATFORM_zh.md), [繁體](PLATFORM_zh_Hant.md)) + | | Windows | Linux | macOS | FreeBSD | |----------------------------|:--------------------------------------------------|:---------------------------|:------------------------------------------------------------------------|:---------------------------| @@ -35,4 +37,4 @@ Legend: * `/`: Not applicable. We have no plans to support these platforms at this time, mainly because we do not have the equipment to test them. - If you can help us adapt, please file a support request via GitHub Issue. \ No newline at end of file + If you can help us adapt, please file a support request via GitHub Issue. diff --git a/docs/PLATFORM_zh.md b/docs/PLATFORM_zh.md index a03c6334e..dcdef58ee 100644 --- a/docs/PLATFORM_zh.md +++ b/docs/PLATFORM_zh.md @@ -1,6 +1,8 @@ # 平台支持状态 + [English](PLATFORM.md) | **中文** (**简体**, [繁體](PLATFORM_zh_Hant.md)) + | | Windows | Linux | macOS | FreeBSD | |----------------------------|:--------------------------------------------------|:---------------------------|:-----------------------------------------------------------------------|:--------------------------| @@ -35,4 +37,4 @@ * `/`: 不支持的平台 我们目前还没有打算支持这些平台,主要是因为我们没有测试这些平台的设备。 - 如果你能帮助我们进行测试,请通过提交 Issue 提出支持请求。 \ No newline at end of file + 如果你能帮助我们进行测试,请通过提交 Issue 提出支持请求。 diff --git a/docs/PLATFORM_zh_Hant.md b/docs/PLATFORM_zh_Hant.md index 855cc3b09..46cc95521 100644 --- a/docs/PLATFORM_zh_Hant.md +++ b/docs/PLATFORM_zh_Hant.md @@ -1,6 +1,8 @@ # 平臺支援狀態 + [English](PLATFORM.md) | **中文** ([简体](PLATFORM_zh.md), **繁體**) + | | Windows | Linux | macOS | FreeBSD | |----------------------------|:--------------------------------------------------|:---------------------------|:-----------------------------------------------------------------------|:--------------------------| @@ -35,4 +37,4 @@ * `/`: 不支援的平臺 我們目前還沒有打算支援這些平臺,主要是因為我們沒有測試這些平臺的裝置。 - 如果你能幫助我們進行測試,請透過提交 Issue 提出支援請求。 \ No newline at end of file + 如果你能幫助我們進行測試,請透過提交 Issue 提出支援請求。 diff --git a/docs/README.md b/docs/README.md index 9d197e015..b75985c21 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -**English** | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | -[español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + +**English** | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | [español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + ## Introduction diff --git a/docs/README_es.md b/docs/README_es.md index d535ebfd3..f5bc19ff1 100644 --- a/docs/README_es.md +++ b/docs/README_es.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | -**español** | [русский](README_ru.md) | [українська](README_uk.md) + +[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | **español** | [русский](README_ru.md) | [українська](README_uk.md) + ## Introducción @@ -61,4 +62,4 @@ Asegúrate de tener instalado Java 17 o una versión posterior. | `-Dhmcl.native.encoding=` | Sobrescribe la codificación nativa | | `-Dhmcl.microsoft.auth.id=` | Sobrescribe el ID de la App OAuth de Microsoft | | `-Dhmcl.microsoft.auth.secret=` | Sobrescribe el secreto de la App OAuth de Microsoft | -| `-Dhmcl.curseforge.apikey=` | Sobrescribe la clave API de CurseForge | \ No newline at end of file +| `-Dhmcl.curseforge.apikey=` | Sobrescribe la clave API de CurseForge | diff --git a/docs/README_ja.md b/docs/README_ja.md index 3783414ef..db812d6d6 100644 --- a/docs/README_ja.md +++ b/docs/README_ja.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | **日本語** | -[español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + +[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | **日本語** | [español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + ## 紹介 diff --git a/docs/README_lzh.md b/docs/README_lzh.md index 37d6263b5..6ec3d0238 100644 --- a/docs/README_lzh.md +++ b/docs/README_lzh.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -[English](README.md) | **中文** ([简体](README_zh.md), [繁體](README_zh_Hant.md), **文言**) | [日本語](README_ja.md) | -[español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + +[English](README.md) | **中文** ([简体](README_zh.md), [繁體](README_zh_Hant.md), **文言**) | [日本語](README_ja.md) | [español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + ### 概說 diff --git a/docs/README_ru.md b/docs/README_ru.md index 624594124..d056397d8 100644 --- a/docs/README_ru.md +++ b/docs/README_ru.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | -[español](README_es.md) | **русский** | [українська](README_uk.md) + +[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | [español](README_es.md) | **русский** | [українська](README_uk.md) + ## Введение diff --git a/docs/README_uk.md b/docs/README_uk.md index 076c2d94a..d7fca7896 100644 --- a/docs/README_uk.md +++ b/docs/README_uk.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | -[español](README_es.md) | [русский](README_ru.md) | **українська** + +[English](README.md) | 中文 ([简体](README_zh.md), [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | [español](README_es.md) | [русский](README_ru.md) | **українська** + ## Вступ diff --git a/docs/README_zh.md b/docs/README_zh.md index ba0c92124..8ec858d8d 100644 --- a/docs/README_zh.md +++ b/docs/README_zh.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -[English](README.md) | **中文** (**简体**, [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | -[español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + +[English](README.md) | **中文** (**简体**, [繁體](README_zh_Hant.md), [文言](README_lzh.md)) | [日本語](README_ja.md) | [español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + ## 简介 diff --git a/docs/README_zh_Hant.md b/docs/README_zh_Hant.md index b16eba4a5..752d53060 100644 --- a/docs/README_zh_Hant.md +++ b/docs/README_zh_Hant.md @@ -6,8 +6,9 @@ [![Discord](https://img.shields.io/discord/995291757799538688.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/jVvC7HfM6U) [![QQ Group](https://img.shields.io/badge/QQ-HMCL-bright?label=&logo=qq&logoColor=ffffff&color=1EBAFC&labelColor=1DB0EF&logoSize=auto)](https://docs.hmcl.net/groups.html) -[English](README.md) | **中文** ([简体](README_zh.md), **繁體**, [文言](README_lzh.md)) | [日本語](README_ja.md) | -[español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + +[English](README.md) | **中文** ([简体](README_zh.md), **繁體**, [文言](README_lzh.md)) | [日本語](README_ja.md) | [español](README_es.md) | [русский](README_ru.md) | [українська](README_uk.md) + ## 簡介