mirror of
https://github.com/mayurankv/Obsidian-Code-Styler.git
synced 2026-07-22 08:10:29 +00:00
Regex highlighting
This commit is contained in:
parent
3e79d42fd9
commit
cda626c017
9 changed files with 114 additions and 55 deletions
17
README.md
17
README.md
|
|
@ -114,14 +114,20 @@ Clicking on header
|
|||
|
||||
### Highlighting
|
||||
|
||||
To highlight lines, specify `hl:` followed by line numbers in the first line of the codeblock.
|
||||
To highlight lines, specify `hl:` followed by line numbers, plain text or regular expressions in the first line of the codeblock.
|
||||
|
||||
- You can specify either single line numbers separated with a comma e.g.: `hl:1,3,5,7`.
|
||||
- You can specify ranges e.g.: `hl:2-5` This would highlight lines from 2 to 5.
|
||||
- You can also combine the methods e.g.: `hl:1,3,4-6` This would highlight lines 1, 3 and lines from 4 to 6.
|
||||
You can specify any of the following highlight types separated with commas (**without spaces**) e.g.: `hl:1,3-4,foo,'bar baz',"bar and baz",/#\w{6}/`.
|
||||
|
||||
- Single numbers: `hl:1` would highlight the first line
|
||||
- Number ranges: `hl:1-3` would highlight lines 1 through to 3
|
||||
- Plain text: `hl:foo` would highlight lines with the word `foo` inside them
|
||||
- Plain text in speech marks or quotation marks: `hl:'bar baz'` or `hl:"bar baz"` would highlight lines with the word `bar baz` inside them
|
||||
- Regular Expressions: `hl:/#\w{6}/` would highlight lines which match this regular expression (tested by `regex.test(line)`) - for this example any lines with hexadecimal colors are highlighted
|
||||
|
||||
Combinations of these will highlight all relevant lines.
|
||||
|
||||
Example:
|
||||
` ```cpp hl:1,3,4-6`
|
||||
` ```cpp hl:1,3-4,foo,'bar baz',"bar and baz",/#\w{6}/`
|
||||
|
||||

|
||||
|
||||
|
|
@ -239,7 +245,6 @@ Take a look at the [changelog](CHANGELOG.md) to see what has changed in past ver
|
|||
- Implement code wrapping options
|
||||
- In reading mode, if wrapped, keep line numbers to the left when scrolling
|
||||
- Add commands to fold all, unfold all and reset default fold for codeblocks
|
||||
- Regex highlighting parameter
|
||||
- Context Menu on right click
|
||||
- Copy codeblock
|
||||
- Copy line
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 103 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 196 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 102 KiB |
73
main.js
73
main.js
File diff suppressed because one or more lines are too long
|
|
@ -1,5 +1,5 @@
|
|||
import { LANGUAGE_NAMES, LANGUAGE_ICONS, CodeblockCustomizerThemeSettings } from "./Settings";
|
||||
import { CodeblockParameters } from "./CodeblockParsing";
|
||||
import { CodeblockParameters, Highlights } from "./CodeblockParsing";
|
||||
|
||||
export function createHeader(codeblockParameters: CodeblockParameters, themeSettings: CodeblockCustomizerThemeSettings): HTMLElement {
|
||||
const headerContainer = createDiv({cls: `codeblock-customizer-header-container${(codeblockParameters.fold.enabled || codeblockParameters.title !== '')?'-specific':''}`});
|
||||
|
|
@ -20,7 +20,10 @@ export function createHeader(codeblockParameters: CodeblockParameters, themeSett
|
|||
if (codeblockParameters.title !== '')
|
||||
headerText = codeblockParameters.title;
|
||||
else if (codeblockParameters.fold.enabled)
|
||||
headerText = codeblockParameters.fold.placeholder!==''?codeblockParameters.fold.placeholder:themeSettings.header.collapsePlaceholder!==''?themeSettings.header.collapsePlaceholder:'Collapsed Code';
|
||||
if (codeblockParameters.fold.placeholder!=='')
|
||||
headerText = codeblockParameters.fold.placeholder;
|
||||
else
|
||||
headerText = themeSettings.header.collapsePlaceholder!==''?themeSettings.header.collapsePlaceholder:'Collapsed Code';
|
||||
headerContainer.appendChild(createDiv({cls: "codeblock-customizer-header-text", text: headerText}));
|
||||
|
||||
return headerContainer;
|
||||
|
|
@ -40,13 +43,12 @@ function getLanguageIcon(language: string) {
|
|||
return null;
|
||||
}
|
||||
|
||||
export function getLineClass(codeblockParameters: CodeblockParameters, lineNumber: number): Array<string> {
|
||||
//TODO (@mayurankv) Future: Speed this up by setting up a reverse dictionary for line number to highlights
|
||||
export function getLineClass(codeblockParameters: CodeblockParameters, lineNumber: number, line: string): Array<string> {
|
||||
let classList: Array<string> = [];
|
||||
if (codeblockParameters.highlights.default.includes(lineNumber))
|
||||
if (codeblockParameters.highlights.default.lineNumbers.includes(lineNumber) || codeblockParameters.highlights.default.plainText.some(text => line.indexOf(text) > -1) || codeblockParameters.highlights.default.regularExpressions.some(regExp => regExp.test(line)))
|
||||
classList.push('codeblock-customizer-line-highlighted');
|
||||
Object.entries(codeblockParameters.highlights.alternative).forEach(([alternativeHighlight,highlightedLineNumbers]: [string,Array<number>]) => {
|
||||
if (highlightedLineNumbers.includes(lineNumber))
|
||||
Object.entries(codeblockParameters.highlights.alternative).forEach(([alternativeHighlight,highlightedLines]: [string,Highlights]) => {
|
||||
if (highlightedLines.lineNumbers.includes(lineNumber) || highlightedLines.plainText.some(text => line.indexOf(text) > -1) || highlightedLines.regularExpressions.some(regExp => regExp.test(line)))
|
||||
classList.push(`codeblock-customizer-line-highlighted-${alternativeHighlight.replace(/\s+/g, '-').toLowerCase()}`);
|
||||
})
|
||||
if (classList.length === 0)
|
||||
|
|
|
|||
|
|
@ -13,12 +13,18 @@ export interface CodeblockParameters {
|
|||
offset: number;
|
||||
}
|
||||
highlights: {
|
||||
default: Array<number>;
|
||||
alternative: Record<string,Array<number>>
|
||||
default: Highlights;
|
||||
alternative: Record<string,Highlights>
|
||||
},
|
||||
ignore: boolean;
|
||||
}
|
||||
|
||||
export interface Highlights {
|
||||
lineNumbers: Array<number>;
|
||||
plainText: Array<string>;
|
||||
regularExpressions: Array<RegExp>;
|
||||
}
|
||||
|
||||
export function parseCodeblockParameters(parameterLine: string, theme: CodeblockCustomizerTheme): CodeblockParameters {
|
||||
let codeblockParameters: CodeblockParameters = {
|
||||
language: '',
|
||||
|
|
@ -33,7 +39,11 @@ export function parseCodeblockParameters(parameterLine: string, theme: Codeblock
|
|||
offset: 0,
|
||||
},
|
||||
highlights: {
|
||||
default: [],
|
||||
default: {
|
||||
lineNumbers: [],
|
||||
plainText: [],
|
||||
regularExpressions: [],
|
||||
},
|
||||
alternative: {},
|
||||
},
|
||||
ignore: false,
|
||||
|
|
@ -82,7 +92,7 @@ function parseParameterString(parameterString: string, codeblockParameters: Code
|
|||
codeblockParameters.lineNumbers.offset = 0;
|
||||
}
|
||||
} else {
|
||||
let highlightMatch = /^(\w+):((?:\d+-\d+|\d+)(?:,\d+-\d+|,\d+)*)$/.exec(parameterString);
|
||||
let highlightMatch = /^(\w+):(.+)$/.exec(parameterString);
|
||||
if (highlightMatch) {
|
||||
let highlights = parseHighlightedLines(highlightMatch[2]);
|
||||
if (highlightMatch[1] === 'hl')
|
||||
|
|
@ -93,18 +103,35 @@ function parseParameterString(parameterString: string, codeblockParameters: Code
|
|||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
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();
|
||||
highlightRules.forEach(highlightRule => {
|
||||
if (/\d+-\d+/.test(highlightRule)) { // Number Range
|
||||
const [start,end] = highlightRule.split('-').map(num => parseInt(num));
|
||||
if (start && end && start <= end)
|
||||
Array.from({length:end-start+1}, (_,num) => num + start).forEach(lineNumber => lineNumbers.add(lineNumber));
|
||||
} else if (/^\/(.*)\/$/.test(highlightRule)) { // Regex
|
||||
try {
|
||||
regularExpressions.add(new RegExp(highlightRule.replace(/^\/(.*)\/$/,"$1")));
|
||||
} catch { }
|
||||
} else if (/".*"/.test(highlightRule)) { // Plain Text
|
||||
plainText.add(highlightRule.substring(1,highlightRule.length-1));
|
||||
} else if (/'.*'/.test(highlightRule)) { // Plain Text
|
||||
plainText.add(highlightRule.substring(1,highlightRule.length-1));
|
||||
} else if (/\D/.test(highlightRule)) { // Plain Text
|
||||
plainText.add(highlightRule);
|
||||
} else if (/\d+/.test(highlightRule)) { // Plain Number
|
||||
lineNumbers.add(parseInt(highlightRule));
|
||||
}
|
||||
return [];
|
||||
}).flat();
|
||||
});
|
||||
return {
|
||||
lineNumbers: [...lineNumbers],
|
||||
plainText: [...plainText],
|
||||
regularExpressions: [...regularExpressions],
|
||||
};
|
||||
}
|
||||
export function isLanguageExcluded(language: string, excludedLanguagesString: string): boolean {
|
||||
return parseRegexExcludedLanguages(excludedLanguagesString).some(regexExcludedLanguage => {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export function createCodeMirrorExtensions(settings: CodeblockCustomizerSettings
|
|||
if (excludedCodeblock)
|
||||
return;
|
||||
if (node.type.name.includes("HyperMD-codeblock")) {
|
||||
decorations.push(Decoration.line({attributes: {class: (settings.specialLanguages.includes(codeblockParameters.language)||startLine||endLine?'codeblock-customizer-line':getLineClass(codeblockParameters,lineNumber).join(' '))+([''].concat(settings.specialLanguages).includes(codeblockParameters.language)?'':` language-${codeblockParameters.language}`)}}).range(node.from))
|
||||
decorations.push(Decoration.line({attributes: {class: (settings.specialLanguages.includes(codeblockParameters.language)||startLine||endLine?'codeblock-customizer-line':getLineClass(codeblockParameters,lineNumber,line.text).join(' '))+([''].concat(settings.specialLanguages).includes(codeblockParameters.language)?'':` language-${codeblockParameters.language}`)}}).range(node.from))
|
||||
decorations.push(Decoration.line({}).range(node.from));
|
||||
decorations.push(Decoration.widget({widget: new LineNumberWidget(lineNumber,codeblockParameters,startLine||endLine)}).range(node.from))
|
||||
lineNumber++;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ async function remakeCodeblock(codeblockCodeElement: HTMLElement, codeblockPreEl
|
|||
codeblockParameters.lineNumbers.offset = codePreviewParams.start - 1;
|
||||
codeblockParameters.lineNumbers.alwaysEnabled = codePreviewParams.lineNumber;
|
||||
}
|
||||
codeblockParameters.highlights.default = [...new Set(codeblockParameters.highlights.default.concat(Array.from(plugins['obsidian-code-preview'].analyzeHighLightLines(codePreviewParams.lines,codePreviewParams.highlight),([num,_])=>(num))))];
|
||||
codeblockParameters.highlights.default.lineNumbers = [...new Set(codeblockParameters.highlights.default.lineNumbers.concat(Array.from(plugins['obsidian-code-preview'].analyzeHighLightLines(codePreviewParams.lines,codePreviewParams.highlight),([num,_])=>(num))))];
|
||||
if (codeblockParameters.title === '')
|
||||
codeblockParameters.title = codePreviewParams.filePath;
|
||||
codeblockParameters.language = codePreviewParams.language;
|
||||
|
|
@ -112,7 +112,7 @@ function decorateCodeblock(codeblockCodeElement: HTMLElement, codeblockPreElemen
|
|||
return;
|
||||
const lineNumber = index + 1;
|
||||
const lineWrapper = document.createElement("div");
|
||||
getLineClass(codeblockParameters,lineNumber).forEach((lineClass) => {
|
||||
getLineClass(codeblockParameters,lineNumber,line).forEach((lineClass) => {
|
||||
lineWrapper.classList.add(lineClass);
|
||||
});
|
||||
codeblockCodeElement.appendChild(lineWrapper);
|
||||
|
|
|
|||
Loading…
Reference in a new issue