This commit is contained in:
mayurankv 2025-01-30 12:38:05 +00:00
parent 0aad76228e
commit 71dff89726
21 changed files with 36835 additions and 193 deletions

6
.todo
View file

@ -1,4 +1,6 @@
external reference
blur end of title if scrollable
blur end of reference if scrollable
external reference styling
get shiki base theme to class names
add shiki to fence rendered and codemirror both
add not shiki clauses for decorating colours
@ -20,7 +22,7 @@ Refactor:
☐ Guide for adding Icons and note about language support: https://github.com/mayurankv/Obsidian-Code-Styler/discussions/185
☐ Hide delimiter lines
☐ code styler compatibility
☐ Look into tokenising wiht textmate tokeniser
☐ Look into tokenising with textmate tokeniser
☐ https://shiki.style
☐ https://github.com/mProjectsCode/obsidian-shiki-plugin/issues/25
☐ Textmate tokeniser

View file

@ -3,10 +3,10 @@ import { CodeStylerThemeSettings } from "src/Internal/types/settings";
export function isHeaderHidden(
codeParameters: CodeParameters,
themeSettings: CodeStylerThemeSettings,
plugin: CodeStylerPlugin,
iconURL: string | undefined,
): boolean {
return !isHeaderRequired(codeParameters) && (codeParameters.language === "" || (themeSettings.header.languageTag.display !== "always" && (themeSettings.header.languageIcon.display !== "always" || (typeof iconURL == "undefined"))));
return !isHeaderRequired(codeParameters) && (codeParameters.language === "" || (plugin.settings.header.languageTag.display !== "always" && (themeSettings.header.languageIcon.display !== "always" || (typeof iconURL == "undefined"))));
}
function isLanguageIconShown(
@ -31,5 +31,5 @@ function isLanguageTagShown(
function isHeaderRequired(
codeParameters: CodeParameters,
): boolean {
return codeParameters.fold.enabled || codeParameters.title !== "";
return codeParameters.fold.enabled || codeParameters.title !== null;
}

View file

@ -21,7 +21,7 @@ const context = await esbuild.context({
"src/styles.scss",
],
bundle: true,
minify: true,
// minify: true,
external: [
"obsidian",
"electron",

36328
main.js

File diff suppressed because one or more lines are too long

View file

@ -6,7 +6,7 @@ export function foldOnClick(
view: EditorView,
target: HTMLElement,
folded: boolean,
language: string,
language: string | null,
) {
codeblockFoldCallback(
view.posAtDOM(target),

View file

@ -155,7 +155,7 @@ export class LineNumberWidget extends WidgetType {
cls: [
PREFIX + "line-number",
],
text: (this.lineNumber + this.lineNumbers.offset).toString(),
text: (this.lineNumber + (this.lineNumbers.offset ?? 0)).toString(),
});
}
}

View file

@ -80,7 +80,7 @@ function buildInlineCodeDecoration(
}),
});
if (toHighlightInlineCode(plugin))
if (toHighlightInlineCode(inlineCodeInfo.parameters.value, plugin))
decorations = [
...decorations,
...inlineSyntaxHighlight(
@ -132,11 +132,14 @@ function buildInlineCodeDecoration(
function inlineSyntaxHighlight(
state: EditorState,
language: string,
language: string | null,
content: string,
start: number,
plugin: CodeStylerPlugin,
): Array<Range<Decoration>> {
if (language === null)
return []
const decorations: Array<{from: number, to: number, value: Decoration}> = []
// @ts-expect-error Undocumented Obsidian API

View file

@ -229,18 +229,14 @@ function markupFencePreElement(
fencePreElement.classList.add(...classList);
fencePreElement.setAttribute(DEFAULT_FOLD_ATTRIBUTE, fenceCodeParameters.fold.enabled.toString());
if (fenceCodeParameters.fold.enabled !== null)
fencePreElement.setAttribute(DEFAULT_FOLD_ATTRIBUTE, fenceCodeParameters.fold.enabled.toString());
if (staticRender)
return;
if (fenceCodeParameters.fold.enabled)
fencePreElement.setAttribute(FOLD_ATTRIBUTE, "true");
if (fenceCodeParameters.lineUnwrap.alwaysEnabled)
fencePreElement.setAttribute(WRAP_ATTRIBUTE, fenceCodeParameters.lineUnwrap.activeWrap ? "unwrapped-inactive" : "unwrapped");
else if (fenceCodeParameters.lineUnwrap.alwaysDisabled)
fencePreElement.setAttribute(WRAP_ATTRIBUTE, "wrapped");
}
function markupFenceCodeElement(
@ -272,13 +268,22 @@ function markupFenceCodeElement(
(line, idx, fenceCodeLines) => idx !== fenceCodeLines.length - 1,
).map(
(line, idx) => {
const lineNumber = idx + fenceCodeParameters.lineNumbers.offset + 1
const lineNumber = idx + (fenceCodeParameters.lineNumbers.offset ?? 0) + 1
const lineContainer = createDiv({
cls: getLineClasses(fenceCodeParameters, lineNumber, line)
});
lineContainer.append(
createDiv({ cls: PREFIX + "line-number", text: lineNumber.toString() }),
createDiv({ cls: PREFIX + "line-text", text: sanitizeHTMLToDom(line !== "" ? line : "<br>") }),
createDiv({
cls: [
PREFIX + "line-number",
...((fenceCodeParameters.lineNumbers.enabled === null) ? [] : [PREFIX + "line-numbers-enabled-" + fenceCodeParameters.lineNumbers.enabled]),
],
text: lineNumber.toString(),
}),
createDiv({
cls: PREFIX + "line-text",
text: sanitizeHTMLToDom(line !== "" ? line : "<br>"),
}),
);
return lineContainer
@ -286,9 +291,19 @@ function markupFenceCodeElement(
)
fenceCodeElement.addClass(`${PREFIX}code`)
if (fenceCodeParameters.language !== "")
if (fenceCodeParameters.language)
fenceCodeElement.addClass(`language-${fenceCodeParameters.language}`);
if (fenceCodeParameters.lineUnwrap !== null)
fenceCodeElement.setAttribute(
WRAP_ATTRIBUTE,
fenceCodeParameters.lineUnwrap === "inactive"
? "unwrapped-inactive"
: fenceCodeParameters.lineUnwrap
? "unwrapped"
: "wrapped",
);
fenceCodeElement.replaceChildren(...lineContainers)
}

View file

@ -86,32 +86,17 @@ async function markupInlineCodeElement(
inlineCodeParameters: InlineCodeParameters,
plugin: CodeStylerPlugin,
): Promise<void> {
if (toHighlightInlineCode(plugin)) {
if (!USE_SHIKI) {
const temporaryRenderingContainer = createDiv();
await MarkdownRenderer.render(
plugin.app,
["```", inlineCodeParameters.language, "\n", inlineCodeElement.getAttribute(CONTENT_ATTRIBUTE) ?? "", "\n", "```"].join(""),
temporaryRenderingContainer,
TEMPORARY_SOURCEPATH,
plugin,
);
const renderedCodeElement = temporaryRenderingContainer.querySelector("code");
if (!renderedCodeElement)
throw new Error("Could not render highlighted code");
inlineCodeElement.innerHTML = renderedCodeElement.innerHTML + '&ZeroWidthSpace;';
} else {
if (toHighlightInlineCode(inlineCodeParameters, plugin)) {
if (USE_SHIKI) {
try {
const htmlSections = (
await codeToHtml(
inlineCodeElement.getAttribute(CONTENT_ATTRIBUTE) ?? "",
{
lang: inlineCodeParameters.language,
lang: inlineCodeParameters.language ?? "",
themes: {
light: (inlineCodeParameters.theme === "") ? 'github-light' : inlineCodeParameters.theme, //TODO: Replace github with settings default theme
dark: (inlineCodeParameters.theme === "") ? 'github-dark' : inlineCodeParameters.theme, //TODO: Replace github with settings default theme
light: inlineCodeParameters.theme ?? 'github-light', //TODO: Replace github with settings default theme
dark: inlineCodeParameters.theme ?? 'github-dark', //TODO: Replace github with settings default theme
},
defaultColor: inlineCodeParameters.dark === null
? false
@ -133,7 +118,24 @@ async function markupInlineCodeElement(
if (inlineCodeParameters.dark !== null)
inlineCodeElement.addClass(`${PREFIX}shiki-${inlineCodeParameters.dark ? 'dark' : 'light'}`)
} catch (error) { }
} else {
const temporaryRenderingContainer = createDiv();
await MarkdownRenderer.render(
plugin.app,
["```", inlineCodeParameters.language ?? "", "\n", inlineCodeElement.getAttribute(CONTENT_ATTRIBUTE) ?? "", "\n", "```"].join(""),
temporaryRenderingContainer,
TEMPORARY_SOURCEPATH,
plugin,
);
const renderedCodeElement = temporaryRenderingContainer.querySelector("code");
if (!renderedCodeElement)
throw new Error("Could not render highlighted code");
inlineCodeElement.innerHTML = renderedCodeElement.innerHTML + '&ZeroWidthSpace;';
}
} else {
inlineCodeElement.innerHTML = inlineCodeElement.getAttribute(CONTENT_ATTRIBUTE) ?? "";
}
inlineCodeElement.addClass(`${PREFIX}code-inline`)

View file

@ -134,7 +134,7 @@ function createLanguageTitle(
{
cls: [
PREFIX + "language-title",
...(codeParameters.language !== "" ? [] : [PREFIX + "hidden"]),
...(codeParameters.language !== null ? [] : [PREFIX + "hidden"]),
],
text: getLanguageName(codeParameters.language)
},
@ -148,19 +148,19 @@ function createNamedTitle(
plugin: CodeStylerPlugin,
): HTMLElement {
const title = fence
? codeParameters.title || (codeParameters as FenceCodeParameters).fold.placeholder || plugin.settings.currentTheme.settings.header.foldPlaceholder || FOLD_PLACEHOLDER || ""
? codeParameters.title || ((codeParameters as FenceCodeParameters).fold.placeholder ?? plugin.settings.currentTheme.settings.header.foldPlaceholder) || FOLD_PLACEHOLDER || ""
: codeParameters.title || ""
const namedTitleContainer = createEl(
fence ? "div" : "span",
{
cls: [
PREFIX + "title",
...(codeParameters.title !== "" ? [] : [PREFIX + "hidden"]),
...(codeParameters.title !== null ? [] : [PREFIX + "hidden"]),
],
},
)
if (codeParameters.reference !== "")
if (codeParameters.reference !== null)
MarkdownRenderer.render( //TODO (@mayurankv) Add links to metadata cache properly
plugin.app,
isUrl(codeParameters.reference)
@ -292,7 +292,7 @@ function createExternalReferenceTitle(
{
cls: [
PREFIX + "reference-title",
...(codeParameters.title !== "" ? [] : [PREFIX + "hidden"]),
...(codeParameters.title !== null ? [] : [PREFIX + "hidden"]),
],
text: fence
? codeParameters.title || (codeParameters as FenceCodeParameters).fold.placeholder || plugin.settings.currentTheme.settings.header.foldPlaceholder || FOLD_PLACEHOLDER || ""
@ -329,7 +329,7 @@ function createHeaderSeparator(
{
cls: [
PREFIX + "separator",
...((!fence && ((codeParameters.title !== "") || (codeParameters.language !== "" && (codeParameters.icon || true)))) ? [] : [PREFIX + "hidden"]), //TODO: true should be setting if to add language title
...((!fence && ((codeParameters.title !== null) || (codeParameters.language !== null && (codeParameters.icon || true)))) ? [] : [PREFIX + "hidden"]), //TODO: true should be setting if to add language title
],
text: '\uff5c',
},

View file

@ -48,16 +48,16 @@ function getBodyClasses(
const themeSettings = plugin.settings.currentTheme.settings
return Object.entries({
"code-styler-style-inline": themeSettings.inline.style,
"code-styler-gutter-highlight": themeSettings.gutter.highlight,
"code-styler-gutter-active-line": themeSettings.gutter.activeLine,
"code-styler-active-line-highlight": themeSettings.highlights.activeEditorLine && themeSettings.highlights.activeCodeblockLine, // Inside and outside of codeblocks with different colours
"code-styler-active-line-highlight-editor": themeSettings.highlights.activeEditorLine && !themeSettings.highlights.activeCodeblockLine, // Only outside codeblocks
"code-styler-active-line-highlight-codeblock": !themeSettings.highlights.activeEditorLine && themeSettings.highlights.activeCodeblockLine, // Only inside codeblocks
"line-numbers-enabled-false": !themeSettings.codeblock.lineNumbers,
// "code-styler-gutter-highlight": themeSettings.gutter.highlight,
// "code-styler-gutter-active-line": themeSettings.gutter.activeLine,
// "code-styler-active-line-highlight": themeSettings.highlights.activeEditorLine && themeSettings.highlights.activeCodeblockLine, // Inside and outside of codeblocks with different colours
// "code-styler-active-line-highlight-editor": themeSettings.highlights.activeEditorLine && !themeSettings.highlights.activeCodeblockLine, // Only outside codeblocks
// "code-styler-active-line-highlight-codeblock": !themeSettings.highlights.activeEditorLine && themeSettings.highlights.activeCodeblockLine, // Only inside codeblocks
}).filter(
([cssclass, setting]) => setting,
).map(
([cssclass, setting]) => cssclass,
([cssclass, setting]) => PREFIX + cssclass,
)
}

View file

@ -113,10 +113,8 @@ export async function referenceAdjustParameters(
if (reference.external)
fenceCodeParameters.externalReference = reference;
if (!fenceCodeParameters.lineNumbers.alwaysDisabled && !fenceCodeParameters.lineNumbers.alwaysEnabled) {
if (fenceCodeParameters.lineNumbers.offset === null)
fenceCodeParameters.lineNumbers.offset = reference.startLine - 1;
fenceCodeParameters.lineNumbers.alwaysEnabled = Boolean(reference.startLine !== 1);
}
}
return fenceCodeParameters;
@ -136,7 +134,7 @@ function externalPluginAdjustFenceCodeParameters(
if (fenceCodeParameters.title === "")
adjustedParameters.title = executeCodeCodeblockArgs?.label ?? fenceCodeParameters.title
if (fenceCodeParameters.language.startsWith("run-")) {
if (fenceCodeParameters.language?.startsWith("run-")) {
const executeCodeLanguage = fenceCodeParameters.language.slice(4)
if (EXECUTE_CODE_SUPPORTED_LANGUAGES.includes(executeCodeLanguage) && !isLanguageMatched(fenceCodeParameters.language, plugin.settings.processedCodeblocksWhitelist))
adjustedParameters.language = executeCodeLanguage
@ -195,26 +193,7 @@ function inferFenceValue(
parameterValue: string,
): Partial<FenceCodeParameters> {
if (parameterKey === "unwrap") {
if (parameterValue === "incactive")
return {
lineUnwrap: {
alwaysEnabled: true,
alwaysDisabled: false,
activeWrap: true
}
}
const booleanParameterValue = convertBoolean(parameterValue)
return booleanParameterValue === null
? {}
: {
lineUnwrap: {
alwaysEnabled: booleanParameterValue,
alwaysDisabled: !booleanParameterValue,
activeWrap: false
}
}
return { lineUnwrap: (parameterValue === "inactive") ? "inactive" : convertBoolean(parameterValue)}
} else if (parameterKey === "fold") {
return {
@ -229,18 +208,16 @@ function inferFenceValue(
if (/^\d+$/.test(parameterValue))
return {
lineNumbers: {
alwaysEnabled: true,
alwaysDisabled: false,
enabled: true,
offset: parseInt(parameterValue) - 1,
}
}
const booleanParameterValue = convertBoolean(parameterValue)
return booleanParameterValue === null ? {} : {
return {
lineNumbers: {
alwaysEnabled: booleanParameterValue,
alwaysDisabled: !booleanParameterValue,
enabled: booleanParameterValue,
offset: 0
}
}
@ -268,28 +245,15 @@ function inferFenceShorthand(
}
else if (parameterShorthand === "wrap")
return {
lineUnwrap: {
alwaysEnabled: true,
alwaysDisabled: false,
activeWrap: false
}
}
return { lineUnwrap: false }
else if (parameterShorthand === "unwrap")
return {
lineUnwrap: {
alwaysEnabled: true,
alwaysDisabled: false,
activeWrap: false
}
}
return { lineUnwrap: true }
else if (parameterShorthand === "ln")
return {
lineNumbers: {
alwaysEnabled: true,
alwaysDisabled: false,
enabled: true,
offset: 0,
}
}

View file

@ -82,9 +82,10 @@ export function toDecorateInlineCode(
}
export function toHighlightInlineCode(
inlineCodeParameters: InlineCodeParameters,
plugin: CodeStylerPlugin,
): boolean {
return plugin.settings.currentTheme.settings.inline.syntaxHighlight
return plugin.settings.currentTheme.settings.inline.syntaxHighlight && (inlineCodeParameters.language !== null)
}
export function splitInlineCodeRaw(

View file

@ -33,8 +33,8 @@ export const OBSIDIAN_THEME_STYLES: Record<string, ThemeStyle> = {
export const DECORATED_ATTRIBUTE = DATA_PREFIX + PREFIX + "decorated"
export const DEFAULT_FOLD_ATTRIBUTE = DATA_PREFIX + PREFIX + "fold-default"
export const FOLD_ATTRIBUTE = PREFIX + "fold"
export const WRAP_ATTRIBUTE = PREFIX + "wrap"
export const FOLD_ATTRIBUTE = DATA_PREFIX + PREFIX + "fold"
export const WRAP_ATTRIBUTE = DATA_PREFIX + PREFIX + "wrap"
export const FOLD_PLACEHOLDER = "Folded Code";

View file

@ -1,4 +1,5 @@
import { CodeStylerThemeModeColours, Colour } from "../types/settings";
import { Colour } from "../types/decoration";
import { CodeStylerThemeModeColours } from "../types/settings";
const DEFAULT_THEME: Record<string, Colour> = {
backgroundColour: "--code-background",

View file

@ -10,32 +10,29 @@ export interface LinkInfo {
}
export class CodeParameters {
language: string = "";
title: string = "";
reference: string = "";
theme: string = "";
language: string | null = null;
title: string | null = null;
reference: string | null = null;
theme: string | null = null;
dark: boolean | null = null;
icon: boolean = true;
ignore: boolean = false;
}
export interface LineParameters {
alwaysEnabled: boolean;
alwaysDisabled: boolean;
offset: number;
enabled: boolean | null;
offset: number | null;
}
export interface FoldParameters {
enabled: boolean | null;
placeholder: string | null;
}
export class FenceCodeParameters extends CodeParameters {
fold: {
enabled: boolean;
placeholder: string;
} = {enabled: false, placeholder: ""};
lineNumbers: LineParameters = {alwaysEnabled: false, alwaysDisabled: false, offset: 0};
lineUnwrap: {
alwaysEnabled: boolean;
alwaysDisabled: boolean;
activeWrap: boolean;
} = {alwaysEnabled: false, alwaysDisabled: false, activeWrap: false};
fold: FoldParameters = {enabled: null, placeholder: null};
lineNumbers: LineParameters = {enabled: null, offset: null};
lineUnwrap: boolean | null | "inactive" = null;
highlights: {
default: Highlights;
alternative: Record<string, Highlights>

View file

@ -17,7 +17,7 @@ export function getLineClasses(
const classList = [
PREFIX + "line",
...Object.entries({ default: fenceCodeParameters.highlights.default, ...fenceCodeParameters.highlights.alternative }).filter(
([highlightName, highlights]: [string, Highlights]) => toHighlight(highlights, lineNumber + fenceCodeParameters.lineNumbers.offset, line)
([highlightName, highlights]: [string, Highlights]) => toHighlight(highlights, lineNumber + (fenceCodeParameters.lineNumbers.offset ?? 0), line)
).map(
([highlightName, highlights]: [string, Highlights]) => `${PREFIX}highlighted-${toKebabCase(highlightName)}`
),
@ -27,15 +27,21 @@ export function getLineClasses(
}
export function getLanguageIcon(
language: string,
language: string | null,
plugin: CodeStylerPlugin,
): string | null {
if (language === null)
return null
return plugin.resources.languageIcons?.[getLanguageName(language)] ?? null;
}
export function getLanguageName(
language: string,
language: string | null,
): string {
if (language === null)
return ""
return LANGUAGE_NAMES?.[language] ?? ((language.charAt(0).toUpperCase() + language.slice(1)) || "");
}

View file

@ -114,9 +114,12 @@ function getLinks(
}
export function isLanguageMatched(
language: string,
language: string | null,
languagesString: string,
): boolean {
if (language === null)
return false
return languagesString.split(",").filter(
regexLanguage => regexLanguage !== ""
).map(

View file

@ -4,6 +4,10 @@ body.cs-plugin {
--cs-language-border: var(--size-4-1);
--cs-gutter-border-width: var(--size-2-1);
.markdown-source-view.mod-cm6 .cm-embed-block:not(.cm-table-widget):has(> .cs-pre-parent) {
border-radius: var(--cs-code-fence-radius);
}
.cs-pre-parent {
> pre.cs-pre {
border-radius: var(--cs-code-fence-radius);
@ -14,23 +18,6 @@ body.cs-plugin {
background-color: var(--cs-code-background-colour);
padding-right: var(--cs-fixed-left-fence);
// &::before {
// content: "";
// background-color: orange;
// // background: linear-gradient(to right, transparent, 20%, var(--cs-code-background-colour));
// position: sticky;
// left: 0;
// top: 0;
// // margin-left: calc(-1 * var(--size-4-4));
// width: var(--size-4-4);
// padding-right: 0px;
// margin-right: 0px;
// height: 100%;
// z-index: 3;
// grid-row: 2;
// padding-bottom: var(--size-4-3);
// }
&::after {
content: "";
background: linear-gradient(to right, transparent, var(--cs-fixed-gradient-1), var(--cs-code-background-colour));
@ -155,14 +142,22 @@ body.cs-plugin {
> code.cs-code {
display: grid;
grid-row: 2;
grid-column: span 2;
// grid-column-start: 1;
// grid-column-end: 2;
grid-template-columns: min-content auto;
grid-template-rows: auto;
overflow: visible;
white-space: pre;
width: max-content;
padding-right: var(--cs-fixed-left-fence);
padding-top: var(--size-4-1);
&[data-cs-wrap = "wrapped"],
&[data-cs-wrap = "unwrapped-inactive"]:active {
width: unset;
padding-right: 0;
}
> div.cs-line {
display: contents;
@ -206,6 +201,14 @@ body.cs-plugin {
// backdrop-filter: blur(2px);
z-index: 10;
}
&.cs-line-numbers-enabled-false {
display: none;
}
&.cs-line-numbers-enabled-true {
display: block;
}
}
> div.cs-line-text {
@ -235,5 +238,42 @@ body.cs-plugin {
}
}
}
}
body.cs-plugin.line-numbers-enabled-false {
.cs-pre-parent {
> pre.cs-pre {
> code.cs-code {
> div.cs-line {
> div.cs-line-number {
&:not(.cs-line-numbers-enabled-true) {
display: none;
}
}
}
}
}
}
}
// body.cs-plugin {
// .cs-pre-parent {
// > pre.cs-pre:not(:active) {
// > code.cs-code {
// > div.cs-line {
// > div.cs-line-number {
// &:not(.cs-line-numbers-enabled-true) {
// display: none;
// }
// }
// }
// }
// }
// }
// }
// &[data-cs-wrap = "unwrapped-inactive"]:not(:active) {
// width: unset;
// padding-right: 0;
// }

File diff suppressed because one or more lines are too long