-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #47 from a-nano-dust/future-开发统计功能
Future 开发统计功能
- Loading branch information
Showing
24 changed files
with
564 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import {WorkspaceLeaf} from 'obsidian'; | ||
import DustCalendarPlugin from "../main"; | ||
import {CalendarView, VIEW_TYPE_CALENDAR} from "../view/CalendarView"; | ||
|
||
|
||
/** | ||
* 有很多逻辑都需要刷新日历界面,为避免刷新过快,带来性能方面的影响 | ||
* 所有的刷新请求都需要交给 CalendarViewFlushController 处理,由它来控制刷新的频率 | ||
*/ | ||
export class CalendarViewFlushController { | ||
|
||
public readonly plugin: DustCalendarPlugin; | ||
private requestCounter: number; // 请求刷新的次数 | ||
private lastRequestTime: number; // 上次请求时间 | ||
|
||
constructor(plugin: DustCalendarPlugin) { | ||
this.plugin = plugin; | ||
this.requestCounter = 0; | ||
this.lastRequestTime = 0; | ||
} | ||
|
||
// 立即刷新 | ||
public forceFlush(): void { | ||
const {workspace} = this.plugin.app; | ||
|
||
// 检查该类型的视图是否存在,如果不存在,则创建 | ||
let leaf: WorkspaceLeaf | null = null; | ||
const leaves = workspace.getLeavesOfType(VIEW_TYPE_CALENDAR); | ||
if (leaves.length > 0) { | ||
leaf = leaves[0]; | ||
(leaf.view as CalendarView).flush(); | ||
} | ||
} | ||
|
||
/** | ||
* 请求刷新 | ||
* 如果某个地方调用了请求刷新函数,就表示它需要刷新日历界面,但处于性能考虑,并不需要立即刷新 | ||
* 默认情况下,该函数会在调用1秒之后刷新界面,在此期间,如果该函数再次被调用,那么刷新时间会继续向后顺延1秒 | ||
*/ | ||
public requestFlush(): void { | ||
this.requestCounter = this.requestCounter + 1; | ||
this.lastRequestTime = performance.now(); | ||
setTimeout(() => { | ||
if (this.requestCounter <= 0) { | ||
return; | ||
} | ||
const now = performance.now(); | ||
if (now - this.lastRequestTime < 990) { | ||
return; | ||
} | ||
this.requestCounter = 0; | ||
this.forceFlush(); | ||
}, 1000); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import {TAbstractFile, TFile} from "obsidian"; | ||
import {DateTime} from "luxon"; | ||
import DustCalendarPlugin from "../main"; | ||
import {NoteType, TodoAnnotationMode} from "../base/enum"; | ||
import NoteStatistic from "../entity/NoteStatistic"; | ||
|
||
|
||
export default class NoteStatisticController { | ||
|
||
private static PATTERN_FOR_COUNTING_WORDS = /(?:[0-9]+(?:(?:,|\.)[0-9]+)*|[\-'’A-Za-z\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC-가-힣ꥠ-ꥼힰ-ퟆ])+|[\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u4E00-\u9FD5\uAC00-\uD7A3\uA960-\uA97C\uD7B0-\uD7C6]/g; | ||
|
||
public readonly plugin: DustCalendarPlugin; | ||
private noteStatisticRegistry: Map<string, NoteStatistic>; | ||
|
||
constructor(plugin: DustCalendarPlugin) { | ||
this.plugin = plugin; | ||
this.noteStatisticRegistry = new Map(); | ||
|
||
// 关联文件修改也删除事件,保证界面信息及时更新 | ||
this.plugin.app.vault.on("modify", (file) => this.onFileModify(file)); | ||
this.plugin.app.vault.on("delete", (file) => this.onFileDelete(file)); | ||
} | ||
|
||
public getWordsPerDot(): number { | ||
return this.plugin.database.setting.wordsPerDot; | ||
} | ||
|
||
public setWordsPerDot(wordsPerDot: number): void { | ||
this.plugin.database.setting.wordsPerDot = wordsPerDot; | ||
} | ||
|
||
public getDotUpperLimit(): number { | ||
return this.plugin.database.setting.dotUpperLimit; | ||
} | ||
|
||
public setDotUpperLimit(dotUpperLimit: number): void { | ||
this.plugin.database.setting.dotUpperLimit = dotUpperLimit; | ||
} | ||
|
||
public getTodoAnnotationMode(): TodoAnnotationMode { | ||
return this.plugin.database.setting.todoAnnotationMode; | ||
} | ||
|
||
public setTodoAnnotationMode(todoAnnotationMode: TodoAnnotationMode): void { | ||
this.plugin.database.setting.todoAnnotationMode = todoAnnotationMode; | ||
} | ||
|
||
public getNoteStatic(date: DateTime, noteType: NoteType): NoteStatistic { | ||
const filename = this.plugin.noteController.getNoteFilename(date, noteType); | ||
if (filename === null) { | ||
return new NoteStatistic(); | ||
} | ||
const noteStatistic = this.noteStatisticRegistry.get(filename); | ||
if (noteStatistic === undefined) { | ||
return new NoteStatistic(); | ||
} | ||
return noteStatistic; | ||
} | ||
|
||
// 添加一个文件信息统计任务,由界面触发 | ||
public addTaskByDateAndNoteType(date: DateTime, noteType: NoteType): void { | ||
setTimeout(async () => { | ||
await this.executeStaticByDateAndNoteType(date, noteType); | ||
}, 0); | ||
} | ||
|
||
// 添加一个文件信息统计任务,新建周期性笔记时触发,或者文件内容修改时触发 | ||
public addTaskByFile(file: TAbstractFile | null): void { | ||
setTimeout(async () => { | ||
await this.executeStaticByFile(file); | ||
}, 0); | ||
} | ||
|
||
private async executeStaticByDateAndNoteType(date: DateTime, noteType: NoteType): Promise<void> { | ||
const filename = this.plugin.noteController.getNoteFilename(date, noteType); | ||
await this.executeStaticByFilename(filename); | ||
} | ||
|
||
private async executeStaticByFilename(filename: string | null): Promise<void> { | ||
if (filename === null) { | ||
return; | ||
} | ||
|
||
const {vault} = this.plugin.app; | ||
const file = vault.getAbstractFileByPath(filename); | ||
await this.executeStaticByFile(file); | ||
} | ||
|
||
// 文件信息统计 | ||
private async executeStaticByFile(file: TAbstractFile | null): Promise<void> { | ||
if (file === null) { | ||
return; | ||
} | ||
|
||
if (!(file instanceof TFile)) { | ||
return; | ||
} | ||
|
||
const newNoteStatistic = new NoteStatistic(); | ||
|
||
const filename = file.path; | ||
const {vault} = this.plugin.app; | ||
const content = await vault.cachedRead(file as TFile); | ||
const {wordsPerDot, dotUpperLimit, todoAnnotationMode} = this.plugin.database.setting; | ||
|
||
// 统计字数 | ||
const totalWords = NoteStatisticController.countWords(content); | ||
newNoteStatistic.totalWords = totalWords; | ||
newNoteStatistic.totalDots = Math.ceil((totalWords + 1) / wordsPerDot); | ||
if (newNoteStatistic.totalDots >= dotUpperLimit) { | ||
newNoteStatistic.totalDots = dotUpperLimit; | ||
} | ||
|
||
// 统计待办 | ||
if (todoAnnotationMode === TodoAnnotationMode.NONE) { | ||
newNoteStatistic.hasUnfinishedTasks = false; | ||
} | ||
else { | ||
const totalTodos = NoteStatisticController.countTodos(content); | ||
newNoteStatistic.hasUnfinishedTasks = totalTodos !== 0; | ||
} | ||
|
||
// 更新统计信息 | ||
const oldNoteStatistic = this.noteStatisticRegistry.get(filename); | ||
const isUpdated: boolean = oldNoteStatistic === undefined || !oldNoteStatistic.equals(newNoteStatistic); | ||
this.noteStatisticRegistry.set(filename, newNoteStatistic); | ||
// 判断信息有没有更新,如果有更新,就需要刷新界面 | ||
if (isUpdated) { | ||
this.plugin.calendarViewFlushController.requestFlush(); | ||
} | ||
} | ||
|
||
private onFileModify(file: TAbstractFile): void { | ||
this.addTaskByFile(file); | ||
} | ||
|
||
private onFileDelete(file: TAbstractFile): void { | ||
if (!(file instanceof TFile)) { | ||
return; | ||
} | ||
const filename = file.path; | ||
if (!this.noteStatisticRegistry.delete(filename)) { | ||
return; | ||
} | ||
// 如果成功从注册表中删除了文件,则需要刷新日历界面 | ||
this.plugin.calendarViewFlushController.requestFlush(); | ||
} | ||
|
||
private static countWords(text: string): number { | ||
const result = text.match(NoteStatisticController.PATTERN_FOR_COUNTING_WORDS); | ||
return result ? result.length : 0; | ||
} | ||
|
||
private static countTodos(text: string): number { | ||
const result = text.match(/(-|\*) \[ \]/g); | ||
return result ? result.length : 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.