Skip to content

Commit fadab56

Browse files
committed
refactor(syntax): 移除部分 Markdown 基础设施的硬编码, 同步更新到 syntax.toml
- 组 markdown: Markdown 图片, 内部链接, 外部链接, 防截断自动链接
1 parent 3a07487 commit fadab56

3 files changed

Lines changed: 65 additions & 59 deletions

File tree

public/editor.html

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -291,31 +291,23 @@
291291
if (m) {
292292
openTag = m[1].replace(/\\/g, '');
293293
if (openTag === '↓↓') closeTag = '↑↑';
294-
else if (openTag.startsWith('{')) closeTag = openTag.endsWith('}') ? '{/' + openTag.substring(1) : '{/' + openTag.substring(1).replace(/[:\-].*/, '') + '}';
294+
else if (openTag.startsWith('{')) {
295+
closeTag = openTag.endsWith('}') ? '{/' + openTag.substring(1) : '{/' + openTag.substring(1).replace(/[:\-].*/, '') + '}';
296+
}
295297
}
296298
}
297299
return { ...r, openTag, closeTag };
298300
});
299301
}
300-
parse(str) { return this.render(this.tokenize(str)); }
302+
303+
parse(str) {
304+
return this.render(this.tokenize(str));
305+
}
306+
301307
tokenize(str) {
302308
let tokens = [], i = 0, len = str.length;
303309
while (i < len) {
304310
if (str[i] === '\\' && i + 1 < len) { tokens.push({ type: 'text', val: str[i + 1] }); i += 2; continue; }
305-
if (str.startsWith('![', i)) {
306-
let c1 = str.indexOf('](', i + 2);
307-
if (c1 > -1) {
308-
let c2 = str.indexOf(')', c1 + 2);
309-
if (c2 > -1) { tokens.push({ type: 'img', alt: str.slice(i + 2, c1), url: str.slice(c1 + 2, c2) }); i = c2 + 1; continue; }
310-
}
311-
}
312-
if (str.startsWith('[', i)) {
313-
let c1 = str.indexOf('](', i + 1);
314-
if (c1 > -1) {
315-
let c2 = str.indexOf(')', c1 + 2);
316-
if (c2 > -1) { tokens.push({ type: 'link', content: this.tokenize(str.slice(i + 1, c1)), url: str.slice(c1 + 2, c2) }); i = c2 + 1; continue; }
317-
}
318-
}
319311
let matched = false;
320312
for (let r of this.customRules) {
321313
if (r.regex) {
@@ -333,7 +325,10 @@
333325
if (outer.indexOf(r.openTag, r.openTag.length) > -1) {
334326
let out = outer.substring(0, r.openTag.length), innerD = 0, sIdx = -1;
335327
for (let k = r.openTag.length; k < outer.length - r.closeTag.length; ) {
336-
if (outer[k] === '\\' && k + 1 < outer.length) { if (innerD === 0) out += outer.substring(k, k+2); k += 2; continue; }
328+
if (outer[k] === '\\' && k + 1 < outer.length) {
329+
if (innerD === 0) out += outer.substring(k, k+2);
330+
k += 2; continue;
331+
}
337332
if (outer.startsWith(r.openTag, k)) { if (innerD === 0) sIdx = k; innerD++; k += r.openTag.length; }
338333
else if (outer.startsWith(r.closeTag, k)) {
339334
innerD--; k += r.closeTag.length;
@@ -371,29 +366,18 @@
371366
}
372367
}
373368
if (matched) continue;
374-
let urlMatch = str.slice(i).match(/^https?:\/\/[^\s<]+/);
375-
if (urlMatch) {
376-
let url = urlMatch[0], trailing = '';
377-
let pMatch = url.match(/([.,;:!?]+)$/);
378-
if (pMatch) { url = url.substring(0, url.length - pMatch[0].length); trailing = pMatch[0]; }
379-
tokens.push({ type: 'autolink', url });
380-
if (trailing) tokens.push({ type: 'text', val: trailing });
381-
i += urlMatch[0].length; continue;
382-
}
383369
tokens.push({ type: 'text', val: str[i] }); i++;
384370
}
385371
return tokens.reduce((a, c) => {
386372
if (c.type === 'text' && a.length && a[a.length - 1].type === 'text') a[a.length - 1].val += c.val;
387373
else a.push(c); return a;
388374
}, []);
389375
}
376+
390377
render(tokens) {
391378
return tokens.map(t => {
392379
if (t.type === 'text') return t.val;
393-
if (t.type === 'img') return `<img src="${t.url}" alt="${t.alt}" class="card-img" loading="lazy" />`;
394-
if (t.type === 'link') return `<a href="${t.url}" ${t.url.startsWith('#') ? '' : 'target="_blank" rel="noopener noreferrer"'} class="card-link">${this.render(t.content)}</a>`;
395-
if (t.type === 'autolink') return `<a href="${t.url}" target="_blank" class="card-link" rel="noopener noreferrer">${t.url.replace(/^https?:\/\//, '').replace(/\/$/, '')}</a>`;
396-
if (t.type === 'custom_regex') return t.rule.replacement.replace(/\$(\d)/g, (m, p1) => this.parse(t.match[parseInt(p1)] || ''));
380+
if (t.type === 'custom_regex') return t.rule.replacement.replace(/\$(\d)/g, (_, p1) => this.parse(t.match[parseInt(p1)] || '')).replace(/@(\d)/g, (_, p1) => t.match[parseInt(p1)] || '');
397381
if (t.type === 'custom_prefix') return t.rule.replacement.replace(/\$1/g, this.parse(t.content));
398382
return '';
399383
}).join('');

public/index.html

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -347,21 +347,6 @@ <h1 id="site-title"></h1>
347347
let tokens = [], i = 0, len = str.length;
348348
while (i < len) {
349349
if (str[i] === '\\' && i + 1 < len) { tokens.push({ type: 'text', val: str[i + 1] }); i += 2; continue; }
350-
if (str.startsWith('![', i)) {
351-
let c1 = str.indexOf('](', i + 2);
352-
if (c1 > -1) {
353-
let c2 = str.indexOf(')', c1 + 2);
354-
if (c2 > -1) { tokens.push({ type: 'img', alt: str.slice(i + 2, c1), url: str.slice(c1 + 2, c2) }); i = c2 + 1; continue; }
355-
}
356-
}
357-
if (str.startsWith('[', i)) {
358-
let c1 = str.indexOf('](', i + 1);
359-
if (c1 > -1) {
360-
let c2 = str.indexOf(')', c1 + 2);
361-
if (c2 > -1) { tokens.push({ type: 'link', content: this.tokenize(str.slice(i + 1, c1)), url: str.slice(c1 + 2, c2) }); i = c2 + 1; continue; }
362-
}
363-
}
364-
365350
let matched = false;
366351
for (let r of this.customRules) {
367352
if (r.regex) {
@@ -420,16 +405,6 @@ <h1 id="site-title"></h1>
420405
}
421406
}
422407
if (matched) continue;
423-
424-
let urlMatch = str.slice(i).match(/^https?:\/\/[^\s<]+/);
425-
if (urlMatch) {
426-
let url = urlMatch[0], trailing = '';
427-
let pMatch = url.match(/([.,;:!?]+)$/);
428-
if (pMatch) { url = url.substring(0, url.length - pMatch[0].length); trailing = pMatch[0]; }
429-
tokens.push({ type: 'autolink', url });
430-
if (trailing) tokens.push({ type: 'text', val: trailing });
431-
i += urlMatch[0].length; continue;
432-
}
433408
tokens.push({ type: 'text', val: str[i] }); i++;
434409
}
435410
return tokens.reduce((a, c) => {
@@ -441,10 +416,7 @@ <h1 id="site-title"></h1>
441416
render(tokens) {
442417
return tokens.map(t => {
443418
if (t.type === 'text') return t.val;
444-
if (t.type === 'img') return `<img src="${t.url}" alt="${t.alt}" class="card-img" loading="lazy" />`;
445-
if (t.type === 'link') return `<a href="${t.url}" ${t.url.startsWith('#') ? '' : 'target="_blank" rel="noopener noreferrer"'} class="card-link">${this.render(t.content)}</a>`;
446-
if (t.type === 'autolink') return `<a href="${t.url}" target="_blank" class="card-link" rel="noopener noreferrer">${t.url.replace(/^https?:\/\//, '').replace(/\/$/, '')}</a>`;
447-
if (t.type === 'custom_regex') return t.rule.replacement.replace(/\$(\d)/g, (m, p1) => this.parse(t.match[parseInt(p1)] || ''));
419+
if (t.type === 'custom_regex') return t.rule.replacement.replace(/\$(\d)/g, (_, p1) => this.parse(t.match[parseInt(p1)] || '')).replace(/@(\d)/g, (_, p1) => t.match[parseInt(p1)] || '');
448420
if (t.type === 'custom_prefix') return t.rule.replacement.replace(/\$1/g, this.parse(t.content));
449421
return '';
450422
}).join('');

public/syntax.toml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,56 @@ view_value = "ri-subtract-line"
100100

101101
####################
102102

103+
[merge_groups.markdown]
104+
title = "Markdown 基础设施"
105+
icon_html = """<i class="ri-government-line"></i><i class="ri-arrow-down-s-line" style="font-size: 0.8em; margin-left: -2px;"></i>"""
106+
107+
[[rules]]
108+
regex = "!\\[([^\\]]*)\\]\\(([^)]+)\\)"
109+
flags = "g"
110+
replacement = '<img src="@2" alt="@1" class="card-img" loading="lazy" />'
111+
prefix = "!["
112+
suffix = "]()"
113+
group = "markdown"
114+
title = "Markdown 图片"
115+
view_type = "icon_class"
116+
view_value = "ri-image-line"
117+
118+
[[rules]]
119+
regex = "\\[([^\\]]+)\\]\\((#[^)]*)\\)"
120+
flags = "g"
121+
replacement = '<a href="@2" class="card-link">$1</a>'
122+
prefix = "["
123+
suffix = "]()"
124+
group = "markdown"
125+
title = "内部链接"
126+
view_type = "icon_class"
127+
view_value = "ri-link-m"
128+
129+
[[rules]]
130+
regex = "\\[([^\\]]+)\\]\\(([^)#][^)]*)?\\)"
131+
flags = "g"
132+
replacement = '<a href="@2" target="_blank" class="card-link" rel="noopener noreferrer">$1</a>'
133+
prefix = "["
134+
suffix = "]()"
135+
group = "markdown"
136+
title = "外部链接"
137+
view_type = "icon_class"
138+
view_value = "ri-external-link-line"
139+
140+
[[rules]]
141+
regex = "(https?:\\/\\/)([^\\s<]+?[^.,;:!?。,、!?\\s<\\/>])(\\/?)(?=[.,;:!?。,、!?]*(?:\\s|<|$))"
142+
flags = "g"
143+
replacement = '<a href="@1@2@3" target="_blank" class="card-link" rel="noopener noreferrer">@2</a>'
144+
prefix = "https://"
145+
suffix = ""
146+
group = "markdown"
147+
title = "自动链接(防截断)"
148+
view_type = "icon_class"
149+
view_value = "ri-global-line"
150+
151+
####################
152+
103153
[merge_groups.underline_color]
104154
title = "下划线"
105155
icon_html = """<i class="ri-underline"></i><i class="ri-arrow-down-s-line" style="font-size: 0.8em; margin-left: -2px;"></i>"""

0 commit comments

Comments
 (0)