Browse Source

Merge branch 'convert-next-cmake' into develop

zinface 2 years ago
parent
commit
5037d17503
55 changed files with 8087 additions and 139 deletions
  1. 42 0
      .gitignore
  2. 96 80
      CMakeLists.txt
  3. 24 14
      Makefile
  4. BIN
      assets/spark.png
  5. 323 0
      cmake/DebPackageConfig.cmake
  6. 164 0
      cmake/NoteadPlugin-Linux-Development.md
  7. 218 0
      cmake/NotepadPluginConfig.cmake.in
  8. 139 0
      cmake/SparkAppimageConfig.cmake
  9. 36 0
      cmake/SparkDesktopMacros.cmake
  10. 8 0
      cmake/SparkEnvConfig.cmake
  11. 153 0
      cmake/SparkFindQt5Config.cmake
  12. 130 0
      cmake/SparkFindQt6Config.cmake
  13. 132 0
      cmake/SparkInstallMacrosConfig.cmake
  14. 161 0
      cmake/SparkMacrosConfig.cmake
  15. 237 0
      cmake/SparkMacrosExtendConfig.cmake
  16. 33 0
      cmake/modules/Notepad--.cmake
  17. 29 0
      cmake/modules/QScint.cmake
  18. 45 0
      cmake/package-deb.descript
  19. 48 0
      cmake/platforms/linux-appimage.cmake
  20. 18 0
      cmake/platforms/linux-debian.cmake
  21. 110 0
      cmake/platforms/linux-universal.cmake
  22. 72 0
      cmake/platforms/linux-uos.cmake
  23. 113 0
      cmake/platforms/linux.cmake
  24. 13 0
      cmake/platforms/linux/universal/usr/share/applications/io.gitee.cxasm.notepad--.desktop
  25. BIN
      cmake/platforms/linux/universal/usr/share/icons/hicolor/128x128/apps/notepad--.png
  26. BIN
      cmake/platforms/linux/universal/usr/share/icons/hicolor/32x32/apps/notepad--.png
  27. BIN
      cmake/platforms/linux/universal/usr/share/icons/hicolor/64x64/apps/notepad--.png
  28. 674 0
      cmake/platforms/linux/universal/usr/share/licenses/notepad--/LICENSE
  29. 18 0
      cmake/platforms/linux/universal/usr/share/metainfo/io.gitee.cxasm.notepad--.metainfo.xml
  30. 17 0
      cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/applications/io.gitee.cxasm.notepad--.desktop
  31. 2 0
      cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/icons/hicolor/scalable/apps/ndd.svg
  32. 674 0
      cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/licenses/notepad--/LICENSE
  33. 18 0
      cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/metainfo/io.gitee.cxasm.notepad--.metainfo.xml
  34. 18 0
      cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/info
  35. 0 0
      cmake/platforms/macos.cmake
  36. 94 0
      cmake/platforms/windows-deployqt.cmake
  37. 93 0
      cmake/platforms/windows-universal.cmake
  38. 80 0
      cmake/platforms/windows.cmake
  39. 10 0
      cmake/spark-appimage.desktop.in
  40. 12 0
      cmake/spark-desktop.desktop.in
  41. 47 0
      linux-appimage.mk
  42. 19 0
      linux-debian.mk
  43. 21 0
      linux-universal.mk
  44. 39 0
      linux-uos.mk
  45. 10 38
      linux.mk
  46. 4 0
      macos.mk
  47. 56 0
      patchs/README.md
  48. 890 0
      patchs/base-4c8661d74aa78ea504a9a2f8b06139d571caed3d-linux-qt6.patch
  49. 2759 0
      patchs/coconil-cmake-spark-deb-appimage.patch
  50. 27 0
      patchs/coconil-cmake-version-3.16.patch
  51. 38 0
      patchs/coconil-cmake-version-3.22.patch
  52. 38 0
      patchs/fix-windows-qtcreator-build-fail.patch
  53. 48 7
      src/include/pluginGl.h
  54. 31 0
      windows-universal.mk
  55. 6 0
      windows.mk

+ 42 - 0
.gitignore

@@ -475,3 +475,45 @@ compile_commands.json
 [Bb]uild/
 .vscode/
 .vs/
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml
+
+
+
+# Ignore the build directory generated by the vsocde cmake extension
+build/
+# Ignore the build directory generated by the vsocde clangd extension
+.cache
+
+# Created by https://www.toptal.com/developers/gitignore/api/cmake
+# Edit at https://www.toptal.com/developers/gitignore?templates=cmake
+
+### CMake ###
+CMakeLists.txt.user
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Testing
+Makefile
+cmake_install.cmake
+install_manifest.txt
+compile_commands.json
+CTestTestfile.cmake
+_deps
+
+### CMake Patch ###
+# External projects
+*-prefix/
+
+# End of https://www.toptal.com/developers/gitignore/api/cmake
+!/Makefile

+ 96 - 80
CMakeLists.txt

@@ -1,90 +1,106 @@
-cmake_minimum_required(VERSION 3.16)
-project(NotePad-- VERSION 1.22.0)
+cmake_minimum_required(VERSION 3.22)
 
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTOUIC ON)
-set(CMAKE_AUTORCC ON)
+project(Notepad-- VERSION 1.22.0)
 
-find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Concurrent Network PrintSupport XmlPatterns)
+include(cmake/SparkEnvConfig.cmake)
+include(cmake/SparkMacrosConfig.cmake)
+include(cmake/SparkFindQt5Config.cmake)
+# include(cmake/SparkFindQt6Config.cmake)
+include(cmake/SparkMacrosExtendConfig.cmake)
 
-# qscint 关键依赖库
-add_subdirectory(${PROJECT_SOURCE_DIR}/src/qscint)
 
-# 插件库包含
-# helloworld 动态插件库
-add_subdirectory(${PROJECT_SOURCE_DIR}/src/plugin/helloworld)
-
-# win下需要开启UNICODE进行支持TCHAR
-if(CMAKE_HOST_WIN32)
-    add_definitions(-D_UNICODE -DUNICODE)
+# ----------------- 构建之前 全局定义 ----------------- #
+# 在 Windows 中开启 UNICODE 以支持 TCHAR 功能
+if(WIN32)
+    add_compile_definitions(_UNICODE= UNICODE=)
 endif()
 
+# ----------------- 构建 QSci 静态库 ----------------- #
+if(TRUE)
+    include(cmake/modules/QScint.cmake)
+endif(TRUE)
+
+
+# ----------------- 构建 Notepad-- 程序 ----------------- #
+if(TRUE)
+    include(cmake/modules/Notepad--.cmake)
+endif(TRUE)
+
+# ----------------- Notepad-- 其它主线构建相关  ----------------- #
+option(USE_MACOS_UNIVERSAL   "通用 MacOS 平台构建"            OFF)
+#
+option(USE_LINUX_UNIVERSAL   "通用 Linux 平台构建"            OFF)
+option(USE_LINUX_DEBIAN      "通用 Debian Linux 平台构建"     OFF)
+option(USE_LINUX_APPIMAGE    "通用 Appimage Linux 平台构建"   OFF)
+#
+option(USE_LINUX_UOS         "独立 Linux 平台的 Uos 构建"      OFF)
+#
+option(USE_WINDOWS_UNIVERSAL "通用 Windows 平台构建"          OFF)
+option(USE_WINDOWS_MINGW     "通用 Windows 平台 MinGW 构建"   OFF)
+option(USE_WINDOWS_MSVC      "通用 Windows 平台 MSVC 构建"    OFF)
+#
+option(WINDOWS_DEPLOY_QT     "通用 Windows 平台 Qt 部署" OFF)
+option(WINDOWS_DEPLOY_QT5    "通用 Windows 平台指定 Qt5 部署 windeployqt" OFF)
+option(WINDOWS_DEPLOY_QT6    "通用 Windows 平台指定 Qt6 部署 windeployqt" OFF)
+
+
+# 使用 macos.cmake / linux.cmake / windows.cmake 维护构建.
+if(APPLE)
+    # 通用 MacOS 平台的构建(一个无具体实现的空构建)
+    # include(cmake/platforms/macos.cmake)
+
+    # 在 Linux 中此处将由通用构建、Debian 打包构建、Appimage 打包构建、Uos 打包构建组成
+elseif(UNIX AND NOT APPLE AND NOT WIN32 AND NOT ANDROID)
+
+    # 通用 Linux 平台构建,一切的起始
+    if(USE_LINUX_UNIVERSAL)
+        include(cmake/platforms/linux-universal.cmake)
+
+        # 通用 Linux 平台的 Debian deb 构建
+        if(USE_LINUX_DEBIAN)    
+            include(cmake/platforms/linux-debian.cmake)
+        endif()
+
+        # 通用 Linux 平台的  Appimage  构建
+        if(USE_LINUX_APPIMAGE)  
+            include(cmake/platforms/linux-appimage.cmake)
+        endif()
+
+        # 独立 Linux 平台的 Uos 构建
+    elseif(USE_LINUX_UOS)
+        include(cmake/platforms/linux-uos.cmake)
+
+        # 其它 Linux 平台的构建
+    else()
+        # include(cmake/platforms/linux.cmake)
+    endif(USE_LINUX_UNIVERSAL)
+    
+    # 在 Windows 中此处将由通用构建、MinGW 构建、MSVC 构建组成
+elseif(WIN32)
+    
+    # 通用 Windows 平台构建,一切的起始
+    if(USE_WINDOWS_UNIVERSAL)
+        include(cmake/platforms/windows-universal.cmake)
+
+        # 为 Windows 中构建的应用进行 windeployqt 的配方
+        include(cmake/platforms/windows-deployqt.cmake)
+    
+        # 通用平台的  Windows MinGW 构建
+        if(USE_WINDOWS_MINGW)
+            # include(cmake/platforms/windows-mingw.cmake)
+        endif()
+        
+        # 通用平台的  Windows MSVC 构建
+        if(USE_WINDOWS_MSVC)
+            # include(cmake/platforms/windows-msvc.cmake)
+        endif()
+
+        # 其它 Windows 平台的构建
+    else()
+        # include(cmake/platforms/windows-other.cmake)
+    endif(USE_WINDOWS_UNIVERSAL)
 
-if(${PLUGIN_EN})
-    if(${PLUGIN_EN}  STREQUAL on)
-        add_definitions(-DNO_PLUGIN=1)
-    endif(${PLUGIN_EN})    
 endif()
 
+# ----------------- Notepad-- 其它主线构建相关  ----------------- #
 
-
-file(GLOB UI_SRC ${PROJECT_SOURCE_DIR}/src/*.ui)
-set(UI_SRC ${UI_SRC} ${PROJECT_SOURCE_DIR}/src/cceditor/ccnotepad.ui)
-aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
-aux_source_directory(${PROJECT_SOURCE_DIR}/src/cceditor SRC)
-
-
-if(CMAKE_HOST_WIN32)
-# 添加 WIN32 保证主程序启动没有命令行
-    list(APPEND WIN_RCS ${PROJECT_SOURCE_DIR}/src/RealCompareToMinGw.rc)
-    add_executable(${PROJECT_NAME} WIN32 ${WIN_RCS} ${SRC} ${UI_SRC} ${PROJECT_SOURCE_DIR}/src/RealCompare.qrc)
-else()
-    add_executable(${PROJECT_NAME} ${SRC} ${UI_SRC} ${PROJECT_SOURCE_DIR}/src/RealCompare.qrc)
-endif()
-
-target_include_directories(${PROJECT_NAME} PRIVATE
-${PROJECT_SOURCE_DIR}/src
-${PROJECT_SOURCE_DIR}/src/cceditor
-
-${PROJECT_SOURCE_DIR}/src/qscint/src
-${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
-${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
-${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
-${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
-${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
-)
-
-target_link_libraries(${PROJECT_NAME} qscint Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent Qt5::Network  Qt5::PrintSupport Qt5::XmlPatterns)
-
-# set(PROJECT_BINARY_DIR "${PROJECT_BINARY_DIR}/bin")
-# set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
-
-if(CMAKE_HOST_UNIX)
-    install(
-        TARGETS ${PROJECT_NAME}
-        DESTINATION "bin"
-    )
-
-    install(DIRECTORY  ${PROJECT_SOURCE_DIR}/src/linux/usr
-            DESTINATION "/")
-
-    include(${PROJECT_SOURCE_DIR}/cmake/deb_package_config.cmake) 
-    include(CPack)
-elseif(CMAKE_HOST_WIN32)
-    install(TARGETS ${PROJECT_NAME}
-            DESTINATION "/")
-
-    install(DIRECTORY  ${PROJECT_SOURCE_DIR}/build/bin/
-            DESTINATION "/")
-    # 设置软件版本
-    set(CPACK_PACKAGE_NAME "NotePad--")
-    set(CPACK_PACKAGE_DESCRIPTION "NotePad--")
-    set(CPACK_PACKAGE_COPYRIGHT "Copyright (c) 2023")
-    set(CPACK_PACKAGE_VERSION "1.22.0")
-    set(CPACK_PACKAGE_VERSION_MAJOR "1")
-    set(CPACK_PACKAGE_VERSION_MINOR "22")
-    set(CPACK_PACKAGE_VERSION_PATCH "0")
-
-    include(${PROJECT_SOURCE_DIR}/cmake/nsis_package_config.cmake) 
-    include(CPack)
-endif()

+ 24 - 14
Makefile

@@ -1,17 +1,27 @@
-UNAME:=WIN32
-UNAME:=$(shell uname)
+# 主体构建入口
 
-# Win下使用Git Bash运行make
+# 1. 在 Windows 中 $(OS) 为 Windows_NT
+# 2. 在 Linux 中 $(OS) 为空的,此时应该使用 uname 
+    # 注意:在 Linux 中 uanme -s 显示为 Linux
+    # 注意:在 Linux 中某些内核 uanme -p 显示为 unknow 
+# 3. 待验证:在 OSX 中 $(OS) 为空的,此时应该使用 uname 
+    # 待验证:在 OSX 中 uname -s 显示为 Darwin
+    # 待验证:在 OSX 中 uname -p 显示为 ?
 
-ifeq ($(UNAME), Linux)
-all:linux
-linux:
-	make -f linux.mk package
-else
-all:
-	make -f win.mk all
-msvc:
-	make -f win.mk msvc
-mingw:
-	make -f win.mk mingw
+# Windows 平台相关
+ifeq ($(OS),Windows_NT)
+    include windows.mk
+# Unix 平台相关
+else 
+    UNAME_S := $(shell uname -s)
+    # Linux 构建
+    ifeq ($(UNAME_S),Linux)
+		include linux.mk
+    endif
+
+    # MacOS 构建
+    ifeq ($(UNAME_S),Darwin)
+        include macos.mk
+    endif
 endif
+

BIN
assets/spark.png


+ 323 - 0
cmake/DebPackageConfig.cmake

@@ -0,0 +1,323 @@
+cmake_minimum_required(VERSION 3.0.0)
+
+# function(add_deb_package PACKAGE_NAME PACKAGE_VERSION PACKAGE_MAINTAINER PACKAGE_EMAIL PACKAGE_SHORT_DESCRIPTION PACKAGE_LONG_DESCRIPTION)
+
+# endfunction(add_deb_package PACKAGE_NAME PACKAGE_VERSION PACKAGE_MAINTAINER PACKAGE_EMAIL PACKAGE_SHORT_DESCRIPTION PACKAGE_LONG_DESCRIPTION)
+
+# if(add_deb_package    VALUE) set(Package    ${VALUE} PARENT_SCOPE) endif(add_deb_package    VALUE)
+# if(add_deb_version    VALUE) set(Version    ${VALUE} PARENT_SCOPE) endif(add_deb_version    VALUE)
+# if(add_deb_maintainer VALUE) set(Maintainer ${VALUE} PARENT_SCOPE) endif(add_deb_maintainer VALUE)
+# if(add_deb_email      VALUE) set(Email      ${VALUE} PARENT_SCOPE) endif(add_deb_email      VALUE)
+# if(add_deb_descrition VALUE) set(Descrition ${VALUE} PARENT_SCOPE) endif(add_deb_descrition VALUE)
+# if(add_deb_detail     VALUE) set(Detail     ${VALUE} PARENT_SCOPE) endif(add_deb_detail     VALUE)
+
+
+# set(Package         "")
+# set(Version         "")
+# set(Architecture    "")
+# set(Maintainer      "")
+# set(Email           "")
+# set(Descrition      "")
+
+function(find_str _IN _SEP _OUT)
+    string(FIND "${_IN}" "${_SEP}" _TMP)
+    set(${_OUT} ${_TMP} PARENT_SCOPE)
+endfunction(find_str _IN _SEP _OUT)
+
+
+function(find_next _IN _OUT)
+    find_str("${_IN}" "\n" _TMP)
+    set(${_OUT} ${_TMP} PARENT_SCOPE)
+endfunction(find_next _IN _OUT)
+
+function(sub_next _IN _INDEX _OUT __OUT)
+    find_next(${_IN} _NEXTINDEX)
+    string(SUBSTRING "${_IN}" ${_INDEX} ${_NEXTINDEX} _TMP)
+    math(EXPR _NEXTINDEX ${_NEXTINDEX}+1)
+    string(SUBSTRING "${_IN}" ${_NEXTINDEX} -1 __TMP)
+    set(${_OUT} ${_TMP} PARENT_SCOPE)
+    set(${__OUT} ${__TMP} PARENT_SCOPE)
+endfunction(sub_next _IN _INDEX _OUT)
+
+function(trim_str _IN _OUT)
+    string(STRIP "${_IN}" _TMP)
+    set(${_OUT} ${_TMP} PARENT_SCOPE)
+endfunction(trim_str _IN _OUT)
+
+function(split_str _IN _SEP _OUT)
+    string(FIND "${_IN}" "${_SEP}" _TMP_INDEX)
+    if(NOT _TMP_INDEX EQUAL -1)
+        string(SUBSTRING "${_IN}" 0 ${_TMP_INDEX} _TMP)
+        math(EXPR _TMP_INDEX ${_TMP_INDEX}+1)
+        string(SUBSTRING "${_IN}" ${_TMP_INDEX} -1 __TMP)
+        set(${_OUT} "${_TMP};${__TMP}" PARENT_SCOPE)
+    else()
+        set(${_OUT} ${_IN} PARENT_SCOPE)
+    endif(NOT _TMP_INDEX EQUAL -1)
+endfunction(split_str _IN _SEP _OUT)
+
+function(split_str_p _IN _SEP _OUT __OUT)
+    split_str("${_IN}" "${_SEP}" _TMP)
+    list(GET _TMP 0 __TMP)
+    list(GET _TMP 1 ___TMP)
+    set(${_OUT} ${__TMP} PARENT_SCOPE)
+    set(${__OUT} ${___TMP} PARENT_SCOPE)
+endfunction(split_str_p _IN _SEP _OUT __OUT)
+
+function(split_str_n _IN _SEP _OUT _N)
+    if(_N GREATER 1)
+        set(_C ${_N})
+        set(_RET "")
+        set(_NEXT ${_IN})
+        while(NOT _C EQUAL 0)
+            split_str("${_NEXT}" "${_SEP}" _TMP)
+            list(LENGTH _TMP _TMP_LEN)
+            if(_TMP_LEN EQUAL 2)
+                list(GET _TMP 0 __TMP)
+                list(GET _TMP 1 _NEXT)
+                list(APPEND _RET ${__TMP})
+            else()
+                break()
+            endif(_TMP_LEN EQUAL 2)
+            math(EXPR _C "${_C}-1")
+        endwhile(NOT _C EQUAL 0)
+        list(APPEND _RET ${_NEXT})
+        set(${_OUT} ${_RET} PARENT_SCOPE)
+    else()
+        split_str("${_IN}" "${_SEP}" _TMP)
+        set(${_OUT} ${_TMP} PARENT_SCOPE)
+    endif(_N GREATER 1)
+endfunction(split_str_n _IN _SEP _OUT _N)
+
+
+function(set_package_vars _IN_KEY _IN_VAL)
+
+    # trim_str("${_IN_KEY}" _IN_KEY)
+
+    find_str("${_IN_KEY}" "Type" _Type)
+    if(_Type EQUAL "0")
+        string(TOUPPER "${_IN_VAL}" _IN_VAL_UPPER)
+        string(TOLOWER "${_IN_VAL}" _IN_VAL_LOWER)
+        set(CPACK_GENERATOR "${_IN_VAL_UPPER}" PARENT_SCOPE)
+        message("--> 软件包类型: ${_IN_VAL_LOWER}")
+    endif(_Type EQUAL "0")
+
+    find_str("${_IN_KEY}" "Package" _Package)
+    if(_Package EQUAL "0")
+        if(_IN_VAL STREQUAL "auto")
+            set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}" PARENT_SCOPE)
+        else()
+            set(CPACK_DEBIAN_PACKAGE_NAME "${_IN_VAL}" PARENT_SCOPE)
+        endif(_IN_VAL STREQUAL "auto")
+        message("--> 软件包名: ${_IN_VAL}")
+    endif(_Package EQUAL "0")
+
+    find_str("${_IN_KEY}" "Version" _Version)
+    if(_Version EQUAL "0")
+        if(_IN_VAL STREQUAL "auto")
+            set(CPACK_DEBIAN_PACKAGE_VERSION "${PROJECT_VERSION}" PARENT_SCOPE)
+        else()
+            set(CPACK_DEBIAN_PACKAGE_VERSION "${_IN_VAL}" PARENT_SCOPE)
+        endif(_IN_VAL STREQUAL "auto")
+
+        message("--> 软件版本: ${_IN_VAL}")
+    endif(_Version EQUAL "0")
+
+    find_str("${_IN_KEY}" "CalVer" _CalVer)
+    if(_CalVer EQUAL "0")
+        set(CalVer "${_IN_VAL}" PARENT_SCOPE)
+        message("--> 日历化版本: ${_IN_VAL}")
+    endif(_CalVer EQUAL "0")
+
+    find_str("${_IN_KEY}" "Architecture" _Architecture)
+    if(_Architecture EQUAL "0")
+        set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${_IN_VAL}" PARENT_SCOPE)
+        if(_IN_VAL STREQUAL "auto")
+            execute_process(
+                COMMAND dpkg --print-architecture
+                OUTPUT_VARIABLE _RETV
+                OUTPUT_STRIP_TRAILING_WHITESPACE
+            )
+            set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${_RETV}" PARENT_SCOPE)
+        endif(_IN_VAL STREQUAL "auto")
+        message("--> 软件架构: ${_IN_VAL}")
+    endif(_Architecture EQUAL "0")
+
+    find_str("${_IN_KEY}" "Priority" _Priority)
+    if(_Priority EQUAL "0")
+        set(CPACK_DEBIAN_PACKAGE_PRIORITY "${_IN_VAL}" PARENT_SCOPE)
+        message("--> 优先级: ${_IN_VAL}")
+    endif(_Priority EQUAL "0")
+
+    find_str("${_IN_KEY}" "Depends" _Depends)
+    if(_Depends EQUAL "0")
+        set(CPACK_DEBIAN_PACKAGE_DEPENDS "${_IN_VAL}" PARENT_SCOPE)
+        message("--> 软件依赖: ${_IN_VAL}")
+    endif(_Depends EQUAL "0")
+
+    find_str("${_IN_KEY}" "Maintainer" _Maintainer)
+    if(_Maintainer EQUAL "0")
+        set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${_IN_VAL}" PARENT_SCOPE)
+        message("--> 软件维护者: ${_IN_VAL}")
+    endif(_Maintainer EQUAL "0")
+
+    find_str("${_IN_KEY}" "Homepage" _Homepage)
+    if(_Homepage EQUAL "0")
+        set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${_IN_VAL}" PARENT_SCOPE)
+        message("--> 软件主页: ${_IN_VAL}")
+    endif(_Homepage EQUAL "0")
+
+    find_str("${_IN_KEY}" "Recommends" _Recommends)
+    if(_Recommends EQUAL "0")
+        set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "${_IN_VAL}" PARENT_SCOPE)
+        message("--> 软件建议: ${_IN_VAL}")
+    endif(_Recommends EQUAL "0")
+
+endfunction(set_package_vars _IN_KEY _IN_VAL)
+
+# 定义一个自定义(add_package_descript)函数
+# 用于按特定配置约定自动化构建软件包配置
+function(add_package_descript IN_DES)
+    set(PACKAGE_DES_PATH "${IN_DES}")
+
+    if(EXISTS ${IN_DES})
+
+    elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${IN_DES}")
+        set(PACKAGE_DES_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${IN_DES}")
+    else()
+        message(FATAL_ERROR "!! Not Found Path: ${PACKAGE_DES_PATH}")
+        return()
+    endif(EXISTS ${IN_DES})
+
+    file(READ ${PACKAGE_DES_PATH} DES_CONTENT)
+    trim_str("${DES_CONTENT}" DES_CONTENT)
+
+    ################## 解析 ##################
+
+    sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
+    set(PREV_DES "")
+    while(NOT DES_LINE STREQUAL "${PREV_DES}")
+        # 检查该描述行是否是 # 注释开头,是的话将跳过该行
+        find_str("${DES_LINE}" "#" _COMMENT)
+        if(_COMMENT EQUAL "0")
+            message("--> !!!!!!! ${DES_LINE}")
+            sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
+            continue()
+        endif(_COMMENT EQUAL "0")
+
+        # 检查该描述行是否是 Descrition 开头,是的话说明描述结尾了
+        find_str("${DES_LINE}" "Descrition" _DESCRIPTION)
+        if(_DESCRIPTION EQUAL "0")
+            break()
+        endif(_DESCRIPTION EQUAL "0")
+
+        split_str_n("${DES_LINE}" ":" _TMP 1)
+        list(LENGTH _TMP _TMP_LEN)
+
+        if(_TMP_LEN EQUAL 2)
+            split_str_p("${DES_LINE}" ":" _TMP __TMP)
+            trim_str("${__TMP}" __TMP)
+            string(LENGTH "${__TMP}" __TMP_LENGTH)
+            if(NOT __TMP_LENGTH EQUAL "0")
+                set_package_vars("${_TMP}" "${__TMP}")
+            endif(NOT __TMP_LENGTH EQUAL "0")
+        endif(_TMP_LEN EQUAL 2)
+
+        # 记录当前行,获取下一行,可能是已经结尾了(将保持重复行)
+        set(PREV_DES "${DES_LINE}")
+        sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
+    endwhile(NOT DES_LINE STREQUAL "${PREV_DES}")
+
+
+    # 再一次检查该描述行是否是 Descrition 开头,是的话将进行分析描述行
+    find_str("${DES_LINE}" "Descrition" _DESCRIPTION)
+    if(_DESCRIPTION EQUAL "0")
+        split_str_p("${DES_LINE}" ":" _TMP __TMP)
+        trim_str("${__TMP}" __TMP)
+        set(Descrition ${__TMP})
+        set(PREV_DES_LINE "")
+        while(NOT PREV_DES_LINE STREQUAL DES_LINE)
+            if(NOT PREV_DES_LINE STREQUAL "")
+                set(Descrition "${Descrition}\n${DES_LINE}")
+            endif(NOT PREV_DES_LINE STREQUAL "")
+            set(PREV_DES_LINE "${DES_LINE}")
+            sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
+        endwhile(NOT PREV_DES_LINE STREQUAL DES_LINE)
+        # set(Descrition "${Descrition}")
+        message("--> 软件说明: ${Descrition}")
+
+        set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${Descrition})
+    endif(_DESCRIPTION EQUAL "0")
+
+    ##################### deb #####################
+    # ARCHITECTURE
+    if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
+        set(ARCHITECTURE "amd64")
+    elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "aarch64")
+        set(ARCHITECTURE "arm64")
+    endif()
+
+    #################### Calendar Version ###################
+    if("${CalVer}" STREQUAL "true")
+        string(TIMESTAMP BUILD_TIME "%Y%m%d")
+        set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_DEBIAN_PACKAGE_VERSION}-${BUILD_TIME}")
+    endif("${CalVer}" STREQUAL "true")
+
+
+
+    ##################### deb file name #####################
+    set(_Package      "${CPACK_DEBIAN_PACKAGE_NAME}")
+    set(_Version      "${CPACK_DEBIAN_PACKAGE_VERSION}")
+    set(_Architecture "${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
+
+    set(_DebFileName
+        "${_Package}_${_Version}_${_Architecture}${PACKAGE_SUFFIX}.deb"
+    )
+    set(CPACK_DEBIAN_FILE_NAME            ${_DebFileName})
+
+
+    # set(CPACK_DEBIAN_PACKAGE_NAME         "${Package}")
+    # set(CPACK_DEBIAN_PACKAGE_VERSION      "${Version}")
+    # set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${Architecture}")
+    # set(CPACK_DEBIAN_PACKAGE_DEPENDS      "${Depends}")
+    # set(CPACK_DEBIAN_PACKAGE_PRIORITY     "${Priority}")
+    # set(CPACK_DEBIAN_PACKAGE_MAINTAINER   "${Maintainer}")
+    # set(CPACK_DEBIAN_PACKAGE_DESCRIPTION  "${Descrition}")
+
+    # 设置即将使用的标准脚本
+    # set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
+    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/preinst"
+    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/postinst"
+    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/prerm"
+    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/postrm"
+    # )
+
+    # 设置为ON,以便使用 dpkg-shlibdeps 生成更好的包依赖列表。
+    # set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+    # set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
+    # set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY "=")
+
+    include(CPack)
+
+endfunction(add_package_descript IN_DES)
+
+
+# TODO:
+# CPACK_GENERATOR
+# CPACK_DEBIAN_FILE_NAME                - n
+# CPACK_DEBIAN_PACKAGE_NAME             - y
+# CPACK_DEBIAN_PACKAGE_VERSION          - y
+# CPACK_DEBIAN_PACKAGE_ARCHITECTURE     - y(auto)
+# CPACK_DEBIAN_PACKAGE_DEPENDS          - y
+# CPACK_DEBIAN_PACKAGE_PRIORITY         - y
+# CPACK_DEBIAN_PACKAGE_MAINTAINER       - y
+# CPACK_DEBIAN_PACKAGE_DESCRIPTION      - y
+
+# ARCHITECTURE
+# if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
+#     set(ARCHITECTURE "amd64")
+# elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "aarch64")
+#     set(ARCHITECTURE "arm64")
+# endif()
+
+# string(TIMESTAMP BUILD_TIME "%Y%m%d")

+ 164 - 0
cmake/NoteadPlugin-Linux-Development.md

@@ -0,0 +1,164 @@
+# NotepadPlugin 开发说明
+
+> 当前插件实现的提供 Linux 层开发说明
+
+- 引用 NotepadPluginConfig.cmake 中的说明
+
+    ```cmake
+    # NotepadPluginConfig.cmake
+    # 用于 Notepad-- 插件实现的 CMake 模块初级定义
+
+    # 在 Linux 中,它的布局应该如下:
+    # /usr/lib/x86_64-linux-gnu/cmake/NotepadPlugin/NotepadPluginConfig.cmake
+
+    # 在 插件开发层中,它的使用如下:
+        # 1. 查找 NotepadPlugin 模块
+            # find_package(NotepadPlugin)
+        # 2. 使用 add_notepad_plugin(<模块名称> <源代码、资源文件> [...])
+            # add_notepad_plugin(<plugin_name> <plugin_srcs> ...)
+    ```
+
+- 着手进行实现插件
+
+    > 将项目中的 src/plugin/helloworld 复制为单个项目,并使用 CMake 进行构建
+
+    ```cmake
+    cmake_minimum_required(VERSION 3.5.1)
+
+    project(template LANGUAGES CXX VERSION 0.0.1)
+
+    # 1. 查找 NotepadPlugin 模块
+    find_package(NotepadPlugin REQUIRED)
+
+    # 2. 使用 add_notepad_plugin(<模块名称> <源代码、资源文件> [...])
+    add_notepad_plugin(Helloworld
+        helloworld/helloworldexport.cpp
+        helloworld/qttestclass.cpp
+        helloworld/qttestclass.h
+        helloworld/qttestclass.ui
+    )
+
+    # 以上将会构建出一个名叫 libHelloworld.so 的插件扩展
+    ```
+
+- 一些 NotepadPluginConfig.cmake 中的变量声明
+
+    ```cmake
+
+    # NOTEPAD_PLUGIN                                   [不重要]CMake 模块名称
+    # NOTEPAD_PLUGIN_CONFIG                            [不重要]CMake 模块文件名名称
+    # NOTEPAD_PLUGIN_INCLUDEDIR                        [插件 头文件目录]插件开发者可自行使用
+    # NOTEPAD_PLUGIN_LIBDIR                            [插件 库存放目录]插件开发者可自行使用
+    # NOTEPAD_PLUGIN_CORELIB                           [插件 核心库名称]插件开发者可自行使用
+    # NOTEPAD_PLUGIN_EXTERNAL_INCLUDES                 [插件 扩展的头文件目录]插件开发者可自行使用
+    # NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY [插件 扩展插件安装目录(位置)]插件开发者可自行使用
+
+    # NOTEPAD_BUILD_BY_QT5     
+    # NOTEPAD_BUILD_BY_QT6     
+        [NOTEPAD_BUILD_BY_约定]如果在构建 Notepad-- 时开启了此项,将会向 CMake 构建系统询问相关模块
+
+    例如:
+        询问 Qt5 基本模块: 将会在 find_package(NotepadPlugin REQUIRED) 时自动加入
+            set(CMAKE_AUTOMOC ON)
+            set(CMAKE_AUTOUIC ON)
+            find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
+
+        为开发者自动添加 Qt5 模块依赖: 将会在 add_notepad_plugin 时自动加入
+            if(NOTEPAD_PLUGIN_QT5)
+                target_link_libraries(${PLUGIN_VAR} Qt5::Core Qt5::Widgets)
+            endif(NOTEPAD_PLUGIN_QT5)
+
+    ```
+
+- 当前提供插件的 Linux 目录结构
+
+    ```
+    build/_CPack_Packages/Linux/DEB/notepad---1.22.0-Linux
+    ├── control
+    ├── control.tar.gz
+    ├── data.tar.gz
+    ├── debian-binary
+    ├── md5sums
+    └── usr
+        ├── bin
+        │   └── notepad--
+        ├── include
+        │   └── NotepadPlugin
+        │       ├── pluginGl.h
+        │       └── Qsci
+        │           ├── qsciabstractapis.h
+        │           ├── qsciapis.h
+        │           ├── qscicommand.h
+        │           ├── qscicommandset.h
+        │           ├── qscidocument.h
+        │           ├── qsciglobal.h
+        │           ├── qscilexerasm.h
+        │           ├── qscilexeravs.h
+        │           ├── qscilexerbash.h
+        │           ├── qscilexerbatch.h
+        │           ├── qscilexercmake.h
+        │           ├── qscilexercoffeescript.h
+        │           ├── qscilexercpp.h
+        │           ├── qscilexercsharp.h
+        │           ├── qscilexercss.h
+        │           ├── qscilexercustom.h
+        │           ├── qscilexerd.h
+        │           ├── qscilexerdiff.h
+        │           ├── qscilexeredifact.h
+        │           ├── qscilexerfortran77.h
+        │           ├── qscilexerfortran.h
+        │           ├── qscilexerglobal.h
+        │           ├── qscilexergo.h
+        │           ├── qscilexer.h
+        │           ├── qscilexerhtml.h
+        │           ├── qscilexeridl.h
+        │           ├── qscilexerjava.h
+        │           ├── qscilexerjavascript.h
+        │           ├── qscilexerjson.h
+        │           ├── qscilexerlua.h
+        │           ├── qscilexermakefile.h
+        │           ├── qscilexermarkdown.h
+        │           ├── qscilexermatlab.h
+        │           ├── qscilexernsis.h
+        │           ├── qscilexeroctave.h
+        │           ├── qscilexerpascal.h
+        │           ├── qscilexerperl.h
+        │           ├── qscilexerpo.h
+        │           ├── qscilexerpostscript.h
+        │           ├── qscilexerpov.h
+        │           ├── qscilexerproperties.h
+        │           ├── qscilexerpython.h
+        │           ├── qscilexerruby.h
+        │           ├── qscilexerrust.h
+        │           ├── qscilexerspice.h
+        │           ├── qscilexersql.h
+        │           ├── qscilexertcl.h
+        │           ├── qscilexertex.h
+        │           ├── qscilexertext.h
+        │           ├── qscilexervb.h
+        │           ├── qscilexerverilog.h
+        │           ├── qscilexervhdl.h
+        │           ├── qscilexerxml.h
+        │           ├── qscilexeryaml.h
+        │           ├── qscimacro.h
+        │           ├── qsciprinter.h
+        │           ├── qsciscintillabase.h
+        │           ├── qsciscintilla.h
+        │           ├── qscistyledtext.h
+        │           └── qscistyle.h
+        ├── lib
+        │   ├── cmake
+        │   │   └── NotepadPlugin
+        │   │       └── NotepadPluginConfig.cmake
+        │   └── NotepadPlugin
+        │       └── libQSci.a
+        └── share
+            ├── applications
+            │   └── notepad--.desktop
+            └── notepad--
+                └── icons
+                    └── spark.png
+
+    13 directories, 71 files
+
+    ```

+ 218 - 0
cmake/NotepadPluginConfig.cmake.in

@@ -0,0 +1,218 @@
+# NotepadPluginConfig.cmake
+# 用于 Notepad-- 插件实现的 CMake 模块初级定义
+
+# 在 Linux 中,它的布局应该如下:
+# /usr/lib/x86_64-linux-gnu/cmake/NotepadPlugin/NotepadPluginConfig.cmake
+
+# 在 插件开发层中,它的使用如下:
+    # 1. 查找 NotepadPlugin 模块
+        # find_package(NotepadPlugin)
+    # 2. 使用 add_notepad_plugin(<模块名称> <源代码、资源文件> [...])
+        # add_notepad_plugin(<plugin_name> <plugin_srcs> ...)
+
+# 一些无关紧要的部分,如果需要实现插件安装操作时,即可进行使用
+# include(CMakePackageConfigHelpers)
+# include(GNUInstallDirs)
+ 
+# 主要内容,在构建时的填充
+set(NOTEPAD_PLUGIN              @NOTEPAD_PLUGIN@)
+set(NOTEPAD_BUILD_BY_QT5        @NOTEPAD_BUILD_BY_QT5@)
+set(NOTEPAD_BUILD_BY_QT6        @NOTEPAD_BUILD_BY_QT6@)
+set(NOTEPAD_BUILD_BY_SHARED     FALSE)
+set(NOTEPAD_PLUGIN_CORELIB      @NOTEPAD_PLUGIN_CORELIB@)
+# 由插件开发者进行参考的 "Notepad 提供的插件安装目录(位置)" 
+set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY 
+        @NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_DIRECTORY@)
+
+# 这些是被废除的内容
+# set(NOTEPAD_PLUGIN_INCLUDEDIR   @NOTEPAD_PLUGIN_INCLUDEDIR@)
+# set(NOTEPAD_PLUGIN_LIBDIR       @NOTEPAD_PLUGIN_LIBDIR@)
+
+# 一些核心位置设定参考
+# ./usr/bin/
+# ./usr/bin/notepad--
+# ./usr/include/
+# ./usr/include/NotepadPlugin/
+# ./usr/include/NotepadPlugin/Qsci/
+# ./usr/include/NotepadPlugin/Qsci/...
+# ./usr/include/NotepadPlugin/qscint/
+# ./usr/include/NotepadPlugin/qscint/scintilla/src/XPM.cp
+# ./usr/lib/
+# ./usr/lib/NotepadPlugin/
+# ./usr/lib/NotepadPlugin/libQSci.a
+# ./usr/lib/cmake/
+# ./usr/lib/cmake/NotepadPlugin/
+# ./usr/lib/cmake/NotepadPlugin/NotepadPluginConfig.cmake
+#                              ^ 以此文件目录位置开始,Linux/Windows中都相同,但不是写死路径
+#                                ../                为 /usr/lib/cmake 目录
+#                                ../../             为 /usr/lib 目录
+#                                ../../../          为 /usr 目录
+#                                ../../../include   为 /usr/include 目录
+#                                ../../../lib       为 /usr/lib 目录
+
+#                                ../../../include/NotepadPlugin     # (/usr)头文件目录(NOTEPAD_PLUGIN_INCLUDEDIR)
+#                                ../../NotepadPlugin                # (/usr/lib)库文件目录(NOTEPAD_PLUGIN_LIBDIR)
+#                                ../../cmake                        # (/usr/lib)cmake文件目录(无需关心)
+set(NOTEPAD_PLUGIN_INCLUDEDIR
+    ${CMAKE_CURRENT_LIST_DIR}/../../../include/${NOTEPAD_PLUGIN}
+    ${CMAKE_CURRENT_LIST_DIR}/../../../include/${NOTEPAD_PLUGIN}/Qsci)
+set(NOTEPAD_PLUGIN_LIBDIR       
+    ${CMAKE_CURRENT_LIST_DIR}/../../${NOTEPAD_PLUGIN})
+
+if(NOTEPAD_BUILD_BY_QT5)
+    set(CMAKE_AUTOMOC ON)
+    set(CMAKE_AUTOUIC ON)
+    set(CMAKE_AUTORCC ON)
+    find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
+endif(NOTEPAD_BUILD_BY_QT5)
+
+if(NOTEPAD_BUILD_BY_QT6)
+    set(CMAKE_AUTOMOC ON)
+    set(CMAKE_AUTOUIC ON)
+    set(CMAKE_AUTORCC ON)
+    find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
+endif(NOTEPAD_BUILD_BY_QT6)
+
+if(NOTEPAD_BUILD_BY_SHARED)
+    set(NOTEPAD_IMPORTED_CORELIB_PATH ${NOTEPAD_PLUGIN_LIBDIR}/lib${NOTEPAD_PLUGIN_CORELIB}.so)
+    add_library(${NOTEPAD_PLUGIN} SHARED IMPORTED)
+    set_target_properties(${${NOTEPAD_PLUGIN}} PROPERTIES 
+        IMPORTED_LOCATION 
+            ${NOTEPAD_IMPORTED_CORELIB_PATH}
+        INCLUDE_DIRECTORIES 
+            "${NOTEPAD_PLUGIN_INCLUDEDIR}"
+    )
+else()
+    set(NOTEPAD_IMPORTED_CORELIB_PATH ${NOTEPAD_PLUGIN_LIBDIR}/lib${NOTEPAD_PLUGIN_CORELIB}.a)
+    add_library(${NOTEPAD_PLUGIN} STATIC IMPORTED)
+    set_target_properties(${${NOTEPAD_PLUGIN}} PROPERTIES 
+        IMPORTED_LOCATION 
+            ${NOTEPAD_IMPORTED_CORELIB_PATH}
+        INCLUDE_DIRECTORIES 
+            "${NOTEPAD_PLUGIN_INCLUDEDIR}"
+    )
+endif()
+
+if(CMAKE_HOST_UNIX)
+    # 在 Linux 中开启 compile_commands.json 文件输出,增强 clangd 能力
+    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)   
+endif(CMAKE_HOST_UNIX)
+
+# add_notepad_plugin(<PLUGIN_VAR> <PLUGIN_SRC> [...])
+# 此宏定义了,基于源代码文件构建 Notepad-- 插件时所需要的一系列流程内容
+macro(add_notepad_plugin PLUGIN_VAR PLUGIN_SRC)
+    # aux_source_directory(${PLUGIN_VAR}_SOURCES  ${ARGN})
+    add_library(${PLUGIN_VAR} SHARED ${PLUGIN_SRC} ${ARGN})
+    
+    if(CMAKE_HOST_WIN32)
+        # Win32 已提供宏判断
+        # target_compile_definitions(${PLUGIN_VAR} PUBLIC NDD_EXPORT=export)
+    endif(CMAKE_HOST_WIN32)
+
+    if(CMAKE_HOST_UNIX)
+        target_compile_definitions(${PLUGIN_VAR} PUBLIC NDD_EXPORT=)
+    endif(CMAKE_HOST_UNIX)
+    
+    # ------------ 为在不同平台构建的插件定义输出名称(尾巴) ------------- #
+    # <OS>          平台:  Windows/MacOS/Linux
+    # <ARCH>        架构:  X86_64、AMD64、ARM64、....
+    # <COMPILER>    编译器:MinGW、Cygwin、MSVC、GNU、Clang、Intel....
+    # <QT>          Qt版本:
+    set(${PLUGIN_VAR}_OUTPUT_NAME ${PLUGIN_VAR})
+
+    # <OS> ------- 确定平台 Apple/Linux/Windows ------------------- #
+    if(APPLE)
+        string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_MacOS")
+    elseif(UNIX AND NOT APPLE AND NOT WIN32 AND NOT ANDROID)
+        string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_Linux")
+    elseif(WIN32)
+        string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_Win32")
+    endif()
+
+    # <ARCH> ------- 确定架构 X86_64/AMD64/ARM64/... -------------- #
+    string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_${CMAKE_HOST_SYSTEM_PROCESSOR}")
+    # if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
+    #     if(CMAKE_APPLE_SILICON_PROCESSOR)
+    #         string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_Silicon")
+    #     endif(CMAKE_APPLE_SILICON_PROCESSOR)
+    # endif(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
+    
+    # <COMPILER> ----- 确定编译器类型 
+    # string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_MinGW")
+    if(WIN32)
+        if(MINGW)
+            string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_MinGW")
+        elseif(CYGWIN)
+            string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_Cygwin")
+        elseif(MSVC)
+            string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_MSVC")
+        else() # 如果不是 MinGW、 Cygwin 、MSVC
+            if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "")
+                string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_Unknow")
+            else() # 如果不是 CMAKE_CXX_COMPILER_ID 不为空
+                string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_${CMAKE_CXX_COMPILER_ID}")
+            endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "")
+        endif()
+    else()
+        # 此处:如果不提前进行 MINGW 判断,MINGW 也将会是 GNU
+        string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_${CMAKE_CXX_COMPILER_ID}")
+    endif()
+
+    # 预留: GNU Compiler 系列并不清楚如何区分
+    # if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
+        # string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_GCC")
+    # endif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
+
+    # <Qt 版本尾巴规划:待确定,目前使用 Qt5/Qt6 进行区分>
+    # if(NOT "${Qt5_}" STREQUAL "")
+    #     string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_${QT_VERSION}")
+    # endif(NOT "${QT_VERSION}" STREQUAL "")
+    if(NOTEPAD_BUILD_BY_QT5)
+        string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_Qt5")
+    else()
+        string(APPEND ${PLUGIN_VAR}_OUTPUT_NAME "_Qt6")
+    endif(NOTEPAD_BUILD_BY_QT5)
+    
+    
+    set_property(TARGET ${PLUGIN_VAR}
+            PROPERTY
+                OUTPUT_NAME "${${PLUGIN_VAR}_OUTPUT_NAME}")
+    # ------------ 为构建的插件配置尾巴 ------------- #
+
+    # Notepad-- 插件开发时应该使用的 头文件安装目录、库文件安装目录
+    target_include_directories(${PLUGIN_VAR} PUBLIC 
+        ${NOTEPAD_PLUGIN_INCLUDEDIR})
+    target_link_directories(${PLUGIN_VAR} PUBLIC 
+        ${NOTEPAD_PLUGIN_LIBDIR})
+    target_link_libraries(${PLUGIN_VAR} ${NOTEPAD_PLUGIN_CORELIB})
+    if(NOTEPAD_BUILD_BY_QT5)
+        target_link_libraries(${PLUGIN_VAR} Qt5::Core Qt5::Widgets)
+    endif(NOTEPAD_BUILD_BY_QT5)
+
+    if(NOTEPAD_BUILD_BY_QT6)
+        target_link_libraries(${PLUGIN_VAR} Qt6::Core Qt6::Widgets)
+    endif(NOTEPAD_BUILD_BY_QT6)
+
+    # 这是插件实现接口中增加的 NOTEPAD_PLUGIN_MANAGER 宏开关
+        # 来处理减少 Notepad-- 在编译时不需要,但在插件编译时所需要的模板内容
+    target_compile_definitions(${PLUGIN_VAR} PUBLIC NOTEPAD_PLUGIN_MANAGER=)
+    
+endmacro(add_notepad_plugin PLUGIN_VAR PLUGIN_SRC)
+
+# support git plugin
+# add_notepad_plugin_with_git <plugin_name> <git_repo_url> <plugin_sources_path>
+# 该宏定义了从指定的 git 仓库中获取插件源代码,并进行简单的构建
+macro(add_notepad_plugin_with_git PLUGIN_VAR GIT_REPO_URL GIT_REPO_PLUGIN_PATH)
+    execute_process(COMMAND git clone ${GIT_REPO_URL} ${PLUGIN_VAR}_git
+        WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+    aux_source_directory(${CMAKE_BINARY_DIR}/${PLUGIN_VAR}_git/${GIT_REPO_PLUGIN_PATH} ${PLUGIN_VAR}_RESOURCES)
+    add_notepad_plugin(${PLUGIN_VAR} ${${PLUGIN_VAR}_RESOURCES})
+endmacro(add_notepad_plugin_with_git PLUGIN_VAR GIT_REPO_URL GIT_REPO_PLUGIN_PATH)
+
+message("- >>>>>>>>>>>>>>>>>> NotepadPlugin: <<<<<<<<<<<<<<<<<<")
+message("  - ${CMAKE_CURRENT_LIST_FILE}")
+message("  - ${NOTEPAD_PLUGIN_INCLUDEDIR}")
+message("  - ${NOTEPAD_PLUGIN_LIBDIR}")
+message("  - ${NOTEPAD_PLUGIN_CORELIB}")
+message("  - ${NOTEPAD_IMPORTED_CORELIB_PATH}")
+message("- >>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<")

+ 139 - 0
cmake/SparkAppimageConfig.cmake

@@ -0,0 +1,139 @@
+# export PATH=/usr/lib/x86_64-linux-gnu/qt5/bin:$PATH
+# export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
+# export QT_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/qt5/plugins:$QT_PLUGIN_PATH
+# export QML2_IMPORT_PATH=/usr/lib/x86_64-linux-gnu/qt5/qml:$QML2_IMPORT_PATH
+
+# export PATH=/usr/lib/x86_64-linux-gnu/qt5/bin:$PATH
+# ~/linuxdeployqt-continuous-x86_64.AppImage spark-store-submitter -appimage
+# cd ..
+# ~/appimagetool-x86_64.AppImage appimage/
+
+# LINUXDEPLOYQT=/home/zinface/linuxdeployqt-continuous-x86_64.AppImage
+# APPIMAGETOOL=/home/zinface/appimagetool-x86_64.AppImage
+
+# if ()
+set(APPIMAGE_OUTPUT  "${CMAKE_BINARY_DIR}/appimage")
+set(APPIMAGE_ICON    "${APPIMAGE_OUTPUT}/default.png")
+set(APPIMAGE_DESTKOP "${APPIMAGE_OUTPUT}/default.desktop")
+# set(LINUXDEPLOYQT)
+# set(APPIMAGETOOL)
+
+function(execute_linuxdeploy _PATH)
+    execute_process(COMMAND ${LINUXDEPLOYQT}
+        WORKING_DIRECTORY "${APPIMAGE_OUTPUT}"
+        )
+endfunction(execute_linuxdeploy _PATH)
+
+function(target_linuxdeploy)
+    add_custom_target(linuxdeploy pwd
+        BYPRODUCTS appimage
+        COMMAND cp ../${PROJECT_NAME} .
+        COMMAND "${LINUXDEPLOYQT}" ${PROJECT_NAME} -appimage -unsupported-allow-new-glibc -verbose=3 -no-strip|| true
+        COMMAND cp ../spark-appimage.desktop default.desktop
+        COMMAND cp ../spark-appimage.png     default.png
+        WORKING_DIRECTORY "${APPIMAGE_OUTPUT}")
+endfunction(target_linuxdeploy)
+
+function(target_appimage)
+    add_custom_target(copy-desktop-appimage
+        COMMAND cp ../spark-appimage.desktop default.desktop
+        COMMAND cp ../spark-appimage.png     default.png
+        WORKING_DIRECTORY "${APPIMAGE_OUTPUT}")
+    add_custom_target(appimage pwd
+        COMMAND ${APPIMAGETOOL} ${APPIMAGE_OUTPUT}
+        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+        DEPENDS copy-desktop-appimage)
+endfunction(target_appimage)
+
+function(add_appimage)
+    # check linuxdeploy
+    if(NOT DEFINED LINUXDEPLOYQT)
+        message("AppImage> Not Found LINUXDEPLOYQT Variable!")
+        return()
+    endif(NOT DEFINED LINUXDEPLOYQT)
+    if(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
+        message("> cmake version is less than 3.19")
+        message(WARNING "!Relative paths are not supported!")
+    else()
+        file(REAL_PATH ${LINUXDEPLOYQT} LINUXDEPLOYQT_REAL_PATH)
+    endif(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
+    message("AppImage> Found LINUXDEPLOYQT Variable: ${LINUXDEPLOYQT_REAL_PATH}")
+
+    # check appimagetool
+    if(NOT DEFINED APPIMAGETOOL)
+        message("AppImage> Not Found APPIMAGETOOL Variable!")
+        return()
+    endif(NOT DEFINED APPIMAGETOOL)
+    if(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
+        # execute_process(COMMAND realpath ${APPIMAGETOOL} OUTPUT_VARIABLE APPIMAGETOOL_REAL_PATH)
+        message("> cmake version is less than 3.19")
+        message(WARNING "!Relative paths are not supported!")
+    else()
+        file(REAL_PATH ${APPIMAGETOOL} APPIMAGETOOL_REAL_PATH)
+    endif(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
+    message("AppImage> Found APPIMAGETOOL Variable: ${LINUXDEPLOYQT_REAL_PATH}")
+
+    # do add_custome_target
+    make_directory(${APPIMAGE_OUTPUT})
+    target_linuxdeploy()
+    target_appimage()
+endfunction(add_appimage)
+
+function(add_appimage_desktop)
+    configure_file(cmake/spark-appimage.desktop.in
+        ${CMAKE_BINARY_DIR}/spark-appimage.desktop @ONLY)
+endfunction(add_appimage_desktop)
+
+function(add_appimage_icon _ICON_PATH)
+    if(CMAKE_VERSION VERSION_LESS 3.21)
+        message("> cmake version is less than 3.21")
+        configure_file(${_ICON_PATH} ${CMAKE_BINARY_DIR}/spark-appimage.png COPYONLY)
+    else()
+        file(COPY_FILE ${_ICON_PATH} ${CMAKE_BINARY_DIR}/spark-appimage.png)
+    endif(CMAKE_VERSION VERSION_LESS 3.21)
+endfunction(add_appimage_icon _ICON_PATH)
+
+
+
+# 如果glic>=2.27,你就需要加上参数 -unsupported-allow-new-glibc (意思就是不再低版本发行版使用了)
+# 或 -unsupported-bundle-everything(大概的意思是尝试兼容,实际测试,到其他发行版直接用不了了,有可能是发行版的原因,还是建议用前者,虽然放弃了低版本)
+
+# -unsupported-bundle-everything
+    # 捆绑所有依赖库,包括 ld-linux.so 加载器和 glibc。这将允许构建在较新系统上的应用程序在较旧的目标系统上运行,但不建议这样做,因为它会导致捆绑包超出所需的大小(并且可能到其他发行版无法使用)
+# -unsupported-allow-new-glibc
+    # 允许 linuxdeployqt 在比仍受支持的最旧 Ubuntu LTS 版本更新的发行版上运行。这将导致 AppImage无法在所有仍受支持的发行版上运行,既不推荐也不测试或支持
+
+# ./linuxdeployqt-7-x86_64.AppImage 程序目录/程序 -appimage -unsupported-allow-new-glibc
+# ./linuxdeployqt-7-x86_64.AppImage 程序目录/程序 -appimage -unsupported-bundle-everything
+
+
+
+
+# 1. 在顶层构建中导入 Appimage 的构建
+# include(cmake/SparkAppimageConfig.cmake)  # 导入来自 Spark 构建的 Appimage 构建
+# add_appimage_icon(assets/spark.png)       # 添加到 Appimage 中的默认的图标
+# add_appimage_desktop()                    # 添加到 Appimage 中的默认desktop(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
+# add_appimage()                            # 应用对 Appimage 的构建
+
+# 2. 在 Makefile 进行构建目标构建 Appimage 的构建流 --
+# 在 Makefile 进行构建目标构建 Appimage (要求提供工具的绝对路径,然后可依次进行linuxdeployqt, genrate-appimage)
+# 来自于 https://github.com/probonopd/linuxdeployqt 	的 linuxdeployqt
+# 来自于 https://github.com/AppImage/AppImageKit		的 appimagetool
+# 来自于 https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git  托管存储的工具
+
+# 或指定你所想存放克隆项目的位置
+# BUNDLE_LINUXDEPLOYQT := $(shell pwd)/build/bundle-linuxdeployqt
+
+# download-bundle-linuxdeploytools:
+# 	-git clone https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git $(BUNDLE_LINUXDEPLOYQT)
+
+# LINUXDEPLOYQT := "$(BUNDLE_LINUXDEPLOYQT)/linuxdeployqt-continuous-x86_64.AppImage"
+# APPIMAGETOOL  := "$(BUNDLE_LINUXDEPLOYQT)/appimagetool-x86_64.AppImage"
+
+# linuxdeploy: release download-bundle-linuxdeploytools
+# 	cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
+# 	cd build && make linuxdeploy
+
+# genrate-appimage:
+# 	cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
+# 	cd build && make appimage

+ 36 - 0
cmake/SparkDesktopMacros.cmake

@@ -0,0 +1,36 @@
+
+macro(spark_desktop_macros _APP_NAME _APP_NAME_ZH_CN _APP_COMMENT _APP_TYPE _APP_EXECUTE_PATH _APP_EXECUTE_ICON_PATH _APP_CATEGORIES)
+    set(APP_NAME               ${_APP_NAME})
+    set(APP_NAME_ZH_CN         ${_APP_NAME_ZH_CN})
+    set(APP_COMMENT            ${_APP_COMMENT})
+    set(APP_TYPE               ${_APP_TYPE})
+    set(APP_EXECUTE_PATH       ${_APP_EXECUTE_PATH})
+    set(APP_EXECUTE_ICON_PATH  ${_APP_EXECUTE_ICON_PATH})
+    set(APP_CATEGORIES         ${_APP_CATEGORIES})
+    configure_file(cmake/spark-desktop.desktop.in
+        ${CMAKE_BINARY_DIR}/${_APP_NAME}.desktop
+    )
+    set(SPARK_DESKTOP_FILE ${CMAKE_BINARY_DIR}/${_APP_NAME}.desktop)
+endmacro(spark_desktop_macros _APP_NAME _APP_NAME_ZH_CN _APP_COMMENT _APP_TYPE _APP_EXECUTE_PATH _APP_EXECUTE_ICON_PATH _APP_CATEGORIES)
+
+# include(cmake/SparkDesktopMacros.cmake)
+# 内容默认应用名称: Name= 应与项目名称相同
+# spark_desktop_macros(
+    # 应用名称: Name=
+    # 应用名称: Name[zh_CN]=
+    # 应用说明: Comment=
+    # 应用类型: Type=
+    # 执行程序: Exec=
+    # 图标路径: Icon=
+    # 应用分类: Category=
+# )
+
+# configure_file(<input> <output>
+#                [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
+#                 FILE_PERMISSIONS <permissions>...]
+#                [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
+#                [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
+
+# install(FILES ${APP_NAME}.desktop
+#     DESTINATION /usr/share/applications
+# )

+ 8 - 0
cmake/SparkEnvConfig.cmake

@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.5.1)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+# set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTORCC ON)
+# set(CMAKE_BUILD_TYPE "Debug")

+ 153 - 0
cmake/SparkFindQt5Config.cmake

@@ -0,0 +1,153 @@
+cmake_minimum_required(VERSION 3.5.1)
+
+set(SPARK_FIND_QT5 TRUE)
+
+find_package(Qt5 COMPONENTS Core Widgets Network REQUIRED)
+
+# function(target_link_qt5 NAME)
+#     target_link_libraries(${NAME}
+#         Qt5::Core
+#         Qt5::Widgets
+#         Qt5::Network)
+# endfunction(target_link_qt5 NAME)
+
+# 使用 spark_add_link 生成 target_link_qt5 以替代上面内容
+spark_add_link(qt5 Qt5::Core Qt5::Widgets Qt5::Network)
+
+
+# spark_add_link_qt5
+# 自定义宏 spark_add_link_qt5 以扩展 target_link_qt5_<name> 结构
+    # _IN_NAME: 此宏使用嵌套宏 spark_add_link 时追加 <name> 名称
+    # 同等于 spark_add_link(qt_<name> ${ARGN})
+macro(spark_add_link_qt5 _IN_NAME)
+    spark_add_link(qt5_${_IN_NAME} ${ARGN})
+endmacro(spark_add_link_qt5 _IN_NAME)
+
+# 使用 spark_add_link_qt5 生成 target_link_qt5_<name> 的宏
+# spark_add_link_qt5(Concurrent Qt5::Concurrent)
+
+# 高级自定义
+# spark_add_links_qt5
+# 自定义宏 spark_add_links_qt5 以扩展 spark_add_link_qt5 宏配置组
+    # 特点: 任意长度参数
+    # qt5_item: 为进行遍历后的单项,类似于 python3 中的 (for item in items:)
+    # 例如: qt5_item 为 Core:
+        # spark_add_link_qt5(${qt5_item} Qt5::${qt5_item})
+        # 展开为 spark_add_link_qt5(Core Qt5::Core)
+        # 展开为 spark_add_link(qt5_Core Qt5::Core)
+        # 展开为 spark_add_link(qt5_Core Qt5::Core)
+        # 特性: 增加 qt5_Core 转 qt5_core
+            # string(TOLOWER <string> <output_variable>)
+macro(spark_add_links_qt5)
+    set(qt5_items ${ARGN})
+    foreach(qt5_item IN LISTS qt5_items)
+        find_package(Qt5${qt5_item})
+        spark_add_link_qt5(${qt5_item} Qt5::${qt5_item})
+
+        string(TOLOWER "${qt5_item}" qt5_lower_item)
+        spark_add_link_qt5(${qt5_lower_item} Qt5::${qt5_item})
+        message("add_target_link_qt5_${qt5_item} or add_target_link_qt5_${qt5_lower_item}")
+    endforeach(qt5_item IN LISTS qt5_items)
+endmacro(spark_add_links_qt5)
+
+
+# Core	                用于其它模块的核心非图形类。
+# GUI	                图形用户界面 GUI 组件基类。包括 OpenGL。
+# Multimedia	        音频 视频 无线电 摄像头功能类。
+# Multimedia Widgets	用于实现多媒体功能,基于 Widget 的类。
+# Network	            使网络编程更容易和更可移植的类。
+
+# QML	                QML 和 JavaScript 语言类。
+# Quick	                以自定义用户界面 UI 构建高动态应用程序的声明性框架。
+# Quick Controls	    为桌面、嵌入式及移动设备创建高性能用户界面提供轻量 QML 类型。这些类型运用简单样式化体系结构且非常高效。
+# Quick Dialogs	        用于从 Qt Quick 应用程序创建系统对话框,并与之交互的类型。
+# Quick Layouts	        布局是用于在用户界面中排列基于 Qt Quick 2 项的项。
+# Quick Test	        用于 QML 应用程序的单元测试框架,其测试案例被编写成 JavaScript 函数。
+                        # 注意: 二进制保证不兼容 Qt Quick Test,但源代码仍兼容。
+
+# Qt SQL	            集成使用 SQL 数据库的类。
+# Qt Test	            单元测试 Qt 应用程序和库的类。
+                        # 注意: 二进制保证不兼容 Qt Test,但源代码仍兼容。
+# Qt Widgets	        以 C++ 小部件扩展 Qt GUI 的类。
+
+
+
+# 找出所有 Qt5 模板
+# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5
+
+# 掐头去尾,洗一次
+# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d'
+
+# 排序
+# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d' | sort | pr -t -3
+
+spark_add_links_qt5(
+    # AccessibilitySupport
+    # AttributionsScannerTools
+    Concurrent
+    # Core
+    # DBus
+    # Designer
+    # DesignerComponents
+    # DeviceDiscoverySupport
+    # DocTools
+    # EdidSupport
+    # EglFSDeviceIntegration
+    # EglFsKmsSupport
+    # EglSupport
+    # EventDispatcherSupport
+    # FbSupport
+    # FontDatabaseSupport
+    # GlxSupport
+    Gui
+    # Help
+    # InputSupport
+    # KmsSupport
+    # LinguistTools
+    # LinuxAccessibilitySupport
+    # Network
+    # OpenGL
+    # OpenGLExtensions
+    # PacketProtocol
+    # PlatformCompositorSupport
+    # Positioning
+    # PositioningQuick
+    PrintSupport
+    # Qml
+    # QmlDebug
+    # QmlDevTools
+    # QmlImportScanner
+    # QmlModels
+    # QmlWorkerScript
+    # Quick
+    # QuickCompiler
+    # QuickControls2
+    # QuickParticles
+    # QuickShapes
+    # QuickTemplates2
+    # QuickTest
+    # QuickWidgets
+    # SerialBus
+    # SerialPort
+    # ServiceSupport
+    # Sql
+    # Svg
+    # Test
+    # ThemeSupport
+    # UiPlugin
+    # UiTools
+    # VulkanSupport
+    # WebChannel
+    # WebEngine
+    # WebEngineCore
+    # WebEngineWidgets
+    # WebKit
+    # WebKitWidgets
+    # WebSockets
+    # Widgets
+    # X11Extras
+    # XcbQpa
+    # XkbCommonSupport
+    # Xml
+    XmlPatterns
+)

+ 130 - 0
cmake/SparkFindQt6Config.cmake

@@ -0,0 +1,130 @@
+cmake_minimum_required(VERSION 3.5.1)
+
+set(SPARK_FIND_QT6 TRUE)
+
+find_package(Qt6 COMPONENTS Core Widgets Network REQUIRED)
+
+# function(target_link_qt6 NAME)
+#     target_link_libraries(${NAME}
+#         Qt6::Core
+#         Qt6::Widgets
+#         Qt6::Network)
+# endfunction(target_link_qt6 NAME)
+
+# 使用 spark_add_link 生成 target_link_qt6 以替代上面内容
+spark_add_link(qt6 Qt6::Core Qt6::Widgets Qt6::Network)
+
+
+# spark_add_link_qt6
+# 自定义宏 spark_add_link_qt6 以扩展 target_link_qt6_<name> 结构
+    # _IN_NAME: 此宏使用嵌套宏 spark_add_link 时追加 <name> 名称
+    # 同等于 spark_add_link(qt_<name> ${ARGN})
+macro(spark_add_link_qt6 _IN_NAME)
+    spark_add_link(qt6_${_IN_NAME} ${ARGN})
+endmacro(spark_add_link_qt6 _IN_NAME)
+
+# 使用 spark_add_link_qt6 生成 target_link_qt6_<name> 的宏
+# spark_add_link_qt5(Concurrent Qt6::Concurrent)
+
+# 高级自定义
+# spark_add_links_qt6
+# 自定义宏 spark_add_links_qt6 以扩展 spark_add_link_qt6 宏配置组
+    # 特点: 任意长度参数
+    # qt6_item: 为进行遍历后的单项,类似于 python3 中的 (for item in items:)
+    # 例如: qt6_item 为 Core:
+        # spark_add_link_qt6(${qt6_item} Qt6::${qt6_item})
+        # 展开为 spark_add_link_qt6(Core Qt6::Core)
+        # 展开为 spark_add_link(qt6_Core Qt6::Core)
+        # 展开为 spark_add_link(qt6_Core Qt6::Core)
+        # 特性: 增加 qt6_Core 转 qt6_core
+            # string(TOLOWER <string> <output_variable>)
+macro(spark_add_links_qt6)
+    set(qt6_items ${ARGN})
+    foreach(qt6_item IN LISTS qt6_items)
+        find_package(Qt6${qt6_item})
+        spark_add_link_qt6(${qt6_item} Qt6::${qt6_item})
+
+        string(TOLOWER "${qt6_item}" qt6_lower_item)
+        spark_add_link_qt6(${qt6_lower_item} Qt6::${qt6_item})
+        message("add_target_link_qt6_${qt6_item} or add_target_link_qt6_${qt6_lower_item}")
+    endforeach(qt6_item IN LISTS qt6_items)
+endmacro(spark_add_links_qt6)
+
+# 找出所有 Qt6 模板
+# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt6@Qt6@;' | grep ^Qt6
+
+# 掐头去尾,洗一次
+# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d'
+
+# 排序
+# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d' | sort | pr -t -3
+# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt6@Qt6@;' | grep ^Qt6 | sed 's@^Qt6@@; [email protected]$@@; /^\s*$/d' | sort | pr -t -3
+
+spark_add_links_qt6(
+    # BuildInternals
+    # BuildInternals/StandaloneTests/Qt5CompatTests
+    # BuildInternals/StandaloneTests/QtBaseTests
+    Concurrent
+    # Core
+    Core5Compat
+    # CoreTools
+    # DBus
+    # DBusTools
+    # DeviceDiscoverySupportPrivate
+    # EglFSDeviceIntegrationPrivate
+    # EglFsKmsGbmSupportPrivate
+    # EglFsKmsSupportPrivate
+    # FbSupportPrivate
+    # Gui
+    # GuiTools
+    # HostInfo
+    # InputSupportPrivate
+    # KmsSupportPrivate
+    # Network
+    # OpenGL
+    # OpenGLWidgets
+    PrintSupport
+    # QComposePlatformInputContextPlugin
+    # QCupsPrinterSupportPlugin
+    # QEglFSEmulatorIntegrationPlugin
+    # QEglFSIntegrationPlugin
+    # QEglFSKmsEglDeviceIntegrationPlugin
+    # QEglFSKmsGbmIntegrationPlugin
+    # QEglFSX11IntegrationPlugin
+    # QEvdevKeyboardPlugin
+    # QEvdevMousePlugin
+    # QEvdevTabletPlugin
+    # QEvdevTouchScreenPlugin
+    # QGifPlugin
+    # QGtk3ThemePlugin
+    # QIBaseDriverPlugin
+    # QIbusPlatformInputContextPlugin
+    # QICOPlugin
+    # QJpegPlugin
+    # QLibInputPlugin
+    # QLinuxFbIntegrationPlugin
+    # QMinimalEglIntegrationPlugin
+    # QMinimalIntegrationPlugin
+    # QMYSQLDriverPlugin
+    # QNetworkManagerNetworkInformationPlugin
+    # QODBCDriverPlugin
+    # QOffscreenIntegrationPlugin
+    # QPSQLDriverPlugin
+    # QSQLiteDriverPlugin
+    # QTlsBackendCertOnlyPlugin
+    # QTlsBackendOpenSSLPlugin
+    # QTsLibPlugin
+    # QTuioTouchPlugin
+    # QVkKhrDisplayIntegrationPlugin
+    # QVncIntegrationPlugin
+    # QXcbEglIntegrationPlugin
+    # QXcbGlxIntegrationPlugin
+    # QXcbIntegrationPlugin
+    # QXdgDesktopPortalThemePlugin
+    # Sql
+    # Test
+    # Widgets
+    # WidgetsTools
+    # XcbQpaPrivate
+    # Xml
+)

+ 132 - 0
cmake/SparkInstallMacrosConfig.cmake

@@ -0,0 +1,132 @@
+
+# spark_install_target
+# 基于传入的路径/目标进行安装
+# 可接受的值为: 安装路径 目标A
+# 可接受的值为: 安装路径 目标A 目标B 目标C...
+macro(spark_install_target INSTALL_TARGET_DIR INSTALL_TARGETS)
+    install(TARGETS
+        ${INSTALL_TARGETS} ${ARGN}
+        DESTINATION ${INSTALL_TARGET_DIR})
+endmacro(spark_install_target INSTALL_TARGET_DIR INSTALL_TARGETS)
+
+# spark_install_file
+# 基于传入的路径/文件进行安装
+# 可接受的值为: 安装路径 文件A
+# 可接受的值为: 安装路径 文件A 文件B 文件C...
+macro(spark_install_file INSTALL_FILE_DIR INSTALL_FILE)
+    install(FILES
+        ${INSTALL_FILE} ${ARGN}
+        DESTINATION ${INSTALL_FILE_DIR})
+endmacro(spark_install_file INSTALL_FILE_DIR INSTALL_FILE)
+
+# spark_install_program
+# 基于传入的路径/文件进行安装,并自动为其添加可执行权限
+# 可接受的值为: 安装路径 文件A
+# 可接受的值为: 安装路径 文件A 文件B 文件C...
+macro(spark_install_program INSTALL_PROGRAM_DIR INSTALL_PROGRAM)
+    install(PROGRAMS
+        ${INSTALL_PROGRAM} ${ARGN}
+        DESTINATION ${INSTALL_PROGRAM_DIR})
+endmacro(spark_install_program INSTALL_PROGRAM_DIR INSTALL_PROGRAM)
+
+
+# spark_install_directory
+# 基于传入的路径/目录进行安装
+# 可接受的值为: 安装路径 路径A
+# 可接受的值为: 安装路径 路径A/* 为安装路径A下所有内容
+macro(spark_install_directory INSTALL_DIRECTORY_DIR INSTALL_DIRECOTRY)
+    # INSTALL_DIRECOTRY 可能包含 * ?
+    # 1. 找到 '*', 截取,列出目录下所有文件,安装
+    # 2. 是文件的直接使用 spark_install_file 安装
+    # 2. 是目录的直接使用 spark_install_directory 安装
+    # message(FATAL_ERROR "${INSTALL_DIRECTORY_DIR}")
+    # string(FIND <string> <substring> <output_variable> [REVERSE])
+    string(FIND "${INSTALL_DIRECOTRY}" "*" INSTALL_DIRECTORY_FIND_INDEX)
+    # message(FATAL_ERROR "${INSTALL_DIRECTORY_FIND_INDEX}:  ${INSTALL_DIRECTORY_DIR}")
+
+    # file(GLOB <variable>
+    #  [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
+    #  [<globbing-expressions>...])
+
+    if (NOT INSTALL_DIRECTORY_FIND_INDEX EQUAL -1)
+        # string(SUBSTRING <string> <begin> <length> <output_variable>)
+        string(SUBSTRING "${INSTALL_DIRECOTRY}" 0 ${INSTALL_DIRECTORY_FIND_INDEX} INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING)
+        # message(FATAL_ERROR "directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING}")
+
+        # file(GLOB <variable>
+        #     [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
+        #     [<globbing-expressions>...])
+
+        file(GLOB INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST  ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING}/*)
+        list(LENGTH INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST_LENGTH)
+        foreach(item IN LISTS INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST)
+            # message("-> ${item}")
+            if(IS_DIRECTORY ${item})
+                message("-> ${item} IS_DIRECTORY")
+                # spark_install_directory(${INSTALL_DIRECTORY_DIR} ${item})
+                install(DIRECTORY
+                    ${item}
+                    DESTINATION ${INSTALL_DIRECTORY_DIR}
+                    USE_SOURCE_PERMISSIONS)
+            else()
+                message("-> ${item} NOT IS_DIRECTORY")
+                spark_install_program(${INSTALL_DIRECTORY_DIR} ${item})
+                # spark_install_file(${INSTALL_DIRECTORY_DIR} ${item})
+            endif(IS_DIRECTORY ${item})
+        endforeach(item IN LISTS INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST)
+
+        # message(FATAL_ERROR " directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST}")
+        # message(FATAL_ERROR " directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST_LENGTH}")
+
+    else()
+        # ISSUES: You Must check here
+        # message(FATAL_ERROR "install: ${INSTALL_DIRECTORY_DIR}")
+
+        install(DIRECTORY
+            ${INSTALL_DIRECOTRY} ${ARGN}
+            DESTINATION ${INSTALL_DIRECTORY_DIR})
+    endif(NOT INSTALL_DIRECTORY_FIND_INDEX EQUAL -1)
+
+endmacro(spark_install_directory INSTALL_DIRECTORY_DIR INSTALL_DIRECOTRY)
+
+
+
+macro(spark_install_changelog CHANGE_LOG_FILE)
+    set(SOURCE_CHANGE_LOG_FILE ${CHANGE_LOG_FILE})
+    if (EXISTS ${SOURCE_CHANGE_LOG_FILE})
+
+        execute_process(COMMAND test -f ${SOURCE_CHANGE_LOG_FILE}
+            RESULT_VARIABLE changelog_test
+        )
+        execute_process(COMMAND which gzip
+            RESULT_VARIABLE gzip_test
+        )
+        if (NOT changelog_test  EQUAL 0)
+            message(FATAL_ERROR "NOTE: 不是常规文件: ${SOURCE_CHANGE_LOG_FILE}")
+        endif(NOT changelog_test  EQUAL 0)
+
+        if (NOT gzip_test  EQUAL 0)
+            message(FATAL_ERROR "NOTE: 未安装 gzip, 无法压缩 changelog")
+        endif(NOT gzip_test  EQUAL 0)
+
+        # 压缩与安装日志文件
+        add_custom_command(
+            OUTPUT "${CMAKE_BINARY_DIR}/changelog.gz"
+            COMMAND gzip -cn9 "${SOURCE_CHANGE_LOG_FILE}" > "${CMAKE_BINARY_DIR}/changelog.gz"
+            WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+            COMMENT "Compressing changelog"
+        )
+        add_custom_target(changelog ALL DEPENDS "${CMAKE_BINARY_DIR}/changelog.gz")
+
+        # include(GNUInstallDirs)
+        set(SPARK_INSTALL_CHANGE_LOG_DIR "/usr/share/doc/${PROJECT_NAME}/")
+        install(FILES
+            ${CMAKE_BINARY_DIR}/changelog.gz
+            debian/copyright
+
+            DESTINATION ${SPARK_INSTALL_CHANGE_LOG_DIR}
+        )
+    else()
+        message(FATAL_ERROR "未找到: ${SOURCE_CHANGE_LOG_FILE}")
+    endif(EXISTS ${SOURCE_CHANGE_LOG_FILE})
+endmacro(spark_install_changelog CHANGE_LOG_FILE)

+ 161 - 0
cmake/SparkMacrosConfig.cmake

@@ -0,0 +1,161 @@
+cmake_minimum_required(VERSION 3.5.1)
+
+# 定义一些 macro 用于自动生成构建结构
+
+# spark_add_library <lib_name> [files]...
+# 构建一个库,基于指定的源文件
+    # 并根据库名生成 target_link_<lib_name> 函数
+macro(spark_add_library _lib_name)
+    message("================ ${_lib_name} Library ================")
+    add_library(${_lib_name} ${ARGN})
+
+    set(SRCS ${ARGN})
+    foreach(item IN LISTS SRCS)
+        message(" -> ${item}")
+    endforeach(item IN LISTS SRCS)
+
+    function(target_link_${_lib_name} TARGET)
+        message("${_lib_name}")
+        target_link_libraries(${TARGET} ${_lib_name})
+    endfunction(target_link_${_lib_name} TARGET)
+
+endmacro(spark_add_library _lib_name)
+
+# spark_add_library_path <lib_name> <lib_path>
+# 构建一个库,基于指定的路径
+    # 并根据库名生成 target_link_<lib_name> 函数
+        # 函数内增加以 <lib_path> 头文件搜索路径
+macro(spark_add_library_path _lib_name _lib_path)
+
+    set(${_lib_name}_SOURCE_PATH ${_lib_path})
+    set(${_lib_name}_TYPE)
+    if(${${_lib_name}_SOURCE_PATH} STREQUAL SHARED OR ${${_lib_name}_SOURCE_PATH} STREQUAL STATIC)
+        set(${_lib_name}_SOURCE_PATH ${ARGV2})
+        set(${_lib_name}_TYPE ${_lib_path})
+        message("_lib_path: ${${_lib_name}_SOURCE_PATH}(${ARGV2})[${${_lib_name}_TYPE}]")
+
+        if(${ARGC} LESS 3)
+            message(FATAL_ERROR "Missing parameter, library path not specified.")
+        endif(${ARGC} LESS 3)
+    endif(${${_lib_name}_SOURCE_PATH} STREQUAL SHARED OR ${${_lib_name}_SOURCE_PATH} STREQUAL STATIC)
+
+    aux_source_directory(${${_lib_name}_SOURCE_PATH} ${_lib_name}_SOURCES)
+
+    message("================ spark_add_library_path: ${_lib_name} ================")
+    file(GLOB UI_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${${_lib_name}_SOURCE_PATH}/*.ui)
+    add_library(${_lib_name} ${${_lib_name}_TYPE} ${${_lib_name}_SOURCES} ${UI_LIST})
+    message("${_lib_name}_SOURCES: ${${_lib_name}_SOURCES}, ${${_lib_name}_SOURCE_PATH}")
+    foreach(item IN LISTS ${_lib_name}_SOURCES)
+        message(" -> ${item}")
+    endforeach(item IN LISTS ${_lib_name}_SOURCES)
+
+    function(target_link_${_lib_name} TARGET)
+        # message("target_link_${_lib_name}")
+        message(" -> (include): ${${_lib_name}_SOURCE_PATH}")
+        target_include_directories(${TARGET} PUBLIC "${${_lib_name}_SOURCE_PATH}")
+        target_link_libraries(${TARGET} ${_lib_name})
+    endfunction(target_link_${_lib_name} TARGET)
+
+    function(target_include_${_lib_name} TARGET)
+        # message("target_link_${_lib_name}")
+        message(" -> (include): ${${_lib_name}_SOURCE_PATH}")
+        target_include_directories(${TARGET} PUBLIC "${${_lib_name}_SOURCE_PATH}")
+        # target_link_libraries(${TARGET} ${_lib_name})
+    endfunction(target_include_${_lib_name} TARGET)
+
+    # file(GLOB HEADER_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${${_lib_name}_SOURCE_PATH}/*.h)
+    target_include_directories(${_lib_name} PUBLIC "${${_lib_name}_SOURCE_PATH}")
+
+    # 如果想用以下操作手动实现 target_link_include_directories
+        # 请注意对 LIST 类型使用 "" 进行包围
+        # target_link_include_directories 的 PUBLIC 将会填充(追加)目标的 INCLUDE_DIRECTORIES 属性
+        # target_link_include_directories 支持 cmake 生成大表达式,更容易操作,手动将无法实现此类能力
+        # target_link_include_directories 支持相对路径和绝对路径参数
+            # 手动操作将必须使用绝对路径,这是不好的地方
+    # get_target_property(_lib_include_directories ${_lib_name} INCLUDE_DIRECTORIES)
+    # list(APPEND _lib_include_directories "${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
+    # message("----> ${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
+    # message("----> ${_lib_include_directories}")
+    # set_target_properties(${_lib_name} PROPERTIES
+    #     INCLUDE_DIRECTORIES "${_lib_include_directories}"
+        # INTERFACE_INCLUDE_DIRECTORIES "${_lib_include_directories}"
+    # )
+
+endmacro(spark_add_library_path _lib_name _lib_path)
+
+# spark_add_executable <exec_name> [files]...
+# 构建一个可执行文件,基于指定的源文件
+    # Qt编译时源文件包括很多类型,需要指定 *.h/*.cpp/*.qrc/*.qm/... 等
+macro(spark_add_executable _exec_name)
+
+    message("================ ${_exec_name} Executable ================")
+    add_executable(${_exec_name} ${ARGN})
+
+endmacro(spark_add_executable _exec_name)
+
+macro(spark_add_executable_path _exec_name _exec_path)
+    aux_source_directory(${_exec_path} ${_exec_name}_SOURCES)
+
+    message("================ ${_exec_name} Executable ================")
+    file(GLOB UI_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${_exec_path}/*.ui)
+    add_executable(${_exec_name} ${${_exec_name}_SOURCES} ${ARGN} ${UI_LIST})
+    foreach(item IN LISTS ${_exec_name}_SOURCES)
+        message(" -> ${item}")
+    endforeach(item IN LISTS ${_exec_name}_SOURCES)
+
+    # function(target_link_${_exec_name} TARGET)
+    #     message("target_link_${_lib_name}")
+    message(" -> (include): ${_exec_path}")
+    target_include_directories(${_exec_name} PUBLIC "${_exec_path}")
+        # target_link_libraries(${TARGET} ${_lib_name})
+    # endfunction(target_link_${_exec_name} TARGET)
+    # target_link_${_exec_name}(${_exec_name})
+
+endmacro(spark_add_executable_path _exec_name _exec_path)
+
+# spark_find_library
+# 搜索一个库,基于指定的库名,调用 pkg-config 搜索库
+    # 并根据库名生成一个 target_link_<prefix> 函数
+macro(spark_find_library _prefix)
+    find_package(PkgConfig REQUIRED)
+
+    # libnotify
+    pkg_check_modules(${_prefix} ${ARGN})
+    function(target_link_${_prefix} TARGET)
+        target_include_directories(${TARGET} PUBLIC
+            ${${_prefix}_INCLUDE_DIRS})
+        target_link_libraries(${TARGET}
+            ${${_prefix}_LIBRARIES})
+    endfunction(target_link_${_prefix} TARGET)
+
+endmacro(spark_find_library _prefix)
+
+
+# spark_add_executable_paths
+# 自定义构建宏,基于指定的前缀名称,处理后续参数为子目录
+    # item: 为进行遍历后的单项,类似于 python3 中的 (for item in items:)
+    # file: 为在目录中不以递归(GLOB_RECURSE)方式寻找 qrc 文件,需要将其参与编译才能被 rcc
+    # 并根据 prefix-<item> 生成构建目标,
+macro(spark_add_executable_paths _prefix_path)
+    set(PATHS ${ARGN})
+    foreach(item IN LISTS PATHS)
+        file(GLOB QRCS "${item}/*.qrc")
+        message(">>> add_executable: " "${_prefix_path}-${item} ${item} + ${QRCS}")
+        spark_add_executable_path(${_prefix_path}-${item} ${item} ${QRCS})
+        target_link_qt5(${_prefix_path}-${item})
+    endforeach(item IN LISTS PATHS)
+endmacro(spark_add_executable_paths _prefix_path)
+
+# spark_add_link
+# 自定义宏以代替当前使用 fucntion 定义 target_link_<name> 结构
+    # _IN_NAME: 此宏生成 target_link_<name> 的要求参数
+    # ARGN: 此宏剩余的参数列表
+        # 在使用 target_link_<name> 时
+        # _NAME: 用于此 fucntion 中的要求参数: <_NAME>目标将要连接此库
+macro(spark_add_link _IN_NAME)
+    function(target_link_${_IN_NAME} _NAME)
+        message("LINK ${_NAME} ${ARGN}")
+        target_link_libraries(${_NAME}
+            ${ARGN})
+    endfunction(target_link_${_IN_NAME} _NAME)
+endmacro(spark_add_link _IN_NAME)

+ 237 - 0
cmake/SparkMacrosExtendConfig.cmake

@@ -0,0 +1,237 @@
+
+# find_plus
+# 寻找 INVAl 传入的字符串,如果存在 + 字符将写入位置到 OUTVAL
+function(find_plus INVAL OUTVAL)
+    string(FIND "${INVAL}" "+" plus_index)
+    set(${OUTVAL} ${plus_index} PARENT_SCOPE)
+    # if(plus_index LESS 0)
+    #     set(${OUTVAL} -1 PARENT_SCOPE)
+    # else()
+    #     set(${OUTVAL} ${plus_index} PARENT_SCOPE)
+    # endif(plus_index LESS 0)
+endfunction(find_plus INVAL OUTVAL)
+
+# find_plus("FF" FFFF)
+# message("--> FFFF ${FFFF}")  # --> FFFF -1
+# find_plus("F+F" FFFF)
+# message("--> FFFF ${FFFF}")  # --> FFFF 1
+# find_plus("+F+F" FFFF)
+# message("--> FFFF ${FFFF}")  # --> FFFF 0
+
+# set(FFF)
+# list(APPEND FFFF )
+# list(APPEND FFFF "F")
+# list(APPEND FFFF "FA")
+# message("--> FFFF: ${FFFF}")  # --> FFFF: F;FA
+
+# set(FFFFS "")
+# list(APPEND FFFFS ${FFFF})
+# message("--> FFFFS: ${FFFFS}")  # --> FFFFS: F;FA
+
+# set(FFFF "+AA+BB+CC+DD")
+# string(REPLACE "+" ";" FFFFL "${FFFF}")
+# list(LENGTH FFFFL FFFFLEN)
+# message("--> FFFFL: ${FFFFL} --> ${FFFFLEN}") # --> FFFFL: F;
+
+# plus_list
+# 将传入的 "+AAA+BBB+CCC" 类型数据变成一个 列表(list)
+# 适用于不使用 string 进行替换 + 为 ";" 的情况下使用直接变成 list
+function(plus_list INVAL OUTVAL OUTVALLEN)
+    # set(${OUTVAL} "..." PARENT_SCOPE)
+    # set(${OUTVALLEN} 0 PARENT_SCOPE)
+
+    set(_tmps "")       # 设置为空的
+
+    # 寻找下一个 + 位置
+    find_plus(${INVAL} RIGHT_PLUS)
+
+    string(LENGTH "${INVAL}" INVALLEN)
+    message("--> 传入的 INVAL: --> 内容: ${INVAL}")
+    message("--> 传入的 INVAL: --> 长度: ${INVALLEN}")
+    message("--> 传入的 INVAL: --> +位置: ${RIGHT_PLUS}")
+
+    # 判断是否有右侧 + 号
+    if(RIGHT_PLUS LESS 0)
+        message("--> 传入的 INVAL: --> 无需计算新的+位置")
+        # message("--> 计算新的 + 位置: ${_PLUSINDEX}")
+        list(APPEND _tmps ${INVAL})
+    else()
+        math(EXPR _PLUSINDEX "${RIGHT_PLUS}+1")
+        message("--> 传入的 INVAL: --> 需计算+位置 --> 右移: ${_PLUSINDEX}")
+
+        string(SUBSTRING "${INVAL}" ${_PLUSINDEX} ${INVALLEN} NewVal)
+        message("--> 传入的 INVAL: --> 需计算+位置 --> 右移: ${_PLUSINDEX} -> 内容: ${NewVal}")
+        # string(REPLACE "+" ";" _tmps "${NewVal}")
+        # list(LENGTH FFFFL FFFFLEN)
+
+        # message("--> 计算新的 + 位置: ${_PLUSINDEX} --> 后面的 NewVal: ${NewVal}")
+
+        # find_plus(${NewVal} _NextPlus)
+        # if(_NextPlus LESS 0)
+            # list(APPEND _tmps ${NewVal})
+            # message("--> 追加新的 + 位置: ${_PLUSINDEX} --> 后面的")
+        # else()
+        #     message("--> 追加新的 + 位置: ${_PLUSINDEX} --> 后面的")
+        #     # 重新
+        #     # plus_list(${NewVal} NewValS )
+        #     # foreach(item)
+        #         # list(APPEND _tmps ${item})
+        #     # endforeach(item)
+        # endif(_NextPlus LESS 0)
+    endif(RIGHT_PLUS LESS 0)
+
+    set(${OUTVAL} ${_tmps} PARENT_SCOPE)
+    list(LENGTH _tmps _tmps_len)
+    set(${OUTVALLEN} ${_tmps_len} PARENT_SCOPE)
+
+endfunction(plus_list INVAL OUTVAL OUTVALLEN)
+
+# plus_list("+AAA+BBB+CCC+DDD" FFF FFLEN)
+# message("--------> ${FFF}: -> ${FFLEN}")
+
+# spark_add_library_realpaths
+# 基于传入的项进行构建
+# 可接受的值为: 路径列表
+# 可接受的值为: 路径列表+依赖库A+依赖库B
+macro(spark_add_library_realpaths)
+    message("---> 基于传入的项进行构建 <---")
+    # message("--> src/unclassified/ItemDelegates/NdStyledItemDelegate")
+    # string(FIND <string> <substring> <output_variable> [REVERSE])
+    # string(SUBSTRING <string> <begin> <length> <output_variable>)
+    # math(EXPR value "100 * 0xA" OUTPUT_FORMAT DECIMAL)      # value is set to "1000"
+
+    set(REALPATHS ${ARGN})
+    foreach(REALPATH IN LISTS REALPATHS)
+        message("---> 传入路径: ${REALPATH} <--- ")
+        string(LENGTH "${REALPATH}" REALPATH_LENGTH)
+        message("---> 计算传入路径长度: --> 长度: ${REALPATH_LENGTH}")
+
+        string(FIND "${REALPATH}" "/" LASTINDEX REVERSE)
+        message("---> 计算传入路径末尾/位置: --> 长度: ${LASTINDEX}")
+        math(EXPR LASTINDEX "${LASTINDEX}+1")
+        message("---> 计算传入路径末尾/右移: --> 长度: ${LASTINDEX}")
+        string(SUBSTRING "${REALPATH}" ${LASTINDEX} ${REALPATH_LENGTH} REALNAME_Dependency)
+
+        # 找 + 号下标,这是找+号的函数
+        find_plus(${REALPATH} RIGHT_PLUS)
+
+        # 判断是否有找到 + 号下标,值为 -1 或 正整数
+        if(RIGHT_PLUS LESS 0) # 小于0: 不存在 + 号
+            set(REALNAME "${REALNAME_Dependency}")
+            message("---> 传入路径末尾/右移部分: --> ${REALNAME} <-- 无依赖+")
+
+            message("---> 构建 ${REALNAME} -> ${REALNAME} ${REALPATH} ")
+
+            spark_add_library_path(${REALNAME} ${REALPATH})
+
+            if(SPARK_FIND_QT5)
+                target_link_qt5(${REALNAME})
+            endif(SPARK_FIND_QT5)
+
+            if(SPARK_FIND_QT6)
+                target_link_qt6(${REALNAME})
+            endif(SPARK_FIND_QT6)
+
+        else()
+            message("---> 传入路径末尾/右移部分: --> ${REALNAME_Dependency} <-- 依赖+")
+
+            # 存在+号,将截取从 / 到 + 号之间的内容作为目标名称
+            # 例如 src/unclassified/widgets/DocTypeListView+JsonDeploy
+            #                             ^(LASTINDEX)    ^(RIGHT_PLUS)
+            # 将 RIGHT_PLUS - LASTINDEX 计算出 DocTypeListView 字符长度
+            math(EXPR REALNAME_LENGTH "${RIGHT_PLUS}-${LASTINDEX}")
+
+            message("---> 计算传入路径末尾/右移部分: --> 位置: ${RIGHT_PLUS}")
+            # message("---> 计算传入路径末尾/右移部分: --> 长度: ${REALNAME_Dependency}")
+
+            # 目标名称为 DocTypeListView
+            # 依赖为    JsonDeploy
+            # set(REALNAME "")
+            string(SUBSTRING "${REALPATH}" 0 ${RIGHT_PLUS} _REALPATH_DIR)
+            string(SUBSTRING "${REALPATH}" ${LASTINDEX} ${REALNAME_LENGTH} REALNAME)
+
+            message("---> 计算传入路径末尾/右移部分: --> 库名: ${REALNAME}")
+
+            string(SUBSTRING "${REALPATH}" ${RIGHT_PLUS} ${REALPATH_LENGTH} Dependency)
+            message("---> 计算传入路径末尾/右移部分: --> 库名: ${REALNAME} --> +部分: ${Dependency}")
+
+            # plus_list(${Dependency} dependencies dependencies_len)
+            string(REPLACE "+" ";" dependencies "${Dependency}")
+            message("---> 计算传入路径末尾/右移部分: --> 库名: ${REALNAME} --> +部分: ${Dependency} --> 列表: ${dependencies} <-- ")
+
+
+            message("---> 构建 ${REALNAME} -> ${REALNAME} ${_REALPATH_DIR}")
+
+            spark_add_library_path(${REALNAME} ${_REALPATH_DIR})
+            # target_link_qt5(${REALNAME}) # 使用依赖的依赖或许也不错
+
+            target_include_directories(${REALNAME} PUBLIC ${_REALPATH_DIR})
+            target_link_libraries(${REALNAME} ${dependencies})
+
+        endif(RIGHT_PLUS LESS 0)
+    endforeach(REALPATH IN LISTS REALPATHS)
+
+endmacro(spark_add_library_realpaths)
+
+
+# spark_aux_source_paths
+# 将指定路径中的文件变成可用的AUX源文件列表
+macro(spark_aux_source_paths AUX_VAR)
+    set(${AUX_VAR} "")
+    set(${AUX_VAR}_PATHS ${ARGN})
+
+    foreach(aux_path IN LISTS ${AUX_VAR}_PATHS)
+        # message("aux_path: ${aux_path}")
+        aux_source_directory(${aux_path} ${AUX_VAR})
+    endforeach(aux_path IN LISTS ${AUX_VAR}_PATHS)
+
+endmacro(spark_aux_source_paths AUX_VAR)
+
+# spark_file_glob
+#
+macro(spark_file_glob FGLOB_VAR)
+    set(${FGLOB_VAR} "")
+    set(${FGLOB_VAR}_PATHS ${ARGN})
+
+    foreach(fglob_path IN LISTS ${FGLOB_VAR}_PATHS)
+
+        file(GLOB FGLOB_PATH_SRCS ${fglob_path})
+        foreach(fglob_path_src IN LISTS FGLOB_PATH_SRCS)
+            # message(" -> ${item}")
+            list(APPEND ${FGLOB_VAR} ${fglob_path_src})
+        endforeach(fglob_path_src IN LISTS FGLOB_PATH_SRCS)
+
+    endforeach(fglob_path IN LISTS ${FGLOB_VAR}_PATHS)
+
+endmacro(spark_file_glob FGLOB_VAR)
+
+
+# spark_add_source_paths
+# 将指定路径中的文件变成可用的源文件列表
+#
+macro(spark_add_source_paths SOURCE_VAR)
+    set(${SOURCE_VAR} "")
+    set(${SOURCE_VAR}_PATHS ${ARGN})
+
+    spark_aux_source_paths(${SOURCE_VAR} ${ARGN})
+    foreach(source_path IN LISTS ${SOURCE_VAR}_PATHS)
+        # list(APPEND ${SOURCE_VAR}_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_PATH})
+        # aux_source_directory(${SOURCE_PATH} _SOURCES)
+        # foreach(item IN LISTS _SOURCES)
+        #     # message(" -> ${item}")
+        #     list(APPEND ${SOURCE_VAR} ${item})
+        # endforeach(item IN LISTS _SOURCES)
+
+        # file(GLOB HEADER_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${SOURCE_PATH}/*.h)
+        # foreach(item IN LISTS HEADER_LIST)
+        #     # message(" -> ${item}")
+        #     list(APPEND ${SOURCE_VAR} ${item})
+        # endforeach(item IN LISTS HEADER_LIST)
+
+        file(GLOB UI_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${source_path}/*.ui)
+        foreach(ui_src IN LISTS UI_SRCS)
+            # message(" -> ${item}")
+            list(APPEND ${SOURCE_VAR} ${ui_src})
+        endforeach(ui_src IN LISTS UI_SRCS)
+    endforeach(source_path IN LISTS ${SOURCE_VAR}_PATHS)
+endmacro(spark_add_source_paths SOURCE_VAR)

+ 33 - 0
cmake/modules/Notepad--.cmake

@@ -0,0 +1,33 @@
+if(TRUE)
+    # 准备构建 Notepad-- 主程序
+    set(QRC_SOURCES src/RealCompare.qrc)
+    spark_aux_source_paths(CCEditorSources
+        src
+        src/cceditor
+    )
+    spark_add_executable(${PROJECT_NAME} ${CCEditorSources} ${QRC_SOURCES})
+    target_include_directories(${PROJECT_NAME} PRIVATE
+        ${PROJECT_SOURCE_DIR}/src
+        ${PROJECT_SOURCE_DIR}/src/cceditor
+
+        ${PROJECT_SOURCE_DIR}/src/qscint/src
+        ${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
+        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
+        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
+        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
+        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
+    )
+    # target_link_libraries(${PROJECT_NAME} QSci)
+    target_link_QSci(${PROJECT_NAME})
+    target_link_qt5_XmlPatterns(${PROJECT_NAME})
+
+endif(TRUE)
+
+# ----------------- Notepad-- 插件支持相关  ----------------- #
+if(TRUE)
+    # 开启插件支持
+    target_compile_definitions(${PROJECT_NAME} PUBLIC NO_PLUGIN=0)
+    # 其它有关插件的部分处理...
+endif(TRUE)
+
+

+ 29 - 0
cmake/modules/QScint.cmake

@@ -0,0 +1,29 @@
+if(TRUE)
+    # add_subdirectory(${PROJECT_SOURCE_DIR}/src/qscint)
+    # file(GLOB MOC_HEADER src/qscint/src/Qsci/*.h)
+    spark_file_glob(MOC_HEADER "src/qscint/src/Qsci/*.h")
+
+    spark_add_source_paths(QSciSources
+        src/qscint/src
+        src/qscint/scintilla/lexers
+        src/qscint/scintilla/lexlib
+        src/qscint/scintilla/src
+        src/qscint/scintilla/boostregex
+
+        # src/qscint/src/Qsci
+        # FAIL: only *.ui will spark_file_glob(MOC_HEADER ...)
+    )
+    spark_add_library(QSci STATIC ${QSciSources} ${MOC_HEADER})
+    target_compile_definitions(QSci PRIVATE SCINTILLA_QT SCI_LEXER INCLUDE_DEPRECATED_FEATURES)
+    target_include_directories(QSci PRIVATE
+        src/qscint/scintilla/boostregex
+        src/qscint/scintilla/lexlib)
+    target_include_directories(QSci PUBLIC
+        src/qscint/src
+        src/qscint/src/Qsci
+        src/qscint/scintilla/src
+        src/qscint/scintilla/include)
+    target_link_qt5(QSci)
+    target_link_qt5_PrintSupport(QSci)
+    target_link_qt5_Concurrent(QSci)
+endif(TRUE)

+ 45 - 0
cmake/package-deb.descript

@@ -0,0 +1,45 @@
+# 注释行(使用方式)
+# find_package(DebPackage PATHS ${CMAKE_SOURCE_DIR})
+# add_package_descript(cmake/package-deb.descript)
+
+# 打包后的文件名称
+# FileName: 待定
+# 配置 PACKAGE_SUFFIX 变量可添加尾巴名称
+# 如在 Makefile 中硬编码方式
+# OSID=$(shell lsb_release -si)
+# OSRELEASE=$(shell lsb_release -sr)
+# -DPACKAGE_SUFFIX="_$(OSID)$(OSRELEASE)"
+
+# deb 安装包的安装时脚本
+# 1.安装[前|后]执行脚本(preinst,postinst),
+# 2.卸载[前|后]执行脚本(prerm,postrm)
+# ControlExtra: 未定义(暂不支持)
+# 如需指定请修改 DebPackageConfig.cmake 模板(第252行)
+# CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA 变量
+
+# 打包类型,暂支持 deb, 未来支持 tgz(tar.gz)
+Type: deb
+# 软件包名称(自动, 使用 PROJECT_NAME 变量值)
+Package: com.hmja.notepad
+# 软件包版本(自动, 使用 PROJECT_VERSION 变量值)
+Version: auto
+# 日历化尾部版本
+CalVer: true
+# 软件包架构(自动)
+Architecture: auto
+# 软件包属于的系统部分[admin|cli-mono|comm|database|debug|devel|doc|editors|education|electronics|embedded|fonts|games|gnome|gnu-r|gnustep|graphics|hamradio|haskell|httpd|interpreters|introspection|java|javascript|kde|kernel|libdevel|libs|lisp|localization|mail|math|metapackages|misc|net|news|ocaml|oldlibs|otherosfs|perl|php|python|ruby|rust|science|shells|sound|tasks|tex|text|utils|vcs|video|web|x11|xfce|zope]
+Section: editors
+# 软件包优先级[required|important|stantard|optional|extra]
+Priority: optional
+# 软件包依赖
+Depends:
+# 软件包维护者(组织或个人)
+Maintainer: 尹作为 <[email protected]>
+# 软件包主页
+Homepage: https://gitee.com/cxasm/notepad--
+# 软件包建议
+Recommends:
+# 软件包描述信息
+Descrition: Notepad--是一个国产跨平台、简单的文本编辑器。
+ Notepad--是一个国产跨平台、简单的文本编辑器,是替换notepad++的一种选择。
+ 其内置强大的代码对比功能,让你丢掉付费的beyond compare。

+ 48 - 0
cmake/platforms/linux-appimage.cmake

@@ -0,0 +1,48 @@
+# linux-appimage.cmake
+
+# 此构建表示,在 Linux 中以通用平台的构建方式进行 Appimage 打包
+
+# 1. SparkAppimageConfig.cmake 依赖于 SparkDesktopMacros.cmake 构建的 desktop
+# 2. 为可执行程序进行部署一个 linuxdeployqt 操作,并生成为 Appimage 可用于打包的目录结构
+# 3. 使用 Appimagetool 对已生成的 Appimage 标准目录进行打包
+# 4. 将会生成一个 Notepad--.X86_64.Appimage 
+
+# 参看 Appimagetool 相关的内容: 
+    # https://doc.appimage.cn/docs/appimagetool-usage/ 
+
+option(LINUX_DEPLOY_QT "为 Linux 中构建的应用进程 linuxdeployqt" OFF)
+if(LINUX_DEPLOY_QT)
+    # ... 已由 Appimage 自动化构建组件完成
+endif(LINUX_DEPLOY_QT)
+
+option(USE_LINUX_APPIMAGE "为 Linux 生成 Appimage 可执行程序" OFF)
+
+if(USE_LINUX_APPIMAGE)
+
+    include(cmake/SparkDesktopMacros.cmake)
+    # 内容默认应用名称: Name= 应与项目名称相同
+    spark_desktop_macros(
+        # 应用名称: Name=
+        ${PROJECT_NAME}
+        # 应用名称: Name[zh_CN]=
+        "Notepad--"
+        # 应用说明: Comment=
+        "Notepad-- 是一个国产跨平台、简单的文本编辑器。"
+        # 应用类型: Type=
+        "Application"
+        # 执行程序: Exec=
+        # 有关此 %F 参数可查看: https://gitee.com/zinface/z-tools/blob/desktop-dev/src/DesktopGenerater/desktopexecparamdialog.cpp
+        "notepad-- %F"
+        # 图标路径: Icon=
+        "/usr/share/notepad--/icons/spark.png"
+        # 应用分类: Category=
+        "Development"
+    )
+
+    # 1. 在顶层构建中导入 Appimage 的构建
+    include(cmake/SparkAppimageConfig.cmake)  # 导入来自 Spark 构建的 Appimage 构建
+    add_appimage_icon(assets/spark.png)       # 添加到 Appimage 中的默认的图标
+    add_appimage_desktop()                    # 添加到 Appimage 中的默认desktop(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
+    add_appimage()                            # 应用对 Appimage 的构建
+
+endif(USE_LINUX_APPIMAGE)

+ 18 - 0
cmake/platforms/linux-debian.cmake

@@ -0,0 +1,18 @@
+# linux-debian.cmake
+
+# 此构建表示,在 Linux 中以通用平台的构建方式进行 Debian 打包
+
+# 1. 在 cmake/package-deb.descript 中提供标准软件包描述信息
+# 2. 在 DebPackageConfig.cmake 构建模块中分析与自动化配置
+
+option(USE_LINUX_DEBIAN "为 Linux 生成 deb 软件包" OFF)
+
+if(USE_LINUX_DEBIAN)
+    
+    find_package(DebPackage PATHS ${CMAKE_SOURCE_DIR})
+    add_package_descript(cmake/package-deb.descript)
+
+endif(USE_LINUX_DEBIAN)
+
+
+

+ 110 - 0
cmake/platforms/linux-universal.cmake

@@ -0,0 +1,110 @@
+# linux-universal.cmake 
+
+# 此构建表示,在 Linux 中以通用平台的构建方式进行构建此内容
+# 
+# /usr/bin/         在 Linux 中标准的程序位置
+#       Notepad--
+#
+# /usr/inculde/       在 Linux 中提供一系列可提供插件开发的头文件
+#       NotepadPlugin/
+#           pluginGl.h
+#           QSci/
+#           qscint/scintilla/
+#
+# /usr/lib/           在 Linux 中提供一个用于插件开发的核心依赖文件
+#       NotepadPlugin/
+#               libQSci.so
+# 
+# /usr/lib/cmake/         在 Linux 中提供一个用于插件开发的核心开发配置
+#           NotepadPlugin/
+#               NotepadPluginConfig.cmake
+#   
+# /usr/share/Notepad--/     在 Linux 中提供一个用于随带资源文件的目录
+#                   plugin/
+#                   themes/
+# 
+
+
+# 可能需要变更为 CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" ??
+# 并使用 Linux.cmake 维护?
+if(CMAKE_HOST_UNIX)
+    include(cmake/SparkInstallMacrosConfig.cmake)
+
+    # 当使用 Linux 构建应用时,可执行程序的资源文件应该存放在此处
+    set(LINUX_APPLICATION_DIR /usr/share/${PROJECT_NAME})
+
+    # 通用的 Linux 资源文件
+    spark_install_directory(/usr   cmake/platforms/linux/universal/usr/*)    
+    
+    # 如何安装 themes ? 安装到该程序的资源目录/themes
+    # 如何准备 plugin ?  安装到该程序的资源目录/plugin
+    spark_install_directory(${LINUX_APPLICATION_DIR}   src/themes)
+
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    include(CMakePackageConfigHelpers)
+    include(GNUInstallDirs)
+    
+    # 定义插件配置安装位置
+    set(CMAKE_INSTALL_PREFIX "/usr")
+    set(NOTEPAD_PLUGIN NotepadPlugin)
+    
+    # 定义开发插件时的配置目录与 CMake 模块文件名称
+    set(NOTEPAD_PLUGIN_CONFIG       ${NOTEPAD_PLUGIN}Config.cmake)
+    # 定义一些扩展内容,主要是提供给 CMake 模块文件填充
+    set(NOTEPAD_PLUGIN_CORELIB QSci) # QSci 为构建的 QScintllia 库
+
+    # 定义在插件开发的 CMake 模块中,Notepad-- 是否是基于 QT5 实现
+        # 并自动为插件开发层自动开启相关 Qt 依赖组件
+        # 此部分逻辑将自动提供给 add_notepad_plugin 自行处理
+    set(NOTEPAD_BUILD_BY_QT5 TRUE)
+    set(NOTEPAD_BUILD_BY_QT6 FALSE)
+
+    # 定义在平台中插件应该安装的位置(待确定)
+        # 定义在插件开发的 CMake 模块中,Notepad-- 是否将提供 "插件安装目录(位置)"
+    set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY "")
+
+    # 这些是在此部分安装时使用,但不被用于填充 NotepadPlugin.cmake.in 的内容
+    set(NOTEPAD_PLUGIN_INCLUDEDIR   ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/${NOTEPAD_PLUGIN})
+    set(NOTEPAD_PLUGIN_LIBDIR       ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${NOTEPAD_PLUGIN})
+    
+
+    # 将 NOTEPAD_PLUGIN_INCLUDEDIR NOTEPAD_PLUGIN_LIBDIR 填充到 cmake 文件
+    configure_package_config_file(cmake/NotepadPluginConfig.cmake.in
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG}
+        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN})
+    # 安装 cmake 文件
+    spark_install_file(${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN} 
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG})
+    # 安装头插件接口文件
+    spark_install_file(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/include/pluginGl.h)
+    # 安装插件所需要的Qsci文件
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/qscint/src/Qsci)
+    # 安装开发插件高级功能所需要的内容
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR}/qscint
+        src/qscint/scintilla)
+
+    # 导出 QSci 的头文件(从插件实现层面来看,目前是使用*.h 与 pluginGl.h
+        # 但从 Qsci 层面来看,*.h 使用的是 #include <Qsci/*.h> ,所以此部分不被使用)
+    # spark_file_glob(QSci_HEADERS src/qscint/src/Qsci/*.h src/include/pluginGl.h)
+    # set_target_properties(QSci PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 导出 Notepad-- 的接口文件(从逻辑层面来看,目前已经在前面安装了接口文件,所以此部分不被使用)
+    # spark_file_glob(Notepad_HEADERS src/include/pluginGl.h)
+    # set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 安装项目文件与 QSci 文件
+    install(TARGETS ${PROJECT_NAME} QSci
+        RUNTIME DESTINATION         bin
+        LIBRARY DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        ARCHIVE DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        PUBLIC_HEADER DESTINATION   ${NOTEPAD_PLUGIN_INCLUDEDIR}
+    )
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+
+endif(CMAKE_HOST_UNIX)

+ 72 - 0
cmake/platforms/linux-uos.cmake

@@ -0,0 +1,72 @@
+# linux-uos.cmake
+
+# 此构建表示,在独立于 Linux 的 Uos 或 Deepin 平台,以此方式构建内容
+# 1. 主要用于规范化构建,并使用项目中准备好的目录结构进行构建
+# 2. 安装内容
+    # 1. 起始路径要求: /opt/apps/<appid>/
+    # 2. 系统路径要求:  entries
+        # 1. icon、applications、metadata 等位于 entries
+    # 3. 文件部分要求: files
+        # 1. Notepad-- 位于 files
+        # 2. themes 位于 files
+        # 3. plugin 位于 files
+
+# /.
+# /opt
+# /opt/apps
+# /opt/apps/com.hmja.notepad
+# /opt/apps/com.hmja.notepad/entries
+# /opt/apps/com.hmja.notepad/entries/applications
+# /opt/apps/com.hmja.notepad/entries/applications/com.hmja.notepad.desktop
+# /opt/apps/com.hmja.notepad/entries/icons
+# /opt/apps/com.hmja.notepad/entries/icons/hicolor
+# /opt/apps/com.hmja.notepad/entries/icons/hicolor/scalable
+# /opt/apps/com.hmja.notepad/entries/icons/hicolor/scalable/apps
+# /opt/apps/com.hmja.notepad/entries/icons/hicolor/scalable/apps/ndd.svg
+# /opt/apps/com.hmja.notepad/files
+# /opt/apps/com.hmja.notepad/files/Notepad--
+# /opt/apps/com.hmja.notepad/files/themes
+# /opt/apps/com.hmja.notepad/files/themes/....
+# /opt/apps/com.hmja.notepad/info
+
+option(USE_LINUX_UOS "为 Linux Uos 生成规范的软件包" OFF)
+
+if(USE_LINUX_UOS)
+
+    # 一些相关的信息,用标准结构定义
+    set(UOS_APP_ID             "com.hmja.notepad")
+    set(UOS_APP_HOME_DIR       "/opt/apps/${UOS_APP_ID}")
+    set(UOS_APP_HOME_ENTRY_DIR "${UOS_APP_HOME_DIR}/entries")
+    set(UOS_APP_HOME_FILES_DIR "${UOS_APP_HOME_DIR}/files")
+    set(UOS_APP_HOME_INFO_FILE "${UOS_APP_HOME_DIR}/info")
+
+    # 当使用 Linux 构建应用时,可执行程序的资源文件应该存放在此处
+    set(LINUX_UOS_APP_HOME_DIR ${UOS_APP_HOME_DIR})
+    
+    include(cmake/SparkInstallMacrosConfig.cmake)
+
+    # ------------------ 部署应用目录结构 ------------------ #
+    # 1. 将项目内准备的 Uos 应用目录安装到 /opt/apps/ 中
+    spark_install_directory(/opt/apps/
+        cmake/platforms/linux/uos/${UOS_APP_HOME_DIR}
+    )
+
+    # ------------------ 构建与资源文件安装 ------------------ #
+    # 1. 安装可执行文件到 files 目录
+    spark_install_target(${UOS_APP_HOME_FILES_DIR}
+        ${PROJECT_NAME}
+    )
+    # 2. 安装 themes 目录到 files 目录
+    spark_install_directory(${UOS_APP_HOME_FILES_DIR}
+        src/themes
+    )
+
+    # ------------------ 最终打包 deb 部分 ------------------ #
+    # 1. 为即将构建的 Uos 增加 Uos 后缀
+    set(PACKAGE_SUFFIX "_Uos") 
+
+    # 2. 使用同样来自 debian 系列的 deb 构建能力
+    find_package(DebPackage PATHS ${CMAKE_SOURCE_DIR})
+    add_package_descript(cmake/package-deb.descript)
+
+endif(USE_LINUX_UOS)

+ 113 - 0
cmake/platforms/linux.cmake

@@ -0,0 +1,113 @@
+
+# 可能需要变更为 CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" ??
+# 并使用 Linux.cmake 维护?
+if(CMAKE_HOST_UNIX)
+    include(cmake/SparkInstallMacrosConfig.cmake)
+    include(cmake/SparkDesktopMacros.cmake)
+    # 内容默认应用名称: Name= 应与项目名称相同
+    spark_desktop_macros(
+        # 应用名称: Name=
+        ${PROJECT_NAME}
+        # 应用名称: Name[zh_CN]=
+        "Notepad--"
+        # 应用说明: Comment=
+        "Notepad-- 是一个国产跨平台、简单的文本编辑器。"
+        # 应用类型: Type=
+        "Application"
+        # 执行程序: Exec=
+        # 有关此 %F 参数可查看: https://gitee.com/zinface/z-tools/blob/desktop-dev/src/DesktopGenerater/desktopexecparamdialog.cpp
+        "notepad-- %F"
+        # 图标路径: Icon=
+        "/usr/share/notepad--/icons/spark.png"
+        # 应用分类: Category=
+        "Development"
+    )
+    # spark_install_file(/usr/share/applications/    ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.desktop)
+    # spark_install_file(/usr/share/notepad--/icons/ assets/spark.png)
+    # spark_install_target(/usr/bin/ ${PROJECT_NAME})
+
+    # 完成:如果主线已经将 linux/destkop 的PR合入,即可移除此部分以上部分,而使用以下部分
+        # 但 spark_desktop_macros 不能移除,因为它被 Appimage 构建部分依赖
+        # Appimage 构建部分,要求(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
+    spark_install_directory(/usr   src/linux/usr/*)    # 完整的 Linux 资源文件
+
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    include(CMakePackageConfigHelpers)
+    include(GNUInstallDirs)
+    
+    # 定义插件配置安装位置
+    set(CMAKE_INSTALL_PREFIX "/usr")
+    set(NOTEPAD_PLUGIN NotepadPlugin)
+    
+    # 定义开发插件时的配置目录与 CMake 模块文件名称
+    set(NOTEPAD_PLUGIN_CONFIG       ${NOTEPAD_PLUGIN}Config.cmake)
+    # 定义一些扩展内容,主要是提供给 CMake 模块文件填充
+    set(NOTEPAD_PLUGIN_CORELIB QSci) # QSci 为构建的 QScintllia 库
+
+    # 定义在插件开发的 CMake 模块中,Notepad-- 是否是基于 QT5 实现
+        # 并自动为插件开发层自动开启相关 Qt 依赖组件
+        # 此部分逻辑将自动提供给 add_notepad_plugin 自行处理
+    set(NOTEPAD_BUILD_BY_QT5 TRUE)
+    set(NOTEPAD_BUILD_BY_QT6 FALSE)
+
+    # 定义在平台中插件应该安装的位置(待确定)
+        # 定义在插件开发的 CMake 模块中,Notepad-- 是否将提供 "插件安装目录(位置)"
+    set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY "")
+
+    # 这些是在此部分安装时使用,但不被用于填充 NotepadPlugin.cmake.in 的内容
+    set(NOTEPAD_PLUGIN_INCLUDEDIR   ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/${NOTEPAD_PLUGIN})
+    set(NOTEPAD_PLUGIN_LIBDIR       ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${NOTEPAD_PLUGIN})
+    
+
+    # 将 NOTEPAD_PLUGIN_INCLUDEDIR NOTEPAD_PLUGIN_LIBDIR 填充到 cmake 文件
+    configure_package_config_file(cmake/NotepadPluginConfig.cmake.in
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG}
+        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN})
+    # 安装 cmake 文件
+    spark_install_file(${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN} 
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG})
+    # 安装头插件接口文件
+    spark_install_file(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/include/pluginGl.h)
+    # 安装插件所需要的Qsci文件
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/qscint/src/Qsci)
+    # 安装开发插件高级功能所需要的内容
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR}/qscint
+        src/qscint/scintilla)
+
+    # 导出 QSci 的头文件(从插件实现层面来看,目前是使用*.h 与 pluginGl.h
+        # 但从 Qsci 层面来看,*.h 使用的是 #include <Qsci/*.h> ,所以此部分不被使用)
+    # spark_file_glob(QSci_HEADERS src/qscint/src/Qsci/*.h src/include/pluginGl.h)
+    # set_target_properties(QSci PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 导出 Notepad-- 的接口文件(从逻辑层面来看,目前已经在前面安装了接口文件,所以此部分不被使用)
+    # spark_file_glob(Notepad_HEADERS src/include/pluginGl.h)
+    # set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 安装项目文件与 QSci 文件
+    install(TARGETS ${PROJECT_NAME} QSci
+        RUNTIME DESTINATION         bin
+        LIBRARY DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        ARCHIVE DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        PUBLIC_HEADER DESTINATION   ${NOTEPAD_PLUGIN_INCLUDEDIR}
+    )
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+
+
+    # 1. 在顶层构建中导入 Appimage 的构建
+    include(cmake/SparkAppimageConfig.cmake)  # 导入来自 Spark 构建的 Appimage 构建
+    add_appimage_icon(assets/spark.png)       # 添加到 Appimage 中的默认的图标
+    add_appimage_desktop()                    # 添加到 Appimage 中的默认desktop(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
+    add_appimage()                            # 应用对 Appimage 的构建
+
+
+    # 注释行(使用方式)
+    find_package(DebPackage PATHS ${CMAKE_SOURCE_DIR})
+    add_package_descript(cmake/package-deb.descript)
+
+endif(CMAKE_HOST_UNIX)

+ 13 - 0
cmake/platforms/linux/universal/usr/share/applications/io.gitee.cxasm.notepad--.desktop

@@ -0,0 +1,13 @@
+[Desktop Entry]
+Version=1.0
+Name=Notepad--
+Name[zh_CN]=Notepad--
+Comment=Notepad-- 是一个国产跨平台、简单的文本编辑器。
+Type=Application
+Exec=Notepad-- %F 
+Icon=notepad--
+Categories=Development;Office;
+Terminal=false
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-patch;text/x-adasrc;text/x-chdr;text/x-csrc;text/css;application/x-desktop;text/x-patch;text/x-fortran;text/html;text/x-java;text/x-tex;text/x-makefile;text/x-objcsrc;text/x-pascal;application/x-perl;application/x-perl;application/x-php;text/vnd.wap.wml;text/x-python;application/x-ruby;text/sgml;application/xml;model/vrml;image/svg+xml;application/json;
+
+# Generated from the DesktopGenerater component of the z-Tools toolkit

BIN
cmake/platforms/linux/universal/usr/share/icons/hicolor/128x128/apps/notepad--.png


BIN
cmake/platforms/linux/universal/usr/share/icons/hicolor/32x32/apps/notepad--.png


BIN
cmake/platforms/linux/universal/usr/share/icons/hicolor/64x64/apps/notepad--.png


+ 674 - 0
cmake/platforms/linux/universal/usr/share/licenses/notepad--/LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 18 - 0
cmake/platforms/linux/universal/usr/share/metainfo/io.gitee.cxasm.notepad--.metainfo.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="desktop-application">
+  <id>io.gitee.cxasm.notepad--</id>
+
+  <name>Notepad--</name>
+  <summary>Notepad--</summary>
+
+  <metadata_license>MIT</metadata_license>
+  <project_license>GPL-2.0-or-later</project_license>
+
+  <description>
+    <p>
+      notepad--是一个国产跨平台、简单的文本编辑器,是替换notepad++的一种选择。其内置强大的代码对比功能,让你丢掉付费的beyond compare。
+    </p>
+  </description>
+
+  <launchable type="desktop-id">io.gitee.cxasm.notepad--.desktop</launchable>
+</component>

+ 17 - 0
cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/applications/io.gitee.cxasm.notepad--.desktop

@@ -0,0 +1,17 @@
+[Desktop Entry]
+Version=1.0
+Name=Notepad--
+Name[zh_CN]=Notepad--
+Comment=Notepad-- 是一个国产跨平台、简单的文本编辑器。
+Type=Application
+Exec=/opt/apps/com.hmja.notepad/files/Notepad-- %U
+Icon=/opt/apps/com.hmja.notepad/entries/icons/hicolor/scalable/apps/ndd.svg
+Categories=TextEditor;
+Encoding=UTF-8
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-patch;text/x-adasrc;text/x-chdr;text/x-csrc;text/css;application/x-desktop;text/x-patch;text/x-fortran;text/html;text/x-java;text/x-tex;text/x-makefile;text/x-objcsrc;text/x-pascal;application/x-perl;application/x-perl;application/x-php;text/vnd.wap.wml;text/x-python;application/x-ruby;text/sgml;application/xml;model/vrml;image/svg+xml;application/json;
+StartupNotify=true
+Terminal=false
+TryExec=/opt/apps/com.hmja.notepad/files/Notepad--
+X-DDE-FileManager-MenuTypes=SingleFile
+
+# Generated from the DesktopGenerater component of the z-Tools toolkit

+ 2 - 0
cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/icons/hicolor/scalable/apps/ndd.svg

@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653643519286" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8215" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
+</style></defs><path d="M648.479968 0.00064h-511.99968A48.959969 48.959969 0 0 0 100.64031 15.36063 54.399966 54.399966 0 0 0 85.28032 51.200608v921.599424a48.959969 48.959969 0 0 0 15.35999 35.839978A50.559968 50.559968 0 0 0 136.480288 1024h751.039531a49.279969 49.279969 0 0 0 35.839977-15.35999 50.559968 50.559968 0 0 0 15.359991-35.839978V290.240459z" fill="#A5D940" p-id="8216"></path><path d="M938.719787 290.240459H699.679936a52.479967 52.479967 0 0 1-51.199968-51.199968V0.00064l290.239819 290.239819z" fill="#C4EAFF" p-id="8217"></path><path d="M407.520119 459.520353v29.759981H331.360166v198.719876H296.800188v-198.719876H220.320236v-29.759981zM462.240084 459.520353l55.679966 82.559948 55.679965-82.559948h42.559973l-77.439951 110.399931 82.879948 118.079926h-42.559974l-61.119961-90.559943-61.119962 90.559943h-42.559974l82.239949-118.079926-76.799952-110.399931zM815.199864 459.520353v29.759981h-76.159953v198.719876h-34.559978v-198.719876H629.27998v-29.759981z" fill="#FFFFFF" p-id="8218"></path></svg>

+ 674 - 0
cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/licenses/notepad--/LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 18 - 0
cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/entries/metainfo/io.gitee.cxasm.notepad--.metainfo.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="desktop-application">
+  <id>io.gitee.cxasm.notepad--</id>
+
+  <name>Notepad--</name>
+  <summary>Notepad--</summary>
+
+  <metadata_license>MIT</metadata_license>
+  <project_license>GPL-2.0-or-later</project_license>
+
+  <description>
+    <p>
+      notepad--是一个国产跨平台、简单的文本编辑器,是替换notepad++的一种选择。其内置强大的代码对比功能,让你丢掉付费的beyond compare。
+    </p>
+  </description>
+
+  <launchable type="desktop-id">io.gitee.cxasm.notepad--.desktop</launchable>
+</component>

+ 18 - 0
cmake/platforms/linux/uos/opt/apps/com.hmja.notepad/info

@@ -0,0 +1,18 @@
+{
+  "appid": "com.hmja.notepad",
+  "name": "Notepad--",
+  "version": "1.22.1.0",
+  "arch": ["amd64"],
+  "permissions": {
+    "autostart": false,
+    "notification": false,
+    "trayicon": false,
+    "clipboard": true,
+    "account": false,
+    "bluetooth": false,
+    "camera": false,
+    "audio_record": false,
+    "installed_apps": false
+  }
+}
+

+ 0 - 0
cmake/platforms/macos.cmake


+ 94 - 0
cmake/platforms/windows-deployqt.cmake

@@ -0,0 +1,94 @@
+# windows-deployqt.cmake
+
+# Windows 平台 windeployqt 自动化模块
+# 在对项目进行构建时,是否需要配置 deployqt 来为项目进行构建部署设计
+
+# 1. 如果需要进行 windeployqt,需要提供此 WINDOWS_DEPLOY_QT 开关
+# 2. 默认应用构建的内容将随附在此处
+# 3. 预先设置一个默认的 Windows Qt 目录变量
+set(WINDOWS_QT_DIR "")
+
+option(WINDOWS_DEPLOY_QT  "为 Windows 中构建的应用进行 windeployqt" OFF)
+option(WINDOWS_DEPLOY_QT5 "为 Windows 中构建的 QT5 应用进行 windeployqt" OFF)
+option(WINDOWS_DEPLOY_QT6 "为 Windows 中构建的 QT6 应用进行 windeployqt" OFF)
+
+if(WINDOWS_DEPLOY_QT)    
+
+    if(WINDOWS_DEPLOY_QT5)
+        # 当使用 WINDOWS_DEPLOY_QT5 配方时,将使用来源于 Qt5 中提供的路径
+        set(WINDOWS_QT_DIR "${Qt5_DIR}")
+    elseif(WINDOWS_DEPLOY_QT6)
+        # 当使用 WINDOWS_DEPLOY_QT6 配方时,将使用来源于 Qt6 中提供的路径
+        set(WINDOWS_QT_DIR "${Qt6_DIR}")
+    endif()
+
+    if (WINDOWS_DEPLOY_QT5 OR WINDOWS_DEPLOY_QT6)
+        message(" -------- ${CMAKE_INSTALL_PREFIX} ---------- ")
+        message("${WINDOWS_QT_DIR}/../../../bin/windeployqt")
+
+        # install(TARGETS ${PROJECT_NAME} 
+        #     DESTINATION ${CMAKE_BINARY_DIR}/windows-deployqt)
+
+
+        # 配置一个自动运行 windeployqt 配方的位置
+        # 当使用 Windows Deploy Qt 时,可执行程序与即将部署的应用运行时将在此处出现
+        set(WINDOWS_APPLICATION_DEPLOY_PATH 
+            ${CMAKE_BINARY_DIR}/windows-deployqt/${PROJECT_NAME}.app/bin)
+
+        # 在开启支持 windeployqt 配方后,这部分将会改变默认构建的目标的一些行为
+        # 这是 windeployqt,所以,它应该是一个 WIN32 程序
+        # 它的输出目录将定义为
+        set_target_properties(${PROJECT_NAME}
+            PROPERTIES
+                # 这是一个 WIN32 程序,即可执行文件不再出现黑窗口,转而使用 WinMain(某种 Windows 内部特性)
+                WIN32_EXECUTABLE true
+                # 静态库生成目录
+                # ARCHIVE_OUTPUT_DIRECTORY ""
+                # 动态库生成目录
+                # LIBRARY_OUTPUT_DIRECTORY ""
+                # 可执行文件生成目录
+                RUNTIME_OUTPUT_DIRECTORY ${WINDOWS_APPLICATION_DEPLOY_PATH})
+        
+        # 自动化构建 Windows Deploy Qt Application
+        # 参考: windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>
+        add_custom_command(TARGET ${PROJECT_NAME}
+            # 在构建之后计划进行执行以下命令
+            POST_BUILD
+                # 即将在构建目录中
+                WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+                # 执行以下命令进行 windeployqt
+                COMMAND ${WINDOWS_QT_DIR}/../../../bin/windeployqt
+                    # 
+                    ${WINDOWS_APPLICATION_DEPLOY_PATH}/${PROJECT_NAME}.exe
+
+                    # 扫描QML-从目录开始导入。
+                    --qmlimport ${WINDOWS_QT_DIR}/../../../qml
+                    # 部署编译器运行时(仅限桌面)。
+                    --compiler-runtime  
+                    # 详细级别(0-2)
+                    --verbose 2
+                    # 部署运行时使用指定的目录
+                    --dir ${WINDOWS_APPLICATION_DEPLOY_PATH}
+        )
+
+        # 此部分为创建一个 windows-deployqt 的虚拟目标,用于对执行安装后的应用进行 windeployqt
+        # 手动化构建 Windows Deploy Qt Application
+        # 参考: windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>
+        add_custom_target(windows-deployqt
+            COMMAND ${WINDOWS_QT_DIR}/../../../bin/windeployqt
+                    # 
+                    ${WINDOWS_APPLICATION_DEPLOY_PATH}/${PROJECT_NAME}.exe
+
+                    # 扫描QML-从目录开始导入。
+                    --qmlimport ${WINDOWS_QT_DIR}/../../../qml
+                    # 部署编译器运行时(仅限桌面)。
+                    --compiler-runtime  
+                    # 详细级别(0-2)
+                    --verbose 2
+                    # 部署运行时使用指定的目录
+                    --dir ${CMAKE_INSTALL_PREFIX}/bin
+        )
+
+    endif (WINDOWS_DEPLOY_QT5 OR WINDOWS_DEPLOY_QT6)
+
+endif(WINDOWS_DEPLOY_QT)

+ 93 - 0
cmake/platforms/windows-universal.cmake

@@ -0,0 +1,93 @@
+# windows-universal.cmake 
+
+# 此构建表示,在 Windows 中以通用平台构建方式进行构建此内容
+# 为 Notepad-- 通用构建的设计安装结构
+#  
+# /bin                  在 Windows 中标准的程序位置
+#   Notepad--.exe
+#   plugin/
+#   themes
+# 
+# /include/             在 Windows 中提供一系列可提供插件开发的头文件
+#       NotepadPlugin/
+#           pluginGl.h
+#           QSci/
+#           qscint/scintilla/
+# 
+# /lib/             在 Windows 中提供一个用于插件开发的核心依赖文件
+#   NotepadPlugin/
+#       libQSci.so
+# 
+
+
+if(CMAKE_HOST_WIN32)
+    include(cmake/SparkInstallMacrosConfig.cmake)
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    include(CMakePackageConfigHelpers)
+    include(GNUInstallDirs)
+    
+    # 定义插件配置安装位置
+    # set(CMAKE_INSTALL_PREFIX "/usr") # 仅限 Linux ,Windows 中不使用
+    set(NOTEPAD_PLUGIN NotepadPlugin)
+    
+    # 定义开发插件时的配置目录与 CMake 模块文件名称
+    set(NOTEPAD_PLUGIN_CONFIG       ${NOTEPAD_PLUGIN}Config.cmake)
+    # 定义一些扩展内容,主要是提供给 CMake 模块文件填充
+    set(NOTEPAD_PLUGIN_CORELIB QSci) # QSci 为构建的 QScintllia 库
+
+    # 定义在插件开发的 CMake 模块中,Notepad-- 是否是基于 QT5 实现
+        # 并自动为插件开发层自动开启相关 Qt 依赖组件
+        # 此部分逻辑将自动提供给 add_notepad_plugin 自行处理
+    set(NOTEPAD_BUILD_BY_QT5 TRUE)
+    set(NOTEPAD_BUILD_BY_QT6 FALSE)
+
+    # 定义在平台中插件应该安装的位置(待确定)
+        # 定义在插件开发的 CMake 模块中,Notepad-- 是否将提供 "插件安装目录(位置)"
+    set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY "")
+
+    # 这些是在此部分安装时使用,但不被用于填充 NotepadPlugin.cmake.in 的内容
+    set(NOTEPAD_PLUGIN_INCLUDEDIR   ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/${NOTEPAD_PLUGIN})
+    set(NOTEPAD_PLUGIN_LIBDIR       ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${NOTEPAD_PLUGIN})
+    
+
+    # 将 NOTEPAD_PLUGIN_INCLUDEDIR NOTEPAD_PLUGIN_LIBDIR 填充到 cmake 文件
+    configure_package_config_file(cmake/NotepadPluginConfig.cmake.in
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG}
+        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN})
+    # 安装 cmake 文件
+    spark_install_file(${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN} 
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG})
+    # 安装头插件接口文件
+    spark_install_file(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/include/pluginGl.h)
+    # 安装插件所需要的Qsci文件
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/qscint/src/Qsci)
+    # 安装开发插件高级功能所需要的内容
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR}/qscint
+        src/qscint/scintilla)
+
+    # 导出 QSci 的头文件(从插件实现层面来看,目前是使用*.h 与 pluginGl.h
+        # 但从 Qsci 层面来看,*.h 使用的是 #include <Qsci/*.h> ,所以此部分不被使用)
+    # spark_file_glob(QSci_HEADERS src/qscint/src/Qsci/*.h src/include/pluginGl.h)
+    # set_target_properties(QSci PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 导出 Notepad-- 的接口文件(从逻辑层面来看,目前已经在前面安装了接口文件,所以此部分不被使用)
+    # spark_file_glob(Notepad_HEADERS src/include/pluginGl.h)
+    # set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 安装项目文件与 QSci 文件
+    install(TARGETS ${PROJECT_NAME} QSci
+        RUNTIME DESTINATION         bin
+        LIBRARY DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        ARCHIVE DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        PUBLIC_HEADER DESTINATION   ${NOTEPAD_PLUGIN_INCLUDEDIR}
+    )
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+
+endif(CMAKE_HOST_WIN32)
+

+ 80 - 0
cmake/platforms/windows.cmake

@@ -0,0 +1,80 @@
+
+if(CMAKE_HOST_WIN32)
+    include(cmake/SparkInstallMacrosConfig.cmake)
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    include(CMakePackageConfigHelpers)
+    include(GNUInstallDirs)
+    
+    # 定义插件配置安装位置
+    # set(CMAKE_INSTALL_PREFIX "/usr") # 仅限 Linux ,Windows 中不使用
+    set(NOTEPAD_PLUGIN NotepadPlugin)
+    
+    # 定义开发插件时的配置目录与 CMake 模块文件名称
+    set(NOTEPAD_PLUGIN_CONFIG       ${NOTEPAD_PLUGIN}Config.cmake)
+    # 定义一些扩展内容,主要是提供给 CMake 模块文件填充
+    set(NOTEPAD_PLUGIN_CORELIB QSci) # QSci 为构建的 QScintllia 库
+
+    # 定义在插件开发的 CMake 模块中,Notepad-- 是否是基于 QT5 实现
+        # 并自动为插件开发层自动开启相关 Qt 依赖组件
+        # 此部分逻辑将自动提供给 add_notepad_plugin 自行处理
+    set(NOTEPAD_BUILD_BY_QT5 TRUE)
+    set(NOTEPAD_BUILD_BY_QT6 FALSE)
+
+    # 定义在平台中插件应该安装的位置(待确定)
+        # 定义在插件开发的 CMake 模块中,Notepad-- 是否将提供 "插件安装目录(位置)"
+    set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY "")
+
+    # 这些是在此部分安装时使用,但不被用于填充 NotepadPlugin.cmake.in 的内容
+    set(NOTEPAD_PLUGIN_INCLUDEDIR   ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/${NOTEPAD_PLUGIN})
+    set(NOTEPAD_PLUGIN_LIBDIR       ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${NOTEPAD_PLUGIN})
+    
+
+    # 将 NOTEPAD_PLUGIN_INCLUDEDIR NOTEPAD_PLUGIN_LIBDIR 填充到 cmake 文件
+    configure_package_config_file(cmake/NotepadPluginConfig.cmake.in
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG}
+        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN})
+    # 安装 cmake 文件
+    spark_install_file(${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN} 
+        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG})
+    # 安装头插件接口文件
+    spark_install_file(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/include/pluginGl.h)
+    # 安装插件所需要的Qsci文件
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR} 
+        src/qscint/src/Qsci)
+    # 安装开发插件高级功能所需要的内容
+    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR}/qscint
+        src/qscint/scintilla)
+
+    # 导出 QSci 的头文件(从插件实现层面来看,目前是使用*.h 与 pluginGl.h
+        # 但从 Qsci 层面来看,*.h 使用的是 #include <Qsci/*.h> ,所以此部分不被使用)
+    # spark_file_glob(QSci_HEADERS src/qscint/src/Qsci/*.h src/include/pluginGl.h)
+    # set_target_properties(QSci PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 导出 Notepad-- 的接口文件(从逻辑层面来看,目前已经在前面安装了接口文件,所以此部分不被使用)
+    # spark_file_glob(Notepad_HEADERS src/include/pluginGl.h)
+    # set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
+
+    # 安装项目文件与 QSci 文件
+    install(TARGETS ${PROJECT_NAME} QSci
+        RUNTIME DESTINATION         bin
+        LIBRARY DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        ARCHIVE DESTINATION         ${NOTEPAD_PLUGIN_LIBDIR}
+        PUBLIC_HEADER DESTINATION   ${NOTEPAD_PLUGIN_INCLUDEDIR}
+    )
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+
+    message(" -------- ${CMAKE_INSTALL_PREFIX} ---------- ")
+    message("${Qt5_DIR}/../../../bin/windeployqt")
+
+	# 1. 在顶层构建中导入 WindowsQtDeploy 的构建
+    # 自动化构建 Windows Qt 部署功能
+    add_custom_target(windeployqt
+            COMMAND ${Qt5_DIR}/../../../bin/windeployqt ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.exe --compiler-runtime --verbose 2 --dir ${CMAKE_BINARY_DIR}/winqt/)
+
+endif(CMAKE_HOST_WIN32)
+

+ 10 - 0
cmake/spark-appimage.desktop.in

@@ -0,0 +1,10 @@
+[Desktop Entry]
+Name=@APP_NAME@
+Name[zh_CN]=@APP_NAME_ZH_CN@
+Exec=AppRun %F
+Icon=default
+Comment=@APP_COMMENT@
+Terminal=true
+Type=Application
+Categories=@APP_CATEGORIES@
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-patch;text/x-adasrc;text/x-chdr;text/x-csrc;text/css;application/x-desktop;text/x-patch;text/x-fortran;text/html;text/x-java;text/x-tex;text/x-makefile;text/x-objcsrc;text/x-pascal;application/x-perl;application/x-perl;application/x-php;text/vnd.wap.wml;text/x-python;application/x-ruby;text/sgml;application/xml;model/vrml;image/svg+xml;application/json;

+ 12 - 0
cmake/spark-desktop.desktop.in

@@ -0,0 +1,12 @@
+[Desktop Entry]
+Version=1.0
+Name=@APP_NAME@
+Name[zh_CN]=@APP_NAME_ZH_CN@
+Comment=@APP_COMMENT@
+Type=@APP_TYPE@
+Exec=@APP_EXECUTE_PATH@
+Icon=@APP_EXECUTE_ICON_PATH@
+Categories=@APP_CATEGORIES@
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-patch;text/x-adasrc;text/x-chdr;text/x-csrc;text/css;application/x-desktop;text/x-patch;text/x-fortran;text/html;text/x-java;text/x-tex;text/x-makefile;text/x-objcsrc;text/x-pascal;application/x-perl;application/x-perl;application/x-php;text/vnd.wap.wml;text/x-python;application/x-ruby;text/sgml;application/xml;model/vrml;image/svg+xml;application/json;
+
+# Generated from the DesktopGenerater component of the z-Tools toolkit

+ 47 - 0
linux-appimage.mk

@@ -0,0 +1,47 @@
+# Linux Appimage - 通用 Linux 平台 Appimage 构建方案
+
+include linux-universal.mk
+
+CPUS=$(shell nproc)
+
+builddir  := build/linux-appimage
+# sourcedir := .
+# CMAKE_DEBUG     := -DCMAKE_BUILD_TYPE=Debug
+# CMAKE_RELEASE   := -DCMAKE_BUILD_TYPE=Release
+CMAKE_OPTIONS   := -DUSE_LINUX_APPIMAGE=ON $(CMAKE_OPTIONS)
+
+
+# -------------------------------- Appimage Build Tools -------------------------------- #
+# Appimage 的构建流 --
+# 在 Makefile 进行构建目标构建 Appimage (要求提供工具的绝对路径,然后可依次进行linuxdeployqt, genrate-appimage)
+# 来自于 https://github.com/probonopd/linuxdeployqt 	的 linuxdeployqt
+# 来自于 https://github.com/AppImage/AppImageKit		的 appimagetool
+# 来自于 https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git  托管存储的工具
+
+# 或指定你所想存放克隆项目的位置
+BUNDLE_LINUXDEPLOYQT := $(shell pwd)/$(builddir)/bundle-linuxdeployqt
+
+download-bundle-linuxdeploytools:
+	-git clone https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git $(BUNDLE_LINUXDEPLOYQT)
+
+LINUXDEPLOYQT := "$(BUNDLE_LINUXDEPLOYQT)/linuxdeployqt-continuous-x86_64.AppImage"
+APPIMAGETOOL  := "$(BUNDLE_LINUXDEPLOYQT)/appimagetool-x86_64.AppImage"
+
+# 追加 Appimagetool、linuxdeployqt 构建配置
+CMAKE_OPTIONS := -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL) $(CMAKE_OPTIONS)
+
+linuxdeploy: download-bundle-linuxdeploytools
+	cmake -B$(builddir) $(CMAKE_OPTIONS)
+	cmake --build $(builddir) -- linuxdeploy
+
+genrate-appimage:
+	cmake -B$(builddir) $(CMAKE_OPTIONS)
+	cmake --build $(builddir) -- appimage
+
+
+package: linux-universal-release linuxdeploy genrate-appimage
+
+linux-build-options:
+	@echo $(CMAKE_OPTIONS)
+
+# 此配置为构建 linux Appimage 通用版本构建

+ 19 - 0
linux-debian.mk

@@ -0,0 +1,19 @@
+# Linux Debian - 通用 Linux 平台 Debian 构建方案
+
+include linux-universal.mk
+
+CPUS=$(shell nproc)
+
+builddir  := build/linux-debian
+# sourcedir := .
+# CMAKE_DEBUG     := -DCMAKE_BUILD_TYPE=Debug
+# CMAKE_RELEASE   := -DCMAKE_BUILD_TYPE=Release
+CMAKE_OPTIONS   := -DUSE_LINUX_DEBIAN=ON $(CMAKE_OPTIONS)
+
+package: linux-universal-release
+	make -C $(builddir) package
+
+linux-build-options:
+	@echo $(CMAKE_OPTIONS)
+
+# 此配置为构建 linux debian 通用版本构建

+ 21 - 0
linux-universal.mk

@@ -0,0 +1,21 @@
+# Linux Universal - 通用 Linux 平台 构建方案
+
+CPUS=$(shell nproc)
+
+builddir  := build/linux-universal
+sourcedir := .
+CMAKE_DEBUG     := -DCMAKE_BUILD_TYPE=Debug
+CMAKE_RELEASE   := -DCMAKE_BUILD_TYPE=Release
+CMAKE_OPTIONS   := -DUSE_LINUX_UNIVERSAL=ON
+
+
+linux-universal:
+	cmake -B$(builddir) $(CMAKE_OPTIONS) $(CMAKE_DEBUG)
+	cmake --build $(builddir) -- -j$(CPUS)
+
+
+linux-universal-release:
+	cmake -B$(builddir) $(CMAKE_OPTIONS) $(CMAKE_RELEASE)
+	cmake --build $(builddir) -- -j$(CPUS)
+
+# 此配置为构建 linux 通用版本构建

+ 39 - 0
linux-uos.mk

@@ -0,0 +1,39 @@
+# 独立 Linux 平台的 Uos 构建
+
+include linux-universal.mk
+
+# 覆盖 linux-universal.mk 中定义的部分
+linux-universal:
+	@echo "此目标不应该由 UOS 配方构建"
+linux-universal-release:
+	@echo "此目标不应该由 UOS 配方构建"
+
+
+CPUS=$(shell nproc)
+
+builddir  := build/linux-uos
+# sourcedir := .
+# CMAKE_DEBUG     := -DCMAKE_BUILD_TYPE=Debug
+# CMAKE_RELEASE   := -DCMAKE_BUILD_TYPE=Release
+CMAKE_OPTIONS   := -DUSE_LINUX_UOS=ON
+
+
+linux-uos:
+	cmake -B$(builddir) $(CMAKE_OPTIONS) $(CMAKE_DEBUG)
+	cmake --build build -- -j$(CPUS)
+
+linux-uos-release:
+	cmake -B$(builddir) $(CMAKE_OPTIONS) $(CMAKE_RELEASE)
+	cmake --build build -- -j$(CPUS)
+
+package:
+	cmake -B$(builddir) $(CMAKE_OPTIONS) $(CMAKE_RELEASE)
+	cmake --build $(builddir) -- -j$(CPUS) package
+
+package-contents:
+	-cd $(builddir)/_CPack_Packages/Linux/DEB/ && find
+
+package-contents-tree:
+	-tree $(builddir)/_CPack_Packages/Linux/DEB/
+
+# 此配置为构建 linux 通用版本构建

+ 10 - 38
linux.mk

@@ -1,42 +1,14 @@
-CPUS=$(shell nproc)
-CALENDAR=$(shell date '+%Y%m%d')
-OSID=$(shell lsb_release -si)
-OSRELEASE=$(shell lsb_release -sr)
-SUFFIX=
-ifneq ("$(OSID)", "")
-SUFFIX=_$(OSID)$(OSRELEASE)
-endif
+Msg   := 'Build with the following configuration:'
+One   := '1. make -f linux-universal.mk'
+Two   := '2. make -f linux-debian.mk package'
+Three := '3. make -f linux-appimage.mk package'
+Four  := '4. make -f linux-uos.mk package'
 
-PROJECT_NAME=notepad--
-PACKAGE_NAME=com.hmja.notepad
 
 all:
-	mkdir -p build
-	cd build && cmake ..
-	cd build && make -j$(CPUS)
-
-run: all
-	exec $(shell find build/ -maxdepth 1 -type f -executable | grep $(PROJECT_NAME))
-
-debug:
-	mkdir -p build
-	cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..
-	cd build && make -j$(CPUS)
-
-release:
-	mkdir -p build
-	cd build && cmake -DCMAKE_BUILD_TYPE=Release -DPLUGIN_EN=off -DPACKAGE_SUFFIX="$(SUFFIX)" ..
-	cd build && make -j$(CPUS)
-
-package: release
-	cd build && make package
-	tree build/_CPack_Packages/Linux/DEB/$(PROJECT_NAME)-*
-# 	dpkg-deb --contents build/$(PROJECT_NAME)$(SUFFIX).deb
-
-builddeps:
-	cd build && make builddeps
-
-cpus:
-	@echo "CPU数量: $(CPUS)"
-
+	@echo $(Msg)
+	@echo $(One)    "\n\t默认的通用 Linux 平台构建."
+	@echo $(Two)    "\n\t通用 Linux 平台的 Debian deb 构建."
+	@echo $(Three)  "\n\t通用 Linux 平台的 Appimage 构建."
+	@echo $(Four)   "\n\t独立 Linux 平台的 Uos 构建."
 

+ 4 - 0
macos.mk

@@ -0,0 +1,4 @@
+Msg   := 'Build with the following configuration:'
+
+all:
+	@echo $(Msg)

+ 56 - 0
patchs/README.md

@@ -0,0 +1,56 @@
+# 补丁操作说明
+
+> 用于 patchs/coconil-cmake-spark-deb-appimage.patch 补丁化构建方式
+
+- 如何使用此补丁(测试本补丁)
+
+    > 注:此补丁仅可基于 master 分支进行构建
+
+    1. 在项目中使用此补丁?
+        ```shell
+        git am --whitespace=fix < patchs/coconil-cmake-spark-deb-appimage.patch 
+        ```
+    2. 使用在线的方式直接使用补丁文件,并对纯净的 ndd 项目进行打补丁
+        ```
+        # 克隆 notepad-- 项目
+        git clone https://gitee.com/cxasm/notepad--
+        cd notepad--
+    
+        # 打在线补丁 
+        curl -s https://gitee.com/zinface/coconil-notepad--/raw/cmake-patchs/patchs/coconil-cmake-spark-deb-appimage.patch | git am --whitespace=fix
+    
+        make package     # 构建 release 模式的 deb 包
+        make linuxdeploy # 构建出相关文件与自动组织 appimage 的结构目录
+        make genrate-appimage # 基于已 linuxdeploy 的结构目录进行打包为 Appimage 
+        ```
+
+
+- 在应用补丁时,并对补丁进行的更新操作
+
+    ```shell
+    # 切换到一个新的分支,即可开始进行补丁内的更新提交
+    git checkout -b coconil-cmake-spark-deb-appimage
+    
+    # origin/dev 表示本仓库的 dev 开发分支
+    # 在应用过补丁,并产生了新的提交,即可在当前所在补丁更新分支内
+    # 相对基于 origin/master 为参考,目前所包含的所有最新提交内容将生成为一个补丁文件(其中尾部为增量更新)
+    git format-patch --stdout origin/master > patchs/coconil-cmake-spark-deb-appimage.patch
+
+    # 最后,回到你的原 master 分支,将被改变的补丁文件进行提交
+    # 在推送完成后,即可放弃你在 coconil-cmake-spark-deb-appimage 分支中所有产生的内容(因为都已经进入补丁)
+    ```
+
+- 一些注意事项
+
+    ```shell
+    # 在不了解补丁时,你需要认识一下补丁,但补丁与补丁之间有着不同的用法
+    # 本 patchs/coconil-cmake-spark-deb-appimage.patch 补丁为支持 Appimage 构建
+    
+    # 关于补丁的一些方面
+    # 1. 首先你需要了解 git 是什么,以及简单的使用
+    # 2. 你需要了解补丁是什么,以及简单的使用(应用补丁)
+    # 3. 你需要了解如何创建一个补丁,最基本的就是相对于旧目标分支,将本分区新增的提交进行导出为补丁
+    # 4. 你可能只会将单个提交、或多个提交导出为补丁,但这还不够,你需要具有绝对的对于补丁的理解
+    # 5. 对于不同的目的补丁,应该是多个 patch 文件存在的形式
+    # 6. 最后,不管在什么时候,你在应用补丁前,你应该考虑是否应用到当前分支?为什么不切换到一个新的分支呢?
+    ```

+ 890 - 0
patchs/base-4c8661d74aa78ea504a9a2f8b06139d571caed3d-linux-qt6.patch

@@ -0,0 +1,890 @@
+From 34d458cf82810609bee2c85f1eb772bbef40a152 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Mon, 6 Feb 2023 16:40:36 +0800
+Subject: [PATCH] =?UTF-8?q?linux-qt6:=20=E6=B7=BB=E5=8A=A0=E7=94=A8?=
+ =?UTF-8?q?=E4=BA=8E=20Qt6=20=E7=BC=96=E8=AF=91=E7=9A=84=E7=9B=B8=E5=85=B3?=
+ =?UTF-8?q?=E5=8F=98=E6=9B=B4?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ src/CmpareMode.cpp            |  4 +-
+ src/Encode.cpp                |  2 +-
+ src/RealCompare.pro           | 44 ++++++++++----------
+ src/batchfindreplace.cpp      |  6 +--
+ src/cceditor/ccnotepad.cpp    | 64 ++++++++++++++--------------
+ src/columnedit.cpp            |  4 +-
+ src/ctipwin.cpp               |  2 +-
+ src/draglineedit.cpp          |  1 +
+ src/encodeconvert.cpp         |  2 +-
+ src/findresultwin.cpp         | 26 +++++++-----
+ src/findwin.cpp               |  4 +-
+ src/langstyledefine.cpp       |  8 ++--
+ src/nddsetting.cpp            |  2 +-
+ src/qscint/src/qscilexer.cpp  |  4 +-
+ src/qscint/src/qscintilla.pro | 18 ++------
+ src/qtlangset.cpp             | 78 +++++++++++++++++------------------
+ src/scintillaeditview.cpp     |  8 ++--
+ src/userlexdef.cpp            |  6 +--
+ 18 files changed, 139 insertions(+), 144 deletions(-)
+
+diff --git a/src/CmpareMode.cpp b/src/CmpareMode.cpp
+index b8fb335..1245275 100755
+--- a/src/CmpareMode.cpp
++++ b/src/CmpareMode.cpp
+@@ -181,7 +181,7 @@ quint32 CmpareMode::readLineFromFileWithUnicodeLe(uchar* m_fileFpr, const int fi
+ 		else if (mode == 2)
+ 		{
+ 			QString temp = lineInfo.unicodeStr;
+-			md4.addData(temp.replace(QRegExp("\\s"), QString("")).toUtf8());
++            md4.addData(temp.replace(QRegularExpression("\\s"), QString("")).toUtf8());
+ 		}
+ 	};
+ 
+@@ -429,7 +429,7 @@ CODE_ID CmpareMode::readLineFromFile(uchar* m_fileFpr, const int fileLength, con
+ 		else if (mode == 2)
+ 		{
+ 			QString temp = lineInfo.unicodeStr;
+-			md4.addData(temp.replace(QRegExp("\\s"), QString("")).toUtf8());
++            md4.addData(temp.replace(QRegularExpression("\\s"), QString("")).toUtf8());
+ 		}
+ 	};
+ 
+diff --git a/src/Encode.cpp b/src/Encode.cpp
+index 2164880..9fd8af1 100755
+--- a/src/Encode.cpp
++++ b/src/Encode.cpp
+@@ -1,6 +1,6 @@
+ 锘�#include "Encode.h"
+ #include <QTextCodec>
+-#include <QtDebug>
++#include <QDebug>
+ 
+ /* 妫€鏌ュ瓧绗︿覆缂栫爜鐨勭被銆傜湅浜嗗ぇ閲忔枃鐚�紝缁撹�濡備笅锛�
+ *濡傛灉鏄疷TF BOM鏍煎紡锛屾垨鑰匲NICODE鏍煎紡锛屽叾鏂囦欢澶撮儴鍓嶅嚑涓�瓧鑺傦紙2-3锛夋湁涓€瀹氱殑鏍囪瘑銆傜敱姝ゆ爣璇嗙洿鎺ユ寜瀵瑰簲缂栫爜澶勭悊銆�
+diff --git a/src/RealCompare.pro b/src/RealCompare.pro
+index 1035414..0da717e 100755
+--- a/src/RealCompare.pro
++++ b/src/RealCompare.pro
+@@ -3,9 +3,9 @@ LANGUAGE = C++
+ 
+ TARGET = Notepad--
+ 
+-CONFIG	+= qt warn_on Debug
++CONFIG	+= qt warn_on
+ 
+-QT += core gui widgets concurrent network xmlpatterns
++QT += core gui widgets concurrent network core5compat
+ 
+ 
+ HEADERS	+= *.h \
+@@ -33,47 +33,47 @@ INCLUDEPATH += cceditor
+ 
+ TRANSLATIONS += realcompare_zh.ts
+ 
+- if(contains(QMAKE_HOST.arch, x86_64)){
+-    CONFIG(Debug, Debug|Release){
++ if(contains(QMAKE_HOST.arch, x86_64|loongarch64)){
++    CONFIG(debug, debug|release){
+         DESTDIR = x64/Debug
+-		LIBS	+= -Lx64/Debug
+-		LIBS += -lqmyedit_qt5d
++                LIBS += -Lx64/Debug
++                LIBS += -lqmyedit_qt6d
+     }else{
+         DESTDIR = x64/Release
+ 		LIBS	+= -Lx64/Release
+-		LIBS += -lqmyedit_qt5
++                LIBS += -lqmyedit_qt6
+         #QMAKE_CXXFLAGS += /openmp
+     }
+-   }
++}
++
+ unix{
+-if(CONFIG(debug, Debug|Release)){
+-          LIBS += -L/home/yzw/build/CCNotePad/x64/Debug -lqmyedit_qt5
++    if(CONFIG(debug, debug|release)){
++        LIBS += -L/home/yzw/build/CCNotePad/x64/Debug -lqmyedit_qt6
+ 
+-QMAKE_CXXFLAGS += -fopenmp
+-LIBS += -lgomp -lpthread
++        QMAKE_CXXFLAGS += -fopenmp
++        LIBS += -lgomp -lpthread
+     }else{
+-          LIBS += -L/home/yzw/build/CCNotePad/x64/Release -lqmyedit_qt5
++        LIBS += -L/home/yzw/build/CCNotePad/x64/Release -lqmyedit_qt6
+         DESTDIR = x64/Release
+ 
+         QMAKE_CXXFLAGS += -fopenmp -O2
+         LIBS += -lgomp -lpthread
+     }
+-   }
+-
++}
+ 
+ RC_FILE += RealCompare.rc
++
+ unix
+ {
+-
+-INCLUDEPATH += $$PWD/.
+-DEPENDPATH += $$PWD/.
++    INCLUDEPATH += $$PWD/.
++    DEPENDPATH += $$PWD/.
+ 
+ 
+-unix:!macx: LIBS += -L$$PWD/x64/Release/ -lqmyedit_qt5
++    unix:!macx: LIBS += -L$$PWD/x64/Release/ -lqmyedit_qt6
+ 
+-INCLUDEPATH += $$PWD/x64/Release
+-DEPENDPATH += $$PWD/x64/Release
++    INCLUDEPATH += $$PWD/x64/Release
++    DEPENDPATH += $$PWD/x64/Release
+ 
+-unix:!macx: PRE_TARGETDEPS += $$PWD/x64/Release/libqmyedit_qt5.a
++    unix:!macx: PRE_TARGETDEPS += $$PWD/x64/Release/libqmyedit_qt6.a
+ }
+ 
+diff --git a/src/batchfindreplace.cpp b/src/batchfindreplace.cpp
+index cb071c3..2602e3c 100755
+--- a/src/batchfindreplace.cpp
++++ b/src/batchfindreplace.cpp
+@@ -89,7 +89,7 @@ void BatchFindReplace::appendToFindReplaceTable(QStringList& findKeyword)
+ bool BatchFindReplace::tranInputKeyword(QString& findKeyWord, QStringList& outputKeyWordList)
+ {
+ 	//把空白字符,空格或者\t \r\n 等字符进行替换为空格
+-	QRegExp re("\\s");
++    QRegularExpression re("\\s");
+ 	findKeyWord.replace(re, QString(" "));
+ 
+ 	//再进行空格分隔处理
+@@ -257,7 +257,7 @@ void BatchFindReplace::on_export()
+ 	if (!fileName.isEmpty())
+ 	{
+ 		QSettings setting(fileName, QSettings::IniFormat);
+-		setting.setIniCodec("UTF-8");
++//		setting.setIniCodec("UTF-8");
+ 
+ 		int rowNums = ui.findReplaceTable->rowCount();
+ 
+@@ -303,7 +303,7 @@ void BatchFindReplace::on_import()
+ 		QFileInfo fi(fileNameList[0]);
+ 
+ 		QSettings setting(fi.filePath(), QSettings::IniFormat);
+-		setting.setIniCodec("UTF-8");
++//		setting.setIniCodec("UTF-8");
+ 
+ 		ui.findKeywordEdit->setPlainText(setting.value("find").toStringList().join(" "));
+ 		ui.replaceKeywordEdit->setPlainText(setting.value("replace").toStringList().join(" "));
+diff --git a/src/cceditor/ccnotepad.cpp b/src/cceditor/ccnotepad.cpp
+index 1f04879..5efe091 100755
+--- a/src/cceditor/ccnotepad.cpp
++++ b/src/cceditor/ccnotepad.cpp
+@@ -507,7 +507,7 @@ void initFileTypeLangMap()
+ 		//鎶婃柊璇�█tagName,鍜屽叧鑱攅xt鍗曠嫭瀛樻斁璧锋潵ext_tag.ini銆傚彧璇诲彇涓€涓�枃浠跺氨鑳借幏鍙栨墍鏈夛紝閬垮厤閬嶅巻鎱�
+ 		QString extsFile = QString("notepad/userlang/ext_tag");//ext_tag鏄�瓨鍦ㄦ墍鏈塼ag ext鐨勬枃浠�
+ 		QSettings qs(QSettings::IniFormat, QSettings::UserScope, extsFile);
+-		qs.setIniCodec("UTF-8");
++//		qs.setIniCodec("UTF-8");
+ 
+ 		QStringList keys = qs.allKeys();
+ 		//LangType lexId = L_USER_TXT;
+@@ -3981,7 +3981,7 @@ void  CCNotePad::initFileListDockWin()
+ 			}
+ 		});
+ 		m_dockFileListWin->setAttribute(Qt::WA_DeleteOnClose);
+-		m_dockFileListWin->layout()->setMargin(0);
++        m_dockFileListWin->layout()->setContentsMargins(0, 0, 0, 0);
+ 		m_dockFileListWin->layout()->setSpacing(0);
+ 
+ 		//鏆傛椂涓嶆彁渚涘叧闂�紝鍥犱负鍏抽棴鍚庨渶瑕佸悓姝ヨ彍鍗曠殑check鐘舵€�
+@@ -4312,7 +4312,7 @@ void CCNotePad::slot_actionSaveFile_toggle(bool /*checked*/)
+ 	if (pEdit != nullptr)
+ 	{
+ 		//濡傛灉鏄�柊寤虹殑鏂囦欢锛屽垯寮瑰嚭淇濆瓨瀵硅瘽妗嗭紝杩涜�淇濆瓨
+-		if (pEdit->property(Edit_File_New) >= 0)
++        if (pEdit->property(Edit_File_New).toString().length() >= 0)
+ 		{
+ 			QString filter("Text files (*.txt);;XML files (*.xml);;h files (*.h);;cpp file(*.cpp);;All types(*.*)");
+ 			QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), QString(), filter);
+@@ -4472,7 +4472,7 @@ void CCNotePad::slot_actionSaveAsFile_toggle(bool /*checked*/)
+ 	if (pEdit != nullptr)
+ 	{
+ 		//濡傛灉鏄�柊寤虹殑鏂囦欢锛屽垯寮瑰嚭淇濆瓨瀵硅瘽妗嗭紝杩涜�淇濆瓨
+-		if (pEdit->property(Edit_File_New) >= 0)
++        if (pEdit->property(Edit_File_New).toString().length() >= 0)
+ 		{
+ 			QString filter("Text files (*.txt);;XML files (*.xml);;h files (*.h);;cpp file(*.cpp);;All types(*.*)");
+ 			QString fileName = QFileDialog::getSaveFileName(this, tr("Save File As ..."),QString(), filter);
+@@ -4763,7 +4763,7 @@ void CCNotePad::saveTempFile(ScintillaEditView* pEdit,int index, QSettings& qs)
+ 		return;
+ 	}
+ 
+-	QVariant v = pEdit->property(Edit_Text_Change);
++    QVariant v = pEdit->property(Edit_Text_Change);
+ 	bool isDirty = v.toBool();
+ 
+ 	//涓嶈剰鍒欎笉闇€瑕佷繚瀛橈紝鐩存帴璺宠繃銆備笉鑴忕殑鏂囦欢锛屽彧璁板綍1涓�悕绉帮紝涓嬫�鎵撳紑鏃舵仮澶�
+@@ -4773,7 +4773,7 @@ void CCNotePad::saveTempFile(ScintillaEditView* pEdit,int index, QSettings& qs)
+ 		//鎶婃枃浠惰�褰曞埌qs涓�幓
+ 		//index涓€瀹氫笉鑳介噸澶嶃€俷琛ㄧず鏂板缓
+ 		//濡傛灉鏄�柊寤虹殑鏂囦欢
+-		if (pEdit->property(Edit_File_New) >= 0)
++        if (pEdit->property(Edit_File_New).toInt() >= 0)
+ 		{
+ 			qs.setValue(QString("%1").arg(index), QString("%1|1").arg(fileName));
+ 		}
+@@ -4792,7 +4792,7 @@ void CCNotePad::saveTempFile(ScintillaEditView* pEdit,int index, QSettings& qs)
+ 	}
+ 
+ 	//濡傛灉鏄�柊寤虹殑鏂囦欢
+-	if (pEdit->property(Edit_File_New) >= 0)
++    if (pEdit->property(Edit_File_New).toInt() >= 0)
+ 	{
+ 		QString qsSavePath = qs.fileName();
+ 
+@@ -4963,7 +4963,7 @@ void CCNotePad::closeAllFileStatic()
+ {
+ 	QString tempFileList = QString("notepad/temp/list");
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, tempFileList);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 	qs.clear();
+ 
+ 	//浠庡熬閮ㄥ紑濮嬩緷娆¤皟鐢ㄤ繚瀛樻墍鏈夋枃浠躲€傛病淇�敼鐨勪笉闇€瑕佷繚瀛�
+@@ -5047,7 +5047,7 @@ void CCNotePad::closeEvent(QCloseEvent * event)
+ #else
+ 	if ((s_restoreLastFile == 1) && m_isMainWindows)
+ 	{
+-		closeAllFileStatic();
++		closeAllFileStatic();
+ 		m_isQuitCancel = false;
+ 	}
+ 	else
+@@ -5094,9 +5094,9 @@ void CCNotePad::closeEvent(QCloseEvent * event)
+ 			{
+ 				c->showNormal();
+ 			}
+-		qlonglong winId = (qlonglong)c->effectiveWinId();
+-		m_shareMem->lock();
+-		memcpy(m_shareMem->data(), &winId, sizeof(qlonglong));
++		qlonglong winId = (qlonglong)c->effectiveWinId();
++		m_shareMem->lock();
++		memcpy(m_shareMem->data(), &winId, sizeof(qlonglong));
+ 		m_shareMem->unlock();
+ 			c->m_isMainWindows = true;
+ 	}
+@@ -5480,7 +5480,7 @@ void CCNotePad::initFindWindow()
+ 			//浠庡巻鍙叉煡鎵捐�褰曟枃浠朵腑鍔犺浇
+ 			QString searchHistory = QString("notepad/searchHistory");//鍘嗗彶鏌ユ壘璁板綍
+ 			QSettings qs(QSettings::IniFormat, QSettings::UserScope, searchHistory);
+-			qs.setIniCodec("UTF-8");
++//			qs.setIniCodec("UTF-8");
+ 
+ 			if (qs.contains("keys"))
+ 			{
+@@ -5545,7 +5545,7 @@ void CCNotePad::slot_saveSearchHistory()
+ 	//浠庡巻鍙叉煡鎵捐�褰曟枃浠朵腑鍔犺浇
+ 	QString searchHistory = QString("notepad/searchHistory");//鍘嗗彶鏌ユ壘璁板綍
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, searchHistory);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 
+ 	if (s_findHistroy.count() > 15)
+ 	{
+@@ -5772,7 +5772,7 @@ void  CCNotePad::initFindResultDockWin()
+ 		m_dockSelectTreeWin = new QDockWidget(tr("Find result"), this);
+ 		connect(m_dockSelectTreeWin, &QDockWidget::dockLocationChanged, this, &CCNotePad::slot_findResultPosChangeed);
+ 
+-		m_dockSelectTreeWin->layout()->setMargin(0);
++        m_dockSelectTreeWin->layout()->setContentsMargins(0, 0, 0, 0);
+ 		m_dockSelectTreeWin->layout()->setSpacing(0);
+ 
+ 		//鏆傛椂涓嶆彁渚涘叧闂�紝鍥犱负鍏抽棴鍚庨渶瑕佸悓姝ヨ彍鍗曠殑check鐘舵€�
+@@ -6573,7 +6573,7 @@ bool CCNotePad::eventFilter(QObject * watched, QEvent * event)
+ 	}
+ 	return false;
+ }
+-
++
+ 
+ #ifdef Q_OS_WIN
+ static const ULONG_PTR CUSTOM_TYPE = 10000;
+@@ -6581,16 +6581,16 @@ static const ULONG_PTR OPEN_NOTEPAD_TYPE = 10001;
+ 
+ bool CCNotePad::nativeEvent(const QByteArray & eventType, void * message, long * result)
+ {
+-	MSG *param = static_cast<MSG *>(message);
+-
+-	switch (param->message)
+-	{
+-		case WM_COPYDATA:
+-		{
+-			COPYDATASTRUCT *cds = reinterpret_cast<COPYDATASTRUCT*>(param->lParam);
+-			if (cds->dwData == CUSTOM_TYPE)
+-			{
+-				QString openFilePath = QString::fromUtf8(reinterpret_cast<char*>(cds->lpData), cds->cbData);
++	MSG *param = static_cast<MSG *>(message);
++
++	switch (param->message)
++	{
++		case WM_COPYDATA:
++		{
++			COPYDATASTRUCT *cds = reinterpret_cast<COPYDATASTRUCT*>(param->lParam);
++			if (cds->dwData == CUSTOM_TYPE)
++			{
++				QString openFilePath = QString::fromUtf8(reinterpret_cast<char*>(cds->lpData), cds->cbData);
+ 				
+ 				int retIndex = findFileIsOpenAtPad(openFilePath);
+ 				if (-1 == retIndex)
+@@ -6622,9 +6622,9 @@ bool CCNotePad::nativeEvent(const QByteArray & eventType, void * message, long *
+ 				
+ 				
+ 				this->activateWindow();
+-				*result = 1;
+-				return true;
+-			}
++				*result = 1;
++				return true;
++			}
+ 			else if (cds->dwData == OPEN_NOTEPAD_TYPE)
+ 			{
+ 				activateWindow();
+@@ -6632,8 +6632,8 @@ bool CCNotePad::nativeEvent(const QByteArray & eventType, void * message, long *
+ 
+ 				*result = 1;
+ 				return true;
+-		}
+-	}
++		}
++	}
+ 	}
+ 
+ 	return QWidget::nativeEvent(eventType, message, result);
+@@ -7124,7 +7124,7 @@ int CCNotePad::restoreLastFiles()
+ 
+ 	QString tempFileList = QString("notepad/temp/list");
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, tempFileList);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 
+ 	QStringList fileList = qs.allKeys();
+ 	//浠庡皬鍒板ぇ鎺掑簭涓€涓�
+diff --git a/src/columnedit.cpp b/src/columnedit.cpp
+index 50fd9ae..aaf93f1 100755
+--- a/src/columnedit.cpp
++++ b/src/columnedit.cpp
+@@ -216,13 +216,13 @@ void ColumnEdit::slot_ok()
+ 		{
+ 			QByteArray s_space(cursorCol - lineEndCol, ' ');
+ 			lineData.append(s_space);
+-			lineData.append(text);
++            lineData.append(text.toLatin1());
+ 		}
+ 		else
+ 		{
+ 			int posAbs2Start = pEdit->execute(SCI_FINDCOLUMN, i, cursorCol);
+ 			int posRelative2Start = posAbs2Start - lineBegin;
+-			lineData.insert(posRelative2Start, text);
++            lineData.insert(posRelative2Start, text.toLatin1());
+ 		}
+ 
+ 		pEdit->SendScintilla(SCI_SETTARGETRANGE, lineBegin, lineEnd);
+diff --git a/src/ctipwin.cpp b/src/ctipwin.cpp
+index 9412777..5bf16a9 100755
+--- a/src/ctipwin.cpp
++++ b/src/ctipwin.cpp
+@@ -9,7 +9,7 @@ CTipWin::CTipWin(QWidget *parent)
+ 	this->setWindowFlags(Qt::ToolTip);
+ 
+ 	QPalette  palette(this->palette());
+-	palette.setColor(QPalette::Background, QColor(0xfff29d));
++    palette.setColor(QPalette::Window, QColor(0xfff29d));
+ 	this->setPalette(palette);
+ }
+ 
+diff --git a/src/draglineedit.cpp b/src/draglineedit.cpp
+index c21f3de..d8a8513 100755
+--- a/src/draglineedit.cpp
++++ b/src/draglineedit.cpp
+@@ -1,4 +1,5 @@
+ #include "draglineedit.h"
++#include <QFile>
+ 
+ DragLineEdit::DragLineEdit(QWidget *parent)
+ 	: QLineEdit(parent)
+diff --git a/src/encodeconvert.cpp b/src/encodeconvert.cpp
+index c17022e..7bbcfc5 100755
+--- a/src/encodeconvert.cpp
++++ b/src/encodeconvert.cpp
+@@ -11,7 +11,7 @@
+ #include <QtConcurrent>
+ #include <QInputDialog>
+ #include <QDragEnterEvent>
+-
++#include <QTextCodec>
+ 
+ const int ITEM_CODE = Qt::UserRole + 1;
+ 
+diff --git a/src/findresultwin.cpp b/src/findresultwin.cpp
+index 7d86701..ad01b46 100755
+--- a/src/findresultwin.cpp
++++ b/src/findresultwin.cpp
+@@ -5,7 +5,7 @@
+ #include <QTreeWidgetItem>
+ #include <QStyleFactory>
+ #include <QToolButton>
+-#include <qtreeview.h>
++#include <QTreeView>>
+ #include <QStandardItem> 
+ #include <QStandardItemModel>
+ #include <QClipboard>
+@@ -151,8 +151,8 @@ void FindResultWin::slot_selectAll()
+ 		QModelIndex pMi = curSelItem.parent();
+ 		if (pMi.isValid())
+ 		{
+-			curSelItem = pMi;
+-}
++            curSelItem = pMi;
++        }
+ 		else
+ 		{
+ 			break;
+@@ -176,12 +176,13 @@ void FindResultWin::slot_selectAll()
+ 		//閬嶅巻涓嬮潰鐨勫瓙鑺傜偣
+ 		int i = 0;
+ 		QModelIndex childMi;
+-		childMi = sectionItem.child(i, 0);
++        const QAbstractItemModel *const sectionItemModel = sectionItem.model();
++        childMi = sectionItemModel->index(i, 0);
+ 		while (childMi.isValid())
+ 		{
+ 			++i;
+ 			ui.resultTreeView->selectionModel()->select(childMi, QItemSelectionModel::Select);
+-			childMi = sectionItem.child(i, 0);
++            childMi = sectionItemModel->index(i, 0);
+ 		}
+ 		return i+1;
+ 	};
+@@ -189,17 +190,20 @@ void FindResultWin::slot_selectAll()
+ 	QModelIndex rootItem = firstRootItem;
+ 	int j = 0;
+ 	int selectCount = 0;
++    const QAbstractItemModel *const rootItemModel = rootItem.model();
++    const QAbstractItemModel *const firstRootItemModel = firstRootItem.model();
++
+ 	while (rootItem.isValid())
+ 	{
+ 		//閬嶅巻鏍硅妭鐐逛笅闈㈡瘡涓€涓猻ection
+ 		{
+ 			int i = 0;
+-			QModelIndex section = rootItem.child(i, 0);
++            QModelIndex section = rootItemModel->index(i, 0);
+ 			while (section.isValid() && !section.data(ResultItemEditor).isNull())
+ 			{
+ 				++i;
+ 				selectCount += selectSection(section);
+-				section = firstRootItem.child(i, 0);
++                section = firstRootItemModel->index(i, 0);
+ 			}
+ 		}
+ 
+@@ -223,12 +227,12 @@ void FindResultWin::slot_selectSection()
+ 		//閬嶅巻涓嬮潰鐨勫瓙鑺傜偣
+ 		int i = 0;
+ 		QModelIndex childMi;
+-		childMi = sectionItem.child(i, 0);
++        childMi = sectionItem.model()->index(i, 0);
+ 		while (childMi.isValid())
+ 		{
+ 			++i;
+ 			ui.resultTreeView->selectionModel()->select(childMi, QItemSelectionModel::Select);
+-			childMi = sectionItem.child(i, 0);
++            childMi = sectionItem.model()->index(i, 0);
+ 		}
+ 		return i+1;
+ 	};
+@@ -420,7 +424,7 @@ QString FindResultWin::highlightFindText(FindRecord& record)
+ 			}
+ 		src = QString("<font style='background-color:#ffffbf'>%1</font>").arg(QString(utf8bytes.mid(targetStart, targetLens)).toHtmlEscaped());
+ 			tail = QString(utf8bytes.mid(tailStart));
+-			if (tail > MAX_TAIL_LENGTH)
++            if (tail.size() > MAX_TAIL_LENGTH)
+ 			{
+ 				tail = (tail.mid(0, MAX_TAIL_LENGTH) + "...").toHtmlEscaped();
+ 			}
+@@ -454,7 +458,7 @@ QString FindResultWin::highlightFindText(FindRecord& record)
+ 			src = QString("<font style='font-weight:bold;color:#ffaa00'>%1</font>").arg(QString(utf8bytes.mid(targetStart, targetLens)).toHtmlEscaped());
+ 
+ 			QString tailContens = QString(utf8bytes.mid(tailStart));
+-			if (tailContens > MAX_TAIL_LENGTH)
++            if (tailContens.size() > MAX_TAIL_LENGTH)
+ 			{
+ 				tailContens = (tailContens.mid(0, MAX_TAIL_LENGTH) + "...").toHtmlEscaped();
+ 			}
+diff --git a/src/findwin.cpp b/src/findwin.cpp
+index 7a55059..8fe891e 100755
+--- a/src/findwin.cpp
++++ b/src/findwin.cpp
+@@ -559,8 +559,8 @@ bool readBase(const QChar * str, int * value, int base, int size)
+ 		current = str[i];
+ 		if (current >= 'A')
+ 		{
+-			current = current.digitValue() & 0xdf;
+-			current = current.digitValue() - ('A' - '0' - 10);
++            current = static_cast<QChar>(current.digitValue() & 0xdf);
++            current = static_cast<QChar>(current.digitValue() - ('A' - '0' - 10));
+ 		}
+ 		else if (current > '9')
+ 			return false;
+diff --git a/src/langstyledefine.cpp b/src/langstyledefine.cpp
+index 2df3a4f..f667f09 100755
+--- a/src/langstyledefine.cpp
++++ b/src/langstyledefine.cpp
+@@ -30,7 +30,7 @@ bool LangStyleDefine::readLangSetFile(QString langName, bool isLoadToUI)
+ {
+ 	QString userLangFile = QString("notepad/userlang/%1").arg(langName);//鑷�畾涔夎�瑷€涓�笉鑳芥湁.瀛楃�锛屽惁鍒欏彲鑳芥湁閿欙紝鍚庣画瑕佹�鏌�
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, userLangFile);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 	qDebug() << qs.fileName();
+ 
+ 	if (!qs.contains("mz"))
+@@ -160,7 +160,7 @@ void LangStyleDefine::slot_save()
+ 	//鎶婃柊璇�█tagName,鍜屽叧鑱攅xt鍗曠嫭瀛樻斁璧锋潵銆傚悗闈㈠彧璇诲彇涓€涓�枃浠跺氨鑳借幏鍙栨墍鏈夛紝閬垮厤閬嶅巻鎱�
+ 	QString extsFile = QString("notepad/userlang/ext_tag");//ext_tag鏄�瓨鍦ㄦ墍鏈塼ag ext鐨勬枃浠�
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, extsFile);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 
+ 	QStringList extList = ui.extNameLe->text().trimmed().split(" ");
+ 	extList.append(QString::number(motherLangs)); //鏈€鍚庝竴涓�槸mother lexer
+@@ -201,7 +201,7 @@ void LangStyleDefine::slot_delete()
+ 	{
+ 		QString userLangFile = QString("notepad/userlang/%1").arg(name);//鑷�畾涔夎�瑷€涓�笉鑳芥湁.瀛楃�锛屽惁鍒欏彲鑳芥湁閿欙紝鍚庣画瑕佹�鏌�
+ 		QSettings qs(QSettings::IniFormat, QSettings::UserScope, userLangFile);
+-		qs.setIniCodec("UTF-8");
++//		qs.setIniCodec("UTF-8");
+ 
+ 		//鍒犻櫎userlang涓嬮潰鐨則ag.ini
+ 		QFile::remove(qs.fileName());
+@@ -211,7 +211,7 @@ void LangStyleDefine::slot_delete()
+ 		//鎶婃柊璇�█鍦╡xt_tag涓�殑鍏宠仈鏂囦欢璁板綍涔熷垹闄�
+ 		QString extsFile = QString("notepad/userlang/ext_tag");//ext_tag鏄�瓨鍦ㄦ墍鏈塼ag ext鐨勬枃浠�
+ 		QSettings qs(QSettings::IniFormat, QSettings::UserScope, extsFile);
+-		qs.setIniCodec("UTF-8");
++//		qs.setIniCodec("UTF-8");
+ 
+ 		QStringList extList = qs.value(name).toStringList();
+ 		//鏇存柊褰撳墠ExtLexerManager::getInstance()銆傚�鏋滀笉鏇存柊锛屽氨瑕侀噸鍚�蒋浠舵墠鑳界敓鏁�
+diff --git a/src/nddsetting.cpp b/src/nddsetting.cpp
+index ed20f73..7e2070a 100755
+--- a/src/nddsetting.cpp
++++ b/src/nddsetting.cpp
+@@ -50,7 +50,7 @@ void NddSetting::init()
+ 	QString qsSetPath = qs.fileName();
+ 
+ 	s_nddSet = new QSettings(QSettings::IniFormat, QSettings::UserScope, settingDir);
+-	s_nddSet->setIniCodec("UTF-8");
++//	s_nddSet->setIniCodec("UTF-8");
+ 	bool initOk = true;
+ 
+ 	auto initNddSet = []() {
+diff --git a/src/qscint/src/qscilexer.cpp b/src/qscint/src/qscilexer.cpp
+index b49fdc5..f21fff8 100755
+--- a/src/qscint/src/qscilexer.cpp
++++ b/src/qscint/src/qscilexer.cpp
+@@ -896,7 +896,7 @@ const char* QsciLexer::getUserDefineKeywords()
+ 
+ 	QString userLangFile = QString("notepad/userlang/%1").arg(m_tagName);//鑷�畾涔夎�瑷€涓�笉鑳芥湁.瀛楃�锛屽惁鍒欏彲鑳芥湁閿欙紝鍚庣画瑕佹�鏌�
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, userLangFile);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 
+ 	if (!qs.contains("mz"))
+ 	{
+@@ -948,4 +948,4 @@ void QsciLexer::setCommentEnd(QByteArray commentEnd)
+ void QsciLexer::setCurThemes(int themesId)
+ {
+     m_themesId = themesId;
+-}
+\ No newline at end of file
++}
+diff --git a/src/qscint/src/qscintilla.pro b/src/qscint/src/qscintilla.pro
+index 2704d72..9ef4520 100755
+--- a/src/qscint/src/qscintilla.pro
++++ b/src/qscint/src/qscintilla.pro
+@@ -21,24 +21,14 @@
+ !win32:VERSION = 15.1.0
+ 
+ TEMPLATE = lib
+-CONFIG += qt warn_off thread exceptions hide_symbols debug staticlib
++CONFIG += qt warn_off thread exceptions hide_symbols staticlib
+ 
+ CONFIG(debug, debug|release) {
+-    mac: {
+-        TARGET = qmyedit_qt$${QT_MAJOR_VERSION}_debug
+-    } else {
+-        win32: {
+-            TARGET = qmyedit_qt$${QT_MAJOR_VERSION}d
+-        } else {
+-            TARGET = qmyedit_qt$${QT_MAJOR_VERSION}
+-        }
+-    }
+-	
+-	DESTDIR = ../../x64/Debug
++    TARGET = qmyedit_qt$${QT_MAJOR_VERSION}
++    DESTDIR = ../../x64/Debug
+ } else {
+     TARGET = qmyedit_qt$${QT_MAJOR_VERSION}
+-	
+-	DESTDIR = ../../x64/Release
++    DESTDIR = ../../x64/Release
+ }
+ 
+ macx:!CONFIG(staticlib) {
+diff --git a/src/qtlangset.cpp b/src/qtlangset.cpp
+index e88d132..99b6258 100755
+--- a/src/qtlangset.cpp
++++ b/src/qtlangset.cpp
+@@ -36,8 +36,8 @@ enum LangType {
+ 	// Don't use L_JS, use L_JAVASCRIPT instead
+ 	// The end of enumated language type, so it should be always at the end
+ 	L_EXTERNAL = 100, L_USER_DEFINE = 200
+-};
+-#endif
++};
++#endif
+ 
+ //static const QColor blackColor(Qt::black);
+ //static const QColor lightColor(0xdedede);
+@@ -421,14 +421,14 @@ void QtLangSet::updateAllLangeStyleWithGlobal(GLOBAL_STYLE_SET flag)
+ 		QsciLexer *pLexer = ScintillaEditView::createLexer(index);
+ 		if (nullptr != pLexer)
+ 		{
+-
++
+ 			switch (flag)
+ 			{
+ 			case GLOBAL_FONT:
+ 			{
+-				for (int i = 0; i <= 255; ++i)
+-				{
+-					if (!pLexer->description(i).isEmpty())
++				for (int i = 0; i <= 255; ++i)
++				{
++					if (!pLexer->description(i).isEmpty())
+ 					{
+ 						oldfont = pLexer->font(i);
+ 						oldfont.setFamily(m_curStyleData.font.family());
+@@ -439,9 +439,9 @@ void QtLangSet::updateAllLangeStyleWithGlobal(GLOBAL_STYLE_SET flag)
+ 			break;
+ 			case GLOBAL_FONT_SIZE:
+ 			{
+-				for (int i = 0; i <= 255; ++i)
+-				{
+-					if (!pLexer->description(i).isEmpty())
++				for (int i = 0; i <= 255; ++i)
++				{
++					if (!pLexer->description(i).isEmpty())
+ 					{
+ 						oldfont = pLexer->font(i);
+ 						oldfont.setPointSize(m_curStyleData.font.pointSize());
+@@ -452,9 +452,9 @@ void QtLangSet::updateAllLangeStyleWithGlobal(GLOBAL_STYLE_SET flag)
+ 			break;
+ 			case GLOBAL_FONT_BOLD:
+ 			{
+-				for (int i = 0; i <= 255; ++i)
+-				{
+-					if (!pLexer->description(i).isEmpty())
++				for (int i = 0; i <= 255; ++i)
++				{
++					if (!pLexer->description(i).isEmpty())
+ 					{
+ 						oldfont = pLexer->font(i);
+ 						oldfont.setBold(m_curStyleData.font.bold());
+@@ -465,9 +465,9 @@ void QtLangSet::updateAllLangeStyleWithGlobal(GLOBAL_STYLE_SET flag)
+ 			break;
+ 			case GLOBAL_FONT_UNDERLINE:
+ 			{
+-				for (int i = 0; i <= 255; ++i)
+-				{
+-					if (!pLexer->description(i).isEmpty())
++				for (int i = 0; i <= 255; ++i)
++				{
++					if (!pLexer->description(i).isEmpty())
+ 					{
+ 						oldfont = pLexer->font(i);
+ 						oldfont.setUnderline(m_curStyleData.font.underline());
+@@ -478,9 +478,9 @@ void QtLangSet::updateAllLangeStyleWithGlobal(GLOBAL_STYLE_SET flag)
+ 			break;
+ 			case GLOBAL_FONT_ITALIC:
+ 			{
+-				for (int i = 0; i <= 255; ++i)
+-				{
+-					if (!pLexer->description(i).isEmpty())
++				for (int i = 0; i <= 255; ++i)
++				{
++					if (!pLexer->description(i).isEmpty())
+ 					{
+ 						oldfont = pLexer->font(i);
+ 						oldfont.setItalic(m_curStyleData.font.italic());
+@@ -503,10 +503,10 @@ void QtLangSet::updateAllLangeStyleWithGlobal(GLOBAL_STYLE_SET flag)
+ 			break;
+ 			default:
+ 				break;
+-			}
++			}
+ 			
+ 			saveLangeSet(pLexer);
+-		}
++		}
+ 		delete pLexer;
+ 	}
+ }
+@@ -537,7 +537,7 @@ void  QtLangSet::restoreOriginLangAllStyle()
+ 		{
+ 			QFile::remove(qs.fileName());
+ 		}
+-
++
+ 		delete pLexer;
+ 		pLexer = nullptr;
+ 	}
+@@ -578,12 +578,12 @@ void QtLangSet::restoreOriginLangOneStyle(GLOBAL_STYLE_SET flag)
+ 		QsciLexer *pLexer = ScintillaEditView::createLexer(index);
+ 		QsciLexer *pOriginLexer = ScintillaEditView::createLexer(index,"",true);
+ 		if (nullptr != pLexer)
+-		{
+-			for (int i = 0; i <= 255; ++i)
+-			{
+-				if (!pLexer->description(i).isEmpty())
+-				{
+-
++		{
++			for (int i = 0; i <= 255; ++i)
++			{
++				if (!pLexer->description(i).isEmpty())
++				{
++
+ 					switch (flag)
+ 					{
+ 					case GLOBAL_FONT:
+@@ -649,11 +649,11 @@ void QtLangSet::restoreOriginLangOneStyle(GLOBAL_STYLE_SET flag)
+ 					break;
+ 					default:
+ 						break;
+-					}
+-				}
++					}
++				}
+ 			}
+ 			saveLangeSet(pLexer);
+-		}
++		}
+ 		delete pLexer;
+ 		delete pOriginLexer;
+ 	}
+@@ -795,7 +795,7 @@ bool QtLangSet::readLangSetFile(QString langName,QString &keyword, QString &moth
+ {
+ 	QString userLangFile = QString("notepad/userlang/%1").arg(langName);//自定义语言中不能有.字符,否则可能有错,后续要检查
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, userLangFile);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 	//qDebug() << qs.fileName();
+ 
+ 	if (!qs.contains("mz"))
+@@ -917,15 +917,15 @@ void QtLangSet::slot_itemSelect(QListWidgetItem *item)
+ 		ui.keywordTe->setPlainText(keyword);
+ 		ui.motherLangCb->setCurrentIndex(0);
+ 
+-		for (int i = 0; i <= 255; ++i)
+-		{
+-			QString desc = pLexer->description(i);
+-			if (!desc.isEmpty())
+-			{
++		for (int i = 0; i <= 255; ++i)
++		{
++			QString desc = pLexer->description(i);
++			if (!desc.isEmpty())
++			{
+ 				QListWidgetItem *itemtemp = new QListWidgetItem(desc);
+-				itemtemp->setData(Qt::UserRole, i);
+-				ui.styleListWidget->addItem(itemtemp);
+-			}
++				itemtemp->setData(Qt::UserRole, i);
++				ui.styleListWidget->addItem(itemtemp);
++			}
+ 		}
+ 	}
+ 
+diff --git a/src/scintillaeditview.cpp b/src/scintillaeditview.cpp
+index 60181dd..fac3648 100755
+--- a/src/scintillaeditview.cpp
++++ b/src/scintillaeditview.cpp
+@@ -2155,7 +2155,7 @@ void ScintillaEditView::changeCase(const TextCaseType & caseToConvert, QString&
+ 				else if (caseToConvert == TITLECASE_FORCE)
+ 					strToConvert[i] = strToConvert[i].toLower();
+ 				//An exception
+-				if ((i < 2) ? false : (strToConvert[i - 1] == L'\'' && (strToConvert[i - 2].isLetter())))
++                if ((i < 2) ? false : (strToConvert[i - 1] == QChar(L'\'') && (strToConvert[i - 2].isLetter())))
+ 					strToConvert[i] = strToConvert[i].toLower();
+ 			}
+ 		}
+@@ -2183,11 +2183,11 @@ void ScintillaEditView::changeCase(const TextCaseType & caseToConvert, QString&
+ 				wasEolR = false;
+ 				wasEolN = false;
+ 				//An exception
+-				if (strToConvert[i] == L'i' &&
++                if (strToConvert[i] == static_cast<QChar>(L'i') &&
+ 					((i < 1) ? false : (strToConvert[i - 1].isSpace() || strToConvert[i - 1] == '(' || strToConvert[i - 1] == '"')) && \
+ 					((i + 1 == nbChars) ? false : (strToConvert[i + 1].isSpace() || strToConvert[i + 1] == '\'')))
+ 				{
+-					strToConvert[i] = L'I';
++                    strToConvert[i] = static_cast<QChar>(L'I');
+ 				}
+ 			}
+ 			else if (strToConvert[i] == '.' || strToConvert[i] == '!' || strToConvert[i] == '?')
+@@ -2856,7 +2856,7 @@ bool isUrlQueryDelimiter(QChar const c)
+ void scanToUrlEnd(QString & text, int textLen, int start, int* distance)
+ {
+ 	int p = start;
+-	QChar q = 0;
++    QChar q;
+ 	enum { sHostAndPath, sQuery, sQueryAfterDelimiter, sQueryQuotes, sQueryAfterQuotes, sFragment } s = sHostAndPath;
+ 	while (p < textLen)
+ 	{
+diff --git a/src/userlexdef.cpp b/src/userlexdef.cpp
+index 6b8c7d2..86e238b 100755
+--- a/src/userlexdef.cpp
++++ b/src/userlexdef.cpp
+@@ -24,7 +24,7 @@ bool UserLexDef::readUserSettings(QString langTagName)
+ 
+ 	QString userLangFile = QString("notepad/userlang/%1").arg(langTagName);
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, userLangFile);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 
+ 	if (!qs.contains(QString("mz")))
+ 	{
+@@ -93,13 +93,13 @@ bool UserLexDef::writeUserSettings(QString langTagName)
+ 
+ 	QString userLangFile = QString("notepad/userlang/%1").arg(langTagName);
+ 	QSettings qs(QSettings::IniFormat, QSettings::UserScope, userLangFile);
+-	qs.setIniCodec("UTF-8");
++//	qs.setIniCodec("UTF-8");
+ 	qs.clear();
+ 
+ 	qs.setValue("mz", langTagName);
+ 	qs.setValue("mother", m_motherLang); 
+ 	qs.setValue("ext", m_extTypes);
+-	qs.setValue("keyword", m_keyword.data());
++    qs.setValue("keyword", m_keyword.toStdString().c_str());
+ 
+ 	return true;
+ }
+-- 
+2.20.1
+

+ 2759 - 0
patchs/coconil-cmake-spark-deb-appimage.patch

@@ -0,0 +1,2759 @@
+From cc06baf3b21851b8addc0f691a31541ca436d395 Mon Sep 17 00:00:00 2001
+From: coconil <[email protected]>
+Date: Tue, 31 Jan 2023 22:17:32 +0800
+Subject: [PATCH 01/13] add cmake support
+
+---
+ CMakeLists.txt            | 2 ++
+ src/qscint/CMakeLists.txt | 6 +++---
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index f1d6eea..f1c6d25 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -53,3 +53,5 @@ install(DIRECTORY  ${PROJECT_SOURCE_DIR}/src/linux/usr
+ 
+ include(${PROJECT_SOURCE_DIR}/cmake/package_config.cmake) 
+ include(CPack)
++
++target_link_libraries(${PROJECT_NAME} qscint Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent Qt5::Network  Qt5::PrintSupport Qt5::XmlPatterns)
+\ No newline at end of file
+diff --git a/src/qscint/CMakeLists.txt b/src/qscint/CMakeLists.txt
+index b114614..f132dc6 100644
+--- a/src/qscint/CMakeLists.txt
++++ b/src/qscint/CMakeLists.txt
+@@ -1,5 +1,5 @@
+-cmake_minimum_required(VERSION 3.16)
+-project(qscintilla2_qt5 CXX)
++cmake_minimum_required(VERSION 3.24)
++project(qscint CXX)
+ 
+ set(CMAKE_AUTOMOC ON)
+ set(CMAKE_AUTOUIC ON)
+@@ -28,7 +28,7 @@ ${PROJECT_SOURCE_DIR}/scintilla/boostregex
+ 
+ target_include_directories(${PROJECT_NAME} PUBLIC
+ ${PROJECT_SOURCE_DIR}/src
+-${PROJECT_SOURCE_DIR}/src/Qsci 
++${PROJECT_SOURCE_DIR}/src/Qsci
+ ${PROJECT_SOURCE_DIR}/scintilla/src
+ ${PROJECT_SOURCE_DIR}/scintilla/include)
+ 
+-- 
+2.20.1
+
+
+From 7466475538da85ba7eb24024e34b5fde8babe5f9 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Wed, 1 Feb 2023 20:04:05 +0800
+Subject: [PATCH 02/13] =?UTF-8?q?repo:=20=E5=BC=95=E5=85=A5=20Spark=20?=
+ =?UTF-8?q?=E6=9E=84=E5=BB=BA=EF=BC=8C=E6=94=AF=E6=8C=81=E6=9E=84=E5=BB=BA?=
+ =?UTF-8?q?=20deb?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ .gitignore                           |  54 ++++-
+ CMakeLists.txt                       |  36 ++-
+ Makefile                             |  61 +++++
+ assets/spark.png                     | Bin 0 -> 4959 bytes
+ cmake/DebPackageConfig.cmake         | 323 +++++++++++++++++++++++++++
+ cmake/SparkDesktopMacros.cmake       |  35 +++
+ cmake/SparkInstallMacrosConfig.cmake | 131 +++++++++++
+ cmake/package-deb.descript           |  45 ++++
+ cmake/spark-desktop.desktop.in       |  12 +
+ 9 files changed, 682 insertions(+), 15 deletions(-)
+ create mode 100644 Makefile
+ create mode 100644 assets/spark.png
+ create mode 100644 cmake/DebPackageConfig.cmake
+ create mode 100644 cmake/SparkDesktopMacros.cmake
+ create mode 100644 cmake/SparkInstallMacrosConfig.cmake
+ create mode 100644 cmake/package-deb.descript
+ create mode 100644 cmake/spark-desktop.desktop.in
+
+diff --git a/.gitignore b/.gitignore
+index 8d723bc..72fb977 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -384,15 +384,45 @@ FodyWeavers.xsd
+ !.vscode/extensions.json
+ *.code-workspace
+ 
+-# Local History for Visual Studio Code
+-.history/
+-
+-# Windows Installer files from build outputs
+-*.cab
+-*.msi
+-*.msix
+-*.msm
+-*.msp
+-
+-# JetBrains Rider
+-*.sln.iml
++# Local History for Visual Studio Code
++.history/
++
++# Windows Installer files from build outputs
++*.cab
++*.msi
++*.msix
++*.msm
++*.msp
++
++# JetBrains Rider
++*.sln.iml
++
++
++
++# Ignore the build directory generated by the vsocde cmake extension
++build/
++# Ignore the build directory generated by the vsocde clangd extension
++.cache
++
++# Created by https://www.toptal.com/developers/gitignore/api/cmake
++# Edit at https://www.toptal.com/developers/gitignore?templates=cmake
++
++### CMake ###
++CMakeLists.txt.user
++CMakeCache.txt
++CMakeFiles
++CMakeScripts
++Testing
++Makefile
++cmake_install.cmake
++install_manifest.txt
++compile_commands.json
++CTestTestfile.cmake
++_deps
++
++### CMake Patch ###
++# External projects
++*-prefix/
++
++# End of https://www.toptal.com/developers/gitignore/api/cmake
++!/Makefile
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index f1c6d25..666fbdb 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1,5 +1,5 @@
+-cmake_minimum_required(VERSION 3.16)
+-project(notepad--)
++cmake_minimum_required(VERSION 3.24)
++project(notepad-- VERSION 1.22.0)
+ 
+ set(CMAKE_AUTOMOC ON)
+ set(CMAKE_AUTOUIC ON)
+@@ -54,4 +54,34 @@ install(DIRECTORY  ${PROJECT_SOURCE_DIR}/src/linux/usr
+ include(${PROJECT_SOURCE_DIR}/cmake/package_config.cmake) 
+ include(CPack)
+ 
+-target_link_libraries(${PROJECT_NAME} qscint Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent Qt5::Network  Qt5::PrintSupport Qt5::XmlPatterns)
+\ No newline at end of file
++target_link_libraries(${PROJECT_NAME} qscint Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent Qt5::Network  Qt5::PrintSupport Qt5::XmlPatterns)
++
++if(CMAKE_HOST_UNIX)
++    include(cmake/SparkInstallMacrosConfig.cmake)
++    include(cmake/SparkDesktopMacros.cmake)
++    # 内容默认应用名称: Name= 应与项目名称相同
++    spark_desktop_macros(
++        # 应用名称: Name=
++        ${PROJECT_NAME}
++        # 应用名称: Name[zh_CN]=
++        "Notepad--"
++        # 应用说明: Comment=
++        "Notepad-- 是一个国产跨平台、简单的文本编辑器。"
++        # 应用类型: Type=
++        "Application"
++        # 执行程序: Exec=
++        "notepad--"
++        # 图标路径: Icon=
++        "/usr/share/notepad--/icons/spark.png"
++        # 应用分类: Category=
++        "Development"
++    )
++    spark_install_file(/usr/share/applications/    ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.desktop)
++    spark_install_file(/usr/share/notepad--/icons/ assets/spark.png)
++    spark_install_target(/usr/bin/ ${PROJECT_NAME})
++
++    # 注释行(使用方式)
++    find_package(DebPackage PATHS ${CMAKE_SOURCE_DIR})
++    add_package_descript(cmake/package-deb.descript)
++
++endif(CMAKE_HOST_UNIX)
+diff --git a/Makefile b/Makefile
+new file mode 100644
+index 0000000..43e849f
+--- /dev/null
++++ b/Makefile
+@@ -0,0 +1,61 @@
++CPUS=$(shell nproc)
++CALENDAR=$(shell date '+%Y%m%d')
++OSID=$(shell lsb_release -si)
++OSRELEASE=$(shell lsb_release -sr)
++SUFFIX=
++ifneq ("$(OSID)", "")
++SUFFIX=_$(OSID)$(OSRELEASE)
++endif
++
++PROJECT_NAME=notepad--
++PACKAGE_NAME=com.hmja.notepad
++
++all:
++	mkdir -p build
++	cd build && cmake ..
++	cd build && make -j$(CPUS)
++
++run: all
++	exec $(shell find build/ -maxdepth 1 -type f -executable | grep $(PROJECT_NAME))
++
++debug:
++	mkdir -p build
++	cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..
++	cd build && make -j$(CPUS)
++
++release:
++	mkdir -p build
++	cd build && cmake -DCMAKE_BUILD_TYPE=Release -DPACKAGE_SUFFIX="$(SUFFIX)" ..
++	cd build && make -j$(CPUS)
++
++package: release
++	cd build && make package
++	tree build/_CPack_Packages/Linux/DEB/$(PROJECT_NAME)-*
++	dpkg-deb --contents build/$(PACKAGE_NAME)_*$(CALENDAR)*$(SUFFIX).deb
++	# cd build/_CPack_Packages/Linux/DEB/$(PROJECT_NAME)_*$(CALENDAR)*$(SUFFIX).deb && find .
++
++builddeps:
++	cd build && make builddeps
++
++cpus:
++	@echo "CPU数量: $(CPUS)"
++
++copytosource:package
++	cp build/$(PACKAGE_NAME)_*$(CALENDAR)*.deb .
++
++# 进入 qdebug 模式,在 deepin 中默认被禁用,可 env | grep QT 查看,并在 /etc/X11/Xsession.d/00deepin-dde-env 配置中已定义
++# 1. 禁止 qt 的 debug 打印: qt.*.debug=false
++# 	qt.qpa.input.events
++#	qt.qpa.events
++# 2. 禁止 dtk 的 debug 打印: dtk.*.debug=false
++# 	dtk.dpluginloader
++# 3. 禁止 qtcreator 本身的 debug 打印
++# 	qtc.autotest.testcodeparser
++#	qtc.clangbackend.server
++#	...
++# 4. 关闭其它的太麻烦了,直接只启用本地 debug
++#	.debug=true
++enter-qdebug-mode:
++	# 进入新的 bash 环境
++	@# export QT_LOGGING_RULES=".debug=true; qt.*.debug=false; dtk.*.debug=false; dde.*.debug=false; qtc*=false; " && bash
++	export QT_LOGGING_RULES=".debug=true" && bash
+diff --git a/assets/spark.png b/assets/spark.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..544e2c7cff5f70894e27a7a717d4a62120630b7a
+GIT binary patch
+literal 4959
+zcmZ9Qc|26n`^T?!hOvx&4Pz%{EZLPYvTq^E5@pRcGGvX$AW~VT?0YC8CHu}WL)I*j
+zCA+d^OJw_v@Avn|@AZ4V?z!iAo%_7*bMCpH^W6J>;>=8R>1nxX0RW)a*F)YU^_YtW
+zrY4=^DWIpMj{2UVE)p04)_~)Bx;9qQ2n|Z_wm$&K2wgO?prUJmq(Kl`-&hB<LJMYK
+z;H4PWY#<GBp>=G~+P>c2E<R{L`=N^y+QnJmkq6pcKv&<`%=!rf2LLb=^pRSYLEks+
+zJuEHVG9I`5p0%~o`xwP(T(A&BWF})#9Om3~bQ_b(#@9SAhwGar%cpFq%$%?GJzQBD
+z^t%0dF=*wD8muRw+g(o51m|ccnE8Hz9D~pmFQqMqR8NPt`aZ@95GBoY%)<s5UuG3-
+zH8&0V|Ja-Yuky}6rHyUK_RAqC-|kS+r+)ehbx%+Lhha7VgMsr_00aWHDT62$d9(aF
+z!U1cV`EuMgw}GD4t)>7|<?qk1QBcY33S(8F5ArwUXi7fPCW(YRo7<tLi0uxDVj0(x
+z_<)l*SC*HNybE?BH(Rz$LC4rr3wa955G0X;EJy0xN_ATM3~{@N^o9Ne<uYS1%xvjV
+zouES0hFd~~oOYam0PHA>m)F7F$6%61XMsolUg0zXycp@v@GZ1K>rt9xd?C!>%*+W7
+z%C&esu?1QvJQKjm(&8q^?oTJ)%8V0?)|OjY&d?Gr6jy6+xCM5i6!*6NB4P1KRCNm^
+zm+NR*M%4c-!-n9r0lIJ!D)W+&T9oD)Dem^7SRik@V(WfPQ@fFKyaf2lH?CLvA5uka
+za&warZ&7cj6r);vpGc6CZ?~=95<VC}D!vy*f{QjEl&9OWL;iubp?H5yvEdB%@e6NX
+z57kp^2wVcQ3u~hI>k;2K+aF*1m@^PTnvH2@U9bunlhI3nmsfK^BZU;4=_*3}V}PoZ
+zEP*COH$^QdyIwzO=Shp{b@@LAC7u=@nYJ8)oEoIduWITqMn>MScBnM|V;V8ajW%>c
+z2|9_!;}u5SRyWpkQzR8giy<WH+QY*7;#%0KMPjz2J^$`S;Aj2Q$(O|;?s2!}W-s;l
+zu^~Jf@3^eIMr&D_;mxvB-21`xyjo8Mh`|)KZ&GW@tY9Ko+xhEH9q-}Ic$pF6Rb{$J
+z6WRQGL}`*GY6-rGR-l>|l$Ivq`@U%TZM4}hv^OUI<i-$GP!{(iq3D;wT5100{_<z8
+z=1;Ad?c^U8>k_s0z#=s!u~04W3Iv&C;FbL%51jwmUPHQ@0l~qZwrDUlHbTaRh}I7O
+zg75zlU9YVkytJ~+#_*>+av3b*ZLbM`=lrm(GyKlhzDKd&-~YS-XuB{i6aEdZrmT8V
+z5=&CIeIGmv+apvfRY7`h1Zf4_L_-7KYf+zDaL#{K)Hw61>q|2q>%TNiMk|sXtmY*1
+z`E77tq7vBO#3uo(t!jj^QMa-dh_<S@?yNd3zMLp*QM?3}j{(IjCNs>__m=cxM&AL^
+zdT&14OSgK$%!-|9_M)?`i4B)w7eegd!IoH)mWyyhiqc1~EPAqoCCYEgl(hFM{^Ftj
+z%GS_$^uT<GuMO-c^$e_!ZI<)tqNempDT6iTHz|9|_cjckvM6YmeEHw;h;Vg`YvL(_
+z(jqSectWzGVyL@+N;(xwEU<0OHRyt^OcZ<Qbm(M^U%g>6K)$jtUK69tc1oS-cV3H(
+zyzVwJW(p>4KWuO@dx-z65M|t#j~xmYkY<&V$cV9IcL@+9-%Akb(9C^=$km21|8lq_
+za=b^e+n~SA!s?z86LD4&0RU2Vl|bwCrvOB*uG>-oaP+AaCy?IW;MZ7A&oS_=puC#x
+zTSjKS2X}HZv)}oKicKX7<~q>8hy|~*HpzV*Y^DRSBNNv-=<Mz7m2X=<O(`+?bKF-{
+z>R$KtX-5a5FE<rK_;&5d64zhwYmB)DihD|kGMY$s$ypA4DYTWSd;03~Stbic2f`sB
+zAwh%dMJa#xYuO@4+Y^@mQ7demfUh*~%iSD#4K60n5j(6;z0A87Nb@>!_Wj#!o0njA
+z8JkG4+{e@({dOMVP51|1y`CGI?{rMiLdMQTV)8ojeNwqrgP)*5q}hq9`jG=rE*1L0
+z=0gY)xu5I$L0nYIwuM<@k7MqNbid7Ko1mz?Wtyzjo`jUhJJU|J`Jq_(fZ+l%ogp5Y
+zIDI`mBjycCE3h-oAO06y%KHv_U0fWu7`0F)$u5yL6u~KnhuEC++z(})gQ{w9X}O1^
+ziig+EPJfUA4&ecpZ?0Sc06XsoNMjeO3Wcj3%MW32I2nYaNKiwF#jknm8fO-R8aEHO
+zS;P_Zcdx7H>7UoVjHFijGh;WVUGy??)C=6c|6BJ?%amgTP(}HCU2Z0Y^Sx|AO%6>B
+z7k8KD-1)Kga0b7Xt>)Jmz><_Svi*-IB6_0ky0@X$d%1Z$EAcD*>w~VW$*SRrQOa6E
+z)cKJdzv;DO-USxsZnV8sfR>g0;TF*eXKlHEv~kBDQlVHocet}SvAsd<?82yC)LQ;W
+z)r39#Wqj$`6kE-tmwVMDs-}*UN680yV|?4qFL>I1E^G1doNa$er}pksd?U1pF|_rB
+zSIJIEOQLI~-<DjQJQ8&;nMSY8T27<NNl5c#E}S#wNzCQvhkqlEIn<jTityd}$UF=$
+z<XI5Ea=B|>J9cO}P)Oz~yJ4z~jwPCIW7GR>tKG}oJGSkdoz};#7?(Sg>_x?Y_Q?4k
+zZ$BO!ta2Sdt}R&N@%WDQoxFGNn8p;VW$7qF|8D7og^|0?JUW*}Y|jx!#LUqPlwg=m
+zRt9aEBD1%*_tO_~T=|(R%DbCN?p_VFK+vzERN1}RWAZ6OAYYD(J}CcnVj9+as%G)o
+z;NJXAE1<2%q6D=&D&c&^K7J$1uCL+uS>u|xgNGNU%c~o5r72Q`D?M*NaI@;bFQ#CT
+zV0IV|1Ll4vb*8mCG70}W_>J!pbL`q(Mk#Luq5Ho-?sljN6JfW)-Tyt?3`DZ%L<hO-
+zm1%2QcpEFqC@DA&Y)noZo<L3wmXhWO7T5CLyr%;aQ&VF{Kezq9Z=e-t6lGcYBlO&>
+z>1cfFaA%b9aDM4sjzPiuCSI52<vO<;a(uRp40{~Kn6LBMmPVEeHJcOgypIw^HdR}0
+zm6LbOEkgM=13_yKJS&9@eZ|7<X9r<lqI?mrld4&}+y)ocsy*K}qL^g986$Oc82=ro
+zuC2p`f>j;PmRFq03dvd{@)=@Z9{wG$dz~4@#t3rj;1m%CZ{=~k9~XcBC6v7Nc<RUf
+za0fm?Azz;LlJ)Y#jjF*)x4$yVmk#DrhOl)`Kk7jI4dJu{T@8Dun*0WoGkW%6p%IA#
+zwzFR1?;{r8naAakq}Ot?>kqV@1WVYQ<43f3{9(XPWS>EN{EO~*-CK*bt;ZS;!OLuY
+z87ft)RVyp(Cw{BC?#*W-X}?E8n+mG`{Ikbd@Mf3BkFQ_T3aIyS+g0*qIBMqV83`?o
+zX*3SoyLQT=V65w9M3)n><3cpp4wMiSNQ6I0WTSfL@yq6O5RJ^;rpPEzOSf?<#OEal
+z#JE8?_%;i?y7A-hXB(+R7p{hi!m)9NPT7A;G|icpHm~w<e;6$!Y4Fb<`kxOQK~ik7
+z2qb>S^k`I({`l+|qO9g~*i~G*9imYv^HH~-3PeB-S_xwv+Y2l=g6>lXZk|B1v+dn|
+zeA>r~Z}f3>@r<u`RNC~JSzXHVKWuV9PJevXSM)4ETvGjoXTP+@Sm!4fMnM%7F8Iff
+zb>Byy3Q<u#`SlY{K^5Dg)A{NK6p<$`7p6%c+oJK*xb-{t=b^TC*q$w1kQI7~<=I#n
+zUsrx-EC2+C9;adF_CoSYvo)?|_N_Pw%krKb00Zo)kx)$aOO2R5(5K_Eb(0c#$B5sg
+z{0z_oksNnVsOYo_E#b$gov$vI);T=pzwd=%0b+vx5R`k((5OLUU}$(4UhG+Kr*w?}
+zJ?oUew851nEwl58vi2;*E5|K?7<%F-)kCDbPq*w+RQGiP>&w80&#K>pvR%5geJnqq
+z#YL_Lw5jl$vkg7ZRPvcNku1Nz{`lM2`2I<R--ltN0hN~4vHK*U?_%TU@<IG~k|O@%
+znoTwT&;f1hd-Fe&&gpyQWo1oNlp#yTCg)~Y#%qU+b`54q1>+BH-`3Ba?R1ny-~VYe
+z9l%0>oH`pOV?m#)LN)yxXMS#M>?$?Ja6PLFE);UCNl#M06nrh>lc`K1PMyM&Ka>tI
+zyKVLSSwJ-z2RX<M$Fc<(rS~fTW{%nyS1=}&<eqVbw)PSJ<ep)k90YElR8ezf%^Lc)
+zK7m(V2eK4@R)4svw76Xh8k(GJt$8#twX<q^25G1`_B?J<$Kz*ToHDUP1f|Y;lv8Ey
+z@>NRh*UcPO%t2{i@X_0uuwJ6@h;-=Qef3g6X8cFUHPoCZIv{}R78rZ%99agCe;SpR
+z2&R5q?E=vp9E`14e_L9iWfefrys(&*EXOenhi}(uR8D%;1^v32tF*i$meYY6!3~@Q
+zv5OSB5c`O2eYdLw^yThU*z33iu!U)sm(UUi!Yh5@S`weCs{BaFFDP7dWAap2{nG=s
+zg+-P;PwqQ+?wHv<WGCsCsCO4rx|Wd_14)@oaLWm2&kft9v8-l^{=qia<93z$CT*z^
+z*q2JT%@xykw-Ow2s?^%W_=BG?$=o_stHxWYMy+|vajaCg^4_v!TByq*Mc@g$G@in+
+zYNuZb6#9Mik)Vb&y{T`IPuoggq35^!q9Us2#>S{X^xRx~)ampA>1zW`P2@zwfa|>{
+z(Zt?9q>hUSNyY-w8WjF3)S{^{Y;7-zeNdEWXCYNlYE#WdCdLmAQQa{ib}eB{46!Vm
+zo13!fMtVj@*A05r-xRqe1O+nR=OyKWG>u1mlD&rJ7WUEOHCORSf`H4G9m&D*U>eu{
+zLp6o#gU{59h79h}@mqyQxAYnwjZ3|e)+cm~c9C*PmcN-nJ13-pb9}j+aMZB3eWbuU
+z(aP`J@@Js(3eo*K%?H@(M#W~b(~+qW`F;+iobQ&M*W>{=WjBNNZqtpbh4N5N(I2dG
+z-RX`fI|JPp?}OI)XaR2iVs;j=E!yAobeUouDw>}0b0z1W+MTAGY0eJ{GDB$rxn+Jx
+zijgtNgG}Ip-xgzR(6Y<B6j5&7I?EKz2e+k2gn|!#VFBU$FP~`ekpaTJkZ6yKe@hcz
+z0&P<dte_M3j=c?L(KKla=JLCh$&q23=Ki1!(x1)bR{e(s(~5Hx!^RaGOirY(Ya+~q
+zTax0op$Cq0B+JhX=8V5lAHJ;;{jP&Y^DwLVk?U_UN+40B#x_l|2@WMt@X^?PUm5R`
+zka5Zoe%Mb;=NtBYJRMnP9OukRlM*dPy%;#8-SK6r$;j&qkHb)1d#Z^N<KZr2!&#Pj
+zIU-G_uQVE_d}&k&{6RLLsXdWz{x!xRnx?axhpuNik+1!(RuG-vy%XmTtmxPBGjh&s
+z%2Mr?Ut8IWv!*#|Vmm`90TQDH+;(IJMHnN3{zDQxfmd>w>ce#I{RXF)m?YpDnSx1P
+z-qxP|)1Pe80-2Yo{|kjzD-b|ra*a%GbQ-JEf<BbF&h$&RrZ-+pVa7@^kGNqEe<rct
+z-kwj~m}xv3un)%C!WKTK+rEbQ$D;L=|3ipou){Jid{G5mhMkg6p^%}xPG=SSMvT+>
+zY4Ef^R`Uo`;5%GzqsAjSR8OWeT$^xkT*!`awX@U|_Abd2Kni%MHCjtQr!HimpSd78
+zqrPOZv^3?zw<Q83PJS%)jk5~sW5wL%>eIu9Gt!GTOD19I)$#R&XHcKG{N6t4Uzm)%
+z_&ik-;lla8ao5f-XCXafQiDpVG*V0{N!aCZPn=1CN`%)rVO5b3-l1<&5Rm>dgqG6&
+zi6I?9NDN#D1uh~vl;mU=49d2IlV^tnzNl6O2YpihPema^^jse;K;WdUa}|$oaghqg
+z(6Awt@Duo-@b4d^62bJ31eGM@W)0Qd@X!Ndd;7ddj(j^*YY2<F9B0=q{CkRTYlO1D
+zGl*<!ByB1D*e5nwTT@}02EOS{{EEVld=V|ut?N{K!<D?M$QX97EGNgVZS|_~peG9q
+zL$e2NzJNfu_N=TG$8b>nz}q(w%?j=RPLP@eEF|B$PQ2KtCtcE0TG0n}qx$Q0g;>#Q
+zXb4R~mYm3CJ1RdzfK4TCyeNO)4km{6`QK7Rtf74G7sV*O8|HzS0B>>4yF}W2o(lp*
+zM{UWrv+Ba@vnVNI88u6!KF%=Wbx&cqT*am6q30wD#F98KVc5!5oJkm|LweHam10~r
+zX@~3#%zVK@yDeBv6!qOETx37pSa`UBTxI#cHI-Sl3=?)E1K4yNsZ5YEKwM8qGV1Vn
+zk8qYSbHYB+UTkQmS<k~+_u?XWiR}U~EWCgOKyF#9aFf?0NFlo?l9dJq7v*7@BT&B>
+t;Jjx^&~6n@&egfT2m_h_UkqA5Co_+SJESY3=}2`iKwrlMS%GlG{15vgE&>1m
+
+literal 0
+HcmV?d00001
+
+diff --git a/cmake/DebPackageConfig.cmake b/cmake/DebPackageConfig.cmake
+new file mode 100644
+index 0000000..cfba051
+--- /dev/null
++++ b/cmake/DebPackageConfig.cmake
+@@ -0,0 +1,323 @@
++cmake_minimum_required(VERSION 3.0.0)
++
++# function(add_deb_package PACKAGE_NAME PACKAGE_VERSION PACKAGE_MAINTAINER PACKAGE_EMAIL PACKAGE_SHORT_DESCRIPTION PACKAGE_LONG_DESCRIPTION)
++
++# endfunction(add_deb_package PACKAGE_NAME PACKAGE_VERSION PACKAGE_MAINTAINER PACKAGE_EMAIL PACKAGE_SHORT_DESCRIPTION PACKAGE_LONG_DESCRIPTION)
++
++# if(add_deb_package    VALUE) set(Package    ${VALUE} PARENT_SCOPE) endif(add_deb_package    VALUE)
++# if(add_deb_version    VALUE) set(Version    ${VALUE} PARENT_SCOPE) endif(add_deb_version    VALUE)
++# if(add_deb_maintainer VALUE) set(Maintainer ${VALUE} PARENT_SCOPE) endif(add_deb_maintainer VALUE)
++# if(add_deb_email      VALUE) set(Email      ${VALUE} PARENT_SCOPE) endif(add_deb_email      VALUE)
++# if(add_deb_descrition VALUE) set(Descrition ${VALUE} PARENT_SCOPE) endif(add_deb_descrition VALUE)
++# if(add_deb_detail     VALUE) set(Detail     ${VALUE} PARENT_SCOPE) endif(add_deb_detail     VALUE)
++
++
++# set(Package         "")
++# set(Version         "")
++# set(Architecture    "")
++# set(Maintainer      "")
++# set(Email           "")
++# set(Descrition      "")
++
++function(find_str _IN _SEP _OUT)
++    string(FIND "${_IN}" "${_SEP}" _TMP)
++    set(${_OUT} ${_TMP} PARENT_SCOPE)
++endfunction(find_str _IN _SEP _OUT)
++
++
++function(find_next _IN _OUT)
++    find_str("${_IN}" "\n" _TMP)
++    set(${_OUT} ${_TMP} PARENT_SCOPE)
++endfunction(find_next _IN _OUT)
++
++function(sub_next _IN _INDEX _OUT __OUT)
++    find_next(${_IN} _NEXTINDEX)
++    string(SUBSTRING "${_IN}" ${_INDEX} ${_NEXTINDEX} _TMP)
++    math(EXPR _NEXTINDEX ${_NEXTINDEX}+1)
++    string(SUBSTRING "${_IN}" ${_NEXTINDEX} -1 __TMP)
++    set(${_OUT} ${_TMP} PARENT_SCOPE)
++    set(${__OUT} ${__TMP} PARENT_SCOPE)
++endfunction(sub_next _IN _INDEX _OUT)
++
++function(trim_str _IN _OUT)
++    string(STRIP "${_IN}" _TMP)
++    set(${_OUT} ${_TMP} PARENT_SCOPE)
++endfunction(trim_str _IN _OUT)
++
++function(split_str _IN _SEP _OUT)
++    string(FIND "${_IN}" "${_SEP}" _TMP_INDEX)
++    if(NOT _TMP_INDEX EQUAL -1)
++        string(SUBSTRING "${_IN}" 0 ${_TMP_INDEX} _TMP)
++        math(EXPR _TMP_INDEX ${_TMP_INDEX}+1)
++        string(SUBSTRING "${_IN}" ${_TMP_INDEX} -1 __TMP)
++        set(${_OUT} "${_TMP};${__TMP}" PARENT_SCOPE)
++    else()
++        set(${_OUT} ${_IN} PARENT_SCOPE)
++    endif(NOT _TMP_INDEX EQUAL -1)
++endfunction(split_str _IN _SEP _OUT)
++
++function(split_str_p _IN _SEP _OUT __OUT)
++    split_str("${_IN}" "${_SEP}" _TMP)
++    list(GET _TMP 0 __TMP)
++    list(GET _TMP 1 ___TMP)
++    set(${_OUT} ${__TMP} PARENT_SCOPE)
++    set(${__OUT} ${___TMP} PARENT_SCOPE)
++endfunction(split_str_p _IN _SEP _OUT __OUT)
++
++function(split_str_n _IN _SEP _OUT _N)
++    if(_N GREATER 1)
++        set(_C ${_N})
++        set(_RET "")
++        set(_NEXT ${_IN})
++        while(NOT _C EQUAL 0)
++            split_str("${_NEXT}" "${_SEP}" _TMP)
++            list(LENGTH _TMP _TMP_LEN)
++            if(_TMP_LEN EQUAL 2)
++                list(GET _TMP 0 __TMP)
++                list(GET _TMP 1 _NEXT)
++                list(APPEND _RET ${__TMP})
++            else()
++                break()
++            endif(_TMP_LEN EQUAL 2)
++            math(EXPR _C "${_C}-1")
++        endwhile(NOT _C EQUAL 0)
++        list(APPEND _RET ${_NEXT})
++        set(${_OUT} ${_RET} PARENT_SCOPE)
++    else()
++        split_str("${_IN}" "${_SEP}" _TMP)
++        set(${_OUT} ${_TMP} PARENT_SCOPE)
++    endif(_N GREATER 1)
++endfunction(split_str_n _IN _SEP _OUT _N)
++
++
++function(set_package_vars _IN_KEY _IN_VAL)
++
++    # trim_str("${_IN_KEY}" _IN_KEY)
++
++    find_str("${_IN_KEY}" "Type" _Type)
++    if(_Type EQUAL "0")
++        string(TOUPPER "${_IN_VAL}" _IN_VAL_UPPER)
++        string(TOLOWER "${_IN_VAL}" _IN_VAL_LOWER)
++        set(CPACK_GENERATOR "${_IN_VAL_UPPER}" PARENT_SCOPE)
++        message("--> 软件包类型: ${_IN_VAL_LOWER}")
++    endif(_Type EQUAL "0")
++
++    find_str("${_IN_KEY}" "Package" _Package)
++    if(_Package EQUAL "0")
++        if(_IN_VAL STREQUAL "auto")
++            set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}" PARENT_SCOPE)
++        else()
++            set(CPACK_DEBIAN_PACKAGE_NAME "${_IN_VAL}" PARENT_SCOPE)
++        endif(_IN_VAL STREQUAL "auto")
++        message("--> 软件包名: ${_IN_VAL}")
++    endif(_Package EQUAL "0")
++
++    find_str("${_IN_KEY}" "Version" _Version)
++    if(_Version EQUAL "0")
++        if(_IN_VAL STREQUAL "auto")
++            set(CPACK_DEBIAN_PACKAGE_VERSION "${PROJECT_VERSION}" PARENT_SCOPE)
++        else()
++            set(CPACK_DEBIAN_PACKAGE_VERSION "${_IN_VAL}" PARENT_SCOPE)
++        endif(_IN_VAL STREQUAL "auto")
++
++        message("--> 软件版本: ${_IN_VAL}")
++    endif(_Version EQUAL "0")
++
++    find_str("${_IN_KEY}" "CalVer" _CalVer)
++    if(_CalVer EQUAL "0")
++        set(CalVer "${_IN_VAL}" PARENT_SCOPE)
++        message("--> 日历化版本: ${_IN_VAL}")
++    endif(_CalVer EQUAL "0")
++
++    find_str("${_IN_KEY}" "Architecture" _Architecture)
++    if(_Architecture EQUAL "0")
++        set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${_IN_VAL}" PARENT_SCOPE)
++        if(_IN_VAL STREQUAL "auto")
++            execute_process(
++                COMMAND dpkg --print-architecture
++                OUTPUT_VARIABLE _RETV
++                OUTPUT_STRIP_TRAILING_WHITESPACE
++            )
++            set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${_RETV}" PARENT_SCOPE)
++        endif(_IN_VAL STREQUAL "auto")
++        message("--> 软件架构: ${_IN_VAL}")
++    endif(_Architecture EQUAL "0")
++
++    find_str("${_IN_KEY}" "Priority" _Priority)
++    if(_Priority EQUAL "0")
++        set(CPACK_DEBIAN_PACKAGE_PRIORITY "${_IN_VAL}" PARENT_SCOPE)
++        message("--> 优先级: ${_IN_VAL}")
++    endif(_Priority EQUAL "0")
++
++    find_str("${_IN_KEY}" "Depends" _Depends)
++    if(_Depends EQUAL "0")
++        set(CPACK_DEBIAN_PACKAGE_DEPENDS "${_IN_VAL}" PARENT_SCOPE)
++        message("--> 软件依赖: ${_IN_VAL}")
++    endif(_Depends EQUAL "0")
++
++    find_str("${_IN_KEY}" "Maintainer" _Maintainer)
++    if(_Maintainer EQUAL "0")
++        set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${_IN_VAL}" PARENT_SCOPE)
++        message("--> 软件维护者: ${_IN_VAL}")
++    endif(_Maintainer EQUAL "0")
++
++    find_str("${_IN_KEY}" "Homepage" _Homepage)
++    if(_Homepage EQUAL "0")
++        set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${_IN_VAL}" PARENT_SCOPE)
++        message("--> 软件主页: ${_IN_VAL}")
++    endif(_Homepage EQUAL "0")
++
++    find_str("${_IN_KEY}" "Recommends" _Recommends)
++    if(_Recommends EQUAL "0")
++        set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "${_IN_VAL}" PARENT_SCOPE)
++        message("--> 软件建议: ${_IN_VAL}")
++    endif(_Recommends EQUAL "0")
++
++endfunction(set_package_vars _IN_KEY _IN_VAL)
++
++# 定义一个自定义(add_package_descript)函数
++# 用于按特定配置约定自动化构建软件包配置
++function(add_package_descript IN_DES)
++    set(PACKAGE_DES_PATH "${IN_DES}")
++
++    if(EXISTS ${IN_DES})
++
++    elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${IN_DES}")
++        set(PACKAGE_DES_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${IN_DES}")
++    else()
++        message(FATAL_ERROR "!! Not Found Path: ${PACKAGE_DES_PATH}")
++        return()
++    endif(EXISTS ${IN_DES})
++
++    file(READ ${PACKAGE_DES_PATH} DES_CONTENT)
++    trim_str("${DES_CONTENT}" DES_CONTENT)
++
++    ################## 解析 ##################
++
++    sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
++    set(PREV_DES "")
++    while(NOT DES_LINE STREQUAL "${PREV_DES}")
++        # 检查该描述行是否是 # 注释开头,是的话将跳过该行
++        find_str("${DES_LINE}" "#" _COMMENT)
++        if(_COMMENT EQUAL "0")
++            message("--> !!!!!!! ${DES_LINE}")
++            sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
++            continue()
++        endif(_COMMENT EQUAL "0")
++
++        # 检查该描述行是否是 Descrition 开头,是的话说明描述结尾了
++        find_str("${DES_LINE}" "Descrition" _DESCRIPTION)
++        if(_DESCRIPTION EQUAL "0")
++            break()
++        endif(_DESCRIPTION EQUAL "0")
++
++        split_str_n("${DES_LINE}" ":" _TMP 1)
++        list(LENGTH _TMP _TMP_LEN)
++
++        if(_TMP_LEN EQUAL 2)
++            split_str_p("${DES_LINE}" ":" _TMP __TMP)
++            trim_str("${__TMP}" __TMP)
++            string(LENGTH "${__TMP}" __TMP_LENGTH)
++            if(NOT __TMP_LENGTH EQUAL "0")
++                set_package_vars("${_TMP}" "${__TMP}")
++            endif(NOT __TMP_LENGTH EQUAL "0")
++        endif(_TMP_LEN EQUAL 2)
++
++        # 记录当前行,获取下一行,可能是已经结尾了(将保持重复行)
++        set(PREV_DES "${DES_LINE}")
++        sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
++    endwhile(NOT DES_LINE STREQUAL "${PREV_DES}")
++
++
++    # 再一次检查该描述行是否是 Descrition 开头,是的话将进行分析描述行
++    find_str("${DES_LINE}" "Descrition" _DESCRIPTION)
++    if(_DESCRIPTION EQUAL "0")
++        split_str_p("${DES_LINE}" ":" _TMP __TMP)
++        trim_str("${__TMP}" __TMP)
++        set(Descrition ${__TMP})
++        set(PREV_DES_LINE "")
++        while(NOT PREV_DES_LINE STREQUAL DES_LINE)
++            if(NOT PREV_DES_LINE STREQUAL "")
++                set(Descrition "${Descrition}\n${DES_LINE}")
++            endif(NOT PREV_DES_LINE STREQUAL "")
++            set(PREV_DES_LINE "${DES_LINE}")
++            sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
++        endwhile(NOT PREV_DES_LINE STREQUAL DES_LINE)
++        # set(Descrition "${Descrition}")
++        message("--> 软件说明: ${Descrition}")
++
++        set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${Descrition})
++    endif(_DESCRIPTION EQUAL "0")
++
++    ##################### deb #####################
++    # ARCHITECTURE
++    if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
++        set(ARCHITECTURE "amd64")
++    elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "aarch64")
++        set(ARCHITECTURE "arm64")
++    endif()
++
++    #################### Calendar Version ###################
++    if("${CalVer}" STREQUAL "true")
++        string(TIMESTAMP BUILD_TIME "%Y%m%d")
++        set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_DEBIAN_PACKAGE_VERSION}-${BUILD_TIME}")
++    endif("${CalVer}" STREQUAL "true")
++
++
++
++    ##################### deb file name #####################
++    set(_Package      "${CPACK_DEBIAN_PACKAGE_NAME}")
++    set(_Version      "${CPACK_DEBIAN_PACKAGE_VERSION}")
++    set(_Architecture "${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
++
++    set(_DebFileName
++        "${_Package}_${_Version}_${_Architecture}${PACKAGE_SUFFIX}.deb"
++    )
++    set(CPACK_DEBIAN_FILE_NAME            ${_DebFileName})
++
++
++    # set(CPACK_DEBIAN_PACKAGE_NAME         "${Package}")
++    # set(CPACK_DEBIAN_PACKAGE_VERSION      "${Version}")
++    # set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${Architecture}")
++    # set(CPACK_DEBIAN_PACKAGE_DEPENDS      "${Depends}")
++    # set(CPACK_DEBIAN_PACKAGE_PRIORITY     "${Priority}")
++    # set(CPACK_DEBIAN_PACKAGE_MAINTAINER   "${Maintainer}")
++    # set(CPACK_DEBIAN_PACKAGE_DESCRIPTION  "${Descrition}")
++
++    # 设置即将使用的标准脚本
++    # set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
++    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/preinst"
++    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/postinst"
++    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/prerm"
++    #     "${CMAKE_SOURCE_DIR}/config/DEBIAN/postrm"
++    # )
++
++    # 设置为ON,以便使用 dpkg-shlibdeps 生成更好的包依赖列表。
++    # set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
++    # set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
++    # set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY "=")
++
++    include(CPack)
++
++endfunction(add_package_descript IN_DES)
++
++
++# TODO:
++# CPACK_GENERATOR
++# CPACK_DEBIAN_FILE_NAME                - n
++# CPACK_DEBIAN_PACKAGE_NAME             - y
++# CPACK_DEBIAN_PACKAGE_VERSION          - y
++# CPACK_DEBIAN_PACKAGE_ARCHITECTURE     - y(auto)
++# CPACK_DEBIAN_PACKAGE_DEPENDS          - y
++# CPACK_DEBIAN_PACKAGE_PRIORITY         - y
++# CPACK_DEBIAN_PACKAGE_MAINTAINER       - y
++# CPACK_DEBIAN_PACKAGE_DESCRIPTION      - y
++
++# ARCHITECTURE
++# if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
++#     set(ARCHITECTURE "amd64")
++# elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "aarch64")
++#     set(ARCHITECTURE "arm64")
++# endif()
++
++# string(TIMESTAMP BUILD_TIME "%Y%m%d")
+diff --git a/cmake/SparkDesktopMacros.cmake b/cmake/SparkDesktopMacros.cmake
+new file mode 100644
+index 0000000..223ac6b
+--- /dev/null
++++ b/cmake/SparkDesktopMacros.cmake
+@@ -0,0 +1,35 @@
++
++macro(spark_desktop_macros _APP_NAME _APP_NAME_ZH_CN _APP_COMMENT _APP_TYPE _APP_EXECUTE_PATH _APP_EXECUTE_ICON_PATH _APP_CATEGORIES)
++    set(APP_NAME ${_APP_NAME})
++    set(APP_NAME_ZH_CN ${_APP_NAME_ZH_CN})
++    set(APP_COMMENT ${_APP_COMMENT})
++    set(APP_TYPE ${_APP_TYPE})
++    set(APP_EXECUTE_PATH ${_APP_EXECUTE_PATH})
++    set(APP_EXECUTE_ICON_PATH ${_APP_EXECUTE_ICON_PATH})
++    set(APP_CATEGORIES ${_APP_CATEGORIES})
++    configure_file(cmake/spark-desktop.desktop.in
++        ${CMAKE_BINARY_DIR}/${_APP_NAME}.desktop
++    )
++endmacro(spark_desktop_macros _APP_NAME _APP_NAME_ZH_CN _APP_COMMENT _APP_TYPE _APP_EXECUTE_PATH _APP_EXECUTE_ICON_PATH _APP_CATEGORIES)
++
++# include(cmake/SparkDesktopMacros.cmake)
++# 内容默认应用名称: Name= 应与项目名称相同
++# spark_desktop_macros(
++    # 应用名称: Name=
++    # 应用名称: Name[zh_CN]=
++    # 应用说明: Comment=
++    # 应用类型: Type=
++    # 执行程序: Exec=
++    # 图标路径: Icon=
++    # 应用分类: Category=
++# )
++
++# configure_file(<input> <output>
++#                [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
++#                 FILE_PERMISSIONS <permissions>...]
++#                [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
++#                [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
++
++# install(FILES ${APP_NAME}.desktop
++#     DESTINATION /usr/share/applications
++# )
+\ No newline at end of file
+diff --git a/cmake/SparkInstallMacrosConfig.cmake b/cmake/SparkInstallMacrosConfig.cmake
+new file mode 100644
+index 0000000..1f8939b
+--- /dev/null
++++ b/cmake/SparkInstallMacrosConfig.cmake
+@@ -0,0 +1,131 @@
++
++# spark_install_target
++# 基于传入的路径/目标进行安装
++# 可接受的值为: 安装路径 目标A
++# 可接受的值为: 安装路径 目标A 目标B 目标C...
++macro(spark_install_target INSTALL_TARGET_DIR INSTALL_TARGETS)
++    install(TARGETS
++        ${INSTALL_TARGETS} ${ARGN}
++        DESTINATION ${INSTALL_TARGET_DIR})
++endmacro(spark_install_target INSTALL_TARGET_DIR INSTALL_TARGETS)
++
++# spark_install_file
++# 基于传入的路径/文件进行安装
++# 可接受的值为: 安装路径 文件A
++# 可接受的值为: 安装路径 文件A 文件B 文件C...
++macro(spark_install_file INSTALL_FILE_DIR INSTALL_FILE)
++    install(FILES
++        ${INSTALL_FILE} ${ARGN}
++        DESTINATION ${INSTALL_FILE_DIR})
++endmacro(spark_install_file INSTALL_FILE_DIR INSTALL_FILE)
++
++# spark_install_program
++# 基于传入的路径/文件进行安装,并自动为其添加可执行权限
++# 可接受的值为: 安装路径 文件A
++# 可接受的值为: 安装路径 文件A 文件B 文件C...
++macro(spark_install_program INSTALL_PROGRAM_DIR INSTALL_PROGRAM)
++    install(PROGRAMS
++        ${INSTALL_PROGRAM} ${ARGN}
++        DESTINATION ${INSTALL_PROGRAM_DIR})
++endmacro(spark_install_program INSTALL_PROGRAM_DIR INSTALL_PROGRAM)
++
++
++# spark_install_directory
++# 基于传入的路径/目录进行安装
++# 可接受的值为: 安装路径 路径A
++# 可接受的值为: 安装路径 路径A/* 为安装路径A下所有内容
++macro(spark_install_directory INSTALL_DIRECTORY_DIR INSTALL_DIRECOTRY)
++    # INSTALL_DIRECOTRY 可能包含 * ?
++    # 1. 找到 '*', 截取,列出目录下所有文件,安装
++    # 2. 是文件的直接使用 spark_install_file 安装
++    # 2. 是目录的直接使用 spark_install_directory 安装
++    # message(FATAL_ERROR "${INSTALL_DIRECTORY_DIR}")
++    # string(FIND <string> <substring> <output_variable> [REVERSE])
++    string(FIND "${INSTALL_DIRECOTRY}" "*" INSTALL_DIRECTORY_FIND_INDEX)
++    # message(FATAL_ERROR "${INSTALL_DIRECTORY_FIND_INDEX}:  ${INSTALL_DIRECTORY_DIR}")
++
++    # file(GLOB <variable>
++    #  [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
++    #  [<globbing-expressions>...])
++
++    if (NOT INSTALL_DIRECTORY_FIND_INDEX EQUAL -1)
++        # string(SUBSTRING <string> <begin> <length> <output_variable>)
++        string(SUBSTRING "${INSTALL_DIRECOTRY}" 0 ${INSTALL_DIRECTORY_FIND_INDEX} INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING)
++        # message(FATAL_ERROR "directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING}")
++
++        # file(GLOB <variable>
++        #     [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
++        #     [<globbing-expressions>...])
++
++        file(GLOB INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST  ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING}/*)
++        list(LENGTH INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST_LENGTH)
++        foreach(item IN LISTS INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST)
++            # message("-> ${item}")
++            if(IS_DIRECTORY ${item})
++                message("-> ${item} IS_DIRECTORY")
++                # spark_install_directory(${INSTALL_DIRECTORY_DIR} ${item})
++                install(DIRECTORY
++                    ${item}
++                    DESTINATION ${INSTALL_DIRECTORY_DIR}
++                    USE_SOURCE_PERMISSIONS)
++            else()
++                message("-> ${item} NOT IS_DIRECTORY")
++                spark_install_program(${INSTALL_DIRECTORY_DIR} ${item})
++                # spark_install_file(${INSTALL_DIRECTORY_DIR} ${item})
++            endif(IS_DIRECTORY ${item})
++        endforeach(item IN LISTS INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST)
++
++        # message(FATAL_ERROR " directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST}")
++        # message(FATAL_ERROR " directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST_LENGTH}")
++
++    else()
++        message(FATAL_ERROR "install: ${INSTALL_DIRECTORY_DIR}")
++
++        install(DIRECTORY
++            ${INSTALL_DIRECOTRY} ${ARGN}
++            DESTINATION ${INSTALL_DIRECTORY_DIR})
++    endif(NOT INSTALL_DIRECTORY_FIND_INDEX EQUAL -1)
++
++endmacro(spark_install_directory INSTALL_DIRECTORY_DIR INSTALL_DIRECOTRY)
++
++
++
++macro(spark_install_changelog CHANGE_LOG_FILE)
++    set(SOURCE_CHANGE_LOG_FILE ${CHANGE_LOG_FILE})
++    if (EXISTS ${SOURCE_CHANGE_LOG_FILE})
++
++        execute_process(COMMAND test -f ${SOURCE_CHANGE_LOG_FILE}
++            RESULT_VARIABLE changelog_test
++        )
++        execute_process(COMMAND which gzip
++            RESULT_VARIABLE gzip_test
++        )
++        if (NOT changelog_test  EQUAL 0)
++            message(FATAL_ERROR "NOTE: 不是常规文件: ${SOURCE_CHANGE_LOG_FILE}")
++        endif(NOT changelog_test  EQUAL 0)
++
++        if (NOT gzip_test  EQUAL 0)
++            message(FATAL_ERROR "NOTE: 未安装 gzip, 无法压缩 changelog")
++        endif(NOT gzip_test  EQUAL 0)
++
++        # 压缩与安装日志文件
++        add_custom_command(
++            OUTPUT "${CMAKE_BINARY_DIR}/changelog.gz"
++            COMMAND gzip -cn9 "${SOURCE_CHANGE_LOG_FILE}" > "${CMAKE_BINARY_DIR}/changelog.gz"
++            WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
++            COMMENT "Compressing changelog"
++        )
++        add_custom_target(changelog ALL DEPENDS "${CMAKE_BINARY_DIR}/changelog.gz")
++
++        # include(GNUInstallDirs)
++        set(SPARK_INSTALL_CHANGE_LOG_DIR "/usr/share/doc/${PROJECT_NAME}/")
++        install(FILES
++            ${CMAKE_BINARY_DIR}/changelog.gz
++            debian/copyright
++
++            DESTINATION ${SPARK_INSTALL_CHANGE_LOG_DIR}
++        )
++    else()
++        message(FATAL_ERROR "未找到: ${SOURCE_CHANGE_LOG_FILE}")
++    endif(EXISTS ${SOURCE_CHANGE_LOG_FILE})
++endmacro(spark_install_changelog CHANGE_LOG_FILE)
+diff --git a/cmake/package-deb.descript b/cmake/package-deb.descript
+new file mode 100644
+index 0000000..be0fa83
+--- /dev/null
++++ b/cmake/package-deb.descript
+@@ -0,0 +1,45 @@
++# 注释行(使用方式)
++# find_package(DebPackage PATHS ${CMAKE_SOURCE_DIR})
++# add_package_descript(cmake/package-deb.descript)
++
++# 打包后的文件名称
++# FileName: 待定
++# 配置 PACKAGE_SUFFIX 变量可添加尾巴名称
++# 如在 Makefile 中硬编码方式
++# OSID=$(shell lsb_release -si)
++# OSRELEASE=$(shell lsb_release -sr)
++# -DPACKAGE_SUFFIX="_$(OSID)$(OSRELEASE)"
++
++# deb 安装包的安装时脚本
++# 1.安装[前|后]执行脚本(preinst,postinst),
++# 2.卸载[前|后]执行脚本(prerm,postrm)
++# ControlExtra: 未定义(暂不支持)
++# 如需指定请修改 DebPackageConfig.cmake 模板(第252行)
++# CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA 变量
++
++# 打包类型,暂支持 deb, 未来支持 tgz(tar.gz)
++Type: deb
++# 软件包名称(自动, 使用 PROJECT_NAME 变量值)
++Package: com.hmja.notepad
++# 软件包版本(自动, 使用 PROJECT_VERSION 变量值)
++Version: auto
++# 日历化尾部版本
++CalVer: true
++# 软件包架构(自动)
++Architecture: auto
++# 软件包属于的系统部分[admin|cli-mono|comm|database|debug|devel|doc|editors|education|electronics|embedded|fonts|games|gnome|gnu-r|gnustep|graphics|hamradio|haskell|httpd|interpreters|introspection|java|javascript|kde|kernel|libdevel|libs|lisp|localization|mail|math|metapackages|misc|net|news|ocaml|oldlibs|otherosfs|perl|php|python|ruby|rust|science|shells|sound|tasks|tex|text|utils|vcs|video|web|x11|xfce|zope]
++Section: editors
++# 软件包优先级[required|important|stantard|optional|extra]
++Priority: optional
++# 软件包依赖
++Depends:
++# 软件包维护者(组织或个人)
++Maintainer: 尹作为 <[email protected]>
++# 软件包主页
++Homepage: https://gitee.com/cxasm/notepad--
++# 软件包建议
++Recommends:
++# 软件包描述信息
++Descrition: Notepad--是一个国产跨平台、简单的文本编辑器。
++ Notepad--是一个国产跨平台、简单的文本编辑器,是替换notepad++的一种选择。
++ 其内置强大的代码对比功能,让你丢掉付费的beyond compare。
+diff --git a/cmake/spark-desktop.desktop.in b/cmake/spark-desktop.desktop.in
+new file mode 100644
+index 0000000..e7c3b18
+--- /dev/null
++++ b/cmake/spark-desktop.desktop.in
+@@ -0,0 +1,12 @@
++[Desktop Entry]
++Version=1.0
++Name=@APP_NAME@
++Name[zh_CN]=@APP_NAME_ZH_CN@
++Comment=@APP_COMMENT@
++Type=@APP_TYPE@
++Exec=@APP_EXECUTE_PATH@
++Icon=@APP_EXECUTE_ICON_PATH@
++Categories=@APP_CATEGORIES@
++MimeType=text/plain
++
++# Generated from the DesktopGenerater component of the z-Tools toolkit
+\ No newline at end of file
+-- 
+2.20.1
+
+
+From 684ced155e1c749b06e76449177c95db9392c0fc Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Wed, 1 Feb 2023 20:09:49 +0800
+Subject: [PATCH 03/13] =?UTF-8?q?repo:=20=E5=BC=95=E5=85=A5=20Spark=20?=
+ =?UTF-8?q?=E6=9E=84=E5=BB=BA=EF=BC=8C=E6=94=AF=E6=8C=81=E6=9E=84=E5=BB=BA?=
+ =?UTF-8?q?=20Appimage?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt                  |   8 ++
+ Makefile                        |  23 ++++++
+ cmake/SparkAppimageConfig.cmake | 139 ++++++++++++++++++++++++++++++++
+ cmake/spark-appimage.desktop.in |  10 +++
+ 4 files changed, 180 insertions(+)
+ create mode 100644 cmake/SparkAppimageConfig.cmake
+ create mode 100644 cmake/spark-appimage.desktop.in
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 666fbdb..a8f27aa 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -80,6 +80,14 @@ if(CMAKE_HOST_UNIX)
+     spark_install_file(/usr/share/notepad--/icons/ assets/spark.png)
+     spark_install_target(/usr/bin/ ${PROJECT_NAME})
+ 
++
++    # 1. 在顶层构建中导入 Appimage 的构建
++    include(cmake/SparkAppimageConfig.cmake)  # 导入来自 Spark 构建的 Appimage 构建
++    add_appimage_icon(assets/spark.png)       # 添加到 Appimage 中的默认的图标
++    add_appimage_desktop()                    # 添加到 Appimage 中的默认desktop(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
++    add_appimage()                            # 应用对 Appimage 的构建
++
++
+     # 注释行(使用方式)
+     find_package(DebPackage PATHS ${CMAKE_SOURCE_DIR})
+     add_package_descript(cmake/package-deb.descript)
+diff --git a/Makefile b/Makefile
+index 43e849f..b71b27f 100644
+--- a/Makefile
++++ b/Makefile
+@@ -59,3 +59,26 @@ enter-qdebug-mode:
+ 	# 进入新的 bash 环境
+ 	@# export QT_LOGGING_RULES=".debug=true; qt.*.debug=false; dtk.*.debug=false; dde.*.debug=false; qtc*=false; " && bash
+ 	export QT_LOGGING_RULES=".debug=true" && bash
++
++# Appimage 的构建流 --
++# 在 Makefile 进行构建目标构建 Appimage (要求提供工具的绝对路径,然后可依次进行linuxdeployqt, genrate-appimage)
++# 来自于 https://github.com/probonopd/linuxdeployqt 	的 linuxdeployqt
++# 来自于 https://github.com/AppImage/AppImageKit		的 appimagetool
++# 来自于 https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git  托管存储的工具
++
++# 或指定你所想存放克隆项目的位置
++BUNDLE_LINUXDEPLOYQT := $(shell pwd)/build/bundle-linuxdeployqt
++
++download-bundle-linuxdeploytools:
++	-git clone https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git $(BUNDLE_LINUXDEPLOYQT)
++
++LINUXDEPLOYQT := "$(BUNDLE_LINUXDEPLOYQT)/linuxdeployqt-continuous-x86_64.AppImage"
++APPIMAGETOOL  := "$(BUNDLE_LINUXDEPLOYQT)/appimagetool-x86_64.AppImage"
++
++linuxdeploy: release download-bundle-linuxdeploytools
++	cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
++	cd build && make linuxdeploy
++
++genrate-appimage:
++	cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
++	cd build && make appimage
+diff --git a/cmake/SparkAppimageConfig.cmake b/cmake/SparkAppimageConfig.cmake
+new file mode 100644
+index 0000000..7463a48
+--- /dev/null
++++ b/cmake/SparkAppimageConfig.cmake
+@@ -0,0 +1,139 @@
++# export PATH=/usr/lib/x86_64-linux-gnu/qt5/bin:$PATH
++# export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
++# export QT_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/qt5/plugins:$QT_PLUGIN_PATH
++# export QML2_IMPORT_PATH=/usr/lib/x86_64-linux-gnu/qt5/qml:$QML2_IMPORT_PATH
++
++# export PATH=/usr/lib/x86_64-linux-gnu/qt5/bin:$PATH
++# ~/linuxdeployqt-continuous-x86_64.AppImage spark-store-submitter -appimage
++# cd ..
++# ~/appimagetool-x86_64.AppImage appimage/
++
++# LINUXDEPLOYQT=/home/zinface/linuxdeployqt-continuous-x86_64.AppImage
++# APPIMAGETOOL=/home/zinface/appimagetool-x86_64.AppImage
++
++# if ()
++set(APPIMAGE_OUTPUT  "${CMAKE_BINARY_DIR}/appimage")
++set(APPIMAGE_ICON    "${APPIMAGE_OUTPUT}/default.png")
++set(APPIMAGE_DESTKOP "${APPIMAGE_OUTPUT}/default.desktop")
++# set(LINUXDEPLOYQT)
++# set(APPIMAGETOOL)
++
++function(execute_linuxdeploy _PATH)
++    execute_process(COMMAND ${LINUXDEPLOYQT}
++        WORKING_DIRECTORY "${APPIMAGE_OUTPUT}"
++        )
++endfunction(execute_linuxdeploy _PATH)
++
++function(target_linuxdeploy)
++    add_custom_target(linuxdeploy pwd
++        BYPRODUCTS appimage
++        COMMAND cp ../${PROJECT_NAME} .
++        COMMAND "${LINUXDEPLOYQT}" ${PROJECT_NAME} -appimage -unsupported-allow-new-glibc -verbose=3 -no-strip|| true
++        COMMAND cp ../spark-appimage.desktop default.desktop
++        COMMAND cp ../spark-appimage.png     default.png
++        WORKING_DIRECTORY "${APPIMAGE_OUTPUT}")
++endfunction(target_linuxdeploy)
++
++function(target_appimage)
++    add_custom_target(copy-desktop-appimage
++        COMMAND cp ../spark-appimage.desktop default.desktop
++        COMMAND cp ../spark-appimage.png     default.png
++        WORKING_DIRECTORY "${APPIMAGE_OUTPUT}")
++    add_custom_target(appimage pwd
++        COMMAND ${APPIMAGETOOL} ${APPIMAGE_OUTPUT}
++        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
++        DEPENDS copy-desktop-appimage)
++endfunction(target_appimage)
++
++function(add_appimage)
++    # check linuxdeploy
++    if(NOT DEFINED LINUXDEPLOYQT)
++        message("AppImage> Not Found LINUXDEPLOYQT Variable!")
++        return()
++    endif(NOT DEFINED LINUXDEPLOYQT)
++    if(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
++        message("> cmake version is less than 3.19")
++        message(WARNING "!Relative paths are not supported!")
++    else()
++        file(REAL_PATH ${LINUXDEPLOYQT} LINUXDEPLOYQT_REAL_PATH)
++    endif(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
++    message("AppImage> Found LINUXDEPLOYQT Variable: ${LINUXDEPLOYQT_REAL_PATH}")
++
++    # check appimagetool
++    if(NOT DEFINED APPIMAGETOOL)
++        message("AppImage> Not Found APPIMAGETOOL Variable!")
++        return()
++    endif(NOT DEFINED APPIMAGETOOL)
++    if(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
++        # execute_process(COMMAND realpath ${APPIMAGETOOL} OUTPUT_VARIABLE APPIMAGETOOL_REAL_PATH)
++        message("> cmake version is less than 3.19")
++        message(WARNING "!Relative paths are not supported!")
++    else()
++        file(REAL_PATH ${APPIMAGETOOL} APPIMAGETOOL_REAL_PATH)
++    endif(CMAKE_VERSION VERSION_LESS 3.19 AND NOT EXISTS ${LINUXDEPLOYQT})
++    message("AppImage> Found APPIMAGETOOL Variable: ${LINUXDEPLOYQT_REAL_PATH}")
++
++    # do add_custome_target
++    make_directory(${APPIMAGE_OUTPUT})
++    target_linuxdeploy()
++    target_appimage()
++endfunction(add_appimage)
++
++function(add_appimage_desktop)
++    configure_file(cmake/spark-appimage.desktop.in
++        ${CMAKE_BINARY_DIR}/spark-appimage.desktop @ONLY)
++endfunction(add_appimage_desktop)
++
++function(add_appimage_icon _ICON_PATH)
++    if(CMAKE_VERSION VERSION_LESS 3.21)
++        message("> cmake version is less than 3.21")
++        configure_file(${_ICON_PATH} ${CMAKE_BINARY_DIR}/spark-appimage.png COPYONLY)
++    else()
++        file(COPY_FILE ${_ICON_PATH} ${CMAKE_BINARY_DIR}/spark-appimage.png)
++    endif(CMAKE_VERSION VERSION_LESS 3.21)
++endfunction(add_appimage_icon _ICON_PATH)
++
++
++
++# 如果glic>=2.27,你就需要加上参数 -unsupported-allow-new-glibc (意思就是不再低版本发行版使用了)
++# 或 -unsupported-bundle-everything(大概的意思是尝试兼容,实际测试,到其他发行版直接用不了了,有可能是发行版的原因,还是建议用前者,虽然放弃了低版本)
++
++# -unsupported-bundle-everything
++    # 捆绑所有依赖库,包括 ld-linux.so 加载器和 glibc。这将允许构建在较新系统上的应用程序在较旧的目标系统上运行,但不建议这样做,因为它会导致捆绑包超出所需的大小(并且可能到其他发行版无法使用)
++# -unsupported-allow-new-glibc
++    # 允许 linuxdeployqt 在比仍受支持的最旧 Ubuntu LTS 版本更新的发行版上运行。这将导致 AppImage无法在所有仍受支持的发行版上运行,既不推荐也不测试或支持
++
++# ./linuxdeployqt-7-x86_64.AppImage 程序目录/程序 -appimage -unsupported-allow-new-glibc
++# ./linuxdeployqt-7-x86_64.AppImage 程序目录/程序 -appimage -unsupported-bundle-everything
++
++
++
++
++# 1. 在顶层构建中导入 Appimage 的构建
++# include(cmake/SparkAppimageConfig.cmake)  # 导入来自 Spark 构建的 Appimage 构建
++# add_appimage_icon(assets/spark.png)       # 添加到 Appimage 中的默认的图标
++# add_appimage_desktop()                    # 添加到 Appimage 中的默认desktop(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
++# add_appimage()                            # 应用对 Appimage 的构建
++
++# 2. 在 Makefile 进行构建目标构建 Appimage 的构建流 --
++# 在 Makefile 进行构建目标构建 Appimage (要求提供工具的绝对路径,然后可依次进行linuxdeployqt, genrate-appimage)
++# 来自于 https://github.com/probonopd/linuxdeployqt 	的 linuxdeployqt
++# 来自于 https://github.com/AppImage/AppImageKit		的 appimagetool
++# 来自于 https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git  托管存储的工具
++
++# 或指定你所想存放克隆项目的位置
++# BUNDLE_LINUXDEPLOYQT := $(shell pwd)/build/bundle-linuxdeployqt
++
++# download-bundle-linuxdeploytools:
++# 	-git clone https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git $(BUNDLE_LINUXDEPLOYQT)
++
++# LINUXDEPLOYQT := "$(BUNDLE_LINUXDEPLOYQT)/linuxdeployqt-continuous-x86_64.AppImage"
++# APPIMAGETOOL  := "$(BUNDLE_LINUXDEPLOYQT)/appimagetool-x86_64.AppImage"
++
++# linuxdeploy: release download-bundle-linuxdeploytools
++# 	cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
++# 	cd build && make linuxdeploy
++
++# genrate-appimage:
++# 	cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
++# 	cd build && make appimage
+diff --git a/cmake/spark-appimage.desktop.in b/cmake/spark-appimage.desktop.in
+new file mode 100644
+index 0000000..0ca2577
+--- /dev/null
++++ b/cmake/spark-appimage.desktop.in
+@@ -0,0 +1,10 @@
++[Desktop Entry]
++Name=@APP_NAME@
++Name[zh_CN]=@APP_NAME_ZH_CN@
++Exec=AppRun %F
++Icon=default
++Comment=@APP_COMMENT@
++Terminal=true
++Type=Application
++Categories=@APP_CATEGORIES@
++MimeType=text/plain
+-- 
+2.20.1
+
+
+From c241f19bbcec29d7a1ed8fe8e1f0d6e36a957b69 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Thu, 2 Feb 2023 13:58:29 +0800
+Subject: [PATCH 04/13] =?UTF-8?q?desktop:=20=E4=B8=BA=20desktop=20?=
+ =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E6=9C=AC=E6=96=87=E4=BB=B6=E7=9A=84?=
+ =?UTF-8?q?=E7=9B=B8=E5=85=B3=20MimeType?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ cmake/spark-appimage.desktop.in | 2 +-
+ cmake/spark-desktop.desktop.in  | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/cmake/spark-appimage.desktop.in b/cmake/spark-appimage.desktop.in
+index 0ca2577..70fc6b9 100644
+--- a/cmake/spark-appimage.desktop.in
++++ b/cmake/spark-appimage.desktop.in
+@@ -7,4 +7,4 @@ Comment=@APP_COMMENT@
+ Terminal=true
+ Type=Application
+ Categories=@APP_CATEGORIES@
+-MimeType=text/plain
++MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-patch;text/x-adasrc;text/x-chdr;text/x-csrc;text/css;application/x-desktop;text/x-patch;text/x-fortran;text/html;text/x-java;text/x-tex;text/x-makefile;text/x-objcsrc;text/x-pascal;application/x-perl;application/x-perl;application/x-php;text/vnd.wap.wml;text/x-python;application/x-ruby;text/sgml;application/xml;model/vrml;image/svg+xml;application/json;
+diff --git a/cmake/spark-desktop.desktop.in b/cmake/spark-desktop.desktop.in
+index e7c3b18..e33c74e 100644
+--- a/cmake/spark-desktop.desktop.in
++++ b/cmake/spark-desktop.desktop.in
+@@ -7,6 +7,6 @@ Type=@APP_TYPE@
+ Exec=@APP_EXECUTE_PATH@
+ Icon=@APP_EXECUTE_ICON_PATH@
+ Categories=@APP_CATEGORIES@
+-MimeType=text/plain
++MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-patch;text/x-adasrc;text/x-chdr;text/x-csrc;text/css;application/x-desktop;text/x-patch;text/x-fortran;text/html;text/x-java;text/x-tex;text/x-makefile;text/x-objcsrc;text/x-pascal;application/x-perl;application/x-perl;application/x-php;text/vnd.wap.wml;text/x-python;application/x-ruby;text/sgml;application/xml;model/vrml;image/svg+xml;application/json;
+ 
+ # Generated from the DesktopGenerater component of the z-Tools toolkit
+\ No newline at end of file
+-- 
+2.20.1
+
+
+From 4a74a60af053dfa4680918ceac8a78974d481d53 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Thu, 2 Feb 2023 14:00:54 +0800
+Subject: [PATCH 05/13] =?UTF-8?q?repo:=20=E5=AF=B9=20desktop=20=E6=96=87?=
+ =?UTF-8?q?=E4=BB=B6=E6=B7=BB=E5=8A=A0=20%F=20=E5=8F=82=E6=95=B0=EF=BC=8C?=
+ =?UTF-8?q?=E4=BB=A5=E4=BF=9D=E8=AF=81=E5=8F=AF=E6=AD=A3=E7=A1=AE=E4=BC=A0?=
+ =?UTF-8?q?=E5=85=A5=E5=8F=82=E6=95=B0?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index a8f27aa..63e878c 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -70,7 +70,8 @@ if(CMAKE_HOST_UNIX)
+         # 应用类型: Type=
+         "Application"
+         # 执行程序: Exec=
+-        "notepad--"
++        # 有关此 %F 参数可查看: https://gitee.com/zinface/z-tools/blob/desktop-dev/src/DesktopGenerater/desktopexecparamdialog.cpp
++        "notepad-- %F"
+         # 图标路径: Icon=
+         "/usr/share/notepad--/icons/spark.png"
+         # 应用分类: Category=
+-- 
+2.20.1
+
+
+From b7f8abc6c6631ea598216c3606d0f61a9b653474 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Thu, 2 Feb 2023 14:47:56 +0800
+Subject: [PATCH 06/13] =?UTF-8?q?cmake-version:=20=E5=B0=86=E7=89=88?=
+ =?UTF-8?q?=E6=9C=AC=E9=99=8D=E5=88=B0=203.22=20=E4=BB=A5=E9=80=82?=
+ =?UTF-8?q?=E7=94=A8=E4=BA=8E=20cmake=20=E6=9E=84=E5=BB=BA?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt            | 2 +-
+ src/qscint/CMakeLists.txt | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 63e878c..60e9171 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1,4 +1,4 @@
+-cmake_minimum_required(VERSION 3.24)
++cmake_minimum_required(VERSION 3.22)
+ project(notepad-- VERSION 1.22.0)
+ 
+ set(CMAKE_AUTOMOC ON)
+diff --git a/src/qscint/CMakeLists.txt b/src/qscint/CMakeLists.txt
+index f132dc6..77f02f2 100644
+--- a/src/qscint/CMakeLists.txt
++++ b/src/qscint/CMakeLists.txt
+@@ -1,4 +1,4 @@
+-cmake_minimum_required(VERSION 3.24)
++cmake_minimum_required(VERSION 3.22)
+ project(qscint CXX)
+ 
+ set(CMAKE_AUTOMOC ON)
+-- 
+2.20.1
+
+
+From 8661b20c61ad6f70f645e69e89da46e2b945bf7d Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Sun, 5 Feb 2023 12:55:38 +0800
+Subject: [PATCH 07/13] =?UTF-8?q?repo:=20=E5=BC=95=E5=85=A5=20Spark=20?=
+ =?UTF-8?q?=E7=8E=B0=E6=9C=89=E5=AE=8C=E6=95=B4=E6=9E=84=E5=BB=BA=E6=A8=A1?=
+ =?UTF-8?q?=E5=9D=97?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ cmake/SparkEnvConfig.cmake          |   8 +
+ cmake/SparkFindQt5Config.cmake      | 153 ++++++++++++++++++
+ cmake/SparkFindQt6Config.cmake      | 130 +++++++++++++++
+ cmake/SparkMacrosConfig.cmake       | 161 +++++++++++++++++++
+ cmake/SparkMacrosExtendConfig.cmake | 237 ++++++++++++++++++++++++++++
+ 5 files changed, 689 insertions(+)
+ create mode 100644 cmake/SparkEnvConfig.cmake
+ create mode 100644 cmake/SparkFindQt5Config.cmake
+ create mode 100644 cmake/SparkFindQt6Config.cmake
+ create mode 100644 cmake/SparkMacrosConfig.cmake
+ create mode 100644 cmake/SparkMacrosExtendConfig.cmake
+
+diff --git a/cmake/SparkEnvConfig.cmake b/cmake/SparkEnvConfig.cmake
+new file mode 100644
+index 0000000..3690f1a
+--- /dev/null
++++ b/cmake/SparkEnvConfig.cmake
+@@ -0,0 +1,8 @@
++cmake_minimum_required(VERSION 3.5.1)
++
++set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
++# set(CMAKE_INCLUDE_CURRENT_DIR ON)
++set(CMAKE_AUTOMOC ON)
++set(CMAKE_AUTOUIC ON)
++set(CMAKE_AUTORCC ON)
++# set(CMAKE_BUILD_TYPE "Debug")
+\ No newline at end of file
+diff --git a/cmake/SparkFindQt5Config.cmake b/cmake/SparkFindQt5Config.cmake
+new file mode 100644
+index 0000000..ad2db4c
+--- /dev/null
++++ b/cmake/SparkFindQt5Config.cmake
+@@ -0,0 +1,153 @@
++cmake_minimum_required(VERSION 3.5.1)
++
++set(SPARK_FIND_QT5 TRUE)
++
++find_package(Qt5 COMPONENTS Core Widgets Network REQUIRED)
++
++# function(target_link_qt5 NAME)
++#     target_link_libraries(${NAME}
++#         Qt5::Core
++#         Qt5::Widgets
++#         Qt5::Network)
++# endfunction(target_link_qt5 NAME)
++
++# 使用 spark_add_link 生成 target_link_qt5 以替代上面内容
++spark_add_link(qt5 Qt5::Core Qt5::Widgets Qt5::Network)
++
++
++# spark_add_link_qt5
++# 自定义宏 spark_add_link_qt5 以扩展 target_link_qt5_<name> 结构
++    # _IN_NAME: 此宏使用嵌套宏 spark_add_link 时追加 <name> 名称
++    # 同等于 spark_add_link(qt_<name> ${ARGN})
++macro(spark_add_link_qt5 _IN_NAME)
++    spark_add_link(qt5_${_IN_NAME} ${ARGN})
++endmacro(spark_add_link_qt5 _IN_NAME)
++
++# 使用 spark_add_link_qt5 生成 target_link_qt5_<name> 的宏
++# spark_add_link_qt5(Concurrent Qt5::Concurrent)
++
++# 高级自定义
++# spark_add_links_qt5
++# 自定义宏 spark_add_links_qt5 以扩展 spark_add_link_qt5 宏配置组
++    # 特点: 任意长度参数
++    # qt5_item: 为进行遍历后的单项,类似于 python3 中的 (for item in items:)
++    # 例如: qt5_item 为 Core:
++        # spark_add_link_qt5(${qt5_item} Qt5::${qt5_item})
++        # 展开为 spark_add_link_qt5(Core Qt5::Core)
++        # 展开为 spark_add_link(qt5_Core Qt5::Core)
++        # 展开为 spark_add_link(qt5_Core Qt5::Core)
++        # 特性: 增加 qt5_Core 转 qt5_core
++            # string(TOLOWER <string> <output_variable>)
++macro(spark_add_links_qt5)
++    set(qt5_items ${ARGN})
++    foreach(qt5_item IN LISTS qt5_items)
++        find_package(Qt5${qt5_item})
++        spark_add_link_qt5(${qt5_item} Qt5::${qt5_item})
++
++        string(TOLOWER "${qt5_item}" qt5_lower_item)
++        spark_add_link_qt5(${qt5_lower_item} Qt5::${qt5_item})
++        message("add_target_link_qt5_${qt5_item} or add_target_link_qt5_${qt5_lower_item}")
++    endforeach(qt5_item IN LISTS qt5_items)
++endmacro(spark_add_links_qt5)
++
++
++# Core	                用于其它模块的核心非图形类。
++# GUI	                图形用户界面 GUI 组件基类。包括 OpenGL。
++# Multimedia	        音频 视频 无线电 摄像头功能类。
++# Multimedia Widgets	用于实现多媒体功能,基于 Widget 的类。
++# Network	            使网络编程更容易和更可移植的类。
++
++# QML	                QML 和 JavaScript 语言类。
++# Quick	                以自定义用户界面 UI 构建高动态应用程序的声明性框架。
++# Quick Controls	    为桌面、嵌入式及移动设备创建高性能用户界面提供轻量 QML 类型。这些类型运用简单样式化体系结构且非常高效。
++# Quick Dialogs	        用于从 Qt Quick 应用程序创建系统对话框,并与之交互的类型。
++# Quick Layouts	        布局是用于在用户界面中排列基于 Qt Quick 2 项的项。
++# Quick Test	        用于 QML 应用程序的单元测试框架,其测试案例被编写成 JavaScript 函数。
++                        # 注意: 二进制保证不兼容 Qt Quick Test,但源代码仍兼容。
++
++# Qt SQL	            集成使用 SQL 数据库的类。
++# Qt Test	            单元测试 Qt 应用程序和库的类。
++                        # 注意: 二进制保证不兼容 Qt Test,但源代码仍兼容。
++# Qt Widgets	        以 C++ 小部件扩展 Qt GUI 的类。
++
++
++
++# 找出所有 Qt5 模板
++# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5
++
++# 掐头去尾,洗一次
++# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d'
++
++# 排序
++# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d' | sort | pr -t -3
++
++spark_add_links_qt5(
++    # AccessibilitySupport
++    # AttributionsScannerTools
++    Concurrent
++    # Core
++    # DBus
++    # Designer
++    # DesignerComponents
++    # DeviceDiscoverySupport
++    # DocTools
++    # EdidSupport
++    # EglFSDeviceIntegration
++    # EglFsKmsSupport
++    # EglSupport
++    # EventDispatcherSupport
++    # FbSupport
++    # FontDatabaseSupport
++    # GlxSupport
++    Gui
++    # Help
++    # InputSupport
++    # KmsSupport
++    # LinguistTools
++    # LinuxAccessibilitySupport
++    # Network
++    # OpenGL
++    # OpenGLExtensions
++    # PacketProtocol
++    # PlatformCompositorSupport
++    # Positioning
++    # PositioningQuick
++    PrintSupport
++    # Qml
++    # QmlDebug
++    # QmlDevTools
++    # QmlImportScanner
++    # QmlModels
++    # QmlWorkerScript
++    # Quick
++    # QuickCompiler
++    # QuickControls2
++    # QuickParticles
++    # QuickShapes
++    # QuickTemplates2
++    # QuickTest
++    # QuickWidgets
++    # SerialBus
++    # SerialPort
++    # ServiceSupport
++    # Sql
++    # Svg
++    # Test
++    # ThemeSupport
++    # UiPlugin
++    # UiTools
++    # VulkanSupport
++    # WebChannel
++    # WebEngine
++    # WebEngineCore
++    # WebEngineWidgets
++    # WebKit
++    # WebKitWidgets
++    # WebSockets
++    # Widgets
++    # X11Extras
++    # XcbQpa
++    # XkbCommonSupport
++    # Xml
++    XmlPatterns
++)
+\ No newline at end of file
+diff --git a/cmake/SparkFindQt6Config.cmake b/cmake/SparkFindQt6Config.cmake
+new file mode 100644
+index 0000000..fb2d741
+--- /dev/null
++++ b/cmake/SparkFindQt6Config.cmake
+@@ -0,0 +1,130 @@
++cmake_minimum_required(VERSION 3.5.1)
++
++set(SPARK_FIND_QT6 TRUE)
++
++find_package(Qt6 COMPONENTS Core Widgets Network REQUIRED)
++
++# function(target_link_qt6 NAME)
++#     target_link_libraries(${NAME}
++#         Qt6::Core
++#         Qt6::Widgets
++#         Qt6::Network)
++# endfunction(target_link_qt6 NAME)
++
++# 使用 spark_add_link 生成 target_link_qt6 以替代上面内容
++spark_add_link(qt6 Qt6::Core Qt6::Widgets Qt6::Network)
++
++
++# spark_add_link_qt6
++# 自定义宏 spark_add_link_qt6 以扩展 target_link_qt6_<name> 结构
++    # _IN_NAME: 此宏使用嵌套宏 spark_add_link 时追加 <name> 名称
++    # 同等于 spark_add_link(qt_<name> ${ARGN})
++macro(spark_add_link_qt6 _IN_NAME)
++    spark_add_link(qt6_${_IN_NAME} ${ARGN})
++endmacro(spark_add_link_qt6 _IN_NAME)
++
++# 使用 spark_add_link_qt6 生成 target_link_qt6_<name> 的宏
++# spark_add_link_qt5(Concurrent Qt6::Concurrent)
++
++# 高级自定义
++# spark_add_links_qt6
++# 自定义宏 spark_add_links_qt6 以扩展 spark_add_link_qt6 宏配置组
++    # 特点: 任意长度参数
++    # qt6_item: 为进行遍历后的单项,类似于 python3 中的 (for item in items:)
++    # 例如: qt6_item 为 Core:
++        # spark_add_link_qt6(${qt6_item} Qt6::${qt6_item})
++        # 展开为 spark_add_link_qt6(Core Qt6::Core)
++        # 展开为 spark_add_link(qt6_Core Qt6::Core)
++        # 展开为 spark_add_link(qt6_Core Qt6::Core)
++        # 特性: 增加 qt6_Core 转 qt6_core
++            # string(TOLOWER <string> <output_variable>)
++macro(spark_add_links_qt6)
++    set(qt6_items ${ARGN})
++    foreach(qt6_item IN LISTS qt6_items)
++        find_package(Qt6${qt6_item})
++        spark_add_link_qt6(${qt6_item} Qt6::${qt6_item})
++
++        string(TOLOWER "${qt6_item}" qt6_lower_item)
++        spark_add_link_qt6(${qt6_lower_item} Qt6::${qt6_item})
++        message("add_target_link_qt6_${qt6_item} or add_target_link_qt6_${qt6_lower_item}")
++    endforeach(qt6_item IN LISTS qt6_items)
++endmacro(spark_add_links_qt6)
++
++# 找出所有 Qt6 模板
++# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt6@Qt6@;' | grep ^Qt6
++
++# 掐头去尾,洗一次
++# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d'
++
++# 排序
++# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt5@Qt5@;' | grep ^Qt5 | sed 's@^Qt5@@; [email protected]$@@; /^\s*$/d' | sort | pr -t -3
++# find /usr/lib/x86_64-linux-gnu/cmake/ -name "*Config.cmake" | sed 's@^.*/Qt6@Qt6@;' | grep ^Qt6 | sed 's@^Qt6@@; [email protected]$@@; /^\s*$/d' | sort | pr -t -3
++
++spark_add_links_qt6(
++    # BuildInternals
++    # BuildInternals/StandaloneTests/Qt5CompatTests
++    # BuildInternals/StandaloneTests/QtBaseTests
++    Concurrent
++    # Core
++    Core5Compat
++    # CoreTools
++    # DBus
++    # DBusTools
++    # DeviceDiscoverySupportPrivate
++    # EglFSDeviceIntegrationPrivate
++    # EglFsKmsGbmSupportPrivate
++    # EglFsKmsSupportPrivate
++    # FbSupportPrivate
++    # Gui
++    # GuiTools
++    # HostInfo
++    # InputSupportPrivate
++    # KmsSupportPrivate
++    # Network
++    # OpenGL
++    # OpenGLWidgets
++    PrintSupport
++    # QComposePlatformInputContextPlugin
++    # QCupsPrinterSupportPlugin
++    # QEglFSEmulatorIntegrationPlugin
++    # QEglFSIntegrationPlugin
++    # QEglFSKmsEglDeviceIntegrationPlugin
++    # QEglFSKmsGbmIntegrationPlugin
++    # QEglFSX11IntegrationPlugin
++    # QEvdevKeyboardPlugin
++    # QEvdevMousePlugin
++    # QEvdevTabletPlugin
++    # QEvdevTouchScreenPlugin
++    # QGifPlugin
++    # QGtk3ThemePlugin
++    # QIBaseDriverPlugin
++    # QIbusPlatformInputContextPlugin
++    # QICOPlugin
++    # QJpegPlugin
++    # QLibInputPlugin
++    # QLinuxFbIntegrationPlugin
++    # QMinimalEglIntegrationPlugin
++    # QMinimalIntegrationPlugin
++    # QMYSQLDriverPlugin
++    # QNetworkManagerNetworkInformationPlugin
++    # QODBCDriverPlugin
++    # QOffscreenIntegrationPlugin
++    # QPSQLDriverPlugin
++    # QSQLiteDriverPlugin
++    # QTlsBackendCertOnlyPlugin
++    # QTlsBackendOpenSSLPlugin
++    # QTsLibPlugin
++    # QTuioTouchPlugin
++    # QVkKhrDisplayIntegrationPlugin
++    # QVncIntegrationPlugin
++    # QXcbEglIntegrationPlugin
++    # QXcbGlxIntegrationPlugin
++    # QXcbIntegrationPlugin
++    # QXdgDesktopPortalThemePlugin
++    # Sql
++    # Test
++    # Widgets
++    # WidgetsTools
++    # XcbQpaPrivate
++    # Xml
++)
+\ No newline at end of file
+diff --git a/cmake/SparkMacrosConfig.cmake b/cmake/SparkMacrosConfig.cmake
+new file mode 100644
+index 0000000..4f68ce1
+--- /dev/null
++++ b/cmake/SparkMacrosConfig.cmake
+@@ -0,0 +1,161 @@
++cmake_minimum_required(VERSION 3.5.1)
++
++# 定义一些 macro 用于自动生成构建结构
++
++# spark_add_library <lib_name> [files]...
++# 构建一个库,基于指定的源文件
++    # 并根据库名生成 target_link_<lib_name> 函数
++macro(spark_add_library _lib_name)
++    message("================ ${_lib_name} Library ================")
++    add_library(${_lib_name} ${ARGN})
++
++    set(SRCS ${ARGN})
++    foreach(item IN LISTS SRCS)
++        message(" -> ${item}")
++    endforeach(item IN LISTS SRCS)
++
++    function(target_link_${_lib_name} TARGET)
++        message("${_lib_name}")
++        target_link_libraries(${TARGET} ${_lib_name})
++    endfunction(target_link_${_lib_name} TARGET)
++
++endmacro(spark_add_library _lib_name)
++
++# spark_add_library_path <lib_name> <lib_path>
++# 构建一个库,基于指定的路径
++    # 并根据库名生成 target_link_<lib_name> 函数
++        # 函数内增加以 <lib_path> 头文件搜索路径
++macro(spark_add_library_path _lib_name _lib_path)
++
++    set(${_lib_name}_SOURCE_PATH ${_lib_path})
++    set(${_lib_name}_TYPE)
++    if(${${_lib_name}_SOURCE_PATH} STREQUAL SHARED OR ${${_lib_name}_SOURCE_PATH} STREQUAL STATIC)
++        set(${_lib_name}_SOURCE_PATH ${ARGV2})
++        set(${_lib_name}_TYPE ${_lib_path})
++        message("_lib_path: ${${_lib_name}_SOURCE_PATH}(${ARGV2})[${${_lib_name}_TYPE}]")
++
++        if(${ARGC} LESS 3)
++            message(FATAL_ERROR "Missing parameter, library path not specified.")
++        endif(${ARGC} LESS 3)
++    endif(${${_lib_name}_SOURCE_PATH} STREQUAL SHARED OR ${${_lib_name}_SOURCE_PATH} STREQUAL STATIC)
++
++    aux_source_directory(${${_lib_name}_SOURCE_PATH} ${_lib_name}_SOURCES)
++
++    message("================ spark_add_library_path: ${_lib_name} ================")
++    file(GLOB UI_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${${_lib_name}_SOURCE_PATH}/*.ui)
++    add_library(${_lib_name} ${${_lib_name}_TYPE} ${${_lib_name}_SOURCES} ${UI_LIST})
++    message("${_lib_name}_SOURCES: ${${_lib_name}_SOURCES}, ${${_lib_name}_SOURCE_PATH}")
++    foreach(item IN LISTS ${_lib_name}_SOURCES)
++        message(" -> ${item}")
++    endforeach(item IN LISTS ${_lib_name}_SOURCES)
++
++    function(target_link_${_lib_name} TARGET)
++        # message("target_link_${_lib_name}")
++        message(" -> (include): ${${_lib_name}_SOURCE_PATH}")
++        target_include_directories(${TARGET} PUBLIC "${${_lib_name}_SOURCE_PATH}")
++        target_link_libraries(${TARGET} ${_lib_name})
++    endfunction(target_link_${_lib_name} TARGET)
++
++    function(target_include_${_lib_name} TARGET)
++        # message("target_link_${_lib_name}")
++        message(" -> (include): ${${_lib_name}_SOURCE_PATH}")
++        target_include_directories(${TARGET} PUBLIC "${${_lib_name}_SOURCE_PATH}")
++        # target_link_libraries(${TARGET} ${_lib_name})
++    endfunction(target_include_${_lib_name} TARGET)
++
++    # file(GLOB HEADER_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${${_lib_name}_SOURCE_PATH}/*.h)
++    target_include_directories(${_lib_name} PUBLIC "${${_lib_name}_SOURCE_PATH}")
++
++    # 如果想用以下操作手动实现 target_link_include_directories
++        # 请注意对 LIST 类型使用 "" 进行包围
++        # target_link_include_directories 的 PUBLIC 将会填充(追加)目标的 INCLUDE_DIRECTORIES 属性
++        # target_link_include_directories 支持 cmake 生成大表达式,更容易操作,手动将无法实现此类能力
++        # target_link_include_directories 支持相对路径和绝对路径参数
++            # 手动操作将必须使用绝对路径,这是不好的地方
++    # get_target_property(_lib_include_directories ${_lib_name} INCLUDE_DIRECTORIES)
++    # list(APPEND _lib_include_directories "${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
++    # message("----> ${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
++    # message("----> ${_lib_include_directories}")
++    # set_target_properties(${_lib_name} PROPERTIES
++    #     INCLUDE_DIRECTORIES "${_lib_include_directories}"
++        # INTERFACE_INCLUDE_DIRECTORIES "${_lib_include_directories}"
++    # )
++
++endmacro(spark_add_library_path _lib_name _lib_path)
++
++# spark_add_executable <exec_name> [files]...
++# 构建一个可执行文件,基于指定的源文件
++    # Qt编译时源文件包括很多类型,需要指定 *.h/*.cpp/*.qrc/*.qm/... 等
++macro(spark_add_executable _exec_name)
++
++    message("================ ${_exec_name} Executable ================")
++    add_executable(${_exec_name} ${ARGN})
++
++endmacro(spark_add_executable _exec_name)
++
++macro(spark_add_executable_path _exec_name _exec_path)
++    aux_source_directory(${_exec_path} ${_exec_name}_SOURCES)
++
++    message("================ ${_exec_name} Executable ================")
++    file(GLOB UI_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${_exec_path}/*.ui)
++    add_executable(${_exec_name} ${${_exec_name}_SOURCES} ${ARGN} ${UI_LIST})
++    foreach(item IN LISTS ${_exec_name}_SOURCES)
++        message(" -> ${item}")
++    endforeach(item IN LISTS ${_exec_name}_SOURCES)
++
++    # function(target_link_${_exec_name} TARGET)
++    #     message("target_link_${_lib_name}")
++    message(" -> (include): ${_exec_path}")
++    target_include_directories(${_exec_name} PUBLIC "${_exec_path}")
++        # target_link_libraries(${TARGET} ${_lib_name})
++    # endfunction(target_link_${_exec_name} TARGET)
++    # target_link_${_exec_name}(${_exec_name})
++
++endmacro(spark_add_executable_path _exec_name _exec_path)
++
++# spark_find_library
++# 搜索一个库,基于指定的库名,调用 pkg-config 搜索库
++    # 并根据库名生成一个 target_link_<prefix> 函数
++macro(spark_find_library _prefix)
++    find_package(PkgConfig REQUIRED)
++
++    # libnotify
++    pkg_check_modules(${_prefix} ${ARGN})
++    function(target_link_${_prefix} TARGET)
++        target_include_directories(${TARGET} PUBLIC
++            ${${_prefix}_INCLUDE_DIRS})
++        target_link_libraries(${TARGET}
++            ${${_prefix}_LIBRARIES})
++    endfunction(target_link_${_prefix} TARGET)
++
++endmacro(spark_find_library _prefix)
++
++
++# spark_add_executable_paths
++# 自定义构建宏,基于指定的前缀名称,处理后续参数为子目录
++    # item: 为进行遍历后的单项,类似于 python3 中的 (for item in items:)
++    # file: 为在目录中不以递归(GLOB_RECURSE)方式寻找 qrc 文件,需要将其参与编译才能被 rcc
++    # 并根据 prefix-<item> 生成构建目标,
++macro(spark_add_executable_paths _prefix_path)
++    set(PATHS ${ARGN})
++    foreach(item IN LISTS PATHS)
++        file(GLOB QRCS "${item}/*.qrc")
++        message(">>> add_executable: " "${_prefix_path}-${item} ${item} + ${QRCS}")
++        spark_add_executable_path(${_prefix_path}-${item} ${item} ${QRCS})
++        target_link_qt5(${_prefix_path}-${item})
++    endforeach(item IN LISTS PATHS)
++endmacro(spark_add_executable_paths _prefix_path)
++
++# spark_add_link
++# 自定义宏以代替当前使用 fucntion 定义 target_link_<name> 结构
++    # _IN_NAME: 此宏生成 target_link_<name> 的要求参数
++    # ARGN: 此宏剩余的参数列表
++        # 在使用 target_link_<name> 时
++        # _NAME: 用于此 fucntion 中的要求参数: <_NAME>目标将要连接此库
++macro(spark_add_link _IN_NAME)
++    function(target_link_${_IN_NAME} _NAME)
++        message("LINK ${_NAME} ${ARGN}")
++        target_link_libraries(${_NAME}
++            ${ARGN})
++    endfunction(target_link_${_IN_NAME} _NAME)
++endmacro(spark_add_link _IN_NAME)
+diff --git a/cmake/SparkMacrosExtendConfig.cmake b/cmake/SparkMacrosExtendConfig.cmake
+new file mode 100644
+index 0000000..bd15f0d
+--- /dev/null
++++ b/cmake/SparkMacrosExtendConfig.cmake
+@@ -0,0 +1,237 @@
++
++# find_plus
++# 寻找 INVAl 传入的字符串,如果存在 + 字符将写入位置到 OUTVAL
++function(find_plus INVAL OUTVAL)
++    string(FIND "${INVAL}" "+" plus_index)
++    set(${OUTVAL} ${plus_index} PARENT_SCOPE)
++    # if(plus_index LESS 0)
++    #     set(${OUTVAL} -1 PARENT_SCOPE)
++    # else()
++    #     set(${OUTVAL} ${plus_index} PARENT_SCOPE)
++    # endif(plus_index LESS 0)
++endfunction(find_plus INVAL OUTVAL)
++
++# find_plus("FF" FFFF)
++# message("--> FFFF ${FFFF}")  # --> FFFF -1
++# find_plus("F+F" FFFF)
++# message("--> FFFF ${FFFF}")  # --> FFFF 1
++# find_plus("+F+F" FFFF)
++# message("--> FFFF ${FFFF}")  # --> FFFF 0
++
++# set(FFF)
++# list(APPEND FFFF )
++# list(APPEND FFFF "F")
++# list(APPEND FFFF "FA")
++# message("--> FFFF: ${FFFF}")  # --> FFFF: F;FA
++
++# set(FFFFS "")
++# list(APPEND FFFFS ${FFFF})
++# message("--> FFFFS: ${FFFFS}")  # --> FFFFS: F;FA
++
++# set(FFFF "+AA+BB+CC+DD")
++# string(REPLACE "+" ";" FFFFL "${FFFF}")
++# list(LENGTH FFFFL FFFFLEN)
++# message("--> FFFFL: ${FFFFL} --> ${FFFFLEN}") # --> FFFFL: F;
++
++# plus_list
++# 将传入的 "+AAA+BBB+CCC" 类型数据变成一个 列表(list)
++# 适用于不使用 string 进行替换 + 为 ";" 的情况下使用直接变成 list
++function(plus_list INVAL OUTVAL OUTVALLEN)
++    # set(${OUTVAL} "..." PARENT_SCOPE)
++    # set(${OUTVALLEN} 0 PARENT_SCOPE)
++
++    set(_tmps "")       # 设置为空的
++
++    # 寻找下一个 + 位置
++    find_plus(${INVAL} RIGHT_PLUS)
++
++    string(LENGTH "${INVAL}" INVALLEN)
++    message("--> 传入的 INVAL: --> 内容: ${INVAL}")
++    message("--> 传入的 INVAL: --> 长度: ${INVALLEN}")
++    message("--> 传入的 INVAL: --> +位置: ${RIGHT_PLUS}")
++
++    # 判断是否有右侧 + 号
++    if(RIGHT_PLUS LESS 0)
++        message("--> 传入的 INVAL: --> 无需计算新的+位置")
++        # message("--> 计算新的 + 位置: ${_PLUSINDEX}")
++        list(APPEND _tmps ${INVAL})
++    else()
++        math(EXPR _PLUSINDEX "${RIGHT_PLUS}+1")
++        message("--> 传入的 INVAL: --> 需计算+位置 --> 右移: ${_PLUSINDEX}")
++
++        string(SUBSTRING "${INVAL}" ${_PLUSINDEX} ${INVALLEN} NewVal)
++        message("--> 传入的 INVAL: --> 需计算+位置 --> 右移: ${_PLUSINDEX} -> 内容: ${NewVal}")
++        # string(REPLACE "+" ";" _tmps "${NewVal}")
++        # list(LENGTH FFFFL FFFFLEN)
++
++        # message("--> 计算新的 + 位置: ${_PLUSINDEX} --> 后面的 NewVal: ${NewVal}")
++
++        # find_plus(${NewVal} _NextPlus)
++        # if(_NextPlus LESS 0)
++            # list(APPEND _tmps ${NewVal})
++            # message("--> 追加新的 + 位置: ${_PLUSINDEX} --> 后面的")
++        # else()
++        #     message("--> 追加新的 + 位置: ${_PLUSINDEX} --> 后面的")
++        #     # 重新
++        #     # plus_list(${NewVal} NewValS )
++        #     # foreach(item)
++        #         # list(APPEND _tmps ${item})
++        #     # endforeach(item)
++        # endif(_NextPlus LESS 0)
++    endif(RIGHT_PLUS LESS 0)
++
++    set(${OUTVAL} ${_tmps} PARENT_SCOPE)
++    list(LENGTH _tmps _tmps_len)
++    set(${OUTVALLEN} ${_tmps_len} PARENT_SCOPE)
++
++endfunction(plus_list INVAL OUTVAL OUTVALLEN)
++
++# plus_list("+AAA+BBB+CCC+DDD" FFF FFLEN)
++# message("--------> ${FFF}: -> ${FFLEN}")
++
++# spark_add_library_realpaths
++# 基于传入的项进行构建
++# 可接受的值为: 路径列表
++# 可接受的值为: 路径列表+依赖库A+依赖库B
++macro(spark_add_library_realpaths)
++    message("---> 基于传入的项进行构建 <---")
++    # message("--> src/unclassified/ItemDelegates/NdStyledItemDelegate")
++    # string(FIND <string> <substring> <output_variable> [REVERSE])
++    # string(SUBSTRING <string> <begin> <length> <output_variable>)
++    # math(EXPR value "100 * 0xA" OUTPUT_FORMAT DECIMAL)      # value is set to "1000"
++
++    set(REALPATHS ${ARGN})
++    foreach(REALPATH IN LISTS REALPATHS)
++        message("---> 传入路径: ${REALPATH} <--- ")
++        string(LENGTH "${REALPATH}" REALPATH_LENGTH)
++        message("---> 计算传入路径长度: --> 长度: ${REALPATH_LENGTH}")
++
++        string(FIND "${REALPATH}" "/" LASTINDEX REVERSE)
++        message("---> 计算传入路径末尾/位置: --> 长度: ${LASTINDEX}")
++        math(EXPR LASTINDEX "${LASTINDEX}+1")
++        message("---> 计算传入路径末尾/右移: --> 长度: ${LASTINDEX}")
++        string(SUBSTRING "${REALPATH}" ${LASTINDEX} ${REALPATH_LENGTH} REALNAME_Dependency)
++
++        # 找 + 号下标,这是找+号的函数
++        find_plus(${REALPATH} RIGHT_PLUS)
++
++        # 判断是否有找到 + 号下标,值为 -1 或 正整数
++        if(RIGHT_PLUS LESS 0) # 小于0: 不存在 + 号
++            set(REALNAME "${REALNAME_Dependency}")
++            message("---> 传入路径末尾/右移部分: --> ${REALNAME} <-- 无依赖+")
++
++            message("---> 构建 ${REALNAME} -> ${REALNAME} ${REALPATH} ")
++
++            spark_add_library_path(${REALNAME} ${REALPATH})
++
++            if(SPARK_FIND_QT5)
++                target_link_qt5(${REALNAME})
++            endif(SPARK_FIND_QT5)
++
++            if(SPARK_FIND_QT6)
++                target_link_qt6(${REALNAME})
++            endif(SPARK_FIND_QT6)
++
++        else()
++            message("---> 传入路径末尾/右移部分: --> ${REALNAME_Dependency} <-- 依赖+")
++
++            # 存在+号,将截取从 / 到 + 号之间的内容作为目标名称
++            # 例如 src/unclassified/widgets/DocTypeListView+JsonDeploy
++            #                             ^(LASTINDEX)    ^(RIGHT_PLUS)
++            # 将 RIGHT_PLUS - LASTINDEX 计算出 DocTypeListView 字符长度
++            math(EXPR REALNAME_LENGTH "${RIGHT_PLUS}-${LASTINDEX}")
++
++            message("---> 计算传入路径末尾/右移部分: --> 位置: ${RIGHT_PLUS}")
++            # message("---> 计算传入路径末尾/右移部分: --> 长度: ${REALNAME_Dependency}")
++
++            # 目标名称为 DocTypeListView
++            # 依赖为    JsonDeploy
++            # set(REALNAME "")
++            string(SUBSTRING "${REALPATH}" 0 ${RIGHT_PLUS} _REALPATH_DIR)
++            string(SUBSTRING "${REALPATH}" ${LASTINDEX} ${REALNAME_LENGTH} REALNAME)
++
++            message("---> 计算传入路径末尾/右移部分: --> 库名: ${REALNAME}")
++
++            string(SUBSTRING "${REALPATH}" ${RIGHT_PLUS} ${REALPATH_LENGTH} Dependency)
++            message("---> 计算传入路径末尾/右移部分: --> 库名: ${REALNAME} --> +部分: ${Dependency}")
++
++            # plus_list(${Dependency} dependencies dependencies_len)
++            string(REPLACE "+" ";" dependencies "${Dependency}")
++            message("---> 计算传入路径末尾/右移部分: --> 库名: ${REALNAME} --> +部分: ${Dependency} --> 列表: ${dependencies} <-- ")
++
++
++            message("---> 构建 ${REALNAME} -> ${REALNAME} ${_REALPATH_DIR}")
++
++            spark_add_library_path(${REALNAME} ${_REALPATH_DIR})
++            # target_link_qt5(${REALNAME}) # 使用依赖的依赖或许也不错
++
++            target_include_directories(${REALNAME} PUBLIC ${_REALPATH_DIR})
++            target_link_libraries(${REALNAME} ${dependencies})
++
++        endif(RIGHT_PLUS LESS 0)
++    endforeach(REALPATH IN LISTS REALPATHS)
++
++endmacro(spark_add_library_realpaths)
++
++
++# spark_aux_source_paths
++# 将指定路径中的文件变成可用的AUX源文件列表
++macro(spark_aux_source_paths AUX_VAR)
++    set(${AUX_VAR} "")
++    set(${AUX_VAR}_PATHS ${ARGN})
++
++    foreach(aux_path IN LISTS ${AUX_VAR}_PATHS)
++        # message("aux_path: ${aux_path}")
++        aux_source_directory(${aux_path} ${AUX_VAR})
++    endforeach(aux_path IN LISTS ${AUX_VAR}_PATHS)
++
++endmacro(spark_aux_source_paths AUX_VAR)
++
++# spark_file_glob
++#
++macro(spark_file_glob FGLOB_VAR)
++    set(${FGLOB_VAR} "")
++    set(${FGLOB_VAR}_PATHS ${ARGN})
++
++    foreach(fglob_path IN LISTS ${FGLOB_VAR}_PATHS)
++
++        file(GLOB FGLOB_PATH_SRCS ${fglob_path})
++        foreach(fglob_path_src IN LISTS FGLOB_PATH_SRCS)
++            # message(" -> ${item}")
++            list(APPEND ${FGLOB_VAR} ${fglob_path_src})
++        endforeach(fglob_path_src IN LISTS FGLOB_PATH_SRCS)
++
++    endforeach(fglob_path IN LISTS ${FGLOB_VAR}_PATHS)
++
++endmacro(spark_file_glob FGLOB_VAR)
++
++
++# spark_add_source_paths
++# 将指定路径中的文件变成可用的源文件列表
++#
++macro(spark_add_source_paths SOURCE_VAR)
++    set(${SOURCE_VAR} "")
++    set(${SOURCE_VAR}_PATHS ${ARGN})
++
++    spark_aux_source_paths(${SOURCE_VAR} ${ARGN})
++    foreach(source_path IN LISTS ${SOURCE_VAR}_PATHS)
++        # list(APPEND ${SOURCE_VAR}_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_PATH})
++        # aux_source_directory(${SOURCE_PATH} _SOURCES)
++        # foreach(item IN LISTS _SOURCES)
++        #     # message(" -> ${item}")
++        #     list(APPEND ${SOURCE_VAR} ${item})
++        # endforeach(item IN LISTS _SOURCES)
++
++        # file(GLOB HEADER_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${SOURCE_PATH}/*.h)
++        # foreach(item IN LISTS HEADER_LIST)
++        #     # message(" -> ${item}")
++        #     list(APPEND ${SOURCE_VAR} ${item})
++        # endforeach(item IN LISTS HEADER_LIST)
++
++        file(GLOB UI_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${source_path}/*.ui)
++        foreach(ui_src IN LISTS UI_SRCS)
++            # message(" -> ${item}")
++            list(APPEND ${SOURCE_VAR} ${ui_src})
++        endforeach(ui_src IN LISTS UI_SRCS)
++    endforeach(source_path IN LISTS ${SOURCE_VAR}_PATHS)
++endmacro(spark_add_source_paths SOURCE_VAR)
+-- 
+2.20.1
+
+
+From ba6310f45bd803ed6ac60b9851cecc14445cc942 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Sun, 5 Feb 2023 13:00:22 +0800
+Subject: [PATCH 08/13] =?UTF-8?q?repo:=20=E5=B0=86=E7=8E=B0=E6=9C=89?=
+ =?UTF-8?q?=E6=9E=84=E5=BB=BA=E8=BD=AC=E4=B8=BA=20spark=20=E5=8C=96?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt | 120 +++++++++++++++++++++++++++----------------------
+ 1 file changed, 66 insertions(+), 54 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 60e9171..d990b1d 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1,60 +1,72 @@
+ cmake_minimum_required(VERSION 3.22)
++
+ project(notepad-- VERSION 1.22.0)
+ 
+-set(CMAKE_AUTOMOC ON)
+-set(CMAKE_AUTOUIC ON)
+-set(CMAKE_AUTORCC ON)
+-
+-find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Concurrent Network PrintSupport XmlPatterns)
+-
+-# TODO: use system provided libraries to build 
+-# current status: some header can not be found,for example: Scintilla.h
+-find_library(QSCINTILLA_LIB_PATH qscintilla2_qt5)
+-find_path(QSCINTILLA_INC_PATH qsciscintilla.h PATHS /usr/include/)
+-find_path(SCINTILLA_INC_PATH Scintilla.h PATHS /usr/include/)
+-if((${QSCINTILLA_LIB_PATH} STREQUAL "QSCINTILLA_LIB_PATH-NOTFOUND") OR 
+-   (${QSCINTILLA_INC_PATH} STREQUAL "QSCINTILLA_INC_PATH-NOTFOUND") OR 
+-   (${SCINTILLA_INC_PATH}  STREQUAL "SCINTILLA_INC_PATH-NOTFOUND") )
+-set(NOTEPAD_USE_SYS_LIB OFF)
+-message("system libraries or header not found,build from local")
+-add_subdirectory(${PROJECT_SOURCE_DIR}/src/qscint)
+-else()
+-set(NOTEPAD_USE_SYS_LIB ON)
+-message("use system libraries")
+-message("QSCINTILLA_LIB_PATH:" ${QSCINTILLA_LIB_PATH})
+-message("QSCINTILLA_INC_PATH:" ${QSCINTILLA_INC_PATH})
+-message("SCINTILLA_INC_PATH:" ${SCINTILLA_INC_PATH})
+-endif()
+-
+-file(GLOB UI_SRC ${PROJECT_SOURCE_DIR}/src/*.ui)
+-set(UI_SRC ${UI_SRC} ${PROJECT_SOURCE_DIR}/src/cceditor/ccnotepad.ui)
+-aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
+-aux_source_directory(${PROJECT_SOURCE_DIR}/src/cceditor SRC)
+-
+-add_executable(${PROJECT_NAME} ${SRC} ${UI_SRC} ${PROJECT_SOURCE_DIR}/src/RealCompare.qrc)
+-target_include_directories(${PROJECT_NAME} PRIVATE 
+-${PROJECT_SOURCE_DIR}/src
+-${PROJECT_SOURCE_DIR}/src/cceditor
+-)
+-
+-if(NOTEPAD_USE_SYS_LIB)
+-target_include_directories(${PROJECT_NAME} PRIVATE ${QSCINTILLA_INC_PATH} ${SCINTILLA_INC_PATH})
+-endif()
+-
+-target_link_libraries(${PROJECT_NAME} qscintilla2_qt5 Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent Qt5::Network  Qt5::PrintSupport Qt5::XmlPatterns)
+-
+-install(
+-    TARGETS ${PROJECT_NAME}
+-    DESTINATION "bin"
+-)
+-
+-install(DIRECTORY  ${PROJECT_SOURCE_DIR}/src/linux/usr
+-        DESTINATION "/")
+-
+-include(${PROJECT_SOURCE_DIR}/cmake/package_config.cmake) 
+-include(CPack)
+-
+-target_link_libraries(${PROJECT_NAME} qscint Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent Qt5::Network  Qt5::PrintSupport Qt5::XmlPatterns)
++include(cmake/SparkEnvConfig.cmake)
++include(cmake/SparkMacrosConfig.cmake)
++include(cmake/SparkFindQt5Config.cmake)
++# include(cmake/SparkFindQt6Config.cmake)
++include(cmake/SparkMacrosExtendConfig.cmake)
++
++# ----------------- Build QScint ----------------- #
++if(TRUE)
++    # add_subdirectory(${PROJECT_SOURCE_DIR}/src/qscint)
++    # file(GLOB MOC_HEADER src/qscint/src/Qsci/*.h)
++    spark_file_glob(MOC_HEADER "src/qscint/src/Qsci/*.h")
++
++    spark_add_source_paths(QSciSources
++        src/qscint/src
++        src/qscint/scintilla/lexers
++        src/qscint/scintilla/lexlib
++        src/qscint/scintilla/src
++        src/qscint/scintilla/boostregex
++
++        # src/qscint/src/Qsci
++        # FAIL: only *.ui will spark_file_glob(MOC_HEADER ...)
++    )
++    spark_add_library(QSci STATIC ${QSciSources} ${MOC_HEADER})
++    target_compile_definitions(QSci PRIVATE SCINTILLA_QT SCI_LEXER INCLUDE_DEPRECATED_FEATURES)
++    target_include_directories(QSci PRIVATE
++        src/qscint/scintilla/boostregex
++        src/qscint/scintilla/lexlib)
++    target_include_directories(QSci PUBLIC
++        src/qscint/src
++        src/qscint/src/Qsci
++        src/qscint/scintilla/src
++        src/qscint/scintilla/include)
++    target_link_qt5(QSci)
++    target_link_qt5_PrintSupport(QSci)
++    target_link_qt5_Concurrent(QSci)
++endif(TRUE)
++
++
++# ----------------- Build CCEditor ----------------- #
++if(TRUE)
++
++    # 准备构建 CCEditor
++    set(QRC_SOURCES src/RealCompare.qrc)
++    spark_aux_source_paths(CCEditorSources
++        src
++        src/cceditor
++    )
++    spark_add_executable(${PROJECT_NAME} ${CCEditorSources} ${QRC_SOURCES})
++    target_include_directories(${PROJECT_NAME} PRIVATE
++        ${PROJECT_SOURCE_DIR}/src
++        ${PROJECT_SOURCE_DIR}/src/cceditor
++
++        ${PROJECT_SOURCE_DIR}/src/qscint/src
++        ${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
++        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
++        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
++        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
++        ${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
++    )
++    # target_link_libraries(${PROJECT_NAME} QSci)
++    target_link_QSci(${PROJECT_NAME})
++    target_link_qt5_XmlPatterns(${PROJECT_NAME})
++
++endif(TRUE)
++
+ 
+ if(CMAKE_HOST_UNIX)
+     include(cmake/SparkInstallMacrosConfig.cmake)
+-- 
+2.20.1
+
+
+From 28e63cf37d6e4b41b4a0720ee7a321d484487eb5 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Sun, 5 Feb 2023 16:58:53 +0800
+Subject: [PATCH 09/13] =?UTF-8?q?repo:=20=E9=A2=84=E7=95=99=E9=85=8D?=
+ =?UTF-8?q?=E7=BD=AE=E4=B8=BA=E6=8F=92=E4=BB=B6=E7=9B=B8=E5=85=B3=E6=94=AF?=
+ =?UTF-8?q?=E6=8C=81=E9=83=A8=E5=88=86?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index d990b1d..c18417f 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -67,6 +67,16 @@ if(TRUE)
+ 
+ endif(TRUE)
+ 
++# ----------------- CCEditor Plugin Support or Other  ----------------- #
++if(TRUE)
++    
++    # 开启插件支持
++    # target_compile_definitions(${PROJECT_NAME} PUBLIC NO_PLUGIN=0)
++
++    # 其它有关插件的部分处理...
++
++endif(TRUE)
++
+ 
+ if(CMAKE_HOST_UNIX)
+     include(cmake/SparkInstallMacrosConfig.cmake)
+-- 
+2.20.1
+
+
+From 481a7f7b39fe4b67bec6a3cab24e59a4e06b39f0 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Mon, 6 Feb 2023 01:10:42 +0800
+Subject: [PATCH 10/13] =?UTF-8?q?linux/plugin-support:=20=E6=B7=BB?=
+ =?UTF-8?q?=E5=8A=A0=20Notepad--=20=E6=8F=92=E4=BB=B6=E6=9E=84=E5=BB=BA?=
+ =?UTF-8?q?=E6=A8=A1=E5=9D=97=E6=94=AF=E6=8C=81?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt                       | 71 +++++++++++++++++++-
+ cmake/NotepadPluginConfig.cmake.in   | 96 ++++++++++++++++++++++++++++
+ cmake/SparkInstallMacrosConfig.cmake |  3 +-
+ 3 files changed, 167 insertions(+), 3 deletions(-)
+ create mode 100644 cmake/NotepadPluginConfig.cmake.in
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index c18417f..28b3007 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -71,13 +71,14 @@ endif(TRUE)
+ if(TRUE)
+     
+     # 开启插件支持
+-    # target_compile_definitions(${PROJECT_NAME} PUBLIC NO_PLUGIN=0)
++    target_compile_definitions(${PROJECT_NAME} PUBLIC NO_PLUGIN=0)
+ 
+     # 其它有关插件的部分处理...
+ 
+ endif(TRUE)
+ 
+-
++# 可能需要变更为 CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" ??
++# 并使用 Linux.cmake 维护?
+ if(CMAKE_HOST_UNIX)
+     include(cmake/SparkInstallMacrosConfig.cmake)
+     include(cmake/SparkDesktopMacros.cmake)
+@@ -103,6 +104,72 @@ if(CMAKE_HOST_UNIX)
+     spark_install_file(/usr/share/notepad--/icons/ assets/spark.png)
+     spark_install_target(/usr/bin/ ${PROJECT_NAME})
+ 
++    # TODO:如果主线已经将 linux/destkop 的PR合入,即可移除此部分以上部分,而使用以下部分
++    # spark_install_directory(/usr   src/linux/usr/*)    # 完整的 Linux 资源文件
++
++    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
++    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
++    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
++    include(CMakePackageConfigHelpers)
++    include(GNUInstallDirs)
++    
++    # 定义插件配置安装位置
++    set(CMAKE_INSTALL_PREFIX "/usr")
++    set(NOTEPAD_PLUGIN NotepadPlugin)
++    
++    # 定义开发插件时的配置目录与 CMake 模块文件名称
++    set(NOTEPAD_PLUGIN_CONFIG       ${NOTEPAD_PLUGIN}Config.cmake)
++    set(NOTEPAD_PLUGIN_INCLUDEDIR   ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/${NOTEPAD_PLUGIN})
++    set(NOTEPAD_PLUGIN_LIBDIR       ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${NOTEPAD_PLUGIN})
++    
++    # 定义一些扩展内容,主要是提供给 CMake 模块文件填充
++    set(NOTEPAD_PLUGIN_CORELIB QSci)
++    set(NOTEPAD_PLUGIN_EXTERNAL_INCLUDES 
++        ${NOTEPAD_PLUGIN_INCLUDEDIR}/Qsci)
++
++    # 定义在插件开发的 CMake 模块中,Notepad-- 是否是基于 QT5 实现
++        # 并自动为插件开发层自动开启相关 Qt 依赖组件
++        # 此部分逻辑将自动提供给 add_notepad_plugin 自行处理
++    set(NOTEPAD_BUILD_BY_QT5 TRUE)
++    set(NOTEPAD_BUILD_BY_QT6 FALSE)
++
++    # 定义在插件开发的 CMake 模块中,Notepad-- 是否将提供 "插件安装目录(位置)"
++    set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY "")
++
++    # 将 NOTEPAD_PLUGIN_INCLUDEDIR NOTEPAD_PLUGIN_LIBDIR 填充到 cmake 文件
++    configure_package_config_file(cmake/NotepadPluginConfig.cmake.in
++        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG}
++        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN})
++    # 安装 cmake 文件
++    spark_install_file(${CMAKE_INSTALL_LIBDIR}/cmake/${NOTEPAD_PLUGIN} 
++        ${CMAKE_BINARY_DIR}/${NOTEPAD_PLUGIN_CONFIG})
++    # 安装头插件接口文件
++    spark_install_file(${NOTEPAD_PLUGIN_INCLUDEDIR} 
++        src/include/pluginGl.h)
++    # 安装插件所需要的Qsci文件
++    spark_install_directory(${NOTEPAD_PLUGIN_INCLUDEDIR} 
++        src/qscint/src/Qsci)
++    
++    # 导出 QSci 的头文件(从插件实现层面来看,目前是使用*.h 与 pluginGl.h
++        # 但从 Qsci 层面来看,*.h 使用的是 #include <Qsci/*.h> ,所以此部分不被使用)
++    # spark_file_glob(QSci_HEADERS src/qscint/src/Qsci/*.h src/include/pluginGl.h)
++    # set_target_properties(QSci PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
++
++    # 导出 Notepad-- 的接口文件(从逻辑层面来看,目前已经在前面安装了接口文件,所以此部分不被使用)
++    # spark_file_glob(Notepad_HEADERS src/include/pluginGl.h)
++    # set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${QSci_HEADERS}")
++
++    # 安装项目文件与 QSci 文件
++    install(TARGETS ${PROJECT_NAME} QSci
++        RUNTIME DESTINATION bin
++        LIBRARY DESTINATION ${NOTEPAD_PLUGIN_LIBDIR}
++        ARCHIVE DESTINATION ${NOTEPAD_PLUGIN_LIBDIR}
++        PUBLIC_HEADER DESTINATION ${NOTEPAD_PLUGIN_INCLUDEDIR}
++    )
++    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
++    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
++    # ------------------ INSTALL PLUGIN CONFIG ------------------ #
++
+ 
+     # 1. 在顶层构建中导入 Appimage 的构建
+     include(cmake/SparkAppimageConfig.cmake)  # 导入来自 Spark 构建的 Appimage 构建
+diff --git a/cmake/NotepadPluginConfig.cmake.in b/cmake/NotepadPluginConfig.cmake.in
+new file mode 100644
+index 0000000..58e0bd7
+--- /dev/null
++++ b/cmake/NotepadPluginConfig.cmake.in
+@@ -0,0 +1,96 @@
++# NotepadPluginConfig.cmake
++# 用于 Notepad-- 插件实现的 CMake 模块初级定义
++
++# 在 Linux 中,它的布局应该如下:
++# /usr/lib/x86_64-linux-gnu/cmake/NotepadPlugin/NotepadPluginConfig.cmake
++
++# 在 插件开发层中,它的使用如下:
++    # 1. 查找 NotepadPlugin 模块
++        # find_package(NotepadPlugin)
++    # 2. 使用 add_notepad_plugin(<模块名称> <源代码、资源文件> [...])
++        # add_notepad_plugin(<plugin_name> <plugin_srcs> ...)
++
++# 一些无关紧要的部分,如果需要实现插件安装操作时,即可进行使用
++# include(CMakePackageConfigHelpers)
++# include(GNUInstallDirs)
++
++# 
++set(NOTEPAD_PLUGIN              @NOTEPAD_PLUGIN@)
++set(NOTEPAD_PLUGIN_INCLUDEDIR   @NOTEPAD_PLUGIN_INCLUDEDIR@)
++set(NOTEPAD_PLUGIN_LIBDIR       @NOTEPAD_PLUGIN_LIBDIR@)
++set(NOTEPAD_PLUGIN_CORELIB      @NOTEPAD_PLUGIN_CORELIB@)
++
++# 一些扩展内容,主要是 CMake 模块文件的填充
++set(NOTEPAD_PLUGIN_EXTERNAL_INCLUDES
++        @NOTEPAD_PLUGIN_EXTERNAL_INCLUDES@)
++
++# 由插件开发者进行参考的 "Notepad 提供的插件安装目录(位置)" 
++set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY @NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_DIRECTORY@)
++
++set(NOTEPAD_BUILD_BY_QT5          @NOTEPAD_BUILD_BY_QT5@)
++set(NOTEPAD_BUILD_BY_QT6          @NOTEPAD_BUILD_BY_QT6@)
++
++if(NOTEPAD_PLUGIN_BY_QT5)
++    set(CMAKE_AUTOMOC ON)
++    set(CMAKE_AUTOUIC ON)
++    find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
++endif(NOTEPAD_PLUGIN_BY_QT5)
++
++if(NOTEPAD_BUILD_BY_QT6)
++    set(CMAKE_AUTOMOC ON)
++    set(CMAKE_AUTOUIC ON)
++    find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
++endif(NOTEPAD_BUILD_BY_QT6)
++
++
++
++add_library(${NOTEPAD_PLUGIN} SHARED IMPORTED)
++set_target_properties(${${NOTEPAD_PLUGIN}} PROPERTIES 
++    IMPORTED_LOCATION 
++        ${NOTEPAD_PLUGIN_LIBDIR}/lib${NOTEPAD_PLUGIN_CORELIB}.so
++    
++    INCLUDE_DIRECTORIES 
++        "${NOTEPAD_PLUGIN_INCLUDEDIR};${NOTEPAD_PLUGIN_EXTERNAL_INCLUDES}"
++)
++
++# add_notepad_plugin(<PLUGIN_VAR> <PLUGIN_SRC> [...])
++# 
++macro(add_notepad_plugin PLUGIN_VAR PLUGIN_SRC)
++    # aux_source_directory(${PLUGIN_VAR}_SOURCES  ${ARGN})
++    add_library(${PLUGIN_VAR} SHARED ${PLUGIN_SRC} ${ARGN})
++    if(CMAKE_HOST_WIN32)
++        # Win32 已提供宏判断
++        # target_compile_definitions(${PLUGIN_VAR} PUBLIC NDD_EXPORT=export)
++    endif(CMAKE_HOST_WIN32)
++
++    if(CMAKE_HOST_UNIX)
++        target_compile_definitions(${PLUGIN_VAR} PUBLIC NDD_EXPORT=export)
++    endif(CMAKE_HOST_UNIX)
++    target_include_directories(${PLUGIN_VAR} PUBLIC ${NOTEPAD_PLUGIN_INCLUDEDIR} ${NOTEPAD_PLUGIN_EXTERNAL_INCLUDES})
++    target_link_directories(${PLUGIN_VAR} PUBLIC ${NOTEPAD_PLUGIN_LIBDIR})
++    target_link_libraries(${PLUGIN_VAR} ${NOTEPAD_PLUGIN_CORELIB})
++    if(NOTEPAD_PLUGIN_QT5)
++        target_link_libraries(${PLUGIN_VAR} Qt5::Core Qt5::Widgets)
++    endif(NOTEPAD_PLUGIN_QT5)
++
++    if(NOTEPAD_PLUGIN_QT5)
++        target_link_libraries(${PLUGIN_VAR} Qt6::Core Qt6::Widgets)
++    endif(NOTEPAD_PLUGIN_QT5)
++    
++endmacro(add_notepad_plugin PLUGIN_VAR PLUGIN_SRC)
++
++# support git plugin
++macro(add_notepad_plugin_with_git PLUGIN_VAR GIT_REPO_URL GIT_REPO_PLUGIN_PATH)
++    execute_process(COMMAND git clone ${GIT_REPO_URL} ${PLUGIN_VAR}_git
++        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
++        ERROR_QUIET)
++    aux_source_directory(${CMAKE_BINARY_DIR}/$${PLUGIN_VAR}_git/${GIT_REPO_PLUGIN_PATH} ${PLUGIN_VAR}_RESOURCES)
++    add_notepad_plugin(${PLUGIN_VAR} ${${PLUGIN_VAR}_RESOURCES})
++endmacro(add_notepad_plugin_with_git PLUGIN_VAR GIT_REPO_URL GIT_REPO_PLUGIN_PATH)
++
++message("- >>>>>>>>>>>>>>>>>> NotepadPlugin: <<<<<<<<<<<<<<<<<<")
++message("  - ${CMAKE_CURRENT_LIST_FILE}")
++message("  - ${NOTEPAD_PLUGIN_INCLUDEDIR}")
++message("  - ${NOTEPAD_PLUGIN_LIBDIR}")
++message("  - ${NOTEPAD_PLUGIN_CORELIB}")
++message("- >>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<")
+\ No newline at end of file
+diff --git a/cmake/SparkInstallMacrosConfig.cmake b/cmake/SparkInstallMacrosConfig.cmake
+index 1f8939b..204d16a 100644
+--- a/cmake/SparkInstallMacrosConfig.cmake
++++ b/cmake/SparkInstallMacrosConfig.cmake
+@@ -79,7 +79,8 @@ macro(spark_install_directory INSTALL_DIRECTORY_DIR INSTALL_DIRECOTRY)
+         # message(FATAL_ERROR " directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST_LENGTH}")
+ 
+     else()
+-        message(FATAL_ERROR "install: ${INSTALL_DIRECTORY_DIR}")
++        # ISSUES: You Must check here
++        # message(FATAL_ERROR "install: ${INSTALL_DIRECTORY_DIR}")
+ 
+         install(DIRECTORY
+             ${INSTALL_DIRECOTRY} ${ARGN}
+-- 
+2.20.1
+
+
+From 7e215f5fe65a9962bf29588a0e566d239b734d25 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Mon, 6 Feb 2023 01:11:26 +0800
+Subject: [PATCH 11/13] =?UTF-8?q?linux/plugin-doc:=20=E6=B7=BB=E5=8A=A0=20?=
+ =?UTF-8?q?Notepad--=20=E6=8F=92=E4=BB=B6=E6=9E=84=E5=BB=BA=E6=8F=8F?=
+ =?UTF-8?q?=E8=BF=B0=E6=96=87=E6=A1=A3?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ cmake/NoteadPlugin-Linux-Development.md | 164 ++++++++++++++++++++++++
+ 1 file changed, 164 insertions(+)
+ create mode 100644 cmake/NoteadPlugin-Linux-Development.md
+
+diff --git a/cmake/NoteadPlugin-Linux-Development.md b/cmake/NoteadPlugin-Linux-Development.md
+new file mode 100644
+index 0000000..c642fc7
+--- /dev/null
++++ b/cmake/NoteadPlugin-Linux-Development.md
+@@ -0,0 +1,164 @@
++# NotepadPlugin 开发说明
++
++> 当前插件实现的提供 Linux 层开发说明
++
++- 引用 NotepadPluginConfig.cmake 中的说明
++
++    ```cmake
++    # NotepadPluginConfig.cmake
++    # 用于 Notepad-- 插件实现的 CMake 模块初级定义
++
++    # 在 Linux 中,它的布局应该如下:
++    # /usr/lib/x86_64-linux-gnu/cmake/NotepadPlugin/NotepadPluginConfig.cmake
++
++    # 在 插件开发层中,它的使用如下:
++        # 1. 查找 NotepadPlugin 模块
++            # find_package(NotepadPlugin)
++        # 2. 使用 add_notepad_plugin(<模块名称> <源代码、资源文件> [...])
++            # add_notepad_plugin(<plugin_name> <plugin_srcs> ...)
++    ```
++
++- 着手进行实现插件
++
++    > 将项目中的 src/plugin/helloworld 复制为单个项目,并使用 CMake 进行构建
++
++    ```cmake
++    cmake_minimum_required(VERSION 3.5.1)
++
++    project(template LANGUAGES CXX VERSION 0.0.1)
++
++    # 1. 查找 NotepadPlugin 模块
++    find_package(NotepadPlugin REQUIRED)
++
++    # 2. 使用 add_notepad_plugin(<模块名称> <源代码、资源文件> [...])
++    add_notepad_plugin(Helloworld
++        helloworld/helloworldexport.cpp
++        helloworld/qttestclass.cpp
++        helloworld/qttestclass.h
++        helloworld/qttestclass.ui
++    )
++
++    # 以上将会构建出一个名叫 libHelloworld.so 的插件扩展
++    ```
++
++- 一些 NotepadPluginConfig.cmake 中的变量声明
++
++    ```cmake
++
++    # NOTEPAD_PLUGIN                                   [不重要]CMake 模块名称
++    # NOTEPAD_PLUGIN_CONFIG                            [不重要]CMake 模块文件名名称
++    # NOTEPAD_PLUGIN_INCLUDEDIR                        [插件 头文件目录]插件开发者可自行使用
++    # NOTEPAD_PLUGIN_LIBDIR                            [插件 库存放目录]插件开发者可自行使用
++    # NOTEPAD_PLUGIN_CORELIB                           [插件 核心库名称]插件开发者可自行使用
++    # NOTEPAD_PLUGIN_EXTERNAL_INCLUDES                 [插件 扩展的头文件目录]插件开发者可自行使用
++    # NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY [插件 扩展插件安装目录(位置)]插件开发者可自行使用
++
++    # NOTEPAD_BUILD_BY_QT5     
++    # NOTEPAD_BUILD_BY_QT6     
++        [NOTEPAD_BUILD_BY_约定]如果在构建 Notepad-- 时开启了此项,将会向 CMake 构建系统询问相关模块
++
++    例如:
++        询问 Qt5 基本模块: 将会在 find_package(NotepadPlugin REQUIRED) 时自动加入
++            set(CMAKE_AUTOMOC ON)
++            set(CMAKE_AUTOUIC ON)
++            find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
++
++        为开发者自动添加 Qt5 模块依赖: 将会在 add_notepad_plugin 时自动加入
++            if(NOTEPAD_PLUGIN_QT5)
++                target_link_libraries(${PLUGIN_VAR} Qt5::Core Qt5::Widgets)
++            endif(NOTEPAD_PLUGIN_QT5)
++
++    ```
++
++- 当前提供插件的 Linux 目录结构
++
++    ```
++    build/_CPack_Packages/Linux/DEB/notepad---1.22.0-Linux
++    ├── control
++    ├── control.tar.gz
++    ├── data.tar.gz
++    ├── debian-binary
++    ├── md5sums
++    └── usr
++        ├── bin
++        │   └── notepad--
++        ├── include
++        │   └── NotepadPlugin
++        │       ├── pluginGl.h
++        │       └── Qsci
++        │           ├── qsciabstractapis.h
++        │           ├── qsciapis.h
++        │           ├── qscicommand.h
++        │           ├── qscicommandset.h
++        │           ├── qscidocument.h
++        │           ├── qsciglobal.h
++        │           ├── qscilexerasm.h
++        │           ├── qscilexeravs.h
++        │           ├── qscilexerbash.h
++        │           ├── qscilexerbatch.h
++        │           ├── qscilexercmake.h
++        │           ├── qscilexercoffeescript.h
++        │           ├── qscilexercpp.h
++        │           ├── qscilexercsharp.h
++        │           ├── qscilexercss.h
++        │           ├── qscilexercustom.h
++        │           ├── qscilexerd.h
++        │           ├── qscilexerdiff.h
++        │           ├── qscilexeredifact.h
++        │           ├── qscilexerfortran77.h
++        │           ├── qscilexerfortran.h
++        │           ├── qscilexerglobal.h
++        │           ├── qscilexergo.h
++        │           ├── qscilexer.h
++        │           ├── qscilexerhtml.h
++        │           ├── qscilexeridl.h
++        │           ├── qscilexerjava.h
++        │           ├── qscilexerjavascript.h
++        │           ├── qscilexerjson.h
++        │           ├── qscilexerlua.h
++        │           ├── qscilexermakefile.h
++        │           ├── qscilexermarkdown.h
++        │           ├── qscilexermatlab.h
++        │           ├── qscilexernsis.h
++        │           ├── qscilexeroctave.h
++        │           ├── qscilexerpascal.h
++        │           ├── qscilexerperl.h
++        │           ├── qscilexerpo.h
++        │           ├── qscilexerpostscript.h
++        │           ├── qscilexerpov.h
++        │           ├── qscilexerproperties.h
++        │           ├── qscilexerpython.h
++        │           ├── qscilexerruby.h
++        │           ├── qscilexerrust.h
++        │           ├── qscilexerspice.h
++        │           ├── qscilexersql.h
++        │           ├── qscilexertcl.h
++        │           ├── qscilexertex.h
++        │           ├── qscilexertext.h
++        │           ├── qscilexervb.h
++        │           ├── qscilexerverilog.h
++        │           ├── qscilexervhdl.h
++        │           ├── qscilexerxml.h
++        │           ├── qscilexeryaml.h
++        │           ├── qscimacro.h
++        │           ├── qsciprinter.h
++        │           ├── qsciscintillabase.h
++        │           ├── qsciscintilla.h
++        │           ├── qscistyledtext.h
++        │           └── qscistyle.h
++        ├── lib
++        │   ├── cmake
++        │   │   └── NotepadPlugin
++        │   │       └── NotepadPluginConfig.cmake
++        │   └── NotepadPlugin
++        │       └── libQSci.a
++        └── share
++            ├── applications
++            │   └── notepad--.desktop
++            └── notepad--
++                └── icons
++                    └── spark.png
++
++    13 directories, 71 files
++
++    ```
+\ No newline at end of file
+-- 
+2.20.1
+
+
+From 8c582a774e8cb0a3c347de5a574ecfd91f7522d2 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Mon, 6 Feb 2023 01:37:46 +0800
+Subject: [PATCH 12/13] =?UTF-8?q?fix-plugin-cmake:=20=E4=BF=AE=E5=A4=8D?=
+ =?UTF-8?q?=E6=8F=92=E4=BB=B6=20CMake=20=E9=83=A8=E5=88=86=E5=AE=9A?=
+ =?UTF-8?q?=E4=B9=89=E7=9A=84=E9=94=99=E8=AF=AF?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ cmake/NotepadPluginConfig.cmake.in | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/cmake/NotepadPluginConfig.cmake.in b/cmake/NotepadPluginConfig.cmake.in
+index 58e0bd7..37ad692 100644
+--- a/cmake/NotepadPluginConfig.cmake.in
++++ b/cmake/NotepadPluginConfig.cmake.in
+@@ -30,11 +30,11 @@ set(NOTEPAD_PLUGIN_EXTERNAL_PLUGIN_INSTALL_DIRECTORY @NOTEPAD_PLUGIN_EXTERNAL_PL
+ set(NOTEPAD_BUILD_BY_QT5          @NOTEPAD_BUILD_BY_QT5@)
+ set(NOTEPAD_BUILD_BY_QT6          @NOTEPAD_BUILD_BY_QT6@)
+ 
+-if(NOTEPAD_PLUGIN_BY_QT5)
++if(NOTEPAD_BUILD_BY_QT5)
+     set(CMAKE_AUTOMOC ON)
+     set(CMAKE_AUTOUIC ON)
+     find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
+-endif(NOTEPAD_PLUGIN_BY_QT5)
++endif(NOTEPAD_BUILD_BY_QT5)
+ 
+ if(NOTEPAD_BUILD_BY_QT6)
+     set(CMAKE_AUTOMOC ON)
+@@ -42,8 +42,6 @@ if(NOTEPAD_BUILD_BY_QT6)
+     find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
+ endif(NOTEPAD_BUILD_BY_QT6)
+ 
+-
+-
+ add_library(${NOTEPAD_PLUGIN} SHARED IMPORTED)
+ set_target_properties(${${NOTEPAD_PLUGIN}} PROPERTIES 
+     IMPORTED_LOCATION 
+@@ -69,13 +67,13 @@ macro(add_notepad_plugin PLUGIN_VAR PLUGIN_SRC)
+     target_include_directories(${PLUGIN_VAR} PUBLIC ${NOTEPAD_PLUGIN_INCLUDEDIR} ${NOTEPAD_PLUGIN_EXTERNAL_INCLUDES})
+     target_link_directories(${PLUGIN_VAR} PUBLIC ${NOTEPAD_PLUGIN_LIBDIR})
+     target_link_libraries(${PLUGIN_VAR} ${NOTEPAD_PLUGIN_CORELIB})
+-    if(NOTEPAD_PLUGIN_QT5)
++    if(NOTEPAD_BUILD_BY_QT5)
+         target_link_libraries(${PLUGIN_VAR} Qt5::Core Qt5::Widgets)
+-    endif(NOTEPAD_PLUGIN_QT5)
++    endif(NOTEPAD_BUILD_BY_QT5)
+ 
+-    if(NOTEPAD_PLUGIN_QT5)
++    if(NOTEPAD_BUILD_BY_QT6)
+         target_link_libraries(${PLUGIN_VAR} Qt6::Core Qt6::Widgets)
+-    endif(NOTEPAD_PLUGIN_QT5)
++    endif(NOTEPAD_BUILD_BY_QT6)
+     
+ endmacro(add_notepad_plugin PLUGIN_VAR PLUGIN_SRC)
+ 
+@@ -84,7 +82,7 @@ macro(add_notepad_plugin_with_git PLUGIN_VAR GIT_REPO_URL GIT_REPO_PLUGIN_PATH)
+     execute_process(COMMAND git clone ${GIT_REPO_URL} ${PLUGIN_VAR}_git
+         WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+         ERROR_QUIET)
+-    aux_source_directory(${CMAKE_BINARY_DIR}/$${PLUGIN_VAR}_git/${GIT_REPO_PLUGIN_PATH} ${PLUGIN_VAR}_RESOURCES)
++    aux_source_directory(${CMAKE_BINARY_DIR}/${PLUGIN_VAR}_git/${GIT_REPO_PLUGIN_PATH} ${PLUGIN_VAR}_RESOURCES)
+     add_notepad_plugin(${PLUGIN_VAR} ${${PLUGIN_VAR}_RESOURCES})
+ endmacro(add_notepad_plugin_with_git PLUGIN_VAR GIT_REPO_URL GIT_REPO_PLUGIN_PATH)
+ 
+-- 
+2.20.1
+
+
+From e9fed613d3f0fe2593f2d163df3d611bf3cd3c2a Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Mon, 6 Feb 2023 10:31:30 +0800
+Subject: [PATCH 13/13] =?UTF-8?q?repo:=20=E9=87=87=E7=94=A8=E9=A1=B9?=
+ =?UTF-8?q?=E7=9B=AE=E4=B8=AD=E5=AE=8C=E6=95=B4=E7=9A=84=20Linux=20?=
+ =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=96=87=E4=BB=B6=E5=AE=89=E8=A3=85?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 28b3007..b8f5fa7 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -100,12 +100,14 @@ if(CMAKE_HOST_UNIX)
+         # 应用分类: Category=
+         "Development"
+     )
+-    spark_install_file(/usr/share/applications/    ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.desktop)
+-    spark_install_file(/usr/share/notepad--/icons/ assets/spark.png)
+-    spark_install_target(/usr/bin/ ${PROJECT_NAME})
+-
+-    # TODO:如果主线已经将 linux/destkop 的PR合入,即可移除此部分以上部分,而使用以下部分
+-    # spark_install_directory(/usr   src/linux/usr/*)    # 完整的 Linux 资源文件
++    # spark_install_file(/usr/share/applications/    ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.desktop)
++    # spark_install_file(/usr/share/notepad--/icons/ assets/spark.png)
++    # spark_install_target(/usr/bin/ ${PROJECT_NAME})
++
++    # 完成:如果主线已经将 linux/destkop 的PR合入,即可移除此部分以上部分,而使用以下部分
++        # 但 spark_desktop_macros 不能移除,因为它被 Appimage 构建部分依赖
++        # Appimage 构建部分,要求(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
++    spark_install_directory(/usr   src/linux/usr/*)    # 完整的 Linux 资源文件
+ 
+     # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+     # ------------------ INSTALL PLUGIN CONFIG ------------------ #
+-- 
+2.20.1
+

+ 27 - 0
patchs/coconil-cmake-version-3.16.patch

@@ -0,0 +1,27 @@
+From 3dd815a0893c7200605ba0f3e0806e460d0b2be7 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Sun, 5 Feb 2023 13:59:44 +0800
+Subject: [PATCH] =?UTF-8?q?cmake-version:=20=E5=B0=86=E7=89=88=E6=9C=AC?=
+ =?UTF-8?q?=E9=99=8D=E5=88=B0=203.16=20=E4=BB=A5=E9=80=82=E7=94=A8?=
+ =?UTF-8?q?=E4=BA=8E=20cmake=20=E6=9E=84=E5=BB=BA?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index d990b1d..e86ba02 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1,4 +1,4 @@
+-cmake_minimum_required(VERSION 3.22)
++cmake_minimum_required(VERSION 3.16)
+ 
+ project(notepad-- VERSION 1.22.0)
+ 
+-- 
+2.20.1
+

+ 38 - 0
patchs/coconil-cmake-version-3.22.patch

@@ -0,0 +1,38 @@
+From afb95e9e995366874845f021d4fb7dd9d7d2fdd1 Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Thu, 2 Feb 2023 14:47:56 +0800
+Subject: [PATCH] =?UTF-8?q?cmake-version:=20=E5=B0=86=E7=89=88=E6=9C=AC?=
+ =?UTF-8?q?=E9=99=8D=E5=88=B0=203.22=20=E4=BB=A5=E9=80=82=E7=94=A8?=
+ =?UTF-8?q?=E4=BA=8E=20cmake=20=E6=9E=84=E5=BB=BA?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ CMakeLists.txt            | 2 +-
+ src/qscint/CMakeLists.txt | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index fed2a51..dc957c3 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -1,4 +1,4 @@
+-cmake_minimum_required(VERSION 3.24)
++cmake_minimum_required(VERSION 3.22)
+ project(notepad-- VERSION 1.22.0)
+ 
+ set(CMAKE_AUTOMOC ON)
+diff --git a/src/qscint/CMakeLists.txt b/src/qscint/CMakeLists.txt
+index f132dc6..77f02f2 100644
+--- a/src/qscint/CMakeLists.txt
++++ b/src/qscint/CMakeLists.txt
+@@ -1,4 +1,4 @@
+-cmake_minimum_required(VERSION 3.24)
++cmake_minimum_required(VERSION 3.22)
+ project(qscint CXX)
+ 
+ set(CMAKE_AUTOMOC ON)
+-- 
+2.20.1
+

+ 38 - 0
patchs/fix-windows-qtcreator-build-fail.patch

@@ -0,0 +1,38 @@
+From 3ced487bd23b92a6f35eb590123bc510c9e2429c Mon Sep 17 00:00:00 2001
+From: zinface <[email protected]>
+Date: Mon, 6 Feb 2023 21:13:23 +0800
+Subject: [PATCH] =?UTF-8?q?fix:=20=E5=9C=A8=20Windows=20QtCreator=20?=
+ =?UTF-8?q?=E4=B8=AD=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=A4=84=E7=90=86=E5=AF=BC?=
+ =?UTF-8?q?=E8=87=B4=E7=BC=96=E8=AF=91=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=97=AE?=
+ =?UTF-8?q?=E9=A2=98?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+---
+ src/cceditor/ccnotepad.cpp | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/src/cceditor/ccnotepad.cpp b/src/cceditor/ccnotepad.cpp
+index ae615be..b2071d3 100755
+--- a/src/cceditor/ccnotepad.cpp
++++ b/src/cceditor/ccnotepad.cpp
+@@ -983,11 +983,12 @@ int CCNotePad::runAsAdmin(const QString& filePath)
+ 	//}
+ 	QString argStr = QString("-muti %1").arg(filePath);
+ 
+-	std::basic_string<TCHAR> args = StringToWString(argStr.toStdString());
+-	size_t shellExecRes = (size_t)::ShellExecute(NULL, TEXT("runas"), nddFullPath, args.c_str(), TEXT("."), SW_SHOW);
++//	std::basic_string<TCHAR> args = StringToWString(argStr.toStdString());
++//	size_t shellExecRes = (size_t)::ShellExecute(NULL, TEXT("runas"), nddFullPath, args.c_str(), TEXT("."), SW_SHOW);
++    size_t shellExecRes = (size_t)::ShellExecute(NULL, TEXT("runas"), nddFullPath, argStr.toUtf8(), TEXT("."), SW_SHOW);
+ 
+ 	// If the function succeeds, it returns a value greater than 32. If the function fails,
+-	// it returns an error value that indicates the cause of the failure.
++    // it returns an error value that indicates the cause of the failure.
+ 	// https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx
+ 
+ 	if (shellExecRes < 32)
+-- 
+2.39.1.windows.1
+

+ 48 - 7
src/include/pluginGl.h

@@ -16,13 +16,13 @@
 
 struct ndd_proc_data
 {
-	QString m_strPlugName; //插件名称 必选
-	QString m_strFilePath; //lib 插件的全局路径。必选。插件内部不用管,主程序传递下来
-	QString m_strComment; //插件说明
-	QString m_version; //版本号码。可选
-	QString m_auther;//作者名称。可选
-	int m_menuType;//菜单类型。0:不使用二级菜单 1:创建二级菜单
-	QMenu* m_rootMenu;//如果m_menuType = 1,给出二级根菜单的地址。其他值nullptr
+	QString m_strPlugName;       // [必选]插件名称
+	QString m_strFilePath;       // [留空]插件的全局路径,主程序传递下来的路径
+	QString m_strComment;        // [可选]插件说明
+	QString m_version;           // [可选]版本号码
+	QString m_auther;            // [可选]作者名称
+	int 	m_menuType;			 // [可选]菜单类型(0:不使用二级菜单 1:创建二级菜单)
+	QMenu* 	m_rootMenu;			 // [依赖]当 m_menuType = 1,给出二级根菜单的地址(默认为 nullptr)
 
 	ndd_proc_data(): m_rootMenu(nullptr), m_menuType(0)
 	{
@@ -35,3 +35,44 @@ typedef struct ndd_proc_data NDD_PROC_DATA;
 
 typedef bool (*NDD_PROC_IDENTIFY_CALLBACK)(NDD_PROC_DATA* pProcData);
 typedef void (*NDD_PROC_FOUND_CALLBACK)(NDD_PROC_DATA* pProcData, void* pUserData);
+
+
+/***********在编译插件时提供的内容**************/
+
+#ifdef  NOTEPAD_PLUGIN_MANAGER
+
+#if defined(Q_OS_WIN)
+#   if defined(NDD_EXPORTDLL)
+#       define NDD_EXPORT __declspec(dllexport)
+#   else
+#       define NDD_EXPORT __declspec(dllimport)
+#   endif
+#endif
+
+#include <Qsci/qsciscintilla.h>
+
+#ifdef __cplusplus
+	extern "C" {
+#endif
+
+	NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData);
+	NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit);
+
+#ifdef __cplusplus
+	}
+#endif
+
+#define NOTEPAD_PLUGIN_METADATA(name, version, author, comment, filepath)\
+        pProcData->m_strPlugName = QString(name);       \
+        pProcData->m_version     = QString(version);    \
+        pProcData->m_strComment  = QString(comment);    \
+        pProcData->m_auther      = QString(author);     \
+        pProcData->m_strFilePath = QString(filepath);   \
+
+#define NOTEPAD_PLUGIN_IMPLEMENT(imp_class)                        \
+    imp_class *imp = new imp_class(pNotepad, getCurEdit()); \
+    //imp->setWindowFlag(Qt::Window);                         \
+    imp->show();
+
+#endif  //NOTEPAD_PLUGIN_MANAGER
+/***********在编译插件时提供的内容**************/

+ 31 - 0
windows-universal.mk

@@ -0,0 +1,31 @@
+# windows-universal.mk
+# Windows Universal - 通用 Windows 平台构建方案
+
+builddir  := build
+sourcedir := .
+CMAKE_DEBUG     := -DCMAKE_BUILD_TYPE=Debug
+CMAKE_RELEASE   := -DCMAKE_BUILD_TYPE=Release
+CMAKE_OPTIONS   := -DUSE_WINDOWS_UNIVERSAL=ON
+CMAKE_GENERATER := ""
+CMAKE_UNIVERSAL_QT  := $(CMAKE_OPTIONS)      -DWINDOWS_DEPLOY_QT=ON 
+CMAKE_UNIVERSAL_QT5 := $(CMAKE_UNIVERSAL_QT) -DWINDOWS_DEPLOY_QT5=ON 
+CMAKE_UNIVERSAL_QT6 := $(CMAKE_UNIVERSAL_QT) -DWINDOWS_DEPLOY_QT6=ON 
+
+JOBS=$(shell nproc)
+
+
+windows-universal:
+	cmake -B$(builddir) $(CMAKE_DEBUG) $(CMAKE_GENERATER) $(CMAKE_OPTIONS) 
+	cmake --build $(builddir) -- -j$(JOBS)
+
+windows-universal-release:
+	cmake -B$(builddir) $(CMAKE_RELEASE) $(CMAKE_GENERATER) $(CMAKE_OPTIONS) 
+	cmake --build $(builddir) -- -j$(JOBS)
+
+windows-universal-release-qt5:
+	cmake $(CMAKE_GENERATER) -B$(builddir) $(CMAKE_RELEASE) $(CMAKE_UNIVERSAL_QT5)
+	cmake --build $(builddir) -- -j$(JOBS)
+
+windows-universal-release-qt6:
+	cmake $(CMAKE_GENERATER) -B$(builddir) $(CMAKE_RELEASE) $(CMAKE_UNIVERSAL_QT6)
+	cmake --build $(builddir) -- -j$(JOBS)

+ 6 - 0
windows.mk

@@ -0,0 +1,6 @@
+Msg   := 'Build with the following configuration:'
+One   := '1. make -f windows-universal.mk'
+
+all:
+	@echo -e $(Msg)
+	@echo -e $(One)    "\n\tThe default Universal Windows platform build"