diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 4c8f25d..cf1e7bf 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -1,10 +1,16 @@ { + "command": { + "active": "Add thesaurus tags to active file" + }, "error": { "csv": { "columns": "The columns doesn't correspond with the settings.", "header": "You can have only two column in your thesaurus. You have: {{- len}} columns.", "malformed": "Your CSV is malformed: {{- len}} columns found.", "separator": "The specified separator is invalid. You seems to use \"{{- sep}}\" as separator." + }, + "file": { + "empty": "The file {{- file}} is empty!" } }, "settings": { @@ -19,11 +25,11 @@ }, "title": "Column title" }, - "excludedPath": { - "desc": "Exclude files in theses paths when using the global command. ", + "includedPaths": { + "desc": "Includes files from its paths when using the global command.", "regex": "Regex are supported.", "separate": "Separate paths with coma, semicolon, spaces or newlines.", - "title": "Excluded path" + "title": "Included paths" }, "separator": { "desc": "CSV column separator.", @@ -38,5 +44,9 @@ "title": "Thesaurus", "verify": "Verify validity of the file" } + }, + "success": { + "none": "No tag to add!", + "title": "The tags has been added:" } } \ No newline at end of file diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index d1c909d..0663e69 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1,10 +1,16 @@ { + "command": { + "active": "Ajouter les tags du thésaurus au fichier actif" + }, "error": { "csv": { "columns": "Les colonnes du CSV fourni ne correspondent pas avec les colonnes des paramètres.", "header": "Vous ne pouvez avoir que deux colonnes dans votre thésaurus. Vous avez {{- len}} colonnes.", "malformed": "Votre CSV est mal formé : {{- len}} colonnes trouvées.", "separator": "Le séparateur spécifié n'est pas le bon. Vous semblez utiliser \"{{- sep}}\" comme séparateur." + }, + "file": { + "empty": "Le fichier {{- file}} est vide !" } }, "settings": { @@ -19,11 +25,11 @@ }, "title": "Titre des colonnes" }, - "excludedPath": { - "desc": "Exclus les fichiers depuis ses chemins lors d'utilisation de la commande globale.", + "includedPaths": { + "desc": "Inclus les fichiers depuis ses chemins lors d'utilisation de la commande globale.", "regex": "Les expressions régulières sont supportées.", - "separate": "Séparer les chemins par une virgule, point virgule, un espace ou un retour à la ligne.", - "title": "Fichier exclus" + "separate": "Séparer les chemins par une virgule, point virgule ou un retour à la ligne.", + "title": "Chemins inclus" }, "separator": { "desc": "Séparateur des colonnes du fichier CSV.", @@ -38,5 +44,9 @@ "title": "Thesaurus", "verify": "Verifier la validité du fichier" } + }, + "success": { + "none": "Aucun tag à ajouter !", + "title": "Les tags suivants ont bien été ajoutés :" } } \ No newline at end of file diff --git a/src/interfaces.ts b/src/interfaces.ts index ff59884..1324aef 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -2,7 +2,7 @@ import type { TFunction } from "i18next"; export interface MyThesaurusSettings { thesaurusPath: string; - excludedPath: string[]; + includedPaths: string[]; separator: Separator; columns: ColumnName; } @@ -19,7 +19,7 @@ export type Translation = TFunction<"translation", undefined>; export const DEFAULT_SETTINGS: MyThesaurusSettings = { thesaurusPath: "", - excludedPath: [], + includedPaths: [], separator: ";", columns: { term: "term", diff --git a/src/main.ts b/src/main.ts index 29fa9c5..098871f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,14 +1,55 @@ import i18next from "i18next"; -import { Plugin } from "obsidian"; +import { Notice, Plugin, type TFile, sanitizeHTMLToDom } from "obsidian"; import { resources, translationLanguage } from "./i18n"; import { DEFAULT_SETTINGS, type MyThesaurusSettings } from "./interfaces"; import { MyThesaurusSettingTab } from "./settings"; import "uniformize"; +import { getTags, getThesaurus } from "./utils"; export default class MyThesaurus extends Plugin { settings!: MyThesaurusSettings; + async addTagsToNote(tags: string[], file: TFile) { + const currentTags = this.app.metadataCache.getFileCache(file)?.tags || []; + const newTags = [...new Set([...currentTags, ...tags])]; + if (newTags.length === 0) return; + await this.app.fileManager.processFrontMatter(file, (frontmatter) => { + frontmatter.tags = newTags; + }); + } + + async parseFile(file: TFile) { + const contents = await this.app.vault.read(file); + const thesaurusFile = this.app.vault.getAbstractFileByPath( + this.settings.thesaurusPath + ) as TFile; + const thesaurusContents = await this.app.vault.read(thesaurusFile); + if (contents.length === 0) { + new Notice(i18next.t("error.file.empty", { file: file.name })); + } + try { + const thesaurus = getThesaurus( + thesaurusContents, + this.settings.separator, + i18next.t, + this.settings.columns + ); + const tags = getTags(contents, thesaurus); + if (tags.length > 0) { + await this.addTagsToNote(tags, file); + const successMsg = sanitizeHTMLToDom( + `

${i18next.t("success.title")}

` + ); + new Notice(successMsg); + } else { + new Notice(i18next.t("success.none")); + } + } catch (error) { + new Notice((error as Error).message); + } + } + async onload() { console.log(`[${this.manifest.name}] Loaded`); await this.loadSettings(); @@ -21,6 +62,20 @@ export default class MyThesaurus extends Plugin { returnEmptyString: false, }); this.addSettingTab(new MyThesaurusSettingTab(this.app, this)); + this.addCommand({ + id: "parse-file", + name: i18next.t("command.active"), + checkCallback: (checking) => { + const file = this.app.workspace.getActiveFile(); + if (file && file.extension == "md") { + if (!checking) { + this.parseFile(file); + } + return true; + } + return false; + }, + }); } onunload() { diff --git a/src/settings.ts b/src/settings.ts index 39f190d..94427a5 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -10,7 +10,7 @@ import { import type { MyThesaurusSettings, Separator } from "./interfaces"; import type MyThesaurus from "./main"; import { FileSuggester } from "./searchFile"; -import { verifCSV } from "./utils"; +import { getThesaurus } from "./utils"; export class MyThesaurusSettingTab extends PluginSettingTab { plugin: MyThesaurus; @@ -91,7 +91,7 @@ export class MyThesaurusSettingTab extends PluginSettingTab { } const content = await this.app.vault.read(file); try { - verifCSV( + getThesaurus( content, this.settings.separator, i18next.t, @@ -110,16 +110,19 @@ export class MyThesaurusSettingTab extends PluginSettingTab { }); new Setting(containerEl) - .setName(i18next.t("settings.excludedPath.title")) + .setName(i18next.t("settings.includedPaths.title")) .setHeading() .setDesc( sanitizeHTMLToDom( - `${i18next.t("settings.excludedPath.desc")}
${i18next.t("settings.excludedPath.separate")}
${i18next.t("settings.excludedPath.regex")}` + `${i18next.t("settings.includedPaths.desc")}
${i18next.t("settings.includedPaths.separate")}
${i18next.t("settings.includedPaths.regex")}` ) ) .addTextArea((text) => { - text.setValue(this.settings.excludedPath.join("\n")).onChange(async (value) => { - this.settings.excludedPath = value.split(/[\n,; ]+/).map((path) => path.trim()); + text.setValue(this.settings.includedPaths.join("\n")).onChange(async (value) => { + this.settings.includedPaths = value + .split(/[\n,;]+/) + .map((path) => path.trim()) + .filter((path) => path.length > 0); await this.plugin.saveSettings(); }); }); diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..8fdcc47 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,4 @@ +import { getThesaurus } from "./parse_csv"; +import { getTags } from "./parse_file"; + +export { getThesaurus, getTags }; diff --git a/src/utils.ts b/src/utils/parse_csv.ts similarity index 95% rename from src/utils.ts rename to src/utils/parse_csv.ts index 7808b99..8576ced 100644 --- a/src/utils.ts +++ b/src/utils/parse_csv.ts @@ -1,11 +1,11 @@ -import type { ColumnName, Separator, Thesaurus, Translation } from "./interfaces"; +import type { ColumnName, Separator, Thesaurus, Translation } from "../interfaces"; function verifySeparator(header: string, sep: Separator): boolean { return header.includes(sep); } function searchSeparator(header: string): Separator { - return header.match(/[,;\t|]/)?.[0] as Separator; + return header.match(/[,;\t\|]/)?.[0] as Separator; } function getColumn( @@ -33,7 +33,7 @@ function getColumn( return { indexKey, indexSynonyms }; } -export function verifCSV( +export function getThesaurus( fileContent: string, separator: Separator, ln: Translation, diff --git a/src/utils/parse_file.ts b/src/utils/parse_file.ts new file mode 100644 index 0000000..ba0e037 --- /dev/null +++ b/src/utils/parse_file.ts @@ -0,0 +1,14 @@ +import type { Thesaurus } from "../interfaces"; + +export function getTags(content: string, thesaurus: Thesaurus) { + const tagsToAdd: string[] = []; + + for (const tags of Object.keys(thesaurus)) { + const synonyms = thesaurus[tags]; + const regex = new RegExp(`\\b(${[...synonyms].join("|")})\\b`, "gi"); + if (regex.test(content)) { + tagsToAdd.push(tags); + } + } + return tagsToAdd; +}