feat: the assistant's answers in Markdown; thinking shows «Думаю…», then «Думал N с», opening smoothly by its arrow
This commit is contained in:
1 parent
4b7220fffb
commit
4da1cc4200
4 files changed
+103
-12
No files matched your search
@@ -58,6 +58,49 @@
|
||||
}
|
||||
return out;
|
||||
}
|
||||
const api = {shellQuote, shellQuoteAll, dropAction, fmtSize, scope, parseActions};
|
||||
// md turns an assistant's text (no ``` blocks - those are drawn apart)
|
||||
// into HTML: headings, lists, quotes, bold, italic, `code` and http(s)
|
||||
// links. Everything is escaped first, so nothing else gets through.
|
||||
const escH = v => String(v).replace(/[&<>"]/g, c => ({'&': '&', '<': '<', '>': '>', '"': '"'}[c]));
|
||||
function mdInline(t) {
|
||||
const codes = [];
|
||||
t = t.replace(/`([^`\n]+)`/g, (_, c) => { codes.push(c); return '\u0000' + (codes.length - 1) + '\u0000'; });
|
||||
t = escH(t)
|
||||
.replace(/\*\*([^*\n]+)\*\*/g, '<b>$1</b>')
|
||||
.replace(/(^|[^*\w])\*([^*\n]+)\*(?!\w)/g, '$1<i>$2</i>')
|
||||
.replace(/(^|\W)_([^_\n]+)_(?!\w)/g, '$1<i>$2</i>')
|
||||
.replace(/\[([^\]\n]+)\]\(((?:[^()\s]|\([^()\s]*\))+)\)/g, (_, txt, url) => /^https?:\/\//i.test(url.replace(/&/g, '&'))
|
||||
? '<a href="' + url + '" target="_blank" rel="noopener">' + txt + '</a>' : txt);
|
||||
return t.replace(/\u0000(\d+)\u0000/g, (_, i) => '<code>' + escH(codes[+i]) + '</code>');
|
||||
}
|
||||
function md(text) {
|
||||
const out = [];
|
||||
let para = [], list = null;
|
||||
const flush = () => {
|
||||
if (para.length) out.push('<p>' + para.map(mdInline).join('<br>') + '</p>');
|
||||
para = [];
|
||||
if (list) { out.push('<' + list.tag + '>' + list.items.map(x => '<li>' + mdInline(x) + '</li>').join('') + '</' + list.tag + '>'); list = null; }
|
||||
};
|
||||
for (const line of String(text).split('\n')) {
|
||||
let m;
|
||||
if (!line.trim()) { flush(); continue; }
|
||||
if ((m = /^#{1,6}\s+(.*)$/.exec(line))) { flush(); out.push('<h4>' + mdInline(m[1]) + '</h4>'); continue; }
|
||||
if (/^\s*(-{3,}|\*{3,})\s*$/.test(line)) { flush(); out.push('<hr>'); continue; }
|
||||
if ((m = /^>\s?(.*)$/.exec(line))) { flush(); out.push('<blockquote>' + mdInline(m[1]) + '</blockquote>'); continue; }
|
||||
const ul = /^\s*[-*•]\s+(.*)$/.exec(line), ol = /^\s*\d+[.)]\s+(.*)$/.exec(line);
|
||||
if (ul || ol) {
|
||||
const tag = ul ? 'ul' : 'ol';
|
||||
if (para.length || (list && list.tag !== tag)) flush();
|
||||
if (!list) list = {tag, items: []};
|
||||
list.items.push((ul || ol)[1]);
|
||||
continue;
|
||||
}
|
||||
if (list) flush();
|
||||
para.push(line);
|
||||
}
|
||||
flush();
|
||||
return out.join('');
|
||||
}
|
||||
const api = {shellQuote, shellQuoteAll, dropAction, fmtSize, scope, parseActions, md};
|
||||
if (typeof module !== 'undefined') module.exports = api; else root.WSUtil = api;
|
||||
})(this);
|
||||
Reference in new issue
Block a user