/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/core.ts
function getHeaderLevel(text, startHeaderLevel) {
const match = text.match(/^#+/);
if (!match)
return [0, 0];
let level = match ? match[0].length : 0;
return [level - startHeaderLevel + 1, level];
}
function getNextNumber(cntNums, headerLevel) {
let nextNums = [...cntNums];
if (nextNums.length >= headerLevel) {
nextNums = nextNums.slice(0, headerLevel);
nextNums[nextNums.length - 1]++;
} else {
while (nextNums.length < headerLevel) {
nextNums.push(1);
}
}
return nextNums;
}
function isNeedInsertNumber(text, splitor) {
const match = text.match(/^(#{1,6})\s+(.*)/);
if (!match)
return false;
const contentAfterHash = match[2];
if (splitor == " ") {
return !/^\d+(?:\.\d+)*\s+/.test(contentAfterHash);
} else {
return !contentAfterHash.contains(splitor);
}
}
function isNeedUpdateNumber(nextNumsStr, text, splitor) {
const match = text.match(/^(#{1,6})\s+(.*)/);
if (!match)
return false;
const contentAfterHash = match[2];
let cntNumsStr;
if (splitor == " ") {
const numMatch = contentAfterHash.match(/^(\d+(?:\.\d+)*)\s+/);
if (!numMatch)
return true;
cntNumsStr = numMatch[1];
} else {
const parts = contentAfterHash.split(splitor);
if (parts.length < 2)
return true;
cntNumsStr = parts[0].trim();
}
return nextNumsStr !== cntNumsStr;
}
function removeHeaderNumber(text, splitor) {
const match = text.match(/^(#{1,6})\s+(.*)/);
if (!match)
return text;
const sharp = match[1];
const contentAfterHash = match[2];
if (splitor == " ") {
const header = contentAfterHash.replace(/^\d+(?:\.\d+)*\s+/, "");
return sharp + " " + header;
} else {
if (!contentAfterHash.contains(splitor))
return text;
const parts = contentAfterHash.split(splitor);
const header = parts.slice(1).join(splitor).trim();
return sharp + " " + header;
}
}
function isHeader(text) {
return /^#{1,6} .*/.test(text.trim());
}
function analyzeHeaderLevels(content) {
const lines = content.split("\n");
const usedLevels = /* @__PURE__ */ new Set();
let isCodeBlock = false;
let headerCount = 0;
for (const line of lines) {
if (line.startsWith("```")) {
isCodeBlock = !isCodeBlock;
if (line.slice(3).includes("```")) {
isCodeBlock = !isCodeBlock;
}
}
if (isCodeBlock)
continue;
if (isHeader(line)) {
const match = line.match(/^#+/);
if (match) {
const level = match[0].length;
usedLevels.add(level);
headerCount++;
}
}
}
if (usedLevels.size === 0) {
return {
minLevel: 0,
maxLevel: 0,
usedLevels: [],
isEmpty: true,
headerCount: 0
};
}
const levels = Array.from(usedLevels).sort((a, b) => a - b);
if (levels.length === 1) {
const singleLevel = levels[0];
return {
minLevel: singleLevel,
maxLevel: Math.min(singleLevel + 2, 6),
// 默认扩展2级,但不超过H6
usedLevels: levels,
isEmpty: false,
headerCount
};
}
return {
minLevel: levels[0],
maxLevel: levels[levels.length - 1],
usedLevels: levels,
isEmpty: false,
headerCount
};
}
var init_core = __esm({
"src/core.ts"() {
}
});
// src/utils.ts
function getYaml(editor) {
var _a;
const matchResult = editor.getValue().match(YAML_REGEX);
return (_a = matchResult == null ? void 0 : matchResult[0]) != null ? _a : "";
}
function getAutoNumberingYaml(editor) {
var _a;
const yaml = getYaml(editor);
const parsedYaml = (0, import_obsidian.parseYaml)(yaml.slice(4, -4));
return (_a = parsedYaml == null ? void 0 : parsedYaml["header-auto-numbering"]) != null ? _a : "";
}
function setAutoNumberingYaml(editor, value = DEFAULT_YAML_SETTING) {
const yaml = getYaml(editor);
let parsedYaml = (0, import_obsidian.parseYaml)(yaml.slice(4, -4));
if (!parsedYaml) {
parsedYaml = {};
}
parsedYaml["header-auto-numbering"] = value;
const newContent = `---
${(0, import_obsidian.stringifyYaml)(parsedYaml)}---
`;
const startPosition = { line: 0, ch: 0 };
let endOffset = yaml.length;
if (yaml.length > 0) {
const contentAfterYaml = editor.getValue().substring(yaml.length, yaml.length + 1);
if (contentAfterYaml === "\n") {
endOffset += 1;
}
}
const endPosition = editor.offsetToPos(endOffset);
editor.replaceRange(newContent, startPosition, endPosition);
}
var import_obsidian, YAML_REGEX, DEFAULT_YAML_SETTING;
var init_utils = __esm({
"src/utils.ts"() {
import_obsidian = require("obsidian");
YAML_REGEX = /^---\n(?:((?:.|\n)*?)\n)?---(?=\n|$)/;
DEFAULT_YAML_SETTING = [
"state on",
"start-level h2",
"end-level h6",
"start-at 1",
"separator ."
];
}
});
// src/i18n/en.ts
var en_default;
var init_en = __esm({
"src/i18n/en.ts"() {
en_default = {
settings: {
title: "Header Enhancer Settings",
general: "General",
language: {
name: "Language",
desc: "Language for automatic numbering"
},
statusBar: {
name: "Show on Status Bar",
desc: "Show current header level on status bar"
},
sidebar: {
name: "Show on Sidebar",
desc: "Show Header Enhancer icon in the sidebar ribbon"
},
autoDetect: {
name: "Auto Detect Header Level",
desc: "Automatically detect and use the highest and lowest header levels in the document for numbering"
},
headerLevel: {
start: {
name: "Start Header Level",
desc: "The starting level for headers"
},
max: {
name: "Max Header Level",
desc: "Maximum level for headers"
}
},
autoNumbering: {
title: "Header Auto Numbering",
globalToggle: {
name: "Enable Auto Numbering Function",
desc: "Master switch to enable/disable the entire auto numbering functionality. When disabled, no documents will have auto numbering regardless of other settings."
},
globalDisabled: {
title: "Auto Numbering Function Disabled",
description: "The auto numbering function is currently disabled globally. Enable it above to access other auto numbering settings and use the sidebar button to control individual documents."
},
mode: {
name: "Auto Numbering Mode",
desc: "Control how header auto numbering works",
off: "Off",
on: "On",
yaml: "Controlled by YAML"
},
headerLevel: {
name: "Header Level Numbering Method",
toggleLabel: "\u{1F527} Enable Auto Detection",
desc: {
autoDetect: "\u2705 Auto Detection Mode: Intelligently determine numbering range based on document content",
manual: "\u2699\uFE0F Manual Setting Mode: Use fixed level range settings",
yamlControl: "\u{1F4CB} YAML Control Mode: Configure through file frontmatter"
}
},
startNumber: {
name: "Start Number",
desc: "Start numbering at this number",
placeholder: "Enter a number"
},
separator: {
name: "Number Separator",
desc: "Separator between numbers (one of '. , / -')",
placeholder: "Enter separator"
},
headerSeparator: {
name: "Header Separator",
desc: "Separator between header number and text",
error: "You can't change header separator when auto numbering is enabled"
},
updateBacklinks: {
name: "Update Backlinks",
desc: "\u26A0\uFE0F Warning: Automatically update backlinks when headers change. May impact performance in large vaults."
},
endLevelError: "Max header level should be greater than or equal to start header level",
startLevelError: "Start header level should be less than or equal to max header level",
format: {
name: "Your auto numbering format is",
fromLevel: "from",
toLevel: "to",
autoDetect: "Auto Detect",
manual: "Manual",
yamlControlled: "[Controlled by YAML]",
disabled: "[Disabled]"
},
removeConfirmation: {
title: "Turn Off Auto Numbering",
message: "You are about to turn off auto numbering. What would you like to do with existing numbering in your documents?",
warningTitle: "\u26A0\uFE0F Performance Warning",
warningMessage: "This operation will scan all markdown files in your vault. In large vaults, this may take several minutes and temporarily impact Obsidian's performance.",
removeAndTurnOff: "Remove all numbering and turn off",
removeAndTurnOffDesc: "Scan all files and remove header numbering, then disable auto numbering",
turnOffOnly: "Turn off without removing",
turnOffOnlyDesc: "Disable auto numbering but keep existing numbers in documents",
cancel: "Cancel",
processing: "Processing files...",
progressStatus: "Processed {current} of {total} files",
completed: "Successfully removed numbering from {count} files",
error: "Error occurred while processing files: {error}",
noNumberingFound: "No files with header numbering were found",
manualTip: "You can also manually disable auto numbering for individual files using the sidebar button."
},
activationConfirmation: {
title: "Enable Auto Numbering",
message: "You are about to enable auto numbering. What would you like to do with existing documents in your vault?",
warningTitle: "\u26A0\uFE0F Performance Warning",
warningMessage: "This operation will scan all markdown files in your vault. In large vaults, this may take several minutes and temporarily impact Obsidian's performance.",
addToAll: "Add numbering to all documents",
addToAllDesc: "Scan all files and add header numbering to existing documents",
turnOnOnly: "Turn on without adding",
turnOnOnlyDesc: "Enable auto numbering but keep existing documents unchanged",
cancel: "Cancel",
processing: "Adding numbering to files...",
progressStatus: "Processed {current} of {total} files",
completed: "Successfully added numbering to {count} files",
error: "Error occurred while processing files: {error}",
noHeadersFound: "No files with headers were found",
manualTip: "You can also manually enable auto numbering for individual files using the sidebar button."
}
},
headerFont: {
title: "Header Font Settings",
separate: {
name: "Separate Header Font",
desc: "Use different font settings for markdown headers (# ## ###)"
},
preview: {
title: "Header Font Preview",
sample: "Sample Header"
},
family: {
name: "Font Family",
desc: "Header font family (inherit from global font by default)",
options: {
inherit: "Inherit from global font"
}
},
size: {
name: "Font Size",
desc: "Header font size (inherit from global font size by default)",
options: {
inherit: "Inherit from global size",
smaller: "Smaller",
small: "Small",
normal: "Normal",
large: "Large",
larger: "Larger",
xlarge: "Extra Large",
xxlarge: "Extra Extra Large"
}
}
},
titleFont: {
title: "Title Font Settings",
separate: {
name: "Separate Title Font",
desc: "Use different font settings for document titles"
},
preview: {
title: "Title Font Preview",
sample: "Sample Document Title"
},
family: {
name: "Font Family",
desc: "Title font family (inherit from global font by default)",
options: {
inherit: "Inherit from global font"
}
},
size: {
name: "Font Size",
desc: "Title font size (inherit from global font size by default)",
options: {
inherit: "Inherit from global size",
smaller: "Smaller",
small: "Small",
normal: "Normal",
large: "Large",
larger: "Larger",
xlarge: "Extra Large",
xxlarge: "Extra Extra Large"
}
}
},
yamlMode: {
fallback: {
name: "Documents without YAML configuration",
desc: "Choose how to handle documents that don't have YAML configuration",
noNumbering: "No numbering",
useDefault: "Use default settings"
},
defaultStartLevel: {
name: "Default Start Level",
desc: "Default starting header level for documents without YAML"
},
defaultEndLevel: {
name: "Default End Level",
desc: "Default ending header level for documents without YAML"
},
defaultStartNumber: {
name: "Default Start Number",
desc: "Default starting number for documents without YAML"
},
defaultSeparator: {
name: "Default Separator",
desc: "Default number separator for documents without YAML"
}
},
resetSettings: {
name: "Reset Settings",
confirm: "Are you sure you want to reset settings to default?"
},
moreInfo: "More Information",
author: "Author: ",
license: "License: ",
githubRepo: "GitHub Repository: ",
anyQuestion: "Any questions? "
},
autoDetection: {
currentDocument: "Current Document Analysis",
noActiveDocument: "No active document",
noHeaders: "No headers detected",
detected: "Detected levels",
range: "Level range",
mapping: "Number mapping",
totalHeaders: "Total headers",
modes: {
autoDetect: "\u{1F527} Current Mode: Auto Detect - Intelligently determine numbering range based on document content",
yamlControl: "\u2699\uFE0F Current Mode: YAML Control - Configure through file frontmatter",
manual: "\u{1F3AF} Current Mode: Manual - Use fixed level range"
},
info: {
yamlMode: {
title: "\u2699\uFE0F YAML Control Mode",
description: "In this mode, header numbering is controlled by YAML frontmatter in files. Please add the following configuration at the beginning of your document:",
usage: "You can use plugin commands to quickly add or modify these configurations."
},
offMode: {
title: "\u23F8\uFE0F Auto Numbering Disabled",
description: 'Header auto numbering is currently disabled. To enable auto numbering, please select "On" or "Controlled by YAML" mode above.'
}
}
},
statusBar: {
title: "Header Enhancer",
off: "Off",
on: "On",
yaml: "YAML",
auto: "Auto",
autoNoHeaders: "Auto(No Headers)",
globalDisabled: "Global Disabled",
documentEnabled: "Document On",
documentDisabled: "Document Off"
},
commands: {
toggleGlobalAutoNumbering: "Toggle Global Auto Numbering",
toggleDocumentAutoNumbering: "Toggle Document Auto Numbering",
resetAutoNumberingYaml: "Reset Auto Numbering YAML",
removeAutoNumberingYaml: "Remove Auto Numbering YAML",
applyCustomYamlConfig: "Apply Custom YAML Configuration"
},
notices: {
noActiveView: "No active MarkdownView, cannot toggle auto numbering.",
globalDisabledNotice: "Auto numbering is globally disabled. Enable it in settings first.",
globalAutoNumberingEnabled: "Global auto numbering enabled",
globalAutoNumberingDisabled: "Global auto numbering disabled",
autoNumberingEnabledForDocument: "Auto numbering enabled for this document",
autoNumberingDisabledForDocument: "Auto numbering disabled for this document",
yamlAlreadyExists: "auto numbering yaml already exists",
yamlNotExists: "auto numbering yaml not exists",
yamlTemplateInserted: "YAML configuration template inserted successfully"
}
};
}
});
// src/i18n/zh.ts
var zh_default;
var init_zh = __esm({
"src/i18n/zh.ts"() {
zh_default = {
settings: {
title: "\u6807\u9898\u589E\u5F3A\u5668\u8BBE\u7F6E",
general: "\u5E38\u89C4",
language: {
name: "\u8BED\u8A00",
desc: "\u81EA\u52A8\u7F16\u53F7\u7684\u8BED\u8A00"
},
statusBar: {
name: "\u5728\u72B6\u6001\u680F\u663E\u793A",
desc: "\u5728\u72B6\u6001\u680F\u663E\u793A\u5F53\u524D\u6807\u9898\u7EA7\u522B"
},
sidebar: {
name: "\u5728\u4FA7\u8FB9\u680F\u663E\u793A",
desc: "\u5728\u4FA7\u8FB9\u680F\u529F\u80FD\u533A\u663E\u793A\u6807\u9898\u589E\u5F3A\u5668\u56FE\u6807"
},
autoDetect: {
name: "\u81EA\u52A8\u68C0\u6D4B\u6807\u9898\u7EA7\u522B",
desc: "\u6839\u636E\u4E0A\u4E0B\u6587\u81EA\u52A8\u68C0\u6D4B\u6807\u9898\u7EA7\u522B"
},
headerLevel: {
start: {
name: "\u8D77\u59CB\u6807\u9898\u7EA7\u522B",
desc: "\u6807\u9898\u7684\u8D77\u59CB\u7EA7\u522B"
},
max: {
name: "\u6700\u5927\u6807\u9898\u7EA7\u522B",
desc: "\u6807\u9898\u7684\u6700\u5927\u7EA7\u522B"
}
},
autoNumbering: {
title: "\u6807\u9898\u81EA\u52A8\u7F16\u53F7",
globalToggle: {
name: "\u542F\u7528\u81EA\u52A8\u7F16\u53F7\u529F\u80FD",
desc: "\u4E3B\u5F00\u5173\uFF0C\u7528\u4E8E\u542F\u7528/\u7981\u7528\u6574\u4E2A\u81EA\u52A8\u7F16\u53F7\u529F\u80FD\u3002\u7981\u7528\u65F6\uFF0C\u65E0\u8BBA\u5176\u4ED6\u8BBE\u7F6E\u5982\u4F55\uFF0C\u90FD\u4E0D\u4F1A\u6709\u6587\u6863\u8FDB\u884C\u81EA\u52A8\u7F16\u53F7\u3002"
},
globalDisabled: {
title: "\u81EA\u52A8\u7F16\u53F7\u529F\u80FD\u5DF2\u7981\u7528",
description: "\u81EA\u52A8\u7F16\u53F7\u529F\u80FD\u5F53\u524D\u5728\u5168\u5C40\u8303\u56F4\u5185\u88AB\u7981\u7528\u3002\u8BF7\u5728\u4E0A\u65B9\u542F\u7528\u5B83\u4EE5\u8BBF\u95EE\u5176\u4ED6\u81EA\u52A8\u7F16\u53F7\u8BBE\u7F6E\u5E76\u4F7F\u7528\u4FA7\u8FB9\u680F\u6309\u94AE\u63A7\u5236\u5355\u4E2A\u6587\u6863\u3002"
},
mode: {
name: "\u81EA\u52A8\u7F16\u53F7\u6A21\u5F0F",
desc: "\u63A7\u5236\u6807\u9898\u81EA\u52A8\u7F16\u53F7\u7684\u5DE5\u4F5C\u65B9\u5F0F",
off: "\u5173\u95ED",
on: "\u542F\u7528",
yaml: "\u901A\u8FC7YAML\u63A7\u5236"
},
headerLevel: {
name: "\u6807\u9898\u5C42\u7EA7\u7F16\u53F7\u65B9\u5F0F",
toggleLabel: "\u{1F527} \u542F\u7528\u81EA\u52A8\u68C0\u6D4B",
desc: {
autoDetect: "\u2705 \u81EA\u52A8\u68C0\u6D4B\u6A21\u5F0F\uFF1A\u6839\u636E\u6587\u6863\u5185\u5BB9\u667A\u80FD\u786E\u5B9A\u7F16\u53F7\u8303\u56F4",
manual: "\u2699\uFE0F \u624B\u52A8\u8BBE\u7F6E\u6A21\u5F0F\uFF1A\u4F7F\u7528\u56FA\u5B9A\u7684\u5C42\u7EA7\u8303\u56F4\u8BBE\u7F6E",
yamlControl: "\u{1F4CB} YAML\u63A7\u5236\u6A21\u5F0F\uFF1A\u901A\u8FC7\u6587\u4EF6\u524D\u7F6E\u5143\u6570\u636E\u914D\u7F6E"
}
},
startNumber: {
name: "\u8D77\u59CB\u6570\u5B57",
desc: "\u4ECE\u6B64\u6570\u5B57\u5F00\u59CB\u7F16\u53F7",
placeholder: "\u8F93\u5165\u6570\u5B57",
error: "\u8D77\u59CB\u6570\u5B57\u5FC5\u987B\u662F\u6709\u6548\u6570\u5B57"
},
separator: {
name: "\u6570\u5B57\u5206\u9694\u7B26",
desc: "\u6570\u5B57\u4E4B\u95F4\u7684\u5206\u9694\u7B26\uFF08. , / - \u4E2D\u7684\u4E00\u4E2A\uFF09",
placeholder: "\u8F93\u5165\u5206\u9694\u7B26",
error: "\u5206\u9694\u7B26\u5FC5\u987B\u662F\u4EE5\u4E0B\u4E4B\u4E00\uFF1A. , / -"
},
headerSeparator: {
name: "\u6807\u9898\u5206\u9694\u7B26",
desc: "\u6570\u5B57\u548C\u6807\u9898\u6587\u672C\u4E4B\u95F4\u7684\u5206\u9694\u7B26",
error: "\u65E0\u6548\u7684\u6807\u9898\u5206\u9694\u7B26"
},
updateBacklinks: {
name: "\u66F4\u65B0\u53CD\u5411\u94FE\u63A5",
desc: "\u26A0\uFE0F \u8B66\u544A\uFF1A\u5F53\u6807\u9898\u6539\u53D8\u65F6\u81EA\u52A8\u66F4\u65B0\u53CD\u5411\u94FE\u63A5\u3002\u5728\u5927\u578B\u77E5\u8BC6\u5E93\u4E2D\u53EF\u80FD\u4F1A\u5F71\u54CD\u6027\u80FD\u3002"
},
endLevelError: "\u6700\u5927\u6807\u9898\u7EA7\u522B\u5E94\u8BE5\u5927\u4E8E\u6216\u7B49\u4E8E\u8D77\u59CB\u6807\u9898\u7EA7\u522B",
startLevelError: "\u8D77\u59CB\u6807\u9898\u7EA7\u522B\u5E94\u8BE5\u5C0F\u4E8E\u6216\u7B49\u4E8E\u6700\u5927\u6807\u9898\u7EA7\u522B",
format: {
name: "\u5F53\u524D\u683C\u5F0F",
fromLevel: "\u4ECE",
toLevel: "\u5230",
autoDetect: "\u81EA\u52A8\u68C0\u6D4B",
manual: "\u624B\u52A8",
yamlControlled: "\uFF08YAML\u63A7\u5236\uFF09",
disabled: "\uFF08\u5DF2\u5173\u95ED\uFF09"
},
removeConfirmation: {
title: "\u5173\u95ED\u81EA\u52A8\u7F16\u53F7",
message: "\u60A8\u5373\u5C06\u5173\u95ED\u81EA\u52A8\u7F16\u53F7\u529F\u80FD\u3002\u5BF9\u4E8E\u6587\u6863\u4E2D\u73B0\u6709\u7684\u7F16\u53F7\uFF0C\u60A8\u5E0C\u671B\u5982\u4F55\u5904\u7406\uFF1F",
warningTitle: "\u26A0\uFE0F \u6027\u80FD\u8B66\u544A",
warningMessage: "\u6B64\u64CD\u4F5C\u5C06\u626B\u63CF\u77E5\u8BC6\u5E93\u4E2D\u7684\u6240\u6709markdown\u6587\u4EF6\u3002\u5728\u5927\u578B\u77E5\u8BC6\u5E93\u4E2D\uFF0C\u8FD9\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\u65F6\u95F4\u5E76\u6682\u65F6\u5F71\u54CDObsidian\u7684\u6027\u80FD\u3002",
removeAndTurnOff: "\u79FB\u9664\u6240\u6709\u7F16\u53F7\u5E76\u5173\u95ED",
removeAndTurnOffDesc: "\u626B\u63CF\u6240\u6709\u6587\u4EF6\u5E76\u79FB\u9664\u6807\u9898\u7F16\u53F7\uFF0C\u7136\u540E\u7981\u7528\u81EA\u52A8\u7F16\u53F7",
turnOffOnly: "\u4EC5\u5173\u95ED\u4E0D\u79FB\u9664",
turnOffOnlyDesc: "\u7981\u7528\u81EA\u52A8\u7F16\u53F7\u4F46\u4FDD\u7559\u6587\u6863\u4E2D\u7684\u73B0\u6709\u7F16\u53F7",
cancel: "\u53D6\u6D88",
processing: "\u6B63\u5728\u5904\u7406\u6587\u4EF6...",
progressStatus: "\u5DF2\u5904\u7406 {current}/{total} \u4E2A\u6587\u4EF6",
completed: "\u6210\u529F\u4ECE {count} \u4E2A\u6587\u4EF6\u4E2D\u79FB\u9664\u7F16\u53F7",
error: "\u5904\u7406\u6587\u4EF6\u65F6\u53D1\u751F\u9519\u8BEF\uFF1A{error}",
noNumberingFound: "\u672A\u627E\u5230\u5305\u542B\u6807\u9898\u7F16\u53F7\u7684\u6587\u4EF6",
manualTip: "\u4F60\u4E5F\u53EF\u4EE5\u901A\u8FC7\u4FA7\u8FB9\u680F\u6309\u94AE\u624B\u52A8\u5173\u95ED\u5355\u4E2A\u6587\u4EF6\u7684\u81EA\u52A8\u7F16\u53F7\u3002"
},
activationConfirmation: {
title: "\u542F\u7528\u81EA\u52A8\u7F16\u53F7",
message: "\u60A8\u5373\u5C06\u542F\u7528\u81EA\u52A8\u7F16\u53F7\u529F\u80FD\u3002\u5BF9\u4E8E\u77E5\u8BC6\u5E93\u4E2D\u73B0\u6709\u7684\u6587\u6863\uFF0C\u60A8\u5E0C\u671B\u5982\u4F55\u5904\u7406\uFF1F",
warningTitle: "\u26A0\uFE0F \u6027\u80FD\u8B66\u544A",
warningMessage: "\u6B64\u64CD\u4F5C\u5C06\u626B\u63CF\u77E5\u8BC6\u5E93\u4E2D\u7684\u6240\u6709markdown\u6587\u4EF6\u3002\u5728\u5927\u578B\u77E5\u8BC6\u5E93\u4E2D\uFF0C\u8FD9\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\u65F6\u95F4\u5E76\u6682\u65F6\u5F71\u54CDObsidian\u7684\u6027\u80FD\u3002",
addToAll: "\u4E3A\u6240\u6709\u6587\u6863\u6DFB\u52A0\u7F16\u53F7",
addToAllDesc: "\u626B\u63CF\u6240\u6709\u6587\u4EF6\u5E76\u4E3A\u73B0\u6709\u6587\u6863\u6DFB\u52A0\u6807\u9898\u7F16\u53F7",
turnOnOnly: "\u4EC5\u542F\u7528\u4E0D\u6DFB\u52A0",
turnOnOnlyDesc: "\u542F\u7528\u81EA\u52A8\u7F16\u53F7\u529F\u80FD\u4F46\u4FDD\u6301\u73B0\u6709\u6587\u6863\u4E0D\u53D8",
cancel: "\u53D6\u6D88",
processing: "\u6B63\u5728\u4E3A\u6587\u4EF6\u6DFB\u52A0\u7F16\u53F7...",
progressStatus: "\u5DF2\u5904\u7406 {current}/{total} \u4E2A\u6587\u4EF6",
completed: "\u6210\u529F\u4E3A {count} \u4E2A\u6587\u4EF6\u6DFB\u52A0\u7F16\u53F7",
error: "\u5904\u7406\u6587\u4EF6\u65F6\u53D1\u751F\u9519\u8BEF\uFF1A{error}",
noHeadersFound: "\u672A\u627E\u5230\u5305\u542B\u6807\u9898\u7684\u6587\u4EF6",
manualTip: "\u4F60\u4E5F\u53EF\u4EE5\u901A\u8FC7\u4FA7\u8FB9\u680F\u6309\u94AE\u624B\u52A8\u542F\u7528\u5355\u4E2A\u6587\u4EF6\u7684\u81EA\u52A8\u7F16\u53F7\u3002"
}
},
headerFont: {
title: "\u6807\u9898\u5B57\u4F53\u8BBE\u7F6E",
separate: {
name: "\u72EC\u7ACB\u6807\u9898\u5B57\u4F53",
desc: "\u4E3Amarkdown\u6807\u9898\u4F7F\u7528\u72EC\u7ACB\u7684\u5B57\u4F53\u8BBE\u7F6E (# ## ###)"
},
preview: {
title: "\u6807\u9898\u5B57\u4F53\u9884\u89C8",
sample: "\u793A\u4F8B\u6807\u9898"
},
family: {
name: "\u5B57\u4F53\u65CF",
desc: "\u6807\u9898\u5B57\u4F53\u65CF\uFF08\u9ED8\u8BA4\u7EE7\u627F\u5168\u5C40\u5B57\u4F53\uFF09",
options: {
inherit: "\u7EE7\u627F\u5168\u5C40\u5B57\u4F53"
}
},
size: {
name: "\u5B57\u4F53\u5927\u5C0F",
desc: "\u6807\u9898\u5B57\u4F53\u5927\u5C0F\uFF08\u9ED8\u8BA4\u7EE7\u627F\u5168\u5C40\u5B57\u4F53\u5927\u5C0F\uFF09",
options: {
inherit: "\u7EE7\u627F\u5168\u5C40\u5927\u5C0F",
smaller: "\u8F83\u5C0F",
small: "\u5C0F",
normal: "\u6B63\u5E38",
large: "\u5927",
larger: "\u8F83\u5927",
xlarge: "\u7279\u5927",
xxlarge: "\u8D85\u5927"
}
}
},
titleFont: {
title: "\u6587\u6863\u6807\u9898\u5B57\u4F53\u8BBE\u7F6E",
separate: {
name: "\u72EC\u7ACB\u6587\u6863\u6807\u9898\u5B57\u4F53",
desc: "\u4E3A\u6587\u6863\u6807\u9898\u4F7F\u7528\u72EC\u7ACB\u7684\u5B57\u4F53\u8BBE\u7F6E"
},
preview: {
title: "\u6587\u6863\u6807\u9898\u5B57\u4F53\u9884\u89C8",
sample: "\u793A\u4F8B\u6587\u6863\u6807\u9898"
},
family: {
name: "\u5B57\u4F53\u65CF",
desc: "\u6587\u6863\u6807\u9898\u5B57\u4F53\u65CF\uFF08\u9ED8\u8BA4\u7EE7\u627F\u5168\u5C40\u5B57\u4F53\uFF09",
options: {
inherit: "\u7EE7\u627F\u5168\u5C40\u5B57\u4F53"
}
},
size: {
name: "\u5B57\u4F53\u5927\u5C0F",
desc: "\u6587\u6863\u6807\u9898\u5B57\u4F53\u5927\u5C0F\uFF08\u9ED8\u8BA4\u7EE7\u627F\u5168\u5C40\u5B57\u4F53\u5927\u5C0F\uFF09",
options: {
inherit: "\u7EE7\u627F\u5168\u5C40\u5927\u5C0F",
smaller: "\u8F83\u5C0F",
small: "\u5C0F",
normal: "\u6B63\u5E38",
large: "\u5927",
larger: "\u8F83\u5927",
xlarge: "\u7279\u5927",
xxlarge: "\u8D85\u5927"
}
}
},
yamlMode: {
fallback: {
name: "\u6CA1\u6709YAML\u914D\u7F6E\u7684\u6587\u6863\u5904\u7406\u65B9\u5F0F",
desc: "\u9009\u62E9\u5982\u4F55\u5904\u7406\u6CA1\u6709YAML\u914D\u7F6E\u7684\u6587\u6863",
noNumbering: "\u4E0D\u7F16\u53F7",
useDefault: "\u4F7F\u7528\u9ED8\u8BA4\u8BBE\u7F6E"
},
defaultStartLevel: {
name: "\u9ED8\u8BA4\u8D77\u59CB\u5C42\u7EA7",
desc: "\u6CA1\u6709YAML\u914D\u7F6E\u7684\u6587\u6863\u4F7F\u7528\u7684\u9ED8\u8BA4\u8D77\u59CB\u6807\u9898\u5C42\u7EA7"
},
defaultEndLevel: {
name: "\u9ED8\u8BA4\u7ED3\u675F\u5C42\u7EA7",
desc: "\u6CA1\u6709YAML\u914D\u7F6E\u7684\u6587\u6863\u4F7F\u7528\u7684\u9ED8\u8BA4\u7ED3\u675F\u6807\u9898\u5C42\u7EA7"
},
defaultStartNumber: {
name: "\u9ED8\u8BA4\u8D77\u59CB\u6570\u5B57",
desc: "\u6CA1\u6709YAML\u914D\u7F6E\u7684\u6587\u6863\u4F7F\u7528\u7684\u9ED8\u8BA4\u8D77\u59CB\u7F16\u53F7"
},
defaultSeparator: {
name: "\u9ED8\u8BA4\u5206\u9694\u7B26",
desc: "\u6CA1\u6709YAML\u914D\u7F6E\u7684\u6587\u6863\u4F7F\u7528\u7684\u9ED8\u8BA4\u6570\u5B57\u5206\u9694\u7B26"
}
},
resetSettings: {
name: "\u91CD\u7F6E\u8BBE\u7F6E",
confirm: "\u60A8\u786E\u5B9A\u8981\u5C06\u6240\u6709\u8BBE\u7F6E\u91CD\u7F6E\u4E3A\u9ED8\u8BA4\u503C\u5417\uFF1F"
},
moreInfo: "\u66F4\u591A\u4FE1\u606F",
author: "\u4F5C\u8005\uFF1A",
license: "\u8BB8\u53EF\u8BC1\uFF1A",
githubRepo: "GitHub \u4ED3\u5E93\uFF1A",
anyQuestion: "\u6709\u4EFB\u4F55\u95EE\u9898\uFF1F"
},
autoDetection: {
currentDocument: "\u5F53\u524D\u6587\u6863\u68C0\u6D4B\u7ED3\u679C",
noActiveDocument: "\u6CA1\u6709\u6D3B\u52A8\u6587\u6863",
noHeaders: "\u672A\u68C0\u6D4B\u5230\u6807\u9898",
detected: "\u68C0\u6D4B\u5230\u5C42\u7EA7",
range: "\u5C42\u7EA7\u8303\u56F4",
mapping: "\u7F16\u53F7\u6620\u5C04",
totalHeaders: "\u6807\u9898\u603B\u6570",
modes: {
autoDetect: "\u{1F527} \u5F53\u524D\u6A21\u5F0F\uFF1A\u81EA\u52A8\u68C0\u6D4B - \u5C06\u6839\u636E\u6587\u6863\u5185\u5BB9\u667A\u80FD\u786E\u5B9A\u7F16\u53F7\u8303\u56F4",
yamlControl: "\u2699\uFE0F \u5F53\u524D\u6A21\u5F0F\uFF1AYAML\u63A7\u5236 - \u901A\u8FC7\u6587\u4EF6\u524D\u7F6E\u5143\u6570\u636E\u914D\u7F6E",
manual: "\u{1F3AF} \u5F53\u524D\u6A21\u5F0F\uFF1A\u624B\u52A8\u8BBE\u7F6E - \u4F7F\u7528\u56FA\u5B9A\u7684\u5C42\u7EA7\u8303\u56F4"
},
info: {
yamlMode: {
title: "\u2699\uFE0F YAML\u63A7\u5236\u6A21\u5F0F",
description: "\u5728\u6B64\u6A21\u5F0F\u4E0B\uFF0C\u6807\u9898\u7F16\u53F7\u7531\u6587\u4EF6\u7684YAML\u524D\u7F6E\u5143\u6570\u636E\u63A7\u5236\u3002\u8BF7\u5728\u6587\u6863\u5F00\u5934\u6DFB\u52A0\u5982\u4E0B\u914D\u7F6E\uFF1A",
usage: "\u60A8\u53EF\u4EE5\u4F7F\u7528\u63D2\u4EF6\u547D\u4EE4\u6765\u5FEB\u901F\u6DFB\u52A0\u6216\u4FEE\u6539\u8FD9\u4E9B\u914D\u7F6E\u3002"
},
offMode: {
title: "\u23F8\uFE0F \u81EA\u52A8\u7F16\u53F7\u5DF2\u5173\u95ED",
description: '\u5F53\u524D\u6807\u9898\u81EA\u52A8\u7F16\u53F7\u529F\u80FD\u5DF2\u7981\u7528\u3002\u8981\u542F\u7528\u81EA\u52A8\u7F16\u53F7\uFF0C\u8BF7\u5728\u4E0A\u65B9\u9009\u62E9"\u542F\u7528"\u6216"\u901A\u8FC7YAML\u63A7\u5236"\u6A21\u5F0F\u3002'
}
}
},
statusBar: {
title: "\u6807\u9898\u589E\u5F3A\u5668",
off: "\u5173\u95ED",
on: "\u542F\u7528",
yaml: "YAML",
auto: "\u81EA\u52A8",
autoNoHeaders: "\u81EA\u52A8(\u65E0\u6807\u9898)",
globalDisabled: "\u5168\u5C40\u7981\u7528",
documentEnabled: "\u6587\u6863\u542F\u7528",
documentDisabled: "\u6587\u6863\u5173\u95ED"
},
commands: {
toggleGlobalAutoNumbering: "\u5207\u6362\u5168\u5C40\u81EA\u52A8\u7F16\u53F7",
toggleDocumentAutoNumbering: "\u5207\u6362\u6587\u6863\u81EA\u52A8\u7F16\u53F7",
resetAutoNumberingYaml: "\u91CD\u7F6E\u81EA\u52A8\u7F16\u53F7YAML\u914D\u7F6E",
removeAutoNumberingYaml: "\u79FB\u9664\u81EA\u52A8\u7F16\u53F7YAML\u914D\u7F6E",
applyCustomYamlConfig: "\u4E3A\u5F53\u524D\u6587\u4EF6\u5E94\u7528\u81EA\u5B9A\u4E49\u914D\u7F6E"
},
notices: {
noActiveView: "\u6CA1\u6709\u6D3B\u8DC3\u7684MarkdownView\uFF0C\u65E0\u6CD5\u5207\u6362\u81EA\u52A8\u7F16\u53F7\u3002",
globalDisabledNotice: "\u81EA\u52A8\u7F16\u53F7\u5728\u5168\u5C40\u8303\u56F4\u5185\u88AB\u7981\u7528\u3002\u8BF7\u5148\u5728\u8BBE\u7F6E\u4E2D\u542F\u7528\u3002",
globalAutoNumberingEnabled: "\u5168\u5C40\u81EA\u52A8\u7F16\u53F7\u5DF2\u542F\u7528",
globalAutoNumberingDisabled: "\u5168\u5C40\u81EA\u52A8\u7F16\u53F7\u5DF2\u7981\u7528",
autoNumberingEnabledForDocument: "\u5DF2\u4E3A\u6B64\u6587\u6863\u542F\u7528\u81EA\u52A8\u7F16\u53F7",
autoNumberingDisabledForDocument: "\u5DF2\u4E3A\u6B64\u6587\u6863\u7981\u7528\u81EA\u52A8\u7F16\u53F7",
yamlAlreadyExists: "\u81EA\u52A8\u7F16\u53F7YAML\u914D\u7F6E\u5DF2\u5B58\u5728",
yamlNotExists: "\u81EA\u52A8\u7F16\u53F7YAML\u914D\u7F6E\u4E0D\u5B58\u5728",
yamlTemplateInserted: "YAML\u914D\u7F6E\u6A21\u677F\u5DF2\u6210\u529F\u63D2\u5165"
}
};
}
});
// src/i18n/index.ts
var translations, I18n;
var init_i18n = __esm({
"src/i18n/index.ts"() {
init_en();
init_zh();
translations = {
en: en_default,
zh: zh_default
};
I18n = class {
constructor() {
this.currentLanguage = "en";
}
static getInstance() {
if (!I18n.instance) {
I18n.instance = new I18n();
}
return I18n.instance;
}
setLanguage(lang) {
if (translations[lang]) {
this.currentLanguage = lang;
}
}
t(key, placeholders) {
const keys = key.split(".");
let value = translations[this.currentLanguage];
for (const k of keys) {
if (value && value[k]) {
value = value[k];
} else {
value = translations["en"];
for (const fallbackKey of keys) {
if (value && value[fallbackKey]) {
value = value[fallbackKey];
} else {
return key;
}
}
}
}
let result = typeof value === "string" ? value : key;
if (placeholders) {
for (const [placeholder, replacement] of Object.entries(placeholders)) {
result = result.replace(new RegExp(`\\{${placeholder}\\}`, "g"), replacement);
}
}
return result;
}
};
}
});
// src/config.ts
function getAutoNumberingConfig(setting, editor, getDocumentState, currentFilePath) {
let config = {
state: setting.autoNumberingMode !== "off" /* OFF */,
startLevel: setting.startHeaderLevel,
endLevel: setting.endHeaderLevel,
startNumber: parseInt(setting.autoNumberingStartNumber),
separator: setting.autoNumberingSeparator
};
if (!setting.globalAutoNumberingEnabled) {
config.state = false;
return config;
}
if (getDocumentState && currentFilePath) {
const documentEnabled = getDocumentState(currentFilePath);
if (!documentEnabled) {
config.state = false;
return config;
}
}
if (setting.autoNumberingMode === "yaml" /* YAML_CONTROLLED */) {
config = applyYamlConfig(config, editor, setting);
} else if (setting.isAutoDetectHeaderLevel && setting.autoNumberingMode === "on" /* ON */) {
const content = editor.getValue();
const analysis = analyzeHeaderLevels(content);
if (!analysis.isEmpty) {
config.startLevel = analysis.minLevel;
config.endLevel = analysis.maxLevel;
}
}
return config;
}
function applyYamlConfig(config, editor, setting) {
const yaml = getAutoNumberingYaml(editor);
if (yaml === "") {
if (setting.yamlFallbackMode === "no_numbering" /* NO_NUMBERING */) {
config.state = false;
} else {
config.state = true;
config.startLevel = setting.yamlDefaultStartLevel;
config.endLevel = setting.yamlDefaultEndLevel;
config.startNumber = parseInt(setting.yamlDefaultStartNumber);
config.separator = setting.yamlDefaultSeparator;
}
return config;
}
let hasDeprecatedKeys = false;
const deprecatedKeys = [];
for (const item of yaml) {
const [key, ...valueParts] = item.split(" ");
const value = valueParts.join(" ");
switch (key) {
case "state":
config.state = value === "on";
break;
case "start-level":
config.startLevel = parseInt(value.substring(1));
break;
case "first-level":
hasDeprecatedKeys = true;
deprecatedKeys.push("first-level");
config.startLevel = parseInt(value.substring(1));
break;
case "end-level":
config.endLevel = parseInt(value.substring(1));
break;
case "max":
hasDeprecatedKeys = true;
deprecatedKeys.push("max");
config.endLevel = config.startLevel + parseInt(value) - 1;
break;
case "start-at":
config.startNumber = parseInt(value);
break;
case "separator":
config.separator = value;
break;
}
}
if (hasDeprecatedKeys) {
console.warn(
`[Header Enhancer] Deprecated YAML keys detected: ${deprecatedKeys.join(", ")}. Please update to new format: use "start-level" instead of "first-level", and "end-level" instead of "max". The old format will be removed in a future version.`
);
}
return config;
}
var init_config = __esm({
"src/config.ts"() {
init_setting();
init_utils();
init_core();
}
});
// src/dialogs.ts
var dialogs_exports = {};
__export(dialogs_exports, {
AutoNumberingActivationDialog: () => AutoNumberingActivationDialog,
AutoNumberingRemovalDialog: () => AutoNumberingRemovalDialog
});
var import_obsidian2, AutoNumberingRemovalDialog, AutoNumberingActivationDialog;
var init_dialogs = __esm({
"src/dialogs.ts"() {
import_obsidian2 = require("obsidian");
init_i18n();
init_core();
init_config();
AutoNumberingRemovalDialog = class extends import_obsidian2.Modal {
constructor(app, plugin, onConfirm) {
super(app);
this.progressContainer = null;
this.isProcessing = false;
this.plugin = plugin;
this.onConfirm = onConfirm;
this.setTitle("Auto Numbering Settings");
}
onOpen() {
const i18n = I18n.getInstance();
const { contentEl } = this;
contentEl.empty();
contentEl.addClass("header-enhancer-removal-dialog");
contentEl.createEl("h2", {
text: i18n.t("settings.autoNumbering.removeConfirmation.title"),
cls: "modal-title"
});
contentEl.createEl("p", {
text: i18n.t("settings.autoNumbering.removeConfirmation.message"),
cls: "modal-message"
});
const actionsEl = contentEl.createDiv({ cls: "modal-actions" });
const removeAndTurnOffSetting = new import_obsidian2.Setting(actionsEl).setName(i18n.t("settings.autoNumbering.removeConfirmation.removeAndTurnOff")).setDesc(i18n.t("settings.autoNumbering.removeConfirmation.removeAndTurnOffDesc")).addButton((button) => {
button.setButtonText(i18n.t("settings.autoNumbering.removeConfirmation.removeAndTurnOff")).setCta().onClick(async () => {
if (!this.isProcessing) {
await this.handleRemoveAndTurnOff();
}
});
});
const warningEl = removeAndTurnOffSetting.descEl.createDiv({ cls: "setting-item-warning" });
warningEl.createEl("span", {
text: i18n.t("settings.autoNumbering.removeConfirmation.warningTitle") + " ",
cls: "warning-label"
});
warningEl.createEl("span", {
text: i18n.t("settings.autoNumbering.removeConfirmation.warningMessage"),
cls: "warning-text"
});
const manualTipEl = removeAndTurnOffSetting.descEl.createDiv({ cls: "setting-item-tip" });
manualTipEl.createEl("span", {
text: i18n.t("settings.autoNumbering.removeConfirmation.manualTip"),
cls: "manual-tip-text"
});
new import_obsidian2.Setting(actionsEl).setName(i18n.t("settings.autoNumbering.removeConfirmation.turnOffOnly")).setDesc(i18n.t("settings.autoNumbering.removeConfirmation.turnOffOnlyDesc")).addButton((button) => {
button.setButtonText(i18n.t("settings.autoNumbering.removeConfirmation.turnOffOnly")).onClick(async () => {
if (!this.isProcessing) {
await this.handleTurnOffOnly();
}
});
});
const cancelButtonEl = actionsEl.createDiv({ cls: "modal-cancel" });
new import_obsidian2.Setting(cancelButtonEl).addButton((button) => {
button.setButtonText(i18n.t("settings.autoNumbering.removeConfirmation.cancel")).onClick(() => {
if (!this.isProcessing) {
this.close();
}
});
});
this.progressContainer = contentEl.createDiv({
cls: "progress-container",
attr: { style: "display: none;" }
});
}
async handleRemoveAndTurnOff() {
this.isProcessing = true;
try {
this.showProgress();
await this.removeAllHeaderNumbers();
await this.onConfirm(true);
this.close();
} catch (error) {
const i18n = I18n.getInstance();
new import_obsidian2.Notice(i18n.t("settings.autoNumbering.removeConfirmation.error", {
error: error.message
}));
this.hideProgress();
} finally {
this.isProcessing = false;
}
}
async handleTurnOffOnly() {
this.isProcessing = true;
try {
await this.onConfirm(false);
this.close();
} finally {
this.isProcessing = false;
}
}
showProgress() {
const i18n = I18n.getInstance();
if (this.progressContainer) {
this.progressContainer.style.display = "block";
this.progressContainer.empty();
this.progressContainer.createEl("p", {
text: i18n.t("settings.autoNumbering.removeConfirmation.processing"),
cls: "progress-text"
});
}
this.contentEl.querySelectorAll("button").forEach((button) => {
button.setAttribute("disabled", "true");
});
}
hideProgress() {
if (this.progressContainer) {
this.progressContainer.style.display = "none";
this.progressContainer.empty();
}
this.contentEl.querySelectorAll("button").forEach((button) => {
button.removeAttribute("disabled");
});
}
async removeAllHeaderNumbers() {
const i18n = I18n.getInstance();
const markdownFiles = this.app.vault.getMarkdownFiles();
let processedCount = 0;
let modifiedCount = 0;
const batchSize = 5;
const totalFiles = markdownFiles.length;
for (let batchStart = 0; batchStart < totalFiles; batchStart += batchSize) {
const batch = markdownFiles.slice(batchStart, Math.min(batchStart + batchSize, totalFiles));
for (const file of batch) {
try {
const modified = await this.processFile(file);
if (modified) {
modifiedCount++;
await new Promise((resolve) => setTimeout(resolve, 10));
}
processedCount++;
this.updateProgress(processedCount, totalFiles);
} catch (error) {
console.error(`Error processing file ${file.path}:`, error);
}
await new Promise((resolve) => setTimeout(resolve, 5));
}
await new Promise((resolve) => setTimeout(resolve, 50));
}
if (modifiedCount > 0) {
new import_obsidian2.Notice(i18n.t("settings.autoNumbering.removeConfirmation.completed", {
count: modifiedCount.toString()
}));
} else {
new import_obsidian2.Notice(i18n.t("settings.autoNumbering.removeConfirmation.noNumberingFound"));
}
}
async processFile(file) {
try {
const activeLeaves = this.app.workspace.getLeavesOfType("markdown");
const isCurrentlyOpen = activeLeaves.some((leaf) => {
const view = leaf.view;
return view.file && view.file.path === file.path;
});
const content = await this.app.vault.read(file);
const lines = content.split("\n");
let modified = false;
let isInCodeBlock = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith("```")) {
isInCodeBlock = !isInCodeBlock;
continue;
}
if (isInCodeBlock) {
continue;
}
if (isHeader(line)) {
const newLine = removeHeaderNumber(line, this.plugin.settings.autoNumberingHeaderSeparator);
if (newLine !== line) {
lines[i] = newLine;
modified = true;
}
}
}
if (modified) {
await this.app.vault.modify(file, lines.join("\n"));
if (isCurrentlyOpen) {
await new Promise((resolve) => setTimeout(resolve, 20));
}
if (this.plugin.settings.updateBacklinks) {
}
}
return modified;
} catch (error) {
console.error(`Error processing file ${file.path}:`, error);
return false;
}
}
updateProgress(current, total) {
const i18n = I18n.getInstance();
if (this.progressContainer) {
const progressText = this.progressContainer.querySelector(".progress-text");
if (progressText) {
progressText.textContent = i18n.t("settings.autoNumbering.removeConfirmation.progressStatus", {
current: current.toString(),
total: total.toString()
});
}
}
}
onClose() {
this.isProcessing = false;
}
};
AutoNumberingActivationDialog = class extends import_obsidian2.Modal {
constructor(app, plugin, onConfirm) {
super(app);
this.progressContainer = null;
this.isProcessing = false;
this.plugin = plugin;
this.onConfirm = onConfirm;
this.setTitle("Auto Numbering Settings");
}
onOpen() {
const i18n = I18n.getInstance();
const { contentEl } = this;
contentEl.empty();
contentEl.addClass("header-enhancer-activation-dialog");
contentEl.createEl("h2", {
text: i18n.t("settings.autoNumbering.activationConfirmation.title"),
cls: "modal-title"
});
contentEl.createEl("p", {
text: i18n.t("settings.autoNumbering.activationConfirmation.message"),
cls: "modal-message"
});
const actionsEl = contentEl.createDiv({ cls: "modal-actions" });
const addToAllSetting = new import_obsidian2.Setting(actionsEl).setName(i18n.t("settings.autoNumbering.activationConfirmation.addToAll")).setDesc(i18n.t("settings.autoNumbering.activationConfirmation.addToAllDesc")).addButton((button) => {
button.setButtonText(i18n.t("settings.autoNumbering.activationConfirmation.addToAll")).setCta().onClick(async () => {
if (!this.isProcessing) {
await this.handleAddToAll();
}
});
});
const warningEl = addToAllSetting.descEl.createDiv({ cls: "setting-item-warning" });
warningEl.createEl("span", {
text: i18n.t("settings.autoNumbering.activationConfirmation.warningTitle") + " ",
cls: "warning-label"
});
warningEl.createEl("span", {
text: i18n.t("settings.autoNumbering.activationConfirmation.warningMessage"),
cls: "warning-text"
});
const tipEl = addToAllSetting.descEl.createDiv({ cls: "setting-item-tip" });
tipEl.createEl("span", {
text: i18n.t("settings.autoNumbering.activationConfirmation.manualTip"),
cls: "manual-tip-text"
});
new import_obsidian2.Setting(actionsEl).setName(i18n.t("settings.autoNumbering.activationConfirmation.turnOnOnly")).setDesc(i18n.t("settings.autoNumbering.activationConfirmation.turnOnOnlyDesc")).addButton((button) => {
button.setButtonText(i18n.t("settings.autoNumbering.activationConfirmation.turnOnOnly")).onClick(async () => {
if (!this.isProcessing) {
await this.handleTurnOnOnly();
}
});
});
const cancelButtonEl = actionsEl.createDiv({ cls: "modal-cancel" });
new import_obsidian2.Setting(cancelButtonEl).addButton((button) => {
button.setButtonText(i18n.t("settings.autoNumbering.activationConfirmation.cancel")).onClick(() => {
if (!this.isProcessing) {
this.close();
}
});
});
this.progressContainer = contentEl.createDiv({
cls: "progress-container",
attr: { style: "display: none;" }
});
}
async handleAddToAll() {
this.isProcessing = true;
try {
this.showProgress();
await this.addHeaderNumbersToAllFiles();
await this.onConfirm(true);
this.close();
} catch (error) {
const i18n = I18n.getInstance();
new import_obsidian2.Notice(i18n.t("settings.autoNumbering.activationConfirmation.error", {
error: error.message
}));
this.hideProgress();
} finally {
this.isProcessing = false;
}
}
async handleTurnOnOnly() {
this.isProcessing = true;
try {
await this.onConfirm(false);
this.close();
} finally {
this.isProcessing = false;
}
}
showProgress() {
const i18n = I18n.getInstance();
if (this.progressContainer) {
this.progressContainer.style.display = "block";
this.progressContainer.empty();
this.progressContainer.createEl("p", {
text: i18n.t("settings.autoNumbering.activationConfirmation.processing"),
cls: "progress-text"
});
}
this.contentEl.querySelectorAll("button").forEach((button) => {
button.setAttribute("disabled", "true");
});
}
hideProgress() {
if (this.progressContainer) {
this.progressContainer.style.display = "none";
this.progressContainer.empty();
}
this.contentEl.querySelectorAll("button").forEach((button) => {
button.removeAttribute("disabled");
});
}
async addHeaderNumbersToAllFiles() {
const i18n = I18n.getInstance();
const markdownFiles = this.app.vault.getMarkdownFiles();
let processedCount = 0;
let modifiedCount = 0;
const batchSize = 5;
const totalFiles = markdownFiles.length;
for (let batchStart = 0; batchStart < totalFiles; batchStart += batchSize) {
const batch = markdownFiles.slice(batchStart, Math.min(batchStart + batchSize, totalFiles));
for (const file of batch) {
try {
const modified = await this.processFile(file);
if (modified) {
modifiedCount++;
await new Promise((resolve) => setTimeout(resolve, 10));
}
processedCount++;
this.updateProgress(processedCount, totalFiles);
} catch (error) {
console.error(`Error processing file ${file.path}:`, error);
}
await new Promise((resolve) => setTimeout(resolve, 5));
}
await new Promise((resolve) => setTimeout(resolve, 50));
}
if (modifiedCount > 0) {
new import_obsidian2.Notice(i18n.t("settings.autoNumbering.activationConfirmation.completed", {
count: modifiedCount.toString()
}));
} else {
new import_obsidian2.Notice(i18n.t("settings.autoNumbering.activationConfirmation.noHeadersFound"));
}
}
async processFile(file) {
var _a;
try {
const activeLeaves = this.app.workspace.getLeavesOfType("markdown");
const isCurrentlyOpen = activeLeaves.some((leaf) => {
const view = leaf.view;
return view.file && view.file.path === file.path;
});
const content = await this.app.vault.read(file);
const lines = content.split("\n");
let modified = false;
const mockEditor = {
getValue: () => content,
lineCount: () => lines.length,
getLine: (n) => lines[n] || ""
};
const config = getAutoNumberingConfig(this.plugin.settings, mockEditor);
config.state = true;
let insertNumber = [Number(config.startNumber) - 1];
let isInCodeBlock = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith("```")) {
isInCodeBlock = !isInCodeBlock;
if (line.slice(3).contains("```")) {
isInCodeBlock = !isInCodeBlock;
}
}
if (isInCodeBlock) {
continue;
}
if (isHeader(line)) {
const headerLevel = ((_a = line.match(/^#+/)) == null ? void 0 : _a[0].length) || 0;
if (headerLevel < config.startLevel || headerLevel > config.endLevel) {
continue;
}
const adjustedLevel = headerLevel - config.startLevel + 1;
insertNumber = getNextNumber(insertNumber, adjustedLevel);
const insertNumberStr = insertNumber.join(config.separator);
if (!line.includes(this.plugin.settings.autoNumberingHeaderSeparator)) {
const newLine = "#".repeat(headerLevel) + " " + insertNumberStr + this.plugin.settings.autoNumberingHeaderSeparator + line.substring(headerLevel + 1);
if (newLine !== line) {
lines[i] = newLine;
modified = true;
}
}
}
}
if (modified) {
await this.app.vault.modify(file, lines.join("\n"));
if (isCurrentlyOpen) {
await new Promise((resolve) => setTimeout(resolve, 20));
}
}
return modified;
} catch (error) {
console.error(`Error processing file ${file.path}:`, error);
return false;
}
}
updateProgress(current, total) {
const i18n = I18n.getInstance();
if (this.progressContainer) {
const progressText = this.progressContainer.querySelector(".progress-text");
if (progressText) {
progressText.textContent = i18n.t("settings.autoNumbering.activationConfirmation.progressStatus", {
current: current.toString(),
total: total.toString()
});
}
}
}
onClose() {
this.isProcessing = false;
}
};
}
});
// src/setting.ts
var import_obsidian3, DEFAULT_SETTINGS, HeaderEnhancerSettingTab;
var init_setting = __esm({
"src/setting.ts"() {
import_obsidian3 = require("obsidian");
init_i18n();
init_core();
DEFAULT_SETTINGS = {
language: "en",
showOnStatusBar: true,
showOnSidebar: true,
isAutoDetectHeaderLevel: false,
// 自动检测文档中的标题层级功能
startHeaderLevel: 1,
endHeaderLevel: 6,
autoNumberingMode: "on" /* ON */,
autoNumberingStartNumber: "1",
autoNumberingSeparator: ".",
autoNumberingHeaderSeparator: " ",
updateBacklinks: false,
// YAML mode specific settings
yamlFallbackMode: "use_default" /* USE_DEFAULT */,
yamlDefaultStartLevel: 2,
yamlDefaultEndLevel: 6,
yamlDefaultStartNumber: "1",
yamlDefaultSeparator: ".",
// Global function enablement - enabled by default for backward compatibility
globalAutoNumberingEnabled: true,
// Per-document state management - empty object as JSON string
perDocumentStates: "{}",
// Header font settings
isSeparateHeaderFont: false,
headerFontFamily: "inherit",
headerFontSize: "inherit",
// Title font settings
isSeparateTitleFont: false,
titleFontFamily: "inherit",
titleFontSize: "inherit"
};
HeaderEnhancerSettingTab = class extends import_obsidian3.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.formatPreviewSetting = null;
this.autoDetectionPreviewContainer = null;
this.plugin = plugin;
}
display() {
const { containerEl } = this;
const i18n = I18n.getInstance();
containerEl.empty();
this.formatPreviewSetting = null;
this.autoDetectionPreviewContainer = null;
containerEl.createEl("h1", { text: i18n.t("settings.title") });
containerEl.createEl("h2", { text: i18n.t("settings.general") });
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.language.name")).setDesc(i18n.t("settings.language.desc")).addDropdown((dropdown) => {
dropdown.addOption("en", "English");
dropdown.addOption("zh", "\u4E2D\u6587");
dropdown.setValue(this.plugin.settings.language);
dropdown.onChange(async (value) => {
this.plugin.settings.language = value;
i18n.setLanguage(value);
await this.plugin.saveSettings();
this.plugin.handleShowStateBarChange();
this.display();
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.statusBar.name")).setDesc(i18n.t("settings.statusBar.desc")).addToggle((toggle) => {
toggle.setValue(this.plugin.settings.showOnStatusBar).onChange(async (value) => {
this.plugin.settings.showOnStatusBar = value;
await this.plugin.saveSettings();
this.plugin.handleShowStateBarChange();
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.sidebar.name")).setDesc(i18n.t("settings.sidebar.desc")).addToggle((toggle) => {
toggle.setValue(this.plugin.settings.showOnSidebar).onChange(async (value) => {
this.plugin.settings.showOnSidebar = value;
await this.plugin.saveSettings();
this.plugin.handleShowSidebarChange();
});
});
containerEl.createEl("h2", { text: i18n.t("settings.autoNumbering.title") });
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.autoNumbering.globalToggle.name")).setDesc(i18n.t("settings.autoNumbering.globalToggle.desc")).addToggle((toggle) => {
toggle.setValue(this.plugin.settings.globalAutoNumberingEnabled).onChange(async (value) => {
this.plugin.settings.globalAutoNumberingEnabled = value;
await this.plugin.saveSettings();
this.plugin.handleShowStateBarChange();
this.plugin.updateRibbonIconState();
this.display();
});
});
if (!this.plugin.settings.globalAutoNumberingEnabled) {
const globalDisabledInfo = containerEl.createDiv({
cls: "header-enhancer-global-disabled-info"
});
globalDisabledInfo.style.cssText = `
margin: 1.5em 0;
padding: 1.2em;
border: 2px solid var(--text-muted);
border-radius: 8px;
background: var(--background-secondary);
opacity: 0.8;
`;
globalDisabledInfo.innerHTML = `
${i18n.t("settings.autoNumbering.globalDisabled.title")}
${i18n.t("settings.autoNumbering.globalDisabled.description")}
`;
return;
}
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.autoNumbering.mode.name")).setDesc(i18n.t("settings.autoNumbering.mode.desc")).addDropdown((dropdown) => {
dropdown.addOption("off" /* OFF */, i18n.t("settings.autoNumbering.mode.off"));
dropdown.addOption("on" /* ON */, i18n.t("settings.autoNumbering.mode.on"));
dropdown.addOption("yaml" /* YAML_CONTROLLED */, i18n.t("settings.autoNumbering.mode.yaml"));
dropdown.setValue(this.plugin.settings.autoNumberingMode);
dropdown.onChange(async (value) => {
const newMode = value;
if ((this.plugin.settings.autoNumberingMode === "on" /* ON */ || this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */) && newMode === "off" /* OFF */) {
const { AutoNumberingRemovalDialog: AutoNumberingRemovalDialog2 } = await Promise.resolve().then(() => (init_dialogs(), dialogs_exports));
const dialog = new AutoNumberingRemovalDialog2(
this.app,
this.plugin,
async (removeExisting) => {
this.plugin.settings.autoNumberingMode = "off" /* OFF */;
await this.plugin.saveSettings();
this.plugin.handleShowStateBarChange();
this.plugin.updateRibbonIconState();
this.display();
}
);
dialog.open();
dropdown.setValue(this.plugin.settings.autoNumberingMode);
} else if (this.plugin.settings.autoNumberingMode === "off" /* OFF */ && newMode === "on" /* ON */) {
const { AutoNumberingActivationDialog: AutoNumberingActivationDialog2 } = await Promise.resolve().then(() => (init_dialogs(), dialogs_exports));
const dialog = new AutoNumberingActivationDialog2(
this.app,
this.plugin,
async (addToAll) => {
this.plugin.settings.autoNumberingMode = newMode;
await this.plugin.saveSettings();
this.plugin.handleShowStateBarChange();
this.plugin.updateRibbonIconState();
this.display();
}
);
dialog.open();
dropdown.setValue(this.plugin.settings.autoNumberingMode);
} else {
this.plugin.settings.autoNumberingMode = newMode;
await this.plugin.saveSettings();
this.plugin.handleShowStateBarChange();
this.plugin.updateRibbonIconState();
this.display();
}
});
});
if (this.plugin.settings.autoNumberingMode === "on" /* ON */) {
this.renderAutoNumberingSettings(containerEl);
} else if (this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */) {
this.renderYamlModeSettings(containerEl);
} else {
const offInfo = containerEl.createDiv({
cls: "header-enhancer-off-info"
});
offInfo.style.cssText = `
margin: 1.5em 0;
padding: 1.2em;
border: 2px solid var(--text-muted);
border-radius: 8px;
background: var(--background-secondary);
opacity: 0.8;
`;
offInfo.innerHTML = `
${i18n.t("autoDetection.info.offMode.title")}
${i18n.t("autoDetection.info.offMode.description")}
`;
}
containerEl.createEl("h2", { text: i18n.t("settings.headerFont.title") });
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.headerFont.separate.name")).setDesc(i18n.t("settings.headerFont.separate.desc")).addToggle((toggle) => {
toggle.setValue(this.plugin.settings.isSeparateHeaderFont).onChange(async (value) => {
this.plugin.settings.isSeparateHeaderFont = value;
await this.plugin.saveSettings();
this.plugin.styleManager.applyCSSStyles();
this.display();
});
});
if (this.plugin.settings.isSeparateHeaderFont) {
const previewContainer = containerEl.createDiv({ cls: "header-enhancer-font-preview" });
previewContainer.style.cssText = `
margin: 1em 0;
padding: 1em;
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
background: var(--background-secondary);
`;
previewContainer.createEl("div", {
text: i18n.t("settings.headerFont.preview.title"),
cls: "setting-item-name"
});
const previewContent = previewContainer.createDiv({ cls: "font-preview-content" });
for (let i = 1; i <= 3; i++) {
const tagName = i === 1 ? "h1" : i === 2 ? "h2" : "h3";
const headerEl = previewContent.createEl(tagName, {
text: `${i18n.t("settings.headerFont.preview.sample")} ${i}`,
cls: "header-enhancer-preview-header"
});
this.updateHeaderPreviewStyles(headerEl);
}
}
this.createFontFamilySetting(containerEl, "header");
this.createFontSizeSetting(containerEl, "header");
containerEl.createEl("h2", { text: i18n.t("settings.titleFont.title") });
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.titleFont.separate.name")).setDesc(i18n.t("settings.titleFont.separate.desc")).addToggle((toggle) => {
toggle.setValue(this.plugin.settings.isSeparateTitleFont).onChange(async (value) => {
this.plugin.settings.isSeparateTitleFont = value;
await this.plugin.saveSettings();
this.plugin.styleManager.applyCSSStyles();
this.display();
});
});
if (this.plugin.settings.isSeparateTitleFont) {
const previewContainer = containerEl.createDiv({ cls: "header-enhancer-title-font-preview" });
previewContainer.style.cssText = `
margin: 1em 0;
padding: 1em;
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
background: var(--background-secondary);
`;
previewContainer.createEl("div", {
text: i18n.t("settings.titleFont.preview.title"),
cls: "setting-item-name"
});
const previewContent = previewContainer.createDiv({ cls: "font-preview-content" });
const titleEl = previewContent.createEl("div", {
text: i18n.t("settings.titleFont.preview.sample"),
cls: "header-enhancer-preview-title"
});
titleEl.style.cssText = "font-size: 1.5em; font-weight: bold; margin: 0.5em 0;";
this.updateTitlePreviewStyles(titleEl);
}
this.createFontFamilySetting(containerEl, "title");
this.createFontSizeSetting(containerEl, "title");
new import_obsidian3.Setting(containerEl).addButton((button) => {
button.setButtonText(i18n.t("settings.resetSettings.name")).onClick(async () => {
if (confirm(
i18n.t("settings.resetSettings.confirm")
)) {
this.plugin.settings = DEFAULT_SETTINGS;
await this.plugin.saveSettings();
this.display();
}
});
});
containerEl.createEl("h2", { text: i18n.t("settings.moreInfo") });
containerEl.createEl("p", { text: i18n.t("settings.author") }).createEl("a", {
text: "Hobee Liu",
href: "https://github.com/HoBeedzc"
});
containerEl.createEl("p", { text: i18n.t("settings.license") }).createEl("a", {
text: "MIT",
href: "https://github.com/HoBeedzc/obsidian-header-enhancer-plugin/blob/master/LICENSE"
});
containerEl.createEl("p", { text: i18n.t("settings.githubRepo") }).createEl("a", {
text: "obsidian-header-enhancer",
href: "https://github.com/HoBeedzc/obsidian-header-enhancer-plugin"
});
containerEl.createEl("p", { text: i18n.t("settings.anyQuestion") }).createEl("a", {
text: "Github Issues",
href: "https://github.com/HoBeedzc/obsidian-header-enhancer-plugin/issues"
});
}
/**
* 渲染自动编号相关的设置项
*/
renderAutoNumberingSettings(containerEl) {
const i18n = I18n.getInstance();
const headerLevelSetting = new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.autoNumbering.headerLevel.name"));
const updateSettingDesc = () => {
if (this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */) {
headerLevelSetting.setDesc(i18n.t("settings.autoNumbering.headerLevel.desc.yamlControl"));
} else if (this.plugin.settings.isAutoDetectHeaderLevel && this.plugin.settings.autoNumberingMode === "on" /* ON */) {
headerLevelSetting.setDesc(i18n.t("settings.autoNumbering.headerLevel.desc.autoDetect"));
} else {
headerLevelSetting.setDesc(i18n.t("settings.autoNumbering.headerLevel.desc.manual"));
}
};
updateSettingDesc();
headerLevelSetting.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.isAutoDetectHeaderLevel).onChange(async (value) => {
this.plugin.settings.isAutoDetectHeaderLevel = value;
await this.plugin.saveSettings();
updateSettingDesc();
this.display();
}).setDisabled(this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */);
});
if (this.plugin.settings.isAutoDetectHeaderLevel && this.plugin.settings.autoNumberingMode === "on" /* ON */) {
this.autoDetectionPreviewContainer = containerEl.createDiv({
cls: "header-enhancer-auto-detection-preview"
});
this.autoDetectionPreviewContainer.style.cssText = `
margin: 1em 0;
padding: 1.2em;
border: 2px solid var(--color-green);
border-radius: 8px;
background: var(--background-secondary);
position: relative;
`;
const previewTitle2 = this.autoDetectionPreviewContainer.createDiv();
previewTitle2.style.cssText = `
font-weight: 600;
font-size: 1em;
color: var(--color-green);
margin-bottom: 0.8em;
display: flex;
align-items: center;
`;
previewTitle2.innerHTML = "\u{1F527} \u667A\u80FD\u68C0\u6D4B\u7ED3\u679C";
this.updateAutoDetectionPreview();
} else {
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.headerLevel.start.name")).setDesc(i18n.t("settings.headerLevel.start.desc")).addDropdown((dropdown) => {
dropdown.addOption("1", "H1");
dropdown.addOption("2", "H2");
dropdown.addOption("3", "H3");
dropdown.addOption("4", "H4");
dropdown.addOption("5", "H5");
dropdown.addOption("6", "H6");
dropdown.setValue(
this.plugin.settings.startHeaderLevel.toString()
);
dropdown.setDisabled(this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */);
dropdown.onChange(async (value) => {
if (this.checkStartLevel(parseInt(value, 10))) {
this.plugin.settings.startHeaderLevel = parseInt(value, 10);
await this.plugin.saveSettings();
this.updateFormatPreview();
} else {
new import_obsidian3.Notice(
i18n.t("settings.autoNumbering.startLevelError")
);
dropdown.setValue(this.plugin.settings.startHeaderLevel.toString());
}
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.headerLevel.max.name")).setDesc(i18n.t("settings.headerLevel.max.desc")).addDropdown((dropdown) => {
dropdown.addOption("1", "H1");
dropdown.addOption("2", "H2");
dropdown.addOption("3", "H3");
dropdown.addOption("4", "H4");
dropdown.addOption("5", "H5");
dropdown.addOption("6", "H6");
dropdown.setValue(
this.plugin.settings.endHeaderLevel.toString()
);
dropdown.setDisabled(this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */);
dropdown.onChange(async (value) => {
if (this.checkEndLevel(parseInt(value, 10))) {
this.plugin.settings.endHeaderLevel = parseInt(
value,
10
);
await this.plugin.saveSettings();
this.updateFormatPreview();
} else {
new import_obsidian3.Notice(
i18n.t("settings.autoNumbering.endLevelError")
);
dropdown.setValue(this.plugin.settings.endHeaderLevel.toString());
}
});
});
}
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.autoNumbering.startNumber.name")).setDesc(i18n.t("settings.autoNumbering.startNumber.desc")).addDropdown((dropdown) => {
dropdown.addOption("0", "0");
dropdown.addOption("1", "1");
dropdown.setValue(this.plugin.settings.autoNumberingStartNumber);
dropdown.setDisabled(this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */);
dropdown.onChange(async (value) => {
this.plugin.settings.autoNumberingStartNumber = value;
await this.plugin.saveSettings();
this.updateFormatPreview();
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.autoNumbering.separator.name")).setDesc(i18n.t("settings.autoNumbering.separator.desc")).addDropdown((dropdown) => {
dropdown.addOption(".", ".");
dropdown.addOption(",", ",");
dropdown.addOption("-", "-");
dropdown.addOption("/", "/");
dropdown.setValue(this.plugin.settings.autoNumberingSeparator);
dropdown.setDisabled(this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */);
dropdown.onChange(async (value) => {
this.plugin.settings.autoNumberingSeparator = value;
await this.plugin.saveSettings();
this.updateFormatPreview();
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.autoNumbering.headerSeparator.name")).setDesc(i18n.t("settings.autoNumbering.headerSeparator.desc")).addDropdown((dropdown) => {
dropdown.addOption(" ", "Tab");
dropdown.addOption(" ", "Space");
dropdown.setValue(
this.plugin.settings.autoNumberingHeaderSeparator
);
dropdown.setDisabled(this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */);
dropdown.onChange(async (value) => {
this.plugin.settings.autoNumberingHeaderSeparator = value;
await this.plugin.saveSettings();
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.autoNumbering.updateBacklinks.name")).setDesc(i18n.t("settings.autoNumbering.updateBacklinks.desc")).addToggle((toggle) => {
toggle.setValue(this.plugin.settings.updateBacklinks).onChange(async (value) => {
this.plugin.settings.updateBacklinks = value;
await this.plugin.saveSettings();
}).setDisabled(this.plugin.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */);
});
const formatPreviewContainer = containerEl.createDiv({
cls: "header-enhancer-format-preview-container"
});
formatPreviewContainer.style.cssText = `
margin: 1.5em 0;
`;
const previewTitle = formatPreviewContainer.createDiv();
previewTitle.style.cssText = `
font-weight: 600;
font-size: 1.1em;
color: var(--text-accent);
margin-bottom: 1em;
display: flex;
align-items: center;
gap: 0.5em;
`;
previewTitle.innerHTML = `\u{1F3AF} ${i18n.t("settings.autoNumbering.format.name")}`;
const previewContent = formatPreviewContainer.createDiv({
cls: "format-preview-content"
});
this.formatPreviewSetting = {
setDesc: (content) => {
previewContent.innerHTML = content;
}
};
previewContent.innerHTML = this.getFormatPreview();
}
/**
* Create font family setting for header or title
*/
createFontFamilySetting(containerEl, type) {
const i18n = I18n.getInstance();
const isHeader2 = type === "header";
const settingsKey = isHeader2 ? "settings.headerFont" : "settings.titleFont";
new import_obsidian3.Setting(containerEl).setName(i18n.t(`${settingsKey}.family.name`)).setDesc(i18n.t(`${settingsKey}.family.desc`)).addDropdown((dropdown) => {
dropdown.addOption("inherit", i18n.t(`${settingsKey}.family.options.inherit`));
dropdown.addOption("Arial, sans-serif", "Arial");
dropdown.addOption("Helvetica, Arial, sans-serif", "Helvetica");
dropdown.addOption("Verdana, Geneva, sans-serif", "Verdana");
dropdown.addOption("Tahoma, Geneva, sans-serif", "Tahoma");
dropdown.addOption("'Trebuchet MS', Helvetica, sans-serif", "Trebuchet MS");
dropdown.addOption("'Lucida Sans Unicode', 'Lucida Grande', sans-serif", "Lucida Sans");
dropdown.addOption("Impact, Charcoal, sans-serif", "Impact");
dropdown.addOption("'Comic Sans MS', cursive", "Comic Sans MS");
dropdown.addOption("'Times New Roman', Times, serif", "Times New Roman");
dropdown.addOption("Georgia, serif", "Georgia");
dropdown.addOption("'Palatino Linotype', 'Book Antiqua', Palatino, serif", "Palatino");
dropdown.addOption("Garamond, serif", "Garamond");
dropdown.addOption("'Book Antiqua', Palatino, serif", "Book Antiqua");
dropdown.addOption("'Courier New', Courier, monospace", "Courier New");
dropdown.addOption("Consolas, 'Liberation Mono', monospace", "Consolas");
dropdown.addOption("Monaco, 'Lucida Console', monospace", "Monaco");
dropdown.addOption("'JetBrains Mono', Consolas, monospace", "JetBrains Mono");
dropdown.addOption("'Fira Code', Consolas, monospace", "Fira Code");
dropdown.addOption("Menlo, Monaco, monospace", "Menlo");
dropdown.addOption("'Microsoft YaHei', '\u5FAE\u8F6F\u96C5\u9ED1', Arial, sans-serif", "Microsoft YaHei (\u5FAE\u8F6F\u96C5\u9ED1)");
dropdown.addOption("'PingFang SC', '\u82F9\u65B9-\u7B80', 'Helvetica Neue', Arial, sans-serif", "PingFang SC (\u82F9\u65B9-\u7B80)");
dropdown.addOption("'Hiragino Sans GB', '\u51AC\u9752\u9ED1\u4F53\u7B80\u4F53\u4E2D\u6587', 'Microsoft YaHei', sans-serif", "Hiragino Sans GB (\u51AC\u9752\u9ED1\u4F53)");
dropdown.addOption("'Source Han Sans SC', '\u601D\u6E90\u9ED1\u4F53 CN', 'Noto Sans CJK SC', sans-serif", "Source Han Sans SC (\u601D\u6E90\u9ED1\u4F53)");
dropdown.addOption("'Noto Sans SC', '\u601D\u6E90\u9ED1\u4F53', sans-serif", "Noto Sans SC");
dropdown.addOption("SimHei, '\u9ED1\u4F53', sans-serif", "SimHei (\u9ED1\u4F53)");
dropdown.addOption("'WenQuanYi Micro Hei', '\u6587\u6CC9\u9A7F\u5FAE\u7C73\u9ED1', sans-serif", "WenQuanYi Micro Hei (\u6587\u6CC9\u9A7F\u5FAE\u7C73\u9ED1)");
dropdown.addOption("'Songti SC', '\u5B8B\u4F53-\u7B80', SimSun, serif", "Songti SC (\u5B8B\u4F53-\u7B80)");
dropdown.addOption("SimSun, '\u5B8B\u4F53', serif", "SimSun (\u5B8B\u4F53)");
dropdown.addOption("'Source Han Serif SC', '\u601D\u6E90\u5B8B\u4F53 CN', 'Noto Serif CJK SC', serif", "Source Han Serif SC (\u601D\u6E90\u5B8B\u4F53)");
dropdown.addOption("'Noto Serif SC', '\u601D\u6E90\u5B8B\u4F53', serif", "Noto Serif SC");
dropdown.addOption("'STSong', '\u534E\u6587\u5B8B\u4F53', SimSun, serif", "STSong (\u534E\u6587\u5B8B\u4F53)");
dropdown.addOption("'FangSong', '\u4EFF\u5B8B', serif", "FangSong (\u4EFF\u5B8B)");
dropdown.addOption("system-ui, -apple-system, sans-serif", "System UI");
dropdown.addOption("-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", "System Default");
dropdown.addOption("'PingFang SC', 'Microsoft YaHei', 'Hiragino Sans GB', Arial, sans-serif", "\u4E2D\u82F1\u6587\u65E0\u886C\u7EBF\u6DF7\u5408");
dropdown.addOption("'Songti SC', 'Source Han Serif SC', 'Times New Roman', serif", "\u4E2D\u82F1\u6587\u886C\u7EBF\u6DF7\u5408");
const currentValue = isHeader2 ? this.plugin.settings.headerFontFamily : this.plugin.settings.titleFontFamily;
const isEnabled = isHeader2 ? this.plugin.settings.isSeparateHeaderFont : this.plugin.settings.isSeparateTitleFont;
dropdown.setValue(currentValue);
dropdown.setDisabled(!isEnabled);
dropdown.onChange(async (value) => {
if (isHeader2) {
this.plugin.settings.headerFontFamily = value;
} else {
this.plugin.settings.titleFontFamily = value;
}
await this.plugin.saveSettings();
if (isEnabled) {
this.plugin.styleManager.applyCSSStyles();
if (isHeader2) {
this.updateAllHeaderPreviewStyles();
} else {
this.updateAllTitlePreviewStyles();
}
}
});
});
}
/**
* Create font size setting for header or title
*/
createFontSizeSetting(containerEl, type) {
const i18n = I18n.getInstance();
const isHeader2 = type === "header";
const settingsKey = isHeader2 ? "settings.headerFont" : "settings.titleFont";
new import_obsidian3.Setting(containerEl).setName(i18n.t(`${settingsKey}.size.name`)).setDesc(i18n.t(`${settingsKey}.size.desc`)).addDropdown((dropdown) => {
dropdown.addOption("inherit", i18n.t(`${settingsKey}.size.options.inherit`));
dropdown.addOption("0.8em", i18n.t(`${settingsKey}.size.options.smaller`) + " (0.8em)");
dropdown.addOption("0.9em", i18n.t(`${settingsKey}.size.options.small`) + " (0.9em)");
dropdown.addOption("1em", i18n.t(`${settingsKey}.size.options.normal`) + " (1em)");
dropdown.addOption("1.1em", i18n.t(`${settingsKey}.size.options.large`) + " (1.1em)");
dropdown.addOption("1.2em", i18n.t(`${settingsKey}.size.options.larger`) + " (1.2em)");
dropdown.addOption("1.3em", i18n.t(`${settingsKey}.size.options.xlarge`) + " (1.3em)");
dropdown.addOption("1.5em", i18n.t(`${settingsKey}.size.options.xxlarge`) + " (1.5em)");
dropdown.addOption("12px", "12px");
dropdown.addOption("14px", "14px");
dropdown.addOption("16px", "16px");
dropdown.addOption("18px", "18px");
dropdown.addOption("20px", "20px");
dropdown.addOption("24px", "24px");
dropdown.addOption("28px", "28px");
dropdown.addOption("32px", "32px");
dropdown.addOption("120%", "120%");
dropdown.addOption("140%", "140%");
const currentValue = isHeader2 ? this.plugin.settings.headerFontSize : this.plugin.settings.titleFontSize;
const isEnabled = isHeader2 ? this.plugin.settings.isSeparateHeaderFont : this.plugin.settings.isSeparateTitleFont;
dropdown.setValue(currentValue);
dropdown.setDisabled(!isEnabled);
dropdown.onChange(async (value) => {
if (isHeader2) {
this.plugin.settings.headerFontSize = value;
} else {
this.plugin.settings.titleFontSize = value;
}
await this.plugin.saveSettings();
if (isEnabled) {
this.plugin.styleManager.applyCSSStyles();
if (isHeader2) {
this.updateAllHeaderPreviewStyles();
} else {
this.updateAllTitlePreviewStyles();
}
}
});
});
}
/**
* Update auto detection preview
*/
updateAutoDetectionPreview() {
if (!this.autoDetectionPreviewContainer)
return;
const i18n = I18n.getInstance();
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView);
let contentContainer = this.autoDetectionPreviewContainer.querySelector(".preview-content");
if (!contentContainer) {
contentContainer = this.autoDetectionPreviewContainer.createDiv({
cls: "preview-content"
});
}
if (!activeView) {
contentContainer.innerHTML = `${i18n.t("autoDetection.noActiveDocument")}
`;
this.updateFormatPreview();
return;
}
const content = activeView.editor.getValue();
const analysis = analyzeHeaderLevels(content);
contentContainer.innerHTML = `
${this.formatAnalysisResult(analysis)}
`;
this.updateFormatPreview();
}
/**
* Format analysis result for display
*/
formatAnalysisResult(analysis) {
const i18n = I18n.getInstance();
if (analysis.isEmpty) {
return `
\u{1F4DD} ${i18n.t("autoDetection.noHeaders")}
`;
}
const levelNames = analysis.usedLevels.map((level) => `H${level}`).join(" ");
const mappingInfo = analysis.usedLevels.map(
(level, index) => `H${level}\u2192${index + 1}\u7EA7`
).join(" ");
return `
${i18n.t("autoDetection.detected")}:
${levelNames}
${i18n.t("autoDetection.range")}:
H${analysis.minLevel} - H${analysis.maxLevel}
${i18n.t("autoDetection.mapping")}:
${mappingInfo}
${i18n.t("autoDetection.totalHeaders")}:
${analysis.headerCount}
`;
}
/**
* Get format preview string
*/
getFormatPreview() {
const i18n = I18n.getInstance();
switch (this.plugin.settings.autoNumberingMode) {
case "off" /* OFF */:
return `
\u23F9\uFE0F
${i18n.t("settings.autoNumbering.format.disabled")}
`;
case "yaml" /* YAML_CONTROLLED */:
return `
\u{1F4C4}
${i18n.t("settings.autoNumbering.format.yamlControlled")}
`;
case "on" /* ON */:
default:
const formatExample = this.plugin.settings.autoNumberingStartNumber + this.plugin.settings.autoNumberingSeparator + "1" + this.plugin.settings.autoNumberingSeparator + "1";
let levelInfo;
let statusBadge;
if (this.plugin.settings.isAutoDetectHeaderLevel) {
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView);
if (activeView) {
const content = activeView.editor.getValue();
const analysis = analyzeHeaderLevels(content);
if (!analysis.isEmpty) {
levelInfo = `${i18n.t("settings.autoNumbering.format.fromLevel")} H${analysis.minLevel} ${i18n.t("settings.autoNumbering.format.toLevel")} H${analysis.maxLevel}`;
statusBadge = `${i18n.t("settings.autoNumbering.format.autoDetect")}`;
} else {
levelInfo = i18n.t("autoDetection.noHeaders");
statusBadge = `${i18n.t("settings.autoNumbering.format.autoDetect")}`;
}
} else {
levelInfo = i18n.t("autoDetection.noActiveDocument");
statusBadge = `${i18n.t("settings.autoNumbering.format.autoDetect")}`;
}
} else {
levelInfo = `${i18n.t("settings.autoNumbering.format.fromLevel")} H${this.plugin.settings.startHeaderLevel} ${i18n.t("settings.autoNumbering.format.toLevel")} H${this.plugin.settings.endHeaderLevel}`;
statusBadge = `${i18n.t("settings.autoNumbering.format.manual")}`;
}
return `
\u{1F4CF}
${levelInfo}
${statusBadge}
`;
}
}
/**
* Update format preview
*/
updateFormatPreview() {
if (this.formatPreviewSetting) {
this.formatPreviewSetting.setDesc(this.getFormatPreview());
}
}
/**
* Validation methods
*/
checkEndLevel(maxLevel) {
return this.plugin.settings.startHeaderLevel <= maxLevel;
}
checkStartLevel(startLevel) {
return startLevel <= this.plugin.settings.endHeaderLevel;
}
checkStartNumber(startNumber) {
const reg = /^[0-9]*$/;
return reg.test(startNumber);
}
checkSeparator(separator) {
if (separator.length != 1) {
return false;
}
const separators = [".", ",", "-", "/"];
return separators.includes(separator);
}
checkHeaderSeparator(_separator) {
if (this.plugin.settings.autoNumberingMode === "on" /* ON */) {
return false;
}
return true;
}
/**
* Update preview styles for a single header element
*/
updateHeaderPreviewStyles(headerEl) {
if (this.plugin.settings.headerFontFamily && this.plugin.settings.headerFontFamily !== "inherit") {
headerEl.style.fontFamily = this.plugin.settings.headerFontFamily;
} else {
headerEl.style.fontFamily = "";
}
if (this.plugin.settings.headerFontSize && this.plugin.settings.headerFontSize !== "inherit") {
headerEl.style.fontSize = this.plugin.settings.headerFontSize;
} else {
headerEl.style.fontSize = "";
}
}
/**
* Update preview styles for title element
*/
updateTitlePreviewStyles(titleEl) {
if (this.plugin.settings.titleFontFamily && this.plugin.settings.titleFontFamily !== "inherit") {
titleEl.style.fontFamily = this.plugin.settings.titleFontFamily;
} else {
titleEl.style.fontFamily = "";
}
if (this.plugin.settings.titleFontSize && this.plugin.settings.titleFontSize !== "inherit") {
titleEl.style.fontSize = this.plugin.settings.titleFontSize;
} else {
titleEl.style.fontSize = "";
}
}
/**
* Update preview styles for all preview headers
*/
updateAllHeaderPreviewStyles() {
const previewHeaders = this.containerEl.querySelectorAll(".header-enhancer-preview-header");
previewHeaders.forEach((headerEl) => {
this.updateHeaderPreviewStyles(headerEl);
});
}
/**
* Update preview styles for all preview titles
*/
updateAllTitlePreviewStyles() {
const previewTitles = this.containerEl.querySelectorAll(".header-enhancer-preview-title");
previewTitles.forEach((titleEl) => {
this.updateTitlePreviewStyles(titleEl);
});
}
/**
* 渲染 YAML 模式的设置项
*/
renderYamlModeSettings(containerEl) {
const i18n = I18n.getInstance();
const yamlExample = `["state on", "start-level h${this.plugin.settings.yamlDefaultStartLevel}", "end-level h${this.plugin.settings.yamlDefaultEndLevel}", "start-at ${this.plugin.settings.yamlDefaultStartNumber}", "separator ${this.plugin.settings.yamlDefaultSeparator}"]`;
const yamlInfo = containerEl.createDiv({
cls: "header-enhancer-yaml-info"
});
yamlInfo.style.cssText = `
margin: 1.5em 0;
padding: 1.2em;
border: 2px solid var(--color-blue);
border-radius: 8px;
background: var(--background-secondary);
`;
yamlInfo.innerHTML = `
${i18n.t("autoDetection.info.yamlMode.title")}
${i18n.t("autoDetection.info.yamlMode.description")}
---
header-auto-numbering: ${yamlExample}
---
${i18n.t("autoDetection.info.yamlMode.usage")}
`;
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.yamlMode.fallback.name")).setDesc(i18n.t("settings.yamlMode.fallback.desc")).addDropdown((dropdown) => {
dropdown.addOption("no_numbering" /* NO_NUMBERING */, i18n.t("settings.yamlMode.fallback.noNumbering"));
dropdown.addOption("use_default" /* USE_DEFAULT */, i18n.t("settings.yamlMode.fallback.useDefault"));
dropdown.setValue(this.plugin.settings.yamlFallbackMode);
dropdown.onChange(async (value) => {
this.plugin.settings.yamlFallbackMode = value;
await this.plugin.saveSettings();
this.display();
});
});
if (this.plugin.settings.yamlFallbackMode === "use_default" /* USE_DEFAULT */) {
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.yamlMode.defaultStartLevel.name")).setDesc(i18n.t("settings.yamlMode.defaultStartLevel.desc")).addDropdown((dropdown) => {
dropdown.addOption("1", "H1");
dropdown.addOption("2", "H2");
dropdown.addOption("3", "H3");
dropdown.addOption("4", "H4");
dropdown.addOption("5", "H5");
dropdown.addOption("6", "H6");
dropdown.setValue(this.plugin.settings.yamlDefaultStartLevel.toString());
dropdown.onChange(async (value) => {
const numValue = parseInt(value, 10);
if (numValue <= this.plugin.settings.yamlDefaultEndLevel) {
this.plugin.settings.yamlDefaultStartLevel = numValue;
await this.plugin.saveSettings();
this.display();
} else {
new import_obsidian3.Notice(i18n.t("settings.autoNumbering.startLevelError"));
dropdown.setValue(this.plugin.settings.yamlDefaultStartLevel.toString());
}
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.yamlMode.defaultEndLevel.name")).setDesc(i18n.t("settings.yamlMode.defaultEndLevel.desc")).addDropdown((dropdown) => {
dropdown.addOption("1", "H1");
dropdown.addOption("2", "H2");
dropdown.addOption("3", "H3");
dropdown.addOption("4", "H4");
dropdown.addOption("5", "H5");
dropdown.addOption("6", "H6");
dropdown.setValue(this.plugin.settings.yamlDefaultEndLevel.toString());
dropdown.onChange(async (value) => {
const numValue = parseInt(value, 10);
if (numValue >= this.plugin.settings.yamlDefaultStartLevel) {
this.plugin.settings.yamlDefaultEndLevel = numValue;
await this.plugin.saveSettings();
this.display();
} else {
new import_obsidian3.Notice(i18n.t("settings.autoNumbering.endLevelError"));
dropdown.setValue(this.plugin.settings.yamlDefaultEndLevel.toString());
}
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.yamlMode.defaultStartNumber.name")).setDesc(i18n.t("settings.yamlMode.defaultStartNumber.desc")).addDropdown((dropdown) => {
dropdown.addOption("0", "0");
dropdown.addOption("1", "1");
dropdown.setValue(this.plugin.settings.yamlDefaultStartNumber);
dropdown.onChange(async (value) => {
this.plugin.settings.yamlDefaultStartNumber = value;
await this.plugin.saveSettings();
this.display();
});
});
new import_obsidian3.Setting(containerEl).setName(i18n.t("settings.yamlMode.defaultSeparator.name")).setDesc(i18n.t("settings.yamlMode.defaultSeparator.desc")).addDropdown((dropdown) => {
dropdown.addOption(".", ".");
dropdown.addOption(",", ",");
dropdown.addOption("-", "-");
dropdown.addOption("/", "/");
dropdown.setValue(this.plugin.settings.yamlDefaultSeparator);
dropdown.onChange(async (value) => {
this.plugin.settings.yamlDefaultSeparator = value;
await this.plugin.saveSettings();
this.display();
});
});
}
}
};
}
});
// src/main.ts
var main_exports = {};
__export(main_exports, {
default: () => HeaderEnhancerPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian6 = require("obsidian");
init_core();
init_utils();
init_setting();
init_config();
init_i18n();
// src/backlinks.ts
var import_obsidian4 = require("obsidian");
var BacklinkManager = class {
constructor(app) {
this.app = app;
}
/**
* Find backlinks pointing to a specific heading
* @param targetFile Target file
* @param oldHeading Original heading text (without # symbols)
* @returns List of link updates needed
*/
async findHeadingBacklinks(targetFile, oldHeading) {
const updates = [];
try {
const backlinksMap = this.app.metadataCache.getBacklinksForFile(targetFile);
if (!backlinksMap) {
return updates;
}
let actualMap = backlinksMap;
if (backlinksMap.data && backlinksMap.data instanceof Map) {
actualMap = backlinksMap.data;
}
if (!actualMap || actualMap.size === 0) {
return updates;
}
for (const [sourcePath, references] of actualMap) {
const sourceFile = this.app.vault.getAbstractFileByPath(sourcePath);
if (!(sourceFile instanceof import_obsidian4.TFile))
continue;
const content = await this.app.vault.read(sourceFile);
const lines = content.split("\n");
for (const ref of references) {
if (this.isReferenceCache(ref)) {
const linkUpdate = this.extractHeaderLink(
sourceFile,
ref,
lines,
targetFile.basename,
oldHeading
);
if (linkUpdate) {
updates.push(linkUpdate);
}
}
}
}
} catch (error) {
console.error("Error finding heading backlinks:", error);
new import_obsidian4.Notice("Error finding backlinks: " + error.message);
}
return updates;
}
/**
* Batch update header links in multiple files
* @param updates List of header link updates to apply
* @returns Whether all updates were successful
*/
async updateBacklinks(updates) {
if (updates.length === 0)
return true;
const updatePromises = [];
const backupData = [];
try {
for (const update of updates) {
const originalContent = await this.app.vault.read(update.sourceFile);
backupData.push({ file: update.sourceFile, content: originalContent });
updatePromises.push(this.updateSingleBacklink(update, originalContent));
}
await Promise.all(updatePromises);
return true;
} catch (error) {
console.error("Error updating backlinks:", error);
try {
const rollbackPromises = backupData.map(
(backup) => this.app.vault.modify(backup.file, backup.content)
);
await Promise.all(rollbackPromises);
new import_obsidian4.Notice("Backlink update failed, changes rolled back");
} catch (rollbackError) {
console.error("Failed to rollback changes:", rollbackError);
new import_obsidian4.Notice("Critical error: Failed to rollback backlink changes");
}
return false;
}
}
/**
* Update a single backlink
*/
async updateSingleBacklink(update, originalContent) {
const lines = originalContent.split("\n");
const { line } = update.position.start;
if (line >= lines.length)
return;
const oldLine = lines[line];
const newLine = oldLine.replace(update.oldLink, update.newLink);
if (oldLine !== newLine) {
lines[line] = newLine;
const newContent = lines.join("\n");
await this.app.vault.modify(update.sourceFile, newContent);
}
}
/**
* Extract header link information from a reference
*/
extractHeaderLink(sourceFile, ref, lines, targetFileName, oldHeading) {
const { line, ch } = ref.position.start;
if (line >= lines.length)
return null;
const lineContent = lines[line];
const expectedLinkPrefix = `${targetFileName}#`;
if (ref.link && ref.link.startsWith(expectedLinkPrefix)) {
const linkHeading = ref.link.substring(expectedLinkPrefix.length);
const normalizedLinkHeading = this.normalizeSpaces(linkHeading);
const normalizedOldHeading = this.normalizeSpaces(oldHeading);
if (normalizedLinkHeading === normalizedOldHeading || normalizedLinkHeading.includes(normalizedOldHeading) || normalizedOldHeading.includes(normalizedLinkHeading)) {
const linkUpdate = {
sourceFile,
oldLink: ref.original,
// Use original link text
newLink: ref.original,
// Set to same initially, will be updated in main.ts
position: {
start: { line: ref.position.start.line, ch: ref.position.start.col },
end: { line: ref.position.end.line, ch: ref.position.end.col }
}
};
return linkUpdate;
}
}
return null;
}
/**
* Type guard: check if reference is ReferenceCache type
*/
isReferenceCache(ref) {
return ref && typeof ref === "object" && "position" in ref;
}
/**
* Normalize spaces - convert multiple whitespace characters (including Tab) to single space
*/
normalizeSpaces(text) {
return text.replace(/\s+/g, " ").trim();
}
};
// src/editor/editor-handlers.ts
var import_view = require("@codemirror/view");
var import_state = require("@codemirror/state");
var import_obsidian5 = require("obsidian");
init_core();
init_config();
init_setting();
var EditorHandlers = class {
constructor(plugin) {
this.plugin = plugin;
}
/**
* 注册 CodeMirror 按键处理扩展
*/
registerKeyHandlers() {
return [
// Enter 键处理
import_state.Prec.highest(
import_view.keymap.of([
{
key: "Enter",
run: (view) => {
var _a;
const state = view.state;
const pos = state.selection.main.to;
const currentLine = state.doc.lineAt(pos);
if (!isHeader(currentLine.text)) {
return false;
}
if (this.plugin.settings.autoNumberingMode === "off" /* OFF */) {
return false;
}
const app = this.plugin.app;
const activeView = app.workspace.getActiveViewOfType(import_obsidian5.MarkdownView);
if (activeView) {
const editor = activeView.editor;
const filePath = (_a = activeView.file) == null ? void 0 : _a.path;
const config = getAutoNumberingConfig(
this.plugin.settings,
editor,
filePath ? (path) => this.plugin.getDocumentAutoNumberingState(path) : void 0,
filePath
);
if (!config.state) {
return false;
}
}
this.handlePressEnter(view);
return true;
}
}
])
),
// Backspace 键处理
import_state.Prec.highest(
import_view.keymap.of([
{
key: "Backspace",
run: (view) => {
const state = view.state;
const pos = state.selection.main.to;
const currentLine = state.doc.lineAt(pos);
if (!isHeader(currentLine.text)) {
return false;
}
return this.handlePressBackspace(view);
}
}
])
)
];
}
/**
* 处理 Enter 键按下事件
*/
async handlePressEnter(view) {
var _a;
let state = view.state;
let doc = state.doc;
const pos = state.selection.main.to;
const app = this.plugin.app;
const activeView = app.workspace.getActiveViewOfType(import_obsidian5.MarkdownView);
if (!activeView) {
return false;
}
const currentLine = doc.lineAt(pos);
const editor = activeView.editor;
const filePath = (_a = activeView.file) == null ? void 0 : _a.path;
const config = getAutoNumberingConfig(
this.plugin.settings,
editor,
filePath ? (path) => this.plugin.getDocumentAutoNumberingState(path) : void 0,
filePath
);
if (!isHeader(currentLine.text) || !config.state) {
return false;
}
const textBeforeCursor = currentLine.text.substring(0, pos - currentLine.from);
const textAfterCursor = currentLine.text.substring(pos - currentLine.from);
const changes = [{
from: currentLine.from,
to: currentLine.to,
insert: textBeforeCursor + "\n" + textAfterCursor
}];
view.dispatch({
changes,
selection: { anchor: currentLine.from + textBeforeCursor.length + 1 },
userEvent: "HeaderEnhancer.changeAutoNumbering"
});
setTimeout(async () => {
await this.plugin.handleAddHeaderNumber(activeView);
if (this.plugin.settings.isAutoDetectHeaderLevel) {
this.plugin.handleShowStateBarChange();
}
}, 10);
return true;
}
/**
* 处理 Backspace 键按下事件
*/
handlePressBackspace(view) {
let state = view.state;
let doc = state.doc;
const pos = state.selection.main.to;
const changes = [];
if (!isHeader(doc.lineAt(pos).text)) {
return false;
}
changes.push({
from: pos - 1,
to: pos,
insert: ""
});
if (this.plugin.settings.autoNumberingMode === "on" /* ON */) {
}
view.dispatch({
changes,
selection: { anchor: pos - 1 },
userEvent: "HeaderEnhancer.changeAutoNumbering"
});
return true;
}
};
// src/styles/style-manager.ts
var StyleManager = class {
constructor(settings) {
this.settings = settings;
this.headerFontStyleEl = null;
this.titleFontStyleEl = null;
this.dialogStyleEl = null;
this.ribbonIconStyleEl = null;
}
/**
* Apply all CSS styles
*/
applyCSSStyles() {
this.applyHeaderFontStyles();
this.applyTitleFontStyles();
this.applyDialogStyles();
this.applyRibbonIconStyles();
}
/**
* Remove all CSS styles
*/
removeCSSStyles() {
this.removeHeaderFontStyles();
this.removeTitleFontStyles();
this.removeDialogStyles();
this.removeRibbonIconStyles();
}
/**
* Apply header font styles (# ## ### etc.)
*/
applyHeaderFontStyles() {
this.removeHeaderFontStyles();
if (!this.settings.isSeparateHeaderFont) {
return;
}
this.headerFontStyleEl = document.createElement("style");
this.headerFontStyleEl.id = "header-enhancer-header-font-styles";
let cssRules = "";
const headerSelectors = [
".markdown-preview-view h1",
".markdown-preview-view h2",
".markdown-preview-view h3",
".markdown-preview-view h4",
".markdown-preview-view h5",
".markdown-preview-view h6",
".markdown-source-view.mod-cm6 .HyperMD-header-1",
".markdown-source-view.mod-cm6 .HyperMD-header-2",
".markdown-source-view.mod-cm6 .HyperMD-header-3",
".markdown-source-view.mod-cm6 .HyperMD-header-4",
".markdown-source-view.mod-cm6 .HyperMD-header-5",
".markdown-source-view.mod-cm6 .HyperMD-header-6"
].join(", ");
if (this.settings.headerFontFamily && this.settings.headerFontFamily !== "inherit") {
cssRules += `${headerSelectors} { font-family: ${this.settings.headerFontFamily} !important; }
`;
}
if (this.settings.headerFontSize && this.settings.headerFontSize !== "inherit") {
cssRules += `${headerSelectors} { font-size: ${this.settings.headerFontSize} !important; }
`;
}
this.headerFontStyleEl.textContent = cssRules;
if (cssRules) {
document.head.appendChild(this.headerFontStyleEl);
}
}
/**
* 应用文档标题字体样式
*/
applyTitleFontStyles() {
this.removeTitleFontStyles();
if (!this.settings.isSeparateTitleFont) {
return;
}
this.titleFontStyleEl = document.createElement("style");
this.titleFontStyleEl.id = "header-enhancer-title-font-styles";
let cssRules = "";
const titleSelectors = [
// 标签页中的文件标题 - 只针对特定的标签标题元素
".workspace-tab-header-inner-title",
".workspace-tab-header .workspace-tab-header-inner-title",
".workspace-tabs .workspace-tab-header-inner-title",
// 视图标题栏标题
".workspace-leaf-content .view-header-title",
// 文档内联标题(在文档中显示的主标题)
".inline-title",
".markdown-preview-view .inline-title",
".markdown-source-view .inline-title",
// 文件资源管理器中的文件标题
".nav-file-title-content",
".tree-item-inner.nav-file-title-content",
// Frontmatter 标题显示
'.frontmatter-container .metadata-property[data-property-key="title"] .metadata-property-value'
].join(", ");
if (this.settings.titleFontFamily && this.settings.titleFontFamily !== "inherit") {
cssRules += `${titleSelectors} { font-family: ${this.settings.titleFontFamily} !important; }
`;
}
if (this.settings.titleFontSize && this.settings.titleFontSize !== "inherit") {
cssRules += `${titleSelectors} { font-size: ${this.settings.titleFontSize} !important; }
`;
}
this.titleFontStyleEl.textContent = cssRules;
if (cssRules) {
document.head.appendChild(this.titleFontStyleEl);
}
}
/**
* Apply ribbon icon state styles
*/
applyRibbonIconStyles() {
this.removeRibbonIconStyles();
this.ribbonIconStyleEl = document.createElement("style");
this.ribbonIconStyleEl.id = "header-enhancer-ribbon-icon-styles";
const ribbonIconCSS = `
/* Ribbon icon state styles for Header Enhancer */
.side-dock-ribbon-action[aria-label*="Header Enhancer"].header-enhancer-global-disabled {
opacity: 0.4;
}
.side-dock-ribbon-action[aria-label*="Header Enhancer"].header-enhancer-global-disabled:hover {
opacity: 0.6;
}
.side-dock-ribbon-action[aria-label*="Header Enhancer"].header-enhancer-document-enabled {
color: var(--color-accent);
}
.side-dock-ribbon-action[aria-label*="Header Enhancer"].header-enhancer-document-enabled:hover {
color: var(--color-accent-hover);
}
.side-dock-ribbon-action[aria-label*="Header Enhancer"].header-enhancer-document-disabled {
opacity: 0.7;
color: var(--text-muted);
}
.side-dock-ribbon-action[aria-label*="Header Enhancer"].header-enhancer-document-disabled:hover {
opacity: 1;
color: var(--text-normal);
}
/* Additional visual indicator for global disabled state */
.side-dock-ribbon-action[aria-label*="Header Enhancer"].header-enhancer-global-disabled::before {
content: "";
position: absolute;
top: 2px;
right: 2px;
width: 6px;
height: 6px;
border-radius: 50%;
background-color: var(--text-error);
z-index: 10;
}
`;
this.ribbonIconStyleEl.textContent = ribbonIconCSS;
document.head.appendChild(this.ribbonIconStyleEl);
}
/**
* 应用对话框组件样式
*/
applyDialogStyles() {
this.removeDialogStyles();
this.dialogStyleEl = document.createElement("style");
this.dialogStyleEl.id = "header-enhancer-dialog-styles";
const dialogCSS = `
/* Auto numbering dialog styles - shared between removal and activation */
.header-enhancer-removal-dialog,
.header-enhancer-activation-dialog {
max-width: 500px;
}
.header-enhancer-removal-dialog .modal-title,
.header-enhancer-activation-dialog .modal-title {
margin-bottom: 1em;
padding-bottom: 0.5em;
color: var(--text-accent);
border-bottom: 1px solid var(--background-modifier-border);
}
.header-enhancer-removal-dialog .modal-message,
.header-enhancer-activation-dialog .modal-message {
margin-bottom: 1.5em;
line-height: 1.5;
color: var(--text-normal);
}
.header-enhancer-removal-dialog .modal-actions,
.header-enhancer-activation-dialog .modal-actions {
margin-top: 1em;
padding-top: 1em;
border-top: 1px solid var(--background-modifier-border);
}
.header-enhancer-removal-dialog .modal-actions .setting-item,
.header-enhancer-activation-dialog .modal-actions .setting-item {
margin-bottom: 0.75em;
padding: 0.75em;
background-color: var(--background-secondary);
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
transition: all 0.2s ease;
}
.header-enhancer-removal-dialog .modal-actions .setting-item:hover,
.header-enhancer-activation-dialog .modal-actions .setting-item:hover {
background-color: var(--background-secondary-alt);
border-color: var(--background-modifier-border-hover);
}
/* Warning and tip text styles */
.header-enhancer-removal-dialog .setting-item-warning,
.header-enhancer-removal-dialog .setting-item-tip,
.header-enhancer-activation-dialog .setting-item-warning,
.header-enhancer-activation-dialog .setting-item-tip {
margin-top: 0.5em;
font-size: 0.85em;
line-height: 1.3;
}
.header-enhancer-removal-dialog .warning-label,
.header-enhancer-activation-dialog .warning-label {
color: var(--text-error);
font-weight: 600;
}
.header-enhancer-removal-dialog .warning-text,
.header-enhancer-removal-dialog .progress-text,
.header-enhancer-activation-dialog .warning-text,
.header-enhancer-activation-dialog .progress-text {
color: var(--text-muted);
margin: 0;
}
.header-enhancer-removal-dialog .manual-tip-text,
.header-enhancer-activation-dialog .manual-tip-text {
color: var(--text-muted);
font-style: italic;
}
.header-enhancer-removal-dialog .modal-cancel,
.header-enhancer-activation-dialog .modal-cancel {
margin-top: 1em;
padding-top: 1em;
text-align: center;
border-top: 1px solid var(--background-modifier-border-focus);
}
.header-enhancer-removal-dialog .progress-container,
.header-enhancer-activation-dialog .progress-container {
margin-top: 1em;
padding: 1em;
background-color: var(--background-secondary);
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
text-align: center;
}
.header-enhancer-removal-dialog .progress-text,
.header-enhancer-activation-dialog .progress-text {
font-size: 0.9em;
}
.header-enhancer-removal-dialog button:disabled,
.header-enhancer-activation-dialog button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`;
this.dialogStyleEl.textContent = dialogCSS;
document.head.appendChild(this.dialogStyleEl);
}
/**
* 移除标题字体样式
*/
removeHeaderFontStyles() {
if (this.headerFontStyleEl) {
this.headerFontStyleEl.remove();
this.headerFontStyleEl = null;
}
}
/**
* 移除文档标题字体样式
*/
removeTitleFontStyles() {
if (this.titleFontStyleEl) {
this.titleFontStyleEl.remove();
this.titleFontStyleEl = null;
}
}
/**
* 移除对话框样式
*/
removeDialogStyles() {
if (this.dialogStyleEl) {
this.dialogStyleEl.remove();
this.dialogStyleEl = null;
}
}
/**
* 移除侧边栏图标样式
*/
removeRibbonIconStyles() {
if (this.ribbonIconStyleEl) {
this.ribbonIconStyleEl.remove();
this.ribbonIconStyleEl = null;
}
}
/**
* 更新设置引用(当设置改变时调用)
*/
updateSettings(newSettings) {
this.settings = newSettings;
}
};
// src/main.ts
var HeaderEnhancerPlugin = class extends import_obsidian6.Plugin {
constructor() {
super(...arguments);
this.perDocumentStatesMap = /* @__PURE__ */ new Map();
}
async onload() {
await this.loadSettings();
this.backlinkManager = new BacklinkManager(this.app);
this.editorHandlers = new EditorHandlers(this);
this.styleManager = new StyleManager(this.settings);
this.styleManager.applyCSSStyles();
this.ribbonIconEl = this.addRibbonIcon(
"heading-glyph",
"Header Enhancer",
async (_evt) => {
const i18n2 = I18n.getInstance();
const app = this.app;
const activeView = app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!(activeView == null ? void 0 : activeView.file)) {
new import_obsidian6.Notice(i18n2.t("notices.noActiveView"));
return;
}
const filePath = activeView.file.path;
if (!this.settings.globalAutoNumberingEnabled) {
new import_obsidian6.Notice(i18n2.t("notices.globalDisabledNotice"));
return;
}
const currentState = this.getDocumentAutoNumberingState(filePath);
const newState = !currentState;
await this.toggleDocumentState(activeView, newState);
this.updateAllUIStates();
}
);
this.statusBarItemEl = this.addStatusBarItem();
this.handleShowStateBarChange();
this.handleShowSidebarChange();
this.updateAllUIStates();
const keyHandlers = this.editorHandlers.registerKeyHandlers();
keyHandlers.forEach((handler) => this.registerEditorExtension(handler));
this.registerEvent(
this.app.workspace.on("active-leaf-change", () => {
this.updateAllUIStates();
})
);
this.registerEvent(
this.app.workspace.on("file-open", () => {
setTimeout(() => {
this.updateAllUIStates();
}, 50);
})
);
const i18n = I18n.getInstance();
this.addCommand({
id: "toggle-global-auto-numbering",
name: i18n.t("commands.toggleGlobalAutoNumbering"),
callback: async () => {
const newState = !this.settings.globalAutoNumberingEnabled;
this.settings.globalAutoNumberingEnabled = newState;
await this.saveSettings();
new import_obsidian6.Notice(newState ? i18n.t("notices.globalAutoNumberingEnabled") : i18n.t("notices.globalAutoNumberingDisabled"));
this.updateAllUIStates();
}
});
this.addCommand({
id: "toggle-document-auto-numbering",
name: i18n.t("commands.toggleDocumentAutoNumbering"),
callback: async () => {
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!(activeView == null ? void 0 : activeView.file)) {
new import_obsidian6.Notice(i18n.t("notices.noActiveView"));
return;
}
const filePath = activeView.file.path;
if (!this.settings.globalAutoNumberingEnabled) {
new import_obsidian6.Notice(i18n.t("notices.globalDisabledNotice"));
return;
}
const currentState = this.getDocumentAutoNumberingState(filePath);
const newState = !currentState;
await this.toggleDocumentState(activeView, newState);
this.updateAllUIStates();
}
});
this.addCommand({
id: "reset-auto-numbering-yaml",
name: i18n.t("commands.resetAutoNumberingYaml"),
callback: () => {
const app = this.app;
const activeView = app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!activeView) {
new import_obsidian6.Notice(i18n.t("notices.noActiveView"));
return;
} else {
const editor = activeView.editor;
const yaml = getAutoNumberingYaml(editor);
if (yaml === "") {
new import_obsidian6.Notice(i18n.t("notices.yamlNotExists"));
} else {
const value = [
"state on",
"start-level h2",
"end-level h6",
"start-at 1",
"separator ."
];
setAutoNumberingYaml(editor, value);
}
}
}
});
this.addCommand({
id: "remove-auto-numbering-yaml",
name: i18n.t("commands.removeAutoNumberingYaml"),
callback: () => {
const app = this.app;
const activeView = app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!activeView) {
new import_obsidian6.Notice(i18n.t("notices.noActiveView"));
return;
} else {
const editor = activeView.editor;
const yaml = getAutoNumberingYaml(editor);
if (yaml === "") {
new import_obsidian6.Notice(i18n.t("notices.yamlNotExists"));
} else {
setAutoNumberingYaml(editor, []);
}
}
}
});
this.addCommand({
id: "apply-custom-yaml-config",
name: i18n.t("commands.applyCustomYamlConfig"),
callback: () => {
const app = this.app;
const activeView = app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!activeView) {
new import_obsidian6.Notice(i18n.t("notices.noActiveView"));
return;
} else {
const editor = activeView.editor;
const yaml = getAutoNumberingYaml(editor);
if (yaml !== "") {
new import_obsidian6.Notice(i18n.t("notices.yamlAlreadyExists"));
} else {
const value = [
"state on",
`start-level h${this.settings.yamlDefaultStartLevel}`,
`end-level h${this.settings.yamlDefaultEndLevel}`,
`start-at ${this.settings.yamlDefaultStartNumber}`,
`separator ${this.settings.yamlDefaultSeparator}`
];
setAutoNumberingYaml(editor, value);
new import_obsidian6.Notice(i18n.t("notices.yamlTemplateInserted"));
}
}
}
});
this.addSettingTab(new HeaderEnhancerSettingTab(this.app, this));
this.registerInterval(
window.setInterval(() => {
}, 5 * 60 * 1e3)
);
}
onunload() {
this.styleManager.removeCSSStyles();
}
async loadSettings() {
this.settings = Object.assign(
{},
DEFAULT_SETTINGS,
await this.loadData()
);
this.migrateSettings();
try {
if (this.settings.perDocumentStates) {
const parsedStates = JSON.parse(this.settings.perDocumentStates);
this.perDocumentStatesMap = new Map(Object.entries(parsedStates));
}
} catch (error) {
console.warn("Failed to parse perDocumentStates, using empty map:", error);
this.perDocumentStatesMap = /* @__PURE__ */ new Map();
}
}
/**
* Migrate settings for backward compatibility
*/
migrateSettings() {
if (this.settings.globalAutoNumberingEnabled === void 0) {
this.settings.globalAutoNumberingEnabled = this.settings.autoNumberingMode !== "off" /* OFF */;
}
if (this.settings.perDocumentStates === void 0) {
this.settings.perDocumentStates = "{}";
}
}
async saveSettings() {
const statesObject = Object.fromEntries(this.perDocumentStatesMap.entries());
this.settings.perDocumentStates = JSON.stringify(statesObject);
await this.saveData(this.settings);
this.styleManager.updateSettings(this.settings);
}
/**
* Get the current document auto numbering state
* Legacy method - now uses unified state evaluation
*/
getDocumentAutoNumberingState(filePath) {
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!(activeView == null ? void 0 : activeView.file) || activeView.file.path !== filePath) {
return this.getSimpleDocumentState(filePath);
}
return this.getUnifiedDocumentState(activeView.editor, filePath);
}
/**
* Get unified document auto numbering state - includes YAML parsing
* This ensures UI and actual numbering use exactly the same logic
*/
getUnifiedDocumentState(editor, filePath) {
const config = getAutoNumberingConfig(
this.settings,
editor,
(path) => this.getSimpleDocumentState(path),
filePath
);
return config.state;
}
/**
* Get simple document state without YAML parsing (for non-active documents)
*/
getSimpleDocumentState(filePath) {
var _a;
if (!this.settings.globalAutoNumberingEnabled) {
return false;
}
if (this.perDocumentStatesMap.has(filePath)) {
return (_a = this.perDocumentStatesMap.get(filePath)) != null ? _a : false;
}
return this.settings.autoNumberingMode !== "off" /* OFF */;
}
/**
* Set the current document auto numbering state
*/
async setDocumentAutoNumberingState(filePath, enabled) {
this.perDocumentStatesMap.set(filePath, enabled);
await this.saveSettings();
}
/**
* Update all UI states (ribbon icon, status bar)
*/
updateAllUIStates() {
this.updateRibbonIconState();
this.handleShowStateBarChange();
}
/**
* Update ribbon icon state based on global and document settings
*/
updateRibbonIconState() {
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!(activeView == null ? void 0 : activeView.file)) {
if (!this.settings.globalAutoNumberingEnabled) {
this.ribbonIconEl.addClass("header-enhancer-global-disabled");
this.ribbonIconEl.removeClass("header-enhancer-document-enabled");
this.ribbonIconEl.removeClass("header-enhancer-document-disabled");
this.ribbonIconEl.setAttribute("aria-label", "Header Enhancer (Global Disabled)");
} else {
this.ribbonIconEl.removeClass("header-enhancer-global-disabled");
this.ribbonIconEl.removeClass("header-enhancer-document-enabled");
this.ribbonIconEl.addClass("header-enhancer-document-disabled");
this.ribbonIconEl.setAttribute("aria-label", "Header Enhancer (No Active Document)");
}
return;
}
const filePath = activeView.file.path;
const globalEnabled = this.settings.globalAutoNumberingEnabled;
const documentEnabled = this.getDocumentAutoNumberingState(filePath);
if (!globalEnabled) {
this.ribbonIconEl.addClass("header-enhancer-global-disabled");
this.ribbonIconEl.removeClass("header-enhancer-document-enabled");
this.ribbonIconEl.removeClass("header-enhancer-document-disabled");
this.ribbonIconEl.setAttribute("aria-label", "Header Enhancer (Global Disabled)");
} else if (documentEnabled) {
this.ribbonIconEl.removeClass("header-enhancer-global-disabled");
this.ribbonIconEl.addClass("header-enhancer-document-enabled");
this.ribbonIconEl.removeClass("header-enhancer-document-disabled");
this.ribbonIconEl.setAttribute("aria-label", "Header Enhancer (Document Enabled)");
} else {
this.ribbonIconEl.removeClass("header-enhancer-global-disabled");
this.ribbonIconEl.removeClass("header-enhancer-document-enabled");
this.ribbonIconEl.addClass("header-enhancer-document-disabled");
this.ribbonIconEl.setAttribute("aria-label", "Header Enhancer (Document Disabled)");
}
}
handleShowStateBarChange() {
if (this.settings.showOnStatusBar) {
const i18n = I18n.getInstance();
let autoNumberingStatus;
if (!this.settings.globalAutoNumberingEnabled) {
autoNumberingStatus = i18n.t("statusBar.globalDisabled");
} else {
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian6.MarkdownView);
if (!(activeView == null ? void 0 : activeView.file)) {
autoNumberingStatus = i18n.t("statusBar.off");
} else {
const filePath = activeView.file.path;
const documentEnabled = this.getDocumentAutoNumberingState(filePath);
if (documentEnabled) {
switch (this.settings.autoNumberingMode) {
case "on" /* ON */:
if (this.settings.isAutoDetectHeaderLevel) {
const analysis = analyzeHeaderLevels(activeView.editor.getValue());
if (!analysis.isEmpty) {
autoNumberingStatus = `${i18n.t("statusBar.auto")}(H${analysis.minLevel}-H${analysis.maxLevel})`;
} else {
autoNumberingStatus = i18n.t("statusBar.autoNoHeaders");
}
} else {
autoNumberingStatus = `${i18n.t("statusBar.on")}(H${this.settings.startHeaderLevel}-H${this.settings.endHeaderLevel})`;
}
break;
case "yaml" /* YAML_CONTROLLED */:
autoNumberingStatus = i18n.t("statusBar.yaml");
break;
case "off" /* OFF */:
default:
autoNumberingStatus = i18n.t("statusBar.documentEnabled");
break;
}
} else {
autoNumberingStatus = i18n.t("statusBar.documentDisabled");
}
}
}
this.statusBarItemEl.setText(
`${i18n.t("statusBar.title")}: ${autoNumberingStatus}`
);
this.statusBarItemEl.show();
} else {
this.statusBarItemEl.hide();
}
}
handleShowSidebarChange() {
if (this.settings.showOnSidebar) {
this.ribbonIconEl.show();
} else {
this.ribbonIconEl.hide();
}
}
async handleAddHeaderNumber(view) {
var _a;
const editor = view.editor;
const lineCount = editor.lineCount();
let docCharCount = 0;
const filePath = (_a = view.file) == null ? void 0 : _a.path;
const config = getAutoNumberingConfig(
this.settings,
editor,
filePath ? (path) => this.getDocumentAutoNumberingState(path) : void 0,
filePath
);
if (!config.state) {
return false;
}
const currentFile = view.file;
const headerChanges = [];
if (config.state) {
let insertNumber = [Number(config.startNumber) - 1];
let isCodeBlock = false;
for (let i = 0; i <= lineCount; i++) {
const line = editor.getLine(i);
docCharCount += line.length;
if (line.startsWith("```")) {
isCodeBlock = !isCodeBlock;
if (line.slice(3).contains("```")) {
isCodeBlock = !isCodeBlock;
}
}
if (isCodeBlock) {
continue;
}
if (isHeader(line)) {
const [headerLevel, realHeaderLevel] = getHeaderLevel(
line,
config.startLevel
);
if (headerLevel <= 0) {
continue;
}
insertNumber = getNextNumber(insertNumber, headerLevel);
const insertNumberStr = insertNumber.join(config.separator);
let newLine = null;
let originalHeading = null;
if (isNeedInsertNumber(
line,
this.settings.autoNumberingHeaderSeparator
)) {
originalHeading = line.substring(realHeaderLevel + 1).trim();
newLine = "#".repeat(realHeaderLevel) + " " + insertNumberStr + this.settings.autoNumberingHeaderSeparator + line.substring(realHeaderLevel + 1);
} else if (isNeedUpdateNumber(
insertNumberStr,
line,
this.settings.autoNumberingHeaderSeparator
)) {
const textAfterSeparator = line.split(this.settings.autoNumberingHeaderSeparator)[1];
originalHeading = textAfterSeparator ? textAfterSeparator.trim() : null;
const originNumberLength = line.split(
this.settings.autoNumberingHeaderSeparator
)[0].split(" ")[1].length;
newLine = "#".repeat(realHeaderLevel) + " " + insertNumberStr + line.substring(
realHeaderLevel + originNumberLength + 1
);
}
if (newLine && newLine !== line && originalHeading) {
headerChanges.push({
lineIndex: i,
oldText: line,
newText: newLine,
originalHeading
});
editor.setLine(i, newLine);
}
}
}
if (this.settings.updateBacklinks && headerChanges.length > 0 && currentFile) {
await this.updateBacklinksForChanges(currentFile, headerChanges);
}
}
return true;
}
/**
* Handle backlink updates when headers change
*/
async updateBacklinksForChanges(currentFile, headerChanges) {
try {
for (const change of headerChanges) {
const oldHeading = change.originalHeading;
if (oldHeading && change.oldText !== change.newText) {
const backlinks = await this.backlinkManager.findHeadingBacklinks(
currentFile,
oldHeading.trim()
);
const updates = backlinks.map((link) => {
const fullNewHeading = this.extractFullHeadingWithNumber(change.newText);
const newLink = link.oldLink.replace(
`#${oldHeading.trim()}`,
`#${fullNewHeading}`
);
return {
...link,
newLink
};
});
if (updates.length > 0) {
await this.backlinkManager.updateBacklinks(updates);
}
}
}
} catch (error) {
console.error("Error updating backlinks:", error);
new import_obsidian6.Notice("Failed to update backlinks: " + error.message);
}
}
/**
* Extract plain heading text (remove # symbols and numbering)
*/
extractHeadingText(headerLine) {
const match = headerLine.match(/^#+\s*(?:\d+[\.\-\/,]*\d*\s*[\t\s]*)?\s*(.+)$/);
return match ? match[1].trim() : null;
}
/**
* Extract full heading text with numbering (remove # symbols but keep numbering)
*/
extractFullHeadingWithNumber(headerLine) {
const match = headerLine.match(/^#+\s*(.+)$/);
return match ? match[1].trim() : headerLine;
}
async handleRemoveHeaderNumber(view) {
var _a;
const editor = view.editor;
const lineCount = editor.lineCount();
const filePath = (_a = view.file) == null ? void 0 : _a.path;
const config = getAutoNumberingConfig(
this.settings,
editor,
filePath ? (path) => this.getDocumentAutoNumberingState(path) : void 0,
filePath
);
const currentFile = view.file;
const headerChanges = [];
for (let i = 0; i <= lineCount; i++) {
const line = editor.getLine(i);
if (isHeader(line)) {
const [headerLevel, _] = getHeaderLevel(
line,
config.startLevel
);
if (headerLevel <= 0) {
continue;
}
const newLine = removeHeaderNumber(
line,
this.settings.autoNumberingHeaderSeparator
);
if (newLine !== line) {
const originalHeading = this.extractHeadingText(newLine);
if (originalHeading) {
headerChanges.push({
lineIndex: i,
oldText: line,
newText: newLine,
originalHeading
});
}
editor.setLine(i, newLine);
}
}
}
if (this.settings.updateBacklinks && headerChanges.length > 0 && currentFile) {
await this.updateBacklinksForRemoval(currentFile, headerChanges);
}
return true;
}
/**
* Handle backlink updates when removing header numbers
*/
async updateBacklinksForRemoval(currentFile, headerChanges) {
try {
for (const change of headerChanges) {
const oldFullHeading = this.extractFullHeadingWithNumber(change.oldText);
const newHeading = change.originalHeading;
if (oldFullHeading && newHeading) {
const backlinks = await this.backlinkManager.findHeadingBacklinks(
currentFile,
oldFullHeading
);
const updates = backlinks.map((link) => {
const newLink = link.oldLink.replace(
`#${oldFullHeading}`,
`#${newHeading}`
);
return {
...link,
newLink
};
});
if (updates.length > 0) {
await this.backlinkManager.updateBacklinks(updates);
}
}
}
} catch (error) {
console.error("Error updating backlinks for removal:", error);
new import_obsidian6.Notice("Failed to update backlinks during removal: " + error.message);
}
}
/**
* Toggle document auto-numbering state
* In YAML mode: synchronizes both perDocumentStatesMap and YAML state
* In ON mode: only modifies perDocumentStatesMap
*/
async toggleDocumentState(activeView, newState) {
var _a;
const i18n = I18n.getInstance();
const filePath = (_a = activeView.file) == null ? void 0 : _a.path;
if (!filePath)
return;
if (this.settings.autoNumberingMode === "yaml" /* YAML_CONTROLLED */) {
await this.setDocumentAutoNumberingState(filePath, newState);
const editor = activeView.editor;
const yaml = getAutoNumberingYaml(editor);
if (yaml === "") {
const value = [
`state ${newState ? "on" : "off"}`
];
setAutoNumberingYaml(editor, value);
} else {
const yamlArray = yaml;
let hasState = false;
const newYaml = yamlArray.map((line) => {
if (line.startsWith("state ")) {
hasState = true;
return `state ${newState ? "on" : "off"}`;
}
return line;
});
if (!hasState) {
newYaml.unshift(`state ${newState ? "on" : "off"}`);
}
setAutoNumberingYaml(editor, newYaml);
}
if (newState) {
await this.handleAddHeaderNumber(activeView);
new import_obsidian6.Notice(i18n.t("notices.autoNumberingEnabledForDocument"));
} else {
await this.handleRemoveHeaderNumber(activeView);
new import_obsidian6.Notice(i18n.t("notices.autoNumberingDisabledForDocument"));
}
} else {
await this.setDocumentAutoNumberingState(filePath, newState);
if (newState) {
await this.handleAddHeaderNumber(activeView);
new import_obsidian6.Notice(i18n.t("notices.autoNumberingEnabledForDocument"));
} else {
await this.handleRemoveHeaderNumber(activeView);
new import_obsidian6.Notice(i18n.t("notices.autoNumberingDisabledForDocument"));
}
}
}
};
/* nosourcemap */