文章目录
背景
自己写过一个 Typora 主题,使用了 CSS 计数器,实现了在 Typora 中自动显示标题的序号。但这个只是视觉上的,并不是实际的内容。如果需要保留这个序号,那么就可以使用这个工具。
如果想要只依靠 Typora 就实现一键自动排序,一键移除编号,那么可以看这篇文章:非CSS主题的方式实现 Typora 标题自动编码功能 ------ 全网首发!
基本环境
只要有 git bash 即可。
创建一个目录,然后在 git bash 中切换到这个目录下。
创建文件
可以使用 touch 命令创建一个 mdrenum.c 文件。文件名随便。
bash
touch mdrenum.c
复制下面的代码
复制下方的代码,粘贴到之前创建的文件中:
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define MAX_LINE_LENGTH 1024
#define MAX_LEVELS 6
typedef struct {
int counts[MAX_LEVELS]; // 各级标题的当前计数
int last_level; // 上一个处理的标题级别
} HeadingState;
void init_heading_state(HeadingState *state) {
memset(state->counts, 0, sizeof(state->counts));
state->last_level = 0;
}
bool is_heading(const char *line, int *level) {
int i = 0;
while (line[i] == '#') {
i++;
}
if (i > 0 && i <= MAX_LEVELS && (line[i] == ' ' || line[i] == '\t')) {
*level = i;
return true;
}
return false;
}
void extract_title_text(const char *line, int level, char *title_text) {
const char *start = line + level;
while (*start == ' ' || *start == '\t') {
start++;
}
const char *text_start = start;
while (*text_start) {
if (isdigit(*text_start)) {
while (*text_start && (isdigit(*text_start) || *text_start == '.')) {
text_start++;
}
while (*text_start == ' ') {
text_start++;
}
break;
} else if (*text_start != ' ') {
break;
}
text_start++;
}
strcpy(title_text, text_start);
}
void generate_heading_number(HeadingState *state, int level, char *number) {
if (level < state->last_level) {
for (int i = level; i < MAX_LEVELS; i++) {
state->counts[i] = 0;
}
}
state->counts[level - 1]++;
number[0] = '\0';
for (int i = 0; i < level; i++) {
char temp[16];
sprintf(temp, "%d.", state->counts[i]);
strcat(number, temp);
}
// 确保最后有一个点号
if (number[strlen(number)-1] != '.') {
strcat(number, ".");
}
state->last_level = level;
}
void process_file(const char *filename) {
FILE *file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Error: Could not open file %s\n", filename);
exit(1);
}
FILE *temp_file = tmpfile();
if (!temp_file) {
fclose(file);
fprintf(stderr, "Error: Could not create temporary file\n");
exit(1);
}
HeadingState state;
init_heading_state(&state);
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), file)) {
int level;
if (is_heading(line, &level)) {
char title_text[MAX_LINE_LENGTH];
extract_title_text(line, level, title_text);
char number[MAX_LINE_LENGTH];
generate_heading_number(&state, level, number);
// 正确格式: 适当数量的# + 空格 + 序号 + 空格 + 标题文本
// 先写入适当数量的#
for (int i = 0; i < level; i++) {
fputc('#', temp_file);
}
// 然后写入空格、序号和标题
fprintf(temp_file, " %s %s", number, title_text);
} else {
fputs(line, temp_file);
}
}
fclose(file);
file = fopen(filename, "w");
if (!file) {
fclose(temp_file);
fprintf(stderr, "Error: Could not open file %s for writing\n", filename);
exit(1);
}
rewind(temp_file);
while (fgets(line, sizeof(line), temp_file)) {
fputs(line, file);
}
fclose(file);
fclose(temp_file);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <markdown_file.md>\n", argv[0]);
return 1;
}
process_file(argv[1]);
printf("Successfully processed %s\n", argv[1]);
return 0;
}
执行编译
复制下方的命令,到你创建的 C语言文件所在的目录中执行【需要注意文件的名称要一致】:
bash
gcc -Os -o mdrenum.exe mdrenum.c
减小 exe 文件的体积
还是在 git bash 中,执行下方的命令【strip 命令在 git bash 环境中自带了】:
bash
strip --strip-all mdrenum.exe
经过这个 strip 命令 处理后的 exe 文件,体积会大幅度减小。【从59KB 缩减到了 只有 17KB 的大小】。
配置环境变量
可以将编译得到的 exe 文件放到一个特定的目录下,然后将这个 exe 文件配置到系统的环境变量中。这样就可以保证,在终端中的任何目录下,都可以使用这个 mdrenum.exe 文件来处理 markdown 文件的标题序号了。
使用方式
在配置了环境变量后,直接打开任意终端,切换到要处理的 markdown 文件的目录,然后使用:
bash
mdrenum.exe 要处理的md文件名.md
即可。