diff --git a/src/lib/ChatScreens/Chat.svelte b/src/lib/ChatScreens/Chat.svelte
index c4657710..d7c43ce7 100644
--- a/src/lib/ChatScreens/Chat.svelte
+++ b/src/lib/ChatScreens/Chat.svelte
@@ -106,7 +106,7 @@
const marked = await ParseMarkdown(data, charArg, 'pretranslate', chatID)
translating = true
console.log(marked)
- const translated = postTranslationParse(await translateHTML(marked, false, charArg, chatID))
+ const translated = await postTranslationParse(await translateHTML(marked, false, charArg, chatID))
translating = false
lastParsed = translated
lastCharArg = charArg
diff --git a/src/ts/parser.ts b/src/ts/parser.ts
index 7ee9ef26..72d83fb8 100644
--- a/src/ts/parser.ts
+++ b/src/ts/parser.ts
@@ -16,35 +16,29 @@ import { requestChatData } from './process/request';
import type { OpenAIChat } from './process';
import { alertInput, alertNormal } from './alert';
import hljs from 'highlight.js/lib/core'
-import hljavascript from 'highlight.js/lib/languages/javascript';
-import hlpython from 'highlight.js/lib/languages/python';
-import hlcss from 'highlight.js/lib/languages/css';
-import hlxml from 'highlight.js/lib/languages/xml';
-import hllua from 'highlight.js/lib/languages/lua';
import 'highlight.js/styles/atom-one-dark.min.css'
-hljs.registerLanguage('javascript', hljavascript);
-hljs.registerLanguage('python', hlpython);
-hljs.registerLanguage('css', hlcss);
-hljs.registerLanguage('xml', hlxml);
-hljs.registerLanguage('lua', hllua);
-
-const mconverted = markdownit({
+const markdownItOptions = {
html: true,
breaks: true,
linkify: false,
typographer: true,
quotes: '\u{E9b0}\u{E9b1}\u{E9b2}\u{E9b3}', //placeholder characters to convert to real quotes
+}
+
+const md = markdownit(markdownItOptions)
+const mdHighlight = markdownit({
highlight: function (str, lang) {
- if (lang && hljs.getLanguage(lang)) {
- try {
- return '
' + hljs.highlight(lang, str, true).value + '
';
- } catch (__) {}
+ if(lang){
+ return ``+ str +'';
}
return ''
- }
+ },
+ ...markdownItOptions
})
-mconverted.disable(['code'])
+
+md.disable(['code'])
+mdHighlight.disable(['code'])
DOMPurify.addHook("uponSanitizeElement", (node: HTMLElement, data) => {
if (data.tagName === "iframe") {
@@ -84,13 +78,174 @@ DOMPurify.addHook("uponSanitizeAttribute", (node, data) => {
})
function renderMarkdown(data:string){
- return mconverted.render(data)
+ return md.render(data)
.replace(/\uE9b0/gu, '“')
.replace(/\uE9b1/gu, '”')
.replace(/\uE9b2/gu, '‘')
.replace(/\uE9b3/gu, '’')
}
+async function renderHighlightableMarkdown(data:string) {
+ let rendered = mdHighlight.render(data)
+ .replace(/\uE9b0/gu, '“')
+ .replace(/\uE9b1/gu, '”')
+ .replace(/\uE9b2/gu, '‘')
+ .replace(/\uE9b3/gu, '’')
+ console.log(rendered)
+ const highlightPlaceholders = rendered.match(/(.+?)<\/pre-hljs-placeholder>/gms)
+ console.log(highlightPlaceholders)
+ if (!highlightPlaceholders){
+ return rendered
+ }
+
+ for (const placeholder of highlightPlaceholders){
+ try {
+ let lang = placeholder.match(/lang="(.+?)"/)?.[1]
+ const code = placeholder.match(/(.+?)<\/pre-hljs-placeholder>/ms)?.[1]
+ if (!lang || !code){
+ continue
+ }
+ //import language if not already loaded
+ //we do not refactor this to a function because we want to keep vite to only import the languages that are needed
+ let languageModule:any = null
+ switch(lang){
+ case 'js':
+ case 'javascript':{
+ lang = 'javascript'
+ if(!hljs.getLanguage('javascript')){
+ languageModule = await import('highlight.js/lib/languages/javascript')
+ }
+ break
+ }
+ case 'py':
+ case 'python':{
+ lang = 'python'
+ if(!hljs.getLanguage('python')){
+ languageModule = await import('highlight.js/lib/languages/python')
+ }
+ break
+ }
+ case 'css':{
+ lang = 'css'
+ if(!hljs.getLanguage('css')){
+ languageModule = await import('highlight.js/lib/languages/css')
+ }
+ break
+ }
+ case 'xml':
+ case 'html':{
+ lang = 'xml'
+ if(!hljs.getLanguage('xml')){
+ languageModule = await import('highlight.js/lib/languages/xml')
+ }
+ break
+ }
+ case 'lua':{
+ lang = 'lua'
+ if(!hljs.getLanguage('lua')){
+ languageModule = await import('highlight.js/lib/languages/lua')
+ }
+ break
+ }
+ case 'dart':{
+ lang = 'dart'
+ if(!hljs.getLanguage('dart')){
+ languageModule = await import('highlight.js/lib/languages/dart')
+ }
+ break
+ }
+ case 'java':{
+ lang = 'java'
+ if(!hljs.getLanguage('java')){
+ languageModule = await import('highlight.js/lib/languages/java')
+ }
+ break
+ }
+ case 'rust':{
+ lang = 'rust'
+ if(!hljs.getLanguage('rust')){
+ languageModule = await import('highlight.js/lib/languages/rust')
+ }
+ break
+ }
+ case 'c':
+ case 'cpp':{
+ lang = 'cpp'
+ if(!hljs.getLanguage('cpp')){
+ languageModule = await import('highlight.js/lib/languages/cpp')
+ }
+ break
+ }
+ case 'csharp':
+ case 'cs':{
+ lang = 'csharp'
+ if(!hljs.getLanguage('csharp')){
+ languageModule = await import('highlight.js/lib/languages/csharp')
+ }
+ break
+ }
+ case 'ts':
+ case 'typescript':{
+ lang = 'typescript'
+ if(!hljs.getLanguage('typescript')){
+ languageModule = await import('highlight.js/lib/languages/typescript')
+ }
+ break
+ }
+ case 'json':{
+ lang = 'json'
+ if(!hljs.getLanguage('json')){
+ languageModule = await import('highlight.js/lib/languages/json')
+ }
+ break
+ }
+ case 'yaml':{
+ lang = 'yaml'
+ if(!hljs.getLanguage('yaml')){
+ languageModule = await import('highlight.js/lib/languages/yaml')
+ }
+ break
+ }
+ case 'shell':{
+ lang = 'shell'
+ if(!hljs.getLanguage('shell')){
+ languageModule = await import('highlight.js/lib/languages/shell')
+ }
+ break
+ }
+ case 'bash':{
+ lang = 'bash'
+ if(!hljs.getLanguage('bash')){
+ languageModule = await import('highlight.js/lib/languages/bash')
+ }
+ break
+ }
+ default:{
+ lang = 'none'
+ }
+ }
+ if(languageModule){
+ hljs.registerLanguage(lang, languageModule.default)
+ }
+ if(lang === 'none'){
+ rendered = rendered.replace(placeholder, `${md.utils.escapeHtml(code)}
`)
+ }
+ else{
+ const highlighted = hljs.highlight(code, {
+ language: lang,
+ ignoreIllegals: true
+ }).value
+ rendered = rendered.replace(placeholder, `${highlighted}
`)
+ }
+ } catch (error) {
+
+ }
+ }
+
+ return rendered
+
+}
+
export const assetRegex = /{{(raw|img|video|audio|bg|emotion|asset|video-img)::(.+?)}}/g
@@ -211,7 +366,7 @@ export async function ParseMarkdown(data:string, charArg:(character|simpleCharac
data = encodeStyle(data)
if(mode === 'normal'){
- data = renderMarkdown(data)
+ data = await renderHighlightableMarkdown(data)
}
return decodeStyle(DOMPurify.sanitize(data, {
ADD_TAGS: ["iframe", "style", "risu-style", "x-em"],
@@ -219,7 +374,7 @@ export async function ParseMarkdown(data:string, charArg:(character|simpleCharac
}))
}
-export function postTranslationParse(data:string){
+export async function postTranslationParse(data:string){
let lines = data.split('\n')
for(let i=0;i