mirror of
https://github.com/groldsf/obsidian_check_plugin.git
synced 2026-07-22 05:37:48 +00:00
feat(settings): Add option to enable/disable debug logging
This commit is contained in:
parent
28ebd1ddf0
commit
595bb8194e
9 changed files with 232 additions and 50 deletions
|
|
@ -51,6 +51,13 @@ These settings control when and how the synchronization logic runs.
|
|||
- **Enabled:** Automatically synchronizes checkbox states when files are loaded/opened and immediately after plugin settings are applied. This ensures consistency but might have performance implications on very large vaults or files. *(Requires Obsidian restart or settings reload to take full effect)*.
|
||||
- **Disabled (Default):** Synchronization only occurs when you *manually* change a checkbox's state within Obsidian. This is the default behavior to minimize potential performance impact.
|
||||
|
||||
### Dev
|
||||
|
||||
- **Enable console log**
|
||||
- **Description:** Toggles detailed logging to the developer console. When enabled, the plugin will output more information about its operations, which can be helpful for troubleshooting or understanding its behavior.
|
||||
- **Enabled:** Debug logs are printed to the console.
|
||||
- **Disabled (Default):** Debug logs are suppressed.
|
||||
|
||||
### Actions and Status
|
||||
|
||||
- **Error Display:** An area below the settings displays any errors encountered, such as invalid JSON in the symbol configuration.
|
||||
|
|
@ -105,10 +112,17 @@ These settings control when and how the synchronization logic runs.
|
|||
- **Включено:** Автоматически синхронизирует состояния чекбоксов при загрузке/открытии файлов и сразу после применения настроек плагина. Это обеспечивает консистентность, но может влиять на производительность в очень больших хранилищах или файлах. *(Требует перезапуска Obsidian или перезагрузки настроек для полного вступления в силу)*.
|
||||
- **Отключено (По умолчанию):** Синхронизация происходит только тогда, когда вы *вручную* изменяете состояние чекбокса в Obsidian. Это поведение по умолчанию для минимизации потенциального влияния на производительность.
|
||||
|
||||
### Разработка / Отладка
|
||||
|
||||
- **Включить Отладочное Логирование (Enable console log)**
|
||||
- **Описание:** Переключает вывод подробных логов в консоль разработчика. Когда включено, плагин будет выводить больше информации о своих операциях, что может быть полезно для устранения неполадок или понимания его поведения.
|
||||
- **Включено:** Отладочные логи выводятся в консоль.
|
||||
- **Отключено (По умолчанию):** Отладочные логи не выводятся.
|
||||
|
||||
### Действия и Статус
|
||||
|
||||
- **Отображение Ошибок:** Область под настройками отображает любые возникшие ошибки, например, невалидный JSON в конфигурации символов.
|
||||
- **Кнопки:**
|
||||
- `Apply Changes` (Применить изменения): Сохраняет и применяет измененные настройки. Активна только при наличии изменений.
|
||||
- `Reset changes` (Отменить изменения): Возвращает несохраненные изменения к последнему примененному состоянию настроек.
|
||||
- `Reset to defaults` (Сбросить по умолчанию): Сбрасывает все настройки к значениям по умолчанию и немедленно применяет их.
|
||||
- `Reset to defaults` (Сбросить по умолчанию): Сбрасывает все настройки к значениям по умолчанию и немедленно применяет их.
|
||||
|
|
|
|||
78
esbuild-debug-wrap-plugin.mjs
Normal file
78
esbuild-debug-wrap-plugin.mjs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import { promises } from "fs";
|
||||
|
||||
/**
|
||||
* Плагин esbuild для обертывания вызовов console.* в условие.
|
||||
* @param {object} options
|
||||
* @param {string} [options.debugFlagName='DEBUG_WRAP_CONSOLE_PLUGIN_FLAG'] - Имя глобальной переменной для проверки.
|
||||
* @param {string[]} [options.methods=['log', 'warn', 'info', 'debug', 'error']] - Методы console, которые нужно обернуть.
|
||||
* @returns {import('esbuild').Plugin}
|
||||
*/
|
||||
export const debugWrapConsolePlugin = ({
|
||||
debugFlagName = "DEBUG_WRAP_CONSOLE_PLUGIN_FLAG", // Имя глобального флага (лучше сделать уникальным для вашего плагина)
|
||||
methods = ["log", "warn", "info", "debug", "error"], // Какие методы console оборачивать
|
||||
} = {}) => ({
|
||||
name: "debug-wrap-console",
|
||||
setup(build) {
|
||||
// Создаем фильтр для методов console
|
||||
const methodsPattern = methods.join("|");
|
||||
// Регулярное выражение для поиска вызовов console.method(...)
|
||||
// Оно пытается обработать простые случаи, но может быть неидеальным для сложных вложенных выражений или многострочных вызовов.
|
||||
// $& в замене представляет всю совпавшую строку.
|
||||
const consoleRegex = new RegExp(
|
||||
// Match 'console.' followed by one of the specified methods
|
||||
`(^|\\s+|\\{|\\;)(console\\.(${methodsPattern}))\\s*\\(` +
|
||||
// Match arguments (non-greedy) - this is the tricky part and might not capture perfectly balanced parentheses in all complex cases
|
||||
`([\\s\\S]*?)` +
|
||||
// Match the closing parenthesis and optional semicolon
|
||||
`\\)(;?)`,
|
||||
"g" // Global search
|
||||
);
|
||||
|
||||
const wrapperStart = `if (window.${debugFlagName}) { `;
|
||||
const wrapperEnd = ` }`;
|
||||
|
||||
// Перехватываем загрузку JS/TS файлов
|
||||
build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
|
||||
try {
|
||||
// Читаем содержимое файла
|
||||
const source = await promises.readFile(args.path, "utf8");
|
||||
|
||||
// Заменяем вызовы console.*
|
||||
const contents = source.replace(
|
||||
consoleRegex,
|
||||
(match, prefix, fullCall, methodName, argsContent, semicolon) => {
|
||||
// prefix: Пробел, начало строки, {, ; перед вызовом console
|
||||
// fullCall: Сам вызов, например, console.log
|
||||
// methodName: Имя метода, например, log
|
||||
// argsContent: Содержимое скобок
|
||||
// semicolon: Завершающая точка с запятой (если была)
|
||||
|
||||
// Собираем обернутый вызов
|
||||
// Мы используем 'match' целиком, чтобы сохранить оригинальное форматирование и содержимое,
|
||||
// но убираем исходный префикс (пробел/начало строки/итд) и добавляем его перед if.
|
||||
const originalCall = match.substring(prefix.length);
|
||||
return `${prefix}${wrapperStart}${originalCall}${wrapperEnd}`;
|
||||
}
|
||||
);
|
||||
|
||||
// Возвращаем измененное содержимое и указываем esbuild,
|
||||
// что это все еще JS/TS код (в зависимости от исходного файла)
|
||||
const loader =
|
||||
args.path.endsWith(".ts") || args.path.endsWith(".tsx") ? "ts" : "js";
|
||||
|
||||
return {
|
||||
contents,
|
||||
loader,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error processing file ${args.path} in debug-wrap-console plugin:`,
|
||||
error
|
||||
);
|
||||
// В случае ошибки возвращаем null или выбрасываем ошибку, чтобы сборка прервалась
|
||||
return null;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from "builtin-modules";
|
||||
import { debugWrapConsolePlugin } from "./esbuild-debug-wrap-plugin.mjs";
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
|
|
@ -39,6 +40,12 @@ const context = await esbuild.context({
|
|||
treeShaking: true,
|
||||
outfile: "main.js",
|
||||
minify: prod,
|
||||
plugins: [
|
||||
debugWrapConsolePlugin({
|
||||
debugFlagName: 'CHECKBOX_SYNC_DEBUG',
|
||||
methods: ['log', 'info', 'debug'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
|
|
|
|||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -7,7 +7,7 @@
|
|||
"": {
|
||||
"name": "checkbox-sync",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"license": "0BSD",
|
||||
"dependencies": {
|
||||
"async-mutex": "^0.5.0"
|
||||
},
|
||||
|
|
|
|||
103
src/main.ts
103
src/main.ts
|
|
@ -7,49 +7,64 @@ import { CheckboxSyncPluginSettingTab } from "./ui/CheckboxSyncPluginSettingTab"
|
|||
import SyncController from "./SyncController";
|
||||
import { CheckboxSyncPluginSettings, DEFAULT_SETTINGS } from "./types";
|
||||
|
||||
export default class CheckboxSyncPlugin extends Plugin {
|
||||
private _settings: CheckboxSyncPluginSettings;
|
||||
const DEBUG_FLAG_NAME = 'CHECKBOX_SYNC_DEBUG';
|
||||
|
||||
private syncController: SyncController;
|
||||
private checkboxUtils: CheckboxUtils;
|
||||
private fileStateHolder: FileStateHolder;
|
||||
private fileLoadEventHandler: FileLoadEventHandler;
|
||||
private fileChangeEventHandler: FileChangeEventHandler;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
||||
this.fileStateHolder = new FileStateHolder(this.app.vault);
|
||||
this.checkboxUtils = new CheckboxUtils(this.settings);
|
||||
this.syncController = new SyncController(this.app.vault, this.checkboxUtils, this.fileStateHolder);
|
||||
this.fileLoadEventHandler = new FileLoadEventHandler(this, this.app, this.syncController, this.fileStateHolder);
|
||||
this.fileChangeEventHandler = new FileChangeEventHandler(this, this.app, this.syncController, this.fileStateHolder);
|
||||
|
||||
this.addSettingTab(new CheckboxSyncPluginSettingTab(this.app, this));
|
||||
this.fileLoadEventHandler.registerEvents();
|
||||
this.fileChangeEventHandler.registerEvents();
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this._settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
get settings(): Readonly<CheckboxSyncPluginSettings> {
|
||||
return this._settings;
|
||||
}
|
||||
|
||||
async updateSettings(callback: (settings: CheckboxSyncPluginSettings) => void | Promise<void>) {
|
||||
await callback(this._settings);
|
||||
await this.saveData(this.settings);
|
||||
|
||||
if (this.settings.enableAutomaticFileSync) {
|
||||
//надо пересинхронизировать все файлы в кеше
|
||||
const allFile = this.fileStateHolder.getAllFiles();
|
||||
await Promise.all(
|
||||
allFile.map(async (file: TFile) => {
|
||||
await this.syncController.syncFile(file);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
// --- Объявление глобальной переменной для TypeScript ---
|
||||
// Это нужно, чтобы TypeScript не ругался на window[DEBUG_FLAG_NAME]
|
||||
declare global {
|
||||
interface Window {
|
||||
[key: string]: any; // Позволяем индексировать window строкой
|
||||
}
|
||||
}
|
||||
|
||||
export default class CheckboxSyncPlugin extends Plugin {
|
||||
private _settings: CheckboxSyncPluginSettings;
|
||||
|
||||
private syncController: SyncController;
|
||||
private checkboxUtils: CheckboxUtils;
|
||||
private fileStateHolder: FileStateHolder;
|
||||
private fileLoadEventHandler: FileLoadEventHandler;
|
||||
private fileChangeEventHandler: FileChangeEventHandler;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
||||
this.fileStateHolder = new FileStateHolder(this.app.vault);
|
||||
this.checkboxUtils = new CheckboxUtils(this.settings);
|
||||
this.syncController = new SyncController(this.app.vault, this.checkboxUtils, this.fileStateHolder);
|
||||
this.fileLoadEventHandler = new FileLoadEventHandler(this, this.app, this.syncController, this.fileStateHolder);
|
||||
this.fileChangeEventHandler = new FileChangeEventHandler(this, this.app, this.syncController, this.fileStateHolder);
|
||||
|
||||
this.addSettingTab(new CheckboxSyncPluginSettingTab(this.app, this));
|
||||
this.fileLoadEventHandler.registerEvents();
|
||||
this.fileChangeEventHandler.registerEvents();
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this._settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
get settings(): Readonly<CheckboxSyncPluginSettings> {
|
||||
return this._settings;
|
||||
}
|
||||
|
||||
async updateSettings(callback: (settings: CheckboxSyncPluginSettings) => void | Promise<void>) {
|
||||
await callback(this._settings);
|
||||
this.setDebugFlag(this.settings.consoleEnabled);
|
||||
await this.saveData(this.settings);
|
||||
|
||||
if (this.settings.enableAutomaticFileSync) {
|
||||
//надо пересинхронизировать все файлы в кеше
|
||||
const allFile = this.fileStateHolder.getAllFiles();
|
||||
await Promise.all(
|
||||
allFile.map(async (file: TFile) => {
|
||||
await this.syncController.syncFile(file);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private setDebugFlag(enabled: boolean) {
|
||||
window[DEBUG_FLAG_NAME] = enabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export interface CheckboxSyncPluginSettings {
|
|||
ignoreSymbols: string[];
|
||||
unknownSymbolPolicy: CheckboxState;
|
||||
enableAutomaticFileSync: boolean;
|
||||
consoleEnabled: boolean;
|
||||
}
|
||||
|
||||
export enum CheckboxState {
|
||||
|
|
@ -22,4 +23,5 @@ export const DEFAULT_SETTINGS: CheckboxSyncPluginSettings = {
|
|||
ignoreSymbols: [],
|
||||
unknownSymbolPolicy: CheckboxState.Checked,
|
||||
enableAutomaticFileSync: false,
|
||||
};
|
||||
consoleEnabled: false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { EnableParentSyncSettingComponent } from "./components/synchronizationBe
|
|||
import { ConfirmModal, InfoModal, SaveConfirmModal } from "./modals";
|
||||
import { SettingsValidator } from "./validation/SettingsValidator";
|
||||
import { ValidationError } from "./validation/types";
|
||||
import { EnableConsoleLogSettingComponent } from "./components/devGroup/EnableDebug";
|
||||
|
||||
export class CheckboxSyncPluginSettingTab extends PluginSettingTab {
|
||||
plugin: CheckboxSyncPlugin;
|
||||
|
|
@ -58,10 +59,18 @@ export class CheckboxSyncPluginSettingTab extends PluginSettingTab {
|
|||
[parentToggleComp, childrenToggleComp, automaticFileSyncToggleComp]
|
||||
);
|
||||
|
||||
const consoleLog = new EnableConsoleLogSettingComponent();
|
||||
|
||||
const devGroup = new SettingGroup(
|
||||
"Dev",
|
||||
[consoleLog]
|
||||
);
|
||||
|
||||
// Сохраняем созданную группу (или группы) в поле класса
|
||||
this.settingGroups = [
|
||||
symbolGroup,
|
||||
behaviorGroup
|
||||
behaviorGroup,
|
||||
devGroup
|
||||
];
|
||||
|
||||
const changeListener = () => this.settingChanged();
|
||||
|
|
@ -294,4 +303,4 @@ export class CheckboxSyncPluginSettingTab extends PluginSettingTab {
|
|||
throw saveError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
57
src/ui/components/devGroup/EnableDebug.ts
Normal file
57
src/ui/components/devGroup/EnableDebug.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { ToggleComponent, Setting } from "obsidian";
|
||||
import { CheckboxSyncPluginSettings } from "src/types";
|
||||
import { BaseSettingComponent } from "src/ui/basedClasses/BaseSettingComponent";
|
||||
import { ValidationError } from "src/ui/validation/types";
|
||||
import { validateValueIsBoolean } from "src/ui/validation/validators";
|
||||
|
||||
|
||||
export class EnableConsoleLogSettingComponent extends BaseSettingComponent {
|
||||
private toggleComponent: ToggleComponent;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
getSettingKey(): keyof CheckboxSyncPluginSettings {
|
||||
return 'consoleEnabled';
|
||||
}
|
||||
|
||||
render(container: HTMLElement, currentValue: any): void {
|
||||
this.setting = new Setting(container)
|
||||
.setName('Enable console logs')
|
||||
.addToggle(toggle => {
|
||||
this.toggleComponent = toggle;
|
||||
toggle
|
||||
.setValue(currentValue as boolean)
|
||||
.onChange(this.onChangeCallback);
|
||||
});
|
||||
}
|
||||
|
||||
getValueFromUi(): boolean {
|
||||
if (this.toggleComponent) {
|
||||
return this.toggleComponent.getValue();
|
||||
}
|
||||
throw new Error(`[${this.getSettingKey()}] Cannot get value from UI before component is rendered.`);
|
||||
}
|
||||
|
||||
setValueInUi(value: any): void {
|
||||
if (this.toggleComponent) {
|
||||
this.toggleComponent.setValue(value as boolean);
|
||||
} else {
|
||||
throw new Error(`[${this.getSettingKey()}] Cannot set value before component is rendered.`);
|
||||
}
|
||||
}
|
||||
|
||||
validate(): ValidationError | null {
|
||||
const valueFromUi = this.getValueFromUi();
|
||||
const validationResult = validateValueIsBoolean(valueFromUi);
|
||||
|
||||
if (validationResult) {
|
||||
return {
|
||||
field: this.getSettingKey(),
|
||||
message: validationResult.message
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -55,4 +55,4 @@ export class EnableChildSyncSettingComponent extends BaseSettingComponent {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue