From b2ef959464a16a2a6cfccd6d32d96132dc289d66 Mon Sep 17 00:00:00 2001 From: pseudometa <73286100+chrisgrieser@users.noreply.github.com> Date: Fri, 17 Feb 2023 11:40:51 +0100 Subject: [PATCH] feat: add footnote & pandoc citation count --- README.md | 7 +-- src/settings/StatusBarSettings.svelte | 16 ++++++ src/stats/Stats.ts | 6 ++ src/stats/StatsManager.ts | 82 ++++++++++++++++++++++++++- src/status/StatusBar.ts | 2 + src/utils/StatUtils.ts | 17 ++++++ 6 files changed, 125 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index be6d2c7..a9c2f0a 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,9 @@ This plugin is the same as the built-in **Word Count** plugin, except when you s - Allows you to store statistics about your vault. - Works with all languages. - Can display a variety of different stats. Including: - - Words, Characters and Sentences in current file. - - Total Words, Characters and Sentences in vault. - - Words, Characters and Sentences typed today. - - Total Files in vault. + - Words, Characters, Sentences, Footnotes, and Pandoc Citations in current file. + - Total Words, Characters, Sentences, Footnotes, Pandoc Citations, and Files in vault. + - Words, Characters, Sentences, Footnotes, and Pandoc Citations typed today. - Highly Customizable status bar that can be adapted to your needs. ## Contributors diff --git a/src/settings/StatusBarSettings.svelte b/src/settings/StatusBarSettings.svelte index 9e2843a..92665b0 100644 --- a/src/settings/StatusBarSettings.svelte +++ b/src/settings/StatusBarSettings.svelte @@ -18,6 +18,10 @@ return "Chars in Note" case MetricCounter.sentences: return "Sentences in Note" + case MetricCounter.footnotes: + return "Footnotes in Note" + case MetricCounter.citations: + return "Pandoc Citations in Note" case MetricCounter.files: return "Total Notes" } @@ -29,6 +33,10 @@ return "Daily Chars" case MetricCounter.sentences: return "Daily Sentences" + case MetricCounter.footnotes: + return "Daily Footnotes" + case MetricCounter.citations: + return "Daily Citations" case MetricCounter.files: return "Total Notes" } @@ -40,6 +48,10 @@ return "Total Chars" case MetricCounter.sentences: return "Total Sentences" + case MetricCounter.citations: + return "Total Pandoc Citations" + case MetricCounter.footnotes: + return "Total Footnotes" case MetricCounter.files: return "Total Notes" } @@ -181,6 +193,8 @@ + + @@ -348,6 +362,8 @@ + + diff --git a/src/stats/Stats.ts b/src/stats/Stats.ts index 5209bb3..f79a973 100644 --- a/src/stats/Stats.ts +++ b/src/stats/Stats.ts @@ -10,14 +10,20 @@ export interface Day { characters: number; sentences: number; files: number; + footnotes: number; + citations: number; totalWords: number; totalCharacters: number; totalSentences: number; + totalFootnotes: number; + totalCitations: number; } export type ModifiedFiles = Record; export interface FileStat { + footnotes: CountDiff; + citations: CountDiff; words: CountDiff; characters: CountDiff; sentences: CountDiff; diff --git a/src/stats/StatsManager.ts b/src/stats/StatsManager.ts index d96db15..f5fd1f4 100644 --- a/src/stats/StatsManager.ts +++ b/src/stats/StatsManager.ts @@ -6,6 +6,8 @@ import { getCharacterCount, getSentenceCount, getWordCount, + getCitationCount, + getFootnoteCount, } from "../utils/StatUtils"; export default class StatsManager { @@ -76,15 +78,21 @@ export default class StatsManager { const totalWords = await this.calcTotalWords(); const totalCharacters = await this.calcTotalCharacters(); const totalSentences = await this.calcTotalSentences(); + const totalFootnotes = await this.calcTotalFootnotes(); + const totalCitations = await this.calcTotalCitations(); const newDay: Day = { words: 0, characters: 0, sentences: 0, files: 0, + footnotes: 0, + citations: 0, totalWords: totalWords, totalCharacters: totalCharacters, totalSentences: totalSentences, + totalFootnotes: totalFootnotes, + totalCitations: totalCitations, }; this.vaultStats.modifiedFiles = {}; @@ -97,6 +105,8 @@ export default class StatsManager { const currentWords = getWordCount(text); const currentCharacters = getCharacterCount(text); const currentSentences = getSentenceCount(text); + const currentCitations = getCitationCount(text); + const currentFootnotes = getFootnoteCount(text); if ( this.vaultStats.history.hasOwnProperty(this.today) && this.today === moment().format("YYYY-MM-DD") @@ -110,9 +120,15 @@ export default class StatsManager { currentCharacters - modFiles[fileName].characters.current; this.vaultStats.history[this.today].totalSentences += currentSentences - modFiles[fileName].sentences.current; + this.vaultStats.history[this.today].totalFootnotes += + currentSentences - modFiles[fileName].footnotes.current; + this.vaultStats.history[this.today].totalCitations += + currentSentences - modFiles[fileName].citations.current; modFiles[fileName].words.current = currentWords; modFiles[fileName].characters.current = currentCharacters; modFiles[fileName].sentences.current = currentSentences; + modFiles[fileName].footnotes.current = currentSentences; + modFiles[fileName].citations.current = currentSentences; } else { modFiles[fileName] = { words: { @@ -127,6 +143,14 @@ export default class StatsManager { initial: currentSentences, current: currentSentences, }, + footnotes: { + initial: currentFootnotes, + current: currentFootnotes, + }, + citations: { + initial: currentCitations, + current: currentCitations, + }, }; } @@ -145,10 +169,22 @@ export default class StatsManager { Math.max(0, counts.sentences.current - counts.sentences.initial) ) .reduce((a, b) => a + b, 0); + const footnotes = Object.values(modFiles) + .map((counts) => + Math.max(0, counts.footnotes.current - counts.footnotes.initial) + ) + .reduce((a, b) => a + b, 0); + const citations = Object.values(modFiles) + .map((counts) => + Math.max(0, counts.citations.current - counts.citations.initial) + ) + .reduce((a, b) => a + b, 0); this.vaultStats.history[this.today].words = words; this.vaultStats.history[this.today].characters = characters; this.vaultStats.history[this.today].sentences = sentences; + this.vaultStats.history[this.today].footnotes = footnotes; + this.vaultStats.history[this.today].citations = citations; this.vaultStats.history[this.today].files = this.getTotalFiles(); await this.update(); @@ -167,6 +203,8 @@ export default class StatsManager { todayHist.totalWords = await this.calcTotalWords(); todayHist.totalCharacters = await this.calcTotalCharacters(); todayHist.totalSentences = await this.calcTotalSentences(); + todayHist.totalFootnotes = await this.calcTotalFootnotes(); + todayHist.totalCitations = await this.calcTotalCitations(); this.update(); } else { this.updateToday(); @@ -208,10 +246,33 @@ export default class StatsManager { sentence += getSentenceCount(await this.vault.cachedRead(file)); } } - return sentence; } + private async calcTotalFootnotes(): Promise { + let footnotes = 0; + const files = this.vault.getFiles(); + for (const i in files) { + const file = files[i]; + if (file.extension === "md") { + footnotes += getFootnoteCount(await this.vault.cachedRead(file)); + } + } + return footnotes; + } + + private async calcTotalCitations(): Promise { + let citations = 0; + const files = this.vault.getFiles(); + for (const i in files) { + const file = files[i]; + if (file.extension === "md") { + citations += getCitationCount(await this.vault.cachedRead(file)); + } + } + return citations; + } + public getDailyWords(): number { return this.vaultStats.history[this.today].words; } @@ -224,6 +285,14 @@ export default class StatsManager { return this.vaultStats.history[this.today].sentences; } + public getDailyFootnotes(): number { + return this.vaultStats.history[this.today].footnotes; + } + + public getDailyCitations(): number { + return this.vaultStats.history[this.today].citations; + } + public getTotalFiles(): number { return this.vault.getMarkdownFiles().length; } @@ -242,4 +311,15 @@ export default class StatsManager { if (!this.vaultStats) return await this.calcTotalSentences(); return this.vaultStats.history[this.today].totalSentences; } + + public async getTotalFootnotes(): Promise { + if (!this.vaultStats) return await this.calcTotalFootnotes(); + return this.vaultStats.history[this.today].totalFootnotes; + } + + public async getTotalCitations(): Promise { + if (!this.vaultStats) return await this.calcTotalCitations(); + return this.vaultStats.history[this.today].totalCitations; + } + } diff --git a/src/status/StatusBar.ts b/src/status/StatusBar.ts index 7d40bfc..4e1aabb 100644 --- a/src/status/StatusBar.ts +++ b/src/status/StatusBar.ts @@ -4,6 +4,8 @@ import { getWordCount, getCharacterCount, getSentenceCount, + getCitationCount, + getFootnoteCount, } from "src/utils/StatUtils"; import { debounce } from "obsidian"; diff --git a/src/utils/StatUtils.ts b/src/utils/StatUtils.ts index eddaa6d..8040486 100644 --- a/src/utils/StatUtils.ts +++ b/src/utils/StatUtils.ts @@ -27,6 +27,23 @@ export function getCharacterCount(text: string): number { return text.length; } +export function getFootnoteCount(text: string): number { + const regularFn = text.match(/\[\^\S+](?!:)/g); + const inlineFn = text.match(/\^\[[^^].+?]/g); + + let overallFn = 0; + if (regularFn) overallFn += regularFn.length; + if (inlineFn) overallFn += inlineFn.length; + return overallFn; +} + +export function getCitationCount(text: string): number { + const pandocCitations = text.match(/@[A-Za-z0-9-]+[,;\]](?!\()/gi); + if (!pandocCitations) return 0; + const uniqueCitations = [...new Set(pandocCitations)].length; + return uniqueCitations; +} + export function getSentenceCount(text: string): number { const sentences: number = ( (text || "").match(