first commit
This commit is contained in:
commit
0f1cc5ecd8
9 changed files with 207 additions and 0 deletions
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
package-lock.json
|
||||
|
||||
# build
|
||||
main.js
|
||||
*.js.map
|
||||
test-vault/
|
||||
*.zip
|
7
README.md
Normal file
7
README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
## Better Word Count
|
||||
|
||||
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.
|
||||
|
||||
**Note:** This plugin has only been tested with English.
|
||||
|
||||

|
BIN
assets/better-word-count.gif
Normal file
BIN
assets/better-word-count.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 600 KiB |
9
manifest.json
Normal file
9
manifest.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "better-word-count",
|
||||
"name": "Better Word Count",
|
||||
"version": "0.1.0",
|
||||
"description": "Counts the words of selected test in the editor.",
|
||||
"author": "Luke Leppan",
|
||||
"authorUrl": "https://lukeleppan.com",
|
||||
"isDesktopOnly": false
|
||||
}
|
28
package.json
Normal file
28
package.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "better-word-count",
|
||||
"version": "0.1.0",
|
||||
"description": "Counts the words of selected test in the editor.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "rollup --config rollup.config.js -w",
|
||||
"build": "rollup --config rollup.config.js"
|
||||
},
|
||||
"keywords": [
|
||||
"obsidian",
|
||||
"obsidian-md",
|
||||
"obsidian-plugin"
|
||||
],
|
||||
"author": "Luke Leppan",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^15.1.0",
|
||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||
"@rollup/plugin-typescript": "^6.0.0",
|
||||
"@types/node": "^14.14.2",
|
||||
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
|
||||
"rollup": "^2.32.1",
|
||||
"rollup-plugin-copy": "^3.3.0",
|
||||
"tslib": "^2.0.3",
|
||||
"typescript": "^4.0.3"
|
||||
}
|
||||
}
|
27
rollup.config.js
Normal file
27
rollup.config.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import typescript from '@rollup/plugin-typescript';
|
||||
import {nodeResolve} from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
const TEST_VAULT = 'test-vault/.obsidian/plugins/better-word-count';
|
||||
|
||||
export default {
|
||||
input: 'src/main.ts',
|
||||
output: {
|
||||
dir: 'dist/',
|
||||
sourcemap: 'inline',
|
||||
format: 'cjs',
|
||||
exports: 'default'
|
||||
},
|
||||
external: ['obsidian'],
|
||||
plugins: [
|
||||
typescript(),
|
||||
nodeResolve({browser: true}),
|
||||
commonjs(),
|
||||
copy({
|
||||
targets: [
|
||||
{ src: 'dist/main.js', dest: TEST_VAULT },
|
||||
{ src: ['manifest.json'], dest: TEST_VAULT }
|
||||
], flatten: true
|
||||
})
|
||||
]
|
||||
};
|
90
src/main.ts
Normal file
90
src/main.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { App, MarkdownView, Modal, Plugin, TFile } from "obsidian";
|
||||
import { StatusBar } from "./status-bar";
|
||||
|
||||
export default class BetterWordCount extends Plugin {
|
||||
public recentlyTyped: boolean;
|
||||
public statusBar: StatusBar;
|
||||
|
||||
onload() {
|
||||
let statusBarEl = this.addStatusBarItem();
|
||||
this.statusBar = new StatusBar(statusBarEl);
|
||||
|
||||
this.recentlyTyped = false;
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("file-open", this.onFileOpen, this)
|
||||
);
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("quick-preview", this.onQuickPreview, this)
|
||||
);
|
||||
|
||||
let activeLeaf = this.app.workspace.activeLeaf;
|
||||
let files: TFile[] = this.app.vault.getMarkdownFiles();
|
||||
|
||||
files.forEach((file) => {
|
||||
if ((file.basename = activeLeaf.getDisplayText())) {
|
||||
this.onFileOpen(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async onFileOpen(file: TFile) {
|
||||
if (file && file.extension === "md") {
|
||||
const contents = await this.app.vault.cachedRead(file);
|
||||
this.updateWordCount(contents);
|
||||
} else {
|
||||
this.updateWordCount("");
|
||||
}
|
||||
|
||||
let activeLeaf = this.app.workspace.activeLeaf;
|
||||
if (!activeLeaf || !(activeLeaf.view instanceof MarkdownView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let editor = activeLeaf.view.sourceMode.cmEditor;
|
||||
|
||||
activeLeaf.view.registerInterval(
|
||||
window.setInterval(async () => {
|
||||
if (editor.somethingSelected()) {
|
||||
let content: string = editor.getSelection();
|
||||
this.updateWordCount(content);
|
||||
this.recentlyTyped = false;
|
||||
} else if (file && file.extension === "md" && !this.recentlyTyped) {
|
||||
const contents = await this.app.vault.cachedRead(file);
|
||||
this.updateWordCount(contents);
|
||||
} else if (!this.recentlyTyped) {
|
||||
this.updateWordCount("");
|
||||
}
|
||||
}, 500)
|
||||
);
|
||||
}
|
||||
|
||||
onQuickPreview(file: TFile, contents: string) {
|
||||
const leaf = this.app.workspace.activeLeaf;
|
||||
if (leaf && leaf.view.getViewType() === "markdown") {
|
||||
this.recentlyTyped = true;
|
||||
this.updateWordCount(contents);
|
||||
}
|
||||
}
|
||||
|
||||
updateWordCount(text: string) {
|
||||
let words = 0;
|
||||
|
||||
const matches = text.match(
|
||||
/[a-zA-Z0-9_\u0392-\u03c9\u00c0-\u00ff\u0600-\u06ff]+|[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/gm
|
||||
);
|
||||
|
||||
if (matches) {
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
if (matches[i].charCodeAt(0) > 19968) {
|
||||
words += matches[i].length;
|
||||
} else {
|
||||
words += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.statusBar.displayText(`${words} words ` + `${text.length} characters`);
|
||||
}
|
||||
}
|
11
src/status-bar.ts
Normal file
11
src/status-bar.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export class StatusBar {
|
||||
private statusBarEl: HTMLElement;
|
||||
|
||||
constructor(statusBarEl: HTMLElement) {
|
||||
this.statusBarEl = statusBarEl;
|
||||
}
|
||||
|
||||
displayText(text: string) {
|
||||
this.statusBarEl.setText(text);
|
||||
}
|
||||
}
|
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "es5",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es5",
|
||||
"scripthost",
|
||||
"es2015"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue