├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README-ENGLISH.md ├── README.md ├── cgit.bat ├── cgit.sh ├── doc ├── Github-MD-Href.md ├── changelog │ ├── CHANGELOG-ENGLISH.MD │ └── CHANGELOG.md ├── logic │ ├── CODE_BLOCK.md │ ├── Github-MD-Href.md │ ├── SpecialCharTest.md │ └── special_char.txt └── manage │ ├── CI集成.md │ ├── 发布流程.md │ └── 设计规范.md ├── pom.xml ├── release.bat ├── release.sh ├── release_rm.sh └── src ├── main ├── java │ └── com │ │ └── github │ │ └── houbb │ │ └── markdown │ │ └── toc │ │ ├── constant │ │ ├── TocConstant.java │ │ └── VersionConstant.java │ │ ├── core │ │ ├── IMarkdownTocText.java │ │ ├── MarkdownToc.java │ │ ├── MarkdownTocTextContext.java │ │ └── impl │ │ │ ├── AtxMarkdownToc.java │ │ │ └── AtxMarkdownTocText.java │ │ ├── exception │ │ └── MarkdownTocRuntimeException.java │ │ ├── support │ │ ├── I18N.java │ │ ├── IncreaseMap.java │ │ ├── codeblock │ │ │ ├── ICodeBlock.java │ │ │ └── impl │ │ │ │ └── AtxCodeBlock.java │ │ └── md │ │ │ ├── MarkdownContentToc.java │ │ │ ├── MarkdownFileToc.java │ │ │ └── impl │ │ │ ├── AtxMarkdownContentToc.java │ │ │ └── AtxMarkdownFileToc.java │ │ ├── util │ │ ├── MdTocTextHelper.java │ │ └── ThreadLocalUtil.java │ │ └── vo │ │ ├── TocGen.java │ │ ├── TocVo.java │ │ └── config │ │ └── TocConfig.java └── resources │ └── i18n │ ├── MarkdownToc.properties │ ├── MarkdownToc_en.properties │ └── MarkdownToc_zh_CN.properties └── test ├── java └── com │ └── github │ └── houbb │ └── markdown │ └── toc │ ├── constant │ └── TocConstantTest.java │ ├── core │ ├── MarkdownTocTest.java │ └── impl │ │ ├── AtxMarkdownI18NTest.java │ │ ├── AtxMarkdownTocDirTest.java │ │ └── AtxMarkdownTocFileTest.java │ ├── exception │ └── MarkdownTocRuntimeExceptionTest.java │ ├── support │ └── AtxMarkdownContentTocTest.java │ ├── util │ ├── MdTocTextHelperTest.java │ └── TestPathUtil.java │ └── vo │ └── TocVoTest.java └── resources ├── CODE_BLOCK.md ├── N-LEVEL.md ├── README-GBK.md ├── common.md ├── empty-content.md ├── empty.md ├── readme └── README.md ├── special ├── chinese.md ├── emoji.md └── special.md ├── sub ├── 001.md ├── 002.markdown ├── 003.text ├── little │ ├── 003.text │ ├── 008.md │ └── 009.markdown └── sub │ ├── 003.md │ └── 004.md ├── sub0 └── 1.txt ├── sub1 ├── 1.txt └── common.md └── 中文名称.md /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.war 4 | *.zip 5 | *.tar 6 | *.tar.gz 7 | 8 | # eclipse ignore 9 | .settings/ 10 | .project 11 | .classpath 12 | 13 | # idea ignore 14 | .idea/ 15 | *.ipr 16 | *.iml 17 | *.iws 18 | 19 | # temp ignore 20 | *.log 21 | *.cache 22 | *.diff 23 | *.patch 24 | *.tmp 25 | *.java~ 26 | *.properties~ 27 | *.xml~ 28 | 29 | # system ignore 30 | .DS_Store 31 | Thumbs.db 32 | 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true 5 | script: mvn test 6 | after_success: 7 | - mvn clean cobertura:cobertura coveralls:report 8 | env: 9 | global: 10 | secure: dPq6gmrA6Iq750PN/Caai9YhVmMAf+w2KpHJIctb8Wz5Vt/QDNb1fdFdNmUVasHWUFNxFtNTekrbKAf9Hk6VpFnykM9XGygxJG05OUzELnPjm4qdUDOtlsXC1/mfKNK+JU1v5pywRAOgKhjZXUHqBNSNHIV4F8fZr40/W5kMkjuiwVnVcx50C6tZvDovZlMiRHyD4gteEE4euZKLJlKtZ3aVGuqXAsN3mrhkkTIiORUaVdBi6YAJ6Utr5yyIvv3RGQ0tnCZ4nOlFfDzThANbiE3nymSTew51PgoJQnOHSRthwss7r8UOi9IkDyOH0c+UNw0Yvy1vOTAUirh2vyTCGMPJgPTekV0VqYO9JmTdn3cO28jyh2O3v88JmQrRLdhCmrjnZNkf2mRPvBGLc6Acmjhc8KfhYbuuyz+hakVw5HUeUzQcQa6rTuDsZZZMoce6TDi1qKhauKlS39vnQXPQaK/mjznwbCpB0kzXfaapY+5662sEmfsz3cs2ODr+/7CJleMShJAheuTNnbqOD/6Y6QSyqBJ0eLZCl081D4tc0PTtwHiCJ/TGx5oaCGf9kGyZ0CqCtWeMACYRhDuGX+qvM8BbeL2u/tNUCjZpY6WPDowsBoLM9l91r9bWur7NFku2OLhmAOyEEQApBmkjEcTr7A0Jm6+mZIADPv7kE4M02FQ= 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [变更日志](#变更日志) 4 | * [release_1.0.0](#release_100) 5 | * [release_1.0.1](#release_101) 6 | * [release_1.0.2](#release_102) 7 | * [release_1.0.3](#release_103) 8 | * [release_1.0.4](#release_104) 9 | * [release_1.0.5](#release_105) 10 | * [release_1.0.6](#release_106) 11 | * [release_1.0.7](#release_107) 12 | * [release_1.0.8](#release_108) 13 | * [release_1.1.0](#release_110) 14 | * [release_1.1.1](#release_111) 15 | * [release_1.1.2](#release_112) 16 | * [release_1.2.0](#release_120) 17 | 18 | 19 | # 变更日志 20 | 21 | | 类型 | 说明 | 22 | |:----|:----| 23 | | A | 新增 | 24 | | U | 更新 | 25 | | D | 删除 | 26 | | T | 测试 | 27 | | O | 优化 | 28 | | F | 修复BUG | 29 | 30 | # release_1.0.0 31 | 32 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 33 | |:---|:---|:---|:---|:--| 34 | | 1 | A | 添加 toc 生成功能 | | | 35 | 36 | # release_1.0.1 37 | 38 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 39 | |:---|:---|:---|:---|:--| 40 | | 1 | F | 修正 toc 多次生成问题 | | | 41 | | 2 | A | 添加标题名称重复处理 | | | 42 | | 3 | A | 添加标题特殊符号处理 | | | 43 | 44 | # release_1.0.2 45 | 46 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 47 | |:---|:---|:---|:---|:--| 48 | | 1 | O | 代码优化 | 2018-07-04 23:09:46 | | 49 | | 2 | U | 调整文档结构 | 2018-07-04 23:09:46 | | 50 | | 3 | D | 删除 `*.jar` 的支持 | 2018-07-05 10:13:55 | | 51 | 52 | # release_1.0.3 53 | 54 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 55 | |:---|:---|:---|:---|:--| 56 | | 1 | A | 添加多线程支持 | 2018-07-28 13:07:13 | 57 | | 2 | A | 添加 API 规范 | 2018-07-28 13:07:13 | 58 | | 3 | A | 添加 I18N 支持 | 2018-07-28 17:12:25 | 59 | 60 | # release_1.0.4 61 | 62 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 63 | |:---|:---|:---|:---|:--| 64 | | 1 | A | 添加 API version | 2018-08-15 17:44:24 | 65 | | 2 | A | 添加根据内容生成 toc | 2018-08-15 17:44:24 | 66 | 67 | # release_1.0.5 68 | 69 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 70 | |:---|:---|:---|:---|:--| 71 | | 1 | A | 添加 toc 编号生成支持 | 2019-4-9 15:47:03 | 72 | 73 | # release_1.0.6 74 | 75 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 76 | |:---|:---|:---|:---|:--| 77 | | 1 | O | 使用 jdk7 重新编译上传 | 2019-5-10 20:51:29 | 78 | 79 | # release_1.0.7 80 | 81 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 82 | |:---|:---|:---|:---|:--| 83 | | 1 | O | 优化测试代码 | 2019-7-16 15:03:57 | 84 | | 2 | F | 修复代码块 # 也被获取的 BUG | 2019-7-16 15:03:57 | 85 | 86 | # release_1.0.8 87 | 88 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 89 | |:---|:---|:---|:---|:--| 90 | | 1 | F | 修复特殊符号链接生成 BUG | 2019-7-18 17:46:27 | emoji 有部分 BUG,暂时不处理。| 91 | 92 | # release_1.1.0 93 | 94 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 95 | |:---|:---|:---|:---|:--| 96 | | 1 | A | 基于纯文本的目录生成 | 2021-7-04 17:46:27 | | 97 | | 2 | A | 可以指定 headerName 信息 | 2021-7-04 17:46:27 | | 98 | 99 | # release_1.1.1 100 | 101 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 102 | |:---|:---|:---|:---|:--| 103 | | 1 | A | 更新 heaven 依赖 | 2021-8-07 17:46:27 | | 104 | 105 | # release_1.1.2 106 | 107 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 108 | |:---|:---|:---|:---|:--| 109 | | 1 | A | 移除 heaven 依赖 | 2021-8-18 17:46:27 | | 110 | 111 | # release_1.2.0 112 | 113 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 114 | |:---|:---|:---|:---|:--| 115 | | 1 | A | 添加 head 信息自定义支持 | 2022-9-16 17:46:27 | | 116 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2016 ShenHuaJie iBase4J@163.com 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | ====================================================================== 205 | 206 | Apache许可证 207 | 版本 2.0,2004年1月 208 | http://www.apache.org/licenses/ 209 | 210 | 使用、重生成及分发的术语和条件: 211 | 212 | 1.定义 213 | 214 | "许可证"是指根据本文档第1到第9部分关于使用、重生成和分发的术语和条件。 215 | 216 | "许可证颁发者"是指版权所有者或者由版权所有者批准的授权许可证的实体。 217 | 218 | "法律实体"是指实施实体和进行控制的所有其它实体受该实体控制,或者受该实体集中控制。 219 | 根据此定义,"控制"是指(i)让无论是否签订协议的上述实体,进行指导或管理的直接权利或间接权利, 220 | 或者(ii)拥有百分之五十(50%)或以上已发行股票的所有者,或者(iii)上述实体的实权所有者。 221 | 222 | "用户"(或"用户的")是指行使本许可证所授予权限的个人或法律实体。 223 | 224 | "源程序"形式是指对包含但不限制软件源代码、文档源程序和配置文件进行修改的首选形式。 225 | 226 | "目标"形式是指对源程序形式进行机械转换或翻译的任何形式,包括但不限于对编译的目标代码, 227 | 生成的文件以及转换为其它媒体类型。 228 | 229 | "作品"是指根据本许可证所制作的源程序形式或目标形式的著作,在著作中包含的或附加的版权通知 230 | (在下面附录中提供了一个示例)。 231 | 232 | "衍生作品"是指基于作品(或从作品衍生而来)的源程序形式或目标形式的任何作品,以及编辑修订、 233 | 注释、详细描述或其它修订等构成原创著作作品的整体。根据本许可证,衍生作品不得包括与作品及其 234 | 衍生作品分离之作品,或仅与作品及其衍生作品的接口相链接(或按名称结合)之作品。 235 | 236 | "贡献"是指任何著作作品,包括作品的原始版本和对该作品或衍生作品所做的任何修订或补充, 237 | 意在提交给许可证颁发者以让版权所有者或代表版权所有者的授权个人或法律实体包含在其作品中。 238 | 根据此定义,"提交"一词表示发送给许可证颁发者或其代表人,任何电子的、口头的或书面的交流信息形式, 239 | 包括但不限于在由许可证颁发者或者代表其管理的电子邮件清单、源代码控制系统、以及发布跟踪系统上为 240 | 讨论和提高作品的交流,但不包括由版权所有者以书面形式明显标注或指定为"非贡献"的交流活动。 241 | 242 | "贡献者"是指许可证颁发者和代表从许可证颁发者接受之贡献的并随后包含在作品之贡献中的任何个人或法律实体。 243 | 244 | 2.版权许可证的授予 245 | 246 | 根据本许可证的条款,每个贡献者授予用户永久性的、全球性的、非专有性的、免费的、无版权费的、 247 | 不可撤销的版权许可证以源程序形式或目标形式复制、准备衍生作品、公开显示、公开执行、 248 | 授予分许可证、以及分发作品和这样的衍生作品。 249 | 250 | 3.专利许可证的授予 251 | 252 | 根据本许可证的条款,每个贡献者授予用户永久性的、全球性的、非专有性的、免费的、无版权费的、 253 | 不可撤销的(除在本部分进行说明)专利许可证对作品进行制作、让人制作、使用、提供销售、销售、 254 | 进口和其它转让,且这样的许可证仅适用于在所递交作品的贡献中因可由单一的或多个这样的贡献者 255 | 授予而必须侵犯的申请专利。如果用户对任何实体针对作品或作品中所涉及贡献提出因直接性或贡献性 256 | 专利侵权而提起专利法律诉讼(包括交互诉讼请求或反索赔),那么根据本许可证,授予用户针对作品 257 | 的任何专利许可证将在提起上述诉讼之日起终止。 258 | 259 | 4.重新分发 260 | 261 | 用户可在任何媒介中复制和分发作品或衍生作品之副本,无论是否修订,还是以源程序形式或目标形式, 262 | 条件是用户需满足下列条款: 263 | 264 | a) 用户必须为作品或衍生作品的任何其他接收者提供本许可证的副本;并且 265 | 266 | b) 用户必须让任何修改过的文件附带明显的通知,声明用户已更改文件;并且 267 | 268 | c) 用户必须从作品的源程序形式中保留衍生作品源程序形式的用户所分发的所有版权、专利、 269 | 商标和属性通知,但不包括不属于衍生作品任何部分的类似通知;并且 270 | 271 | d) 如果作品将"通知"文本文件包括为其分发作品的一部分,那么用户分发的任何衍生作品中须至少 272 | 在下列地方之一包括,在这样的通知文件中所包含的属性通知的可读副本,但不包括那些不属于衍生 273 | 作品任何部分的通知:在作为衍生作品一部分而分发的通知文本文件中;如果与衍生作品一起提供则 274 | 在源程序形式或文件中;或者通常作为第三方通知出现的时候和地方,在衍生作品中产生的画面中。 275 | 通知文件的内容仅供信息提供,并未对许可证进行修改。用户可在其分发的衍生作品中在作品的通知 276 | 文本后或作为附录添加自己的属性通知,条件是附加的属性通知不得构成修改本许可证。 277 | 278 | 用户可以为自身所做出的修订添加自己的版权声明并可对自身所做出修订内容或为这样的衍生作品作为 279 | 整体的使用、复制或分发提供附加或不同的条款,条件是用户对作品的使用、复制和分发必须符合本许 280 | 可证中声明的条款。 281 | 282 | 5.贡献的提交。 283 | 284 | 除非用户明确声明,在作品中由用户向许可证颁发者的提交若要包含在贡献中,必须在无任何附加条款下 285 | 符合本许可证的条款。尽管上面如此规定,执行许可证颁发者有关贡献的条款时,任何情况下均不得替代 286 | 或修改任何单独许可证协议的条款。 287 | 288 | 6.商标。本许可证并未授予用户使用许可证颁发者的商号、商标、服务标记或产品名称,除非将这些名称 289 | 用于合理性和惯例性描述作品起源和复制通知文件的内容时。 290 | 291 | 7.保证否认条款。除非因适用法律需要或书面同意,许可证颁发者以"按原样"基础提供作品(并且每个 292 | 贡献者提供其贡献),无任何明示的或暗示的保证或条件,包括但不限于关于所有权、不侵权、 293 | 商品适销性、或适用性的保证或条件。用户仅对使用或重新分发作品的正确性负责,并需承担根据本 294 | 许可证行使权限时的任何风险。 295 | 296 | 8.责任限制条款。在任何情况下并根据任何法律,无论是因侵权(包括过失)或根据合同,还是其它原因, 297 | 除非根据适用法律需要(例如故意行为和重大过失行为)或经书面同意,即使贡献者事先已被告知发生 298 | 损害的可能性,任何贡献者不就用户因使用本许可证或不能使用或无法使用作品(包括但不限于商誉损失、 299 | 停工、计算机失效或故障,或任何商业损坏或损失)而造成的损失,包括直接的、非直接的、特殊的、意外 300 | 的或间接的字符损坏而负责。 301 | 302 | 9.接受保证或附加责任。重新分发作品或及其衍生作品时,用户可选择提供或为符合本许可证承担之支持、 303 | 担保、赔偿或其它职责义务和/或权利而收取费用。但是,在承担上述义务时,用户只可代表用户本身和 304 | 用户本身责任来执行,无需代表任何其它贡献者,并且用户仅可保证、防护并保持每个贡献者不受任何 305 | 因此而产生的责任或对因用户自身承担这样的保证或附加责任而对这样的贡献者所提出的索赔。 306 | 307 | 条款结束 308 | 309 | 附录:如何向用户作品中应用Apache许可证。 310 | 311 | 若要向用户作品应用Apache许可证,请附加下列样本通知,将括号"[]"中的字段以用户自身的 312 | 区分信息来替换(但不包括括号)。文本必须以文件格式适当的注释句法包含在其中。 313 | 另外建议将文件名或类别名以及目的说明包含在相同的"打印页"上作为版权通知,以更加容易的区分出第三方档案。 314 | 315 | 版权所有 2016 ShenHuaJie iBase4J@163.com 根据2.0版本Apache许可证("许可证")授权; 316 | 根据本许可证,用户可以不使用此文件。 317 | 318 | 用户可从下列网址获得许可证副本:http://www.apache.org/licenses/LICENSE-2.0 319 | 除非因适用法律需要或书面同意,根据许可证分发的软件是基于"按原样"基础提供, 320 | 无任何明示的或暗示的保证或条件。详见根据许可证许可下,特定语言的管辖权限和限制。 321 | 322 | ======================================================= 323 | 324 | 简要解释: 325 | 326 | 1.需要给代码的用户一份Apache Licence 327 | 2.如果你修改了代码,需要在被修改的文件中说明。 328 | 3.在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议,商标, 329 | 专利声明和其他原来作者规定需要包含的说明。 330 | 4.如果再发布的产品中包含一个Notice文件,则在Notice文件中需要带有 Apache Licence。 331 | 你可以在Notice中增加自己的许可,但不可以表现为对Apache Licence构成更改。 -------------------------------------------------------------------------------- /README-ENGLISH.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [markdown-toc](#markdown-toc) 4 | * [The Features](#the-features) 5 | * [environmental dependence](#environmental-dependence) 6 | * [the JDK](#the-jdk) 7 | * [Maven](#maven) 8 | * [quick start](#quick-start) 9 | * [maven introduced](#maven-introduced) 10 | * [md file](#md-file) 11 | * [quick start](#quick-start-1) 12 | * [attribute configuration](#attribute-configuration) 13 | * [attribute description](#attribute-description) 14 | * [return value description](#return-value-description) 15 | * [test cases](#test-cases) 16 | * [other](#other) 17 | 18 | 19 | # markdown-toc 20 | 21 | ``` 22 | _ __ ___ __ _ _ __| | ____| | _____ ___ __ | |_ ___ ___ 23 | | '_ ` _ \ / _` | '__| |/ / _` |/ _ \ \ /\ / / '_ \ _____| __/ _ \ / __| 24 | | | | | | | (_| | | | < (_| | (_) \ V V /| | | |_____| || (_) | (__ 25 | |_| |_| |_|\__,_|_| |_|\_\__,_|\___/ \_/\_/ |_| |_| \__\___/ \___| 26 | 27 | ``` 28 | 29 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.houbb/markdown-toc/badge.svg)](http://mvnrepository.com/artifact/com.github.houbb/markdown-toc) 30 | [![Build Status](https://www.travis-ci.org/houbb/markdown-toc.svg?branch=release_1.0.2)](https://www.travis-ci.org/houbb/markdown-toc?branch=release_1.0.2) 31 | [![Coverage Status](https://coveralls.io/repos/github/houbb/markdown-toc/badge.svg?branch=release_1.0.2)](https://coveralls.io/github/houbb/markdown-toc?branch=release_1.0.2) 32 | 33 | Markdown-to-toc can be used to generate a directory of the Markdown page for github page rendering. 34 | 35 | - README 36 | 37 | [中文说明](README.md) | [English Readme](README-ENGLISH.md) 38 | 39 | > note 40 | 41 | For the title, there are two kinds of md grammar [setext] (http://docutils.sourceforge.net/mirror/setext.html) 42 | And [atx] (http://www.aaronsw.com/2002/atx/) mode. 43 | 44 | **atx** form is only supported temporarily. 45 | 46 | ## The Features 47 | 48 | - Github Markdown file one click to generate the directory 49 | 50 | - fluent and elegant writing is supported 51 | 52 | - support multiple generation 53 | 54 | - support the generation of duplicate titles 55 | 56 | - supports filtering of special characters 57 | 58 | - supports specifying different file codes 59 | 60 | - supports batch processing of files in folders (you can specify whether subfolder files are included) 61 | 62 | - supports writing to files, returns contents of the directory, and allows users to process by themselves 63 | 64 | - support multi-threads for directory files. 65 | 66 | - support i18n 67 | 68 | - support gen toc number 69 | 70 | # environmental dependence 71 | 72 | ## the JDK 73 | 74 | JDK8+, make sure the JDK is set up correctly. 75 | 76 | Note: If you are use jdk7,download this code and compile by yourself. 77 | ## Maven 78 | 79 | Jars are managed uniformly using [Maven](http://maven.apache.org/). 80 | 81 | Change log 82 | 83 | > [change log](doc/changelog/CHANGELOG-ENGLISH.MD) 84 | 85 | # quick start 86 | 87 | ## maven introduced 88 | 89 | ```xml 90 | 91 | com.github.houbb 92 | markdown-toc 93 | ${maven-version} 94 | 95 | ``` 96 | 97 | ## md file 98 | 99 | The project for the support of md file name suffix `.md` or `.markdown` 100 | 101 | ## quick start 102 | 103 | - single file 104 | 105 | ```Java 106 | AtxMarkdownToc.newInstance().genTocFile(path); 107 | ``` 108 | 109 | Where path is the path of md file 110 | 111 | - specified folder 112 | 113 | ```Java 114 | AtxMarkdownToc.newInstance().genTocFile(path); 115 | ``` 116 | 117 | Where path is the parent class folder of the md file 118 | 119 | # attribute configuration 120 | 121 | - code examples 122 | 123 | ```Java 124 | AtxMarkdownToc.newInstance() 125 | .charset("UTF-8") 126 | .write(true) 127 | .subTree(true); 128 | ``` 129 | 130 | ## attribute description 131 | | 序号 | 属性 | 默认值 | 说明 | 132 | |:----|:----|:----|:----| 133 | | 1 | charset | `UTF-8` | file charset | 134 | | 2 | write | `true` | will toc written to the file (default write) | 135 | | 3 | subTree | `true` | does it include subfolders(default includes) | 136 | | 3 | order | `false` | does it gen toc order num(default false, since 1.0.5) | 137 | 138 | 139 | ## return value description 140 | 141 | `genTocFile()` returns TocGen, `genTocDir()` returns List 142 | 143 | - TocGen attribute description 144 | 145 | | 序号 | 属性 | 类型 | 说明 | 146 | |:----|:----|:----| :----| 147 | | 1 | filePath | String | current md filePath | 148 | | 2 | tocLines | List | current md file toc content | 149 | 150 | # test cases 151 | 152 | [a single file - directory to generate test cases](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocFileTest.java) 153 | 154 | [folder - directory to generate test cases](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocDirTest.java) 155 | 156 | # other 157 | 158 | > [Issues & Bugs] (https://github.com/houbb/markdown-toc/issues) 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * 1 [markdown-toc](#markdown-toc) 4 | * 1.1 [变更日志](#变更日志) 5 | * 1.2 [Features](#features) 6 | * 2 [环境依赖](#环境依赖) 7 | * 2.1 [JDK](#jdk) 8 | * 2.2 [Maven](#maven) 9 | * 3 [快速入门](#快速入门) 10 | * 3.1 [maven 引入](#maven-引入) 11 | * 3.2 [md 文件](#md-文件) 12 | * 3.3 [快速开始](#快速开始) 13 | * 4 [属性配置](#属性配置) 14 | * 4.1 [属性说明](#属性说明) 15 | * 4.2 [返回值说明](#返回值说明) 16 | * 5 [测试案例](#测试案例) 17 | * 6 [其他](#其他) 18 | 19 | 20 | # markdown-toc 21 | 22 | 23 | ``` 24 | _ __ ___ __ _ _ __| | ____| | _____ ___ __ | |_ ___ ___ 25 | | '_ ` _ \ / _` | '__| |/ / _` |/ _ \ \ /\ / / '_ \ _____| __/ _ \ / __| 26 | | | | | | | (_| | | | < (_| | (_) \ V V /| | | |_____| || (_) | (__ 27 | |_| |_| |_|\__,_|_| |_|\_\__,_|\___/ \_/\_/ |_| |_| \__\___/ \___| 28 | 29 | ``` 30 | 31 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.houbb/markdown-toc/badge.svg)](http://mvnrepository.com/artifact/com.github.houbb/markdown-toc) 32 | [![Build Status](https://www.travis-ci.org/houbb/markdown-toc.svg?branch=release_1.0.2)](https://www.travis-ci.org/houbb/markdown-toc?branch=release_1.0.2) 33 | [![Coverage Status](https://coveralls.io/repos/github/houbb/markdown-toc/badge.svg?branch=release_1.0.2)](https://coveralls.io/github/houbb/markdown-toc?branch=release_1.0.2) 34 | 35 | Markdown-toc 可以用来生成 markdown 页面的目录,便于 github 页面展现。 36 | 37 | - 文档 38 | 39 | [中文说明](README.md) | [English Readme](README-ENGLISH.md) 40 | 41 | > 备注 42 | 43 | 对于标题,md 有两种语法 [setext](http://docutils.sourceforge.net/mirror/setext.html) 44 | 和 [atx](http://www.aaronsw.com/2002/atx/) 模式。 45 | 46 | 暂时只支持 **atx** 形式。 47 | 48 | # 快速体验 49 | 50 | > [在线体验](https://houbb.github.io/opensource/sensitive-word) 51 | 52 | ## idea 插件 53 | 54 | 为了便于大家日常开发,整合了 idea 插件。直接 install from disk,在文件上右键/或者在文件中右键,选择第一个【MarkdownTocGen】即可生成。 55 | 56 | ps: 如果没有刷新,可以关闭文件重新打开即可。应该和 idea 对于文件变更的监听有关。 57 | 58 | > [idea 插件](https://github.com/houbb/markdown-toc/releases/download/1.0.0/markdown-toc-idea-plugin-1.0.0.zip) 59 | 60 | ## 变更日志 61 | 62 | [变更日志](doc/changelog/CHANGELOG.md) 63 | 64 | ## Features 65 | 66 | - Github Markdown 文件一键生成目录 67 | 68 | - 支持 fluent 优雅的写法 69 | 70 | - 支持多次生成 71 | 72 | - 支持重复标题的生成 73 | 74 | - 支持特殊字符的过滤 75 | 76 | - 支持指定不同的文件编码 77 | 78 | - 支持文件夹的文件批量处理(可指定是否包含子文件夹文件) 79 | 80 | - 支持是否写入文件,可返回目录的内容,便于用户自行处理 81 | 82 | - 支持多线程写文件 83 | 84 | - 支持 i18n 85 | 86 | - 支持目录编号生成(1.0.5) 87 | 88 | ## v1.1.0 字符串列表 89 | 90 | 1. 支持直接根据字符串列表返回对应的 tocList 91 | 92 | # 环境依赖 93 | 94 | ## JDK 95 | 96 | 1.0.5 及其以前为 jdk8 编译, 请确保 JDK 设置正确。 97 | 98 | 1.0.6 版本使用 jdk7 编译上传。 99 | 100 | 后续 1.XX 版本都将支持 jdk7,更便于使用。 101 | 102 | ## Maven 103 | 104 | Jar 使用 [Maven](http://maven.apache.org/) 进行统一管理。 105 | 106 | # 快速入门 107 | 108 | ## maven 引入 109 | 110 | ```xml 111 | 112 | com.github.houbb 113 | markdown-toc 114 | 1.2.0 115 | 116 | ``` 117 | 118 | ## 字符串列表 119 | 120 | v1.2.0 支持自定义 tocHead 信息。 121 | 122 | ### 默认 123 | 124 | 最简单的使用方式,指定 md 格式的字符串列表。 125 | 126 | ```java 127 | List lines = new ArrayList<>(); 128 | lines.add("# 标题1"); 129 | lines.add("这是一行内容"); 130 | lines.add("# 标题2"); 131 | lines.add("这也是一行内容"); 132 | 133 | List tocList = MdTocTextHelper.getTocList(lines); 134 | ``` 135 | 136 | 返回如下: 137 | 138 | ``` 139 | * [标题1](#标题1) 140 | * [标题2](#标题2) 141 | ``` 142 | 143 | ### 指定序号 144 | 145 | 当然,你也可以指定显示编号。 146 | 147 | ```java 148 | List tocList = MdTocTextHelper.getTocList(lines, true); 149 | ``` 150 | 151 | 返回如下: 152 | 153 | ``` 154 | * 1 [标题1](#标题1) 155 | * 2 [标题2](#标题2) 156 | ``` 157 | 158 | ## md 文件 159 | 160 | 本项目支持的 md 文件后缀名称为 `.md` 或者 `.markdown` 161 | 162 | ## 快速开始 163 | 164 | - 单个文件 165 | 166 | ```java 167 | AtxMarkdownToc.newInstance().genTocFile(path); 168 | ``` 169 | 170 | 其中 path 为 md 文件的路径 171 | 172 | - 指定文件夹 173 | 174 | ```java 175 | AtxMarkdownToc.newInstance().genTocFile(path); 176 | ``` 177 | 178 | 其中 path 为 md 文件的父类文件夹 179 | 180 | # 属性配置 181 | 182 | - 代码示例 183 | 184 | ```java 185 | AtxMarkdownToc.newInstance() 186 | .charset("UTF-8") 187 | .write(true) 188 | .subTree(true); 189 | ``` 190 | 191 | ## 属性说明 192 | 193 | | 序号 | 属性 | 默认值 | 说明 | 194 | |:----|:--------|:----|:------------------------| 195 | | 1 | charset | `UTF-8` | 文件编码 | 196 | | 2 | write | `true` | 是否将 toc 写入文件(默认写入) | 197 | | 3 | subTree | `true` | 是否包含子文件夹的文件(默认包含) | 198 | | 4 | order | `false` | 是否生成目录编号(默认不生成,1.0.5以后) | 199 | | 5 | tocHead | `# Table of Contents` | 自定义 toc 的头信息 | 200 | 201 | ## 返回值说明 202 | 203 | `genTocFile()` 返回 TocGen,`genTocDir()` 返回 List 204 | 205 | - TocGen 属性说明 206 | 207 | | 序号 | 属性 | 类型 | 说明 | 208 | |:----|:----|:----| :----| 209 | | 1 | filePath | String | 当前 md 的文件路径 | 210 | | 2 | tocLines | List | 当前 md 文件对应的目录内容 | 211 | 212 | # 测试案例 213 | 214 | [单个文件-目录生成测试案例](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocFileTest.java) 215 | 216 | [文件夹-目录生成测试案例](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocDirTest.java) 217 | 218 | # 其他 219 | 220 | > [Issues & Bugs](https://github.com/houbb/markdown-toc/issues) 221 | -------------------------------------------------------------------------------- /cgit.bat: -------------------------------------------------------------------------------- 1 | :: 用于提交当前变更(windows) 2 | :: author: houbb 3 | :: LastUpdateTime: 2018-11-22 09:08:52 4 | :: 用法:双击运行,或者当前路径 cmd 直接输入 .\cgit.bat 5 | 6 | git pull 7 | git add . 8 | git commit -m "[Feature] add for new" 9 | git push 10 | git status 11 | 12 | -------------------------------------------------------------------------------- /cgit.sh: -------------------------------------------------------------------------------- 1 | # 提交 2 | 3 | git pull 4 | git add . 5 | git commit -m "[Feature] add for new" 6 | git push 7 | git status 8 | 9 | # 1. 赋值权限: chmod +x ./cgit.sh 10 | # 2. 执行: ./cgit.sh 11 | # Last Update Time: 2018-11-21 21:55:38 12 | # Author: houbb -------------------------------------------------------------------------------- /doc/Github-MD-Href.md: -------------------------------------------------------------------------------- 1 | # Github Markdown Href 2 | 3 | 生成规则如下: 4 | 5 | - 所有的大写字母会被转化为小写 6 | 7 | 如 **AB**,结果为 **ab** 8 | 9 | - 所有的空格会被替换为- 10 | 11 | 一个空格对应一个 `-` 12 | 13 | 如 **a b**,结果为 **a-b** 14 | 15 | - 所有的特殊字符会被过滤 16 | 17 | 比如 `&` `<` `>` `!` `|` 之类的 18 | 19 | 如 **a&b**,结果为 **ab** 20 | 21 | > [特殊字符文件](../src/main/resources/special_char.txt) 22 | 23 | > [特殊字符测试](SpecialCharTest.md) 24 | 25 | - 如果标题重复 26 | 27 | 第一个出现的标题正常。 28 | 后面的名称依次递增。 29 | 30 | 如下: 31 | 32 | 如果有 33 | 34 | ``` 35 | ab 36 | ab 37 | ab 38 | ab 39 | ``` 40 | 41 | 四个标题 42 | 43 | 则结果转化如下 44 | 45 | ``` 46 | ab 47 | ab-1 48 | ab-2 49 | ab-3 50 | ``` 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /doc/changelog/CHANGELOG-ENGLISH.MD: -------------------------------------------------------------------------------- 1 | # change log 2 | 3 | | type | means | 4 | |:----|:----| 5 | | A | add | 6 | | U | updates | 7 | | D | delete | 8 | | T | tests | 9 | | O | optimizes | 10 | | F | fixes BUG | 11 | 12 | # release_1.0.0 13 | 14 | | serial number | change type | means | time | note | 15 | |:----|:----|:----|:----|:----| 16 | | 1 | A | add toc to generate | | | 17 | 18 | # release_1.0.1 19 | 20 | | serial number | change type | means | time | note | 21 | |:----|:----|:----|:----|:----| 22 | | 1 | F | fix toc multiple generation problem | | | 23 | | 2 | A | add title name and repeat | | | 24 | | 3 | A | add A special symbol of the title to handle | | | 25 | 26 | # release_1.0.2 27 | 28 | | serial number | change type | means | time | note | 29 | |:----|:----|:----|:----|:----| 30 | | 1 b| O | code optimization | 2018-07-04 23:09:46 | | 31 | | 2 | U | adjusts document structure | 2018-07-04 23:09:46 | | 32 | | 3 | D | delete `*.jar` support | 2018-07-05 10:13:55 | | 33 | 34 | # release_1.0.3 35 | 36 | | serial number | change type | means | time | note | 37 | |:---|:---|:---|:---|:--| 38 | | 1 | A | Support threads. | 2018-07-28 13:07:13 | 39 | | 2 | A | Add Api rules. | 2018-07-28 13:07:13 | 40 | | 3 | A | Support I18N. | 2018-07-28 17:12:25 | 41 | 42 | # release_1.0.4 43 | 44 | | serial number | change type | means | time | note | 45 | |:---|:---|:---|:---|:--| 46 | | 1 | A | Add API version | 2018-08-15 17:44:24 | 47 | | 2 | A | Generate toc by content list | 2018-08-15 17:44:24 | 48 | 49 | # release_1.0.5 50 | 51 | | serial number | change type | means | time | note | 52 | |:---|:---|:---|:---|:--| 53 | | 1 | A | Add toc order gen support | 2019-4-9 15:47:03 | 54 | 55 | # release_1.0.6 56 | 57 | | serial number | change type | means | time | note | 58 | |:---|:---|:---|:---|:--| 59 | | 1 | A | Compile code by jdk7. | 2019-4-9 15:47:03 | 60 | 61 | 62 | # release_1.0.7 63 | 64 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 65 | |:---|:---|:---|:---|:--| 66 | | 1 | O | Optimize the test case. | 2019-7-16 15:03:57 | 67 | | 2 | F | Fixed bug: get # as head from code block. | 2019-7-16 15:03:57 | 68 | 69 | # release_1.0.8 70 | 71 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 72 | |:---|:---|:---|:---|:--| 73 | | 2 | F | Fixed bug: the github link of special char head | 2019-7-18 17:48:32 | emoji has bugs | -------------------------------------------------------------------------------- /doc/changelog/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 变更日志 2 | 3 | | 类型 | 说明 | 4 | |:----|:----| 5 | | A | 新增 | 6 | | U | 更新 | 7 | | D | 删除 | 8 | | T | 测试 | 9 | | O | 优化 | 10 | | F | 修复BUG | 11 | 12 | # release_1.0.0 13 | 14 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 15 | |:---|:---|:---|:---|:--| 16 | | 1 | A | 添加 toc 生成功能 | | | 17 | 18 | # release_1.0.1 19 | 20 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 21 | |:---|:---|:---|:---|:--| 22 | | 1 | F | 修正 toc 多次生成问题 | | | 23 | | 2 | A | 添加标题名称重复处理 | | | 24 | | 3 | A | 添加标题特殊符号处理 | | | 25 | 26 | # release_1.0.2 27 | 28 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 29 | |:---|:---|:---|:---|:--| 30 | | 1 | O | 代码优化 | 2018-07-04 23:09:46 | | 31 | | 2 | U | 调整文档结构 | 2018-07-04 23:09:46 | | 32 | | 3 | D | 删除 `*.jar` 的支持 | 2018-07-05 10:13:55 | | 33 | 34 | # release_1.0.3 35 | 36 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 37 | |:---|:---|:---|:---|:--| 38 | | 1 | A | 添加多线程支持 | 2018-07-28 13:07:13 | 39 | | 2 | A | 添加 API 规范 | 2018-07-28 13:07:13 | 40 | | 3 | A | 添加 I18N 支持 | 2018-07-28 17:12:25 | 41 | 42 | # release_1.0.4 43 | 44 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 45 | |:---|:---|:---|:---|:--| 46 | | 1 | A | 添加 API version | 2018-08-15 17:44:24 | 47 | | 2 | A | 添加根据内容生成 toc | 2018-08-15 17:44:24 | 48 | 49 | # release_1.0.5 50 | 51 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 52 | |:---|:---|:---|:---|:--| 53 | | 1 | A | 添加 toc 编号生成支持 | 2019-4-9 15:47:03 | 54 | 55 | # release_1.0.6 56 | 57 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 58 | |:---|:---|:---|:---|:--| 59 | | 1 | O | 使用 jdk7 重新编译上传 | 2019-5-10 20:51:29 | 60 | 61 | # release_1.0.7 62 | 63 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 64 | |:---|:---|:---|:---|:--| 65 | | 1 | O | 优化测试代码 | 2019-7-16 15:03:57 | 66 | | 2 | F | 修复代码块 # 也被获取的 BUG | 2019-7-16 15:03:57 | 67 | 68 | # release_1.0.8 69 | 70 | | 序号 | 变更类型 | 说明 | 时间 | 备注 | 71 | |:---|:---|:---|:---|:--| 72 | | 1 | F | 修复特殊符号链接生成 BUG | 2019-7-18 17:46:27 | emoji 有部分 BUG,暂时不处理。| -------------------------------------------------------------------------------- /doc/logic/CODE_BLOCK.md: -------------------------------------------------------------------------------- 1 | # 不同的场景测试 2 | 3 | ## 场景1 4 | 5 | ``` 6 | # code... 7 | ``` 8 | 9 | ## 场景2 10 | 11 | ```c 12 | # code... 13 | ``` 14 | 15 | ## 场景3 16 | 17 | ``` 18 | # code... 19 | ```c 20 | ``` 21 | 22 | ## 场景 4 23 | 24 | ```c 25 | # code... 26 | ```c 27 | ``` 28 | 29 | # 测试结果 30 | 31 | ## 开始: 32 | 33 | ``` 34 | 35 | ```XXX 36 | 37 | ## 结束 38 | 39 | ``` 40 | 41 | 42 | # 基于空格的处理 43 | 44 | 上一行空行 45 | 46 | 本行:四个空格开头。 -------------------------------------------------------------------------------- /doc/logic/Github-MD-Href.md: -------------------------------------------------------------------------------- 1 | # Github Markdown Href 2 | 3 | 生成规则如下: 4 | 5 | - 所有的大写字母会被转化为小写 6 | 7 | 如 **AB**,结果为 **ab** 8 | 9 | - 所有的空格会被替换为- 10 | 11 | 一个空格对应一个 `-` 12 | 13 | 如 **a b**,结果为 **a-b** 14 | 15 | - 所有的特殊字符会被过滤 16 | 17 | 比如 `&` `<` `>` `!` `|` 之类的 18 | 19 | 如 **a&b**,结果为 **ab** 20 | 21 | > [特殊字符文件](../src/main/resources/special_char.txt) 22 | 23 | > [特殊字符测试](SpecialCharTest.md) 24 | 25 | - 如果标题重复 26 | 27 | 第一个出现的标题正常。 28 | 后面的名称依次递增。 29 | 30 | 如下: 31 | 32 | 如果有 33 | 34 | ``` 35 | ab 36 | ab 37 | ab 38 | ab 39 | ``` 40 | 41 | 四个标题 42 | 43 | 则结果转化如下 44 | 45 | ``` 46 | ab 47 | ab-1 48 | ab-2 49 | ab-3 50 | ``` 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /doc/logic/SpecialCharTest.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [ILOVEMD∂ILOVEMD](#ilovemdilovemd) 4 | * [ILOVEMD∏ILOVEMD](#ilovemdilovemd-1) 5 | * [ILOVEMD←ILOVEMD](#ilovemdilovemd-2) 6 | * [ILOVEMD∑ILOVEMD](#ilovemdilovemd-3) 7 | * [ILOVEMD↑ILOVEMD](#ilovemdilovemd-4) 8 | * [ILOVEMD−ILOVEMD](#ilovemdilovemd-5) 9 | * [ILOVEMD→ILOVEMD](#ilovemdilovemd-6) 10 | * [ILOVEMD↓ILOVEMD](#ilovemdilovemd-7) 11 | * [ILOVEMD–ILOVEMD](#ilovemdilovemd-8) 12 | * [ILOVEMD↔ILOVEMD](#ilovemdilovemd-9) 13 | * [ILOVEMD—ILOVEMD](#ilovemdilovemd-10) 14 | * [ILOVEMD‘ILOVEMD](#ilovemdilovemd-11) 15 | * [ILOVEMD’ILOVEMD](#ilovemdilovemd-12) 16 | * [ILOVEMD‚ILOVEMD](#ilovemdilovemd-13) 17 | * [ILOVEMD√ILOVEMD](#ilovemdilovemd-14) 18 | * [ILOVEMD“ILOVEMD](#ilovemdilovemd-15) 19 | * [ILOVEMD”ILOVEMD](#ilovemdilovemd-16) 20 | * [ILOVEMD„ILOVEMD](#ilovemdilovemd-17) 21 | * [ILOVEMD∞ILOVEMD](#ilovemdilovemd-18) 22 | * [ILOVEMD†ILOVEMD](#ilovemdilovemd-19) 23 | * [ILOVEMD!ILOVEMD](#ilovemdilovemd-20) 24 | * [ILOVEMD‡ILOVEMD](#ilovemdilovemd-21) 25 | * [ILOVEMD¡ILOVEMD](#ilovemdilovemd-22) 26 | * [ILOVEMD"ILOVEMD](#ilovemdilovemd-23) 27 | * [ILOVEMD™ILOVEMD](#ilovemdilovemd-24) 28 | * [ILOVEMD•ILOVEMD](#ilovemdilovemd-25) 29 | * [ILOVEMD¢ILOVEMD](#ilovemdilovemd-26) 30 | * [ILOVEMD#ILOVEMD](#ilovemdilovemd-27) 31 | * [ILOVEMD£ILOVEMD](#ilovemdilovemd-28) 32 | * [ILOVEMD$ILOVEMD](#ilovemdilovemd-29) 33 | * [ILOVEMD%ILOVEMD](#ilovemdilovemd-30) 34 | * [ILOVEMD¥ILOVEMD](#ilovemdilovemd-31) 35 | * [ILOVEMD&ILOVEMD](#ilovemdilovemd-32) 36 | * [ILOVEMD¦ILOVEMD](#ilovemdilovemd-33) 37 | * [ILOVEMD…ILOVEMD](#ilovemdilovemd-34) 38 | * [ILOVEMD'ILOVEMD](#ilovemdilovemd-35) 39 | * [ILOVEMD§ILOVEMD](#ilovemdilovemd-36) 40 | * [ILOVEMD(ILOVEMD](#ilovemdilovemd-37) 41 | * [ILOVEMD¨ILOVEMD](#ilovemdilovemd-38) 42 | * [ILOVEMD)ILOVEMD](#ilovemdilovemd-39) 43 | * [ILOVEMD©ILOVEMD](#ilovemdilovemd-40) 44 | * [ILOVEMD∩ILOVEMD](#ilovemdilovemd-41) 45 | * [ILOVEMD*ILOVEMD](#ilovemdilovemd-42) 46 | * [ILOVEMD+ILOVEMD](#ilovemdilovemd-43) 47 | * [ILOVEMD∫ILOVEMD](#ilovemdilovemd-44) 48 | * [ILOVEMD«ILOVEMD](#ilovemdilovemd-45) 49 | * [ILOVEMD,ILOVEMD](#ilovemdilovemd-46) 50 | * [ILOVEMD€ILOVEMD](#ilovemdilovemd-47) 51 | * [ILOVEMD¬ILOVEMD](#ilovemdilovemd-48) 52 | * [ILOVEMD.ILOVEMD](#ilovemdilovemd-49) 53 | * [ILOVEMD®ILOVEMD](#ilovemdilovemd-50) 54 | * [ILOVEMD/ILOVEMD](#ilovemdilovemd-51) 55 | * [ILOVEMD¯ILOVEMD](#ilovemdilovemd-52) 56 | * [ILOVEMD°ILOVEMD](#ilovemdilovemd-53) 57 | * [ILOVEMD‰ILOVEMD](#ilovemdilovemd-54) 58 | * [ILOVEMD±ILOVEMD](#ilovemdilovemd-55) 59 | * [ILOVEMD′ILOVEMD](#ilovemdilovemd-56) 60 | * [ILOVEMD″ILOVEMD](#ilovemdilovemd-57) 61 | * [ILOVEMD´ILOVEMD](#ilovemdilovemd-58) 62 | * [ILOVEMD¶ILOVEMD](#ilovemdilovemd-59) 63 | * [ILOVEMD·ILOVEMD](#ilovemdilovemd-60) 64 | * [ILOVEMD¸ILOVEMD](#ilovemdilovemd-61) 65 | * [ILOVEMD‹ILOVEMD](#ilovemdilovemd-62) 66 | * [ILOVEMD:ILOVEMD](#ilovemdilovemd-63) 67 | * [ILOVEMD›ILOVEMD](#ilovemdilovemd-64) 68 | * [ILOVEMD;ILOVEMD](#ilovemdilovemd-65) 69 | * [ILOVEMD»ILOVEMD](#ilovemdilovemd-66) 70 | * [ILOVEMD¼ILOVEMD](#ilovemdilovemd-67) 71 | * [ILOVEMDILOVEMD](#ilovemdilovemd-72) 76 | * [ILOVEMD‾ILOVEMD](#ilovemdilovemd-73) 77 | * [ILOVEMD?ILOVEMD](#ilovemdilovemd-74) 78 | * [ILOVEMD¿ILOVEMD](#ilovemdilovemd-75) 79 | * [ILOVEMD@ILOVEMD](#ilovemdilovemd-76) 80 | * [ILOVEMD⁄ILOVEMD](#ilovemdilovemd-77) 81 | * [ILOVEMD≈ILOVEMD](#ilovemdilovemd-78) 82 | * [ILOVEMD◊ILOVEMD](#ilovemdilovemd-79) 83 | * [ILOVEMD×ILOVEMD](#ilovemdilovemd-80) 84 | * [ILOVEMD\ILOVEMD](#ilovemdilovemd-81) 85 | * [ILOVEMD˜ILOVEMD](#ilovemdilovemd-82) 86 | * [ILOVEMD^ILOVEMD](#ilovemdilovemd-83) 87 | * [ILOVEMD≠ILOVEMD](#ilovemdilovemd-84) 88 | * [ILOVEMD♠ILOVEMD](#ilovemdilovemd-85) 89 | * [ILOVEMD≡ILOVEMD](#ilovemdilovemd-86) 90 | * [ILOVEMD♣ILOVEMD](#ilovemdilovemd-87) 91 | * [ILOVEMD≤ILOVEMD](#ilovemdilovemd-88) 92 | * [ILOVEMD≥ILOVEMD](#ilovemdilovemd-89) 93 | * [ILOVEMD♥ILOVEMD](#ilovemdilovemd-90) 94 | * [ILOVEMD♦ILOVEMD](#ilovemdilovemd-91) 95 | * [ILOVEMD÷ILOVEMD](#ilovemdilovemd-92) 96 | * [ILOVEMD|ILOVEMD](#ilovemdilovemd-93) 97 | * [ILOVEMD~ILOVEMD](#ilovemdilovemd-94) 98 | 99 | 100 | # ILOVEMD∂ILOVEMD 101 | ILOVEMD∂ILOVEMD 102 | 103 | # ILOVEMD∏ILOVEMD 104 | ILOVEMD∏ILOVEMD 105 | 106 | # ILOVEMD←ILOVEMD 107 | ILOVEMD←ILOVEMD 108 | 109 | # ILOVEMD∑ILOVEMD 110 | ILOVEMD∑ILOVEMD 111 | 112 | # ILOVEMD↑ILOVEMD 113 | ILOVEMD↑ILOVEMD 114 | 115 | # ILOVEMD−ILOVEMD 116 | ILOVEMD−ILOVEMD 117 | 118 | # ILOVEMD→ILOVEMD 119 | ILOVEMD→ILOVEMD 120 | 121 | # ILOVEMD↓ILOVEMD 122 | ILOVEMD↓ILOVEMD 123 | 124 | # ILOVEMD–ILOVEMD 125 | ILOVEMD–ILOVEMD 126 | 127 | # ILOVEMD↔ILOVEMD 128 | ILOVEMD↔ILOVEMD 129 | 130 | # ILOVEMD—ILOVEMD 131 | ILOVEMD—ILOVEMD 132 | 133 | # ILOVEMD‘ILOVEMD 134 | ILOVEMD‘ILOVEMD 135 | 136 | # ILOVEMD’ILOVEMD 137 | ILOVEMD’ILOVEMD 138 | 139 | # ILOVEMD‚ILOVEMD 140 | ILOVEMD‚ILOVEMD 141 | 142 | # ILOVEMD√ILOVEMD 143 | ILOVEMD√ILOVEMD 144 | 145 | # ILOVEMD“ILOVEMD 146 | ILOVEMD“ILOVEMD 147 | 148 | # ILOVEMD”ILOVEMD 149 | ILOVEMD”ILOVEMD 150 | 151 | # ILOVEMD„ILOVEMD 152 | ILOVEMD„ILOVEMD 153 | 154 | # ILOVEMD∞ILOVEMD 155 | ILOVEMD∞ILOVEMD 156 | 157 | # ILOVEMD†ILOVEMD 158 | ILOVEMD†ILOVEMD 159 | 160 | # ILOVEMD!ILOVEMD 161 | ILOVEMD!ILOVEMD 162 | 163 | # ILOVEMD‡ILOVEMD 164 | ILOVEMD‡ILOVEMD 165 | 166 | # ILOVEMD¡ILOVEMD 167 | ILOVEMD¡ILOVEMD 168 | 169 | # ILOVEMD"ILOVEMD 170 | ILOVEMD"ILOVEMD 171 | 172 | # ILOVEMD™ILOVEMD 173 | ILOVEMD™ILOVEMD 174 | 175 | # ILOVEMD•ILOVEMD 176 | ILOVEMD•ILOVEMD 177 | 178 | # ILOVEMD¢ILOVEMD 179 | ILOVEMD¢ILOVEMD 180 | 181 | # ILOVEMD#ILOVEMD 182 | ILOVEMD#ILOVEMD 183 | 184 | # ILOVEMD£ILOVEMD 185 | ILOVEMD£ILOVEMD 186 | 187 | # ILOVEMD$ILOVEMD 188 | ILOVEMD$ILOVEMD 189 | 190 | # ILOVEMD%ILOVEMD 191 | ILOVEMD%ILOVEMD 192 | 193 | # ILOVEMD¥ILOVEMD 194 | ILOVEMD¥ILOVEMD 195 | 196 | # ILOVEMD&ILOVEMD 197 | ILOVEMD&ILOVEMD 198 | 199 | # ILOVEMD¦ILOVEMD 200 | ILOVEMD¦ILOVEMD 201 | 202 | # ILOVEMD…ILOVEMD 203 | ILOVEMD…ILOVEMD 204 | 205 | # ILOVEMD'ILOVEMD 206 | ILOVEMD'ILOVEMD 207 | 208 | # ILOVEMD§ILOVEMD 209 | ILOVEMD§ILOVEMD 210 | 211 | # ILOVEMD(ILOVEMD 212 | ILOVEMD(ILOVEMD 213 | 214 | # ILOVEMD¨ILOVEMD 215 | ILOVEMD¨ILOVEMD 216 | 217 | # ILOVEMD)ILOVEMD 218 | ILOVEMD)ILOVEMD 219 | 220 | # ILOVEMD©ILOVEMD 221 | ILOVEMD©ILOVEMD 222 | 223 | # ILOVEMD∩ILOVEMD 224 | ILOVEMD∩ILOVEMD 225 | 226 | # ILOVEMD*ILOVEMD 227 | ILOVEMD*ILOVEMD 228 | 229 | # ILOVEMD+ILOVEMD 230 | ILOVEMD+ILOVEMD 231 | 232 | # ILOVEMD∫ILOVEMD 233 | ILOVEMD∫ILOVEMD 234 | 235 | # ILOVEMD«ILOVEMD 236 | ILOVEMD«ILOVEMD 237 | 238 | # ILOVEMD,ILOVEMD 239 | ILOVEMD,ILOVEMD 240 | 241 | # ILOVEMD€ILOVEMD 242 | ILOVEMD€ILOVEMD 243 | 244 | # ILOVEMD¬ILOVEMD 245 | ILOVEMD¬ILOVEMD 246 | 247 | # ILOVEMD.ILOVEMD 248 | ILOVEMD.ILOVEMD 249 | 250 | # ILOVEMD®ILOVEMD 251 | ILOVEMD®ILOVEMD 252 | 253 | # ILOVEMD/ILOVEMD 254 | ILOVEMD/ILOVEMD 255 | 256 | # ILOVEMD¯ILOVEMD 257 | ILOVEMD¯ILOVEMD 258 | 259 | # ILOVEMD°ILOVEMD 260 | ILOVEMD°ILOVEMD 261 | 262 | # ILOVEMD‰ILOVEMD 263 | ILOVEMD‰ILOVEMD 264 | 265 | # ILOVEMD±ILOVEMD 266 | ILOVEMD±ILOVEMD 267 | 268 | # ILOVEMD′ILOVEMD 269 | ILOVEMD′ILOVEMD 270 | 271 | # ILOVEMD″ILOVEMD 272 | ILOVEMD″ILOVEMD 273 | 274 | # ILOVEMD´ILOVEMD 275 | ILOVEMD´ILOVEMD 276 | 277 | # ILOVEMD¶ILOVEMD 278 | ILOVEMD¶ILOVEMD 279 | 280 | # ILOVEMD·ILOVEMD 281 | ILOVEMD·ILOVEMD 282 | 283 | # ILOVEMD¸ILOVEMD 284 | ILOVEMD¸ILOVEMD 285 | 286 | # ILOVEMD‹ILOVEMD 287 | ILOVEMD‹ILOVEMD 288 | 289 | # ILOVEMD:ILOVEMD 290 | ILOVEMD:ILOVEMD 291 | 292 | # ILOVEMD›ILOVEMD 293 | ILOVEMD›ILOVEMD 294 | 295 | # ILOVEMD;ILOVEMD 296 | ILOVEMD;ILOVEMD 297 | 298 | # ILOVEMD»ILOVEMD 299 | ILOVEMD»ILOVEMD 300 | 301 | # ILOVEMD¼ILOVEMD 302 | ILOVEMD¼ILOVEMD 303 | 304 | # ILOVEMDILOVEMD 317 | ILOVEMD>ILOVEMD 318 | 319 | # ILOVEMD‾ILOVEMD 320 | ILOVEMD‾ILOVEMD 321 | 322 | # ILOVEMD?ILOVEMD 323 | ILOVEMD?ILOVEMD 324 | 325 | # ILOVEMD¿ILOVEMD 326 | ILOVEMD¿ILOVEMD 327 | 328 | # ILOVEMD@ILOVEMD 329 | ILOVEMD@ILOVEMD 330 | 331 | # ILOVEMD⁄ILOVEMD 332 | ILOVEMD⁄ILOVEMD 333 | 334 | # ILOVEMD≈ILOVEMD 335 | ILOVEMD≈ILOVEMD 336 | 337 | # ILOVEMD◊ILOVEMD 338 | ILOVEMD◊ILOVEMD 339 | 340 | # ILOVEMD×ILOVEMD 341 | ILOVEMD×ILOVEMD 342 | 343 | # ILOVEMD\ILOVEMD 344 | ILOVEMD\ILOVEMD 345 | 346 | # ILOVEMD˜ILOVEMD 347 | ILOVEMD˜ILOVEMD 348 | 349 | # ILOVEMD^ILOVEMD 350 | ILOVEMD^ILOVEMD 351 | 352 | # ILOVEMD≠ILOVEMD 353 | ILOVEMD≠ILOVEMD 354 | 355 | # ILOVEMD♠ILOVEMD 356 | ILOVEMD♠ILOVEMD 357 | 358 | # ILOVEMD≡ILOVEMD 359 | ILOVEMD≡ILOVEMD 360 | 361 | # ILOVEMD♣ILOVEMD 362 | ILOVEMD♣ILOVEMD 363 | 364 | # ILOVEMD≤ILOVEMD 365 | ILOVEMD≤ILOVEMD 366 | 367 | # ILOVEMD≥ILOVEMD 368 | ILOVEMD≥ILOVEMD 369 | 370 | # ILOVEMD♥ILOVEMD 371 | ILOVEMD♥ILOVEMD 372 | 373 | # ILOVEMD♦ILOVEMD 374 | ILOVEMD♦ILOVEMD 375 | 376 | # ILOVEMD÷ILOVEMD 377 | ILOVEMD÷ILOVEMD 378 | 379 | # ILOVEMD|ILOVEMD 380 | ILOVEMD|ILOVEMD 381 | 382 | # ILOVEMD~ILOVEMD 383 | ILOVEMD~ILOVEMD 384 | 385 | # 😊悲伤(*^▽^*) 386 | 387 | # 英文空格 測試 388 | 389 | [github 相关文档](https://help.github.com/en/articles/basic-writing-and-formatting-syntax#links) 390 | 391 | # 中文标点符号 392 | 393 | # 中文标点 ( \uff08 394 | # 中文标点 〈 \u3008 395 | # 中文标点 《 \u300a 396 | # 中文标点 「 \u300c 397 | # 中文标点 『 \u300e 398 | # 中文标点 ﹃ \ufe43 399 | # 中文标点 〔 \u3014 400 | # 中文标点 … \u2026 401 | # 中文标点 ~ \uff5e 402 | # 中文标点 ¥ \uffe5 403 | # 中文标点 【 \u3010 404 | # 中文标点 , \uff0c 405 | # 中文标点 ? \uff1f 406 | # 中文标点 : \uff1a 407 | # 中文标点 “ \u201c 408 | # 中文标点 ‘ \u2018 409 | # 中文标点 ) \uff09 410 | # 中文标点 〉 \u3009 411 | # 中文标点 》 \u300b 412 | # 中文标点 」 \u300d 413 | # 中文标点 』 \u300f 414 | # 中文标点 ﹄ \ufe44 415 | # 中文标点 〕 \u3015 416 | # 中文标点 — \u2014 417 | # 中文标点 ﹏ \ufe4f 418 | # 中文标点 、 \u3001 419 | # 中文标点 】 \u3011 420 | # 中文标点 。 \u3002 421 | # 中文标点 ! \uff01 422 | # 中文标点 ; \uff1b 423 | # 中文标点 ” \u201d 424 | # 中文标点 ’ \u2019 425 | 426 | 427 | # 其他符号 428 | 429 | emoji 表情会怎么处理? 430 | 431 | # 问题 432 | 433 | 不知道具体的转换规则。 434 | 这种只能通过实践获得的效率很低。 435 | -------------------------------------------------------------------------------- /doc/logic/special_char.txt: -------------------------------------------------------------------------------- 1 | ! NOT 2 | | OR 3 | # 4 | . 5 | \ 6 | / 7 | ~ 8 | @ 9 | $ 10 | % 11 | ^ 12 | * 13 | ( 14 | ) 15 | + 16 | = 17 | : 18 | ; 19 | ' 20 | " 21 | | 22 | ? 23 | , 24 | . 25 | ® 26 | © 27 | ™ 28 | ″ ″ 29 | ′ ′ 30 | ´ ´ 31 | & & 32 | “ " 33 | › › 34 | ’ ’ 35 | ‚ ‚ 36 | ¦ ¦ 37 | • • 38 | ¸ ¸ 39 | ¢ ¢ 40 | € € 41 | „ „ 42 | † † 43 | ‡ ‡ 44 | ≈ ≈ 45 | ∩ ∩ 46 | ♣ ♣ 47 | ↓ ↓ 48 | ♦ ♦ 49 | ≡ ≡ 50 | © © 51 | ° ° 52 | ÷ ÷ 53 | ½ ½ 54 | ¼ ¼ 55 | ¾ ¾ 56 | £ £ 57 | … … 58 | “ “ 59 | ‹ ‹ 60 | ‘ ‘ 61 | ⁄ ⁄ 62 | ≥ ≥ 63 | ↔ ↔ 64 | ♥ ♥ 65 | ∞ ∞ 66 | ∫ ∫ 67 | > > 68 | ¡ ¡ 69 | ¿ ¿ 70 | « « 71 | < < 72 | ¯ ¯ 73 | ¥ ¥ 74 | · · 75 | — — 76 | – – 77 | ‰ ‰ 78 | ← ← 79 | ≤ ≤ 80 | ◊ ◊ 81 | − − 82 | ≠ ≠ 83 | ‾ ‾ 84 | » » 85 | ¬ ¬ 86 | ¶ ¶ 87 | ± ± 88 | ∂ ∂ 89 | ∏ ∏ 90 | √ √ 91 | → → 92 | ® ® 93 | § § 94 | ¨ ¨ 95 | × × 96 | ™ ™ 97 | ” ” 98 | ˜ ˜ 99 | ♠ ♠ 100 | ∑ ∑ 101 | ↑ ↑ -------------------------------------------------------------------------------- /doc/manage/CI集成.md: -------------------------------------------------------------------------------- 1 | # 文档说明 2 | 3 | 作者:侯宾宾 4 | 5 | 时间:2018-04-24 10:11:43 6 | 7 | 说明:如何进行项目的持续集成+测试覆盖率 8 | 9 | # Travis-CI 10 | 11 | [https://www.travis-ci.org](https://www.travis-ci.org) 直接添加此项目 12 | 13 | # Coveralls 14 | 15 | - 添加项目 16 | 17 | [https://coveralls.io/repos/new](https://coveralls.io/repos/new) 直接添加项目 18 | 19 | - 生成密匙 20 | 21 | ``` 22 | travis encrypt COVERALLS_TOKEN=${your_repo_token} 23 | ``` 24 | 25 | - 添加到文件 26 | 27 | ``` 28 | travis encrypt COVERALLS_TOKEN=${your_repo_token} --add 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /doc/manage/发布流程.md: -------------------------------------------------------------------------------- 1 | # release version 2 | ``` 3 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=markdown-toc -DoldVersion=1.1.1 -DnewVersion=1.1.2-SNAPSHOT--> 4 | mvn -N versions:update-child-modules 5 | mvn versions:commit 6 | ``` 7 | 8 | # push to mvn center 9 | 10 | ``` 11 | mvn clean deploy -P release 12 | ``` 13 | 14 | # commit to github 15 | 16 | ``` 17 | git add . 18 | git commit -m "release" 19 | git push 20 | git status 21 | ``` 22 | 23 | # merge to master 24 | 25 | ``` 26 | git checkout master 27 | git pull 28 | git checkout branch 29 | git rebase master (用rebase合并主干的修改,如果有冲突在此时解决) 30 | git checkout master 31 | git merge branch 32 | git push 33 | ``` 34 | 35 | # create new branch & checkout 36 | 37 | ``` 38 | git branch release_XXX 39 | git checkout release_XXX 40 | git push --set-upstream origin release_XXX 41 | 42 | ``` 43 | 44 | # modify project version 45 | 46 | ``` 47 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=markdown-toc -DoldVersion=1.1.1 -DnewVersion=1.1.2-SNAPSHOT--> 48 | mvn -N versions:update-child-modules 49 | mvn versions:commit 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /doc/manage/设计规范.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/doc/manage/设计规范.md -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.houbb 8 | markdown-toc 9 | 1.2.0 10 | 11 | 12 | 13 | 3.2 14 | 3.2 15 | 2.18.1 16 | true 17 | true 18 | 19 | 2.2.1 20 | 2.9.1 21 | 1.5 22 | 23 | 1.0.1 24 | 4.3.0 25 | 2.7 26 | 27 | 28 | UTF-8 29 | 1.7 30 | 31 | 32 | 4.12 33 | 34 | 35 | 36 | 37 | 38 | junit 39 | junit 40 | ${junit.version} 41 | test 42 | true 43 | 44 | 45 | 46 | org.apiguardian 47 | apiguardian-api 48 | 1.0.0 49 | true 50 | 51 | 52 | 53 | com.github.houbb 54 | heaven 55 | 0.1.166 56 | 57 | 58 | 59 | 60 | ${project.name} 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-compiler-plugin 68 | ${plugin.compiler.version} 69 | 70 | ${compiler.level} 71 | ${compiler.level} 72 | ${project.build.sourceEncoding} 73 | 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-surefire-plugin 79 | ${plugin.surefire.version} 80 | 81 | ${plugin.surefire.skip-it} 82 | ${plugin.surefire.ignore-failure} 83 | 84 | 85 | 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-assembly-plugin 90 | 91 | false 92 | 93 | jar-with-dependencies 94 | 95 | 96 | 97 | com.github.houbb.markdown.toc.Main 98 | 99 | 100 | 101 | 102 | 103 | make-assembly 104 | package 105 | 106 | assembly 107 | 108 | 109 | 110 | 111 | 112 | 113 | com.github.houbb 114 | gen-maven-plugin 115 | 1.0.2 116 | 117 | true 118 | false 119 | utf-8 120 | 121 | 122 | 123 | 124 | 125 | 126 | org.eluder.coveralls 127 | coveralls-maven-plugin 128 | ${plugin.coveralls.version} 129 | 130 | 131 | 132 | org.codehaus.mojo 133 | cobertura-maven-plugin 134 | ${plugin.cobertura.version} 135 | 136 | xml 137 | 256m 138 | 139 | true 140 | 141 | 142 | **/*Test.class 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | org.apache.maven.plugins 157 | maven-compiler-plugin 158 | 159 | 160 | 161 | org.apache.maven.plugins 162 | maven-surefire-plugin 163 | 164 | 165 | 166 | org.apache.maven.plugins 167 | maven-assembly-plugin 168 | 169 | 170 | 171 | com.github.houbb 172 | gen-maven-plugin 173 | 174 | 175 | 176 | 177 | 178 | org.sonarsource.scanner.maven 179 | sonar-maven-plugin 180 | 3.1.1 181 | 182 | 183 | 184 | 185 | 186 | org.eluder.coveralls 187 | coveralls-maven-plugin 188 | 189 | 190 | 191 | org.codehaus.mojo 192 | cobertura-maven-plugin 193 | 194 | 195 | 196 | 197 | 198 | org.apache.maven.plugins 199 | maven-javadoc-plugin 200 | ${plugin.maven-javadoc-plugin.version} 201 | 202 | 203 | package 204 | 205 | jar 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | markdown-toc 216 | markdown-toc 生成 github md 文件 217 | 218 | 219 | org.sonatype.oss 220 | oss-parent 221 | 7 222 | 223 | 224 | 225 | The Apache Software License, Version 2.0 226 | http://www.apache.org/licenses/LICENSE-2.0.txt 227 | repo 228 | 229 | 230 | 231 | https://github.com/houbb/markdown-toc 232 | https://github.com/houbb/markdown-toc.git 233 | https://houbb.github.io/ 234 | 235 | 236 | 237 | houbb 238 | houbinbin.echo@gmail.com 239 | https://houbb.github.io/ 240 | 241 | 242 | 243 | 244 | 245 | 246 | release 247 | 248 | 249 | 250 | 251 | org.apache.maven.plugins 252 | maven-source-plugin 253 | ${plugin.maven-source-plugin.version} 254 | 255 | 256 | package 257 | 258 | jar-no-fork 259 | 260 | 261 | 262 | 263 | 264 | 265 | org.apache.maven.plugins 266 | maven-javadoc-plugin 267 | ${plugin.maven-javadoc-plugin.version} 268 | 269 | 270 | package 271 | 272 | jar 273 | 274 | 275 | 276 | 277 | 278 | 279 | org.apache.maven.plugins 280 | maven-gpg-plugin 281 | ${plugin.maven-gpg-plugin.version} 282 | 283 | 284 | verify 285 | 286 | sign 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | oss 296 | https://oss.sonatype.org/content/repositories/snapshots/ 297 | 298 | 299 | oss 300 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 301 | 302 | 303 | 304 | 305 | 306 | -------------------------------------------------------------------------------- /release.bat: -------------------------------------------------------------------------------- 1 | :: 用于 release 当前项目(windows) 2 | :: author: houbb 3 | :: LastUpdateTime: 2018-1-22 09:08:52 4 | :: 用法:双击运行,或者当前路径 cmd 直接输入 release.bat 5 | 6 | :: 关闭回显 7 | @echo OFF 8 | 9 | ECHO "============================= RELEASE START..." 10 | 11 | :: 版本号信息(需要手动指定) 12 | :::: 旧版本名称 13 | SET version=1.2.0 14 | :::: 组织名称 15 | SET groupName=com.github.houbb 16 | :::: 项目名称 17 | SET projectName=markdown-toc 18 | 19 | :: 1. release 项目版本 20 | :::: snapshot 版本号 21 | SET snapshot_version=%version%"-SNAPSHOT" 22 | :::: 新的版本号 23 | SET release_version=%version% 24 | 25 | call mvn versions:set -DgroupId=%groupName% -DartifactId=%projectName% -DoldVersion=%snapshot_version% -DnewVersion=%release_version% 26 | call mvn -N versions:update-child-modules 27 | call mvn versions:commit 28 | call echo "1. RELEASE %snapshot_version% TO %release_version% DONE." 29 | 30 | 31 | :: 2. 推送到 github 32 | git add . 33 | git commit -m "release branch %version%" 34 | git push 35 | git status 36 | 37 | ECHO "2. PUSH TO GITHUB DONE." 38 | 39 | :: 3. 发布到 mvn 中央仓库 40 | mvn clean deploy -P release 41 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "============================= RELEASE START..." 3 | 4 | ## 版本号信息(需要手动指定) 5 | version="1.0.5" 6 | newVersion="1.0.6" 7 | projectName="markdown-toc" 8 | 9 | # release 项目版本 10 | ## snapshot 版本号 11 | snapshot_version=${version}"-SNAPSHOT" 12 | ## 新的版本号 13 | release_version=${version} 14 | 15 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=${projectName} -DoldVersion=${snapshot_version} -DnewVersion=${release_version} 16 | mvn -N versions:update-child-modules 17 | mvn versions:commit 18 | echo "1. RELEASE ${snapshot_version} TO ${release_version} DONE." 19 | 20 | 21 | # 推送到 github 22 | git add . 23 | git commit -m "release branch ${version}" 24 | git push 25 | git status 26 | 27 | echo "2. PUSH TO GITHUB DONE." 28 | 29 | 30 | # 推送到 maven 中央仓库 31 | mvn clean deploy -Dmaven.test.skip=true -P release 32 | 33 | echo "3. PUSH TO MAVEN CENTER DONE." 34 | 35 | # 合并到 master 分支 36 | branchName="release_"${version} # 分支名称 37 | git checkout master 38 | git pull 39 | git checkout ${branchName} 40 | git rebase master 41 | git checkout master 42 | git merge ${branchName} 43 | git push 44 | 45 | echo "4. MERGE TO MASTER DONE." 46 | 47 | 48 | # 拉取新的分支 49 | newBranchName="release_"${newVersion} 50 | git branch ${newBranchName} 51 | git checkout ${newBranchName} 52 | git push --set-upstream origin ${newBranchName} 53 | 54 | echo "5. NEW BRANCH DONE." 55 | 56 | # 修改新分支的版本号 57 | ## snapshot 版本号 58 | snapshot_new_version=${newVersion}"-SNAPSHOT" 59 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=${projectName} -DoldVersion=${release_version} -DnewVersion=${snapshot_new_version} 60 | mvn -N versions:update-child-modules 61 | mvn versions:commit 62 | 63 | git add . 64 | git commit -m "modify branch ${release_version} TO ${snapshot_new_version}" 65 | git push 66 | git status 67 | echo "6. MODIFY ${release_version} TO ${snapshot_new_version} DONE." 68 | 69 | echo "============================= RELEASE END..." 70 | 71 | 72 | # 使用方式: 73 | # 1. 赋值权限: chmod +x ./release.sh 74 | # 2. 执行: ./release.sh 75 | # Last Update Time: 2018-01-20 12:07:34 76 | # Author: houbb 77 | 78 | 79 | -------------------------------------------------------------------------------- /release_rm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "============================= RELEASE START..." 3 | 4 | ## 版本号信息(需要手动指定) 5 | oldVersion="1.0.6" 6 | newVersion="1.0.6" 7 | projectName="markdown-toc" 8 | 9 | # 删除分支 10 | oldBranchName="release_"${oldVersion} 11 | git branch -d ${oldBranchName} 12 | git push origin --delete ${oldBranchName} 13 | 14 | echo "1. Branch remove success..." 15 | 16 | # 拉取新的分支 17 | newBranchName="release_"${newVersion} 18 | git branch ${newBranchName} 19 | git checkout ${newBranchName} 20 | git push --set-upstream origin ${newBranchName} 21 | 22 | echo "2. NEW BRANCH DONE." 23 | 24 | # 修改新分支的版本号 25 | ## snapshot 版本号 26 | snapshot_new_version=${newVersion}"-SNAPSHOT" 27 | mvn versions:set -DgroupId=com.github.houbb -DartifactId=${projectName} -DoldVersion=${release_version} -DnewVersion=${snapshot_new_version} 28 | mvn -N versions:update-child-modules 29 | mvn versions:commit 30 | 31 | git add . 32 | git commit -m "modify branch ${release_version} TO ${snapshot_new_version}" 33 | git push 34 | git status 35 | echo "3. MODIFY ${release_version} TO ${snapshot_new_version} DONE." 36 | 37 | echo "============================= BRANCH RE-CREATE END..." 38 | 39 | echo "============================= BRANCH LIST =============================" 40 | git branch -a 41 | 42 | # 使用方式: 43 | # 注意:本脚本用于删除分支,谨慎使用! 44 | # 1. 赋值权限: chmod +x ./release_rm.sh 45 | # 2. 执行: ./release_rm.sh 46 | # Last Update Time: 2018-06-21 11:10:42 47 | # Author: houbb -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/constant/TocConstant.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.constant; 2 | 3 | import org.apiguardian.api.API; 4 | 5 | /** 6 | * TOC 常量 7 | * @author bbhou 8 | * @version 1.0.0 9 | * @since 1.0.0, 2018/01/30 10 | */ 11 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0) 12 | public final class TocConstant { 13 | 14 | private TocConstant(){} 15 | 16 | /** 17 | * 两个空格 18 | */ 19 | public static final String TWO_BLANK = " "; 20 | 21 | /** 22 | * 四个空格 23 | * @since 1.0.7 24 | */ 25 | public static final String FOUR_BLANK = " "; 26 | 27 | /** 28 | * 井号 29 | */ 30 | public static final String ASTERISK = "#"; 31 | 32 | /** 33 | * 星号 34 | */ 35 | public static final String STAR = "*"; 36 | 37 | /** 38 | * 减号 39 | */ 40 | public static final String MINUS = "-"; 41 | 42 | /** 43 | * 减号字符 44 | * @since 1.0.8 45 | */ 46 | public static final char MINUS_CHAR = '-'; 47 | 48 | /** 49 | * 下划线 50 | * @since 1.0.8 51 | */ 52 | public static final String UNDERLINE = "_"; 53 | 54 | /** 55 | * TOC 格式化 56 | */ 57 | public static final String TOC_FORMAT = "* %s[%s](%s)"; 58 | 59 | /** 60 | * 默认的 toc 开头 61 | */ 62 | public static final String DEFAULT_TOC_HEAD = "# Table of Contents"; 63 | 64 | /** 65 | * 通用换行符 66 | */ 67 | public static final String RETURN_LINE = System.getProperty("line.separator"); 68 | 69 | /** 70 | * 点 71 | */ 72 | public static final String DOT = "."; 73 | 74 | /** 75 | * markdown 代码块开始 76 | * 77 | * 示例: 78 | * ``` 79 | * 代码块 80 | * ``` 81 | * or 82 | * 83 | * ```c 84 | * 代码块 85 | * ``` 86 | * @since 1.0.7 87 | */ 88 | public static final String MD_CODE_BLOCK = "```"; 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/constant/VersionConstant.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.constant; 7 | 8 | import org.apiguardian.api.API; 9 | 10 | /** 11 | * 版本常量 12 | * @author bbhou 13 | * @version 1.0.4 14 | * @since 1.0.4, 2018/01/30 15 | */ 16 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_4) 17 | public final class VersionConstant { 18 | 19 | private VersionConstant(){} 20 | 21 | public static final String V_1_0_0 = "1.0.0"; 22 | 23 | public static final String V_1_0_1 = "1.0.1"; 24 | 25 | public static final String V_1_0_3 = "1.0.3"; 26 | 27 | public static final String V_1_0_4 = "1.0.4"; 28 | 29 | /** 30 | * 版本常量 31 | * @since 1.0.5 32 | */ 33 | public static final String V_1_0_5 = "1.0.5"; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/core/IMarkdownTocText.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.core; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 纯文本的目录生成 7 | * 8 | * @author bbhou 9 | * @since 1.1.0 10 | */ 11 | public interface IMarkdownTocText { 12 | 13 | /** 14 | * 获取文本对应的目录结构信息 15 | * @return 生成的结果信息 16 | * @since 1.1.0 17 | */ 18 | List getTocList(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/core/MarkdownToc.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.core; 2 | 3 | import com.github.houbb.markdown.toc.constant.VersionConstant; 4 | import com.github.houbb.markdown.toc.vo.TocGen; 5 | 6 | import org.apiguardian.api.API; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * markdown toc 12 | * @author bbhou 13 | * @version 1.0.0 14 | * @since 1.0.0, 2018/01/30 15 | */ 16 | @API(status = API.Status.MAINTAINED, since = VersionConstant.V_1_0_0) 17 | public interface MarkdownToc { 18 | 19 | /** 20 | * 生成单个文件的 toc 21 | * @param filePath 文件路径 22 | * @return 生成的结果信息 23 | */ 24 | TocGen genTocFile(final String filePath); 25 | 26 | /** 27 | * 生成指定目录下的所有 markdown 文件 toc 28 | * @param dirPath 文件夹路径 29 | * @return 生成的结果信息列表 30 | */ 31 | List genTocDir(final String dirPath); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/core/MarkdownTocTextContext.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.core; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 纯文本的目录生成 7 | * 8 | * @author bbhou 9 | * @since 1.1.0 10 | */ 11 | public class MarkdownTocTextContext { 12 | 13 | /** 14 | * markdown 纯文本 15 | * @since 1.1.0 16 | */ 17 | private List lines; 18 | 19 | /** 20 | * 是否指定编号 21 | * @since 1.1.0 22 | */ 23 | private boolean order; 24 | 25 | public List lines() { 26 | return lines; 27 | } 28 | 29 | public MarkdownTocTextContext lines(List lines) { 30 | this.lines = lines; 31 | return this; 32 | } 33 | 34 | public boolean order() { 35 | return order; 36 | } 37 | 38 | public MarkdownTocTextContext order(boolean order) { 39 | this.order = order; 40 | return this; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "MarkdownTocTextContext{" + 46 | "lines=" + lines + 47 | ", order=" + order + 48 | '}'; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownToc.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.core.impl; 2 | 3 | import com.github.houbb.heaven.util.io.FileUtil; 4 | import com.github.houbb.heaven.util.lang.StringUtil; 5 | import com.github.houbb.heaven.util.lang.ThreadUtil; 6 | import com.github.houbb.heaven.util.util.CollectionUtil; 7 | import com.github.houbb.markdown.toc.constant.TocConstant; 8 | import com.github.houbb.markdown.toc.constant.VersionConstant; 9 | import com.github.houbb.markdown.toc.core.MarkdownToc; 10 | import com.github.houbb.markdown.toc.exception.MarkdownTocRuntimeException; 11 | import com.github.houbb.markdown.toc.support.I18N; 12 | import com.github.houbb.markdown.toc.util.ThreadLocalUtil; 13 | import com.github.houbb.markdown.toc.vo.TocGen; 14 | import com.github.houbb.markdown.toc.vo.config.TocConfig; 15 | 16 | import org.apiguardian.api.API; 17 | 18 | import java.nio.charset.Charset; 19 | import java.nio.charset.StandardCharsets; 20 | import java.nio.file.Files; 21 | import java.nio.file.Path; 22 | import java.nio.file.Paths; 23 | import java.util.ArrayList; 24 | import java.util.Collections; 25 | import java.util.List; 26 | import java.util.concurrent.Callable; 27 | import java.util.concurrent.CopyOnWriteArrayList; 28 | import java.util.concurrent.ExecutionException; 29 | import java.util.concurrent.ExecutorService; 30 | import java.util.concurrent.Executors; 31 | import java.util.concurrent.Future; 32 | 33 | /** 34 | * # 的标题形式 35 | * 36 | * @author bbhou 37 | * @version 1.0.0 38 | * @since 1.0.0, 2018/01/30 39 | */ 40 | @API(status = API.Status.MAINTAINED, since = VersionConstant.V_1_0_0) 41 | public class AtxMarkdownToc implements MarkdownToc { 42 | 43 | //region 外部配置相关 44 | /** 45 | * 编码(默认为utf-8) 46 | */ 47 | private Charset charset = StandardCharsets.UTF_8; 48 | 49 | /** 50 | * 是否包含子文件夹下的文件(默认为包含) 51 | */ 52 | private boolean subTree = true; 53 | 54 | /** 55 | * 是否写入到文件(默认写入) 56 | */ 57 | private boolean write = true; 58 | 59 | /** 60 | * 是否添加 order 编号(默认没有编号) 61 | * @since 1.0.5 62 | */ 63 | private boolean order = false; 64 | 65 | /** 66 | * toc 表头信息 67 | * @since 1.2.0 68 | */ 69 | private String tocHead = TocConstant.DEFAULT_TOC_HEAD; 70 | //endregion 71 | 72 | @Override 73 | public TocGen genTocFile(String filePath) { 74 | checkPath(filePath); 75 | 76 | TocConfig config = buildConfig(); 77 | return ThreadLocalUtil.genTocFile(filePath, config); 78 | } 79 | 80 | /** 81 | * 构建配置信息 82 | * @return 配置信息 83 | */ 84 | private TocConfig buildConfig() { 85 | TocConfig tocConfig = new TocConfig(); 86 | tocConfig.setCharset(charset); 87 | tocConfig.setSubTree(subTree); 88 | tocConfig.setWrite(write); 89 | tocConfig.setOrder(this.order); 90 | tocConfig.setTocHead(this.tocHead); 91 | return tocConfig; 92 | } 93 | 94 | @Override 95 | public List genTocDir(String dirPath) { 96 | checkPath(dirPath); 97 | 98 | final List tocGens = new CopyOnWriteArrayList<>(); 99 | final TocConfig config = buildConfig(); 100 | 101 | Path path = Paths.get(dirPath); 102 | if (!Files.isDirectory(path)) { 103 | final String msg = String.format(I18N.get(I18N.Key.pathIsNotDirectory), dirPath); 104 | throw new MarkdownTocRuntimeException(msg); 105 | } 106 | List paths = FileUtil.getMdFilePathList(path, subTree); 107 | 108 | //1. 列表为空 109 | if(CollectionUtil.isEmpty(paths)) { 110 | return Collections.emptyList(); 111 | } 112 | 113 | //2. 是否为只有单个文件 114 | int bestThreadNum = ThreadUtil.bestThreadNum(paths.size()); 115 | if(bestThreadNum <= 1) { 116 | final Path firstPath = paths.get(0); 117 | final TocGen tocGen = genTocFile(firstPath.toString()); 118 | return Collections.singletonList(tocGen); 119 | } 120 | 121 | //3. 多个文件多线程生成 122 | //TODO: 后期统一使用 Async 框架 123 | ExecutorService executorService = Executors.newFixedThreadPool(bestThreadNum); 124 | 125 | List> futureTasks = new ArrayList<>(); 126 | for(final Path filePath : paths) { 127 | Callable tocGenCallable = new Callable() { 128 | @Override 129 | public TocGen call() { 130 | return ThreadLocalUtil.genTocFile(filePath.toString(), config); 131 | } 132 | }; 133 | 134 | Future tocGenFuture = executorService.submit(tocGenCallable); 135 | futureTasks.add(tocGenFuture); 136 | } 137 | executorService.shutdown(); 138 | ThreadLocalUtil.clear(); 139 | 140 | try { 141 | for(Future tocGenFuture : futureTasks) { 142 | TocGen tocGen = tocGenFuture.get(); 143 | tocGens.add(tocGen); 144 | } 145 | } catch (InterruptedException | ExecutionException e) { 146 | throw new MarkdownTocRuntimeException(e); 147 | } 148 | return tocGens; 149 | } 150 | 151 | /** 152 | * 创建一个实例 153 | * @return 新的实例 154 | */ 155 | public static AtxMarkdownToc newInstance() { 156 | return new AtxMarkdownToc(); 157 | } 158 | 159 | /** 160 | * 设置编码 161 | * @param charset 编码 162 | * @return this 163 | */ 164 | public AtxMarkdownToc charset(final String charset) { 165 | this.charset = Charset.forName(charset); 166 | return this; 167 | } 168 | /** 169 | * 设置是否递归 170 | * 1. 注意:只有在文件夹模式下生效 171 | * @param subTree 是否包含子文件夹元素 172 | * @return this 173 | */ 174 | public AtxMarkdownToc subTree(final boolean subTree) { 175 | this.subTree = subTree; 176 | return this; 177 | } 178 | 179 | /** 180 | * 设置是否写入到文件中 181 | * @param write 写入文件 182 | * @return this 183 | */ 184 | public AtxMarkdownToc write(final boolean write) { 185 | this.write = write; 186 | return this; 187 | } 188 | 189 | /** 190 | * 设置是否设置编号 191 | * @param order 编号 192 | * @return this 193 | */ 194 | public AtxMarkdownToc order(final boolean order) { 195 | this.order = order; 196 | return this; 197 | } 198 | 199 | /** 200 | * 设置 toc 表头 201 | * @param tocHead 编号 202 | * @return this 203 | */ 204 | public AtxMarkdownToc tocHead(final String tocHead) { 205 | this.tocHead = tocHead; 206 | return this; 207 | } 208 | 209 | /** 210 | * 校验路径 211 | * 212 | * @param path 文件路径 213 | */ 214 | private void checkPath(final String path) { 215 | if (StringUtil.isEmpty(path)) { 216 | throw new MarkdownTocRuntimeException(I18N.get(I18N.Key.pathIsNotAllowEmpty)); 217 | } 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocText.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.core.impl; 2 | 3 | import com.github.houbb.heaven.util.lang.StringUtil; 4 | import com.github.houbb.heaven.util.util.CollectionUtil; 5 | import com.github.houbb.markdown.toc.constant.TocConstant; 6 | import com.github.houbb.markdown.toc.core.IMarkdownTocText; 7 | import com.github.houbb.markdown.toc.core.MarkdownTocTextContext; 8 | import com.github.houbb.markdown.toc.support.IncreaseMap; 9 | import com.github.houbb.markdown.toc.support.codeblock.ICodeBlock; 10 | import com.github.houbb.markdown.toc.support.codeblock.impl.AtxCodeBlock; 11 | import com.github.houbb.markdown.toc.vo.TocVo; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.LinkedList; 16 | import java.util.List; 17 | 18 | /** 19 | * @author binbin.hou 20 | * @since 1.1.0 21 | */ 22 | public class AtxMarkdownTocText implements IMarkdownTocText { 23 | 24 | /** 25 | * 配置信息 26 | * @since 1.0.5 27 | */ 28 | private final MarkdownTocTextContext context; 29 | 30 | /** 31 | * toc str列表 32 | */ 33 | private List tocStrList = new LinkedList<>(); 34 | 35 | /** 36 | * toc值对象列表 37 | */ 38 | private List tocVoList = new LinkedList<>(); 39 | 40 | /** 41 | * 结果列表 42 | */ 43 | private List resultList = new LinkedList<>(); 44 | 45 | /** 46 | * 上一个节点 47 | */ 48 | private TocVo previous; 49 | 50 | public AtxMarkdownTocText(MarkdownTocTextContext context) { 51 | this.context = context; 52 | } 53 | 54 | @Override 55 | public List getTocList() { 56 | List lines = context.lines(); 57 | 58 | if(CollectionUtil.isEmpty(lines)) { 59 | return resultList; 60 | } 61 | 62 | //2. 所有 toc 行 63 | ICodeBlock codeBlock = AtxCodeBlock.newInstance(); 64 | for (String string : lines) { 65 | // 是否为代码块的处理 66 | codeBlock.put(string); 67 | if(codeBlock.isCodeBlock()) { 68 | continue; 69 | } 70 | 71 | String trim = string.trim(); 72 | if (trim.startsWith(TocConstant.ASTERISK)) { 73 | tocStrList.add(trim); 74 | } 75 | } 76 | 77 | //3. 构建 tocVo 78 | //3.1 创建一个自增 map,用来处理重复名称 79 | IncreaseMap increaseMap = new IncreaseMap(); 80 | 81 | TocVo root = TocVo.rootToc(increaseMap); 82 | root.setParent(null); 83 | //初始化根节点 84 | tocVoList.add(root); 85 | previous = root; 86 | for (String string : tocStrList) { 87 | addNewToc(string, increaseMap); 88 | } 89 | 90 | //4. 展现 91 | showToc(root.getChildren()); 92 | resultList.add(TocConstant.RETURN_LINE); 93 | 94 | return resultList; 95 | } 96 | 97 | /** 98 | * 显示toc 99 | * v1.0.5 开始支持编号,此处默认从1开始。 100 | * @param tocVoList toc值对象列表 101 | */ 102 | private void showToc(List tocVoList) { 103 | if (tocStrList.isEmpty() 104 | || CollectionUtil.isEmpty(tocVoList)) { 105 | return; 106 | } 107 | //v1.0.5 添加编号支持 108 | for (TocVo tocVo : tocVoList) { 109 | this.fillTocVo(tocVo); 110 | final String intent = tocVo.getIndent(); 111 | String tocVoContent = intent + String.format(TocConstant.TOC_FORMAT, 112 | tocVo.getOrderDesc(), tocVo.getTocTitle(), tocVo.getTocHref()); 113 | resultList.add(tocVoContent); 114 | showToc(tocVo.getChildren()); 115 | } 116 | } 117 | 118 | /** 119 | * 填充信息 120 | * @param tocVo 原始对象 121 | */ 122 | private void fillTocVo(TocVo tocVo) { 123 | final int level = tocVo.getLevel(); 124 | 125 | //1. 前缀空格信息处理 126 | StringBuilder prefixBuilder = new StringBuilder(); 127 | for (int i = 0; i < level - 1; i++) { 128 | prefixBuilder.append(TocConstant.TWO_BLANK); 129 | } 130 | tocVo.setIndent(prefixBuilder.toString()); 131 | 132 | //2. 编号处理 133 | if(context.order()) { 134 | // 递归获取对应的编号信息 135 | String orderDesc = buildOrderDesc(tocVo); 136 | tocVo.setOrderDesc(orderDesc); 137 | } else { 138 | tocVo.setOrderDesc(StringUtil.EMPTY); 139 | } 140 | } 141 | 142 | /** 143 | * 递归获取顺序描述 144 | * 1. 依次获取父类的 order,放在一个列表中。 145 | * 2. 终止的条件是当父类为 root 146 | * 3. 列表最后 reverse+用点连接起来。 147 | * @param tocVo 信息 148 | * @return 结果 149 | * @since 1.0.5 150 | */ 151 | private String buildOrderDesc(final TocVo tocVo) { 152 | List orderList = new ArrayList<>(); 153 | orderList.add(tocVo.getOrder()); 154 | 155 | TocVo current = tocVo; 156 | while(current.getLevel() >= 1) { 157 | current = current.getParent(); 158 | if(current.getLevel() >= 1) { 159 | orderList.add(current.getOrder()); 160 | } 161 | } 162 | 163 | Collections.reverse(orderList); 164 | return CollectionUtil.join(orderList, TocConstant.DOT)+StringUtil.BLANK; 165 | } 166 | 167 | /** 168 | * 添加新的toc 169 | * 170 | * @param tocTrimStr toc trim str 171 | */ 172 | private void addNewToc(String tocTrimStr, IncreaseMap increaseMap) { 173 | TocVo current = new TocVo(tocTrimStr, increaseMap); 174 | 175 | //1 级目录 176 | if (current.getLevel() == 1) { 177 | TocVo root = tocVoList.get(0); 178 | current.setParent(root); 179 | //添加到根目录 180 | root.getChildren().add(current); 181 | } else if (current.getLevel() <= previous.getLevel()) { 182 | TocVo previousParent = previous.getParent(); 183 | current.setParent(previousParent); 184 | previousParent.getChildren().add(current); 185 | //上一节点的子节点 186 | } else if (current.getLevel() > previous.getLevel()) { 187 | current.setParent(previous); 188 | previous.getChildren().add(current); 189 | } 190 | // 统一设置 order 信息 1.0.5 191 | // 编号的下标从1开始 192 | TocVo parentToc = current.getParent(); 193 | List childrenList = parentToc.getChildren(); 194 | current.setOrder(childrenList.size()); 195 | 196 | previous = current; 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/exception/MarkdownTocRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.exception; 2 | 3 | import com.github.houbb.markdown.toc.constant.VersionConstant; 4 | 5 | import org.apiguardian.api.API; 6 | 7 | /** 8 | * markdown toc 运行时异常 9 | * @author bbhou 10 | * @version 1.0.0 11 | * @since 1.0.0, 2018/01/30 12 | */ 13 | @API(status = API.Status.MAINTAINED, since = VersionConstant.V_1_0_0) 14 | public class MarkdownTocRuntimeException extends RuntimeException{ 15 | 16 | private static final long serialVersionUID = 2259479890083314622L; 17 | 18 | public MarkdownTocRuntimeException() { 19 | } 20 | 21 | public MarkdownTocRuntimeException(String message) { 22 | super(message); 23 | } 24 | 25 | public MarkdownTocRuntimeException(String message, Throwable cause) { 26 | super(message, cause); 27 | } 28 | 29 | public MarkdownTocRuntimeException(Throwable cause) { 30 | super(cause); 31 | } 32 | 33 | public MarkdownTocRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 34 | super(message, cause, enableSuppression, writableStackTrace); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/I18N.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.support; 7 | 8 | import com.github.houbb.markdown.toc.constant.VersionConstant; 9 | 10 | import org.apiguardian.api.API; 11 | 12 | import java.util.Locale; 13 | import java.util.ResourceBundle; 14 | 15 | /** 16 | *

i18n 编码支持

17 | * 18 | *
 Created: 2018/7/28 下午4:53  
19 | *
 Project: markdown-toc  
20 | * 21 | * @author houbinbin 22 | * @version 1.0.3 23 | * @since 1.0.3, 2018-07-28 16:53:13 24 | */ 25 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_3) 26 | public final class I18N { 27 | 28 | /** 29 | * 默认的配置文件 30 | */ 31 | private static final String DEFAULT_PROPERTIES_FILE_NAME = "i18n.MarkdownToc"; 32 | 33 | /** 34 | * 获取属性的值 35 | * @param key 键值 36 | * @return 属性 I18n 37 | */ 38 | public static String get(final String key) { 39 | Locale currentLocale = Locale.getDefault(); 40 | ResourceBundle myResources = ResourceBundle.getBundle(DEFAULT_PROPERTIES_FILE_NAME, currentLocale); 41 | return myResources.getString(key); 42 | } 43 | 44 | /** 45 | * 固定的键值标识 46 | */ 47 | public static class Key { 48 | 49 | /** 50 | * 文件路径必须为目录 51 | */ 52 | public static final String pathIsNotDirectory = "pathIsNotDirectory"; 53 | 54 | /** 55 | * 文件路径不可为空 56 | */ 57 | public static final String pathIsNotAllowEmpty = "pathIsNotAllowEmpty"; 58 | 59 | /** 60 | * 只支持 markdown 文件 61 | */ 62 | public static final String onlySupportMdFile = "onlySupportMdFile"; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/IncreaseMap.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.support; 2 | 3 | import com.github.houbb.heaven.util.lang.SpecialCharUtil; 4 | import com.github.houbb.heaven.util.lang.StringUtil; 5 | import com.github.houbb.markdown.toc.constant.TocConstant; 6 | import com.github.houbb.markdown.toc.constant.VersionConstant; 7 | 8 | import org.apiguardian.api.API; 9 | 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | import java.util.concurrent.atomic.AtomicInteger; 13 | 14 | /** 15 | * 增量 map 16 | * @author houbinbin 17 | * @since 1.0.0 18 | */ 19 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0) 20 | public class IncreaseMap { 21 | 22 | private Map map = new ConcurrentHashMap<>(); 23 | 24 | /** 25 | * 构建确切的名称 26 | * @param originalName 原始名称 27 | * @return 最后的构建结果 28 | */ 29 | public String buildActualName(final String originalName) { 30 | String actualName; 31 | String tocHref = getTocHref(originalName); 32 | AtomicInteger value = map.get(tocHref); 33 | if(value != null) { 34 | int count = value.incrementAndGet(); 35 | actualName = TocConstant.ASTERISK+tocHref+TocConstant.MINUS+count; 36 | } else { 37 | AtomicInteger one = new AtomicInteger(0); 38 | map.put(tocHref, one); 39 | actualName = TocConstant.ASTERISK+tocHref; 40 | } 41 | return actualName; 42 | } 43 | 44 | /** 45 | * 对于首字母如果是 46 | * @param tocTitle toc 标题 47 | * @return 对应的连接名称 48 | */ 49 | private static String getTocHref(final String tocTitle) { 50 | if(StringUtil.isEmpty(tocTitle)) { 51 | return tocTitle; 52 | } 53 | 54 | //1. GITHUB 对于大写的处理 55 | String result = tocTitle.toLowerCase(); 56 | 57 | //2. GITHUB 对于空格的处理 58 | result = result.replace(' ', '-'); 59 | 60 | //3. 对于特殊字符的处理 61 | return SpecialCharUtil.filterSpecial(result); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/codeblock/ICodeBlock.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.support.codeblock; 2 | 3 | /** 4 | * 代码块接口 5 | * @author binbin.hou 6 | * @since 1.0.7 7 | */ 8 | public interface ICodeBlock { 9 | 10 | /** 11 | * 是否为代码块 12 | * @return 是否 13 | */ 14 | boolean isCodeBlock(); 15 | 16 | /** 17 | * 添加内容 18 | * @param newLine 新的一行内容 19 | */ 20 | void put(final String newLine); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/codeblock/impl/AtxCodeBlock.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.support.codeblock.impl; 2 | 3 | import com.github.houbb.heaven.util.lang.StringUtil; 4 | import com.github.houbb.markdown.toc.constant.TocConstant; 5 | import com.github.houbb.markdown.toc.support.codeblock.ICodeBlock; 6 | 7 | import java.util.Stack; 8 | 9 | /** 10 | * 注意: 11 | * (1)此处只考虑 ``` 开头的情况,不处理 tab 键对应的代码块。 12 | * (2)如果上一行为空行,或者不存在,且本行以 4 个空格开头,则认为也是代码块。 13 | * @author binbin.hou 14 | * @since 1.0.7 15 | */ 16 | public class AtxCodeBlock implements ICodeBlock { 17 | 18 | /** 19 | * 上一行的内容 20 | */ 21 | private String previous = ""; 22 | 23 | /** 24 | * 本行的内容 25 | */ 26 | private String current = ""; 27 | 28 | /** 29 | * 代码块栈信息 30 | * (1)``` 开头或者 ```XXXX 入栈 31 | * (2)再次遇到 ```,则出栈 32 | * 33 | * 如果,栈内信息为空,则认为是普通信息。 34 | * 如果栈内信息不为空,则认为是代码块信息。 35 | */ 36 | private Stack codeBlockStack = new Stack<>(); 37 | 38 | /** 39 | * 创建新的实例 40 | * @return 实例 41 | */ 42 | public static AtxCodeBlock newInstance() { 43 | return new AtxCodeBlock(); 44 | } 45 | 46 | @Override 47 | public boolean isCodeBlock() { 48 | //1. 空格型的 code block 49 | if(isCodeBlockLine(current)) { 50 | return true; 51 | } 52 | 53 | //2. 根据栈的信息 54 | return !codeBlockStack.isEmpty(); 55 | } 56 | 57 | /** 58 | * 1. 设置当前信息,保留上一行的信息 59 | * 2. 进行 stack 的判断 60 | * 61 | * 2.0 如果为代码块行,直接跳过 62 | * 2.1 stack 为空 63 | * ``` 开头,则入栈 64 | * 2.2 stack 不为空 65 | * 只有信息等于 ```,将 stack 信息出栈 66 | * @param newLine 新的一行内容 67 | */ 68 | @Override 69 | public void put(String newLine) { 70 | previous = current; 71 | current = newLine; 72 | 73 | //1. 代码块行 74 | if(isCodeBlockLine(current)) { 75 | return; 76 | } 77 | 78 | final String currentTrim = current.trim(); 79 | //2. stack 为空 80 | if(codeBlockStack.isEmpty() 81 | && currentTrim.startsWith(TocConstant.MD_CODE_BLOCK)) { 82 | codeBlockStack.push(current); 83 | return; 84 | } 85 | //3. stack 不为空 86 | if(!codeBlockStack.isEmpty() 87 | && TocConstant.MD_CODE_BLOCK.equals(currentTrim)) { 88 | codeBlockStack.pop(); 89 | return; 90 | } 91 | } 92 | 93 | /** 94 | * 是否为代码块行 95 | * @param current 当前内容 96 | * @return 是否 97 | */ 98 | private boolean isCodeBlockLine(final String current) { 99 | if(StringUtil.isEmpty(previous.trim()) 100 | && current.startsWith(TocConstant.FOUR_BLANK)) { 101 | return true; 102 | } 103 | return false; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/md/MarkdownContentToc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.support.md; 7 | 8 | import com.github.houbb.markdown.toc.constant.VersionConstant; 9 | 10 | import org.apiguardian.api.API; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | *

单个文件生成接口

16 | * 17 | *
 Created: 2018/7/27 下午2:53  
18 | *
 Project: markdown-toc  
19 | * 20 | * @author houbinbin 21 | */ 22 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_4) 23 | public interface MarkdownContentToc { 24 | 25 | /** 26 | * 获取纯净的 toc 列表 27 | * @param contentLines 文件内容 28 | * @return 生成的结果信息 29 | * @since 1.0.5 调整接口名称 30 | */ 31 | List getPureTocList(final List contentLines); 32 | 33 | /** 34 | * 获取纯净的内容列表。 35 | * 1. 排除掉 toc 信息 36 | * @param contentLines 原始内容 37 | * @return 过滤掉 toc 后的内容列表 38 | * @since 1.0.5 调整接口名称 39 | */ 40 | List getPureContentList(final List contentLines); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/md/MarkdownFileToc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.support.md; 7 | 8 | import com.github.houbb.markdown.toc.constant.VersionConstant; 9 | import com.github.houbb.markdown.toc.vo.TocGen; 10 | import com.github.houbb.markdown.toc.vo.config.TocConfig; 11 | 12 | import org.apiguardian.api.API; 13 | 14 | /** 15 | *

单个文件生成接口

16 | * 17 | *
 Created: 2018/7/27 下午2:53  
18 | *
 Project: markdown-toc  
19 | * 20 | * @author houbinbin 21 | */ 22 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0) 23 | public interface MarkdownFileToc { 24 | 25 | /** 26 | * 生成单个文件的 toc 27 | * @param filePath 文件路径 28 | * @param config 生成配置 29 | * @return 生成的结果信息 30 | */ 31 | TocGen genTocFile(final String filePath, final TocConfig config); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/md/impl/AtxMarkdownContentToc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.support.md.impl; 7 | 8 | import com.github.houbb.heaven.util.lang.StringUtil; 9 | import com.github.houbb.heaven.util.util.CollectionUtil; 10 | import com.github.houbb.markdown.toc.constant.TocConstant; 11 | import com.github.houbb.markdown.toc.constant.VersionConstant; 12 | import com.github.houbb.markdown.toc.support.IncreaseMap; 13 | import com.github.houbb.markdown.toc.support.codeblock.ICodeBlock; 14 | import com.github.houbb.markdown.toc.support.codeblock.impl.AtxCodeBlock; 15 | import com.github.houbb.markdown.toc.support.md.MarkdownContentToc; 16 | import com.github.houbb.markdown.toc.vo.TocVo; 17 | import com.github.houbb.markdown.toc.vo.config.TocConfig; 18 | import org.apiguardian.api.API; 19 | 20 | import java.util.*; 21 | 22 | /** 23 | *

ATX 根据内容返回目录

24 | * 25 | *
 Created: 2018/8/15 下午2:53  
26 | *
 Project: markdown-toc  
27 | * 28 | * @author houbinbin 29 | */ 30 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_4) 31 | public class AtxMarkdownContentToc implements MarkdownContentToc { 32 | 33 | //region 内部属性 34 | 35 | /** 36 | * 配置信息 37 | * @since 1.0.5 38 | */ 39 | private final TocConfig config; 40 | 41 | /** 42 | * toc str列表 43 | */ 44 | private List tocStrList = new LinkedList<>(); 45 | 46 | /** 47 | * toc值对象列表 48 | */ 49 | private List tocVoList = new LinkedList<>(); 50 | 51 | /** 52 | * 结果列表 53 | */ 54 | private List resultList = new LinkedList<>(); 55 | 56 | /** 57 | * 上一个节点 58 | */ 59 | private TocVo previous; 60 | 61 | public AtxMarkdownContentToc(TocConfig config) { 62 | this.config = config; 63 | } 64 | //endregion 65 | 66 | @Override 67 | public List getPureTocList(List contentLines) { 68 | if (CollectionUtil.isEmpty(contentLines)) { 69 | return Collections.emptyList(); 70 | } 71 | 72 | return buildTocList(contentLines); 73 | } 74 | 75 | @Override 76 | public List getPureContentList(List contentLines) { 77 | List resultList = new LinkedList<>(contentLines); 78 | 79 | //原先的目录过滤 80 | String firstLine = resultList.get(0); 81 | if (firstLine.startsWith(this.config.getTocHead())) { 82 | Iterator stringIterator = resultList.iterator(); 83 | //开头 84 | nextAndRemove(stringIterator, 2); 85 | while (stringIterator.hasNext()) { 86 | String contentTrim = stringIterator.next().trim(); 87 | if (contentTrim.startsWith(TocConstant.STAR)) { 88 | stringIterator.remove(); 89 | } else { 90 | //直接跳出循环 91 | break; 92 | } 93 | } 94 | //移除当前换行 95 | if (stringIterator.hasNext()) { 96 | stringIterator.remove(); 97 | } 98 | //最后的换行 99 | nextAndRemove(stringIterator, 1); 100 | } 101 | 102 | return resultList; 103 | } 104 | 105 | /** 106 | * 构建目录列表 107 | * v1.0.7 修复 bug:当 # 放在代码块中,则不认为是标题信息。 108 | * @param contentList 内容列表 109 | * @return 目录列表 110 | */ 111 | private List buildTocList(final List contentList) { 112 | if (CollectionUtil.isEmpty(contentList)) { 113 | return Collections.emptyList(); 114 | } 115 | 116 | //1. ATX 默认文件头 117 | String tocHead = config.getTocHead(); 118 | if (StringUtil.isNotEmpty(tocHead)) { 119 | resultList.add(tocHead + TocConstant.RETURN_LINE); 120 | } 121 | 122 | //2. 所有 toc 行 123 | ICodeBlock codeBlock = AtxCodeBlock.newInstance(); 124 | for (String string : contentList) { 125 | // 是否为代码块的处理 126 | codeBlock.put(string); 127 | if(codeBlock.isCodeBlock()) { 128 | continue; 129 | } 130 | 131 | String trim = string.trim(); 132 | if (trim.startsWith(TocConstant.ASTERISK)) { 133 | tocStrList.add(trim); 134 | } 135 | } 136 | 137 | //3. 构建 tocVo 138 | //3.1 创建一个自增 map,用来处理重复名称 139 | IncreaseMap increaseMap = new IncreaseMap(); 140 | 141 | TocVo root = TocVo.rootToc(increaseMap); 142 | root.setParent(null); 143 | //初始化根节点 144 | tocVoList.add(root); 145 | previous = root; 146 | for (String string : tocStrList) { 147 | addNewToc(string, increaseMap); 148 | } 149 | 150 | //4. 展现 151 | showToc(root.getChildren()); 152 | resultList.add(TocConstant.RETURN_LINE); 153 | 154 | return resultList; 155 | } 156 | 157 | 158 | /** 159 | * 显示toc 160 | * v1.0.5 开始支持编号,此处默认从1开始。 161 | * @param tocVoList toc值对象列表 162 | */ 163 | private void showToc(List tocVoList) { 164 | if (tocStrList.isEmpty() 165 | || CollectionUtil.isEmpty(tocVoList)) { 166 | return; 167 | } 168 | //v1.0.5 添加编号支持 169 | for (TocVo tocVo : tocVoList) { 170 | this.fillTocVo(tocVo); 171 | final String intent = tocVo.getIndent(); 172 | String tocVoContent = intent + String.format(TocConstant.TOC_FORMAT, 173 | tocVo.getOrderDesc(), tocVo.getTocTitle(), tocVo.getTocHref()); 174 | resultList.add(tocVoContent); 175 | showToc(tocVo.getChildren()); 176 | } 177 | } 178 | 179 | /** 180 | * 填充信息 181 | * @param tocVo 原始对象 182 | */ 183 | private void fillTocVo(TocVo tocVo) { 184 | final int level = tocVo.getLevel(); 185 | 186 | //1. 前缀空格信息处理 187 | StringBuilder prefixBuilder = new StringBuilder(); 188 | for (int i = 0; i < level - 1; i++) { 189 | prefixBuilder.append(TocConstant.TWO_BLANK); 190 | } 191 | tocVo.setIndent(prefixBuilder.toString()); 192 | 193 | //2. 编号处理 194 | if(config.isOrder()) { 195 | // 递归获取对应的编号信息 196 | String orderDesc = buildOrderDesc(tocVo); 197 | tocVo.setOrderDesc(orderDesc); 198 | } else { 199 | tocVo.setOrderDesc(StringUtil.EMPTY); 200 | } 201 | } 202 | 203 | /** 204 | * 递归获取顺序描述 205 | * 1. 依次获取父类的 order,放在一个列表中。 206 | * 2. 终止的条件是当父类为 root 207 | * 3. 列表最后 reverse+用点连接起来。 208 | * @param tocVo 信息 209 | * @return 结果 210 | * @since 1.0.5 211 | */ 212 | private String buildOrderDesc(final TocVo tocVo) { 213 | List orderList = new ArrayList<>(); 214 | orderList.add(tocVo.getOrder()); 215 | 216 | TocVo current = tocVo; 217 | while(current.getLevel() >= 1) { 218 | current = current.getParent(); 219 | if(current.getLevel() >= 1) { 220 | orderList.add(current.getOrder()); 221 | } 222 | } 223 | 224 | Collections.reverse(orderList); 225 | return CollectionUtil.join(orderList, TocConstant.DOT)+StringUtil.BLANK; 226 | } 227 | 228 | /** 229 | * 下一个并且移除元素 230 | * 231 | * @param stringIterator 迭代 232 | * @param times 次数 233 | */ 234 | private void nextAndRemove(Iterator stringIterator, int times) { 235 | for (int i = 0; i < times; i++) { 236 | if (stringIterator.hasNext()) { 237 | String content = stringIterator.next(); 238 | stringIterator.remove(); 239 | } 240 | } 241 | } 242 | 243 | /** 244 | * 添加新的toc 245 | * 246 | * @param tocTrimStr toc trim str 247 | */ 248 | private void addNewToc(String tocTrimStr, IncreaseMap increaseMap) { 249 | TocVo current = new TocVo(tocTrimStr, increaseMap); 250 | 251 | //1 级目录 252 | if (current.getLevel() == 1) { 253 | TocVo root = tocVoList.get(0); 254 | current.setParent(root); 255 | //添加到根目录 256 | root.getChildren().add(current); 257 | } else if (current.getLevel() <= previous.getLevel()) { 258 | TocVo previousParent = previous.getParent(); 259 | current.setParent(previousParent); 260 | previousParent.getChildren().add(current); 261 | //上一节点的子节点 262 | } else if (current.getLevel() > previous.getLevel()) { 263 | current.setParent(previous); 264 | previous.getChildren().add(current); 265 | } 266 | // 统一设置 order 信息 1.0.5 267 | // 编号的下标从1开始 268 | TocVo parentToc = current.getParent(); 269 | List childrenList = parentToc.getChildren(); 270 | current.setOrder(childrenList.size()); 271 | 272 | previous = current; 273 | } 274 | 275 | } 276 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/support/md/impl/AtxMarkdownFileToc.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.support.md.impl; 7 | 8 | import com.github.houbb.heaven.util.io.FileUtil; 9 | import com.github.houbb.markdown.toc.constant.VersionConstant; 10 | import com.github.houbb.markdown.toc.exception.MarkdownTocRuntimeException; 11 | import com.github.houbb.markdown.toc.support.I18N; 12 | import com.github.houbb.markdown.toc.support.md.MarkdownContentToc; 13 | import com.github.houbb.markdown.toc.support.md.MarkdownFileToc; 14 | import com.github.houbb.markdown.toc.vo.TocGen; 15 | import com.github.houbb.markdown.toc.vo.config.TocConfig; 16 | 17 | import org.apiguardian.api.API; 18 | 19 | import java.io.IOException; 20 | import java.nio.file.Files; 21 | import java.nio.file.Path; 22 | import java.nio.file.Paths; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | *

ATX 单个文件生成

28 | * 29 | *
 Created: 2018/7/27 下午2:53  
30 | *
 Project: markdown-toc  
31 | * 32 | * @author houbinbin 33 | */ 34 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0) 35 | public class AtxMarkdownFileToc implements MarkdownFileToc { 36 | 37 | @Override 38 | public TocGen genTocFile(String filePath, TocConfig config) { 39 | Path path = Paths.get(filePath); 40 | return genTocForFile(path, config); 41 | } 42 | 43 | /** 44 | * 为单个文件生成 toc 45 | * 46 | * 1. 这里锁需要进行优化 47 | * 2. 粒度可以更加细致 48 | * @param path 文件路径 49 | * @param config 配置 50 | */ 51 | private TocGen genTocForFile(final Path path, TocConfig config) { 52 | try { 53 | MarkdownContentToc markdownContentToc = new AtxMarkdownContentToc(config); 54 | 55 | //1. 校验文件后缀 56 | if(!FileUtil.isMdFile(path.toString())) { 57 | throw new MarkdownTocRuntimeException(I18N.get(I18N.Key.onlySupportMdFile)); 58 | } 59 | 60 | //2. 获取 toc 列表 61 | List contentList = Files.readAllLines(path, config.getCharset()); 62 | List trimTocContentList = markdownContentToc.getPureContentList(contentList); 63 | List tocList = markdownContentToc.getPureTocList(trimTocContentList); 64 | 65 | //3. 回写 66 | TocGen tocGen = new TocGen(path.toString(), tocList); 67 | if(config.isWrite()) { 68 | // 构建新的回写内容 69 | List resultList = new ArrayList<>(tocList); 70 | resultList.addAll(trimTocContentList); 71 | 72 | Files.write(path, resultList, config.getCharset()); 73 | } 74 | return tocGen; 75 | } catch (IOException e) { 76 | throw new MarkdownTocRuntimeException(e); 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/util/MdTocTextHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.util; 2 | 3 | import com.github.houbb.markdown.toc.core.IMarkdownTocText; 4 | import com.github.houbb.markdown.toc.core.MarkdownTocTextContext; 5 | import com.github.houbb.markdown.toc.core.impl.AtxMarkdownTocText; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 文本帮助类 11 | * @author binbin.hou 12 | * @since 1.1.0 13 | */ 14 | public final class MdTocTextHelper { 15 | 16 | /** 17 | * 获取头信息 18 | * @param lines 行 19 | * @return 结果 20 | * @since 1.1.0 21 | */ 22 | public static List getTocList(final List lines) { 23 | return getTocList(lines, false); 24 | } 25 | 26 | /** 27 | * 获取目录信息 28 | * @param lines 行 29 | * @param orderNum 编号 30 | * @return 结果 31 | * @since 1.1.0 32 | */ 33 | public static List getTocList(final List lines, boolean orderNum) { 34 | MarkdownTocTextContext context = new MarkdownTocTextContext(); 35 | context.lines(lines).order(orderNum); 36 | 37 | IMarkdownTocText tocText = new AtxMarkdownTocText(context); 38 | 39 | return tocText.getTocList(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/util/ThreadLocalUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.util; 7 | 8 | import com.github.houbb.markdown.toc.constant.VersionConstant; 9 | import com.github.houbb.markdown.toc.support.md.MarkdownFileToc; 10 | import com.github.houbb.markdown.toc.support.md.impl.AtxMarkdownFileToc; 11 | import com.github.houbb.markdown.toc.vo.TocGen; 12 | import com.github.houbb.markdown.toc.vo.config.TocConfig; 13 | 14 | import org.apiguardian.api.API; 15 | 16 | /** 17 | *

threadlocal 工具类

18 | * 19 | *
 Created: 2018/7/27 下午6:49  
20 | *
 Project: markdown-toc  
21 | * 22 | * @author houbinbin 23 | * @version 1.0 24 | * @since JDK 1.7 25 | */ 26 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0) 27 | public class ThreadLocalUtil { 28 | 29 | /** 30 | * @since 1.0.8 31 | */ 32 | private ThreadLocalUtil(){} 33 | 34 | /** 35 | * 用于保存当前线程的信息 36 | */ 37 | private static final ThreadLocal FILE_TOC_THREAD_LOCAL = new ThreadLocal<>(); 38 | 39 | /** 40 | * 生成文件 41 | * @param filePath 文件路径 42 | * @param tocConfig 配置信息 43 | * @return 目录结构 44 | */ 45 | public static TocGen genTocFile(final String filePath, TocConfig tocConfig) { 46 | MarkdownFileToc fileToc = getMarkdownFileToc(); 47 | return fileToc.genTocFile(filePath, tocConfig); 48 | } 49 | 50 | /** 51 | * 清空 52 | * 1. 建议在每个线程执行结束,调用 53 | */ 54 | public static void clear() { 55 | FILE_TOC_THREAD_LOCAL.remove(); 56 | } 57 | 58 | /** 59 | * 使用 threadLocal 获取分词器对象 60 | * @return 当前线程的分词器 61 | */ 62 | private static MarkdownFileToc getMarkdownFileToc() { 63 | MarkdownFileToc fileToc = FILE_TOC_THREAD_LOCAL.get(); 64 | if(null == fileToc) { 65 | fileToc = new AtxMarkdownFileToc(); 66 | FILE_TOC_THREAD_LOCAL.set(fileToc); 67 | } 68 | return fileToc; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/vo/TocGen.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.vo; 7 | 8 | import com.github.houbb.markdown.toc.constant.VersionConstant; 9 | 10 | import org.apiguardian.api.API; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | *  toc 内容 16 | * 17 | * @author bbhou 18 | * @version 1.0.0 19 | * @since 1.0.0, 2018/01/30 20 | */ 21 | @API(status = API.Status.MAINTAINED, since = VersionConstant.V_1_0_0) 22 | public class TocGen { 23 | 24 | /** 25 | * 文件路径 26 | */ 27 | private final String filePath; 28 | 29 | /** 30 | * toc 的相关内容 31 | */ 32 | private final List tocLines; 33 | 34 | public TocGen(String filePath, List tocLines) { 35 | this.filePath = filePath; 36 | this.tocLines = tocLines; 37 | } 38 | 39 | public String getFilePath() { 40 | return filePath; 41 | } 42 | 43 | public List getTocLines() { 44 | return tocLines; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "TocGen{" + 50 | "filePath='" + filePath + '\'' + 51 | ", tocLines=" + tocLines + 52 | '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/vo/TocVo.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.vo; 2 | 3 | import com.github.houbb.markdown.toc.constant.VersionConstant; 4 | import com.github.houbb.markdown.toc.support.IncreaseMap; 5 | 6 | import org.apiguardian.api.API; 7 | 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | /** 12 | *  toc值对象 13 | * 14 | * @author bbhou 15 | * @version 1.0.0 16 | * @since 1.0.0, 2018/01/30 17 | */ 18 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0) 19 | public class TocVo { 20 | /** 21 | * ROOT 节点名称 22 | */ 23 | private static final String ROOT_NAME = "ROOT"; 24 | 25 | /** 26 | * 起源 27 | */ 28 | private String origin; 29 | 30 | /** 31 | * 水平 32 | */ 33 | private int level; 34 | 35 | /** 36 | * toc标题 37 | */ 38 | private String tocTitle; 39 | 40 | /** 41 | * toc href 42 | */ 43 | private String tocHref; 44 | 45 | /** 46 | * 父节点 47 | */ 48 | private TocVo parent; 49 | 50 | /** 51 | * 孩子 52 | */ 53 | private List children = new LinkedList<>(); 54 | 55 | /** 56 | * 自增 MAP 57 | */ 58 | private final IncreaseMap increaseMap; 59 | 60 | /** 61 | * 编号序号 62 | * @since 1.0.5 63 | */ 64 | private int order; 65 | 66 | /** 67 | * 编号序号 68 | * @since 1.0.5 69 | */ 70 | private String orderDesc; 71 | 72 | /** 73 | * 空格缩进 74 | * @since 1.0.5 75 | */ 76 | private String indent; 77 | 78 | /** 79 | *  toc值对象 80 | * 81 | * @param origin 起源 82 | * @param increaseMap map 83 | */ 84 | public TocVo(String origin, IncreaseMap increaseMap) { 85 | this.origin = origin; 86 | this.increaseMap = increaseMap; 87 | init(); 88 | } 89 | 90 | /** 91 | * 初始化 92 | */ 93 | private void init() { 94 | if (ROOT_NAME.equals(this.origin)) { 95 | return; 96 | } 97 | 98 | String[] strings = this.origin.split("\\s+"); 99 | this.tocTitle = this.origin.substring(strings[0].length()).trim(); 100 | this.tocHref = increaseMap.buildActualName(tocTitle); 101 | this.level = strings[0].length(); 102 | } 103 | 104 | /** 105 | * 根源toc 106 | * 107 | * @param increaseMap map 集合 108 | * @return com.github.houbb.markdown.toc.vo.TocVo 109 | */ 110 | public static TocVo rootToc(IncreaseMap increaseMap) { 111 | TocVo tocVo = new TocVo(ROOT_NAME, increaseMap); 112 | tocVo.setLevel(0); 113 | return tocVo; 114 | } 115 | 116 | 117 | /** 118 | * 得到起源 119 | * 120 | * @return java.lang.String 121 | */ 122 | public String getOrigin() { 123 | return origin; 124 | } 125 | 126 | /** 127 | * 设置原点 128 | * 129 | * @param origin 起源 130 | */ 131 | public void setOrigin(String origin) { 132 | this.origin = origin; 133 | } 134 | 135 | /** 136 | * 得到水平 137 | * 138 | * @return int 139 | */ 140 | public int getLevel() { 141 | return level; 142 | } 143 | 144 | /** 145 | * 设定等级 146 | * 147 | * @param level 水平 148 | */ 149 | public void setLevel(int level) { 150 | this.level = level; 151 | } 152 | 153 | /** 154 | * 得到toc标题 155 | * 156 | * @return java.lang.String 157 | */ 158 | public String getTocTitle() { 159 | return tocTitle; 160 | } 161 | 162 | /** 163 | * 设置toc标题 164 | * 165 | * @param tocTitle toc标题 166 | */ 167 | public void setTocTitle(String tocTitle) { 168 | this.tocTitle = tocTitle; 169 | } 170 | 171 | /** 172 | * 得到toc href 173 | * 174 | * @return java.lang.String 175 | */ 176 | public String getTocHref() { 177 | return tocHref; 178 | } 179 | 180 | /** 181 | * 设置为hc 182 | * 183 | * @param tocHref toc href 184 | */ 185 | public void setTocHref(String tocHref) { 186 | this.tocHref = tocHref; 187 | } 188 | 189 | /** 190 | * 得到孩子 191 | * 192 | * @return java.util.List 193 | */ 194 | public List getChildren() { 195 | return children; 196 | } 197 | 198 | /** 199 | * 设置孩子 200 | * 201 | * @param children 孩子 202 | */ 203 | public void setChildren(List children) { 204 | this.children = children; 205 | } 206 | 207 | /** 208 | * 得到父母 209 | * 210 | * @return com.github.houbb.markdown.toc.vo.TocVo 211 | */ 212 | public TocVo getParent() { 213 | return parent; 214 | } 215 | 216 | /** 217 | * 设置父母 218 | * 219 | * @param parent 亲 220 | */ 221 | public void setParent(TocVo parent) { 222 | this.parent = parent; 223 | } 224 | 225 | public int getOrder() { 226 | return order; 227 | } 228 | 229 | public void setOrder(int order) { 230 | this.order = order; 231 | } 232 | 233 | public String getOrderDesc() { 234 | return orderDesc; 235 | } 236 | 237 | public void setOrderDesc(String orderDesc) { 238 | this.orderDesc = orderDesc; 239 | } 240 | 241 | public String getIndent() { 242 | return indent; 243 | } 244 | 245 | public void setIndent(String indent) { 246 | this.indent = indent; 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/main/java/com/github/houbb/markdown/toc/vo/config/TocConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.vo.config; 7 | 8 | import com.github.houbb.markdown.toc.constant.VersionConstant; 9 | 10 | import org.apiguardian.api.API; 11 | 12 | import java.nio.charset.Charset; 13 | 14 | /** 15 | *

配置文件

16 | * 17 | *
 Created: 2018/7/27 下午2:58  
18 | *
 Project: markdown-toc  
19 | * 20 | * @author houbinbin 21 | * @since 1.0.5 进行调整 22 | */ 23 | @API(status = API.Status.INTERNAL, since = VersionConstant.V_1_0_0) 24 | public class TocConfig { 25 | 26 | /** 27 | * 编码(默认为utf-8) 28 | */ 29 | private Charset charset; 30 | 31 | /** 32 | * 是否包含子文件夹下的文件(默认为包含) 33 | */ 34 | private boolean subTree; 35 | 36 | /** 37 | * 是否写入到文件(默认写入) 38 | */ 39 | private boolean write; 40 | 41 | /** 42 | * 是否添加编号 43 | * ps: 此处不再使用 immutable 模式,直接 getter/setter 处理 44 | * @since 1.0.5 45 | */ 46 | private boolean order; 47 | 48 | /** 49 | * 头信息 50 | * @since 1.2.0 51 | */ 52 | private String tocHead; 53 | 54 | public Charset getCharset() { 55 | return charset; 56 | } 57 | 58 | public void setCharset(Charset charset) { 59 | this.charset = charset; 60 | } 61 | 62 | public boolean isSubTree() { 63 | return subTree; 64 | } 65 | 66 | public void setSubTree(boolean subTree) { 67 | this.subTree = subTree; 68 | } 69 | 70 | public boolean isWrite() { 71 | return write; 72 | } 73 | 74 | public void setWrite(boolean write) { 75 | this.write = write; 76 | } 77 | 78 | public boolean isOrder() { 79 | return order; 80 | } 81 | 82 | public void setOrder(boolean order) { 83 | this.order = order; 84 | } 85 | 86 | public String getTocHead() { 87 | return tocHead; 88 | } 89 | 90 | public void setTocHead(String tocHead) { 91 | this.tocHead = tocHead; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/resources/i18n/MarkdownToc.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018. houbinbin Inc. 3 | # markdown-toc All rights reserved. 4 | # 5 | 6 | # markdown toc properties file. 7 | 8 | pathIsNotDirectory=%s path is not a directory 9 | 10 | pathIsNotAllowEmpty=Path is not allow empty 11 | 12 | onlySupportMdFile=Only support markdown file 13 | -------------------------------------------------------------------------------- /src/main/resources/i18n/MarkdownToc_en.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018. houbinbin Inc. 3 | # markdown-toc All rights reserved. 4 | # 5 | 6 | # markdown toc properties file. 7 | 8 | pathIsNotDirectory=%s path is not a directory 9 | 10 | pathIsNotAllowEmpty=Path is not allow empty 11 | 12 | onlySupportMdFile=Only support markdown file -------------------------------------------------------------------------------- /src/main/resources/i18n/MarkdownToc_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018. houbinbin Inc. 3 | # markdown-toc All rights reserved. 4 | # 5 | 6 | # markdown toc properties file. 7 | 8 | pathIsNotDirectory=%s \u6587\u4EF6\u8DEF\u5F84\u5FC5\u987B\u662F\u6587\u4EF6\u5939 9 | 10 | pathIsNotAllowEmpty=\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5141\u8BB8\u4E3A\u7A7A 11 | 12 | onlySupportMdFile=\u53EA\u652F\u6301 markdown \u683C\u5F0F\u6587\u4EF6 13 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/constant/TocConstantTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.constant; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * TocConstant Tester. 7 | * 8 | * @author author 9 | * @since 2018-01-30 15:11:47.245 10 | * @version 1.0 11 | */ 12 | public class TocConstantTest { 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/core/MarkdownTocTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.core; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * MarkdownToc Tester. 7 | * 8 | * @author author 9 | * @since 2018-01-30 15:11:47.248 10 | * @version 1.0 11 | */ 12 | public class MarkdownTocTest { 13 | 14 | /** 15 | * 16 | * Method: genToc(url, charset) 17 | */ 18 | @Test 19 | public void genTocTest() throws Exception { 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownI18NTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.core.impl; 7 | 8 | import com.github.houbb.markdown.toc.util.TestPathUtil; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | 12 | import java.util.Locale; 13 | 14 | /** 15 | * AtxMarkdownToc 国家化编码测试 16 | * 17 | * @author author 18 | * @version 1.0 19 | * @since 2018-01-30 15:11:47.256 20 | */ 21 | public class AtxMarkdownI18NTest { 22 | 23 | @Test 24 | public void pathMustDirEnglish() { 25 | try { 26 | Locale.setDefault(new Locale("en", "US")); 27 | String path = TestPathUtil.getAppRootPath("subNotExists"); 28 | AtxMarkdownToc.newInstance() 29 | .genTocDir(path); 30 | } catch (Exception e) { 31 | final String expectedMsg = "D:\\github\\markdown-toc/src/test/resources/subNotExists path is not a directory"; 32 | final String msg = e.getMessage(); 33 | Assert.assertEquals(expectedMsg, msg); 34 | } 35 | } 36 | 37 | @Test 38 | public void pathMustDirChinese() { 39 | try { 40 | Locale.setDefault(new Locale("zh", "CN")); 41 | String path = TestPathUtil.getAppRootPath("subNotExists"); 42 | AtxMarkdownToc.newInstance() 43 | .genTocDir(path); 44 | } catch (Exception e) { 45 | final String expectedMsg = "D:\\github\\markdown-toc/src/test/resources/subNotExists 文件路径必须是文件夹"; 46 | final String msg = e.getMessage(); 47 | Assert.assertEquals(expectedMsg, msg); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocDirTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.core.impl; 7 | 8 | import com.github.houbb.markdown.toc.util.TestPathUtil; 9 | import com.github.houbb.markdown.toc.vo.TocGen; 10 | 11 | import org.junit.Assert; 12 | import org.junit.Test; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * AtxMarkdownToc 文件夹测试 18 | * 19 | * @author author 20 | * @version 1.0 21 | * @since 2018-01-30 15:11:47.256 22 | */ 23 | public class AtxMarkdownTocDirTest { 24 | 25 | /** 26 | * 不包含子元素-测试 27 | */ 28 | @Test 29 | public void notSubTreeTest() { 30 | String path = TestPathUtil.getAppRootPath("sub"); 31 | List tocGens = AtxMarkdownToc.newInstance() 32 | .subTree(false) 33 | .genTocDir(path); 34 | 35 | final int size = tocGens.size(); 36 | Assert.assertEquals(2, size); 37 | } 38 | 39 | /** 40 | * 无 md 文件测试 41 | */ 42 | @Test 43 | public void noMdTest() { 44 | String path = TestPathUtil.getAppRootPath("sub0"); 45 | List tocGens = AtxMarkdownToc.newInstance() 46 | .subTree(false) 47 | .write(false) 48 | .genTocDir(path); 49 | 50 | final int size = tocGens.size(); 51 | Assert.assertEquals(0, size); 52 | } 53 | 54 | /** 55 | * 单 md 文件测试 56 | */ 57 | @Test 58 | public void oneMdTest() { 59 | String path = TestPathUtil.getAppRootPath("sub1"); 60 | List tocGens = AtxMarkdownToc.newInstance() 61 | .subTree(false) 62 | .write(false) 63 | .genTocDir(path); 64 | 65 | final int size = tocGens.size(); 66 | Assert.assertEquals(1, size); 67 | } 68 | 69 | /** 70 | * 普通-测试 71 | * 1. 默认进行文件的递归遍历 72 | */ 73 | @Test 74 | public void commonTest() { 75 | String path = TestPathUtil.getAppRootPath("sub"); 76 | List tocGens = AtxMarkdownToc.newInstance() 77 | .genTocDir(path); 78 | final int size = tocGens.size(); 79 | Assert.assertEquals(6, size); 80 | } 81 | 82 | /** 83 | * 特殊符号测试 84 | */ 85 | @Test 86 | public void specialTest() { 87 | String path = TestPathUtil.getAppRootPath("special"); 88 | List tocGens = AtxMarkdownToc.newInstance() 89 | .subTree(true) 90 | .genTocDir(path); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocFileTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.core.impl; 2 | 3 | import com.github.houbb.markdown.toc.core.MarkdownToc; 4 | import com.github.houbb.markdown.toc.util.TestPathUtil; 5 | import com.github.houbb.markdown.toc.vo.TocGen; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | /** 11 | * AtxMarkdownToc 单个文件测试 12 | * 13 | * @author author 14 | * @version 1.0 15 | * @since 2018-01-30 15:11:47.256 16 | */ 17 | public class AtxMarkdownTocFileTest { 18 | 19 | /** 20 | * 普通-fluent 写法 21 | */ 22 | @Test 23 | public void commonFluentTest() { 24 | String path = TestPathUtil.getAppRootPath("common.md"); 25 | TocGen tocGen = AtxMarkdownToc.newInstance() 26 | .genTocFile(path); 27 | 28 | Assert.assertEquals(8, tocGen.getTocLines().size()); 29 | } 30 | 31 | /** 32 | * 普通-新建接口的方式 33 | */ 34 | @Test 35 | public void commonInterfaceTest() { 36 | String path = TestPathUtil.getAppRootPath("common.md"); 37 | 38 | MarkdownToc markdownToc = new AtxMarkdownToc(); 39 | TocGen tocGen = markdownToc.genTocFile(path); 40 | 41 | Assert.assertEquals(8, tocGen.getTocLines().size()); 42 | } 43 | 44 | /** 45 | * 中文名称测试 46 | */ 47 | @Test 48 | public void chineseFileNameTest() { 49 | String path = TestPathUtil.getAppRootPath("中文名称.md"); 50 | TocGen tocGen = AtxMarkdownToc.newInstance() 51 | .genTocFile(path); 52 | 53 | Assert.assertEquals(10, tocGen.getTocLines().size()); 54 | } 55 | 56 | /** 57 | * 特殊文件编码测试 58 | */ 59 | @Test 60 | public void charsetGbkTest() { 61 | String path = TestPathUtil.getAppRootPath("README-GBK.md"); 62 | TocGen tocGen = AtxMarkdownToc.newInstance() 63 | .charset("GBK") 64 | .genTocFile(path); 65 | 66 | Assert.assertEquals(13, tocGen.getTocLines().size()); 67 | } 68 | 69 | /** 70 | * 不写入文件测试 71 | */ 72 | @Test 73 | public void notWriteTest() { 74 | String path = TestPathUtil.getAppRootPath("common.md"); 75 | 76 | TocGen tocGen = AtxMarkdownToc.newInstance() 77 | .write(false) 78 | .genTocFile(path); 79 | 80 | Assert.assertEquals(8, tocGen.getTocLines().size()); 81 | } 82 | 83 | /** 84 | * 编号测试 85 | */ 86 | @Test 87 | public void orderTest() { 88 | String path = TestPathUtil.getAppRootPath("common.md"); 89 | 90 | TocGen tocGen = AtxMarkdownToc.newInstance() 91 | .order(true) 92 | .genTocFile(path); 93 | 94 | Assert.assertEquals(8, tocGen.getTocLines().size()); 95 | } 96 | 97 | /** 98 | * 多层目录测试 99 | */ 100 | @Test 101 | public void nLevelTest() { 102 | String path = TestPathUtil.getAppRootPath("N-LEVEL.md"); 103 | 104 | TocGen tocGen = AtxMarkdownToc.newInstance() 105 | .genTocFile(path); 106 | 107 | Assert.assertEquals(21, tocGen.getTocLines().size()); 108 | } 109 | 110 | /** 111 | * readme测试 112 | */ 113 | @Test 114 | public void readMeTest() { 115 | String path = TestPathUtil.getAppRootPath("readme/README.md"); 116 | 117 | TocGen tocGen = AtxMarkdownToc.newInstance() 118 | .order(true) 119 | .genTocFile(path); 120 | 121 | Assert.assertEquals(17, tocGen.getTocLines().size()); 122 | } 123 | 124 | /** 125 | * 代码块测试 126 | * @since 1.0.7 127 | */ 128 | @Test 129 | public void codeBlockTest() { 130 | String path = TestPathUtil.getAppRootPath("CODE_BLOCK.md"); 131 | 132 | TocGen tocGen = AtxMarkdownToc.newInstance() 133 | .order(true) 134 | .genTocFile(path); 135 | 136 | Assert.assertEquals(15, tocGen.getTocLines().size()); 137 | } 138 | 139 | /** 140 | * 演示配置测试 141 | */ 142 | @Test 143 | public void justConfigTest() { 144 | AtxMarkdownToc.newInstance() 145 | .charset("UTF-8") 146 | .write(true) 147 | .subTree(true) 148 | .order(true); 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/exception/MarkdownTocRuntimeExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.exception; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * MarkdownTocRuntimeException Tester. 7 | * 8 | * @author author 9 | * @since 2018-01-30 15:11:47.263 10 | * @version 1.0 11 | */ 12 | public class MarkdownTocRuntimeExceptionTest { 13 | 14 | /** 15 | * 16 | * Method: MarkdownTocRuntimeException() 17 | */ 18 | @Test 19 | public void MarkdownTocRuntimeExceptionTest() throws Exception { 20 | } 21 | 22 | /** 23 | * 24 | * Method: MarkdownTocRuntimeException(message) 25 | */ 26 | @Test 27 | public void MarkdownTocRuntimeExceptionMessageTest() throws Exception { 28 | } 29 | 30 | /** 31 | * 32 | * Method: MarkdownTocRuntimeException(message, cause) 33 | */ 34 | @Test 35 | public void MarkdownTocRuntimeExceptionMessageCauseTest() throws Exception { 36 | } 37 | 38 | /** 39 | * 40 | * Method: MarkdownTocRuntimeException(cause) 41 | */ 42 | @Test 43 | public void MarkdownTocRuntimeExceptionCauseTest() throws Exception { 44 | } 45 | 46 | /** 47 | * 48 | * Method: MarkdownTocRuntimeException(message, cause, enableSuppression, writableStackTrace) 49 | */ 50 | @Test 51 | public void MarkdownTocRuntimeExceptionMessageCauseEnableSuppressionWritableStackTraceTest() throws Exception { 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/support/AtxMarkdownContentTocTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.support; 7 | 8 | import com.github.houbb.heaven.util.io.FileUtil; 9 | import com.github.houbb.heaven.util.util.CollectionUtil; 10 | import com.github.houbb.markdown.toc.support.md.MarkdownContentToc; 11 | import com.github.houbb.markdown.toc.support.md.impl.AtxMarkdownContentToc; 12 | import com.github.houbb.markdown.toc.util.TestPathUtil; 13 | import com.github.houbb.markdown.toc.vo.config.TocConfig; 14 | import org.junit.Assert; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | 18 | import java.io.File; 19 | import java.util.List; 20 | 21 | /** 22 | *

atx 内容测试

23 | * 24 | *
 Created: 2018/8/15 下午3:02  
25 | *
 Project: markdown-toc  
26 | * 27 | * @author houbinbin 28 | * @version 1.0 29 | * @since JDK 1.7 30 | */ 31 | public class AtxMarkdownContentTocTest { 32 | 33 | 34 | private MarkdownContentToc markdownContentToc; 35 | 36 | @Before 37 | public void before() { 38 | TocConfig config = new TocConfig(); 39 | markdownContentToc = new AtxMarkdownContentToc(config); 40 | } 41 | 42 | @Test 43 | public void emptyTest() { 44 | List lines = getLines("empty.md"); 45 | List tocs = markdownContentToc.getPureTocList(lines); 46 | Assert.assertTrue(CollectionUtil.isEmpty(tocs)); 47 | } 48 | 49 | @Test 50 | public void emptyContentTest() { 51 | List lines = getLines("empty-content.md"); 52 | List pureLines = markdownContentToc.getPureContentList(lines); 53 | List tocs = markdownContentToc.getPureTocList(pureLines); 54 | Assert.assertTrue(CollectionUtil.isEmpty(tocs)); 55 | } 56 | 57 | @Test 58 | public void commonTest() { 59 | List lines = getLines("common.md"); 60 | List tocs = markdownContentToc.getPureTocList(lines); 61 | 62 | Assert.assertEquals(9, tocs.size()); 63 | showTocs(tocs); 64 | } 65 | 66 | @Test 67 | public void nLevelTest() { 68 | List lines = getLines("N-LEVEL.md"); 69 | List tocs = markdownContentToc.getPureTocList(lines); 70 | 71 | Assert.assertEquals(22, tocs.size()); 72 | showTocs(tocs); 73 | } 74 | 75 | /** 76 | * 代码块测试 77 | * @since 1.0.7 78 | */ 79 | @Test 80 | public void codeBlockTest() { 81 | List lines = getLines("CODE_BLOCK.md"); 82 | List tocs = markdownContentToc.getPureTocList(lines); 83 | 84 | showTocs(tocs); 85 | } 86 | 87 | /** 88 | * 展现目录 89 | * @param tocs toc lines 90 | */ 91 | private void showTocs(final List tocs) { 92 | Assert.assertFalse(CollectionUtil.isEmpty(tocs)); 93 | for(String string : tocs) { 94 | System.out.println(string); 95 | } 96 | } 97 | 98 | /** 99 | * 获取文件内容 100 | * @param filePath 文件路径 101 | * @return 文件内容列表 102 | */ 103 | private List getLines(final String filePath) { 104 | String fullPath = TestPathUtil.getAppRootPath(filePath); 105 | try { 106 | return FileUtil.getFileContentEachLine(new File(fullPath), 0); 107 | } catch (Exception e) { 108 | throw new RuntimeException(e); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/util/MdTocTextHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.util; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * 基本的测试 10 | * 11 | * @since 1.1.0 12 | */ 13 | public class MdTocTextHelperTest { 14 | 15 | @Test 16 | public void helloTest() { 17 | List lines = new ArrayList<>(); 18 | lines.add("# 标题1"); 19 | lines.add("这是一行内容"); 20 | lines.add("# 标题2"); 21 | lines.add("这也是一行内容"); 22 | 23 | List tocList = MdTocTextHelper.getTocList(lines); 24 | foreachPrint(tocList); 25 | } 26 | 27 | @Test 28 | public void orderNumTest() { 29 | List lines = new ArrayList<>(); 30 | lines.add("# 标题1"); 31 | lines.add("这是一行内容"); 32 | lines.add("# 标题2"); 33 | lines.add("这也是一行内容"); 34 | 35 | List tocList = MdTocTextHelper.getTocList(lines, true); 36 | foreachPrint(tocList); 37 | } 38 | 39 | /** 40 | * 循环处理集合 41 | * 42 | * @param tocList 集合 43 | * @since 0.1.93 44 | */ 45 | public static void foreachPrint(List tocList) { 46 | for(String toc : tocList) { 47 | System.out.println(toc); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/util/TestPathUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018. houbinbin Inc. 3 | * markdown-toc All rights reserved. 4 | */ 5 | 6 | package com.github.houbb.markdown.toc.util; 7 | 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | 12 | /** 13 | *

测试路径工具类

14 | * 15 | *
 Created: 2018/7/5 下午2:22  
16 | *
 Project: markdown-toc  
17 | * 18 | * @author houbinbin 19 | * @version 1.0 20 | * @since JDK 1.7 21 | */ 22 | public class TestPathUtil { 23 | 24 | 25 | /** 26 | * 获取项目根路径+测试资源文件路径+XXX 27 | * @param relativeTest 相对路径 28 | * @return 绝对路径 29 | */ 30 | public static String getAppRootPath(final String relativeTest) { 31 | File emptyFile = new File(""); 32 | String root = emptyFile.getAbsolutePath(); 33 | return root+"/src/test/resources/"+relativeTest; 34 | } 35 | 36 | @Test 37 | public void getAppRootPathTest() { 38 | System.out.println(getAppRootPath("common.md")); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/github/houbb/markdown/toc/vo/TocVoTest.java: -------------------------------------------------------------------------------- 1 | package com.github.houbb.markdown.toc.vo; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * TocVo Tester. 7 | * 8 | * @author author 9 | * @since 2018-01-30 15:11:47.253 10 | * @version 1.0 11 | */ 12 | public class TocVoTest { 13 | 14 | /** 15 | * 16 | * Method: TocVo(origin) 17 | */ 18 | @Test 19 | public void TocVoTest() throws Exception { 20 | } 21 | 22 | /** 23 | * 24 | * Method: rootToc() 25 | */ 26 | @Test 27 | public void rootTocTest() throws Exception { 28 | } 29 | 30 | /** 31 | * 32 | * Method: getOrigin() 33 | */ 34 | @Test 35 | public void getOriginTest() throws Exception { 36 | } 37 | 38 | /** 39 | * 40 | * Method: setOrigin(origin) 41 | */ 42 | @Test 43 | public void setOriginTest() throws Exception { 44 | } 45 | 46 | /** 47 | * 48 | * Method: getLevel() 49 | */ 50 | @Test 51 | public void getLevelTest() throws Exception { 52 | } 53 | 54 | /** 55 | * 56 | * Method: setLevel(level) 57 | */ 58 | @Test 59 | public void setLevelTest() throws Exception { 60 | } 61 | 62 | /** 63 | * 64 | * Method: getTocTitle() 65 | */ 66 | @Test 67 | public void getTocTitleTest() throws Exception { 68 | } 69 | 70 | /** 71 | * 72 | * Method: setTocTitle(tocTitle) 73 | */ 74 | @Test 75 | public void setTocTitleTest() throws Exception { 76 | } 77 | 78 | /** 79 | * 80 | * Method: getTocHref() 81 | */ 82 | @Test 83 | public void getTocHrefTest() throws Exception { 84 | } 85 | 86 | /** 87 | * 88 | * Method: setTocHref(tocHref) 89 | */ 90 | @Test 91 | public void setTocHrefTest() throws Exception { 92 | } 93 | 94 | /** 95 | * 96 | * Method: getChildren() 97 | */ 98 | @Test 99 | public void getChildrenTest() throws Exception { 100 | } 101 | 102 | /** 103 | * 104 | * Method: setChildren(children) 105 | */ 106 | @Test 107 | public void setChildrenTest() throws Exception { 108 | } 109 | 110 | /** 111 | * 112 | * Method: getParent() 113 | */ 114 | @Test 115 | public void getParentTest() throws Exception { 116 | } 117 | 118 | /** 119 | * 120 | * Method: setParent(parent) 121 | */ 122 | @Test 123 | public void setParentTest() throws Exception { 124 | } 125 | 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/test/resources/CODE_BLOCK.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * 1 [符号场景测试](#符号场景测试) 4 | * 1.1 [场景 1](#场景-1) 5 | * 1.2 [场景 2](#场景-2) 6 | * 1.3 [场景 3](#场景-3) 7 | * 1.4 [场景 4](#场景-4) 8 | * 1.5 [场景 5](#场景-5) 9 | * 2 [空格的测试场景](#空格的测试场景) 10 | * 2.1 [代码块原则](#代码块原则) 11 | * 2.2 [场景 1](#场景-1-1) 12 | * 2.3 [场景 2](#场景-2-1) 13 | * 3 [混合使用](#混合使用) 14 | * 3.1 [场景 1](#场景-1-2) 15 | * 3.2 [场景 2](#场景-2-2) 16 | 17 | 18 | # 符号场景测试 19 | 20 | @since v1.0.7 21 | 22 | ## 场景 1 23 | 24 | ``` 25 | # code... 26 | ``` 27 | 28 | ## 场景 2 29 | 30 | ```c 31 | # code... 32 | ``` 33 | 34 | ## 场景 3 35 | 36 | ``` 37 | # code... 38 | ```c 39 | ``` 40 | 41 | ## 场景 4 42 | 43 | ```c 44 | # code... 45 | ```c 46 | ``` 47 | 48 | ## 场景 5 49 | 50 | ```c 51 | #三个空格```的测试 52 | ``` 53 | 54 | # 空格的测试场景 55 | 56 | ## 代码块原则 57 | 58 | 上一行空行 59 | 60 | 本行:四个空格开头。 61 | 62 | ## 场景 1 63 | 64 | 第一行 65 | 66 | #第三行是代码 67 | 第四行 68 | 69 | ## 场景 2 70 | 71 | 第一行 72 | 第三行不是代码 73 | 第四行 74 | 75 | # 混合使用 76 | 77 | ## 场景 1 78 | 79 | ```c 80 | #第一行这是代码 81 | # 第二行这是代码 82 | ``` 83 | 84 | ## 场景 2 85 | 86 | ```c 87 | 这不是代码,因为上面的一句被当成代码块处理了。 88 | ``` 89 | ```c 代码块 90 | ``` 91 | -------------------------------------------------------------------------------- /src/test/resources/N-LEVEL.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [N 级深度测试](#n-级深度测试) 4 | * [1级别](#1级别) 5 | * [2 级别](#2-级别) 6 | * [3级别](#3级别) 7 | * [4级别](#4级别) 8 | * [5级别](#5级别) 9 | * [6级别](#6级别) 10 | * [一级别](#一级别) 11 | * [二级别](#二级别) 12 | * [三级别](#三级别) 13 | * [四级别](#四级别) 14 | * [五级别](#五级别) 15 | * [六级别](#六级别) 16 | * [一级别](#一级别-1) 17 | * [二级别](#二级别-1) 18 | * [三级别](#三级别-1) 19 | * [四级别](#四级别-1) 20 | * [五级别](#五级别-1) 21 | * [六级别](#六级别-1) 22 | 23 | 24 | # N 级深度测试 25 | 26 | # 1级别 27 | ## 2 级别 28 | ### 3级别 29 | #### 4级别 30 | ##### 5级别 31 | ###### 6级别 32 | 33 | 34 | # 一级别 35 | ## 二级别 36 | ### 三级别 37 | #### 四级别 38 | ##### 五级别 39 | ###### 六级别 40 | 41 | # 一级别 42 | ## 二级别 43 | ### 三级别 44 | #### 四级别 45 | ##### 五级别 46 | ###### 六级别 47 | -------------------------------------------------------------------------------- /src/test/resources/README-GBK.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/README-GBK.md -------------------------------------------------------------------------------- /src/test/resources/common.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [目录](#目录) 4 | * [二级](#二级) 5 | * [三级](#三级) 6 | * [第二个目录](#第二个目录) 7 | * [二级](#二级-1) 8 | * [三级](#三级-1) 9 | 10 | 11 | # 目录 12 | 13 | ## 二级 14 | 15 | ### 三级 16 | 17 | # 第二个目录 18 | 19 | ## 二级 20 | 21 | ### 三级 22 | -------------------------------------------------------------------------------- /src/test/resources/empty-content.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [N 级深度测试](#n-级深度测试) 4 | * [1级别](#1级别) 5 | * [2 级别](#2-级别) 6 | * [3级别](#3级别) 7 | * [4级别](#4级别) 8 | * [5级别](#5级别) 9 | * [6级别](#6级别) 10 | * [一级别](#一级别) 11 | * [二级别](#二级别) 12 | * [三级别](#三级别) 13 | * [四级别](#四级别) 14 | * [五级别](#五级别) 15 | * [六级别](#六级别) 16 | * [一级别](#一级别-1) 17 | * [二级别](#二级别-1) 18 | * [三级别](#三级别-1) 19 | * [四级别](#四级别-1) 20 | * [五级别](#五级别-1) 21 | * [六级别](#六级别-1) 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/test/resources/empty.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/empty.md -------------------------------------------------------------------------------- /src/test/resources/readme/README.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * 1 [markdown-toc](#markdown-toc) 4 | * 1.1 [变更日志](#变更日志) 5 | * 1.2 [Features](#features) 6 | * 2 [环境依赖](#环境依赖) 7 | * 2.1 [JDK](#jdk) 8 | * 2.2 [Maven](#maven) 9 | * 3 [快速入门](#快速入门) 10 | * 3.1 [maven 引入](#maven-引入) 11 | * 3.2 [md 文件](#md-文件) 12 | * 3.3 [快速开始](#快速开始) 13 | * 4 [属性配置](#属性配置) 14 | * 4.1 [属性说明](#属性说明) 15 | * 4.2 [返回值说明](#返回值说明) 16 | * 5 [测试案例](#测试案例) 17 | * 6 [其他](#其他) 18 | 19 | 20 | # markdown-toc 21 | 22 | 23 | ``` 24 | _ __ ___ __ _ _ __| | ____| | _____ ___ __ | |_ ___ ___ 25 | | '_ ` _ \ / _` | '__| |/ / _` |/ _ \ \ /\ / / '_ \ _____| __/ _ \ / __| 26 | | | | | | | (_| | | | < (_| | (_) \ V V /| | | |_____| || (_) | (__ 27 | |_| |_| |_|\__,_|_| |_|\_\__,_|\___/ \_/\_/ |_| |_| \__\___/ \___| 28 | 29 | ``` 30 | 31 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.houbb/markdown-toc/badge.svg)](http://mvnrepository.com/artifact/com.github.houbb/markdown-toc) 32 | [![Build Status](https://www.travis-ci.org/houbb/markdown-toc.svg?branch=release_1.0.2)](https://www.travis-ci.org/houbb/markdown-toc?branch=release_1.0.2) 33 | [![Coverage Status](https://coveralls.io/repos/github/houbb/markdown-toc/badge.svg?branch=release_1.0.2)](https://coveralls.io/github/houbb/markdown-toc?branch=release_1.0.2) 34 | 35 | Markdown-toc 可以用来生成 markdown 页面的目录,便于 github 页面展现。 36 | 37 | 38 | - 文档 39 | 40 | [中文说明](README.md) | [English Readme](README-ENGLISH.md) 41 | 42 | > 备注 43 | 44 | 对于标题,md 有两种语法 [setext](http://docutils.sourceforge.net/mirror/setext.html) 45 | 和 [atx](http://www.aaronsw.com/2002/atx/) 模式。 46 | 47 | 暂时只支持 **atx** 形式。 48 | 49 | ## 变更日志 50 | 51 | [变更日志](doc/changelog/CHANGELOG.md) 52 | 53 | ## Features 54 | 55 | - Github Markdown 文件一键生成目录 56 | 57 | - 支持 fluent 优雅的写法 58 | 59 | - 支持多次生成 60 | 61 | - 支持重复标题的生成 62 | 63 | - 支持特殊字符的过滤 64 | 65 | - 支持指定不同的文件编码 66 | 67 | - 支持文件夹的文件批量处理(可指定是否包含子文件夹文件) 68 | 69 | - 支持是否写入文件,可返回目录的内容,便于用户自行处理 70 | 71 | - 支持多线程写文件 72 | 73 | - 支持 i18n 74 | 75 | - 支持目录编号生成(1.0.5) 76 | 77 | # 环境依赖 78 | 79 | ## JDK 80 | 81 | JDK8+, 请确保 JDK 设置正确。 82 | 83 | ## Maven 84 | 85 | Jar 使用 [Maven](http://maven.apache.org/) 进行统一管理。 86 | 87 | # 快速入门 88 | 89 | ## maven 引入 90 | 91 | ```xml 92 | 93 | com.github.houbb 94 | markdown-toc 95 | ${maven-version} 96 | 97 | ``` 98 | 99 | ## md 文件 100 | 101 | 本项目支持的 md 文件后缀名称为 `.md` 或者 `.markdown` 102 | 103 | ## 快速开始 104 | 105 | - 单个文件 106 | 107 | ```java 108 | AtxMarkdownToc.newInstance().genTocFile(path); 109 | ``` 110 | 111 | 其中 path 为 md 文件的路径 112 | 113 | - 指定文件夹 114 | 115 | ```java 116 | AtxMarkdownToc.newInstance().genTocFile(path); 117 | ``` 118 | 119 | 其中 path 为 md 文件的父类文件夹 120 | 121 | # 属性配置 122 | 123 | - 代码示例 124 | 125 | ```java 126 | AtxMarkdownToc.newInstance() 127 | .charset("UTF-8") 128 | .write(true) 129 | .subTree(true); 130 | ``` 131 | 132 | ## 属性说明 133 | 134 | | 序号 | 属性 | 默认值 | 说明 | 135 | |:----|:----|:----|:----| 136 | | 1 | charset | `UTF-8` | 文件编码 | 137 | | 2 | write | `true` | 是否将 toc 写入文件(默认写入) | 138 | | 3 | subTree | `true` | 是否包含子文件夹的文件(默认包含) | 139 | | 4 | order | `false` | 是否生成目录编号(默认不生成,1.0.5以后) | 140 | 141 | ## 返回值说明 142 | 143 | `genTocFile()` 返回 TocGen,`genTocDir()` 返回 List 144 | 145 | - TocGen 属性说明 146 | 147 | | 序号 | 属性 | 类型 | 说明 | 148 | |:----|:----|:----| :----| 149 | | 1 | filePath | String | 当前 md 的文件路径 | 150 | | 2 | tocLines | List | 当前 md 文件对应的目录内容 | 151 | 152 | # 测试案例 153 | 154 | [单个文件-目录生成测试案例](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocFileTest.java) 155 | 156 | [文件夹-目录生成测试案例](https://github.com/houbb/markdown-toc/blob/release_1.0.2/src/test/java/com/github/houbb/markdown/toc/core/impl/AtxMarkdownTocDirTest.java) 157 | 158 | # 其他 159 | 160 | > [Issues & Bugs](https://github.com/houbb/markdown-toc/issues) 161 | -------------------------------------------------------------------------------- /src/test/resources/special/chinese.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [中文标点:【】{}()!-=——+@#¥%……&*()——+、。,;‘“:、|、·~《》,。、?](#中文标点-) 4 | 5 | 6 | # 中文标点:【】{}()!-=——+@#¥%……&*()——+、。,;‘“:、|、·~《》,。、? 7 | -------------------------------------------------------------------------------- /src/test/resources/special/emoji.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [笑臉與人物😀 😬 😁 😂 😃 😄 🤣 😅 😆 😇 😉 😊 🙂 🙃 ☺ 😋 😌 😍 😘 😗 😙 😚 🤪 😜 😝 😛 🤑 😎 🤓 🧐 🤠 🤗 🤡 😏 😶 😐 😑 😒 🙄 🤨 🤔 🤫 🤭 🤥 😳 😞 😟 😠 😡 🤬 😔 😕 🙁 ☹ 😣 😖 😫 😩 😤 😮 😱 😨 😰 😯 😦 😧 😢 😥 😪 🤤 😓 😭 🤩 😵 😲 🤯 🤐 😷 🤕 🤒 🤮 🤢 🤧 😴 💤 😈 👿 👹 👺 💩 👻 💀 ☠ 👽 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 👐 🤲 🙌 👏 🙏 🤝 👍 👎 👊 ✊ 🤛 🤜 🤞 ✌ 🤘 🤟 👌 👈 👉 👆 👇 ☝ ✋ 🤚 🖐 🖖 👋 🤙 💪 🖕 ✍ 🤳 💅 👄 👅 👂 👃 👁 👀 🧠 👤 👥 🗣 👶 🧒 👦 👧 🧑 👨 🧔 👱‍♂️ 👩 👱‍♀️ 🧓 👴 👵 👲 👳‍♀️ 👳‍♂️ 🧕 👮‍♀️ 👮‍♂️ 👩‍🚒 👨‍🚒 👷‍♀️ 👷‍♂️ 👩‍🏭 👨‍🏭 👩‍🔧 👨‍🔧 👩‍🌾 👨‍🌾 👩‍🍳 👨‍🍳 👩‍🎤 👨‍🎤 👩‍🎨 👨‍🎨 👩‍🏫 👨‍🏫 👩‍🎓 👨‍🎓 👩‍💼 👨‍💼 👩‍💻 👨‍💻 👩‍🔬 👨‍🔬 👩‍🚀 👨‍🚀 👩‍⚕️ 👨‍⚕️ 👩‍⚖️ 👨‍⚖️ 👩‍✈️ 👨‍✈️ 💂‍♀️ 💂‍♂️ 🕵️‍♀️ 🕵️‍♂️ 🤶 🎅 👼 👸 🤴 👰 🤵‍♀️ 🤵 🕴️‍♀️ 🕴 🧙‍♀️ 🧙‍♂️ 🧝‍♀️ 🧝‍♂️ 🧚‍♀️ 🧚‍♂️ 🧞‍♀️ 🧞‍♂️ 🧜‍♀️ 🧜‍♂️ 🧛‍♀️ 🧛‍♂️ 🧟‍♀️ 🧟‍♂️ 🙇‍♀️ 🙇‍♂️ 💁‍♀️ 💁‍♂️ 🙅‍♀️ 🙅‍♂️ 🙆‍♀️ 🙆‍♂️ 🤷‍♀️ 🤷‍♂️ 🙋‍♀️ 🙋‍♂️ 🤦‍♀️ 🤦‍♂️ 🙎‍♀️ 🙎‍♂️ 🙍‍♀️ 🙍‍♂️ 💇‍♀️ 💇‍♂️ 💆‍♀️ 💆‍♂️ 🤰 🤱 🚶‍♀️ 🚶‍♂️ 🏃‍♀️ 🏃‍♂️ 💃 🕺 👯‍♀️ 👯‍♂️ 👫 👬 👭 💑 👩‍❤️‍👩 👨‍❤️‍👨 💏 👩‍❤️‍💋‍👩 👨‍❤️‍💋‍👨 👪 👨‍👩‍👧 👨‍👩‍👧‍👦 👨‍👩‍👦‍👦 👨‍👩‍👧‍👧 👩‍👩‍👦 👩‍👩‍👧 👩‍👩‍👧‍👦 👩‍👩‍👦‍👦 👩‍👩‍👧‍👧 👨‍👨‍👦 👨‍👨‍👧 👨‍👨‍👧‍👦 👨‍👨‍👦‍👦 👨‍👨‍👧‍👧 👩‍👦 👩‍👧 👩‍👧‍👦 👩‍👦‍👦 👩‍👧‍👧 👨‍👦 👨‍👧 👨‍👧‍👦 👨‍👦‍👦 👨‍👧‍👧 👚 👕 🧥 👖 👔 👗 👙 👘 💄 💋 👣 🧦 👠 👡 👢 👞 👟 🧢 👒 🎩 🎓 👑 ⛑ 🎒 👝 👛 👜 💼 👓 🕶 🧣 🧤 💍 🌂 ☂](#笑臉與人物-----------------------------------------------------------------------------------------------------------------------------------------------------------‍--‍-----‍-‍--‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-------‍--‍--‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍---‍-‍-‍-‍---‍-‍-----‍‍-‍‍--‍‍‍-‍‍‍--‍‍-‍‍‍-‍‍‍-‍‍‍-‍‍-‍‍-‍‍‍-‍‍‍-‍‍‍-‍‍-‍‍-‍‍‍-‍‍‍-‍‍‍-‍-‍-‍‍-‍‍-‍‍-‍-‍-‍‍-‍‍-‍‍-----------------------------------) 4 | * [動物與大自然](#動物與大自然) 5 | * [美食與飲料](#美食與飲料) 6 | * [运动 ⚽ 🏀 🏈 ⚾ 🎾 🏐 🏉 🎱 🏓 🏸 🥅 🏒 🏑 🏏 🥌 ⛳ 🏹 🎣 🥊 🥋 ⛸ 🎿 🛷 ⛷ 🏂 🏋️‍♀️ 🏋️‍♂️ 🤺 🤼‍♀️ 🤼‍♂️ 🤸‍♀️ 🤸‍♂️ ⛹️‍♀️ ⛹️‍♂️ 🤾‍♀️ 🤾‍♂️ 🧗‍♀️ 🧗‍♂️ 🏌️‍♀️ 🏌️‍♂️ 🧘‍♀️ 🧘‍♂️ 🧖‍♀️ 🧖‍♂️ 🏄‍♀️ 🏄‍♂️ 🏊‍♀️ 🏊‍♂️ 🤽‍♀️ 🤽‍♂️ 🚣‍♀️ 🚣‍♂️ 🏇 🚴‍♀️ 🚴‍♂️ 🚵‍♀️ 🚵‍♂️ 🎽 🎖 🏅 🥇 🥈 🥉 🏆 🏵 🎗 🎫 🎟 🎪 🤹‍♀️ 🤹‍♂️ 🎭 🎨 🎬 🎤 🎧 🎼 🎹 🥁 🎷 🎺 🎸 🎻 🎲 🎯 🎳 🎮 👾 🎰](#运动--------------------------‍-‍--‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍-‍--‍-‍-‍-‍-------------‍-‍------------------) 7 | * [旅游🚗 🚕 🚙 🚌 🚎 🏎 🚓 🚑 🚒 🚐 🚚 🚛 🚜 🏍 🛵 🚲 🛴 🚨 🚔 🚍 🚘 🚖 🚡 🚠 🚟 🚃 🚋 🚝 🚄 🚅 🚈 🚞 🚂 🚆 🚇 🚊 🚉 🚁 🛩 ✈ 🛫 🛬 🛶 ⛵ 🛥 🚤 ⛴ 🛳 🚀 🛸 🛰 💺 ⚓ 🚧 ⛽ 🚏 🚦 🚥 🛑 🚢 🎡 🎢 🎠 🏗 🌁 🗼 🏭 ⛲ 🎑 ⛰ 🏔 🗻 🌋 🗾 🏕 ⛺ 🏞 🛣 🛤 🌅 🌄 🏜 🏖 🏝 🌇 🌆 🏙 🌃 🌉 🌌 🌠 🎇 🎆 🌈 🏘 🏰 🏯 🏟 🗽 🏠 🏡 🏚 🏢 🏬 🏣 🏤 🏥 🏦 🏨 🏪 🏫 🏩 💒 🏛 ⛪ 🕌 🕍 🕋 ⛩](#旅游----------------------------------------------------------------------------------------------------------------------) 8 | * [物品 ⌚ 📱 📲 💻 ⌨ 🖥 🖨 🖱 🖲 🕹 🗜 💽 💾 💿 📀 📼 📷 📸 📹 🎥 📽 🎞 📞 ☎ 📟 📠 📺 📻 🎙 🎚 🎛 ⏱ ⏲ ⏰ 🕰 ⏳ ⌛ 📡 🔋 🔌 💡 🔦 🕯 🗑 🛢 🛒 💸 💵 💴 💶 💷 💰 💳 💎 ⚖ 🔧 🔨 ⚒ 🛠 ⛏ 🔩 ⚙ ⛓ 🔫 💣 🔪 🗡 ⚔ 🛡 🚬 ⚰ ⚱ 🏺 🔮 📿 💈 ⚗ 🔭 🔬 🕳 💊 💉 🌡 🏷 🔖 🚽 🚿 🛁 🛀 🔑 🗝 🛋 🛌 🛏 🚪 🛎 🖼 🗺 ⛱ 🗿 🛍 🎈 🎏 🎀 🎁 🎊 🎉 🎎 🎐 🏮 ✉ 📩 📨 📧 💌 📮 📪 📫 📬 📭 📦 📯 📥 📤 📜 📃 📑 📊 📈 📉 📄 📅 📆 🗓 📇 🗃 🗳 🗄 📋 🗒 📁 📂 🗂 🗞 📰 📓 📕 📗 📘 📙 📔 📒 📚 📖 🔗 📎 🖇 ✂ 📐 📏 📌 📍 🔐 🔒 🔓 🔏 🖊 🖋 ✒ 📝 ✏ 🖍 🖌 🔍 🔎](#物品-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------) 9 | * [符號❤ 🧡 💛 💚 💙 💜 🖤 💔 ❣ 💕 💞 💓 💗 💖 💘 💝 💟 ☮ ✝ ☪ 🕉 ☸ ✡ 🔯 🕎 ☯ ☦ 🛐 ⛎ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ 🆔 ⚛ ⚕ ☢ ☣ 📴 📳 🈶 🈚 🈸 🈺 🈷 ✴ 🆚 🉑 💮 🉐 ㊙ ㊗ 🈴 🈵 🈹 🈲 🅰 🅱 🆎 🆑 🅾 🆘 ⛔ 📛 🚫 ❌ ⭕ 💢 ♨ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗ ❕ ❓ ❔ ‼ ⁉ 💯 🔅 🔆 🔱 ⚜ 〽 ⚠ 🚸 🔰 ♻ 🈯 💹 ❇ ✳ ❎ ✅ 💠 🌀 ➿ 🌐 Ⓜ 🏧 🚾 ♿ 🅿 🈳 🈂 🛂 🛃 🛄 🛅 🚰 🚹 ♂ 🚺 ♀ 🚼 🚻 🚮 🎦 📶 🈁 🆖 🆗 🆙 🆒 🆕 🆓 0⃣ 1⃣ 2⃣ 3⃣ 4⃣ 5⃣ 6⃣ 7⃣ 8⃣ 9⃣ 🔟 🔢 ▶ ⏸ ⏯ ⏹ ⏺ ⏏ ⏭ ⏮ ⏩ ⏪ 🔀 🔁 🔂 ◀ 🔼 🔽 ⏫ ⏬ ➡ ⬅ ⬆ ⬇ ↗ ↘ ↙ ↖ ↕ ↔ 🔄 ↪ ↩ 🔃 ⤴ ⤵ #⃣ *⃣ ℹ 🔤 🔡 🔠 🔣 🎵 🎶 〰 ➰ ✔ ➕ ➖ ➗ ✖ 💲 💱 🔚 🔙 🔛 🔝 🔜 ☑ 🔘 ⚪ ⚫ 🔴 🔵 🔸 🔹 🔶 🔷 🔺 ▪ ▫ ⬛ ⬜ 🔻 ◼ ◻ ◾ ◽ 🔲 🔳 🔈 🔉 🔊 🔇 📣 📢 🔔 🔕 🃏 🀄 ♠ ♣ ♥ ♦ 🎴 👁‍🗨 🗨 💭 🗯 💬 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 🕟 🕠 🕡 🕢 🕣 🕤 🕥 🕦 🕧](#符號--------------------------------------------------------------------------------------------------------------ⓜ--------------------------------------------------------------------------------------------------------------------------------------‍----------------------------) 10 | * [旗帜 🏳️ 🏴 🏁 🚩 🏳️‍🌈 🏴‍☠️ 🇦🇫 🇦🇽 🇦🇱 🇩🇿 🇦🇸 🇦🇩 🇦🇴 🇦🇮 🇦🇶 🇦🇬 🇦🇷 🇦🇲 🇦🇼 🇦🇺 🇦🇹 🇦🇿 🇧🇸 🇧🇭 🇧🇩 🇧🇧 🇧🇾 🇧🇪 🇧🇿 🇧🇯 🇧🇲 🇧🇹 🇧🇴 🇧🇦 🇧🇼 🇧🇷 🇮🇴 🇻🇬 🇧🇳 🇧🇬 🇧🇫 🇧🇮 🇰🇭 🇨🇲 🇨🇦 🇮🇨 🇨🇻 🇧🇶 🇰🇾 🇨🇫 🇹🇩 🇨🇱 🇨🇳 🇨🇽 🇨🇨 🇨🇴 🇰🇲 🇨🇬 🇨🇩 🇨🇰 🇨🇷 🇨🇮 🇭🇷 🇨🇺 🇨🇼 🇨🇾 🇨🇿 🇩🇰 🇩🇯 🇩🇲 🇩🇴 🇪🇨 🇪🇬 🇸🇻 🇬🇶 🇪🇷 🇪🇪 🇪🇹 🇪🇺 🇫🇰 🇫🇴 🇫🇯 🇫🇮 🇫🇷 🇬🇫 🇵🇫 🇹🇫 🇬🇦 🇬🇲 🇬🇪 🇩🇪 🇬🇭 🇬🇮 🇬🇷 🇬🇱 🇬🇩 🇬🇵 🇬🇺 🇬🇹 🇬🇬 🇬🇳 🇬🇼 🇬🇾 🇭🇹 🇭🇳 🇭🇰 🇭🇺 🇮🇸 🇮🇳 🇮🇩 🇮🇷 🇮🇶 🇮🇪 🇮🇲 🇮🇱 🇮🇹 🇯🇲 🇯🇵 🎌 🇯🇪 🇯🇴 🇰🇿 🇰🇪 🇰🇮 🇽🇰 🇰🇼 🇰🇬 🇱🇦 🇱🇻 🇱🇧 🇱🇸 🇱🇷 🇱🇾 🇱🇮 🇱🇹 🇱🇺 🇲🇴 🇲🇰 🇲🇬 🇲🇼 🇲🇾 🇲🇻 🇲🇱 🇲🇹 🇲🇭 🇲🇶 🇲🇷 🇲🇺 🇾🇹 🇲🇽 🇫🇲 🇲🇩 🇲🇨 🇲🇳 🇲🇪 🇲🇸 🇲🇦 🇲🇿 🇲🇲 🇳🇦 🇳🇷 🇳🇵 🇳🇱 🇳🇨 🇳🇿 🇳🇮 🇳🇪 🇳🇬 🇳🇺 🇳🇫 🇰🇵 🇲🇵 🇳🇴 🇴🇲 🇵🇰 🇵🇼 🇵🇸 🇵🇦 🇵🇬 🇵🇾 🇵🇪 🇵🇭 🇵🇳 🇵🇱 🇵🇹 🇵🇷 🇶🇦 🇷🇪 🇷🇴 🇷🇺 🇷🇼 🇼🇸 🇸🇲 🇸🇦 🇸🇳 🇷🇸 🇸🇨 🇸🇱 🇸🇬 🇸🇽 🇸🇰 🇸🇮 🇬🇸 🇸🇧 🇸🇴 🇿🇦 🇰🇷 🇸🇸 🇪🇸 🇱🇰 🇧🇱 🇸🇭 🇰🇳 🇱🇨 🇵🇲 🇻🇨 🇸🇩 🇸🇷 🇸🇿 🇸🇪 🇨🇭 🇸🇾 🇹🇼 🇹🇯 🇹🇿 🇹🇭 🇹🇱 🇹🇬 🇹🇰 🇹🇴 🇹🇹 🇹🇳 🇹🇷 🇹🇲 🇹🇨 🇹🇻 🇻🇮 🇺🇬 🇺🇦 🇦🇪 🇬🇧 🏴󠁧󠁢󠁥󠁮󠁧󠁿 🏴󠁧󠁢󠁳󠁣󠁴󠁿 🏴󠁧󠁢󠁷󠁬󠁳󠁿 🇺🇸 🇺🇾 🇺🇿 🇻🇺 🇻🇦 🇻🇪 🇻🇳 🇼🇫 🇪🇭 🇾🇪 🇿🇲 🇿🇼](#旗帜-----‍-‍--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------󠁧󠁢󠁥󠁮󠁧󠁿-󠁧󠁢󠁳󠁣󠁴󠁿-󠁧󠁢󠁷󠁬󠁳󠁿------------) 11 | 12 | 13 | # 笑臉與人物😀 😬 😁 😂 😃 😄 🤣 😅 😆 😇 😉 😊 🙂 🙃 ☺ 😋 😌 😍 😘 😗 😙 😚 🤪 😜 😝 😛 🤑 😎 🤓 🧐 🤠 🤗 🤡 😏 😶 😐 😑 😒 🙄 🤨 🤔 🤫 🤭 🤥 😳 😞 😟 😠 😡 🤬 😔 😕 🙁 ☹ 😣 😖 😫 😩 😤 😮 😱 😨 😰 😯 😦 😧 😢 😥 😪 🤤 😓 😭 🤩 😵 😲 🤯 🤐 😷 🤕 🤒 🤮 🤢 🤧 😴 💤 😈 👿 👹 👺 💩 👻 💀 ☠ 👽 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 👐 🤲 🙌 👏 🙏 🤝 👍 👎 👊 ✊ 🤛 🤜 🤞 ✌ 🤘 🤟 👌 👈 👉 👆 👇 ☝ ✋ 🤚 🖐 🖖 👋 🤙 💪 🖕 ✍ 🤳 💅 👄 👅 👂 👃 👁 👀 🧠 👤 👥 🗣 👶 🧒 👦 👧 🧑 👨 🧔 👱‍♂️ 👩 👱‍♀️ 🧓 👴 👵 👲 👳‍♀️ 👳‍♂️ 🧕 👮‍♀️ 👮‍♂️ 👩‍🚒 👨‍🚒 👷‍♀️ 👷‍♂️ 👩‍🏭 👨‍🏭 👩‍🔧 👨‍🔧 👩‍🌾 👨‍🌾 👩‍🍳 👨‍🍳 👩‍🎤 👨‍🎤 👩‍🎨 👨‍🎨 👩‍🏫 👨‍🏫 👩‍🎓 👨‍🎓 👩‍💼 👨‍💼 👩‍💻 👨‍💻 👩‍🔬 👨‍🔬 👩‍🚀 👨‍🚀 👩‍⚕️ 👨‍⚕️ 👩‍⚖️ 👨‍⚖️ 👩‍✈️ 👨‍✈️ 💂‍♀️ 💂‍♂️ 🕵️‍♀️ 🕵️‍♂️ 🤶 🎅 👼 👸 🤴 👰 🤵‍♀️ 🤵 🕴️‍♀️ 🕴 🧙‍♀️ 🧙‍♂️ 🧝‍♀️ 🧝‍♂️ 🧚‍♀️ 🧚‍♂️ 🧞‍♀️ 🧞‍♂️ 🧜‍♀️ 🧜‍♂️ 🧛‍♀️ 🧛‍♂️ 🧟‍♀️ 🧟‍♂️ 🙇‍♀️ 🙇‍♂️ 💁‍♀️ 💁‍♂️ 🙅‍♀️ 🙅‍♂️ 🙆‍♀️ 🙆‍♂️ 🤷‍♀️ 🤷‍♂️ 🙋‍♀️ 🙋‍♂️ 🤦‍♀️ 🤦‍♂️ 🙎‍♀️ 🙎‍♂️ 🙍‍♀️ 🙍‍♂️ 💇‍♀️ 💇‍♂️ 💆‍♀️ 💆‍♂️ 🤰 🤱 🚶‍♀️ 🚶‍♂️ 🏃‍♀️ 🏃‍♂️ 💃 🕺 👯‍♀️ 👯‍♂️ 👫 👬 👭 💑 👩‍❤️‍👩 👨‍❤️‍👨 💏 👩‍❤️‍💋‍👩 👨‍❤️‍💋‍👨 👪 👨‍👩‍👧 👨‍👩‍👧‍👦 👨‍👩‍👦‍👦 👨‍👩‍👧‍👧 👩‍👩‍👦 👩‍👩‍👧 👩‍👩‍👧‍👦 👩‍👩‍👦‍👦 👩‍👩‍👧‍👧 👨‍👨‍👦 👨‍👨‍👧 👨‍👨‍👧‍👦 👨‍👨‍👦‍👦 👨‍👨‍👧‍👧 👩‍👦 👩‍👧 👩‍👧‍👦 👩‍👦‍👦 👩‍👧‍👧 👨‍👦 👨‍👧 👨‍👧‍👦 👨‍👦‍👦 👨‍👧‍👧 👚 👕 🧥 👖 👔 👗 👙 👘 💄 💋 👣 🧦 👠 👡 👢 👞 👟 🧢 👒 🎩 🎓 👑 ⛑ 🎒 👝 👛 👜 💼 👓 🕶 🧣 🧤 💍 🌂 ☂ 14 | 15 | # 動物與大自然 16 | 🐶 🐱 🐭 🐹 🐰 🐻 🐼 🐨 🐯 🦁 🐮 🐷 🐽 🐸 🐵 🙈 🙉 🙊 🐒 🦍 🐔 🐧 🐦 🐤 🐣 🐥 🐺 🦊 🐗 🐴 🦓 🦒 🦌 🦄 🐝 🐛 🦋 🐌 🐞 🐜 🦗 🕷 🕸 🦂 🐢 🐍 🦎 🦀 🦑 🐙 🦐 🐠 🐟 🐡 🐬 🦈 🐳 🐋 🐊 🐆 🐅 🐃 🐂 🐄 🐪 🐫 🐘 🦏 🐐 🐏 🐑 🐎 🐖 🦇 🐓 🦃 🕊 🦅 🦆 🦉 🐕 🐩 🐈 🐇 🐀 🐁 🐿 🦔 🐾 🐉 🐲 🦕 🦖 🌵 🎄 🌲 🌳 🌴 🌱 🌿 ☘ 🍀 🎍 🎋 🍃 🍂 🍁 🌾 🌺 🌻 🌹 🥀 🌷 🌼 🌸 💐 🍄 🌰 🐚 🌎 🌍 🌏 🌕 🌖 🌗 🌘 🌑 🌒 🌓 🌔 🌚 🌝 🌛 🌜 🌞 🌙 ⭐ 🌟 💫 ✨ ☄ ☀ 🌤 ⛅ 🌥 🌦 ☁ 🌧 ⛈ 🌩 ⚡ 🔥 💥 ❄ 🌨 ☃ ⛄ 🌬 💨 🌪 🌫 ☔ 💧 💦 🌊 17 | 18 | # 美食與飲料 19 | 🍏 🍎 🍐 🍊 🍋 🍌 🍉 🍇 🍓 🍈 🍒 🍑 🍍 🥥 🥝 🍅 🥑 🍆 🌶 🥒 🥦 🌽 🥕 🥗 🥔 🍠 🥜 🍯 🍞 🥐 🥖 🥨 🥞 🧀 🍗 🍖 🥩 🍤 🥚 🍳 🥓 🍔 🍟 🌭 🍕 🍝 🥪 🥙 🌮 🌯 🍜 🥘 🍲 🥫 🍥 🍣 🍱 🍛 🍙 🍚 🍘 🥟 🍢 🍡 🍧 🍨 🍦 🍰 🎂 🥧 🍮 🍭 🍬 🍫 🍿 🍩 🍪 🥠 ☕ 🍵 🥣 🍼 🥤 🥛 🍺 🍻 🍷 🥂 🥃 🍸 🍹 🍾 🍶 🥄 🍴 🍽 🥢 🥡 20 | 21 | 22 | # 运动 ⚽ 🏀 🏈 ⚾ 🎾 🏐 🏉 🎱 🏓 🏸 🥅 🏒 🏑 🏏 🥌 ⛳ 🏹 🎣 🥊 🥋 ⛸ 🎿 🛷 ⛷ 🏂 🏋️‍♀️ 🏋️‍♂️ 🤺 🤼‍♀️ 🤼‍♂️ 🤸‍♀️ 🤸‍♂️ ⛹️‍♀️ ⛹️‍♂️ 🤾‍♀️ 🤾‍♂️ 🧗‍♀️ 🧗‍♂️ 🏌️‍♀️ 🏌️‍♂️ 🧘‍♀️ 🧘‍♂️ 🧖‍♀️ 🧖‍♂️ 🏄‍♀️ 🏄‍♂️ 🏊‍♀️ 🏊‍♂️ 🤽‍♀️ 🤽‍♂️ 🚣‍♀️ 🚣‍♂️ 🏇 🚴‍♀️ 🚴‍♂️ 🚵‍♀️ 🚵‍♂️ 🎽 🎖 🏅 🥇 🥈 🥉 🏆 🏵 🎗 🎫 🎟 🎪 🤹‍♀️ 🤹‍♂️ 🎭 🎨 🎬 🎤 🎧 🎼 🎹 🥁 🎷 🎺 🎸 🎻 🎲 🎯 🎳 🎮 👾 🎰 23 | 24 | 25 | # 旅游🚗 🚕 🚙 🚌 🚎 🏎 🚓 🚑 🚒 🚐 🚚 🚛 🚜 🏍 🛵 🚲 🛴 🚨 🚔 🚍 🚘 🚖 🚡 🚠 🚟 🚃 🚋 🚝 🚄 🚅 🚈 🚞 🚂 🚆 🚇 🚊 🚉 🚁 🛩 ✈ 🛫 🛬 🛶 ⛵ 🛥 🚤 ⛴ 🛳 🚀 🛸 🛰 💺 ⚓ 🚧 ⛽ 🚏 🚦 🚥 🛑 🚢 🎡 🎢 🎠 🏗 🌁 🗼 🏭 ⛲ 🎑 ⛰ 🏔 🗻 🌋 🗾 🏕 ⛺ 🏞 🛣 🛤 🌅 🌄 🏜 🏖 🏝 🌇 🌆 🏙 🌃 🌉 🌌 🌠 🎇 🎆 🌈 🏘 🏰 🏯 🏟 🗽 🏠 🏡 🏚 🏢 🏬 🏣 🏤 🏥 🏦 🏨 🏪 🏫 🏩 💒 🏛 ⛪ 🕌 🕍 🕋 ⛩ 26 | 27 | # 物品 ⌚ 📱 📲 💻 ⌨ 🖥 🖨 🖱 🖲 🕹 🗜 💽 💾 💿 📀 📼 📷 📸 📹 🎥 📽 🎞 📞 ☎ 📟 📠 📺 📻 🎙 🎚 🎛 ⏱ ⏲ ⏰ 🕰 ⏳ ⌛ 📡 🔋 🔌 💡 🔦 🕯 🗑 🛢 🛒 💸 💵 💴 💶 💷 💰 💳 💎 ⚖ 🔧 🔨 ⚒ 🛠 ⛏ 🔩 ⚙ ⛓ 🔫 💣 🔪 🗡 ⚔ 🛡 🚬 ⚰ ⚱ 🏺 🔮 📿 💈 ⚗ 🔭 🔬 🕳 💊 💉 🌡 🏷 🔖 🚽 🚿 🛁 🛀 🔑 🗝 🛋 🛌 🛏 🚪 🛎 🖼 🗺 ⛱ 🗿 🛍 🎈 🎏 🎀 🎁 🎊 🎉 🎎 🎐 🏮 ✉ 📩 📨 📧 💌 📮 📪 📫 📬 📭 📦 📯 📥 📤 📜 📃 📑 📊 📈 📉 📄 📅 📆 🗓 📇 🗃 🗳 🗄 📋 🗒 📁 📂 🗂 🗞 📰 📓 📕 📗 📘 📙 📔 📒 📚 📖 🔗 📎 🖇 ✂ 📐 📏 📌 📍 🔐 🔒 🔓 🔏 🖊 🖋 ✒ 📝 ✏ 🖍 🖌 🔍 🔎 28 | 29 | # 符號❤ 🧡 💛 💚 💙 💜 🖤 💔 ❣ 💕 💞 💓 💗 💖 💘 💝 💟 ☮ ✝ ☪ 🕉 ☸ ✡ 🔯 🕎 ☯ ☦ 🛐 ⛎ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ 🆔 ⚛ ⚕ ☢ ☣ 📴 📳 🈶 🈚 🈸 🈺 🈷 ✴ 🆚 🉑 💮 🉐 ㊙ ㊗ 🈴 🈵 🈹 🈲 🅰 🅱 🆎 🆑 🅾 🆘 ⛔ 📛 🚫 ❌ ⭕ 💢 ♨ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗ ❕ ❓ ❔ ‼ ⁉ 💯 🔅 🔆 🔱 ⚜ 〽 ⚠ 🚸 🔰 ♻ 🈯 💹 ❇ ✳ ❎ ✅ 💠 🌀 ➿ 🌐 Ⓜ 🏧 🚾 ♿ 🅿 🈳 🈂 🛂 🛃 🛄 🛅 🚰 🚹 ♂ 🚺 ♀ 🚼 🚻 🚮 🎦 📶 🈁 🆖 🆗 🆙 🆒 🆕 🆓 0⃣ 1⃣ 2⃣ 3⃣ 4⃣ 5⃣ 6⃣ 7⃣ 8⃣ 9⃣ 🔟 🔢 ▶ ⏸ ⏯ ⏹ ⏺ ⏏ ⏭ ⏮ ⏩ ⏪ 🔀 🔁 🔂 ◀ 🔼 🔽 ⏫ ⏬ ➡ ⬅ ⬆ ⬇ ↗ ↘ ↙ ↖ ↕ ↔ 🔄 ↪ ↩ 🔃 ⤴ ⤵ #⃣ *⃣ ℹ 🔤 🔡 🔠 🔣 🎵 🎶 〰 ➰ ✔ ➕ ➖ ➗ ✖ 💲 💱 🔚 🔙 🔛 🔝 🔜 ☑ 🔘 ⚪ ⚫ 🔴 🔵 🔸 🔹 🔶 🔷 🔺 ▪ ▫ ⬛ ⬜ 🔻 ◼ ◻ ◾ ◽ 🔲 🔳 🔈 🔉 🔊 🔇 📣 📢 🔔 🔕 🃏 🀄 ♠ ♣ ♥ ♦ 🎴 👁‍🗨 🗨 💭 🗯 💬 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 🕟 🕠 🕡 🕢 🕣 🕤 🕥 🕦 🕧 30 | 31 | # 旗帜 🏳️ 🏴 🏁 🚩 🏳️‍🌈 🏴‍☠️ 🇦🇫 🇦🇽 🇦🇱 🇩🇿 🇦🇸 🇦🇩 🇦🇴 🇦🇮 🇦🇶 🇦🇬 🇦🇷 🇦🇲 🇦🇼 🇦🇺 🇦🇹 🇦🇿 🇧🇸 🇧🇭 🇧🇩 🇧🇧 🇧🇾 🇧🇪 🇧🇿 🇧🇯 🇧🇲 🇧🇹 🇧🇴 🇧🇦 🇧🇼 🇧🇷 🇮🇴 🇻🇬 🇧🇳 🇧🇬 🇧🇫 🇧🇮 🇰🇭 🇨🇲 🇨🇦 🇮🇨 🇨🇻 🇧🇶 🇰🇾 🇨🇫 🇹🇩 🇨🇱 🇨🇳 🇨🇽 🇨🇨 🇨🇴 🇰🇲 🇨🇬 🇨🇩 🇨🇰 🇨🇷 🇨🇮 🇭🇷 🇨🇺 🇨🇼 🇨🇾 🇨🇿 🇩🇰 🇩🇯 🇩🇲 🇩🇴 🇪🇨 🇪🇬 🇸🇻 🇬🇶 🇪🇷 🇪🇪 🇪🇹 🇪🇺 🇫🇰 🇫🇴 🇫🇯 🇫🇮 🇫🇷 🇬🇫 🇵🇫 🇹🇫 🇬🇦 🇬🇲 🇬🇪 🇩🇪 🇬🇭 🇬🇮 🇬🇷 🇬🇱 🇬🇩 🇬🇵 🇬🇺 🇬🇹 🇬🇬 🇬🇳 🇬🇼 🇬🇾 🇭🇹 🇭🇳 🇭🇰 🇭🇺 🇮🇸 🇮🇳 🇮🇩 🇮🇷 🇮🇶 🇮🇪 🇮🇲 🇮🇱 🇮🇹 🇯🇲 🇯🇵 🎌 🇯🇪 🇯🇴 🇰🇿 🇰🇪 🇰🇮 🇽🇰 🇰🇼 🇰🇬 🇱🇦 🇱🇻 🇱🇧 🇱🇸 🇱🇷 🇱🇾 🇱🇮 🇱🇹 🇱🇺 🇲🇴 🇲🇰 🇲🇬 🇲🇼 🇲🇾 🇲🇻 🇲🇱 🇲🇹 🇲🇭 🇲🇶 🇲🇷 🇲🇺 🇾🇹 🇲🇽 🇫🇲 🇲🇩 🇲🇨 🇲🇳 🇲🇪 🇲🇸 🇲🇦 🇲🇿 🇲🇲 🇳🇦 🇳🇷 🇳🇵 🇳🇱 🇳🇨 🇳🇿 🇳🇮 🇳🇪 🇳🇬 🇳🇺 🇳🇫 🇰🇵 🇲🇵 🇳🇴 🇴🇲 🇵🇰 🇵🇼 🇵🇸 🇵🇦 🇵🇬 🇵🇾 🇵🇪 🇵🇭 🇵🇳 🇵🇱 🇵🇹 🇵🇷 🇶🇦 🇷🇪 🇷🇴 🇷🇺 🇷🇼 🇼🇸 🇸🇲 🇸🇦 🇸🇳 🇷🇸 🇸🇨 🇸🇱 🇸🇬 🇸🇽 🇸🇰 🇸🇮 🇬🇸 🇸🇧 🇸🇴 🇿🇦 🇰🇷 🇸🇸 🇪🇸 🇱🇰 🇧🇱 🇸🇭 🇰🇳 🇱🇨 🇵🇲 🇻🇨 🇸🇩 🇸🇷 🇸🇿 🇸🇪 🇨🇭 🇸🇾 🇹🇼 🇹🇯 🇹🇿 🇹🇭 🇹🇱 🇹🇬 🇹🇰 🇹🇴 🇹🇹 🇹🇳 🇹🇷 🇹🇲 🇹🇨 🇹🇻 🇻🇮 🇺🇬 🇺🇦 🇦🇪 🇬🇧 🏴󠁧󠁢󠁥󠁮󠁧󠁿 🏴󠁧󠁢󠁳󠁣󠁴󠁿 🏴󠁧󠁢󠁷󠁬󠁳󠁿 🇺🇸 🇺🇾 🇺🇿 🇻🇺 🇻🇦 🇻🇪 🇻🇳 🇼🇫 🇪🇭 🇾🇪 🇿🇲 🇿🇼 32 | -------------------------------------------------------------------------------- /src/test/resources/special/special.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [英文標點:`~!@#$%^&*()_+-=[]{}\|"';:/.,.<>/?](#英文標點_-) 4 | * [ILOVEMD∂ILOVEMD](#ilovemdilovemd) 5 | * [ILOVEMD∏ILOVEMD](#ilovemdilovemd-1) 6 | * [ILOVEMD←ILOVEMD](#ilovemdilovemd-2) 7 | * [ILOVEMD∑ILOVEMD](#ilovemdilovemd-3) 8 | * [ILOVEMD↑ILOVEMD](#ilovemdilovemd-4) 9 | * [ILOVEMD−ILOVEMD](#ilovemdilovemd-5) 10 | * [ILOVEMD→ILOVEMD](#ilovemdilovemd-6) 11 | * [ILOVEMD↓ILOVEMD](#ilovemdilovemd-7) 12 | * [ILOVEMD–ILOVEMD](#ilovemdilovemd-8) 13 | * [ILOVEMD↔ILOVEMD](#ilovemdilovemd-9) 14 | * [ILOVEMD—ILOVEMD](#ilovemdilovemd-10) 15 | * [ILOVEMD‘ILOVEMD](#ilovemdilovemd-11) 16 | * [ILOVEMD’ILOVEMD](#ilovemdilovemd-12) 17 | * [ILOVEMD‚ILOVEMD](#ilovemdilovemd-13) 18 | * [ILOVEMD√ILOVEMD](#ilovemdilovemd-14) 19 | * [ILOVEMD“ILOVEMD](#ilovemdilovemd-15) 20 | * [ILOVEMD”ILOVEMD](#ilovemdilovemd-16) 21 | * [ILOVEMD„ILOVEMD](#ilovemdilovemd-17) 22 | * [ILOVEMD∞ILOVEMD](#ilovemdilovemd-18) 23 | * [ILOVEMD†ILOVEMD](#ilovemdilovemd-19) 24 | * [ILOVEMD!ILOVEMD](#ilovemdilovemd-20) 25 | * [ILOVEMD‡ILOVEMD](#ilovemdilovemd-21) 26 | * [ILOVEMD¡ILOVEMD](#ilovemdilovemd-22) 27 | * [ILOVEMD"ILOVEMD](#ilovemdilovemd-23) 28 | * [ILOVEMD™ILOVEMD](#ilovemdilovemd-24) 29 | * [ILOVEMD•ILOVEMD](#ilovemdilovemd-25) 30 | * [ILOVEMD¢ILOVEMD](#ilovemdilovemd-26) 31 | * [ILOVEMD#ILOVEMD](#ilovemdilovemd-27) 32 | * [ILOVEMD£ILOVEMD](#ilovemdilovemd-28) 33 | * [ILOVEMD$ILOVEMD](#ilovemdilovemd-29) 34 | * [ILOVEMD%ILOVEMD](#ilovemdilovemd-30) 35 | * [ILOVEMD¥ILOVEMD](#ilovemdilovemd-31) 36 | * [ILOVEMD&ILOVEMD](#ilovemdilovemd-32) 37 | * [ILOVEMD¦ILOVEMD](#ilovemdilovemd-33) 38 | * [ILOVEMD…ILOVEMD](#ilovemdilovemd-34) 39 | * [ILOVEMD'ILOVEMD](#ilovemdilovemd-35) 40 | * [ILOVEMD§ILOVEMD](#ilovemdilovemd-36) 41 | * [ILOVEMD(ILOVEMD](#ilovemdilovemd-37) 42 | * [ILOVEMD¨ILOVEMD](#ilovemdilovemd-38) 43 | * [ILOVEMD)ILOVEMD](#ilovemdilovemd-39) 44 | * [ILOVEMD©ILOVEMD](#ilovemdilovemd-40) 45 | * [ILOVEMD∩ILOVEMD](#ilovemdilovemd-41) 46 | * [ILOVEMD*ILOVEMD](#ilovemdilovemd-42) 47 | * [ILOVEMD+ILOVEMD](#ilovemdilovemd-43) 48 | * [ILOVEMD∫ILOVEMD](#ilovemdilovemd-44) 49 | * [ILOVEMD«ILOVEMD](#ilovemdilovemd-45) 50 | * [ILOVEMD,ILOVEMD](#ilovemdilovemd-46) 51 | * [ILOVEMD€ILOVEMD](#ilovemdilovemd-47) 52 | * [ILOVEMD¬ILOVEMD](#ilovemdilovemd-48) 53 | * [ILOVEMD.ILOVEMD](#ilovemdilovemd-49) 54 | * [ILOVEMD®ILOVEMD](#ilovemdilovemd-50) 55 | * [ILOVEMD/ILOVEMD](#ilovemdilovemd-51) 56 | * [ILOVEMD¯ILOVEMD](#ilovemdilovemd-52) 57 | * [ILOVEMD°ILOVEMD](#ilovemdilovemd-53) 58 | * [ILOVEMD‰ILOVEMD](#ilovemdilovemd-54) 59 | * [ILOVEMD±ILOVEMD](#ilovemdilovemd-55) 60 | * [ILOVEMD′ILOVEMD](#ilovemdilovemd-56) 61 | * [ILOVEMD″ILOVEMD](#ilovemdilovemd-57) 62 | * [ILOVEMD´ILOVEMD](#ilovemdilovemd-58) 63 | * [ILOVEMD¶ILOVEMD](#ilovemdilovemd-59) 64 | * [ILOVEMD·ILOVEMD](#ilovemdilovemd-60) 65 | * [ILOVEMD¸ILOVEMD](#ilovemdilovemd-61) 66 | * [ILOVEMD‹ILOVEMD](#ilovemdilovemd-62) 67 | * [ILOVEMD:ILOVEMD](#ilovemdilovemd-63) 68 | * [ILOVEMD›ILOVEMD](#ilovemdilovemd-64) 69 | * [ILOVEMD;ILOVEMD](#ilovemdilovemd-65) 70 | * [ILOVEMD»ILOVEMD](#ilovemdilovemd-66) 71 | * [ILOVEMD¼ILOVEMD](#ilovemdilovemd-67) 72 | * [ILOVEMDILOVEMD](#ilovemdilovemd-72) 77 | * [ILOVEMD‾ILOVEMD](#ilovemdilovemd-73) 78 | * [ILOVEMD?ILOVEMD](#ilovemdilovemd-74) 79 | * [ILOVEMD¿ILOVEMD](#ilovemdilovemd-75) 80 | * [ILOVEMD@ILOVEMD](#ilovemdilovemd-76) 81 | * [ILOVEMD⁄ILOVEMD](#ilovemdilovemd-77) 82 | * [ILOVEMD≈ILOVEMD](#ilovemdilovemd-78) 83 | * [ILOVEMD◊ILOVEMD](#ilovemdilovemd-79) 84 | * [ILOVEMD×ILOVEMD](#ilovemdilovemd-80) 85 | * [ILOVEMD\ILOVEMD](#ilovemdilovemd-81) 86 | * [ILOVEMD˜ILOVEMD](#ilovemdilovemd-82) 87 | * [ILOVEMD^ILOVEMD](#ilovemdilovemd-83) 88 | * [ILOVEMD≠ILOVEMD](#ilovemdilovemd-84) 89 | * [ILOVEMD♠ILOVEMD](#ilovemdilovemd-85) 90 | * [ILOVEMD≡ILOVEMD](#ilovemdilovemd-86) 91 | * [ILOVEMD♣ILOVEMD](#ilovemdilovemd-87) 92 | * [ILOVEMD≤ILOVEMD](#ilovemdilovemd-88) 93 | * [ILOVEMD≥ILOVEMD](#ilovemdilovemd-89) 94 | * [ILOVEMD♥ILOVEMD](#ilovemdilovemd-90) 95 | * [ILOVEMD♦ILOVEMD](#ilovemdilovemd-91) 96 | * [ILOVEMD÷ILOVEMD](#ilovemdilovemd-92) 97 | * [ILOVEMD|ILOVEMD](#ilovemdilovemd-93) 98 | * [ILOVEMD~ILOVEMD](#ilovemdilovemd-94) 99 | 100 | 101 | # 英文標點:`~!@#$%^&*()_+-=[]{}\|"';:/.,.<>/? 102 | 103 | # ILOVEMD∂ILOVEMD 104 | ILOVEMD∂ILOVEMD 105 | 106 | # ILOVEMD∏ILOVEMD 107 | ILOVEMD∏ILOVEMD 108 | 109 | # ILOVEMD←ILOVEMD 110 | ILOVEMD←ILOVEMD 111 | 112 | # ILOVEMD∑ILOVEMD 113 | ILOVEMD∑ILOVEMD 114 | 115 | # ILOVEMD↑ILOVEMD 116 | ILOVEMD↑ILOVEMD 117 | 118 | # ILOVEMD−ILOVEMD 119 | ILOVEMD−ILOVEMD 120 | 121 | # ILOVEMD→ILOVEMD 122 | ILOVEMD→ILOVEMD 123 | 124 | # ILOVEMD↓ILOVEMD 125 | ILOVEMD↓ILOVEMD 126 | 127 | # ILOVEMD–ILOVEMD 128 | ILOVEMD–ILOVEMD 129 | 130 | # ILOVEMD↔ILOVEMD 131 | ILOVEMD↔ILOVEMD 132 | 133 | # ILOVEMD—ILOVEMD 134 | ILOVEMD—ILOVEMD 135 | 136 | # ILOVEMD‘ILOVEMD 137 | ILOVEMD‘ILOVEMD 138 | 139 | # ILOVEMD’ILOVEMD 140 | ILOVEMD’ILOVEMD 141 | 142 | # ILOVEMD‚ILOVEMD 143 | ILOVEMD‚ILOVEMD 144 | 145 | # ILOVEMD√ILOVEMD 146 | ILOVEMD√ILOVEMD 147 | 148 | # ILOVEMD“ILOVEMD 149 | ILOVEMD“ILOVEMD 150 | 151 | # ILOVEMD”ILOVEMD 152 | ILOVEMD”ILOVEMD 153 | 154 | # ILOVEMD„ILOVEMD 155 | ILOVEMD„ILOVEMD 156 | 157 | # ILOVEMD∞ILOVEMD 158 | ILOVEMD∞ILOVEMD 159 | 160 | # ILOVEMD†ILOVEMD 161 | ILOVEMD†ILOVEMD 162 | 163 | # ILOVEMD!ILOVEMD 164 | ILOVEMD!ILOVEMD 165 | 166 | # ILOVEMD‡ILOVEMD 167 | ILOVEMD‡ILOVEMD 168 | 169 | # ILOVEMD¡ILOVEMD 170 | ILOVEMD¡ILOVEMD 171 | 172 | # ILOVEMD"ILOVEMD 173 | ILOVEMD"ILOVEMD 174 | 175 | # ILOVEMD™ILOVEMD 176 | ILOVEMD™ILOVEMD 177 | 178 | # ILOVEMD•ILOVEMD 179 | ILOVEMD•ILOVEMD 180 | 181 | # ILOVEMD¢ILOVEMD 182 | ILOVEMD¢ILOVEMD 183 | 184 | # ILOVEMD#ILOVEMD 185 | ILOVEMD#ILOVEMD 186 | 187 | # ILOVEMD£ILOVEMD 188 | ILOVEMD£ILOVEMD 189 | 190 | # ILOVEMD$ILOVEMD 191 | ILOVEMD$ILOVEMD 192 | 193 | # ILOVEMD%ILOVEMD 194 | ILOVEMD%ILOVEMD 195 | 196 | # ILOVEMD¥ILOVEMD 197 | ILOVEMD¥ILOVEMD 198 | 199 | # ILOVEMD&ILOVEMD 200 | ILOVEMD&ILOVEMD 201 | 202 | # ILOVEMD¦ILOVEMD 203 | ILOVEMD¦ILOVEMD 204 | 205 | # ILOVEMD…ILOVEMD 206 | ILOVEMD…ILOVEMD 207 | 208 | # ILOVEMD'ILOVEMD 209 | ILOVEMD'ILOVEMD 210 | 211 | # ILOVEMD§ILOVEMD 212 | ILOVEMD§ILOVEMD 213 | 214 | # ILOVEMD(ILOVEMD 215 | ILOVEMD(ILOVEMD 216 | 217 | # ILOVEMD¨ILOVEMD 218 | ILOVEMD¨ILOVEMD 219 | 220 | # ILOVEMD)ILOVEMD 221 | ILOVEMD)ILOVEMD 222 | 223 | # ILOVEMD©ILOVEMD 224 | ILOVEMD©ILOVEMD 225 | 226 | # ILOVEMD∩ILOVEMD 227 | ILOVEMD∩ILOVEMD 228 | 229 | # ILOVEMD*ILOVEMD 230 | ILOVEMD*ILOVEMD 231 | 232 | # ILOVEMD+ILOVEMD 233 | ILOVEMD+ILOVEMD 234 | 235 | # ILOVEMD∫ILOVEMD 236 | ILOVEMD∫ILOVEMD 237 | 238 | # ILOVEMD«ILOVEMD 239 | ILOVEMD«ILOVEMD 240 | 241 | # ILOVEMD,ILOVEMD 242 | ILOVEMD,ILOVEMD 243 | 244 | # ILOVEMD€ILOVEMD 245 | ILOVEMD€ILOVEMD 246 | 247 | # ILOVEMD¬ILOVEMD 248 | ILOVEMD¬ILOVEMD 249 | 250 | # ILOVEMD.ILOVEMD 251 | ILOVEMD.ILOVEMD 252 | 253 | # ILOVEMD®ILOVEMD 254 | ILOVEMD®ILOVEMD 255 | 256 | # ILOVEMD/ILOVEMD 257 | ILOVEMD/ILOVEMD 258 | 259 | # ILOVEMD¯ILOVEMD 260 | ILOVEMD¯ILOVEMD 261 | 262 | # ILOVEMD°ILOVEMD 263 | ILOVEMD°ILOVEMD 264 | 265 | # ILOVEMD‰ILOVEMD 266 | ILOVEMD‰ILOVEMD 267 | 268 | # ILOVEMD±ILOVEMD 269 | ILOVEMD±ILOVEMD 270 | 271 | # ILOVEMD′ILOVEMD 272 | ILOVEMD′ILOVEMD 273 | 274 | # ILOVEMD″ILOVEMD 275 | ILOVEMD″ILOVEMD 276 | 277 | # ILOVEMD´ILOVEMD 278 | ILOVEMD´ILOVEMD 279 | 280 | # ILOVEMD¶ILOVEMD 281 | ILOVEMD¶ILOVEMD 282 | 283 | # ILOVEMD·ILOVEMD 284 | ILOVEMD·ILOVEMD 285 | 286 | # ILOVEMD¸ILOVEMD 287 | ILOVEMD¸ILOVEMD 288 | 289 | # ILOVEMD‹ILOVEMD 290 | ILOVEMD‹ILOVEMD 291 | 292 | # ILOVEMD:ILOVEMD 293 | ILOVEMD:ILOVEMD 294 | 295 | # ILOVEMD›ILOVEMD 296 | ILOVEMD›ILOVEMD 297 | 298 | # ILOVEMD;ILOVEMD 299 | ILOVEMD;ILOVEMD 300 | 301 | # ILOVEMD»ILOVEMD 302 | ILOVEMD»ILOVEMD 303 | 304 | # ILOVEMD¼ILOVEMD 305 | ILOVEMD¼ILOVEMD 306 | 307 | # ILOVEMDILOVEMD 320 | ILOVEMD>ILOVEMD 321 | 322 | # ILOVEMD‾ILOVEMD 323 | ILOVEMD‾ILOVEMD 324 | 325 | # ILOVEMD?ILOVEMD 326 | ILOVEMD?ILOVEMD 327 | 328 | # ILOVEMD¿ILOVEMD 329 | ILOVEMD¿ILOVEMD 330 | 331 | # ILOVEMD@ILOVEMD 332 | ILOVEMD@ILOVEMD 333 | 334 | # ILOVEMD⁄ILOVEMD 335 | ILOVEMD⁄ILOVEMD 336 | 337 | # ILOVEMD≈ILOVEMD 338 | ILOVEMD≈ILOVEMD 339 | 340 | # ILOVEMD◊ILOVEMD 341 | ILOVEMD◊ILOVEMD 342 | 343 | # ILOVEMD×ILOVEMD 344 | ILOVEMD×ILOVEMD 345 | 346 | # ILOVEMD\ILOVEMD 347 | ILOVEMD\ILOVEMD 348 | 349 | # ILOVEMD˜ILOVEMD 350 | ILOVEMD˜ILOVEMD 351 | 352 | # ILOVEMD^ILOVEMD 353 | ILOVEMD^ILOVEMD 354 | 355 | # ILOVEMD≠ILOVEMD 356 | ILOVEMD≠ILOVEMD 357 | 358 | # ILOVEMD♠ILOVEMD 359 | ILOVEMD♠ILOVEMD 360 | 361 | # ILOVEMD≡ILOVEMD 362 | ILOVEMD≡ILOVEMD 363 | 364 | # ILOVEMD♣ILOVEMD 365 | ILOVEMD♣ILOVEMD 366 | 367 | # ILOVEMD≤ILOVEMD 368 | ILOVEMD≤ILOVEMD 369 | 370 | # ILOVEMD≥ILOVEMD 371 | ILOVEMD≥ILOVEMD 372 | 373 | # ILOVEMD♥ILOVEMD 374 | ILOVEMD♥ILOVEMD 375 | 376 | # ILOVEMD♦ILOVEMD 377 | ILOVEMD♦ILOVEMD 378 | 379 | # ILOVEMD÷ILOVEMD 380 | ILOVEMD÷ILOVEMD 381 | 382 | # ILOVEMD|ILOVEMD 383 | ILOVEMD|ILOVEMD 384 | 385 | # ILOVEMD~ILOVEMD 386 | ILOVEMD~ILOVEMD 387 | -------------------------------------------------------------------------------- /src/test/resources/sub/001.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [爱与正义](#爱与正义) 4 | * [爱河菠萝](#爱河菠萝) 5 | * [你的过去](#你的过去) 6 | * [散散是谁](#散散是谁) 7 | * [散散是谁](#散散是谁-1) 8 | * [001](#001) 9 | 10 | 11 | # 爱与正义 12 | 13 | ## 爱河菠萝 14 | 15 | ## 你的过去 16 | 17 | ## 散散是谁 18 | 19 | ## 散散是谁 20 | 21 | # 001 22 | -------------------------------------------------------------------------------- /src/test/resources/sub/002.markdown: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [002](#002) 4 | * [爱与正义](#爱与正义) 5 | * [爱河菠萝](#爱河菠萝) 6 | * [你的过去](#你的过去) 7 | * [散散是谁](#散散是谁) 8 | * [爱与正义](#爱与正义-1) 9 | * [爱河菠萝](#爱河菠萝-1) 10 | * [你的过去](#你的过去-1) 11 | * [散散是谁](#散散是谁-1) 12 | 13 | 14 | # 002 15 | 16 | # 爱与正义 17 | 18 | ## 爱河菠萝 19 | 20 | ## 你的过去 21 | 22 | ## 散散是谁 23 | 24 | # 爱与正义 25 | 26 | ## 爱河菠萝 27 | 28 | ## 你的过去 29 | 30 | ## 散散是谁 31 | -------------------------------------------------------------------------------- /src/test/resources/sub/003.text: -------------------------------------------------------------------------------- 1 | # 爱与正义 2 | 3 | ## 爱河菠萝 4 | 5 | # 爱与正义 6 | 7 | ## 爱河菠萝 8 | 9 | ## 你的过去 10 | 11 | ## 散散是谁 12 | 13 | # 爱与正义 14 | 15 | ## 爱河菠萝 16 | 17 | ## 你的过去 18 | 19 | ## 散散是谁 -------------------------------------------------------------------------------- /src/test/resources/sub/little/003.text: -------------------------------------------------------------------------------- 1 | # 爱与正义 2 | 3 | ## 爱河菠萝 4 | 5 | # 爱与正义 6 | 7 | ## 爱河菠萝 8 | 9 | ## 你的过去 10 | 11 | ## 散散是谁 12 | 13 | # 爱与正义 14 | 15 | ## 爱河菠萝 16 | 17 | ## 你的过去 18 | 19 | ## 散散是谁 -------------------------------------------------------------------------------- /src/test/resources/sub/little/008.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [008](#008) 4 | * [爱与正义](#爱与正义) 5 | * [爱河菠萝](#爱河菠萝) 6 | * [你的过去](#你的过去) 7 | * [散散是谁](#散散是谁) 8 | 9 | 10 | # 008 11 | 12 | # 爱与正义 13 | 14 | ## 爱河菠萝 15 | 16 | ## 你的过去 17 | 18 | ## 散散是谁 19 | -------------------------------------------------------------------------------- /src/test/resources/sub/little/009.markdown: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [009](#009) 4 | * [爱与正义](#爱与正义) 5 | * [爱河菠萝](#爱河菠萝) 6 | * [你的过去](#你的过去) 7 | * [散散是谁](#散散是谁) 8 | * [爱与正义](#爱与正义-1) 9 | * [爱河菠萝](#爱河菠萝-1) 10 | * [你的过去](#你的过去-1) 11 | * [散散是谁](#散散是谁-1) 12 | 13 | 14 | # 009 15 | 16 | # 爱与正义 17 | 18 | ## 爱河菠萝 19 | 20 | ## 你的过去 21 | 22 | ## 散散是谁 23 | 24 | # 爱与正义 25 | 26 | ## 爱河菠萝 27 | 28 | ## 你的过去 29 | 30 | ## 散散是谁 31 | -------------------------------------------------------------------------------- /src/test/resources/sub/sub/003.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [003](#003) 4 | * [爱与正义](#爱与正义) 5 | * [爱河菠萝](#爱河菠萝) 6 | * [你的过去](#你的过去) 7 | * [散散是谁](#散散是谁) 8 | 9 | 10 | # 003 11 | 12 | # 爱与正义 13 | 14 | ## 爱河菠萝 15 | 16 | ## 你的过去 17 | 18 | ## 散散是谁 19 | -------------------------------------------------------------------------------- /src/test/resources/sub/sub/004.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [004](#004) 4 | * [爱与正义](#爱与正义) 5 | * [爱河菠萝](#爱河菠萝) 6 | * [你的过去](#你的过去) 7 | * [散散是谁](#散散是谁) 8 | 9 | 10 | # 004 11 | 12 | # 爱与正义 13 | 14 | ## 爱河菠萝 15 | 16 | ## 你的过去 17 | 18 | ## 散散是谁 19 | -------------------------------------------------------------------------------- /src/test/resources/sub0/1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/sub0/1.txt -------------------------------------------------------------------------------- /src/test/resources/sub1/1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/houbb/markdown-toc/e7b9698ed90662f7cc01b6405257478d47cc3879/src/test/resources/sub1/1.txt -------------------------------------------------------------------------------- /src/test/resources/sub1/common.md: -------------------------------------------------------------------------------- 1 | # only one 2 | 3 | ## 只有一个文件哦 4 | 5 | ## 哈哈哈 6 | -------------------------------------------------------------------------------- /src/test/resources/中文名称.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | * [Table of Contents](#table-of-contents) 4 | * [Table of Contents](#table-of-contents-1) 5 | * [Paradise](#paradise) 6 | * [paradise-common](#paradise-common) 7 | * [paradise-enhance](#paradise-enhance) 8 | * [paradise-core](#paradise-core) 9 | * [paradise-test](#paradise-test) 10 | * [变更日志](#变更日志) 11 | 12 | 13 | # Table of Contents 14 | 15 | * [Paradise](#paradise) 16 | * [paradise-common](#paradise-common) 17 | * [paradise-enhance](#paradise-enhance) 18 | * [paradise-core](#paradise-core) 19 | * [paradise-test](#paradise-test) 20 | * [变更日志](#变更日志) 21 | 22 | 23 | # Table of Contents 24 | 25 | * [Paradise](#paradise) 26 | * [paradise-common](#paradise-common) 27 | * [paradise-enhance](#paradise-enhance) 28 | * [paradise-core](#paradise-core) 29 | * [paradise-test](#paradise-test) 30 | * [变更日志](#变更日志) 31 | 32 | 33 | # Paradise 34 | 35 | 在平时写一些小项目时,很多工具类都是重复的。一直以来都是复制修改,后来有一天又找不到了。 36 | 37 | 很繁琐,索性就将平时会用到的大多数东西放在这一个项目下面。 38 | 39 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.houbb/paradise/badge.svg)](http://mvnrepository.com/artifact/com.github.houbb/paradise) 40 | [![Build Status](https://www.travis-ci.org/houbb/paradise.svg?branch=release_1.1.2)](https://www.travis-ci.org/houbb/paradise?branch=release_1.1.2) 41 | [![Coverage Status](https://coveralls.io/repos/github/houbb/paradise/badge.svg?branch=release_1.1.2)](https://coveralls.io/github/houbb/paradise?branch=release_1.1.2) 42 | 43 | ## paradise-common 44 | 45 | 提供通用工具。主要是自己项目使用。不依赖三方 jar。 46 | 47 | ## paradise-enhance 48 | 49 | 功能增强,依赖三方 jar。 50 | 51 | ## paradise-core 52 | 53 | 对于 `compile-annotation`(运行时注解) 进行整合。 54 | 55 | - log-analysis-core 整合过来 56 | 57 | @Log 58 | 59 | - cat-limiter 整合过来 60 | 61 | @LimitCount 62 | 63 | @LimitFrequency 64 | 65 | - @valid 的重新设计 66 | 67 | ## paradise-test 68 | 69 | 仅用于本项目自检测试。 70 | 71 | 72 | # 变更日志 73 | 74 | > [ChangeLog](doc/ChangeLog.md) 75 | --------------------------------------------------------------------------------