diff --git a/README.md b/README.md
index 3944ddc..1fee0fb 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,11 @@
# Better Word Count
-  
-
-**IMPORTANT NOTICE:** Due to the introduction of the new Live Preview feature, this plugin needed to be almost entirely rewritten. It will be unstable for a while so please report bugs on github.
-
-This plugin is the same as the built-in **Word Count** plugin, except when you select text, it will count the selected word instead of the whole document. I recommend turning off the built-in **Word Count** because this plugin is designed to replace that. This plugin also has the ability to store statistics about your vault.
+   

+This plugin is the same as the built-in **Word Count** plugin, except when you select text, it will count the selected word instead of the whole document. I recommend turning off the built-in **Word Count** because this plugin is designed to replace that. This plugin also has the ability to store statistics about your vault.
+
## Features
- Allows you to store statistics about your vault.
diff --git a/src/editor/EditorPlugin.ts b/src/editor/EditorPlugin.ts
index 28c429f..2626e34 100644
--- a/src/editor/EditorPlugin.ts
+++ b/src/editor/EditorPlugin.ts
@@ -1,3 +1,4 @@
+import { Transaction } from "@codemirror/state";
import {
ViewUpdate,
PluginValue,
@@ -22,9 +23,19 @@ class EditorPlugin implements PluginValue {
}
const tr = update.transactions[0];
- if (!tr) return;
+
+ if (!tr) {
+ return;
+ }
+
+ // When selecting text with Shift+Home the userEventType is undefined.
+ // This is probably a bug in codemirror, for the time being doing an explict check
+ // for the type allows us to update the stats for the selection.
+ const userEventTypeUndefined =
+ tr.annotation(Transaction.userEvent) === undefined;
+
if (
- tr.isUserEvent("select") &&
+ (tr.isUserEvent("select") || userEventTypeUndefined) &&
tr.newSelection.ranges[0].from !== tr.newSelection.ranges[0].to
) {
let text = "";
diff --git a/src/main.ts b/src/main.ts
index 5cf97a8..cbc3293 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -33,7 +33,7 @@ export default class BetterWordCount extends Plugin {
// Handle Statistics
if (this.settings.collectStats) {
- this.statsManager = new StatsManager(this.app.vault, this.app.workspace);
+ this.statsManager = new StatsManager(this.app.vault, this.app.workspace, this);
}
// Handle Status Bar
diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts
index 466dc5a..73e73d2 100644
--- a/src/settings/Settings.ts
+++ b/src/settings/Settings.ts
@@ -4,6 +4,7 @@ export enum MetricCounter {
sentences,
footnotes,
citations,
+ pages,
files,
}
@@ -40,6 +41,7 @@ export interface BetterWordCountSettings {
altBar: StatusBarItem[];
countComments: boolean;
collectStats: boolean;
+ pageWords: number;
}
export const DEFAULT_SETTINGS: BetterWordCountSettings = {
@@ -73,4 +75,5 @@ export const DEFAULT_SETTINGS: BetterWordCountSettings = {
],
countComments: false,
collectStats: false,
+ pageWords: 300,
};
diff --git a/src/settings/SettingsTab.ts b/src/settings/SettingsTab.ts
index 0e55833..a6aa43b 100644
--- a/src/settings/SettingsTab.ts
+++ b/src/settings/SettingsTab.ts
@@ -1,4 +1,4 @@
-import { App, PluginSettingTab, Setting, ToggleComponent } from "obsidian";
+import { App, PluginSettingTab, Setting, ToggleComponent, TextComponent } from "obsidian";
import type BetterWordCount from "src/main";
import { addStatusBarSettings } from "./StatusBarSettings";
@@ -37,6 +37,18 @@ export default class BetterWordCountSettingsTab extends PluginSettingTab {
await this.plugin.saveSettings();
});
});
+ new Setting(containerEl)
+ .setName("Page Word Count")
+ .setDesc("Set how many words count as one \"page\"")
+ .addText((text: TextComponent) => {
+ text.inputEl.type = "number";
+ text.setPlaceholder("300");
+ text.setValue(this.plugin.settings.pageWords.toString());
+ text.onChange(async (value: string) => {
+ this.plugin.settings.pageWords = parseInt(value);
+ await this.plugin.saveSettings();
+ });
+ });
// Status Bar Settings
addStatusBarSettings(this.plugin, containerEl);
diff --git a/src/settings/StatusBarSettings.svelte b/src/settings/StatusBarSettings.svelte
index fb506bf..14ece51 100644
--- a/src/settings/StatusBarSettings.svelte
+++ b/src/settings/StatusBarSettings.svelte
@@ -22,6 +22,8 @@
return "Footnotes in Note"
case MetricCounter.citations:
return "Citations in Note"
+ case MetricCounter.pages:
+ return "Pages in Note"
case MetricCounter.files:
return "Total Notes"
}
@@ -37,6 +39,8 @@
return "Daily Footnotes"
case MetricCounter.citations:
return "Daily Citations"
+ case MetricCounter.pages:
+ return "Daily Pages"
case MetricCounter.files:
return "Total Notes"
}
@@ -52,6 +56,8 @@
return "Total Footnotes"
case MetricCounter.citations:
return "Total Citations"
+ case MetricCounter.pages:
+ return "Total Pages"
case MetricCounter.files:
return "Total Notes"
}
@@ -195,6 +201,7 @@
+
@@ -364,6 +371,7 @@
+
diff --git a/src/stats/Stats.ts b/src/stats/Stats.ts
index f79a973..b613b58 100644
--- a/src/stats/Stats.ts
+++ b/src/stats/Stats.ts
@@ -9,6 +9,7 @@ export interface Day {
words: number;
characters: number;
sentences: number;
+ pages: number;
files: number;
footnotes: number;
citations: number;
@@ -17,6 +18,7 @@ export interface Day {
totalSentences: number;
totalFootnotes: number;
totalCitations: number;
+ totalPages: number;
}
export type ModifiedFiles = Record;
@@ -27,6 +29,7 @@ export interface FileStat {
words: CountDiff;
characters: CountDiff;
sentences: CountDiff;
+ pages: CountDiff;
}
export interface CountDiff {
diff --git a/src/stats/StatsManager.ts b/src/stats/StatsManager.ts
index f5fd1f4..e2fee39 100644
--- a/src/stats/StatsManager.ts
+++ b/src/stats/StatsManager.ts
@@ -1,10 +1,12 @@
import { debounce, Debouncer, TFile, Vault, Workspace } from "obsidian";
+import type BetterWordCount from "../main";
import { STATS_FILE } from "../constants";
import type { Day, VaultStatistics } from "./Stats";
import moment from "moment";
import {
getCharacterCount,
getSentenceCount,
+ getPageCount,
getWordCount,
getCitationCount,
getFootnoteCount,
@@ -13,13 +15,15 @@ import {
export default class StatsManager {
private vault: Vault;
private workspace: Workspace;
+ private plugin: BetterWordCount;
private vaultStats: VaultStatistics;
private today: string;
public debounceChange;
- constructor(vault: Vault, workspace: Workspace) {
+ constructor(vault: Vault, workspace: Workspace, plugin: BetterWordCount) {
this.vault = vault;
this.workspace = workspace;
+ this.plugin = plugin;
this.debounceChange = debounce(
(text: string) => this.change(text),
50,
@@ -80,11 +84,13 @@ export default class StatsManager {
const totalSentences = await this.calcTotalSentences();
const totalFootnotes = await this.calcTotalFootnotes();
const totalCitations = await this.calcTotalCitations();
+ const totalPages = await this.calcTotalPages();
const newDay: Day = {
words: 0,
characters: 0,
sentences: 0,
+ pages: 0,
files: 0,
footnotes: 0,
citations: 0,
@@ -93,6 +99,7 @@ export default class StatsManager {
totalSentences: totalSentences,
totalFootnotes: totalFootnotes,
totalCitations: totalCitations,
+ totalPages: totalPages,
};
this.vaultStats.modifiedFiles = {};
@@ -107,6 +114,8 @@ export default class StatsManager {
const currentSentences = getSentenceCount(text);
const currentCitations = getCitationCount(text);
const currentFootnotes = getFootnoteCount(text);
+ const currentPages = getPageCount(text, this.plugin.settings.pageWords);
+
if (
this.vaultStats.history.hasOwnProperty(this.today) &&
this.today === moment().format("YYYY-MM-DD")
@@ -124,11 +133,15 @@ export default class StatsManager {
currentSentences - modFiles[fileName].footnotes.current;
this.vaultStats.history[this.today].totalCitations +=
currentSentences - modFiles[fileName].citations.current;
+ this.vaultStats.history[this.today].totalPages +=
+ currentPages - modFiles[fileName].pages.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;
+ modFiles[fileName].footnotes.current = currentFootnotes;
+ modFiles[fileName].citations.current = currentCitations;
+ modFiles[fileName].pages.current = currentPages;
} else {
modFiles[fileName] = {
words: {
@@ -150,6 +163,9 @@ export default class StatsManager {
citations: {
initial: currentCitations,
current: currentCitations,
+ pages: {
+ initial: currentPages,
+ current: currentPages,
},
};
}
@@ -169,6 +185,7 @@ 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)
@@ -178,6 +195,10 @@ export default class StatsManager {
.map((counts) =>
Math.max(0, counts.citations.current - counts.citations.initial)
)
+ const pages = Object.values(modFiles)
+ .map((counts) =>
+ Math.max(0, counts.pages.current - counts.pages.initial)
+ )
.reduce((a, b) => a + b, 0);
this.vaultStats.history[this.today].words = words;
@@ -185,6 +206,7 @@ export default class StatsManager {
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].pages = pages;
this.vaultStats.history[this.today].files = this.getTotalFiles();
await this.update();
@@ -205,6 +227,7 @@ export default class StatsManager {
todayHist.totalSentences = await this.calcTotalSentences();
todayHist.totalFootnotes = await this.calcTotalFootnotes();
todayHist.totalCitations = await this.calcTotalCitations();
+ todayHist.totalPages = await this.calcTotalPages();
this.update();
} else {
this.updateToday();
@@ -248,6 +271,20 @@ export default class StatsManager {
}
return sentence;
}
+
+ private async calcTotalPages(): Promise {
+ let pages = 0;
+
+ const files = this.vault.getFiles();
+ for (const i in files) {
+ const file = files[i];
+ if (file.extension === "md") {
+ pages += getPageCount(await this.vault.cachedRead(file), this.plugin.settings.pageWords);
+ }
+ }
+
+ return pages;
+ }
private async calcTotalFootnotes(): Promise {
let footnotes = 0;
@@ -285,6 +322,7 @@ export default class StatsManager {
return this.vaultStats.history[this.today].sentences;
}
+
public getDailyFootnotes(): number {
return this.vaultStats.history[this.today].footnotes;
}
@@ -292,6 +330,9 @@ export default class StatsManager {
public getDailyCitations(): number {
return this.vaultStats.history[this.today].citations;
}
+ public getDailyPages(): number {
+ return this.vaultStats.history[this.today].pages;
+ }
public getTotalFiles(): number {
return this.vault.getMarkdownFiles().length;
@@ -311,7 +352,7 @@ 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;
@@ -322,4 +363,8 @@ export default class StatsManager {
return this.vaultStats.history[this.today].totalCitations;
}
+ public async getTotalPages(): Promise {
+ if (!this.vaultStats) return await this.calcTotalPages();
+ return this.vaultStats.history[this.today].totalPages;
+ }
}
diff --git a/src/status/StatusBar.ts b/src/status/StatusBar.ts
index aeee7aa..79c156d 100644
--- a/src/status/StatusBar.ts
+++ b/src/status/StatusBar.ts
@@ -6,6 +6,7 @@ import {
getSentenceCount,
getCitationCount,
getFootnoteCount,
+ getPageCount,
} from "src/utils/StatUtils";
import { debounce } from "obsidian";
@@ -149,6 +150,26 @@ export default class StatusBar {
: 0));
break;
}
+ } else if (metric.counter === MetricCounter.pages) {
+ switch (metric.type) {
+ case MetricType.file:
+ display = display + getPageCount(text, this.plugin.settings.pageWords);
+ break;
+ case MetricType.daily:
+ display =
+ display +
+ (this.plugin.settings.collectStats
+ ? this.plugin.statsManager.getDailyPages()
+ : 0);
+ break;
+ case MetricType.total:
+ display =
+ display +
+ (await (this.plugin.settings.collectStats
+ ? this.plugin.statsManager.getTotalPages()
+ : 0));
+ break;
+ }
} else if (metric.counter === MetricCounter.files) {
switch (metric.type) {
case MetricType.file:
@@ -252,7 +273,7 @@ export default class StatusBar {
break;
}
} else if (metric.counter === MetricCounter.footnotes) {
- switch (metric.type) {
+ switch (metric.type) {
case MetricType.file:
display = display + 0;
break;
@@ -260,14 +281,14 @@ export default class StatusBar {
display =
display +
(this.plugin.settings.collectStats
- ? this.plugin.statsManager.getDailyFootnotes()
- : 0);
+ ? this.plugin.statsManager.getDailyFootnotes()
+ : 0);
break;
case MetricType.total:
display =
display +
(await (this.plugin.settings.collectStats
- ? this.plugin.statsManager.getTotalFootnotes()
+ ? this.plugin.statsManager.getTotalFootnotes()
: 0));
break;
}
@@ -291,6 +312,26 @@ export default class StatusBar {
: 0));
break;
}
+ } else if (metric.counter === MetricCounter.pages) {
+ switch (metric.type) {
+ case MetricType.file:
+ display = display + 0;
+ break;
+ case MetricType.daily:
+ display =
+ display +
+ (this.plugin.settings.collectStats
+ ? this.plugin.statsManager.getDailyPages()
+ : 0);
+ break;
+ case MetricType.total:
+ display =
+ display +
+ (await (this.plugin.settings.collectStats
+ ? this.plugin.statsManager.getTotalPages()
+ : 0));
+ break;
+ }
} else if (metric.counter === MetricCounter.files) {
switch (metric.type) {
case MetricType.file:
diff --git a/src/utils/StatUtils.ts b/src/utils/StatUtils.ts
index 8040486..723f90a 100644
--- a/src/utils/StatUtils.ts
+++ b/src/utils/StatUtils.ts
@@ -54,6 +54,10 @@ export function getSentenceCount(text: string): number {
return sentences;
}
+export function getPageCount(text: string, pageWords: number): number {
+ return parseFloat((getWordCount(text) / pageWords).toFixed(1));
+}
+
export function getTotalFileCount(vault: Vault): number {
return vault.getMarkdownFiles().length;
}