mirror of
https://github.com/mayurankv/Obsidian-Code-Styler.git
synced 2026-07-22 08:10:29 +00:00
Refactoring
This commit is contained in:
parent
8e9c62bec8
commit
00c1907a4e
12 changed files with 634 additions and 625 deletions
2
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
2
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
|
|
@ -34,6 +34,8 @@ assignees: 'mayurankv'
|
|||
- Obsidian Version: <!-- Obsidian Version -->
|
||||
- Platform: <!-- Desktop or Mobile -->
|
||||
- OS: <!-- OS -->
|
||||
- Theme: <!-- Obsidian Theme -->
|
||||
- CSS Snippets: <!-- Do you have any CSS Snippets enabled? -->
|
||||
<!-- Other details that you think may affect this issue -->
|
||||
|
||||
### Screenshots
|
||||
|
|
|
|||
11
.github/TODO.md
vendored
11
.github/TODO.md
vendored
|
|
@ -27,8 +27,7 @@
|
|||
3. Add syntax highlighting for inline code to source view editing mode?
|
||||
4. Add command to select all text inside current codeblock
|
||||
5. Debug really long codeblocks not working
|
||||
6. Debug live preview callouts not working
|
||||
7. Add or update icons for:
|
||||
6. Add or update icons for:
|
||||
- `regex`
|
||||
- `maxima`
|
||||
- `zsh`
|
||||
|
|
@ -38,9 +37,11 @@
|
|||
- `ts`
|
||||
- `julia`
|
||||
- `java`
|
||||
8. Changing line wrap options can be flaky
|
||||
9. Make reset buttons only appear when value is not default value (in settings)
|
||||
10. Implement Live preview re-rendering for relevant settings (search '//TODO (@mayurankv) Re-render' in `settingsTab.ts`)
|
||||
7. Changing line wrap options can be flaky
|
||||
8. Make reset buttons only appear when value is not default value (in settings)
|
||||
9. Implement Live preview re-rendering for relevant settings (search '//TODO (@mayurankv) Re-render' in `settingsTab.ts`)
|
||||
10. Reduce cognitive complexity (and other issues)`
|
||||
11. Clean up reading view `remakeCodeblock`
|
||||
|
||||
See below:
|
||||
|
||||
|
|
|
|||
552
main.js
552
main.js
File diff suppressed because one or more lines are too long
|
|
@ -35,7 +35,7 @@ const THEME_STYLES: Record<string,ThemeStyle> = {
|
|||
}
|
||||
|
||||
export function updateStyling(settings: CodeStylerSettings, app: App): void {
|
||||
let currentTheme = getCurrentTheme(app);
|
||||
const currentTheme = getCurrentTheme(app);
|
||||
let styleTag = document.getElementById(STYLE_ID);
|
||||
if (!styleTag) {
|
||||
styleTag = document.createElement('style');
|
||||
|
|
@ -157,20 +157,9 @@ function styleLanguageColours (themeSettings: CodeStylerThemeSettings, redirectL
|
|||
}
|
||||
|
||||
function addThemeSettingsClasses (themeSettings: CodeStylerThemeSettings): void {
|
||||
if (themeSettings.codeblock.lineNumbers)
|
||||
document.body.classList.add("code-styler-show-line-numbers");
|
||||
else
|
||||
document.body.classList.remove("code-styler-show-line-numbers");
|
||||
|
||||
if (themeSettings.gutter.highlight)
|
||||
document.body.classList.add('code-styler-gutter-highlight');
|
||||
else
|
||||
document.body.classList.remove('code-styler-gutter-highlight');
|
||||
|
||||
if (themeSettings.gutter.activeLine)
|
||||
document.body.classList.add('code-styler-gutter-active-line');
|
||||
else
|
||||
document.body.classList.remove('code-styler-gutter-active-line');
|
||||
themeSettings.codeblock.lineNumbers ? document.body.classList.add("code-styler-show-line-numbers") : document.body.classList.remove("code-styler-show-line-numbers");
|
||||
themeSettings.gutter.highlight ? document.body.classList.add('code-styler-gutter-highlight') : document.body.classList.remove('code-styler-gutter-highlight');
|
||||
themeSettings.gutter.activeLine ? document.body.classList.add('code-styler-gutter-active-line') : document.body.classList.remove('code-styler-gutter-active-line');
|
||||
|
||||
document.body.classList.remove("code-styler-active-line-highlight","code-styler-active-line-highlight-codeblock","code-styler-active-line-highlight-editor")
|
||||
if (themeSettings.highlights.activeEditorLine && themeSettings.highlights.activeCodeblockLine) // Inside and outside of codeblocks with different colours
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export function createInlineOpener(inlineCodeParameters: InlineCodeParameters, l
|
|||
openerContainer.appendChild(createSpan({cls: `code-styler-inline-title`, text: inlineCodeParameters.title}));
|
||||
return openerContainer;
|
||||
}
|
||||
function createImageWrapper(iconURL: string, imageWrapper: HTMLElement, imgClass: string = "code-styler-icon"): HTMLElement {
|
||||
function createImageWrapper(iconURL: string, imageWrapper: HTMLElement, imgClass = "code-styler-icon"): HTMLElement {
|
||||
const img = document.createElement("img");
|
||||
img.classList.add(imgClass);
|
||||
img.src = iconURL;
|
||||
|
|
@ -67,3 +67,11 @@ export function getLineClass(codeblockParameters: CodeblockParameters, lineNumbe
|
|||
classList = ['code-styler-line']
|
||||
return classList;
|
||||
}
|
||||
export function getLineNumberDisplay(codeblockParameters: CodeblockParameters): string {
|
||||
let lineNumberDisplay = '';
|
||||
if (!codeblockParameters.lineNumbers.alwaysEnabled && codeblockParameters.lineNumbers.alwaysDisabled)
|
||||
lineNumberDisplay = '-hide';
|
||||
else if (codeblockParameters.lineNumbers.alwaysEnabled && !codeblockParameters.lineNumbers.alwaysDisabled)
|
||||
lineNumberDisplay = '-specific';
|
||||
return lineNumberDisplay;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,19 +42,22 @@ export async function parseCodeblockSource(codeSection: Array<string>, sourcePat
|
|||
//@ts-expect-error Undocumented Obsidian API
|
||||
const plugins: Record<string,any> = plugin.app.plugins.plugins;
|
||||
const admonitions: boolean = 'obsidian-admonition' in plugins;
|
||||
let codeblocks: Array<Array<string>> = [];
|
||||
let codeblocksParameters: Array<CodeblockParameters> = [];
|
||||
const codeblocks: Array<Array<string>> = [];
|
||||
const codeblocksParameters: Array<CodeblockParameters> = [];
|
||||
function parseCodeblockSection(codeSection: Array<string>): void {
|
||||
if (codeSection.length === 0)
|
||||
return;
|
||||
let openingCodeblockLine = getOpeningLine(codeSection);
|
||||
|
||||
const openingCodeblockLine = getOpeningLine(codeSection);
|
||||
if (!openingCodeblockLine)
|
||||
return;
|
||||
let openDelimiter = /^\s*(?:>\s*)*((?:```+|~~~+)).*$/.exec(openingCodeblockLine)?.[1];
|
||||
|
||||
const openDelimiter = /^\s*(?:>\s*)*((?:```+|~~~+)).*$/.exec(openingCodeblockLine)?.[1];
|
||||
if (!openDelimiter)
|
||||
return;
|
||||
let openDelimiterIndex = codeSection.indexOf(openingCodeblockLine);
|
||||
let closeDelimiterIndex = codeSection.slice(openDelimiterIndex+1).findIndex((line)=>line.indexOf(openDelimiter as string)!==-1);
|
||||
|
||||
const openDelimiterIndex = codeSection.indexOf(openingCodeblockLine);
|
||||
const closeDelimiterIndex = codeSection.slice(openDelimiterIndex+1).findIndex((line)=>line.indexOf(openDelimiter)!==-1);
|
||||
if (!admonitions || !/^\s*(?:>\s*)*(?:```+|~~~+) *ad-.*$/.test(openingCodeblockLine))
|
||||
codeblocks.push(codeSection.slice(0,openDelimiterIndex+2+closeDelimiterIndex))
|
||||
else
|
||||
|
|
@ -63,8 +66,8 @@ export async function parseCodeblockSource(codeSection: Array<string>, sourcePat
|
|||
parseCodeblockSection(codeSection.slice(openDelimiterIndex+1+closeDelimiterIndex+1));
|
||||
}
|
||||
parseCodeblockSection(codeSection);
|
||||
for (let codeblockLines of codeblocks) {
|
||||
let parameterLine = getParameterLine(codeblockLines);
|
||||
for (const codeblockLines of codeblocks) {
|
||||
const parameterLine = getParameterLine(codeblockLines);
|
||||
if (!parameterLine)
|
||||
continue;
|
||||
let codeblockParameters = parseCodeblockParameters(parameterLine,plugin.settings.currentTheme);
|
||||
|
|
@ -79,7 +82,7 @@ export async function parseCodeblockSource(codeSection: Array<string>, sourcePat
|
|||
}
|
||||
export function parseInlineCode(codeText: string): {parameters: InlineCodeParameters | null, text: string} {
|
||||
|
||||
let match = /^({} ?)?{([^}]*)} ?(.*)$/.exec(codeText);
|
||||
const match = /^({} ?)?{([^}]*)} ?(.*)$/.exec(codeText);
|
||||
|
||||
if (!match?.[1] && !(match?.[2] && match?.[3]))
|
||||
return {parameters: null, text: ''};
|
||||
|
|
@ -90,7 +93,7 @@ export function parseInlineCode(codeText: string): {parameters: InlineCodeParame
|
|||
}
|
||||
|
||||
export function parseCodeblockParameters(parameterLine: string, theme: CodeStylerTheme): CodeblockParameters {
|
||||
let codeblockParameters: CodeblockParameters = {
|
||||
const codeblockParameters: CodeblockParameters = {
|
||||
language: '',
|
||||
title: '',
|
||||
fold: {
|
||||
|
|
@ -124,7 +127,7 @@ export function parseCodeblockParameters(parameterLine: string, theme: CodeStyle
|
|||
} else {
|
||||
return codeblockParameters;
|
||||
}
|
||||
let languageBreak = parameterLine.indexOf(' ');
|
||||
const languageBreak = parameterLine.indexOf(' ');
|
||||
codeblockParameters.language = parameterLine.slice(0,languageBreak !== -1?languageBreak:parameterLine.length).toLowerCase();
|
||||
if (languageBreak === -1)
|
||||
return codeblockParameters;
|
||||
|
|
@ -137,7 +140,7 @@ export function parseCodeblockParameters(parameterLine: string, theme: CodeStyle
|
|||
export async function pluginAdjustParameters(codeblockParameters: CodeblockParameters, plugins: Record<string,any>, codeblockLines: Array<string>, sourcePath: string): Promise<CodeblockParameters> {
|
||||
if (codeblockParameters.language === 'preview') {
|
||||
if ('obsidian-code-preview' in plugins) {
|
||||
let codePreviewParams = await plugins['obsidian-code-preview'].code(codeblockLines.slice(1,-1).join('\n'),sourcePath);
|
||||
const codePreviewParams = await plugins['obsidian-code-preview'].code(codeblockLines.slice(1,-1).join('\n'),sourcePath);
|
||||
if (!codeblockParameters.lineNumbers.alwaysDisabled && !codeblockParameters.lineNumbers.alwaysEnabled) {
|
||||
if (typeof codePreviewParams.start === 'number')
|
||||
codeblockParameters.lineNumbers.offset = codePreviewParams.start - 1;
|
||||
|
|
@ -158,12 +161,12 @@ export async function pluginAdjustParameters(codeblockParameters: CodeblockParam
|
|||
return codeblockParameters
|
||||
}
|
||||
function parseInlineCodeParameters(parameterLine: string): InlineCodeParameters {
|
||||
let inlineCodeParameters: InlineCodeParameters = {
|
||||
const inlineCodeParameters: InlineCodeParameters = {
|
||||
language: '',
|
||||
title: '',
|
||||
icon: false,
|
||||
}
|
||||
let languageBreak = parameterLine.indexOf(' ');
|
||||
const languageBreak = parameterLine.indexOf(' ');
|
||||
inlineCodeParameters.language = parameterLine.slice(0,languageBreak !== -1?languageBreak:parameterLine.length).toLowerCase();
|
||||
if (languageBreak === -1)
|
||||
return inlineCodeParameters;
|
||||
|
|
@ -176,11 +179,11 @@ function parseInlineCodeParameters(parameterLine: string): InlineCodeParameters
|
|||
|
||||
function parseCodeblockParameterString(parameterString: string, codeblockParameters: CodeblockParameters, theme: CodeStylerTheme): void {
|
||||
if (parameterString.startsWith('title:')) {
|
||||
let titleMatch = /(["']?)([^\1]+)\1/.exec(parameterString.slice('title:'.length));
|
||||
const titleMatch = /(["']?)([^\1]+)\1/.exec(parameterString.slice('title:'.length));
|
||||
if (titleMatch)
|
||||
codeblockParameters.title = titleMatch[2].trim();
|
||||
} else if (parameterString.startsWith('fold:')) {
|
||||
let foldPlaceholderMatch = /(["']?)([^\1]+)\1/.exec(parameterString.slice('fold:'.length));
|
||||
const foldPlaceholderMatch = /(["']?)([^\1]+)\1/.exec(parameterString.slice('fold:'.length));
|
||||
if (foldPlaceholderMatch) {
|
||||
codeblockParameters.fold = {
|
||||
enabled: true,
|
||||
|
|
@ -249,9 +252,9 @@ function parseCodeblockParameterString(parameterString: string, codeblockParamet
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let highlightMatch = /^(\w+):(.+)$/.exec(parameterString);
|
||||
const highlightMatch = /^(\w+):(.+)$/.exec(parameterString);
|
||||
if (highlightMatch) {
|
||||
let highlights = parseHighlightedLines(highlightMatch[2]);
|
||||
const highlights = parseHighlightedLines(highlightMatch[2]);
|
||||
if (highlightMatch[1] === 'hl')
|
||||
codeblockParameters.highlights.default = highlights;
|
||||
else
|
||||
|
|
@ -262,9 +265,9 @@ function parseCodeblockParameterString(parameterString: string, codeblockParamet
|
|||
}
|
||||
function parseHighlightedLines(highlightedLinesString: string): Highlights {
|
||||
const highlightRules = highlightedLinesString.split(',');
|
||||
let lineNumbers: Set<number> = new Set();
|
||||
let plainText: Set<string> = new Set();
|
||||
let regularExpressions: Set<RegExp> = new Set();
|
||||
const lineNumbers: Set<number> = new Set();
|
||||
const plainText: Set<string> = new Set();
|
||||
const regularExpressions: Set<RegExp> = new Set();
|
||||
highlightRules.forEach(highlightRule => {
|
||||
if (/\d+-\d+/.test(highlightRule)) { // Number Range
|
||||
const [start,end] = highlightRule.split('-').map(num => parseInt(num));
|
||||
|
|
@ -273,7 +276,9 @@ function parseHighlightedLines(highlightedLinesString: string): Highlights {
|
|||
} else if (/^\/(.*)\/$/.test(highlightRule)) { // Regex
|
||||
try {
|
||||
regularExpressions.add(new RegExp(highlightRule.replace(/^\/(.*)\/$/,"$1")));
|
||||
} catch { }
|
||||
} catch {
|
||||
//pass
|
||||
}
|
||||
} else if (/".*"/.test(highlightRule)) { // Plain Text
|
||||
plainText.add(highlightRule.substring(1,highlightRule.length-1));
|
||||
} else if (/'.*'/.test(highlightRule)) { // Plain Text
|
||||
|
|
@ -301,7 +306,7 @@ function parseRegexExcludedLanguages(excludedLanguagesString: string): Array<Reg
|
|||
}
|
||||
function parseInlineCodeParameterString(parameterString: string, inlineCodeParameters: InlineCodeParameters): void {
|
||||
if (parameterString.startsWith('title:')) {
|
||||
let titleMatch = /(["']?)([^\1]+)\1/.exec(parameterString.slice('title:'.length));
|
||||
const titleMatch = /(["']?)([^\1]+)\1/.exec(parameterString.slice('title:'.length));
|
||||
if (titleMatch)
|
||||
inlineCodeParameters.title = titleMatch[2].trim();
|
||||
} else if (parameterString === 'icon' || (parameterString.startsWith('icon:') && parameterString.toLowerCase() === 'icon:true')) {
|
||||
|
|
@ -311,7 +316,7 @@ function parseInlineCodeParameterString(parameterString: string, inlineCodeParam
|
|||
|
||||
export function getParameterLine(codeblockLines: Array<string>): string | undefined {
|
||||
let openingCodeblockLine = getOpeningLine(codeblockLines);
|
||||
if (openingCodeblockLine && (openingCodeblockLine !== codeblockLines[0] || />\s*(?:`|~)/.test(openingCodeblockLine)))
|
||||
if (openingCodeblockLine && (openingCodeblockLine !== codeblockLines[0] || />\s*(?:[`~])/.test(openingCodeblockLine)))
|
||||
openingCodeblockLine = cleanParameterLine(openingCodeblockLine);
|
||||
return openingCodeblockLine
|
||||
}
|
||||
|
|
@ -319,7 +324,7 @@ function getOpeningLine(codeblockLines: Array<string>): string | undefined {
|
|||
return codeblockLines.find((line: string)=>Boolean(testOpeningLine(line)));
|
||||
}
|
||||
export function testOpeningLine(codeblockLine: string): string {
|
||||
let lineMatch = /^(\s*(?:>\s*)*)(```+|~~~+)/.exec(codeblockLine);
|
||||
const lineMatch = /^(\s*(?:>\s*)*)(```+|~~~+)/.exec(codeblockLine);
|
||||
if (!lineMatch)
|
||||
return '';
|
||||
if (codeblockLine.indexOf(lineMatch[2],lineMatch[1].length+lineMatch[2].length+1)===-1)
|
||||
|
|
@ -348,6 +353,6 @@ export async function getFileContentLines(sourcePath: string, plugin: CodeStyler
|
|||
return fileContent.split(/\n/g);
|
||||
}
|
||||
|
||||
export function arraysEqual(array1: Array<any>,array2: Array<any>): boolean {
|
||||
export function arraysEqual(array1: Array<unknown>,array2: Array<unknown>): boolean {
|
||||
return array1.length === array2.length && array1.every((el) => array2.includes(el));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import { editorEditorField, editorInfoField, editorLivePreviewField } from "obsidian";
|
||||
import { ViewPlugin, EditorView, ViewUpdate, Decoration, DecorationSet, WidgetType } from "@codemirror/view";
|
||||
import { Extension, EditorState, StateField, StateEffect, StateEffectType, Range, RangeSetBuilder, Transaction, TransactionSpec, Line, SelectionRange, Annotation } from "@codemirror/state";
|
||||
import { syntaxTree, tokenClassNodeProp, LanguageSupport } from "@codemirror/language";
|
||||
import { syntaxTree, tokenClassNodeProp } from "@codemirror/language";
|
||||
import { SyntaxNodeRef } from "@lezer/common";
|
||||
import { highlightTree, classHighlighter } from "@lezer/highlight";
|
||||
//NOSONAR
|
||||
// import { LanguageSupport } from "@codemirror/language"; //NOTE: For future CM6 Compatibility
|
||||
// import { highlightTree, classHighlighter } from "@lezer/highlight"; //NOTE: For future CM6 Compatibility
|
||||
// import { languages } from "@codemirror/language-data"; //NOTE: For future CM6 Compatibility
|
||||
|
||||
import { CodeStylerSettings, CodeStylerThemeSettings } from "./Settings";
|
||||
import { CodeblockParameters, parseCodeblockParameters, testOpeningLine, isExcluded, arraysEqual, trimParameterLine, InlineCodeParameters, parseInlineCode } from "./CodeblockParsing";
|
||||
import { createHeader, createInlineOpener, getLanguageIcon, getLineClass } from "./CodeblockDecorating";
|
||||
import { createHeader, createInlineOpener, getLanguageIcon, getLineClass, getLineNumberDisplay } from "./CodeblockDecorating";
|
||||
|
||||
export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings, languageIcons: Record<string,string>) {
|
||||
const codeblockLineNumberCharWidth = StateField.define<number>({
|
||||
|
|
@ -92,9 +94,9 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
const codeblocks = findUnduplicatedCodeblocks(view);
|
||||
for (const codeblock of codeblocks) {
|
||||
let codeblockParameters: CodeblockParameters;
|
||||
let excludedCodeblock: boolean = false;
|
||||
let lineNumber: number = 0;
|
||||
let maxLineNum: number = 0;
|
||||
let excludedCodeblock = false;
|
||||
let lineNumber = 0;
|
||||
let maxLineNum = 0;
|
||||
let lineNumberMargin: number | undefined = 0;
|
||||
syntaxTree(view.state).iterate({from: codeblock.from, to: codeblock.to,
|
||||
enter: (syntaxNode)=>{
|
||||
|
|
@ -107,7 +109,7 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
excludedCodeblock = isExcluded(codeblockParameters.language,[this.settings.excludedCodeblocks,this.settings.excludedLanguages].join(',')) || codeblockParameters.ignore;
|
||||
lineNumber = 0;
|
||||
let lineNumberCount = line.number + 1;
|
||||
let startDelimiter = testOpeningLine(lineText);
|
||||
const startDelimiter = testOpeningLine(lineText);
|
||||
while (startDelimiter !== testOpeningLine(view.state.doc.line(lineNumberCount).text)) {
|
||||
lineNumberCount += 1;
|
||||
}
|
||||
|
|
@ -149,12 +151,12 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
return Decoration.none;
|
||||
const builder = new RangeSetBuilder<Decoration>();
|
||||
let codeblockParameters: CodeblockParameters;
|
||||
let startLine: boolean = true;
|
||||
let startDelimiter: string = '```';
|
||||
let startLine = true;
|
||||
let startDelimiter = '```';
|
||||
for (let i = 1; i < transaction.state.doc.lines; i++) {
|
||||
const line = transaction.state.doc.line(i);
|
||||
const lineText = line.text.toString();
|
||||
let currentDelimiter = testOpeningLine(lineText);
|
||||
const currentDelimiter = testOpeningLine(lineText);
|
||||
if (currentDelimiter) {
|
||||
if (startLine) {
|
||||
startLine = false;
|
||||
|
|
@ -185,12 +187,12 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
let codeblockParameters: CodeblockParameters;
|
||||
let collapseStart: Line | null = null;
|
||||
let collapseEnd: Line | null = null;
|
||||
let startLine: boolean = true;
|
||||
let startDelimiter: string = '```';
|
||||
let startLine = true;
|
||||
let startDelimiter = '```';
|
||||
for (let i = 1; i < state.doc.lines; i++) {
|
||||
const line = state.doc.line(i);
|
||||
const lineText = line.text.toString();
|
||||
let currentDelimiter = testOpeningLine(lineText);
|
||||
const currentDelimiter = testOpeningLine(lineText);
|
||||
if (currentDelimiter) {
|
||||
if (startLine) {
|
||||
startLine = false;
|
||||
|
|
@ -252,6 +254,7 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
decorations: DecorationSet;
|
||||
settings: CodeStylerSettings;
|
||||
syntaxHighlight: boolean;
|
||||
//NOSONAR
|
||||
// loadedLanguages: Record<string,LanguageSupport>; //NOTE: For future CM6 Compatibility
|
||||
|
||||
constructor(view: EditorView) {
|
||||
|
|
@ -259,17 +262,17 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
this.settings = settings;
|
||||
this.syntaxHighlight = settings.currentTheme.settings.inline.syntaxHighlight;
|
||||
this.buildDecorations(view);
|
||||
//NOSONAR
|
||||
// this.loadedLanguages = {}; //NOTE: For future CM6 Compatibility
|
||||
}
|
||||
|
||||
update(update: ViewUpdate) {
|
||||
if (update.docChanged || update.viewportChanged || update.selectionSet || update.state.field(editorLivePreviewField)!==update.startState.field(editorLivePreviewField) || this.settings.currentTheme.settings.inline.syntaxHighlight !== this.syntaxHighlight) {
|
||||
if (this.settings.currentTheme.settings.inline.syntaxHighlight !== this.syntaxHighlight)
|
||||
console.log(this.syntaxHighlight)
|
||||
this.syntaxHighlight = this.settings.currentTheme.settings.inline.syntaxHighlight;
|
||||
if (update.docChanged)
|
||||
this.decorations = this.decorations.map(update.changes);
|
||||
this.buildDecorations(update.view);
|
||||
//NOSONAR
|
||||
//NOTE: For future CM6 Compatibility
|
||||
// const toHighlight = this.buildDecorations(update.view);
|
||||
// toHighlight.forEach((highlightSet)=>{
|
||||
|
|
@ -297,12 +300,14 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
}
|
||||
}
|
||||
|
||||
buildDecorations(view: EditorView): void { //Array<{start: number, text: string, language: string}> //NOTE: For future CM6 Compatibility
|
||||
buildDecorations(view: EditorView): void { //Array<{start: number, text: string, language: string}> //NOTE: For future CM6 Compatibility //NOSONAR
|
||||
if (!view?.visibleRanges?.length || editingViewIgnore(view.state)) {
|
||||
this.decorations = Decoration.none;
|
||||
return;
|
||||
//NOSONAR
|
||||
// return [];//NOTE: For future CM6 Compatibility
|
||||
}
|
||||
//NOSONAR
|
||||
// let toHighlight: Array<{start: number, text: string, language: string}> = []; //NOTE: For future CM6 Compatibility
|
||||
for (const {from,to} of view.visibleRanges) {
|
||||
syntaxTree(view.state).iterate({from: from, to: to,
|
||||
|
|
@ -310,13 +315,13 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
const properties = new Set(syntaxNode.node.type.prop<string>(tokenClassNodeProp)?.split(" "));
|
||||
if (!(properties.has("inline-code") && !properties.has("formatting")))
|
||||
return;
|
||||
let previousSibling = syntaxNode.node.prevSibling;
|
||||
const previousSibling = syntaxNode.node.prevSibling;
|
||||
if (!previousSibling)
|
||||
return;
|
||||
let delimiterSize = previousSibling.to-previousSibling.from;
|
||||
let inlineCodeText = view.state.doc.sliceString(syntaxNode.from, syntaxNode.to);
|
||||
let {parameters,text} = parseInlineCode(inlineCodeText);
|
||||
let endOfParameters = inlineCodeText.lastIndexOf(text);
|
||||
const delimiterSize = previousSibling.to-previousSibling.from;
|
||||
const inlineCodeText = view.state.doc.sliceString(syntaxNode.from, syntaxNode.to);
|
||||
const {parameters,text} = parseInlineCode(inlineCodeText);
|
||||
const endOfParameters = inlineCodeText.lastIndexOf(text);
|
||||
if (!parameters) {
|
||||
if (text) {
|
||||
if (view.state.selection.ranges.some((range: SelectionRange)=>range.to >= syntaxNode.from-delimiterSize && range.from <= syntaxNode.to+delimiterSize))
|
||||
|
|
@ -346,11 +351,12 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
if (!settings.currentTheme.settings.inline.syntaxHighlight)
|
||||
return;
|
||||
this.decorations = this.decorations.update({add: modeHighlight({start: syntaxNode.from + endOfParameters, text: text, language: parameters.language})});
|
||||
//NOSONAR
|
||||
// toHighlight.push({start: syntaxNode.from + endOfParameters, text: text, language: parameters.language}); //NOTE: For future CM6 Compatibility
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
// return toHighlight; //NOTE: For future CM6 Compatibility
|
||||
}
|
||||
},
|
||||
|
|
@ -360,9 +366,9 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
)
|
||||
function cursorIntoCollapsedTransactionFilter() {
|
||||
return EditorState.transactionFilter.of((transaction) => {
|
||||
let extraTransactions: Array<TransactionSpec> = [];
|
||||
let collapsedRangeSet = transaction.startState.field(codeblockCollapse,false)?.map(transaction.changes) ?? Decoration.none;
|
||||
let temporarilyUncollapsedRangeSet = transaction.startState.field(temporarilyUncollapsed,false)?.map(transaction.changes) ?? Decoration.none;
|
||||
const extraTransactions: Array<TransactionSpec> = [];
|
||||
const collapsedRangeSet = transaction.startState.field(codeblockCollapse,false)?.map(transaction.changes) ?? Decoration.none;
|
||||
const temporarilyUncollapsedRangeSet = transaction.startState.field(temporarilyUncollapsed,false)?.map(transaction.changes) ?? Decoration.none;
|
||||
transaction.newSelection.ranges.forEach((range: SelectionRange)=>{
|
||||
collapsedRangeSet.between(range.from, range.to, (collapseStartFrom, collapseEndTo, decorationValue) => {
|
||||
if (collapseStartFrom <= range.head && range.head <= collapseEndTo)
|
||||
|
|
@ -380,28 +386,28 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
}
|
||||
|
||||
//todo Finish this filter
|
||||
function manageCollapsedTransactionFilter() {
|
||||
return EditorState.transactionFilter.of((transaction) => {
|
||||
let extraTransactions: Array<TransactionSpec> = [];
|
||||
let collapsedRangeSet = transaction.startState.field(codeblockCollapse,false) ?? Decoration.none;
|
||||
let temporarilyUncollapsedRangeSet = transaction.startState.field(temporarilyUncollapsed,false) ?? Decoration.none;
|
||||
transaction.changes.iterChanges((fromA,toA,fromB,toB,inserted)=>{
|
||||
if (fromB === toB && inserted.toString() === '') {
|
||||
console.log(fromA,toA,fromB,toB,inserted)
|
||||
collapsedRangeSet.between(fromA-100, toA+100, (collapseStartFrom, collapseEndTo, decorationValue) => {
|
||||
console.log(fromA,toA,collapseStartFrom,collapseEndTo)
|
||||
if ((fromA <= collapseStartFrom && collapseStartFrom <= toA) || (fromA <= collapseEndTo && collapseEndTo <= toA))
|
||||
extraTransactions.push({effects: uncollapse.of({filter: (from,to) => (to <= collapseStartFrom || from >= collapseEndTo), filterFrom: collapseStartFrom, filterTo: collapseEndTo}), annotations: temporaryUncollapseAnnotation.of({decorationRange: {from: collapseStartFrom, to: collapseEndTo, value: decorationValue}, uncollapse: true})});
|
||||
});
|
||||
}
|
||||
});
|
||||
if (extraTransactions.length !== 0)
|
||||
console.log('foo',extraTransactions)
|
||||
if (extraTransactions.length !== 0)
|
||||
return [transaction,...extraTransactions];
|
||||
return transaction;
|
||||
});
|
||||
}
|
||||
// function manageCollapsedTransactionFilter() {
|
||||
// return EditorState.transactionFilter.of((transaction) => {
|
||||
// const extraTransactions: Array<TransactionSpec> = [];
|
||||
// const collapsedRangeSet = transaction.startState.field(codeblockCollapse,false) ?? Decoration.none;
|
||||
// const temporarilyUncollapsedRangeSet = transaction.startState.field(temporarilyUncollapsed,false) ?? Decoration.none;
|
||||
// transaction.changes.iterChanges((fromA,toA,fromB,toB,inserted)=>{
|
||||
// if (fromB === toB && inserted.toString() === '') {
|
||||
// console.log(fromA,toA,fromB,toB,inserted)
|
||||
// collapsedRangeSet.between(fromA-100, toA+100, (collapseStartFrom, collapseEndTo, decorationValue) => {
|
||||
// console.log(fromA,toA,collapseStartFrom,collapseEndTo)
|
||||
// if ((fromA <= collapseStartFrom && collapseStartFrom <= toA) || (fromA <= collapseEndTo && collapseEndTo <= toA))
|
||||
// extraTransactions.push({effects: uncollapse.of({filter: (from,to) => (to <= collapseStartFrom || from >= collapseEndTo), filterFrom: collapseStartFrom, filterTo: collapseEndTo}), annotations: temporaryUncollapseAnnotation.of({decorationRange: {from: collapseStartFrom, to: collapseEndTo, value: decorationValue}, uncollapse: true})});
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// if (extraTransactions.length !== 0)
|
||||
// console.log('foo',extraTransactions)
|
||||
// if (extraTransactions.length !== 0)
|
||||
// return [transaction,...extraTransactions];
|
||||
// return transaction;
|
||||
// });
|
||||
// }
|
||||
|
||||
class LineNumberWidget extends WidgetType {
|
||||
lineNumber: number;
|
||||
|
|
@ -422,12 +428,7 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
}
|
||||
|
||||
toDOM(view: EditorView): HTMLElement {
|
||||
let lineNumberDisplay = '';
|
||||
if (!this.codeblockParameters.lineNumbers.alwaysEnabled && this.codeblockParameters.lineNumbers.alwaysDisabled)
|
||||
lineNumberDisplay = '-hide'
|
||||
else if (this.codeblockParameters.lineNumbers.alwaysEnabled && !this.codeblockParameters.lineNumbers.alwaysDisabled)
|
||||
lineNumberDisplay = '-specific'
|
||||
return createSpan({attr: {style: this.maxLineNum.toString().length > (this.lineNumber + this.codeblockParameters.lineNumbers.offset).toString().length?'width: var(--line-number-gutter-width);':''}, cls: `code-styler-line-number${lineNumberDisplay}`, text: this.empty?'':(this.lineNumber + this.codeblockParameters.lineNumbers.offset).toString()});
|
||||
return createSpan({attr: {style: this.maxLineNum.toString().length > (this.lineNumber + this.codeblockParameters.lineNumbers.offset).toString().length?'width: var(--line-number-gutter-width);':''}, cls: `code-styler-line-number${getLineNumberDisplay(this.codeblockParameters)}`, text: this.empty?'':(this.lineNumber + this.codeblockParameters.lineNumbers.offset).toString()});
|
||||
}
|
||||
}
|
||||
class HeaderWidget extends WidgetType {
|
||||
|
|
@ -517,12 +518,12 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
|
||||
let collapseStart: Line | null = null;
|
||||
let collapseEnd: Line | null = null;
|
||||
let startLine: boolean = true;
|
||||
let startDelimiter: string = '```';
|
||||
let startLine = true;
|
||||
let startDelimiter = '```';
|
||||
for (let i = 1; i < view.state.doc.lines; i++) {
|
||||
const line = view.state.doc.line(i);
|
||||
const lineText = line.text.toString();
|
||||
let currentDelimiter = testOpeningLine(lineText);
|
||||
const currentDelimiter = testOpeningLine(lineText);
|
||||
if (currentDelimiter) {
|
||||
if (startLine) {
|
||||
startLine = false;
|
||||
|
|
@ -553,21 +554,21 @@ export function createCodeblockCodeMirrorExtensions(settings: CodeStylerSettings
|
|||
}
|
||||
|
||||
const collapse: StateEffectType<Range<Decoration>> = StateEffect.define();
|
||||
const uncollapse: StateEffectType<{filter: (from: any, to: any) => boolean, filterFrom: number, filterTo: number}> = StateEffect.define();
|
||||
const uncollapse: StateEffectType<{filter: (from: number, to: number) => boolean, filterFrom: number, filterTo: number}> = StateEffect.define();
|
||||
const temporaryUncollapseAnnotation = Annotation.define<{decorationRange: Range<Decoration>, uncollapse: boolean}>();
|
||||
|
||||
return [codeblockLineNumberCharWidth,codeblockLines,codeblockHeader,codeblockCollapse,temporarilyUncollapsed,inlineCodeDecorator,cursorIntoCollapsedTransactionFilter()];
|
||||
}
|
||||
|
||||
function getCharWidth(state: EditorState, default_value: number): number {
|
||||
let charWidths = Array.from(state.field(editorEditorField).contentDOM.querySelectorAll(".HyperMD-codeblock-end")).reduce((result: Array<number>,beginningElement: HTMLElement): Array<number> => {
|
||||
let nextElement = beginningElement.previousElementSibling as HTMLElement;
|
||||
const charWidths = Array.from(state.field(editorEditorField).contentDOM.querySelectorAll(".HyperMD-codeblock-end")).reduce((result: Array<number>,beginningElement: HTMLElement): Array<number> => {
|
||||
const nextElement = beginningElement.previousElementSibling as HTMLElement;
|
||||
if (!nextElement)
|
||||
return result;
|
||||
let lineNumberElement = nextElement.querySelector("[class^='code-styler-line-number']") as HTMLElement;
|
||||
const lineNumberElement = nextElement.querySelector("[class^='code-styler-line-number']") as HTMLElement;
|
||||
if (!lineNumberElement || lineNumberElement.innerText.length <= 2)
|
||||
return result;
|
||||
let computedStyles = window.getComputedStyle(lineNumberElement, null);
|
||||
const computedStyles = window.getComputedStyle(lineNumberElement, null);
|
||||
result.push((lineNumberElement.getBoundingClientRect().width - parseFloat(computedStyles.paddingLeft) - parseFloat(computedStyles.paddingRight)) / lineNumberElement.innerText.length)
|
||||
return result;
|
||||
},[])
|
||||
|
|
@ -600,26 +601,27 @@ function findCodeblocks(view: EditorView): Array<SyntaxNodeRef> {
|
|||
return codeblocks;
|
||||
}
|
||||
|
||||
function languageHighlight({start,text,language}: {start: number, text: string, language: string},loadedLanguages: Record<string,LanguageSupport>): Array<Range<Decoration>> {
|
||||
//NOTE: Uses codemirror 6 implementation which Obsidian does not currently use
|
||||
let markDecorations: Array<Range<Decoration>> = [];
|
||||
const tree = loadedLanguages[language].language.parser.parse(text);
|
||||
highlightTree(tree,classHighlighter,(from,to,token) => { //todo (@mayurankv) Change this highlighter
|
||||
if (token)
|
||||
markDecorations.push({from: start+from, to: start+to, value: Decoration.mark({class: token})});
|
||||
});
|
||||
return markDecorations;
|
||||
}
|
||||
//NOSONAR
|
||||
// function languageHighlight({start,text,language}: {start: number, text: string, language: string},loadedLanguages: Record<string,LanguageSupport>): Array<Range<Decoration>> {
|
||||
// //NOTE: Uses codemirror 6 implementation which Obsidian does not currently use
|
||||
// let markDecorations: Array<Range<Decoration>> = [];
|
||||
// const tree = loadedLanguages[language].language.parser.parse(text);
|
||||
// highlightTree(tree,classHighlighter,(from,to,token) => { //todo (@mayurankv) Change this highlighter
|
||||
// if (token)
|
||||
// markDecorations.push({from: start+from, to: start+to, value: Decoration.mark({class: token})});
|
||||
// });
|
||||
// return markDecorations;
|
||||
// }
|
||||
function modeHighlight ({start,text,language}: {start: number, text: string, language: string}): Array<Range<Decoration>> {
|
||||
//NOTE: Uses CodeMirror 5 implementation which Obsidian currently uses
|
||||
let markDecorations: Array<Range<Decoration>> = [];
|
||||
const markDecorations: Array<Range<Decoration>> = [];
|
||||
//@ts-expect-error Undocumented Obsidian API
|
||||
const mode = window.CodeMirror.getMode(window.CodeMirror.defaults,window.CodeMirror.findModeByName(language)?.mime); // Alternatives: `text/x-${parameters.language}`, window.CodeMirror.findModeByName('js').mime
|
||||
let state = window.CodeMirror.startState(mode);
|
||||
const state = window.CodeMirror.startState(mode);
|
||||
if (mode?.token) {
|
||||
let stream = new window.CodeMirror.StringStream(text);
|
||||
const stream = new window.CodeMirror.StringStream(text);
|
||||
while (!stream.eol()) {
|
||||
let style = mode.token(stream,state);
|
||||
const style = mode.token(stream,state);
|
||||
if (style)
|
||||
markDecorations.push({from: start+stream.start, to: start+stream.pos, value: Decoration.mark({class: `cm-${style}`})})
|
||||
stream.start = stream.pos;
|
||||
|
|
|
|||
|
|
@ -5,144 +5,39 @@ import {visit} from "unist-util-visit";
|
|||
|
||||
import CodeStylerPlugin from "./main";
|
||||
import { TRANSITION_LENGTH } from "./Settings";
|
||||
import { CodeblockParameters, getFileContentLines, isExcluded, parseCodeblockSource, parseInlineCode } from "./CodeblockParsing";
|
||||
import { createHeader, createInlineOpener, getLineClass } from "./CodeblockDecorating";
|
||||
import { CodeblockParameters, InlineCodeParameters, getFileContentLines, isExcluded, parseCodeblockSource, parseInlineCode } from "./CodeblockParsing";
|
||||
import { createHeader, createInlineOpener, getLineClass as getLineClasses, getLineNumberDisplay } from "./CodeblockDecorating";
|
||||
|
||||
export async function readingViewCodeblockDecoratingPostProcessor(element: HTMLElement, {sourcePath,getSectionInfo,frontmatter}: {sourcePath: string, getSectionInfo: (element: HTMLElement) => MarkdownSectionInformation | null, frontmatter: FrontMatterCache | undefined}, plugin: CodeStylerPlugin, editingEmbeds: boolean = false) {
|
||||
export async function readingViewCodeblockDecoratingPostProcessor(element: HTMLElement, {sourcePath,getSectionInfo,frontmatter}: {sourcePath: string, getSectionInfo: (element: HTMLElement) => MarkdownSectionInformation | null, frontmatter: FrontMatterCache | undefined}, plugin: CodeStylerPlugin, editingEmbeds = false) {
|
||||
const cache: CachedMetadata | null = plugin.app.metadataCache.getCache(sourcePath);
|
||||
if (!sourcePath || !element || (frontmatter ?? cache?.frontmatter)?.['code-styler-ignore'] === true)
|
||||
return;
|
||||
|
||||
let codeblockPreElements: Array<HTMLElement>;
|
||||
editingEmbeds = editingEmbeds || Boolean(element.matchParent(".cm-embed-block"));
|
||||
const specific = !Boolean(element.querySelector(".view-content > *"));
|
||||
const specific = !element.querySelector(".view-content > *");
|
||||
const printing = Boolean(element.querySelector("div.print > *"));
|
||||
if (printing && !plugin.settings.decoratePrint)
|
||||
return;
|
||||
|
||||
if (!editingEmbeds && !specific)
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('.markdown-reading-view pre:not(.frontmatter)'));
|
||||
else if (!editingEmbeds && specific) {
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('pre:not(.frontmatter)'));
|
||||
let admonitionCodeElement = codeblockPreElements?.[0]?.querySelector('pre:not([class]) > code[class*="language-ad-"]');
|
||||
if (admonitionCodeElement) {
|
||||
await sleep(50);
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('pre:not(.frontmatter)'));
|
||||
}
|
||||
} else if (editingEmbeds && !specific)
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('.markdown-source-view .cm-embed-block pre:not(.frontmatter)'));
|
||||
else
|
||||
codeblockPreElements = [];
|
||||
const codeblockPreElements: Array<HTMLElement> = await getCodeblockPreElements(element,specific,editingEmbeds);
|
||||
if (codeblockPreElements.length === 0 && !(editingEmbeds && specific))
|
||||
return;
|
||||
|
||||
const codeblockSectionInfo: MarkdownSectionInformation | null = getSectionInfo(codeblockPreElements[0]);
|
||||
if (codeblockSectionInfo && specific && !editingEmbeds)
|
||||
renderSpecificReadingSection(codeblockPreElements,sourcePath,codeblockSectionInfo,plugin);
|
||||
else if (specific && !printing) {
|
||||
await sleep(50);
|
||||
editingEmbeds = editingEmbeds || Boolean(element.matchParent(".cm-embed-block"));
|
||||
if (editingEmbeds || !element.classList.contains("admonition-content")) {
|
||||
let contentEl = element.matchParent('.view-content') as HTMLElement;
|
||||
await readingViewCodeblockDecoratingPostProcessor(contentEl?contentEl:(element.matchParent('div.print') as HTMLElement),{sourcePath,getSectionInfo,frontmatter},plugin,editingEmbeds); // Re-render whole document
|
||||
}
|
||||
}
|
||||
await renderSpecificReadingSection(codeblockPreElements,sourcePath,codeblockSectionInfo,plugin);
|
||||
else if (specific && !printing)
|
||||
await retriggerProcessor(element,{sourcePath,getSectionInfo,frontmatter},plugin,editingEmbeds);
|
||||
else
|
||||
renderDocument(codeblockPreElements,sourcePath,cache,editingEmbeds,printing,plugin);
|
||||
await renderDocument(codeblockPreElements,sourcePath,cache,editingEmbeds,printing,plugin);
|
||||
}
|
||||
async function renderSpecificReadingSection(codeblockPreElements: Array<HTMLElement>, sourcePath: string, codeblockSectionInfo: MarkdownSectionInformation, plugin: CodeStylerPlugin): Promise<void> {
|
||||
const codeblocksParameters = (await parseCodeblockSource(Array.from({length: codeblockSectionInfo.lineEnd-codeblockSectionInfo.lineStart+1}, (_,num) => num + codeblockSectionInfo.lineStart).map((lineNumber)=>codeblockSectionInfo.text.split('\n')[lineNumber]),sourcePath,plugin)).codeblocksParameters;
|
||||
if (codeblockPreElements.length !== codeblocksParameters.length)
|
||||
return;
|
||||
for (let [key,codeblockPreElement] of codeblockPreElements.entries()) {
|
||||
let codeblockParameters = codeblocksParameters[key];
|
||||
let codeblockCodeElement = codeblockPreElement.querySelector('pre > code');
|
||||
if (!codeblockCodeElement)
|
||||
return;
|
||||
if (Array.from(codeblockCodeElement.classList).some(className => /^language-\S+/.test(className)))
|
||||
while(!codeblockCodeElement.classList.contains("is-loaded"))
|
||||
await sleep(2);
|
||||
if (isExcluded(codeblockParameters.language,plugin.settings.excludedLanguages) || codeblockParameters.ignore)
|
||||
continue;
|
||||
await remakeCodeblock(codeblockCodeElement as HTMLElement,codeblockPreElement,codeblockParameters,true,plugin);
|
||||
}
|
||||
}
|
||||
async function renderDocument(codeblockPreElements: Array<HTMLElement>, sourcePath: string, cache: CachedMetadata | null, editingEmbeds: boolean, printing: boolean, plugin: CodeStylerPlugin) {
|
||||
const fileContentLines = await getFileContentLines(sourcePath,plugin);
|
||||
if (!fileContentLines)
|
||||
return;
|
||||
let codeblocksParameters: Array<CodeblockParameters> = [];
|
||||
|
||||
if (typeof cache?.sections !== 'undefined') {
|
||||
for (const section of cache.sections) {
|
||||
if (!editingEmbeds || section.type === 'code' || section.type === 'callout') {
|
||||
const parsedCodeblocksParameters = await parseCodeblockSource(fileContentLines.slice(section.position.start.line,section.position.end.line+1),sourcePath,plugin);
|
||||
if (!editingEmbeds || parsedCodeblocksParameters.nested)
|
||||
codeblocksParameters = codeblocksParameters.concat(parsedCodeblocksParameters.codeblocksParameters);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error(`Metadata cache not found for file: ${sourcePath}`);
|
||||
return;
|
||||
}
|
||||
if (codeblockPreElements.length !== codeblocksParameters.length)
|
||||
return;
|
||||
try {
|
||||
for (let [key,codeblockPreElement] of Array.from(codeblockPreElements).entries()) {
|
||||
let codeblockParameters = codeblocksParameters[key];
|
||||
let codeblockCodeElement: HTMLPreElement | null = codeblockPreElement.querySelector("pre > code");
|
||||
if (!codeblockCodeElement)
|
||||
return;
|
||||
if (Array.from(codeblockCodeElement.classList).some(className => /^language-\S+/.test(className)))
|
||||
while(!codeblockCodeElement.classList.contains("is-loaded"))
|
||||
await sleep(2);
|
||||
if (codeblockCodeElement.querySelector("code [class*='code-styler-line']"))
|
||||
continue;
|
||||
if (isExcluded(codeblockParameters.language,plugin.settings.excludedLanguages) || codeblockParameters.ignore)
|
||||
continue;
|
||||
await remakeCodeblock(codeblockCodeElement,codeblockPreElement,codeblockParameters,!printing,plugin);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error rendering document: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export async function readingViewInlineDecoratingPostProcessor(element: HTMLElement, {sourcePath,getSectionInfo,frontmatter}: {sourcePath: string, getSectionInfo: (element: HTMLElement) => MarkdownSectionInformation | null, frontmatter: FrontMatterCache | undefined}, plugin: CodeStylerPlugin) {
|
||||
export async function readingViewInlineDecoratingPostProcessor(element: HTMLElement, {sourcePath}: {sourcePath: string, getSectionInfo: (element: HTMLElement) => MarkdownSectionInformation | null, frontmatter: FrontMatterCache | undefined}, plugin: CodeStylerPlugin) {
|
||||
if (!sourcePath || !element)
|
||||
return;
|
||||
for (let inlineCodeElement of Array.from(element.querySelectorAll(':not(pre) > code'))) {
|
||||
if (inlineCodeElement.classList.contains('code-styler-highlighted') || inlineCodeElement.classList.contains('code-styler-highlight-ignore'))
|
||||
return;
|
||||
let tempRenderContainer = createDiv();
|
||||
let renderedCodeElement: HTMLElement | null;
|
||||
let inlineCodeText = (inlineCodeElement as HTMLElement).innerText;
|
||||
let {parameters,text} = parseInlineCode(inlineCodeText);
|
||||
if (!parameters) {
|
||||
if (!text)
|
||||
return;
|
||||
MarkdownRenderer.renderMarkdown('`'.repeat(20)+text+'`'.repeat(20),tempRenderContainer,'',new Component());
|
||||
renderedCodeElement = tempRenderContainer.querySelector('code');
|
||||
if (!renderedCodeElement)
|
||||
return;
|
||||
inlineCodeElement.innerHTML = renderedCodeElement.innerHTML;
|
||||
inlineCodeElement.classList.add('code-styler-highlight-ignore');
|
||||
} else {
|
||||
MarkdownRenderer.renderMarkdown(['```',plugin.settings.currentTheme.settings.inline.syntaxHighlight?parameters.language:'','\n',text,'\n','```'].join(''),tempRenderContainer,'',new Component());
|
||||
renderedCodeElement = tempRenderContainer.querySelector('pre > code');
|
||||
if (!renderedCodeElement)
|
||||
return;
|
||||
while(plugin.settings.currentTheme.settings.inline.syntaxHighlight && !renderedCodeElement.classList.contains("is-loaded"))
|
||||
await sleep(2);
|
||||
inlineCodeElement.innerHTML = renderedCodeElement.innerHTML;
|
||||
inlineCodeElement.classList.add('code-styler-highlighted');
|
||||
inlineCodeElement.setAttribute("parameters",inlineCodeText.substring(0,inlineCodeText.lastIndexOf(text)));
|
||||
if (parameters.icon || parameters.title)
|
||||
inlineCodeElement.insertBefore(createInlineOpener(parameters,plugin.languageIcons),inlineCodeElement.childNodes[0]);
|
||||
}
|
||||
for (const inlineCodeElement of Array.from(element.querySelectorAll(':not(pre) > code'))) {
|
||||
await remakeInlineCode(inlineCodeElement as HTMLElement,plugin);
|
||||
}
|
||||
}
|
||||
|
||||
export function destroyReadingModeElements(): void {
|
||||
document.querySelectorAll(".code-styler-pre-parent").forEach(codeblockPreParent => {
|
||||
codeblockPreParent.classList.remove('code-styler-pre-parent');
|
||||
|
|
@ -185,102 +80,203 @@ export function destroyReadingModeElements(): void {
|
|||
});
|
||||
}
|
||||
|
||||
async function remakeCodeblock(codeblockCodeElement: HTMLElement, codeblockPreElement: HTMLElement, codeblockParameters: CodeblockParameters, dynamic: boolean, plugin: CodeStylerPlugin) {
|
||||
function escapeHTML(plaintext: string) {
|
||||
return plaintext.replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
async function renderSpecificReadingSection(codeblockPreElements: Array<HTMLElement>, sourcePath: string, codeblockSectionInfo: MarkdownSectionInformation, plugin: CodeStylerPlugin): Promise<void> {
|
||||
const codeblocksParameters = (await parseCodeblockSource(Array.from({length: codeblockSectionInfo.lineEnd-codeblockSectionInfo.lineStart+1}, (_,num) => num + codeblockSectionInfo.lineStart).map((lineNumber)=>codeblockSectionInfo.text.split('\n')[lineNumber]),sourcePath,plugin)).codeblocksParameters;
|
||||
if (codeblockPreElements.length !== codeblocksParameters.length)
|
||||
return;
|
||||
for (const [key,codeblockPreElement] of codeblockPreElements.entries()) {
|
||||
const codeblockParameters = codeblocksParameters[key];
|
||||
const codeblockCodeElement = codeblockPreElement.querySelector('pre > code');
|
||||
if (!codeblockCodeElement)
|
||||
return;
|
||||
if (Array.from(codeblockCodeElement.classList).some(className => /^language-\S+/.test(className)))
|
||||
while(!codeblockCodeElement.classList.contains("is-loaded"))
|
||||
await sleep(2);
|
||||
if (isExcluded(codeblockParameters.language,plugin.settings.excludedLanguages) || codeblockParameters.ignore)
|
||||
continue;
|
||||
await remakeCodeblock(codeblockCodeElement as HTMLElement,codeblockPreElement,codeblockParameters,true,plugin);
|
||||
}
|
||||
|
||||
// Add Execute Code Observer
|
||||
if (dynamic) {
|
||||
plugin.executeCodeMutationObserver.observe(codeblockPreElement,{
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
characterData: true,
|
||||
});
|
||||
}
|
||||
async function retriggerProcessor(element: HTMLElement, context: {sourcePath: string, getSectionInfo: (element: HTMLElement) => MarkdownSectionInformation | null, frontmatter: FrontMatterCache | undefined}, plugin: CodeStylerPlugin, editingEmbeds: boolean) {
|
||||
await sleep(50);
|
||||
editingEmbeds = editingEmbeds || Boolean(element.matchParent(".cm-embed-block"));
|
||||
if (editingEmbeds || !element.classList.contains("admonition-content")) {
|
||||
const contentEl = element.matchParent('.view-content') as HTMLElement;
|
||||
await readingViewCodeblockDecoratingPostProcessor(contentEl || (element.matchParent('div.print') as HTMLElement),context,plugin,editingEmbeds); // Re-render whole document
|
||||
}
|
||||
|
||||
// Add Parent Classes
|
||||
codeblockPreElement.classList.add(`code-styler-pre`);
|
||||
if (codeblockParameters.language)
|
||||
codeblockPreElement.classList.add(`language-${codeblockParameters.language}`);
|
||||
if (codeblockPreElement.parentElement)
|
||||
codeblockPreElement.parentElement.classList.add(`code-styler-pre-parent`);
|
||||
|
||||
// Create Header
|
||||
const headerContainer = createHeader(codeblockParameters, plugin.settings.currentTheme.settings,plugin.languageIcons);
|
||||
codeblockPreElement.insertBefore(headerContainer,codeblockPreElement.childNodes[0]);
|
||||
|
||||
if (dynamic) {
|
||||
// Add listener for header collapsing on click
|
||||
headerContainer.addEventListener("click",()=>toggleFold(codeblockPreElement));
|
||||
if (codeblockParameters.fold.enabled)
|
||||
codeblockPreElement.classList.add("code-styler-collapsed");
|
||||
|
||||
// Line Wrapping Classes //TODO (@mayurankv) Turn these into classes (ideally phase out codeblockCodeElement)
|
||||
if (codeblockParameters.lineUnwrap.alwaysEnabled) {
|
||||
codeblockCodeElement.style.setProperty('--line-wrapping','pre');
|
||||
if (codeblockParameters.lineUnwrap.activeWrap)
|
||||
codeblockCodeElement.style.setProperty('--line-active-wrapping','pre-wrap');
|
||||
else
|
||||
codeblockCodeElement.style.setProperty('--line-active-wrapping','pre');
|
||||
} else if (codeblockParameters.lineUnwrap.alwaysDisabled)
|
||||
codeblockCodeElement.style.setProperty('--line-wrapping','pre-wrap');
|
||||
} else if (codeblockParameters.fold.enabled) //TODO (@mayurankv) Can this be removed? Is it just folding codeblocks in exports?
|
||||
codeblockPreElement.classList.add("code-styler-collapsed");
|
||||
|
||||
// Ignore styled lines
|
||||
if (codeblockCodeElement.querySelector("code [class*='code-styler-line']"))
|
||||
}
|
||||
async function renderDocument(codeblockPreElements: Array<HTMLElement>, sourcePath: string, cache: CachedMetadata | null, editingEmbeds: boolean, printing: boolean, plugin: CodeStylerPlugin) {
|
||||
const codeblocksParameters: Array<CodeblockParameters> = await getCodeblocksParameters(sourcePath,cache,plugin,editingEmbeds);
|
||||
if (codeblocksParameters.length !== codeblockPreElements.length)
|
||||
return;
|
||||
|
||||
// Add line numbers
|
||||
let tree = unified().use(remarkParse).parse(codeblockCodeElement.innerHTML.replace(/\n/g,'<br>'));
|
||||
let stack: Array<string> = [];
|
||||
let codeblockHTML: string = '';
|
||||
codeblockCodeElement.innerHTML = "";
|
||||
visit(tree,(node)=>{
|
||||
if (node.type === 'html' || node.type === 'text') {
|
||||
if (node.type === 'html' && node.value !== '<br>') {
|
||||
if (node.value.startsWith('<span'))
|
||||
stack.push(node.value);
|
||||
else if (node.value.startsWith('</span'))
|
||||
stack.pop();
|
||||
} else if (node.type === 'html' && node.value === '<br>')
|
||||
node.value = '</span>'.repeat(stack.length)+'<br>'+stack.join('');
|
||||
else
|
||||
node.value = escapeHTML(node.value);
|
||||
codeblockHTML += node.value;
|
||||
try {
|
||||
for (const [key,codeblockPreElement] of Array.from(codeblockPreElements).entries()) {
|
||||
const codeblockParameters = codeblocksParameters[key];
|
||||
const codeblockCodeElement: HTMLPreElement | null = codeblockPreElement.querySelector("pre > code");
|
||||
if (!codeblockCodeElement)
|
||||
return;
|
||||
if (Array.from(codeblockCodeElement.classList).some(className => /^language-\S+/.test(className)))
|
||||
while(!codeblockCodeElement.classList.contains("is-loaded"))
|
||||
await sleep(2);
|
||||
if (codeblockCodeElement.querySelector("code [class*='code-styler-line']"))
|
||||
continue;
|
||||
if (isExcluded(codeblockParameters.language,plugin.settings.excludedLanguages) || codeblockParameters.ignore)
|
||||
continue;
|
||||
await remakeCodeblock(codeblockCodeElement,codeblockPreElement,codeblockParameters,!printing,plugin);
|
||||
}
|
||||
});
|
||||
let codeblockLines = codeblockHTML.split('<br>');
|
||||
if (codeblockLines.length == 1)
|
||||
codeblockLines = ['',''];
|
||||
codeblockLines.forEach((line,index) => {
|
||||
if (index === codeblockLines.length-1)
|
||||
return;
|
||||
const lineNumber = index + 1;
|
||||
const lineWrapper = document.createElement("div");
|
||||
getLineClass(codeblockParameters,lineNumber,line).forEach((lineClass) => {
|
||||
lineWrapper.classList.add(lineClass);
|
||||
});
|
||||
codeblockCodeElement.appendChild(lineWrapper);
|
||||
let lineNumberDisplay = '';
|
||||
if (!codeblockParameters.lineNumbers.alwaysEnabled && codeblockParameters.lineNumbers.alwaysDisabled)
|
||||
lineNumberDisplay = '-hide';
|
||||
else if (codeblockParameters.lineNumbers.alwaysEnabled && !codeblockParameters.lineNumbers.alwaysDisabled)
|
||||
lineNumberDisplay = '-specific';
|
||||
lineWrapper.appendChild(createDiv({cls: `code-styler-line-number${lineNumberDisplay}`, text: (lineNumber+codeblockParameters.lineNumbers.offset).toString()}));
|
||||
lineWrapper.appendChild(createDiv({cls: `code-styler-line-text`, text: sanitizeHTMLToDom(line !== "" ? line : "<br>")}));
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error rendering document: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleFold(codeblockPreElement: HTMLElement) {
|
||||
async function remakeCodeblock(codeblockCodeElement: HTMLElement, codeblockPreElement: HTMLElement, codeblockParameters: CodeblockParameters, dynamic: boolean, plugin: CodeStylerPlugin) {
|
||||
if (dynamic)
|
||||
plugin.executeCodeMutationObserver.observe(codeblockPreElement,{childList: true,subtree: true,attributes: true,characterData: true}); // Add Execute Code Observer
|
||||
|
||||
insertHeader(codeblockPreElement,codeblockParameters,plugin,dynamic);
|
||||
|
||||
codeblockPreElement.classList.add(...getPreClasses(codeblockParameters,dynamic));
|
||||
if (codeblockPreElement.parentElement)
|
||||
codeblockPreElement.parentElement.classList.add(`code-styler-pre-parent`);
|
||||
|
||||
if (!codeblockCodeElement.querySelector("code [class*='code-styler-line']")) // Ignore styled lines
|
||||
decorateCodeblockLines(codeblockCodeElement,codeblockParameters)
|
||||
}
|
||||
async function remakeInlineCode(inlineCodeElement: HTMLElement, plugin: CodeStylerPlugin): Promise<void> {
|
||||
if (inlineCodeElement.classList.contains('code-styler-inline'))
|
||||
return;
|
||||
const inlineCodeText = inlineCodeElement.innerText;
|
||||
const {parameters,text} = parseInlineCode(inlineCodeText);
|
||||
if (parameters && plugin.settings.currentTheme.settings.inline.syntaxHighlight)
|
||||
inlineCodeElement.innerHTML = await getHighlightedHTML(parameters,text,plugin);
|
||||
else if ((!parameters && text) || (parameters && !plugin.settings.currentTheme.settings.inline.syntaxHighlight))
|
||||
inlineCodeElement.innerHTML = text;
|
||||
else
|
||||
return;
|
||||
|
||||
inlineCodeElement.classList.add('code-styler-inline');
|
||||
if (parameters) {
|
||||
const parameterString = inlineCodeText.substring(0,inlineCodeText.lastIndexOf(text));
|
||||
inlineCodeElement.setAttribute("parameters",parameterString); // Store parameter string as attribute so original text can be restored on plugin removal
|
||||
if (parameters.icon || parameters.title)
|
||||
inlineCodeElement.insertBefore(createInlineOpener(parameters,plugin.languageIcons),inlineCodeElement.childNodes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
async function getCodeblockPreElements(element: HTMLElement, specific: boolean,editingEmbeds: boolean): Promise<Array<HTMLElement>> {
|
||||
let codeblockPreElements: Array<HTMLElement>;
|
||||
if (!editingEmbeds && !specific)
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('.markdown-reading-view pre:not(.frontmatter)'));
|
||||
else if (editingEmbeds && !specific)
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('.markdown-source-view .cm-embed-block pre:not(.frontmatter)'));
|
||||
else if (!editingEmbeds && specific) {
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('pre:not(.frontmatter)'));
|
||||
const admonitionCodeElement = codeblockPreElements?.[0]?.querySelector('pre:not([class]) > code[class*="language-ad-"]');
|
||||
if (admonitionCodeElement) {
|
||||
await sleep(50);
|
||||
codeblockPreElements = Array.from(element.querySelectorAll('pre:not(.frontmatter)'));
|
||||
}
|
||||
} else
|
||||
codeblockPreElements = [];
|
||||
return codeblockPreElements
|
||||
}
|
||||
async function getCodeblocksParameters(sourcePath: string, cache: CachedMetadata | null, plugin: CodeStylerPlugin, editingEmbeds: boolean): Promise<Array<CodeblockParameters>> {
|
||||
let codeblocksParameters: Array<CodeblockParameters> = [];
|
||||
const fileContentLines = await getFileContentLines(sourcePath,plugin);
|
||||
if (!fileContentLines)
|
||||
return [];
|
||||
|
||||
if (typeof cache?.sections !== 'undefined') {
|
||||
for (const section of cache.sections) {
|
||||
if (!editingEmbeds || section.type === 'code' || section.type === 'callout') {
|
||||
const parsedCodeblocksParameters = await parseCodeblockSource(fileContentLines.slice(section.position.start.line,section.position.end.line+1),sourcePath,plugin);
|
||||
if (!editingEmbeds || parsedCodeblocksParameters.nested)
|
||||
codeblocksParameters = codeblocksParameters.concat(parsedCodeblocksParameters.codeblocksParameters);
|
||||
}
|
||||
}
|
||||
} else
|
||||
console.error(`Metadata cache not found for file: ${sourcePath}`);
|
||||
return codeblocksParameters;
|
||||
}
|
||||
async function toggleFold(codeblockPreElement: HTMLElement): Promise<void> {
|
||||
codeblockPreElement.querySelectorAll('pre > code').forEach((codeblockCodeElement: HTMLElement)=>codeblockCodeElement.style.setProperty('max-height',`calc(${Math.ceil(codeblockCodeElement.scrollHeight+0.01)}px + var(--code-padding) * ${codeblockCodeElement.classList.contains('execute-code-output')?'3.5 + var(--header-separator-width)':'2'})`));
|
||||
await sleep(1);
|
||||
codeblockPreElement.classList.toggle("code-styler-collapsed");
|
||||
await sleep(TRANSITION_LENGTH);
|
||||
codeblockPreElement.querySelectorAll('pre > code').forEach((codeblockCodeElement: HTMLElement)=>codeblockCodeElement.style.removeProperty('max-height'));
|
||||
}
|
||||
function insertHeader(codeblockPreElement: HTMLElement, codeblockParameters: CodeblockParameters, plugin: CodeStylerPlugin, dynamic: boolean): void {
|
||||
const headerContainer = createHeader(codeblockParameters, plugin.settings.currentTheme.settings,plugin.languageIcons);
|
||||
if (dynamic)
|
||||
headerContainer.addEventListener("click",()=>{toggleFold(codeblockPreElement)}); // Add listener for header collapsing on click
|
||||
codeblockPreElement.insertBefore(headerContainer,codeblockPreElement.childNodes[0]);
|
||||
}
|
||||
function getPreClasses(codeblockParameters: CodeblockParameters, dynamic: boolean): Array<string> {
|
||||
const preClassList = ['code-styler-pre'];
|
||||
if (codeblockParameters.language)
|
||||
preClassList.push(`language-${codeblockParameters.language}`);
|
||||
if (dynamic) {
|
||||
if (codeblockParameters.fold.enabled)
|
||||
preClassList.push("code-styler-collapsed");
|
||||
if (codeblockParameters.lineUnwrap.alwaysEnabled)
|
||||
preClassList.push(codeblockParameters.lineUnwrap.activeWrap?'unwrapped-inactive':'unwrapped');
|
||||
else if (codeblockParameters.lineUnwrap.alwaysDisabled)
|
||||
preClassList.push('unwrapped');
|
||||
}
|
||||
return preClassList;
|
||||
}
|
||||
function decorateCodeblockLines(codeblockCodeElement: HTMLElement, codeblockParameters: CodeblockParameters): void {
|
||||
getCodeblockLines(codeblockCodeElement).forEach((line,index,codeblockLines) => {
|
||||
if (index !== codeblockLines.length-1)
|
||||
insertLineWrapper(codeblockCodeElement,codeblockParameters,index+1,line);
|
||||
});
|
||||
}
|
||||
function getCodeblockLines(codeblockCodeElement: HTMLElement): Array<string> {
|
||||
function escapeHTML(plaintext: string) {
|
||||
return plaintext.replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
const tree = unified().use(remarkParse).parse(codeblockCodeElement.innerHTML.replace(/\n/g,'<br>'));
|
||||
const stack: Array<string> = [];
|
||||
let codeblockHTML = '';
|
||||
visit(tree,['text','html'],(node)=>{
|
||||
if (node.type === 'html' && node.value !== '<br>') {
|
||||
if (node.value.startsWith('<span'))
|
||||
stack.push(node.value);
|
||||
else if (node.value.startsWith('</span'))
|
||||
stack.pop();
|
||||
} else if (node.type === 'html' && node.value === '<br>')
|
||||
node.value = '</span>'.repeat(stack.length)+'<br>'+stack.join('');
|
||||
else if (node.type === 'text')
|
||||
node.value = escapeHTML(node.value);
|
||||
if ('value' in node)
|
||||
codeblockHTML += node.value;
|
||||
});
|
||||
let codeblockLines = codeblockHTML.split('<br>');
|
||||
if (codeblockLines.length == 1)
|
||||
codeblockLines = ['',''];
|
||||
codeblockCodeElement.innerHTML = "";
|
||||
return codeblockLines;
|
||||
}
|
||||
function insertLineWrapper(codeblockCodeElement: HTMLElement, codeblockParameters: CodeblockParameters, lineNumber: number, line: string): void {
|
||||
const lineWrapper = document.createElement("div");
|
||||
codeblockCodeElement.appendChild(lineWrapper);
|
||||
getLineClasses(codeblockParameters,lineNumber,line).forEach((lineClass) => lineWrapper.classList.add(lineClass));
|
||||
lineWrapper.appendChild(createDiv({cls: `code-styler-line-number${getLineNumberDisplay(codeblockParameters)}`, text: (lineNumber+codeblockParameters.lineNumbers.offset).toString()}));
|
||||
lineWrapper.appendChild(createDiv({cls: `code-styler-line-text`, text: sanitizeHTMLToDom(line !== "" ? line : "<br>")}));
|
||||
}
|
||||
async function getHighlightedHTML(parameters: InlineCodeParameters, text: string, plugin: CodeStylerPlugin): Promise<string> {
|
||||
const temporaryRenderingContainer = createDiv();
|
||||
MarkdownRenderer.renderMarkdown(['```',parameters.language,'\n',text,'\n','```'].join(''),temporaryRenderingContainer,'',new Component());
|
||||
const renderedCodeElement = temporaryRenderingContainer.querySelector('code');
|
||||
if (!renderedCodeElement)
|
||||
return 'ERROR: Could not render highlighted code';
|
||||
while(plugin.settings.currentTheme.settings.inline.syntaxHighlight && !renderedCodeElement.classList.contains("is-loaded"))
|
||||
await sleep(2);
|
||||
return renderedCodeElement.innerHTML;
|
||||
}
|
||||
|
||||
export const executeCodeMutationObserver = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation: MutationRecord) => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { ColorTranslator } from "colortranslator";
|
|||
|
||||
import CodeStylerPlugin from "./main";
|
||||
import { Colour, CSS, HEX, Display, CodeStylerSettings, CodeStylerThemeColours, PARAMETERS, DEFAULT_SETTINGS, LANGUAGE_NAMES, LANGUAGE_ICONS_DATA } from './Settings';
|
||||
import { todo } from "node:test";
|
||||
|
||||
const DISPLAY_OPTIONS: Record<Display,string> = {
|
||||
"none": "Never",
|
||||
|
|
@ -261,7 +260,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||
new Setting(containerEl)
|
||||
.setName('Highlight Line Numbers')
|
||||
.setDesc('If enabled, highlights will also highlight the line numbers.')
|
||||
.addToggle(toggle => {let highlightLineNumbersToggle = toggle
|
||||
.addToggle(toggle => {const highlightLineNumbersToggle = toggle
|
||||
.setValue(this.plugin.settings.currentTheme.settings.gutter.highlight)
|
||||
.setDisabled(!this.plugin.settings.currentTheme.settings.codeblock.lineNumbers)
|
||||
.onChange((value) => {
|
||||
|
|
@ -274,7 +273,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||
.setName('Indicate Current Line Number')
|
||||
.setDesc('If enabled, the current line number in codeblocks will be indicated with a separate colour.')
|
||||
.setClass('code-styler-spaced')
|
||||
.addToggle(toggle => {let indicateCurrentLineNumberToggle = toggle
|
||||
.addToggle(toggle => {const indicateCurrentLineNumberToggle = toggle
|
||||
.setValue(this.plugin.settings.currentTheme.settings.gutter.activeLine)
|
||||
.setDisabled(!this.plugin.settings.currentTheme.settings.codeblock.lineNumbers)
|
||||
.onChange((value) => {
|
||||
|
|
@ -908,13 +907,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||
} else {
|
||||
try {
|
||||
this.plugin.settings.redirectLanguages = JSON.parse(value);
|
||||
Object.entries(this.plugin.settings.redirectLanguages).forEach(([languageName, languageSettings]: [string, {colour?: Colour, icon?: string}])=>{
|
||||
if ('icon' in languageSettings) {
|
||||
if (LANGUAGE_NAMES[languageName] in this.plugin.languageIcons)
|
||||
URL.revokeObjectURL(this.plugin.languageIcons[LANGUAGE_NAMES[languageName]]);
|
||||
this.plugin.languageIcons[LANGUAGE_NAMES[languageName]] = URL.createObjectURL(new Blob([`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32">${languageSettings.icon}</svg>`], { type: "image/svg+xml" }));
|
||||
}
|
||||
});
|
||||
this.redirectLanguages();
|
||||
(async () => {await this.plugin.saveSettings()})();
|
||||
} catch {
|
||||
new Notice('Invalid JSON'); //NOSONAR
|
||||
|
|
@ -933,9 +926,20 @@ export class SettingsTab extends PluginSettingTab {
|
|||
donationDiv.appendChild(donationButton);
|
||||
}
|
||||
|
||||
// Setting Parsing
|
||||
redirectLanguages() {
|
||||
Object.entries(this.plugin.settings.redirectLanguages).forEach(([languageName, languageSettings]: [string, {colour?: Colour, icon?: string}])=>{
|
||||
if ('icon' in languageSettings) {
|
||||
if (LANGUAGE_NAMES[languageName] in this.plugin.languageIcons)
|
||||
URL.revokeObjectURL(this.plugin.languageIcons[LANGUAGE_NAMES[languageName]]);
|
||||
this.plugin.languageIcons[LANGUAGE_NAMES[languageName]] = URL.createObjectURL(new Blob([`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32">${languageSettings.icon}</svg>`], { type: "image/svg+xml" }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Setting Creation
|
||||
createPickr(plugin: CodeStylerPlugin, containerEl: HTMLElement, setting: Setting, id: string, getRelevantThemeColour: (relevantThemeColours: CodeStylerThemeColours)=>Colour, saveRelevantThemeColour: (relevantThemeColours: CodeStylerThemeColours, saveColour: Colour)=>void, disabled?: ()=>boolean) {
|
||||
let pickr: PickrResettable = new PickrResettable(plugin,containerEl,setting,getRelevantThemeColour,saveRelevantThemeColour);
|
||||
const pickr: PickrResettable = new PickrResettable(plugin,containerEl,setting,getRelevantThemeColour,saveRelevantThemeColour);
|
||||
pickr
|
||||
.on('show', (colour: Pickr.HSVaColor, instance: Pickr) => {
|
||||
if (typeof disabled !== 'undefined' && disabled())
|
||||
|
|
@ -958,7 +962,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||
this.pickrs[id]=pickr;
|
||||
}
|
||||
|
||||
// Setting Updates
|
||||
// Setting Tab Updates
|
||||
updateDropdown(dropdown: DropdownComponent, settings: CodeStylerSettings) {
|
||||
dropdown.selectEl.empty();
|
||||
Object.keys(settings.themes).forEach((theme_name: string) => {
|
||||
|
|
@ -1068,7 +1072,7 @@ function calc(calcString: string): string {
|
|||
return calcString;
|
||||
}
|
||||
function getCssVariable(cssVariable: CSS): HEX {
|
||||
let variableValue = window.getComputedStyle(document.body).getPropertyValue(cssVariable).trim();
|
||||
const variableValue = window.getComputedStyle(document.body).getPropertyValue(cssVariable).trim();
|
||||
if (typeof variableValue === "string" && variableValue.trim().startsWith('#'))
|
||||
return `#${variableValue.trim().substring(1)}`;
|
||||
else if (variableValue.startsWith('rgb'))
|
||||
|
|
@ -1080,7 +1084,7 @@ function getCssVariable(cssVariable: CSS): HEX {
|
|||
return `#${ColorTranslator.toHEXA(variableValue).substring(1)}`;
|
||||
}
|
||||
export function getColour(themeColour: Colour): Colour {
|
||||
return isCss(themeColour)?getCssVariable(themeColour):themeColour;;
|
||||
return isCss(themeColour)?getCssVariable(themeColour):themeColour;
|
||||
}
|
||||
|
||||
function getCurrentMode() {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@
|
|||
overflow-x: overlay;
|
||||
white-space: var(--line-wrapping);
|
||||
}
|
||||
.code-styler pre.code-styler-pre.wrapped > code {
|
||||
--line-wrapping: pre-wrap;
|
||||
}
|
||||
.code-styler pre.code-styler-pre.unwrapped > code {
|
||||
--line-wrapping: pre;
|
||||
--line-active-wrapping: pre;
|
||||
}
|
||||
.code-styler pre.code-styler-pre.unwrapped-inactive > code {
|
||||
--line-wrapping: pre;
|
||||
--line-active-wrapping: pre-wrap;
|
||||
}
|
||||
.code-styler pre.code-styler-pre code:not(:has( > input[style*="display: inline;"])):active {
|
||||
--line-wrapping: var(--line-active-wrapping) !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export default class CodeStylerPlugin extends Plugin {
|
|||
let zoomTimeout: NodeJS.Timeout = setTimeout(()=>{});
|
||||
this.registerEvent(this.app.workspace.on('css-change',()=>{
|
||||
updateStyling(this.settings,this.app); // Update styling on css changes
|
||||
let currentFontSize = document.body.getCssPropertyValue('--font-text-size');
|
||||
const currentFontSize = document.body.getCssPropertyValue('--font-text-size');
|
||||
if (this.sizes.font !== currentFontSize) {
|
||||
this.sizes.font = currentFontSize;
|
||||
clearTimeout(zoomTimeout);
|
||||
|
|
@ -52,7 +52,7 @@ export default class CodeStylerPlugin extends Plugin {
|
|||
}
|
||||
},this));
|
||||
this.registerEvent(this.app.workspace.on('resize',()=>{
|
||||
let currentZoomSize = document.body.getCssPropertyValue('--zoom-factor');
|
||||
const currentZoomSize = document.body.getCssPropertyValue('--zoom-factor');
|
||||
if (this.sizes.zoom !== currentZoomSize) {
|
||||
this.sizes.zoom = currentZoomSize;
|
||||
clearTimeout(zoomTimeout);
|
||||
|
|
|
|||
13
styles.css
13
styles.css
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue