Add support for code syntax highlight

This commit is contained in:
reuseman 2020-12-12 12:07:01 +01:00
parent e5de6b32aa
commit 7dc7915c1f
13 changed files with 127 additions and 32 deletions

View File

@ -14,7 +14,8 @@ Anki integration for [Obsidian](https://obsidian.md/).
🏷️ Global and local **tags** 🏷️ Global and local **tags**
🔢 Support for **LaTeX** 🔢 Support for **LaTeX**
🖼️ Support for **images** 🖼️ Support for **images**
🔗 **Obsidian URI** support 🔗 Support for **Obsidian URI**
📟 Support for **Code syntax highlight**
## How it works? ## How it works?

View File

@ -56,7 +56,7 @@ export default class ObsidianFlashcard extends Plugin {
} }
private getDefaultSettings(): ISettings { private getDefaultSettings(): ISettings {
return { contextAwareMode: true, contextSeparator: " > ", deck: "Default", flashcardsTag: "card" } return { contextAwareMode: true, codeHighlightSupport: true, contextSeparator: " > ", deck: "Default", flashcardsTag: "card" }
} }
private generateCards(activeFile: TFile) { private generateCards(activeFile: TFile) {

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,4 @@
import { codeDeckExtension } from 'src/constants'
import { arraysEqual } from 'src/utils' import { arraysEqual } from 'src/utils'
export abstract class Card { export abstract class Card {
@ -12,9 +13,11 @@ export abstract class Card {
mediaNames: string[] mediaNames: string[]
mediaBase64Encoded: string[] mediaBase64Encoded: string[]
oldTags: string[] oldTags: string[]
containsCode: boolean
modelName: string
// TODO set "obsidian as optional in the settings", this means that the tag should be outside // TODO set "obsidian as optional in the settings", this means that the tag should be outside
constructor(id: number, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[], inserted: boolean, mediaNames: string[]) { constructor(id: number, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[], inserted: boolean, mediaNames: string[], containsCode: boolean = false) {
this.id = id this.id = id
this.deckName = deckName this.deckName = deckName
this.initialContent = initialContent this.initialContent = initialContent
@ -27,6 +30,8 @@ export abstract class Card {
this.mediaNames = mediaNames this.mediaNames = mediaNames
this.mediaBase64Encoded = [] this.mediaBase64Encoded = []
this.oldTags = [] this.oldTags = []
this.containsCode = containsCode
this.modelName = ""
} }
abstract toString(): string abstract toString(): string
@ -35,6 +40,11 @@ export abstract class Card {
abstract getIdFormat(): string abstract getIdFormat(): string
match(card: any): boolean { match(card: any): boolean {
// TODO not supported currently
// if (this.modelName !== card.modelName) {
// return false
// }
let fields = Object.entries(card.fields) let fields = Object.entries(card.fields)
for (let field of fields) { for (let field of fields) {
let fieldName = field[0] let fieldName = field[0]
@ -45,4 +55,8 @@ export abstract class Card {
return arraysEqual(card.tags, this.tags) return arraysEqual(card.tags, this.tags)
} }
getCodeDeckNameExtension() {
return this.containsCode ? codeDeckExtension : ""
}
} }

View File

@ -1,15 +1,16 @@
import { Card } from "src/entities/card"; import { Card } from "src/entities/card";
export class Flashcard extends Card { export class Flashcard extends Card {
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[]) { constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames) super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
let codeExtension = this.getCodeDeckNameExtension()
this.modelName = this.reversed ? `Obsidian-basic-reversed${codeExtension}` : `Obsidian-basic${codeExtension}`
} }
public getCard(update: boolean = false): object { public getCard(update: boolean = false): object {
let modelName = this.reversed ? "Obsidian-basic-reversed" : "Obsidian-basic"
let card: any = { let card: any = {
"deckName": this.deckName, "deckName": this.deckName,
"modelName": modelName, "modelName": this.modelName,
"fields": { "fields": {
"Front": this.fields["Front"], "Front": this.fields["Front"],
"Back": this.fields["Back"] "Back": this.fields["Back"]

View File

@ -1,15 +1,16 @@
import { Card } from "src/entities/card"; import { Card } from "src/entities/card";
export class Inlinecard extends Card { export class Inlinecard extends Card {
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[]) { constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames) super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
let codeExtension = this.getCodeDeckNameExtension()
this.modelName = `Obsidian-basic${codeExtension}`
} }
public getCard(update: boolean = false): object { public getCard(update: boolean = false): object {
let modelName = "Obsidian-basic"
let card: any = { let card: any = {
"deckName": this.deckName, "deckName": this.deckName,
"modelName": modelName, "modelName": this.modelName,
"fields": { "fields": {
"Front": this.fields["Front"], "Front": this.fields["Front"],
"Back": this.fields["Back"] "Back": this.fields["Back"]

View File

@ -1,15 +1,17 @@
import { Card } from "src/entities/card"; import { Card } from "src/entities/card";
export class Spacedcard extends Card { export class Spacedcard extends Card {
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[]) { constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames) super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
let codeExtension = this.getCodeDeckNameExtension()
this.modelName = `Obsidian-spaced${codeExtension}`
} }
public getCard(update: boolean = false): object { public getCard(update: boolean = false): object {
let modelName = "Obsidian-spaced"
let card: any = { let card: any = {
"deckName": this.deckName, "deckName": this.deckName,
"modelName": modelName, "modelName": this.modelName,
"fields": { "fields": {
"Prompt": this.fields["Prompt"], "Prompt": this.fields["Prompt"],
}, },

View File

@ -32,6 +32,18 @@ export class SettingsTab extends PluginSettingTab {
}) })
) )
new Setting(containerEl)
.setName("Code highlight support")
.setDesc("Add highlight of the code in Anki.")
.addToggle((toggle) =>
toggle
.setValue(plugin.settings.codeHighlightSupport)
.onChange((value) => {
plugin.settings.codeHighlightSupport = value
plugin.saveData(plugin.settings)
})
)
new Setting(containerEl) new Setting(containerEl)
.setName("Default deck") .setName("Default deck")
.setDesc("The name of the default deck where the cards will be added when not specified.") .setDesc("The name of the default deck where the cards will be added when not specified.")
@ -64,5 +76,6 @@ export class SettingsTab extends PluginSettingTab {
}) })
}) })
} }
} }

View File

@ -4,6 +4,7 @@ export class Regex {
headingsRegex: RegExp headingsRegex: RegExp
wikiImageLinks: RegExp wikiImageLinks: RegExp
markdownImageLinks: RegExp markdownImageLinks: RegExp
codeBlock: RegExp
cardsDeckLine: RegExp cardsDeckLine: RegExp
cardsToDelete: RegExp cardsToDelete: RegExp
flashscardsWithTag: RegExp flashscardsWithTag: RegExp
@ -21,6 +22,7 @@ export class Regex {
// Supported images https://publish.obsidian.md/help/How+to/Embed+files // Supported images https://publish.obsidian.md/help/How+to/Embed+files
this.wikiImageLinks = /!\[\[(.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\]\]/gim this.wikiImageLinks = /!\[\[(.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\]\]/gim
this.markdownImageLinks = /!\[\]\((.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\)/gim this.markdownImageLinks = /!\[\]\((.*\.(?:png|jpg|jpeg|gif|bmp|svg|tiff))\)/gim
this.codeBlock = /<code\b[^>]*>(.*?)<\/code>/gims
this.cardsDeckLine = /cards-deck: [\w\d]+/gi this.cardsDeckLine = /cards-deck: [\w\d]+/gi
this.cardsToDelete = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm this.cardsToDelete = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm

View File

@ -1,13 +1,24 @@
import { Card } from 'src/entities/card'; import { Card } from 'src/entities/card';
import { codeScript, highlightjsBase64, hihglightjsInitBase64, highlightCssBase64, codeDeckExtension } from 'src/constants'
export class Anki { export class Anki {
public async createModels() {
public async createModels(codeHighlightSupport: boolean) {
let css = ".card {\r\n font-family: arial;\r\n font-size: 20px;\r\n text-align: center;\r\n color: black;\r\n background-color: white;\r\n}\r\n\r\n.tag::before {\r\n\tcontent: \"#\";\r\n}\r\n\r\n.tag {\r\n color: white;\r\n background-color: #9F2BFF;\r\n border: none;\r\n font-size: 11px;\r\n font-weight: bold;\r\n padding: 1px 8px;\r\n margin: 0px 3px;\r\n text-align: center;\r\n text-decoration: none;\r\n cursor: pointer;\r\n border-radius: 14px;\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n" let css = ".card {\r\n font-family: arial;\r\n font-size: 20px;\r\n text-align: center;\r\n color: black;\r\n background-color: white;\r\n}\r\n\r\n.tag::before {\r\n\tcontent: \"#\";\r\n}\r\n\r\n.tag {\r\n color: white;\r\n background-color: #9F2BFF;\r\n border: none;\r\n font-size: 11px;\r\n font-weight: bold;\r\n padding: 1px 8px;\r\n margin: 0px 3px;\r\n text-align: center;\r\n text-decoration: none;\r\n cursor: pointer;\r\n border-radius: 14px;\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n"
let front = "{{Front}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>" let front = `{{Front}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>`
let frontReversed = "{{Back}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>" let frontReversed = `{{Back}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>`
let prompt = "{{Prompt}}\r\n<p class=\"tags\">🧠spaced {{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>" let prompt = `{{Prompt}}\r\n<p class=\"tags\">🧠spaced {{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>`
let models = this.getModels(front, frontReversed, prompt, css) let models = this.getModels(front, frontReversed, prompt, css)
if (codeHighlightSupport) {
css = ".card {\r\n font-family: arial;\r\n font-size: 20px;\r\n text-align: center;\r\n color: black;\r\n background-color: white;\r\n}\r\n\r\n.tag::before {\r\n\tcontent: \"#\";\r\n}\r\n\r\n.tag {\r\n color: white;\r\n background-color: #9F2BFF;\r\n border: none;\r\n font-size: 11px;\r\n font-weight: bold;\r\n padding: 1px 8px;\r\n margin: 0px 3px;\r\n text-align: center;\r\n text-decoration: none;\r\n cursor: pointer;\r\n border-radius: 14px;\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n"
front = `{{Front}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>\r\n${codeScript}\r\n`
frontReversed = `{{Back}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>\r\n${codeScript}\r\n`
prompt = `{{Prompt}}\r\n<p class=\"tags\">🧠spaced {{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>\r\n${codeScript}\r\n`
models = models.concat(this.getModels(front, frontReversed, prompt, css, codeDeckExtension))
}
return this.invoke("multi", 6, { "actions": models }) return this.invoke("multi", 6, { "actions": models })
} }
@ -34,6 +45,37 @@ export class Anki {
} }
} }
public async storeCodeHighlightMedias() {
let fileExists = await this.invoke(
"retrieveMediaFile",
6,
{
"filename": "_highlightInit.js"
})
if (!fileExists) {
let highlightjs = {
"action": "storeMediaFile", "params": {
"filename": "_highlight.js",
"data": highlightjsBase64
}
}
let highlightjsInit = {
"action": "storeMediaFile", "params": {
"filename": "_highlightInit.js",
"data": hihglightjsInitBase64
}
}
let highlightjcss = {
"action": "storeMediaFile", "params": {
"filename": "_highlight.css",
"data": highlightCssBase64
}
}
return this.invoke("multi", 6, { "actions": [highlightjs, highlightjsInit, highlightjcss] })
}
}
public async addCards(cards: Card[]): Promise<number[]> { public async addCards(cards: Card[]): Promise<number[]> {
let notes: any = [] let notes: any = []
@ -121,7 +163,7 @@ export class Anki {
return actions return actions
} }
private invoke(action: string, version: number, params = {}): any { private invoke(action: string, version: number = 6, params = {}): any {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.addEventListener('error', () => reject('failed to issue request')); xhr.addEventListener('error', () => reject('failed to issue request'));
@ -151,11 +193,11 @@ export class Anki {
}); });
} }
private getModels(front: string, frontReversed: string, prompt: string, css: string): object[] { private getModels(front: string, frontReversed: string, prompt: string, css: string, extension: string = ""): object[] {
let obsidianBasic = { let obsidianBasic = {
"action": "createModel", "action": "createModel",
"params": { "params": {
"modelName": "Obsidian-basic", "modelName": `Obsidian-basic${extension}`,
"inOrderFields": ["Front", "Back"], "inOrderFields": ["Front", "Back"],
"css": css, "css": css,
"cardTemplates": [ "cardTemplates": [
@ -171,7 +213,7 @@ export class Anki {
let obsidianBasicReversed = { let obsidianBasicReversed = {
"action": "createModel", "action": "createModel",
"params": { "params": {
"modelName": "Obsidian-basic-reversed", "modelName": `Obsidian-basic-reversed${extension}`,
"inOrderFields": ["Front", "Back"], "inOrderFields": ["Front", "Back"],
"css": css, "css": css,
"cardTemplates": [ "cardTemplates": [
@ -192,7 +234,7 @@ export class Anki {
let obsidianSpaced = { let obsidianSpaced = {
"action": "createModel", "action": "createModel",
"params": { "params": {
"modelName": "Obsidian-spaced", "modelName": `Obsidian-spaced${extension}`,
"inOrderFields": ["Prompt"], "inOrderFields": ["Prompt"],
"css": css, "css": css,
"cardTemplates": [ "cardTemplates": [

View File

@ -3,7 +3,6 @@ import { App, FileSystemAdapter, FrontMatterCache, Notice, parseFrontMatterEntry
import { Parser } from 'src/services/parser' import { Parser } from 'src/services/parser'
import { ISettings } from 'src/settings' import { ISettings } from 'src/settings'
import { Card } from 'src/entities/card' import { Card } from 'src/entities/card'
import { Flashcard } from 'src/entities/flashcard'
import { arrayBufferToBase64 } from "src/utils" import { arrayBufferToBase64 } from "src/utils"
import { Regex } from 'src/regex' import { Regex } from 'src/regex'
import { noticeTimeout } from 'src/constants' import { noticeTimeout } from 'src/constants'
@ -57,7 +56,8 @@ export class CardsService {
} }
try { try {
await this.anki.createModels() await this.anki.storeCodeHighlightMedias()
await this.anki.createModels(this.settings.codeHighlightSupport)
await this.anki.createDeck(deckName) await this.anki.createDeck(deckName)
this.file = await this.app.vault.read(activeFile) this.file = await this.app.vault.read(activeFile)
// TODO with empty check that does not call ankiCards line // TODO with empty check that does not call ankiCards line

View File

@ -17,6 +17,7 @@ export class Parser {
this.htmlConverter.setOption("simplifiedAutoLink", true) this.htmlConverter.setOption("simplifiedAutoLink", true)
this.htmlConverter.setOption("tables", true) this.htmlConverter.setOption("tables", true)
this.htmlConverter.setOption("tasks", true) this.htmlConverter.setOption("tasks", true)
this.htmlConverter.setOption("ghCodeBlocks", true)
} }
public generateFlashcards(file: string, deck: string, vault: string, globalTags: string[] = []): Flashcard[] { public generateFlashcards(file: string, deck: string, vault: string, globalTags: string[] = []): Flashcard[] {
@ -106,8 +107,9 @@ export class Parser {
let id: number = match[5] ? Number(match[5]) : -1 let id: number = match[5] ? Number(match[5]) : -1
let inserted: boolean = match[5] ? true : false let inserted: boolean = match[5] ? true : false
let fields = { "Prompt": prompt } let fields = { "Prompt": prompt }
let containsCode = this.containsCode([prompt])
let card = new Spacedcard(id, deck, originalPrompt, fields, reversed, endingLine, tags, inserted, imagesMedia) let card = new Spacedcard(id, deck, originalPrompt, fields, reversed, endingLine, tags, inserted, imagesMedia, containsCode)
cards.push(card) cards.push(card)
} }
@ -141,8 +143,9 @@ export class Parser {
let id: number = match[5] ? Number(match[5]) : -1 let id: number = match[5] ? Number(match[5]) : -1
let inserted: boolean = match[5] ? true : false let inserted: boolean = match[5] ? true : false
let fields = { "Front": question, "Back": answer } let fields = { "Front": question, "Back": answer }
let containsCode = this.containsCode([question, answer])
let card = new Inlinecard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, imagesMedia) let card = new Inlinecard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, imagesMedia, containsCode)
cards.push(card) cards.push(card)
} }
@ -173,21 +176,31 @@ export class Parser {
let id: number = match[6] ? Number(match[6]) : -1 let id: number = match[6] ? Number(match[6]) : -1
let inserted: boolean = match[6] ? true : false let inserted: boolean = match[6] ? true : false
let fields = { "Front": question, "Back": answer } let fields = { "Front": question, "Back": answer }
let containsCode = this.containsCode([question, answer])
let card = new Flashcard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, imagesMedia) let card = new Flashcard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, imagesMedia, containsCode)
cards.push(card) cards.push(card)
} }
return cards return cards
} }
public containsCode(str: string[]): boolean {
for (let s of str) {
if (s.match(this.regex.codeBlock)) {
return true
}
}
return false
}
public getCardsToDelete(file: string): number[] { public getCardsToDelete(file: string): number[] {
// Find block IDs with no content above it // Find block IDs with no content above it
return [...file.matchAll(this.regex.cardsToDelete)].map((match) => { return Number(match[1]) }) return [...file.matchAll(this.regex.cardsToDelete)].map((match) => { return Number(match[1]) })
} }
private parseLine(str: string, vaultName: string) { private parseLine(str: string, vaultName: string) {
return this.mathToAnki(this.substituteObsidianLinks(this.substituteImageLinks(str), vaultName)) return this.mathToAnki(this.htmlConverter.makeHtml(this.substituteObsidianLinks(this.substituteImageLinks(str), vaultName)))
} }
private getImageLinks(str: string) { private getImageLinks(str: string) {

View File

@ -1,5 +1,6 @@
export interface ISettings { export interface ISettings {
contextAwareMode: boolean contextAwareMode: boolean
codeHighlightSupport: boolean
contextSeparator: string contextSeparator: string
deck: string deck: string
flashcardsTag: string flashcardsTag: string