Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"emoji-js": "3.9.0",
"export-to-csv": "1.4.0",
"franc-min": "6.2.0",
"graphemer": "1.4.0",
"highlight.js": "11.11.1",
"hls.js": "1.6.16",
"html-diff-ts": "1.4.2",
Expand All @@ -63,7 +62,6 @@
"lodash-es": "4.18.1",
"markdown-it": "14.2.0",
"markdown-it-github-alerts": "1.0.1",
"markdown-it-highlightjs": "4.3.0",
Comment thread
FelixTJDietrich marked this conversation as resolved.
"monaco-editor": "0.55.1",
"ngx-extended-pdf-viewer": "27.0.0",
"ngx-infinite-scroll": "21.0.0",
Expand Down
18 changes: 0 additions & 18 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { MonacoEditorLineHighlight } from 'app/editor/monaco-editor/model/monaco
import { MonacoEditorOptionPreset } from 'app/editor/monaco-editor/model/monaco-editor-option-preset.model';
import { MonacoEditorService } from 'app/editor/monaco-editor/service/monaco-editor.service';
import { getOS } from 'app/foundation/util/os-detector.util';
import Graphemer from 'graphemer';

import { EmojiConvertor } from 'emoji-js';
import * as monaco from 'monaco-editor';
Expand Down Expand Up @@ -1054,8 +1053,8 @@ export class MonacoEditorComponent implements OnInit, OnDestroy {
const lineContent = model.getLineContent(lineNumber);

const textBeforeCursor = lineContent.substring(0, column - 1);
const splitter = new Graphemer();
const graphemes = splitter.splitGraphemes(textBeforeCursor);
const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
const graphemes = Array.from(segmenter.segment(textBeforeCursor), (segment) => segment.segment);
Comment thread
krusche marked this conversation as resolved.
Outdated

if (textBeforeCursor.length === 0) {
editor.trigger('keyboard', 'deleteLeft', null);
Expand Down
51 changes: 48 additions & 3 deletions src/main/webapp/app/foundation/util/markdown.conversion.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import DOMPurify, { Config } from 'dompurify';
import type { PluginSimple } from 'markdown-it';
import type Token from 'markdown-it/lib/token.mjs';
import MarkdownItKatex from '@vscode/markdown-it-katex';
import MarkdownItHighlightjs from 'markdown-it-highlightjs';
import hljs from 'highlight.js';
import TurndownService from 'turndown';
import MarkdownIt from 'markdown-it';
import MarkdownItGitHubAlerts from 'markdown-it-github-alerts';
Expand Down Expand Up @@ -31,6 +31,51 @@ const formulaCompatibilityPlugin = new FormulaCompatibilityPlugin();

const turndownService = new TurndownService();

type MarkdownRenderRule = NonNullable<MarkdownIt['renderer']['rules']['fence']>;

/**
* Highlights a code block with highlight.js, mirroring the behavior of the previously used
* `markdown-it-highlightjs` plugin (auto-detect the language when none is given, otherwise
* highlight with the explicit language, and fall back to escaped HTML on any error).
*/
function highlightWithHljs(md: MarkdownIt, code: string, language: string): string {
try {
if (language) {
return hljs.highlight(code, { language, ignoreIllegals: true }).value;
}
return hljs.highlightAuto(code).value;
} catch {
return md.utils.escapeHtml(code);
}
}
Comment thread
krusche marked this conversation as resolved.

/**
* Wraps a code renderer so the rendered `<code>` element gains the `hljs` CSS class, matching the
* markup `markdown-it-highlightjs` produced. The highlight.js themes (vs.css / monokai.css) target
* this class, so preserving it keeps syntax highlighting styled in both the light and dark theme.
*/
function addHljsClass(renderer: MarkdownRenderRule): MarkdownRenderRule {
return (...args: Parameters<MarkdownRenderRule>) =>
renderer(...args)
.replace(/<code class="/g, '<code class="hljs ')
.replace(/<code>/g, '<code class="hljs">');
}
Comment thread
krusche marked this conversation as resolved.

/**
* Local replacement for the `markdown-it-highlightjs` dependency, configured to match the default
* options it was previously used with (auto language detection, highlight fenced and indented code
* blocks, ignore illegal sequences). The highlight.js engine itself stays a direct dependency.
*/
const markdownItHighlightjs: PluginSimple = (md) => {
md.options.highlight = (code, language) => highlightWithHljs(md, code, language);
if (md.renderer.rules.fence) {
md.renderer.rules.fence = addHljsClass(md.renderer.rules.fence);
}
if (md.renderer.rules.code_block) {
md.renderer.rules.code_block = addHljsClass(md.renderer.rules.code_block);
}
};

/**
* Cache for MarkdownIt instances to avoid expensive re-initialization on every render.
* Only caches the default instance (no custom extensions) since custom extensions
Expand Down Expand Up @@ -62,7 +107,7 @@ function getOrCreateMarkdownIt(extensions: PluginSimple[], lineBreaks: boolean):

// Add default extensions (Code Highlight, Latex, Alerts)
markdownIt
.use(MarkdownItHighlightjs)
.use(markdownItHighlightjs)
.use(formulaCompatibilityPlugin.getExtension())
.use(MarkdownItKatex, {
enableMathInlineInHtml: true,
Expand Down Expand Up @@ -92,7 +137,7 @@ function getOrCreateMarkdownIt(extensions: PluginSimple[], lineBreaks: boolean):
// Add default extensions (Code Highlight, Latex, Alerts)
markdownIt
// Code Highlight
.use(MarkdownItHighlightjs)
.use(markdownItHighlightjs)
.use(formulaCompatibilityPlugin.getExtension())
// Latex formulas
.use(MarkdownItKatex, {
Expand Down
Loading