mirror of
https://github.com/gosticks/flashcards-obsidian.git
synced 2025-10-16 12:05:33 +00:00
Add support for code syntax highlight
This commit is contained in:
parent
e5de6b32aa
commit
7dc7915c1f
@ -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?
|
||||||
|
|
||||||
|
|||||||
2
main.ts
2
main.ts
@ -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
@ -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 : ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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"]
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -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"],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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 {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
|
|||||||
@ -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": [
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user