mirror of
https://github.com/mayurankv/Obsidian-Code-Styler.git
synced 2026-07-22 08:10:29 +00:00
Refactor reading view and structure
This commit is contained in:
parent
c8ba7dbed7
commit
6ab5a421da
13 changed files with 3795 additions and 3852 deletions
6812
main.js
6812
main.js
File diff suppressed because one or more lines are too long
0
src/ApplyStyling.ts
Normal file
0
src/ApplyStyling.ts
Normal file
|
|
@ -2,7 +2,7 @@ import { ViewPlugin, Decoration, WidgetType } from "@codemirror/view";
|
|||
import { RangeSet } from "@codemirror/state";
|
||||
import { syntaxTree } from "@codemirror/language";
|
||||
|
||||
import { splitAndTrimString, searchString, getHighlightedLines, getLanguageIcon, getLanguageName, isExcluded } from "./Utils";
|
||||
import { searchString, getHighlightedLines, getLanguageIcon, getLanguageName, isExcluded } from "./Utils";
|
||||
|
||||
export function codeblockHighlight(settings: CodeblockCustomizerSettings) {
|
||||
const viewPlugin = ViewPlugin.fromClass(
|
||||
|
|
|
|||
49
src/CodeblockDecorating.ts
Normal file
49
src/CodeblockDecorating.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { LANGUAGE_NAMES, LANGUAGE_ICONS } from "./LanguageDetails";
|
||||
import { CodeblockParameters } from "./CodeblockParsing";
|
||||
import { CodeblockCustomizerThemeSettings } from "./Settings";
|
||||
|
||||
export function createHeader(codeblockPreElement: HTMLElement, codeblockParameters: CodeblockParameters, themeSettings: CodeblockCustomizerThemeSettings) {
|
||||
const headerContainer = createDiv({cls: `codeblock-customizer-header-container${(codeblockParameters.fold.enabled || codeblockParameters.title !== '')?'-specific':''}`});
|
||||
if (codeblockParameters.language !== ''){
|
||||
const IconURL = getLanguageIcon(codeblockParameters.language)
|
||||
if (IconURL !== null) {
|
||||
const imageWrapper = createDiv();
|
||||
const img = document.createElement("img");
|
||||
img.classList.add("codeblock-customizer-icon");
|
||||
img.width = themeSettings.advanced.iconSize;
|
||||
img.src = IconURL;
|
||||
imageWrapper.appendChild(img);
|
||||
headerContainer.appendChild(imageWrapper);
|
||||
}
|
||||
headerContainer.appendChild(createDiv({cls: `codeblock-customizer-header-language-tag-${codeblockParameters.language}`, text: getLanguageTag(codeblockParameters.language)}));
|
||||
}
|
||||
|
||||
let headerText = ''
|
||||
if (codeblockParameters.title !== '')
|
||||
headerText = codeblockParameters.title;
|
||||
else if (codeblockParameters.fold.enabled)
|
||||
headerText = codeblockParameters.fold.placeholder!==''?codeblockParameters.fold.placeholder:themeSettings.header.collapsePlaceholder;
|
||||
headerContainer.appendChild(createDiv({cls: "codeblock-customizer-header-text", text: headerText}));
|
||||
|
||||
const codeblockPreParent = codeblockPreElement.parentNode;
|
||||
if (codeblockPreParent)
|
||||
codeblockPreParent.insertBefore(headerContainer, codeblockPreElement);
|
||||
|
||||
headerContainer.addEventListener("click", ()=>{codeblockPreElement.classList.toggle("codeblock-customizer-codeblock-collapsed")});
|
||||
if (codeblockParameters.fold.enabled)
|
||||
codeblockPreElement.classList.add(`codeblock-customizer-codeblock-collapsed`);
|
||||
}
|
||||
|
||||
function getLanguageTag(language: string) {
|
||||
if (language in LANGUAGE_NAMES)
|
||||
return LANGUAGE_NAMES[language];
|
||||
else if (language !== '')
|
||||
return language.charAt(0).toUpperCase() + language.slice(1);
|
||||
return "";
|
||||
}
|
||||
function getLanguageIcon(language: string) {
|
||||
language = getLanguageTag(language);
|
||||
if (language in LANGUAGE_ICONS)
|
||||
return LANGUAGE_ICONS[language];
|
||||
return null;
|
||||
}
|
||||
113
src/CodeblockParsing.ts
Normal file
113
src/CodeblockParsing.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import { CodeblockCustomizerTheme } from "./Settings";
|
||||
|
||||
export interface CodeblockParameters {
|
||||
language: string;
|
||||
title: string;
|
||||
fold: {
|
||||
enabled: boolean;
|
||||
placeholder: string;
|
||||
}
|
||||
lineNumbers: {
|
||||
alwaysEnabled: boolean;
|
||||
alwaysDisabled: boolean;
|
||||
offset: number;
|
||||
}
|
||||
highlights: {
|
||||
default: Array<number>;
|
||||
alternative: Record<string,Array<number>>
|
||||
}
|
||||
}
|
||||
|
||||
function parseHighlightedLines(highlightedLinesString: string): Array<number> {
|
||||
const lineSections = highlightedLinesString.split(',');
|
||||
return lineSections.map(lineSection => {
|
||||
if (lineSection.includes('-')) {
|
||||
const [start,end] = lineSection.split('-').map(num => parseInt(num));
|
||||
if (start && end)
|
||||
return Array.from({length:end-start+1}, (_,num) => num + start);
|
||||
} else {
|
||||
return parseInt(lineSection);
|
||||
}
|
||||
return [];
|
||||
}).flat();
|
||||
}
|
||||
function parseParameterString(parameterString: string, codeblockParameters: CodeblockParameters, theme: CodeblockCustomizerTheme): void {
|
||||
if (parameterString.startsWith('title:')) {
|
||||
let 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));
|
||||
if (foldPlaceholderMatch) {
|
||||
codeblockParameters.fold.enabled = true;
|
||||
codeblockParameters.fold.placeholder = foldPlaceholderMatch[2].trim();
|
||||
}
|
||||
} else if (parameterString === 'fold') {
|
||||
codeblockParameters.fold.enabled = true;
|
||||
codeblockParameters.fold.placeholder = '';
|
||||
} else if (parameterString.startsWith('ln:')) {
|
||||
parameterString = parameterString.slice('ln:'.length)
|
||||
if (/^\d+$/.test(parameterString)) {
|
||||
codeblockParameters.lineNumbers.alwaysEnabled = true;
|
||||
codeblockParameters.lineNumbers.alwaysDisabled = false;
|
||||
codeblockParameters.lineNumbers.offset = parseInt(parameterString)-1;
|
||||
} else if (parameterString.toLowerCase() === 'true') {
|
||||
codeblockParameters.lineNumbers.alwaysEnabled = true;
|
||||
codeblockParameters.lineNumbers.alwaysDisabled = false;
|
||||
codeblockParameters.lineNumbers.offset = 0;
|
||||
} else if (parameterString.toLowerCase() === 'false') {
|
||||
codeblockParameters.lineNumbers.alwaysEnabled = false;
|
||||
codeblockParameters.lineNumbers.alwaysDisabled = true;
|
||||
codeblockParameters.lineNumbers.offset = 0;
|
||||
}
|
||||
} else {
|
||||
let highlightMatch = /^(\w+):((?:\d+-\d+|\d+)(?:,\d+-\d+|,\d+)*)$/.exec(parameterString);
|
||||
if (highlightMatch) {
|
||||
let highlights = parseHighlightedLines(highlightMatch[2]);
|
||||
if (highlightMatch[1] === 'hl')
|
||||
codeblockParameters.highlights.default = highlights;
|
||||
else
|
||||
if (highlightMatch[1] in theme.colors.light.highlights.alternativeHighlights)
|
||||
codeblockParameters.highlights.alternative[highlightMatch[1]] = highlights;
|
||||
}
|
||||
}
|
||||
}
|
||||
export function parseCodeblockParameters(parameterLine: string, theme: CodeblockCustomizerTheme): CodeblockParameters {
|
||||
let codeblockParameters: CodeblockParameters = {
|
||||
language: '',
|
||||
title: '',
|
||||
fold: {
|
||||
enabled: false,
|
||||
placeholder: '',
|
||||
},
|
||||
lineNumbers: {
|
||||
alwaysEnabled: false,
|
||||
alwaysDisabled: false,
|
||||
offset: 0,
|
||||
},
|
||||
highlights: {
|
||||
default: [],
|
||||
alternative: {},
|
||||
},
|
||||
}
|
||||
if (parameterLine.startsWith('```')) {
|
||||
let languageBreak = parameterLine.indexOf(' ');
|
||||
codeblockParameters.language = parameterLine.slice('```'.length,languageBreak !== -1?languageBreak:parameterLine.length).toLowerCase();
|
||||
if (languageBreak === -1)
|
||||
return codeblockParameters;
|
||||
const parameterStrings = parameterLine.slice(languageBreak+1).match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
|
||||
if (!parameterStrings)
|
||||
return codeblockParameters;
|
||||
parameterStrings.forEach((parameterString) => parseParameterString(parameterString,codeblockParameters,theme))
|
||||
}
|
||||
return codeblockParameters;
|
||||
}
|
||||
function parseRegexExcludedLanguages(excludedLanguagesString: string): Array<RegExp> {
|
||||
return excludedLanguagesString.split(",").map(regexLanguage => new RegExp(`^${regexLanguage.trim().replace(/\*/g,'.+')}$`,'i'))
|
||||
}
|
||||
export function isLanguageExcluded(language: string, excludedLanguagesString: string): boolean {
|
||||
return parseRegexExcludedLanguages(excludedLanguagesString).some(regexExcludedLanguage => {
|
||||
if (regexExcludedLanguage.test(language))
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
@ -96,6 +96,11 @@ function createDecorationWidget(textToDisplay: string, languageName: string, spe
|
|||
widget: new TextAboveCodeblockWidget(textToDisplay, languageName, specificHeader), block: true});
|
||||
}// createDecorationWidget
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const Collapse = StateEffect.define(), UnCollapse = StateEffect.define()
|
||||
|
||||
let pluginSettings: CodeblockCustomizerSettings;
|
||||
|
|
@ -152,26 +157,26 @@ class TextAboveCodeblockWidget extends WidgetType {
|
|||
|
||||
toDOM(view: EditorView): HTMLElement {
|
||||
this.view = view;
|
||||
const container = createContainer(this.specificHeader);
|
||||
const headerContainer = createContainer(this.specificHeader);
|
||||
if (this.Lang){
|
||||
const Icon = getLanguageIcon(this.Lang)
|
||||
if (Icon) {
|
||||
container.appendChild(createCodeblockIcon(this.Lang));
|
||||
headerContainer.appendChild(createCodeblockIcon(this.Lang));
|
||||
}
|
||||
container.appendChild(createCodeblockLang(this.Lang));
|
||||
headerContainer.appendChild(createCodeblockLang(this.Lang));
|
||||
}
|
||||
|
||||
container.appendChild(createFileName(this.text));
|
||||
headerContainer.appendChild(createFileName(this.text));
|
||||
|
||||
this.observer.view = view;
|
||||
this.observer.observe(container, { attributes: true });
|
||||
this.observer.observe(headerContainer, { attributes: true });
|
||||
|
||||
container.addEventListener("mousedown", event => {
|
||||
container.setAttribute("data-clicked", "true");
|
||||
headerContainer.addEventListener("mousedown", event => {
|
||||
headerContainer.setAttribute("data-clicked", "true");
|
||||
});
|
||||
//EditorView.requestMeasure;
|
||||
|
||||
return container;
|
||||
return headerContainer;
|
||||
}
|
||||
|
||||
destroy(dom: HTMLElement) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
// Prism Languages
|
||||
// https://prismjs.com/plugins/show-language/
|
||||
|
||||
export const Languages = {
|
||||
const PRISM_LANGUAGES: {[key: string]: string} = { // Prism Languages: https://prismjs.com/plugins/show-language/
|
||||
"none": "Plain text",
|
||||
"plain": "Plain text",
|
||||
"plaintext": "Plain text",
|
||||
|
|
@ -277,9 +274,7 @@ export const Languages = {
|
|||
"yml": "YAML",
|
||||
"yang": "YANG",
|
||||
};
|
||||
|
||||
// manually generated list from https://prismjs.com/ - 297 languages
|
||||
export const manualLang = {
|
||||
const MANUAL_LANGUAGES: {[key: string]: string} = { // Manually generated list from https://prismjs.com/ - 297 languages
|
||||
"css":"CSS",
|
||||
"clike":"C-like",
|
||||
"javascript":"JavaScript",
|
||||
|
|
@ -672,10 +667,8 @@ export const manualLang = {
|
|||
"yang":"YANG",
|
||||
"zig":"Zig"
|
||||
}
|
||||
|
||||
// https://github.com/vscode-icons/vscode-icons/wiki/ListOfFiles
|
||||
// https://devicon.dev/
|
||||
export const Icons = {
|
||||
export const LANGUAGE_NAMES: {[key: string]: string} = {...PRISM_LANGUAGES,...MANUAL_LANGUAGES};
|
||||
const LANGUAGE_ICONS_DATA: {[key: string]: string} = { // Icons from https://github.com/vscode-icons/vscode-icons/wiki/ListOfFiles and https://devicon.dev/
|
||||
".gitignore": `<path d="M29.472,14.753,17.247,2.528a1.8,1.8,0,0,0-2.55,0L12.158,5.067l3.22,3.22a2.141,2.141,0,0,1,2.712,2.73l3.1,3.1a2.143,2.143,0,1,1-1.285,1.21l-2.895-2.895v7.617a2.141,2.141,0,1,1-1.764-.062V12.3a2.146,2.146,0,0,1-1.165-2.814L10.911,6.314,2.528,14.7a1.8,1.8,0,0,0,0,2.551L14.753,29.472a1.8,1.8,0,0,0,2.55,0L29.472,17.3a1.8,1.8,0,0,0,0-2.551" style="fill:#dd4c35"/><path d="M12.158,5.067l3.22,3.22a2.141,2.141,0,0,1,2.712,2.73l3.1,3.1a2.143,2.143,0,1,1-1.285,1.21l-2.895-2.895v7.617a2.141,2.141,0,1,1-1.764-.062V12.3a2.146,2.146,0,0,1-1.165-2.814L10.911,6.314" style="fill:#fff"/>`,
|
||||
".hgignore": `<path d="M28.042,23.172c4.989-8.3-1.054-21.751-12.1-20.384C5.955,4.022,5.794,14.53,14.593,17.026c7.614,2.162,1.573,6.992,1.749,10.208s6.62,4.382,11.7-4.063" style="fill:#1b1b1b"/><circle cx="9.784" cy="24.257" r="4.332" style="fill:#1b1b1b"/><circle cx="4.835" cy="15.099" r="2.835" style="fill:#1b1b1b"/><path d="M28.231,22.835c4.989-8.3-1.054-21.751-12.1-20.384C6.144,3.686,5.983,14.194,14.781,16.69c7.614,2.162,1.573,6.992,1.749,10.208s6.62,4.382,11.7-4.063" style="fill:#bfbfbf"/><circle cx="9.972" cy="23.921" r="4.332" style="fill:#bfbfbf"/><circle cx="5.023" cy="14.762" r="2.835" style="fill:#bfbfbf"/><path d="M17.811,28.168a.669.669,0,0,1,.635-.994,7,7,0,0,0,3.7-.746c3.247-1.841,8.244-10.7,5.731-16.285A12.77,12.77,0,0,0,25.049,5.7c-.236-.249-.1-.236.059-.152a10.08,10.08,0,0,1,2.857,3.676,14.578,14.578,0,0,1,1.1,10.279c-.494,1.817-2.2,5.928-4.691,7.706s-5.424,2.8-6.563.955M15.548,16.673c-1.7-.5-3.894-1.208-5.163-2.867A8.088,8.088,0,0,1,8.854,10.49c-.043-.27-.08-.5,0-.558a21.882,21.882,0,0,0,1.688,2.723,6.487,6.487,0,0,0,3.526,2.256,12.383,12.383,0,0,1,3.867,1.37c.739.629.8,1.989.552,2.142s-.759-1.1-2.938-1.749m-8.155,10.4c3.369,3.121,8.439-1.166,6.207-4.954-.251-.425-.576-.749-.469-.423.714,2.178.054,3.9-1.176,4.788a4.063,4.063,0,0,1-4.192.328c-.39-.2-.551.092-.37.261m-3.93-10.16c.018.2.292.458.722.576a2.969,2.969,0,0,0,2.55-.413,2.759,2.759,0,0,0,.81-3.452c-.172-.308-.4-.533-.218-.041A2.68,2.68,0,0,1,6.148,16.53a2.439,2.439,0,0,1-2.1.164c-.391-.119-.6.016-.58.223"/><path d="M19.056,28.407c-.033.389.414.466,1.016.376a6.755,6.755,0,0,0,2.313-.648,9.54,9.54,0,0,0,3.314-2.63c2.662-3.473,3.6-7.582,3.46-8.173A16.172,16.172,0,0,1,27,22.692c-1.888,2.968-3.256,4.548-6.413,5.314-.879.213-1.485-.112-1.529.4m-7-13.5A7.967,7.967,0,0,0,14.6,16.089a12.2,12.2,0,0,1,2.96,1.31c.378.253.618.819.642.317s-.285-.934-.976-1.164a15.274,15.274,0,0,0-2.009-.674c-.485-.1-1.273-.285-1.949-.493-.371-.114-.748-.313-1.214-.483M10.037,27.718c.429-.09,2.924-.736,3.51-2.788.183-.64.215-.511.164-.165a3.8,3.8,0,0,1-3.358,3.123c-.289.03-.668-.1-.315-.17M5.046,17.2a7.991,7.991,0,0,0,1.195-.336,2.383,2.383,0,0,0,1.232-1.741c.064-.505.083-.378.109-.1a2.627,2.627,0,0,1-2.147,2.324c-.2.028-.56.011-.389-.143" style="fill:#fff"/><path d="M27.54,17.446c2.124-6.123-2.321-15.37-11.315-14.258-8.126,1-8.257,9.557-1.1,11.59,8.112,1.228,3.227,7.347,2.535,10.433-.621,2.766,6.555,3.221,9.876-7.765M7.219,26.2a2.028,2.028,0,0,1,1.332.442,3.525,3.525,0,0,0,3.755-.983A4.154,4.154,0,0,0,12.869,22c-.806-2.319-4.229-2.278-5.758-.353-1.654,2.15-.4,4.539.108,4.548M2.676,15.451a1.166,1.166,0,0,0,.908.863c.731.1.88.434,1.743.263A2.464,2.464,0,0,0,7.1,14.916a1.771,1.771,0,0,0-.824-2.14,2.689,2.689,0,0,0-3.047.363,2.263,2.263,0,0,0-.558,2.312" style="fill:#999"/><path d="M21.981,22.228c-2.2-.272-5.36,4.69-2.378,4.109h0a5.645,5.645,0,0,0,3.683-1.932,23.136,23.136,0,0,0,4.055-7.2c.5-1.861.251-4.745-.269-2.036-.533,2.781-2.893,7.336-5.091,7.064M10.523,26.362A2.778,2.778,0,0,0,12.5,22.99c-.165-1.276-.861,1.584-2.15,2.012-1.953.648-1.733,1.861.176,1.361m-4.978-10.2c.663-.173,1.54-1.077,1.1-1.767-.537-.85-2.033-.122-2.084.824s.277,1.127.979.943" style="fill:#f3f3f3"/>`,
|
||||
".npmignore": `<path d="M2,10.555H30v9.335H16v1.556H9.778V19.889H2Zm1.556,7.779H6.667V13.666H8.222v4.667H9.778V12.111H3.556Zm7.778-6.223v7.779h3.111V18.334h3.111V12.111Zm3.111,1.556H16v3.112H14.444Zm4.667-1.556v6.223h3.111V13.666h1.556v4.667h1.556V13.666h1.556v4.667h1.556V12.111Z" style="fill:#cb3837"/>`,
|
||||
|
|
@ -853,3 +846,7 @@ export const Icons = {
|
|||
"YANG": `<path d="M8.877,23.159c0-5.535,3.992-7.168,7.894-7.168,3.357,0,5.988-3.811,5.988-6.624,0-3.621-2.487-5.831-4.882-7.12A13.881,13.881,0,1,0,14.5,29.8C10.491,28.248,8.877,25.324,8.877,23.159Z" style="fill:#fff"/><path d="M14.482,29.917A14,14,0,0,1,16,2a14.154,14.154,0,0,1,1.893.131l.04.013c2.255,1.213,4.944,3.452,4.944,7.223,0,2.715-2.564,6.741-6.106,6.741-2.9,0-7.776.916-7.776,7.05,0,2.022,1.451,4.946,5.542,6.531ZM16,2.236A13.765,13.765,0,0,0,13.637,29.56c-3.581-1.684-4.877-4.447-4.877-6.4,0-6.576,5.6-7.286,8.012-7.286,3.406,0,5.87-3.886,5.87-6.506,0-3.645-2.606-5.82-4.8-7.006A13.928,13.928,0,0,0,16,2.236Z" style="fill:#231f20"/><path d="M29.882,16a13.882,13.882,0,0,0-12-13.752c2.4,1.289,4.882,3.5,4.882,7.12,0,2.813-2.631,6.624-5.988,6.624-3.9,0-7.894,1.633-7.894,7.168,0,2.166,1.613,5.089,5.618,6.641A13.875,13.875,0,0,0,29.882,16Z" style="fill:#231f20"/><path d="M16,30a14.2,14.2,0,0,1-1.518-.083l-.03-.007c-4.2-1.628-5.693-4.654-5.693-6.75,0-6.576,5.6-7.286,8.012-7.286,3.406,0,5.87-3.886,5.87-6.506,0-3.655-2.621-5.833-4.82-7.016l.072-.221A14,14,0,0,1,16,30Zm-1.477-.316A13.756,13.756,0,0,0,29.764,16,13.807,13.807,0,0,0,18.5,2.466c2.115,1.272,4.377,3.441,4.377,6.9,0,2.715-2.564,6.741-6.106,6.741-2.9,0-7.776.916-7.776,7.05C9,25.178,10.443,28.1,14.523,29.684Z" style="fill:#231f20"/><circle cx="15.943" cy="22.787" r="1.506" style="fill:#fff"/><circle cx="16.007" cy="9.142" r="1.506" style="fill:#231f20"/>`,
|
||||
"Zig": `<polygon points="5.733 19.731 5.733 12.264 8.533 12.264 8.533 8.531 2 8.531 2 23.464 5.547 23.464 8.907 19.731 5.733 19.731" style="fill:#f7a41d"/><polygon points="26.453 8.531 23.093 12.264 26.267 12.264 26.267 19.731 23.467 19.731 23.467 23.464 30 23.464 30 8.531 26.453 8.531" style="fill:#f7a41d"/><polygon points="26.875 6.707 20.513 8.531 9.467 8.531 9.467 12.264 16.847 12.264 5.115 25.293 11.497 23.464 22.533 23.464 22.533 19.731 15.148 19.731 26.875 6.707" style="fill:#f7a41d"/>`
|
||||
}
|
||||
export const LANGUAGE_ICONS: {[key: string]: string} = Object.keys(LANGUAGE_ICONS_DATA).reduce((result: {[key: string]: string}, key: string) => {
|
||||
result[key] = 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">${LANGUAGE_ICONS_DATA[key]}</svg>`], { type: "image/svg+xml" }));
|
||||
return result
|
||||
},{})
|
||||
|
|
@ -1,7 +1,109 @@
|
|||
import { MarkdownView, MarkdownPostProcessorContext, sanitizeHTMLToDom } from "obsidian";
|
||||
import { TFile, MarkdownView, MarkdownPostProcessorContext, MarkdownSectionInformation, CachedMetadata, sanitizeHTMLToDom } from "obsidian";
|
||||
|
||||
import { searchString, getHighlightedLines, getLanguageName, isExcluded, getLanguageIcon, createContainer, createCodeblockLang, createCodeblockIcon, createFileName } from "./Utils";
|
||||
import CodeblockCustomizerPlugin from "./main";
|
||||
import { CodeblockCustomizerThemeSettings } from "./Settings";
|
||||
import { CodeblockParameters, parseCodeblockParameters, isLanguageExcluded } from "./CodeblockParsing";
|
||||
import { createHeader } from "./CodeblockDecorating";
|
||||
|
||||
export async function ReadingView(codeBlockElement: HTMLElement, context: MarkdownPostProcessorContext, plugin: CodeblockCustomizerPlugin) {
|
||||
export async function readingViewPostProcessor(element: HTMLElement, context: MarkdownPostProcessorContext, plugin: CodeblockCustomizerPlugin) {
|
||||
const codeblockCodeElement: HTMLElement | null = element.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);
|
||||
|
||||
const codeblockPreElement: HTMLPreElement | null = element.querySelector("pre:not(.frontmatter)");
|
||||
if (!codeblockPreElement)
|
||||
return;
|
||||
|
||||
const codeblockSectionInfo: MarkdownSectionInformation | null = context.getSectionInfo(codeblockCodeElement);
|
||||
if (codeblockSectionInfo) {
|
||||
const view: MarkdownView | null = plugin.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (!view || typeof view?.editor === 'undefined')
|
||||
return;
|
||||
const codeblockFirstLine = view.editor.getLine(codeblockSectionInfo.lineStart);
|
||||
remakeCodeblock(codeblockCodeElement, codeblockPreElement, codeblockFirstLine, plugin);
|
||||
} else {
|
||||
// PDF export
|
||||
const file = plugin.app.vault.getAbstractFileByPath(context.sourcePath);
|
||||
if (!file) {
|
||||
console.error(`File not found: ${context.sourcePath}`);
|
||||
return;
|
||||
}
|
||||
const fileContent = await plugin.app.vault.cachedRead(<TFile> file).catch((error) => {
|
||||
console.error(`Error reading file: ${error.message}`);
|
||||
return '';
|
||||
});
|
||||
|
||||
}
|
||||
const cache: CachedMetadata | null = plugin.app.metadataCache.getCache(context.sourcePath);
|
||||
const fileContentLines = fileContent.split(/\n/g);
|
||||
const codeBlockFirstLines: Array<string> = [];
|
||||
|
||||
if (typeof cache?.sections !== 'undefined') {
|
||||
for (const element of cache.sections)
|
||||
if (element.type === 'code')
|
||||
codeBlockFirstLines.push(fileContentLines[element.position.start.line]);
|
||||
} else {
|
||||
console.error(`Metadata cache not found for file: ${context.sourcePath}`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
PDFExport(element, plugin, codeBlockFirstLines);
|
||||
} catch (error) {
|
||||
console.error(`Error exporting to PDF: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decorateCodeblock(codeblockCodeElement: HTMLElement, codeblockPreElement: HTMLElement, codeblockParameters: CodeblockParameters, themeSettings: CodeblockCustomizerThemeSettings) {
|
||||
createHeader(codeblockPreElement,codeblockParameters,themeSettings)
|
||||
let codeblockLines = codeblockCodeElement.innerHTML.split("\n");
|
||||
if (codeblockLines.length == 1)
|
||||
codeblockLines = ['',''];
|
||||
codeblockCodeElement.innerHTML = "";
|
||||
codeblockLines.forEach((line,index) => {
|
||||
const lineNumber = index + 1;
|
||||
const lineWrapper = document.createElement("div");
|
||||
//TODO (@mayurankv) Future: Speed this up by setting up a reverse dictionary for line number to highlights
|
||||
if (codeblockParameters.highlights.default.includes(lineNumber))
|
||||
lineWrapper.classList.add('codeblock-customizer-line-highlighted')
|
||||
Object.entries(codeblockParameters.highlights.alternative).forEach(([alternativeHighlight,highlightedLineNumbers]: [string,Array<number>]) => {
|
||||
if (highlightedLineNumbers.includes(lineNumber))
|
||||
lineWrapper.classList.add(`codeblock-customizer-line-highlighted-${alternativeHighlight.replace(/\s+/g, '-').toLowerCase()}`)
|
||||
})
|
||||
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: `codeblock-customizer-line-number${lineNumberDisplay}`, text: lineNumber.toString()}));
|
||||
lineWrapper.appendChild(createDiv({cls: `codeblock-customizer-line-text`, text: sanitizeHTMLToDom(line !== "" ? line : "<br>")}));
|
||||
})
|
||||
}
|
||||
function remakeCodeblock(codeblockCodeElement: HTMLElement, codeblockPreElement: HTMLElement, codeblockFirstLine: string, plugin: CodeblockCustomizerPlugin) {
|
||||
const codeblockParameters = parseCodeblockParameters(codeblockFirstLine,plugin.settings.currentTheme);
|
||||
|
||||
const excludeCodeblock = isLanguageExcluded(codeblockParameters.language,plugin.settings.excludedLanguages);
|
||||
if (excludeCodeblock)
|
||||
return;
|
||||
|
||||
codeblockPreElement.classList.add(`codeblock-customizer-pre`);
|
||||
if (codeblockPreElement.parentElement)
|
||||
codeblockPreElement.parentElement.classList.add(`codeblock-customizer-pre-parent`);
|
||||
|
||||
decorateCodeblock(codeblockCodeElement,codeblockPreElement,codeblockParameters,plugin.settings.currentTheme.settings);
|
||||
}
|
||||
function PDFExport(element: HTMLElement, plugin: CodeblockCustomizerPlugin, codeBlockFirstLines: string[]) {
|
||||
const codeblockPreElements = element.querySelectorAll('pre:not(.frontmatter)');
|
||||
codeblockPreElements.forEach((codeblockPreElement: HTMLElement, key: number) => {
|
||||
const codeblockCodeElement: HTMLPreElement | null = codeblockPreElement.querySelector("pre > code");
|
||||
if (!codeblockCodeElement)
|
||||
return;
|
||||
const codeblockFirstLine = codeBlockFirstLines[key];
|
||||
remakeCodeblock(codeblockCodeElement, codeblockPreElement, codeblockFirstLine, plugin)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,230 +0,0 @@
|
|||
import { MarkdownView, MarkdownPostProcessorContext, sanitizeHTMLToDom } from "obsidian";
|
||||
|
||||
import { searchString, getHighlightedLines, getLanguageName, isExcluded, getLanguageIcon, createContainer, createCodeblockLang, createCodeblockIcon, createFileName } from "./Utils";
|
||||
|
||||
export async function ReadingView(codeBlockElement: HTMLElement, context: MarkdownPostProcessorContext, plugin: CodeblockCustomizerPlugin) {
|
||||
const codeElm: HTMLElement = codeBlockElement.querySelector('pre > code');
|
||||
|
||||
if (!codeElm)
|
||||
return;
|
||||
|
||||
const classRegex = /^language-\S+/;
|
||||
const match = Array.from(codeElm.classList).some(className => classRegex.test(className));
|
||||
if (match)
|
||||
while(!codeElm.classList.contains("is-loaded"))
|
||||
await sleep(2);
|
||||
|
||||
const codeBlockSectionInfo = context.getSectionInfo(codeElm);
|
||||
|
||||
let codeBlockFirstLine = "";
|
||||
if (codeBlockSectionInfo) {
|
||||
const view = plugin.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (view && view.editor)
|
||||
codeBlockFirstLine = view.editor.getLine(codeBlockSectionInfo.lineStart);
|
||||
} else {
|
||||
// PDF export
|
||||
const file = plugin.app.vault.getAbstractFileByPath(context.sourcePath);
|
||||
if (!file) {
|
||||
//console.error(`File not found: ${context.sourcePath}`);
|
||||
return;
|
||||
}
|
||||
const cache = plugin.app.metadataCache.getCache(context.sourcePath);
|
||||
const fileContent = await plugin.app.vault.cachedRead(<TFile> file).catch((error) => {
|
||||
//console.error(`Error reading file: ${error.message}`);
|
||||
return '';
|
||||
});
|
||||
const fileContentLines = fileContent.split(/\n/g);
|
||||
const codeBlockFirstLines: string[] = [];
|
||||
|
||||
if (cache.sections) {
|
||||
for (const element of cache.sections) {
|
||||
if (element.type === 'code') {
|
||||
const lineStart = element.position.start.line;
|
||||
const codeBlockFirstLine = fileContentLines[lineStart];
|
||||
if (!isAdmonition(codeBlockFirstLine)) {
|
||||
codeBlockFirstLines.push(codeBlockFirstLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//console.error(`Metadata cache not found for file: ${context.sourcePath}`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await PDFExport(codeBlockElement, plugin, codeBlockFirstLines);
|
||||
} catch (error) {
|
||||
//console.error(`Error exporting to PDF: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const codeBlockLang = searchString(codeBlockFirstLine, "```");
|
||||
const highlightedLinesParams = searchString(codeBlockFirstLine, "HL:");
|
||||
const linesToHighlight = getHighlightedLines(highlightedLinesParams);
|
||||
const FileName = searchString(codeBlockFirstLine, "file:");
|
||||
const Fold = searchString(codeBlockFirstLine, "fold");
|
||||
const lineNumberOffset = 0; //searchString(codeBlockFirstLine, "ln:")//TODO (@mayurankv) Set line number offset here - Should be ln_value - 1 since it is offset, not starting line number - 0 if true OR false
|
||||
const showNumbers = true; //TODO (@mayurankv) Set showNumbers to be true if ln:<number> or ln:true or false if ln:false
|
||||
const alternateColors = plugin.settings.alternateColors || [];
|
||||
let altHL = [];
|
||||
for (const { name } of alternateColors) {
|
||||
const altParams = searchString(codeBlockFirstLine, `${name}:`);
|
||||
altHL = altHL.concat(getHighlightedLines(altParams).map((lineNumber) => ({ name, lineNumber })));
|
||||
}
|
||||
|
||||
let isCodeBlockExcluded = false;
|
||||
isCodeBlockExcluded = isExcluded(codeBlockFirstLine, plugin.settings.ExcludeLangs);
|
||||
|
||||
const codeElements = codeBlockElement.getElementsByTagName("code");
|
||||
const codeBlockPreElement: HTMLPreElement | null = codeBlockElement.querySelector("pre:not(.frontmatter)");
|
||||
if (codeBlockPreElement === null) {
|
||||
return;
|
||||
}
|
||||
if (!isCodeBlockExcluded) {
|
||||
codeBlockPreElement.classList.add(`codeblock-customizer-pre`);
|
||||
}
|
||||
|
||||
AddHeaderAndHighlight(isCodeBlockExcluded, FileName, codeBlockPreElement, codeBlockLang, Fold, codeElements, showNumbers, lineNumberOffset, linesToHighlight, altHL );
|
||||
}// ReadingView
|
||||
|
||||
function isAdmonition(lineText: string): boolean {
|
||||
const adTypes = ["ad-note", "ad-seealso", "ad-abstract", "ad-summary", "ad-tldr", "ad-info", "ad-todo", "ad-tip", "ad-hint", "ad-important", "ad-success", "ad-check", "ad-done", "ad-question", "ad-help", "ad-faq", "ad-warning", "ad-caution", "ad-attention", "ad-failure", "ad-fail", "ad-missing", "ad-danger", "ad-error", "ad-bug", "ad-example", "ad-quote", "ad-cite"]; //TODO (@mayurankv) refactor to use regex
|
||||
const codeBlockLang = searchString(lineText, "```");
|
||||
return adTypes.some((adType) => codeBlockLang && codeBlockLang.startsWith(adType));
|
||||
}// isAdmonition
|
||||
|
||||
function HeaderWidget(preElements, textToDisplay: string, specificHeader: boolean, codeblockLanguage: string, Collapse: boolean) {
|
||||
const parent = preElements.parentNode;
|
||||
|
||||
const container = createContainer(specificHeader);
|
||||
if (codeblockLanguage){
|
||||
const Icon = getLanguageIcon(codeblockLanguage)
|
||||
if (Icon) {
|
||||
container.appendChild(createCodeblockIcon(codeblockLanguage));
|
||||
}
|
||||
container.appendChild(createCodeblockLang(codeblockLanguage));
|
||||
}
|
||||
container.appendChild(createFileName(textToDisplay));
|
||||
parent.insertBefore(container, preElements);
|
||||
|
||||
// Add event listener to the widget element
|
||||
container.addEventListener("click", function() {
|
||||
// Toggle the "collapsed" class on the codeblock element
|
||||
preElements.classList.toggle("codeblock-customizer-codeblock-collapsed");
|
||||
});
|
||||
|
||||
if (Collapse) {
|
||||
preElements.classList.add(`codeblock-customizer-codeblock-collapsed`);
|
||||
}
|
||||
|
||||
}// HeaderWidget
|
||||
|
||||
function createLineNumberElement(lineNumber,showNumbers) {
|
||||
const lineNumberWrapper = document.createElement("div");
|
||||
lineNumberWrapper.classList.add(`codeblock-customizer-line-number${showNumbers?'':'-hide'}`);
|
||||
lineNumberWrapper.setText(lineNumber);
|
||||
|
||||
return lineNumberWrapper;
|
||||
}// createLineNumberElement
|
||||
|
||||
function createLineTextElement(line) {
|
||||
const lineText = line !== "" ? line : "<br>";
|
||||
const sanitizedText = sanitizeHTMLToDom(lineText);
|
||||
const lineContentWrapper = createDiv({cls: `codeblock-customizer-line-text`, text: sanitizedText});
|
||||
|
||||
return lineContentWrapper;
|
||||
}// createLineTextElement
|
||||
|
||||
function highlightLines(codeElements, showNumbers, lineNumberOffset, linesToHighlight, altHL) {
|
||||
for (let i = 0; i < codeElements.length; i++) {
|
||||
let lines = codeElements[i].innerHTML.split("\n");
|
||||
const preElm = codeElements[i].parentNode;
|
||||
if (preElm === null || preElm.nodeName !== "PRE") // only process pre > code elements
|
||||
return;
|
||||
|
||||
if (lines.length == 1) {
|
||||
lines = ['',''];
|
||||
}
|
||||
codeElements[i].innerHTML = "";
|
||||
for (let j = 0; j < lines.length - 1; j++) {
|
||||
const line = lines[j];
|
||||
const lineNumber = j + 1;
|
||||
const isHighlighted = linesToHighlight.includes(lineNumber);
|
||||
const altHLMatch = altHL.filter((hl) => hl.lineNumber === lineNumber);
|
||||
|
||||
// create line element
|
||||
const lineWrapper = document.createElement("div");
|
||||
if (isHighlighted) {
|
||||
lineWrapper.classList.add(`codeblock-customizer-line-highlighted`);
|
||||
}
|
||||
else if (altHLMatch.length > 0) {
|
||||
lineWrapper.classList.add(`codeblock-customizer-line-highlighted-${altHLMatch[0].name.replace(/\s+/g, '-').toLowerCase()}`);
|
||||
}
|
||||
codeElements[i].appendChild(lineWrapper);
|
||||
|
||||
// create line number element
|
||||
const lineNumberEl = createLineNumberElement(lineNumber+lineNumberOffset,showNumbers);
|
||||
lineWrapper.appendChild(lineNumberEl);
|
||||
|
||||
// create line text element
|
||||
const lineTextEl = createLineTextElement(line);
|
||||
lineWrapper.appendChild(lineTextEl);
|
||||
}
|
||||
}
|
||||
}// highlightLines
|
||||
|
||||
function AddHeaderAndHighlight(isCodeBlockExcluded, fileName, codeBlockPreElement, codeBlockLang, Fold, codeElements, showNumbers, lineNumberOffset, linesToHighlight, altHL ){
|
||||
if (!isCodeBlockExcluded) {
|
||||
let specificHeader = true;
|
||||
if (fileName === null || fileName === "") {
|
||||
if (Fold) {
|
||||
fileName = 'Collapsed Code';
|
||||
} else {
|
||||
fileName = '';
|
||||
specificHeader = false;
|
||||
}
|
||||
}
|
||||
HeaderWidget(codeBlockPreElement, fileName, specificHeader, getLanguageName(codeBlockLang), Fold);
|
||||
highlightLines(codeElements, showNumbers, lineNumberOffset, linesToHighlight, altHL);
|
||||
|
||||
if (codeBlockPreElement.parentElement) {
|
||||
codeBlockPreElement.parentElement.classList.add(`codeblock-customizer-pre-parent`);
|
||||
}
|
||||
}
|
||||
}// AddHeaderAndHighlight
|
||||
|
||||
function PDFExport(codeBlockElement: HTMLElement, plugin: CodeblockCustomizerPlugin, codeBlockFirstLines: string[]) {
|
||||
const codeBlocks = codeBlockElement.querySelectorAll('pre > code');
|
||||
codeBlocks.forEach((codeElm, key) => {
|
||||
const codeBlockFirstLine = codeBlockFirstLines[key];
|
||||
const codeBlockLang = searchString(codeBlockFirstLine, "```");
|
||||
const highlightedLinesParams = searchString(codeBlockFirstLine, "HL:");
|
||||
const linesToHighlight = getHighlightedLines(highlightedLinesParams);
|
||||
const fileName = searchString(codeBlockFirstLine, "file:");
|
||||
const Fold = searchString(codeBlockFirstLine, "fold");
|
||||
const lineNumberOffset = 0; //searchString(codeBlockFirstLine, "ln:")//TODO (@mayurankv) Set line number offset here - Should be ln_value - 1 since it is offset, not starting line number - 0 if true OR false
|
||||
const showNumbers = true; //TODO (@mayurankv) Set showNumbers to be true if ln:<number> or ln:true or false if ln:false
|
||||
const alternateColors = plugin.settings.alternateColors || [];
|
||||
let altHL = [];
|
||||
for (const { name, _ } of alternateColors) {
|
||||
const altParams = searchString(codeBlockFirstLine, `${name}:`);
|
||||
altHL = altHL.concat(getHighlightedLines(altParams).map((lineNumber) => ({ name, lineNumber })));
|
||||
}
|
||||
|
||||
let isCodeBlockExcluded = false;
|
||||
isCodeBlockExcluded = isExcluded(codeBlockFirstLine, plugin.settings.ExcludeLangs);
|
||||
|
||||
const codeBlockPreElement: HTMLPreElement | null = codeElm.parentElement;
|
||||
if (codeBlockPreElement === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCodeBlockExcluded){
|
||||
codeBlockPreElement.classList.add(`codeblock-customizer-pre`);
|
||||
}
|
||||
const codeElements = codeBlockPreElement.getElementsByTagName("code");
|
||||
|
||||
AddHeaderAndHighlight(isCodeBlockExcluded, fileName, codeBlockPreElement, codeBlockLang, Fold, codeElements, showNumbers, lineNumberOffset, linesToHighlight, altHL );
|
||||
})
|
||||
}// PDFExport
|
||||
|
|
@ -92,7 +92,7 @@ export interface CodeblockCustomizerSettings {
|
|||
default: boolean;
|
||||
},
|
||||
newHighlight: string;
|
||||
excludedLangs: string;
|
||||
excludedLanguages: string;
|
||||
}
|
||||
|
||||
// Theme Defaults
|
||||
|
|
@ -244,5 +244,5 @@ export const DEFAULT_SETTINGS: CodeblockCustomizerSettings = {
|
|||
currentTheme: structuredClone(DEFAULT_THEME),
|
||||
newTheme: NEW_THEME_DEFAULT,
|
||||
newHighlight: '',
|
||||
excludedLangs: "dataview, dataviewjs, ad-*",
|
||||
excludedLanguages: "dataview, dataviewjs, ad-*",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ export class SettingsTab extends PluginSettingTab {
|
|||
.setDesc('Define languages in a comma separated list on which the plugin should not apply. You can use a wildcard (*) either at the beginning, or at the end. For example: ad-* will exclude codeblocks where the language starts with ad- e.g.: ad-info, ad-error etc.')
|
||||
.addText(text => text
|
||||
.setPlaceholder('e.g. dataview, python etc.')
|
||||
.setValue(this.plugin.settings.excludedLangs)
|
||||
.setValue(this.plugin.settings.excludedLanguages)
|
||||
.onChange((value) => {
|
||||
this.plugin.settings.excludedLangs = value;
|
||||
this.plugin.settings.excludedLanguages = value;
|
||||
(async () => {await this.plugin.saveSettings()})();
|
||||
}));
|
||||
|
||||
|
|
@ -560,15 +560,12 @@ export class SettingsTab extends PluginSettingTab {
|
|||
|
||||
// ========== Donation ==========
|
||||
const donationDiv = containerEl.createEl("div", { cls: "codeblock-customizer-donation", });
|
||||
const donationText = createEl("p");
|
||||
const donationButton = createEl("a", { href: "https://www.buymeacoffee.com/ThePirateKing"});
|
||||
|
||||
donationText.appendText("If you like this plugin, and would like to help support continued development, use the button below!");
|
||||
donationButton.innerHTML = `<img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=ThePirateKing&button_colour=e3e7ef&font_colour=262626&font_family=Inter&outline_colour=262626&coffee_colour=ff0000" height="42px">`;
|
||||
|
||||
const donationText = createEl("p", {text: "If you like this plugin, and would like to help support continued development, use the button below!"});
|
||||
donationDiv.appendChild(donationText);
|
||||
const donationButton = createEl("a", { href: "https://www.buymeacoffee.com/ThePirateKing"});
|
||||
donationButton.innerHTML = `<img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=ThePirateKing&button_colour=e3e7ef&font_colour=262626&font_family=Inter&outline_colour=262626&coffee_colour=ff0000" height="42px">`;
|
||||
donationDiv.appendChild(donationButton);
|
||||
}//display
|
||||
}
|
||||
|
||||
// Setting Creation
|
||||
createPickr(plugin: CodeblockCustomizerPlugin, containerEl: HTMLElement, setting: Setting, id: string, getRelevantThemeColor: (relevantThemeColors: CodeblockCustomizerThemeColors)=>Color, saveRelevantThemeColor: (relevantThemeColors: CodeblockCustomizerThemeColors, saveColor: Color)=>void, disabled?: ()=>boolean) {
|
||||
|
|
@ -675,7 +672,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||
})
|
||||
})
|
||||
}
|
||||
}// SettingsTab
|
||||
}
|
||||
|
||||
class PickrResettable extends Pickr {
|
||||
saveColor: (saveColor: Color)=>void;
|
||||
|
|
|
|||
233
src/Utils.ts
233
src/Utils.ts
|
|
@ -1,194 +1,43 @@
|
|||
import { Languages, manualLang, Icons } from "./Const";
|
||||
import { CodeblockCustomizerSettings } from "./Settings";
|
||||
|
||||
export function splitAndTrimString(str) {
|
||||
if (!str) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Replace * with .*
|
||||
str = str.replace(/\*/g, '.*');
|
||||
|
||||
if (!str.includes(",")) {
|
||||
return [str];
|
||||
}
|
||||
|
||||
return str.split(",").map(s => s.trim());
|
||||
}// splitAndTrimString
|
||||
|
||||
export function searchString(str, searchTerm) {
|
||||
const originalStr = str;
|
||||
str = str.toLowerCase();
|
||||
searchTerm = searchTerm.toLowerCase();
|
||||
if (searchTerm === "file:") {
|
||||
if (str.includes(searchTerm)) {
|
||||
const startIndex = str.indexOf(searchTerm) + searchTerm.length;
|
||||
let result = "";
|
||||
if (str[startIndex] === "\"") {
|
||||
const endIndex = str.indexOf("\"", startIndex + 1);
|
||||
if (endIndex !== -1) {
|
||||
result = originalStr.substring(startIndex + 1, endIndex);
|
||||
} else {
|
||||
result = originalStr.substring(startIndex + 1);
|
||||
}
|
||||
} else {
|
||||
const endIndex = str.indexOf(" ", startIndex);
|
||||
if (endIndex !== -1) {
|
||||
result = originalStr.substring(startIndex, endIndex);
|
||||
} else {
|
||||
result = originalStr.substring(startIndex);
|
||||
}
|
||||
}
|
||||
return result.trim();
|
||||
}
|
||||
} else if (searchTerm === "```") {
|
||||
if (str.startsWith(searchTerm)) {
|
||||
const startIndex = searchTerm.length;
|
||||
const endIndex = str.indexOf(" ", startIndex);
|
||||
let word = "";
|
||||
if (endIndex !==-1) {
|
||||
word = originalStr.substring(startIndex, endIndex);
|
||||
} else {
|
||||
word = originalStr.substring(startIndex);
|
||||
}
|
||||
if (!word.includes(":")) {
|
||||
if (word.toLowerCase() === "fold")
|
||||
return null;
|
||||
else
|
||||
return word;
|
||||
}
|
||||
}
|
||||
} else if (searchTerm === 'fold') {
|
||||
if (str.includes(" fold ")) {
|
||||
return true;
|
||||
}
|
||||
const index = str.indexOf(searchTerm);
|
||||
if (index !== -1 && index === str.length - searchTerm.length && str[index - 1] === " ") {
|
||||
return true;
|
||||
}
|
||||
if (str.includes("```fold ")) {
|
||||
return true;
|
||||
}
|
||||
if (str.includes("```fold") && str.indexOf("```fold") + "```fold".length === str.length) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
if (str.includes(searchTerm)) {
|
||||
const startIndex = str.indexOf(searchTerm) + searchTerm.length;
|
||||
const endIndex = str.indexOf(" ", startIndex);
|
||||
if (endIndex !== -1) {
|
||||
return originalStr.substring(startIndex, endIndex).trim();
|
||||
} else {
|
||||
return originalStr.substring(startIndex).trim();
|
||||
}
|
||||
// Setting Management
|
||||
export function getCurrentMode() {
|
||||
const body = document.querySelector('body');
|
||||
if (body !== null){
|
||||
if (body.classList.contains('theme-light')) {
|
||||
return "light";
|
||||
} else if (body.classList.contains('theme-dark')) {
|
||||
return "dark";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}//searchString
|
||||
console.log('Warning: Couldn\'t get current theme');
|
||||
return "light";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export function getHighlightedLines(params: string): number[] {
|
||||
if (!params) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const trimmedParams = params.trim();
|
||||
const lines = trimmedParams.split(",");
|
||||
|
||||
return lines.map(line => {
|
||||
if (line.includes("-")) {
|
||||
const range = line.split("-");
|
||||
const start = parseInt(range[0], 10);
|
||||
const end = parseInt(range[1], 10);
|
||||
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
||||
}
|
||||
return parseInt(line, 10);
|
||||
}).flat();
|
||||
}// getHighlightedLines
|
||||
|
||||
export function isExcluded(lineText: string, excludeLangs: string[]) : boolean {
|
||||
const codeBlockLang = searchString(lineText, "```");
|
||||
const regexLangs = splitAndTrimString(excludeLangs).map(lang => new RegExp(`^${lang.replace(/\*/g, '.*')}$`, 'i'));
|
||||
|
||||
for (const regexLang of regexLangs) {
|
||||
if (codeBlockLang && regexLang.test(codeBlockLang)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}// isExcluded
|
||||
|
||||
export function getLanguageIcon(DisplayName) {
|
||||
if (!DisplayName)
|
||||
return "";
|
||||
|
||||
if (Icons.hasOwnProperty(DisplayName)) {
|
||||
return Icons[DisplayName];
|
||||
}
|
||||
|
||||
return null;
|
||||
}// getLanguageIcon
|
||||
|
||||
export function getLanguageName(code) {
|
||||
if (!code)
|
||||
return "";
|
||||
|
||||
code = code.toLowerCase();
|
||||
|
||||
if (Languages.hasOwnProperty(code)) {
|
||||
return Languages[code];
|
||||
} else if (manualLang.hasOwnProperty(code)) {
|
||||
return manualLang[code];
|
||||
} else if (code){
|
||||
return code.charAt(0).toUpperCase() + code.slice(1);
|
||||
}
|
||||
|
||||
return "";
|
||||
}// getLanguageName
|
||||
|
||||
export const BLOBS: Record<string, string> = {};
|
||||
export function loadIcons(){
|
||||
for (const [key, value] of Object.entries(Icons)) {
|
||||
BLOBS[key.replace(/\s/g, "_")] = 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">${value}</svg>`], { type: "image/svg+xml" }));
|
||||
}
|
||||
}// loadIcons
|
||||
|
||||
// Functions for displaying header BEGIN
|
||||
export function createContainer(specific: boolean) {
|
||||
const container = document.createElement("div");
|
||||
container.classList.add(`codeblock-customizer-header-container${specific?'-specific':''}`);
|
||||
return container;
|
||||
}// createContainer
|
||||
|
||||
export function createCodeblockLang(lang: string) {
|
||||
const codeblockLang = document.createElement("div");
|
||||
codeblockLang.innerText = lang;
|
||||
codeblockLang.classList.add(`codeblock-customizer-header-language-tag-${getLanguageName(lang).toLowerCase()}`);
|
||||
return codeblockLang;
|
||||
}// createCodeblockLang
|
||||
|
||||
export function createCodeblockIcon(displayLang: string) {
|
||||
const div = document.createElement("div");
|
||||
const img = document.createElement("img");
|
||||
img.classList.add("codeblock-customizer-icon");
|
||||
img.width = 28; //32
|
||||
img.src = BLOBS[displayLang.replace(/\s/g, "_")];
|
||||
|
||||
div.appendChild(img);
|
||||
|
||||
return div;
|
||||
}// createCodeblockIcon
|
||||
|
||||
export function createFileName(text: string) {
|
||||
const fileName = document.createElement("div");
|
||||
fileName.innerText = text;
|
||||
fileName.classList.add("codeblock-customizer-header-text");
|
||||
return fileName;
|
||||
}// createFileName
|
||||
|
||||
// Functions for displaying header END
|
||||
|
||||
const stylesDict = {
|
||||
activeCodeBlockLineColor: 'codeblock-active-line-color',
|
||||
|
|
@ -339,39 +188,3 @@ function accessSetting(key: string, settings: CodeblockCustomizerSettings) {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Setting Management
|
||||
export function getCurrentMode() {
|
||||
const body = document.querySelector('body');
|
||||
if (body !== null){
|
||||
if (body.classList.contains('theme-light')) {
|
||||
return "light";
|
||||
} else if (body.classList.contains('theme-dark')) {
|
||||
return "dark";
|
||||
}
|
||||
}
|
||||
console.log('Warning: Couldn\'t get current theme');
|
||||
return "light";
|
||||
}
|
||||
|
|
|
|||
37
src/main.ts
37
src/main.ts
|
|
@ -1,11 +1,12 @@
|
|||
import { Plugin } from "obsidian";
|
||||
|
||||
import { DEFAULT_SETTINGS, CodeblockCustomizerSettings } from './Settings';
|
||||
import { LANGUAGE_ICONS } from './LanguageDetails';
|
||||
import { codeblockHighlight } from "./CodeBlockHighlight";
|
||||
import { codeblockHeader, collapseField } from "./Header";
|
||||
import { ReadingView } from "./ReadingViewOld";
|
||||
import { readingViewPostProcessor } from "./ReadingView";
|
||||
import { SettingsTab } from "./SettingsTab";
|
||||
import { loadIcons, BLOBS, updateSettingStyles } from "./Utils";
|
||||
import { } from "./Utils";
|
||||
|
||||
export default class CodeblockCustomizerPlugin extends Plugin {
|
||||
settings: CodeblockCustomizerSettings;
|
||||
|
|
@ -13,43 +14,37 @@ export default class CodeblockCustomizerPlugin extends Plugin {
|
|||
async onload() {
|
||||
await this.loadSettings();
|
||||
document.body.classList.add('codeblock-customizer');
|
||||
|
||||
loadIcons();
|
||||
|
||||
const settingsTab = new SettingsTab(this.app, this);
|
||||
this.addSettingTab(settingsTab);
|
||||
|
||||
codeblockHeader.settings = this.settings;
|
||||
collapseField.pluginSettings = this.settings;
|
||||
|
||||
this.registerEditorExtension([
|
||||
codeblockHeader,
|
||||
collapseField,
|
||||
codeblockHighlight(this.settings)
|
||||
]);
|
||||
|
||||
const settingsTab = new SettingsTab(this.app, this);
|
||||
this.addSettingTab(settingsTab);
|
||||
|
||||
//updateSettingStyles(this.settings);
|
||||
|
||||
this.registerEvent(this.app.workspace.on('css-change', this.handleCssChange.bind(this, settingsTab), this));
|
||||
|
||||
// reading mode
|
||||
this.registerMarkdownPostProcessor(async (el, ctx) => {
|
||||
await ReadingView(el, ctx, this)
|
||||
await readingViewPostProcessor(el, ctx, this)
|
||||
})
|
||||
|
||||
//updateSettingStyles(this.settings);
|
||||
// this.registerEvent(this.app.workspace.on('css-change', this.handleCssChange.bind(this, settingsTab), this));
|
||||
|
||||
console.log("loading CodeBlock Customizer plugin");
|
||||
}// onload
|
||||
}
|
||||
|
||||
handleCssChange(settingsTab) {
|
||||
console.log('updating css');
|
||||
}// handleCssChange
|
||||
// handleCssChange(settingsTab) {
|
||||
// console.log('updating css');
|
||||
// }
|
||||
|
||||
onunload() {
|
||||
console.log("unloading CodeBlock Customizer plugin");
|
||||
// unload icons
|
||||
for (const url of Object.values(BLOBS)) {
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
for (const url of Object.values(LANGUAGE_ICONS))
|
||||
URL.revokeObjectURL(url) // Unload icons
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue