/*
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 __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);

// main.ts
var main_exports = {};
__export(main_exports, {
  default: () => NovelWordCountPlugin
});
module.exports = __toCommonJS(main_exports);

// logic/debug.ts
var DebugHelper = class {
  constructor() {
    this.debugMode = false;
    this.idCounter = 0;
  }
  setDebugMode(debug) {
    this.debugMode = debug;
  }
  debug(...args) {
    if (!this.debugMode) {
      return;
    }
    console.log("novel-word-count:", ...args);
  }
  error(message) {
    if (!this.debugMode) {
      return;
    }
    console.error(message);
  }
  debugStart(name) {
    if (!this.debugMode) {
      return () => {
      };
    }
    const qualifiedName = `novel-word-count|${name} (${++this.idCounter})`;
    console.time(qualifiedName);
    return () => console.timeEnd(qualifiedName);
  }
};

// logic/event.ts
var import_obsidian = require("obsidian");

// logic/cancellation.ts
var CANCEL = Symbol("Cancel");
var CancellationToken = class {
  constructor() {
    this._isCancelled = false;
  }
  get isCancelled() {
    return this._isCancelled;
  }
  [CANCEL]() {
    this._isCancelled = true;
  }
};
var CancellationTokenSource = class {
  constructor() {
    this.token = new CancellationToken();
  }
  cancel() {
    this.token[CANCEL]();
  }
};

// logic/event.ts
var EventHelper = class {
  constructor(plugin, app, debugHelper, fileHelper) {
    this.plugin = plugin;
    this.app = app;
    this.debugHelper = debugHelper;
    this.fileHelper = fileHelper;
    this.cancellationSources = [];
  }
  async handleEvents() {
    const debouncedFileModified = (0, import_obsidian.debounce)(async (file) => {
      const countToken = this.registerNewCountToken();
      await this.fileHelper.updateFileCounts(
        file,
        this.plugin.savedData.cachedCounts,
        countToken.token
      );
      this.cancelToken(countToken);
      await this.plugin.updateDisplayedCounts(file);
      this.plugin.saveSettingsDebounced();
    }, 500);
    this.plugin.registerEvent(
      this.app.metadataCache.on("changed", async (file) => {
        this.debugHelper.debug(
          "[changed] metadataCache hook fired, scheduling file for analysis",
          file.path
        );
        debouncedFileModified(file);
      })
    );
    this.app.workspace.onLayoutReady(() => {
      this.plugin.registerEvent(
        this.app.vault.on("create", async (file) => {
          this.debugHelper.debug(
            "[create] vault hook fired, analyzing file",
            file.path
          );
          const countToken = this.registerNewCountToken();
          await this.fileHelper.updateFileCounts(
            file,
            this.plugin.savedData.cachedCounts,
            countToken.token
          );
          this.cancelToken(countToken);
          await this.plugin.updateDisplayedCounts(file);
          await this.plugin.saveSettings();
        })
      );
      this.plugin.registerEvent(
        this.app.vault.on("modify", async (file) => {
          this.debugHelper.debug(
            "[modify] vault hook fired, scheduling file for analysis",
            file.path
          );
          debouncedFileModified(file);
        })
      );
    });
    this.plugin.registerEvent(
      this.app.vault.on("delete", async (file) => {
        this.debugHelper.debug(
          "[delete] vault hook fired, forgetting file",
          file.path
        );
        this.fileHelper.removeFileCounts(
          file.path,
          this.plugin.savedData.cachedCounts
        );
        await this.plugin.updateDisplayedCounts(file);
        await this.plugin.saveSettings();
      })
    );
    this.plugin.registerEvent(
      this.app.vault.on("rename", async (file, oldPath) => {
        if (file instanceof import_obsidian.TFolder) {
          return;
        }
        this.debugHelper.debug(
          "[rename] vault hook fired, recounting file",
          file.path
        );
        this.fileHelper.removeFileCounts(
          oldPath,
          this.plugin.savedData.cachedCounts
        );
        const countToken = this.registerNewCountToken();
        await this.fileHelper.updateFileCounts(
          file,
          this.plugin.savedData.cachedCounts,
          countToken.token
        );
        this.cancelToken(countToken);
        await this.plugin.updateDisplayedCounts(file);
        await this.plugin.saveSettings();
      })
    );
    const reshowCountsIfNeeded = async (hookName) => {
      this.debugHelper.debug(`[${hookName}] hook fired`);
      const fileExplorerLeaf = await this.plugin.getFileExplorerLeaf();
      if (this.isContainerTouched(fileExplorerLeaf)) {
        this.debugHelper.debug(
          "container already touched, skipping display update"
        );
        return;
      }
      this.debugHelper.debug("container is clean, updating display");
      await this.plugin.updateDisplayedCounts();
    };
    this.plugin.registerEvent(
      this.app.workspace.on(
        "layout-change",
        (0, import_obsidian.debounce)(reshowCountsIfNeeded.bind(this, "layout-change"), 1e3)
      )
    );
  }
  isContainerTouched(leaf) {
    const container = leaf.view.containerEl;
    return container.className.includes("novel-word-count--");
  }
  async reinitializeAllCounts() {
    this.cancelAllCountTokens();
    const countToken = this.registerNewCountToken();
    this.debugHelper.debug("refreshAllCounts");
    this.plugin.savedData.cachedCounts = await this.fileHelper.initializeAllFileCounts(
      countToken.token
    );
    this.cancelToken(countToken);
    await this.plugin.saveSettings();
  }
  /*
     CANCELLATION HANDLING
   */
  registerNewCountToken() {
    const cancellationSource = new CancellationTokenSource();
    this.cancellationSources.push(cancellationSource);
    return cancellationSource;
  }
  cancelToken(source) {
    source.cancel();
    if (this.cancellationSources.includes(source)) {
      this.cancellationSources.splice(
        this.cancellationSources.indexOf(source),
        1
      );
    }
  }
  cancelAllCountTokens() {
    for (const source of this.cancellationSources) {
      source.cancel();
    }
    this.cancellationSources = [];
  }
};

// logic/file.ts
var import_obsidian2 = require("obsidian");

// logic/settings.ts
var $CountType = /* @__PURE__ */ (($CountType2) => {
  $CountType2["None"] = "none";
  $CountType2["Word"] = "word";
  $CountType2["Page"] = "page";
  $CountType2["PageDecimal"] = "pagedecimal";
  $CountType2["Linebreak"] = "linebreak";
  $CountType2["ReadTime"] = "readtime";
  $CountType2["PercentGoal"] = "percentgoal";
  $CountType2["Note"] = "note";
  $CountType2["Character"] = "character";
  $CountType2["Link"] = "link";
  $CountType2["Embed"] = "embed";
  $CountType2["Alias"] = "alias";
  $CountType2["Created"] = "created";
  $CountType2["Modified"] = "modified";
  $CountType2["FileSize"] = "filesize";
  $CountType2["FrontmatterKey"] = "frontmatterKey";
  $CountType2["TrackSession"] = "tracksession";
  return $CountType2;
})($CountType || {});
var COUNT_TYPES = Object.values($CountType);
var SESSION_COUNT_TYPES = [
  "word" /* Word */,
  "page" /* Page */,
  "pagedecimal" /* PageDecimal */,
  "linebreak" /* Linebreak */,
  "note" /* Note */,
  "character" /* Character */
];
var COUNT_TYPE_DISPLAY_STRINGS = {
  ["none" /* None */]: "None",
  ["word" /* Word */]: "Word Count",
  ["page" /* Page */]: "Page Count",
  ["pagedecimal" /* PageDecimal */]: "Page Count (decimal)",
  ["linebreak" /* Linebreak */]: "Line Break Count",
  ["readtime" /* ReadTime */]: "Reading Time",
  ["percentgoal" /* PercentGoal */]: "% of Word Goal",
  ["note" /* Note */]: "Note Count",
  ["character" /* Character */]: "Character Count",
  ["link" /* Link */]: "Link Count",
  ["embed" /* Embed */]: "Embed Count",
  ["alias" /* Alias */]: "First Alias",
  ["created" /* Created */]: "Created Date",
  ["modified" /* Modified */]: "Last Updated Date",
  ["filesize" /* FileSize */]: "File Size",
  ["frontmatterKey" /* FrontmatterKey */]: "Frontmatter Key",
  ["tracksession" /* TrackSession */]: "Track Session"
};
var COUNT_TYPE_DESCRIPTIONS = {
  ["none" /* None */]: "Hidden.",
  ["word" /* Word */]: "Total words.",
  ["page" /* Page */]: "Total pages, rounded up.",
  ["pagedecimal" /* PageDecimal */]: "Total pages, precise to 2 digits after the decimal.",
  ["linebreak" /* Linebreak */]: "Newlines (\xB6), including empty lines.",
  ["readtime" /* ReadTime */]: "Estimated time to read the note.",
  ["percentgoal" /* PercentGoal */]: "Set a word goal by adding the 'word-goal' property to a note.",
  ["note" /* Note */]: "Total notes.",
  ["character" /* Character */]: "Total characters (letters, symbols, numbers, and spaces).",
  ["link" /* Link */]: "Total links to other notes.",
  ["embed" /* Embed */]: "Total embedded images, files, and notes.",
  ["alias" /* Alias */]: "The first alias property of each note.",
  ["created" /* Created */]: "Creation date. (On folders: earliest creation date of any note.)",
  ["modified" /* Modified */]: "Date of last edit. (On folders: latest edit date of any note.)",
  ["filesize" /* FileSize */]: "Total size on hard drive.",
  ["frontmatterKey" /* FrontmatterKey */]: "Key in the frontmatter block.",
  ["tracksession" /* TrackSession */]: "Track progress since last Obsidian startup, plugin init, settings change, or recount"
};
var UNFORMATTABLE_COUNT_TYPES = [
  "none" /* None */,
  "alias" /* Alias */,
  "filesize" /* FileSize */,
  "readtime" /* ReadTime */
];
var COUNT_TYPE_DEFAULT_SHORT_SUFFIXES = {
  ["word" /* Word */]: "w",
  ["page" /* Page */]: "p",
  ["pagedecimal" /* PageDecimal */]: "p",
  ["linebreak" /* Linebreak */]: "\xB6",
  ["percentgoal" /* PercentGoal */]: "%",
  ["note" /* Note */]: "n",
  ["character" /* Character */]: "ch",
  ["link" /* Link */]: "x",
  ["embed" /* Embed */]: "em",
  ["created" /* Created */]: "/c",
  ["modified" /* Modified */]: "/u",
  ["frontmatterKey" /* FrontmatterKey */]: "",
  ["tracksession" /* TrackSession */]: "/s"
};
function getDescription(countType) {
  return `[${COUNT_TYPE_DISPLAY_STRINGS[countType]}] ${COUNT_TYPE_DESCRIPTIONS[countType]}`;
}
var ALIGNMENT_TYPES = [
  "inline" /* Inline */,
  "right" /* Right */,
  "below" /* Below */
];
var DEFAULT_SETTINGS = {
  // FORMATTING
  useAdvancedFormatting: false,
  // NOTES
  countType: "word" /* Word */,
  countConfig: {
    customSuffix: "w",
    $sessionCountType: "word" /* Word */
  },
  countType2: "none" /* None */,
  countConfig2: {
    $sessionCountType: "word" /* Word */
  },
  countType3: "none" /* None */,
  countConfig3: {
    $sessionCountType: "word" /* Word */
  },
  pipeSeparator: "|",
  abbreviateDescriptions: false,
  alignment: "inline" /* Inline */,
  // FOLDERS
  showSameCountsOnFolders: true,
  folderCountType: "word" /* Word */,
  folderCountConfig: {
    customSuffix: "w",
    $sessionCountType: "word" /* Word */
  },
  folderCountType2: "none" /* None */,
  folderCountConfig2: {
    $sessionCountType: "word" /* Word */
  },
  folderCountType3: "none" /* None */,
  folderCountConfig3: {
    $sessionCountType: "word" /* Word */
  },
  folderPipeSeparator: "|",
  folderAbbreviateDescriptions: false,
  folderAlignment: "inline" /* Inline */,
  // ROOT
  showSameCountsOnRoot: true,
  rootCountType: "word" /* Word */,
  rootCountConfig: {
    customSuffix: "w",
    $sessionCountType: "word" /* Word */
  },
  rootCountType2: "none" /* None */,
  rootCountConfig2: {
    $sessionCountType: "word" /* Word */
  },
  rootCountType3: "none" /* None */,
  rootCountConfig3: {
    $sessionCountType: "word" /* Word */
  },
  rootPipeSeparator: "|",
  rootAbbreviateDescriptions: false,
  // ADVANCED
  showAdvanced: false,
  labelOpacity: 0.75,
  wordsPerMinute: 265,
  charsPerMinute: 500,
  wordsPerPage: 300,
  charsPerPage: 1500,
  charsPerPageIncludesWhitespace: false,
  characterCountType: "AllCharacters" /* StringLength */,
  pageCountType: "ByWords" /* ByWords */,
  includeDirectories: "",
  excludeComments: false,
  excludeCodeBlocks: false,
  excludeNonVisibleLinkPortions: false,
  excludeFootnotes: false,
  momentDateFormat: "",
  debugMode: false
};

// logic/parser.ts
var cjkRegex = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/gu;
var allSymbolsRegex = /[\p{S}\p{P}]/gu;
function countMarkdown(content, config) {
  content = removeNonCountedContent(content, config);
  let wordSequences = content.replace(cjkRegex, " ").replace(allSymbolsRegex, "").trim().split(/\s+/);
  if (wordSequences.length === 1 && wordSequences[0] === "") {
    wordSequences = [];
  }
  let lineSequences = content.split("\n");
  if (lineSequences.length === 1 && lineSequences[0] === "") {
    lineSequences = [];
  }
  const result = {
    charCount: content.length,
    nonWhitespaceCharCount: countNonWhitespaceCharacters(content),
    spaceDelimitedWordCount: wordSequences.length,
    cjkWordCount: (content.match(cjkRegex) || []).length,
    newlineCount: lineSequences.length
  };
  return result;
}
var whitespaceRegex = /\s/g;
function countNonWhitespaceCharacters(content) {
  return content.replace(whitespaceRegex, "").length;
}
function removeNonCountedContent(content, config) {
  if (config.excludeCodeBlocks) {
    content = content.replace(/(```.+?```)/gims, "");
  }
  if (config.excludeComments) {
    content = content.replace(/(%%.+?%%|<!--.+?-->)/gims, "");
  }
  if (config.excludeNonVisibleLinkPortions) {
    content = content.replace(/\[([^\]]*?)\]\([^\)]*?\)/gim, "$1");
    content = content.replace(/\[\[(.*?)\]\]/gim, (_, $1) => {
      return !$1 ? "" : $1.includes("|") ? $1.slice($1.indexOf("|") + 1) : $1;
    });
  }
  if (config.excludeFootnotes) {
    content = content.replace(/\[\^.+?\]: .*/gim, "");
    content = content.replace(/\[\^.+?\]/gim, "");
  }
  return content;
}

// logic/canvas.ts
var CanvasHelper = class {
  constructor(debug) {
    this.debug = debug;
  }
  getCanvasText(file, content) {
    try {
      const canvas = JSON.parse(content);
      const texts = canvas.nodes.map((node) => node.text).filter((text) => !!text);
      return texts.join("\n");
    } catch (ex) {
      this.debug.error(`Unable to parse canvas file [${file.name}]: ${ex}`);
      return "";
    }
  }
};

// logic/file.ts
var FileHelper = class {
  constructor(app, plugin) {
    this.app = app;
    this.plugin = plugin;
    this.debugHelper = new DebugHelper();
    this.canvasHelper = new CanvasHelper(this.debugHelper);
    this.pathIncludeMatchers = [];
    this.pathExcludeMatchers = [];
    this.FileTypeAllowlist = /* @__PURE__ */ new Set([
      "",
      // Markdown extensions
      "markdown",
      "md",
      "mdml",
      "mdown",
      "mdtext",
      "mdtxt",
      "mdwn",
      "mkd",
      "mkdn",
      // Obsidian canvas
      "canvas",
      // Text files
      "txt",
      "text",
      "rtf",
      // MD with embedded code
      "qmd",
      "rmd",
      // MD for screenwriters
      "fountain",
      // LaTeX files
      "tex"
    ]);
  }
  get settings() {
    return this.plugin.settings;
  }
  get vault() {
    return this.app.vault;
  }
  async initializeAllFileCounts(cancellationToken) {
    const debugEnd = this.debugHelper.debugStart("getAllFileCounts");
    const files = this.vault.getFiles();
    if (typeof this.plugin.settings.includeDirectories === "string" && this.plugin.settings.includeDirectories.trim() !== "*" && this.plugin.settings.includeDirectories.trim() !== "") {
      const allMatchers = this.plugin.settings.includeDirectories.trim().split(",").map((matcher) => matcher.trim());
      const includeMatchers = allMatchers.filter(
        (matcher) => !matcher.startsWith("!")
      );
      const excludeMatchers = allMatchers.filter((matcher) => matcher.startsWith("!")).map((matcher) => matcher.slice(1));
      const matchedFiles = files.filter(
        (file) => (includeMatchers.length === 0 ? true : includeMatchers.some((matcher) => file.path.includes(matcher))) && !excludeMatchers.some((matcher) => file.path.includes(matcher))
      );
      if (matchedFiles.length > 0) {
        this.pathIncludeMatchers = includeMatchers;
        this.pathExcludeMatchers = excludeMatchers;
      } else {
        this.pathIncludeMatchers = [];
        this.pathExcludeMatchers = [];
        this.debugHelper.debug(
          "No files matched by includeDirectories setting. Defaulting to all files."
        );
      }
    }
    const counts = {};
    for (const file of files) {
      if (cancellationToken.isCancelled) {
        break;
      }
      this.setCounts(counts, file, true);
    }
    debugEnd();
    return counts;
  }
  getCachedDataForPath(counts, path) {
    if (counts.hasOwnProperty(path)) {
      return counts[path];
    }
    const childPaths = this.getChildPaths(counts, path);
    const directoryDefault = {
      isCountable: false,
      targetNodeType: this.isRoot(path) ? "root" /* Root */ : "directory" /* Directory */,
      noteCount: 0,
      wordCount: 0,
      wordCountTowardGoal: 0,
      wordGoal: 0,
      pageCount: 0,
      characterCount: 0,
      nonWhitespaceCharacterCount: 0,
      newlineCount: 0,
      readingTimeInMinutes: 0,
      linkCount: 0,
      embedCount: 0,
      aliases: null,
      createdDate: 0,
      modifiedDate: 0,
      sizeInBytes: 0,
      sessionStart: {
        noteCount: 0,
        pageCount: 0,
        wordCount: 0,
        characterCount: 0,
        nonWhitespaceCharacterCount: 0,
        newlineCount: 0
      }
    };
    return childPaths.reduce((total, childPath) => {
      const childCount = this.getCachedDataForPath(counts, childPath);
      return {
        isCountable: total.isCountable || childCount.isCountable,
        targetNodeType: total.targetNodeType,
        noteCount: total.noteCount + childCount.noteCount,
        linkCount: total.linkCount + childCount.linkCount,
        embedCount: total.embedCount + childCount.embedCount,
        aliases: [],
        wordCount: total.wordCount + childCount.wordCount,
        wordCountTowardGoal: total.wordCountTowardGoal + childCount.wordCountTowardGoal,
        wordGoal: total.wordGoal + childCount.wordGoal,
        pageCount: total.pageCount + childCount.pageCount,
        characterCount: total.characterCount + childCount.characterCount,
        nonWhitespaceCharacterCount: total.nonWhitespaceCharacterCount + childCount.nonWhitespaceCharacterCount,
        newlineCount: total.newlineCount + childCount.newlineCount,
        readingTimeInMinutes: total.readingTimeInMinutes + childCount.readingTimeInMinutes,
        createdDate: total.createdDate === 0 ? childCount.createdDate : Math.min(total.createdDate, childCount.createdDate),
        modifiedDate: Math.max(total.modifiedDate, childCount.modifiedDate),
        sizeInBytes: total.sizeInBytes + childCount.sizeInBytes,
        sessionStart: {
          noteCount: total.sessionStart.noteCount + childCount.sessionStart.noteCount,
          pageCount: total.sessionStart.pageCount + childCount.sessionStart.pageCount,
          wordCount: total.sessionStart.wordCount + childCount.sessionStart.wordCount,
          characterCount: total.sessionStart.characterCount + childCount.sessionStart.characterCount,
          nonWhitespaceCharacterCount: total.sessionStart.nonWhitespaceCharacterCount + childCount.sessionStart.nonWhitespaceCharacterCount,
          newlineCount: total.sessionStart.newlineCount + childCount.sessionStart.newlineCount
        }
      };
    }, directoryDefault);
  }
  setDebugMode(debug) {
    this.debugHelper.setDebugMode(debug);
  }
  removeFileCounts(path, counts) {
    this.removeCounts(counts, path);
    for (const childPath of this.getChildPaths(counts, path)) {
      this.removeCounts(counts, childPath);
    }
  }
  async updateFileCounts(abstractFile, counts, cancellationToken) {
    if (abstractFile instanceof import_obsidian2.TFolder) {
      for (const child of abstractFile.children) {
        await this.updateFileCounts(child, counts, cancellationToken);
      }
      return;
    }
    if (abstractFile instanceof import_obsidian2.TFile) {
      await this.setCounts(counts, abstractFile, false);
    }
  }
  countEmbeds(metadata) {
    var _a, _b;
    return (_b = (_a = metadata == null ? void 0 : metadata.embeds) == null ? void 0 : _a.length) != null ? _b : 0;
  }
  countLinks(metadata) {
    var _a, _b;
    return (_b = (_a = metadata == null ? void 0 : metadata.links) == null ? void 0 : _a.length) != null ? _b : 0;
  }
  getChildPaths(counts, path) {
    const childPaths = Object.keys(counts).filter(
      (countPath) => path === "/" || countPath.startsWith(path + "/")
    );
    return childPaths;
  }
  isRoot(path) {
    return !path || path === "/";
  }
  removeCounts(counts, path) {
    delete counts[path];
  }
  async setCounts(counts, file, startNewSession) {
    var _a, _b;
    const metadata = this.app.metadataCache.getFileCache(
      file
    );
    const shouldCountFile = this.shouldCountFile(file, metadata);
    const existingSession = (_a = counts[file.path]) == null ? void 0 : _a.sessionStart;
    counts[file.path] = {
      isCountable: shouldCountFile,
      targetNodeType: "file" /* File */,
      noteCount: 0,
      wordCount: 0,
      wordCountTowardGoal: 0,
      wordGoal: 0,
      pageCount: 0,
      characterCount: 0,
      nonWhitespaceCharacterCount: 0,
      newlineCount: 0,
      readingTimeInMinutes: 0,
      linkCount: 0,
      embedCount: 0,
      aliases: [],
      createdDate: file.stat.ctime,
      modifiedDate: file.stat.mtime,
      sizeInBytes: file.stat.size,
      sessionStart: startNewSession || !existingSession ? {
        noteCount: 0,
        pageCount: 0,
        wordCount: 0,
        characterCount: 0,
        nonWhitespaceCharacterCount: 0,
        newlineCount: 0
      } : existingSession
    };
    if (!shouldCountFile) {
      return;
    }
    let content = await this.vault.cachedRead(file);
    if (file.extension.toLowerCase() === "canvas") {
      content = this.canvasHelper.getCanvasText(file, content);
    } else {
      content = this.trimFrontmatter(content, metadata);
    }
    const countResult = countMarkdown(content, {
      excludeCodeBlocks: this.settings.excludeCodeBlocks,
      excludeComments: this.settings.excludeComments,
      excludeNonVisibleLinkPortions: this.settings.excludeNonVisibleLinkPortions,
      excludeFootnotes: this.settings.excludeFootnotes
    });
    const combinedWordCount = countResult.cjkWordCount + countResult.spaceDelimitedWordCount;
    const wordGoal = this.getWordGoal(metadata);
    const cjkReadingTime = countResult.cjkWordCount / (this.settings.charsPerMinute || 500);
    const spaceDelimitedReadingTime = countResult.spaceDelimitedWordCount / (this.settings.wordsPerMinute || 265);
    const readingTimeInMinutes = cjkReadingTime + spaceDelimitedReadingTime;
    let pageCount = 0;
    if (this.settings.pageCountType === "ByWords" /* ByWords */) {
      const wordsPerPage = Number(this.settings.wordsPerPage);
      const wordsPerPageValid = !isNaN(wordsPerPage) && wordsPerPage > 0;
      pageCount = combinedWordCount / (wordsPerPageValid ? wordsPerPage : 300);
    } else if (this.settings.pageCountType === "ByChars" /* ByChars */ && !this.settings.charsPerPageIncludesWhitespace) {
      const charsPerPage = Number(this.settings.charsPerPage);
      const charsPerPageValid = !isNaN(charsPerPage) && charsPerPage > 0;
      pageCount = countResult.nonWhitespaceCharCount / (charsPerPageValid ? charsPerPage : 1500);
    } else if (this.settings.pageCountType === "ByChars" /* ByChars */ && this.settings.charsPerPageIncludesWhitespace) {
      const charsPerPage = Number(this.settings.charsPerPage);
      const charsPerPageValid = !isNaN(charsPerPage) && charsPerPage > 0;
      pageCount = countResult.charCount / (charsPerPageValid ? charsPerPage : 1500);
    }
    Object.assign(counts[file.path], {
      noteCount: 1,
      wordCount: combinedWordCount,
      wordCountTowardGoal: wordGoal !== null ? combinedWordCount : 0,
      wordGoal,
      pageCount,
      characterCount: countResult.charCount,
      nonWhitespaceCharacterCount: countResult.nonWhitespaceCharCount,
      newlineCount: countResult.newlineCount,
      readingTimeInMinutes,
      linkCount: this.countLinks(metadata),
      embedCount: this.countEmbeds(metadata),
      aliases: (0, import_obsidian2.parseFrontMatterAliases)(metadata == null ? void 0 : metadata.frontmatter),
      frontmatter: metadata == null ? void 0 : metadata.frontmatter,
      sessionStart: {
        ...(_b = counts[file.path]) == null ? void 0 : _b.sessionStart,
        ...startNewSession ? {
          noteCount: 1,
          pageCount,
          wordCount: combinedWordCount,
          characterCount: countResult.charCount,
          nonWhitespaceCharacterCount: countResult.nonWhitespaceCharCount,
          newlineCount: countResult.newlineCount
        } : {}
      }
    });
  }
  getWordGoal(metadata) {
    const goal = metadata && metadata.frontmatter && metadata.frontmatter["word-goal"];
    if (!goal || isNaN(Number(goal))) {
      return null;
    }
    return Number(goal);
  }
  trimFrontmatter(content, metadata) {
    let meaningfulContent = content;
    const hasFrontmatter = !!metadata && !!metadata.frontmatter;
    if (hasFrontmatter) {
      const frontmatterPos = metadata.frontmatterPosition || metadata.frontmatter.position;
      meaningfulContent = frontmatterPos && frontmatterPos.start && frontmatterPos.end ? meaningfulContent.slice(0, frontmatterPos.start.offset) + meaningfulContent.slice(frontmatterPos.end.offset) : meaningfulContent;
    }
    return meaningfulContent;
  }
  shouldCountFile(file, metadata) {
    if (this.pathIncludeMatchers.length > 0 && !this.pathIncludeMatchers.some((matcher) => file.path.includes(matcher))) {
      return false;
    }
    if (this.pathExcludeMatchers.length > 0 && this.pathExcludeMatchers.some((matcher) => file.path.includes(matcher))) {
      return false;
    }
    if (!this.FileTypeAllowlist.has(file.extension.toLowerCase())) {
      return false;
    }
    if (!metadata) {
      return true;
    }
    if (metadata.frontmatter && metadata.frontmatter.hasOwnProperty("wordcount") && (metadata.frontmatter.wordcount === null || metadata.frontmatter.wordcount === false || metadata.frontmatter.wordcount === "false")) {
      return false;
    }
    const tags = (0, import_obsidian2.getAllTags)(metadata).map((tag) => tag.toLowerCase());
    if (tags.length && (tags.includes("#excalidraw") || tags.filter((tag) => tag.startsWith("#exclude")).map((tag) => tag.replace(/[-_]/g, "")).includes("#excludefromwordcount"))) {
      return false;
    }
    return true;
  }
};

// logic/locale_format.ts
var locales = [...navigator.languages, "en-US"];
var NumberFormatDefault = new Intl.NumberFormat(locales);
var NumberFormatDecimal = new Intl.NumberFormat(locales, {
  minimumFractionDigits: 1,
  maximumFractionDigits: 2
});
var NumberFormatFileSize = new Intl.NumberFormat(locales, {
  minimumFractionDigits: 0,
  maximumFractionDigits: 2
});

// logic/filesize.ts
var formatThresholds = [{
  suffix: "B",
  suffixLong: " B",
  divisor: 1
}, {
  suffix: "kB",
  suffixLong: " kB",
  divisor: 1e3
}, {
  suffix: "MB",
  suffixLong: " MB",
  divisor: 1e6
}, {
  suffix: "GB",
  suffixLong: " GB",
  divisor: 1e9
}, {
  suffix: "TB",
  suffixLong: " TB",
  divisor: 1e12
}];
var FileSizeHelper = class {
  formatFileSize(bytes, shouldAbbreviate) {
    const largestThreshold = formatThresholds.last();
    for (const formatThreshold of formatThresholds) {
      if (bytes < formatThreshold.divisor * 1e3 || formatThreshold === largestThreshold) {
        const units = bytes / formatThreshold.divisor;
        const suffix = shouldAbbreviate ? formatThreshold.suffix : formatThreshold.suffixLong;
        return `${NumberFormatFileSize.format(units)}${suffix}`;
      }
    }
    return `?B`;
  }
};

// logic/readtime.ts
var ReadTimeHelper = class {
  formatReadTime(minutes, shouldAbbreviate) {
    const final = shouldAbbreviate ? "" : " read";
    if (minutes * 60 < 1) {
      return `0m${final}`;
    }
    if (minutes < 1) {
      const seconds = Math.round(minutes * 60);
      return `${seconds}s${final}`;
    }
    if (minutes < 60) {
      return `${Math.round(minutes)}m${final}`;
    }
    const hours = NumberFormatDefault.format(Math.floor(minutes / 60));
    const remainder = Math.floor(minutes) % 60;
    return remainder === 0 ? `${hours}h${final}` : `${hours}h${remainder}m${final}`;
  }
};

// logic/node_label.ts
var import_obsidian3 = require("obsidian");
var NodeLabelHelper = class {
  constructor(plugin) {
    this.plugin = plugin;
    this.fileSizeHelper = new FileSizeHelper();
    this.readTimeHelper = new ReadTimeHelper();
    this.unconditionalCountTypes = [
      "created" /* Created */,
      "filesize" /* FileSize */,
      "modified" /* Modified */
    ];
  }
  get settings() {
    return this.plugin.settings;
  }
  getNodeLabel(counts) {
    let countTypes;
    let abbreviateDescriptions;
    let separator;
    const noteCountTypes = [
      this.getCountTypeWithSuffix(
        this.settings.countType,
        this.settings.countConfig
      ),
      this.getCountTypeWithSuffix(
        this.settings.countType2,
        this.settings.countConfig2
      ),
      this.getCountTypeWithSuffix(
        this.settings.countType3,
        this.settings.countConfig3
      )
    ];
    const noteAbbreviateDescriptions = this.settings.abbreviateDescriptions;
    const noteSeparator = this.settings.useAdvancedFormatting ? this.settings.pipeSeparator : "|";
    switch (counts.targetNodeType) {
      case "root" /* Root */:
        if (this.settings.showSameCountsOnRoot) {
          countTypes = noteCountTypes;
          abbreviateDescriptions = noteAbbreviateDescriptions;
          separator = noteSeparator;
          break;
        }
        countTypes = [
          this.getCountTypeWithSuffix(
            this.settings.rootCountType,
            this.settings.rootCountConfig
          ),
          this.getCountTypeWithSuffix(
            this.settings.rootCountType2,
            this.settings.rootCountConfig2
          ),
          this.getCountTypeWithSuffix(
            this.settings.rootCountType3,
            this.settings.rootCountConfig3
          )
        ];
        abbreviateDescriptions = this.settings.rootAbbreviateDescriptions;
        separator = this.settings.useAdvancedFormatting ? this.settings.rootPipeSeparator : noteSeparator;
        break;
      case "directory" /* Directory */:
        if (this.settings.showSameCountsOnFolders) {
          countTypes = noteCountTypes;
          abbreviateDescriptions = noteAbbreviateDescriptions;
          separator = noteSeparator;
          break;
        }
        countTypes = [
          this.getCountTypeWithSuffix(
            this.settings.folderCountType,
            this.settings.folderCountConfig
          ),
          this.getCountTypeWithSuffix(
            this.settings.folderCountType2,
            this.settings.folderCountConfig2
          ),
          this.getCountTypeWithSuffix(
            this.settings.folderCountType3,
            this.settings.folderCountConfig3
          )
        ];
        abbreviateDescriptions = this.settings.folderAbbreviateDescriptions;
        separator = this.settings.useAdvancedFormatting ? this.settings.folderPipeSeparator : noteSeparator;
        break;
      default:
        countTypes = noteCountTypes;
        abbreviateDescriptions = noteAbbreviateDescriptions;
        separator = noteSeparator;
        break;
    }
    return countTypes.filter((ct) => ct.$countType !== "none" /* None */).map(
      (ct) => this.getDataTypeLabel(
        counts,
        ct,
        abbreviateDescriptions
      )
    ).filter((display) => display !== null).join(` ${separator} `);
  }
  getCountTypeWithSuffix($countType, countConfig) {
    return {
      $countType,
      customSuffix: this.settings.useAdvancedFormatting ? countConfig.customSuffix : null,
      frontmatterKey: countConfig.frontmatterKey,
      $sessionCountType: countConfig.$sessionCountType
    };
  }
  getBasicCountString(config) {
    var _a;
    const defaultSuffix = config.abbreviateDescriptions ? config.abbreviatedNoun : ` ${config.noun}${config.count == "1" ? "" : "s"}`;
    const suffix = (_a = config.customSuffix) != null ? _a : defaultSuffix;
    return `${config.count}${suffix}`;
  }
  getDataTypeLabel(counts, config, abbreviateDescriptions) {
    var _a, _b;
    if (!counts || typeof counts.wordCount !== "number") {
      return null;
    }
    if (!counts.isCountable && !this.unconditionalCountTypes.includes(config.$countType)) {
      return null;
    }
    switch (config.$countType) {
      case "none" /* None */:
        return null;
      case "word" /* Word */:
        return this.getBasicCountString({
          count: NumberFormatDefault.format(Math.ceil(counts.wordCount)),
          noun: "word",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["word" /* Word */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      case "page" /* Page */:
        return this.getBasicCountString({
          count: NumberFormatDefault.format(Math.ceil(counts.pageCount)),
          noun: "page",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["page" /* Page */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      case "pagedecimal" /* PageDecimal */:
        return this.getBasicCountString({
          count: NumberFormatDecimal.format(counts.pageCount),
          noun: "page",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["pagedecimal" /* PageDecimal */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      case "linebreak" /* Linebreak */:
        return this.getBasicCountString({
          count: NumberFormatDefault.format(counts.newlineCount),
          noun: "line",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["linebreak" /* Linebreak */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      case "percentgoal" /* PercentGoal */: {
        if (counts.wordGoal <= 0) {
          return null;
        }
        const fraction = counts.wordCountTowardGoal / counts.wordGoal;
        const percent = NumberFormatDefault.format(Math.round(fraction * 100));
        const defaultSuffix = abbreviateDescriptions ? "%" : `% of ${NumberFormatDefault.format(counts.wordGoal)}`;
        const suffix = (_a = config.customSuffix) != null ? _a : defaultSuffix;
        return `${percent}${suffix}`;
      }
      case "note" /* Note */:
        return this.getBasicCountString({
          count: NumberFormatDefault.format(counts.noteCount),
          noun: "note",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["note" /* Note */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      case "character" /* Character */: {
        const characterCount = this.settings.characterCountType === "ExcludeWhitespace" /* ExcludeWhitespace */ ? counts.nonWhitespaceCharacterCount : counts.characterCount;
        return this.getBasicCountString({
          count: NumberFormatDefault.format(characterCount),
          noun: "character",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["character" /* Character */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      }
      case "readtime" /* ReadTime */:
        return this.readTimeHelper.formatReadTime(
          counts.readingTimeInMinutes,
          abbreviateDescriptions
        );
      case "link" /* Link */:
        if (counts.linkCount === 0) {
          return null;
        }
        return this.getBasicCountString({
          count: NumberFormatDefault.format(counts.linkCount),
          noun: "link",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["link" /* Link */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      case "embed" /* Embed */:
        if (counts.embedCount === 0) {
          return null;
        }
        return this.getBasicCountString({
          count: NumberFormatDefault.format(counts.embedCount),
          noun: "embed",
          abbreviatedNoun: COUNT_TYPE_DEFAULT_SHORT_SUFFIXES["embed" /* Embed */],
          abbreviateDescriptions,
          customSuffix: config.customSuffix
        });
      case "alias" /* Alias */:
        if (!counts.aliases || !Array.isArray(counts.aliases) || !counts.aliases.length) {
          return null;
        }
        return abbreviateDescriptions ? `${counts.aliases[0]}` : `alias: ${counts.aliases[0]}${counts.aliases.length > 1 ? ` +${counts.aliases.length - 1}` : ""}`;
      case "created" /* Created */: {
        if (counts.createdDate === 0) {
          return null;
        }
        const cDate = (0, import_obsidian3.moment)(counts.createdDate).format(this.settings.momentDateFormat || "YYYY/MM/DD");
        if (config.customSuffix !== null) {
          return `${cDate}${config.customSuffix}`;
        }
        return abbreviateDescriptions ? `${cDate}/c` : `Created ${cDate}`;
      }
      case "modified" /* Modified */: {
        if (counts.modifiedDate === 0) {
          return null;
        }
        const uDate = (0, import_obsidian3.moment)(counts.modifiedDate).format(this.settings.momentDateFormat || "YYYY/MM/DD");
        if (config.customSuffix !== null) {
          return `${uDate}${config.customSuffix}`;
        }
        return abbreviateDescriptions ? `${uDate}/u` : `Updated ${uDate}`;
      }
      case "filesize" /* FileSize */:
        return this.fileSizeHelper.formatFileSize(
          counts.sizeInBytes,
          abbreviateDescriptions
        );
      case "frontmatterKey" /* FrontmatterKey */: {
        if (!config.frontmatterKey) {
          return null;
        }
        const value = (_b = counts == null ? void 0 : counts.frontmatter) == null ? void 0 : _b[config.frontmatterKey];
        if (value === void 0 || value === null) {
          return null;
        }
        if (config.customSuffix !== null) {
          return `${value}${config.customSuffix}`;
        }
        return value;
      }
      case "tracksession" /* TrackSession */: {
        if (!config.$sessionCountType) {
          return null;
        }
        const quantity = this.getSessionQuantity(counts, config.$sessionCountType);
        if (config.customSuffix !== null) {
          return `${quantity}${config.customSuffix}`;
        }
        return abbreviateDescriptions ? `${quantity}/s` : `Session: ${quantity}`;
      }
    }
    return null;
  }
  getSessionQuantity(counts, $countType) {
    switch ($countType) {
      case "word" /* Word */:
        return NumberFormatDefault.format(Math.ceil(counts.wordCount - counts.sessionStart.wordCount));
      case "page" /* Page */:
        return NumberFormatDefault.format(Math.ceil(counts.pageCount - counts.sessionStart.pageCount));
      case "pagedecimal" /* PageDecimal */:
        return NumberFormatDecimal.format(counts.pageCount - counts.sessionStart.pageCount);
      case "linebreak" /* Linebreak */:
        return NumberFormatDefault.format(counts.newlineCount - counts.sessionStart.newlineCount);
      case "note" /* Note */:
        return NumberFormatDefault.format(counts.noteCount - counts.sessionStart.noteCount);
      case "character" /* Character */: {
        const characterCount = this.settings.characterCountType === "ExcludeWhitespace" /* ExcludeWhitespace */ ? counts.nonWhitespaceCharacterCount : counts.characterCount;
        const startingCharacterCount = this.settings.characterCountType === "ExcludeWhitespace" /* ExcludeWhitespace */ ? counts.sessionStart.nonWhitespaceCharacterCount : counts.sessionStart.characterCount;
        return NumberFormatDefault.format(characterCount - startingCharacterCount);
      }
    }
  }
};

// logic/saved_data.ts
var SavedDataHelper = class {
  constructor(plugin) {
    this.plugin = plugin;
  }
  async getSavedData() {
    const loaded = await this.plugin.loadData();
    const denulled = Object.assign({}, loaded);
    denulled.settings = Object.assign({}, DEFAULT_SETTINGS, denulled.settings);
    const migrated = migrateSavedData(denulled);
    return migrated;
  }
};
function migrateSavedData(saved) {
  const migrations = [
    overwriteInvalidCountTypes,
    migrateToCountConfigurationObject
  ];
  for (const migrate of migrations) {
    saved = migrate(saved);
  }
  return saved;
}
var overwriteInvalidCountTypes = (saved) => {
  var _a;
  if (!((_a = saved == null ? void 0 : saved.settings) == null ? void 0 : _a.countType)) {
    return;
  }
  const fieldsToCheck = [
    "countType",
    "countType2",
    "countType3",
    "folderCountType",
    "folderCountType2",
    "folderCountType3",
    "rootCountType",
    "rootCountType2",
    "rootCountType3"
  ];
  for (const field of fieldsToCheck) {
    if (!COUNT_TYPES.includes(saved.settings[field])) {
      saved.settings[field] = field === "countType" ? "word" /* Word */ : "none" /* None */;
    }
  }
  return saved;
};
var migrateToCountConfigurationObject = (saved) => {
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
  const settings = saved.settings;
  const oldSettings = saved.settings;
  (_a = settings.countConfig) != null ? _a : settings.countConfig = {};
  if (typeof oldSettings.countTypeSuffix === "string") {
    settings.countConfig.customSuffix = oldSettings.countTypeSuffix;
    delete oldSettings.countTypeSuffix;
  }
  if (typeof oldSettings.frontmatterKey === "string") {
    settings.countConfig.frontmatterKey = oldSettings.frontmatterKey;
    delete oldSettings.frontmatterKey;
  }
  (_b = settings.countConfig2) != null ? _b : settings.countConfig2 = {};
  if (typeof oldSettings.countType2Suffix === "string") {
    settings.countConfig2.customSuffix = oldSettings.countType2Suffix;
    delete oldSettings.countType2Suffix;
  }
  if (typeof oldSettings.frontmatterKey2 === "string") {
    settings.countConfig2.frontmatterKey = oldSettings.frontmatterKey2;
    delete oldSettings.frontmatterKey2;
  }
  (_c = settings.countConfig3) != null ? _c : settings.countConfig3 = {};
  if (typeof oldSettings.countType3Suffix === "string") {
    settings.countConfig3.customSuffix = oldSettings.countType3Suffix;
    delete oldSettings.countType3Suffix;
  }
  if (typeof oldSettings.frontmatterKey3 === "string") {
    settings.countConfig3.frontmatterKey = oldSettings.frontmatterKey3;
    delete oldSettings.frontmatterKey3;
  }
  (_d = settings.folderCountConfig) != null ? _d : settings.folderCountConfig = {};
  if (typeof oldSettings.folderCountTypeSuffix === "string") {
    settings.folderCountConfig.customSuffix = oldSettings.folderCountTypeSuffix;
    delete oldSettings.folderCountTypeSuffix;
  }
  (_e = settings.folderCountConfig2) != null ? _e : settings.folderCountConfig2 = {};
  if (typeof oldSettings.folderCountType2Suffix === "string") {
    settings.folderCountConfig2.customSuffix = oldSettings.folderCountType2Suffix;
    delete oldSettings.folderCountType2Suffix;
  }
  (_f = settings.folderCountConfig3) != null ? _f : settings.folderCountConfig3 = {};
  if (typeof oldSettings.folderCountType3Suffix === "string") {
    settings.folderCountConfig3.customSuffix = oldSettings.folderCountType3Suffix;
    delete oldSettings.folderCountType3Suffix;
  }
  (_g = settings.rootCountConfig) != null ? _g : settings.rootCountConfig = {};
  if (typeof oldSettings.rootCountTypeSuffix === "string") {
    settings.rootCountConfig.customSuffix = oldSettings.rootCountTypeSuffix;
    delete oldSettings.rootCountTypeSuffix;
  }
  (_h = settings.rootCountConfig2) != null ? _h : settings.rootCountConfig2 = {};
  if (typeof oldSettings.rootCountType2Suffix === "string") {
    settings.rootCountConfig2.customSuffix = oldSettings.rootCountType2Suffix;
    delete oldSettings.rootCountType2Suffix;
  }
  (_i = settings.rootCountConfig3) != null ? _i : settings.rootCountConfig3 = {};
  if (typeof oldSettings.rootCountType3Suffix === "string") {
    settings.rootCountConfig3.customSuffix = oldSettings.rootCountType3Suffix;
    delete oldSettings.rootCountType3Suffix;
  }
  return saved;
};

// logic/settings.tab.ts
var import_obsidian4 = require("obsidian");
var NovelWordCountSettingTab = class extends import_obsidian4.PluginSettingTab {
  constructor(app, plugin) {
    super(app, plugin);
    this.plugin = plugin;
  }
  display() {
    const { containerEl } = this;
    containerEl.empty();
    this.renderNoteSettings(containerEl);
    this.renderFolderSettings(containerEl);
    this.renderRootSettings(containerEl);
    this.renderAdvancedSettings(containerEl);
    this.renderReanalyzeButton(containerEl);
    this.renderDonationButton(containerEl);
  }
  //
  // NOTES
  //
  renderNoteSettings(containerEl) {
    const mainHeader = containerEl.createEl("div", {
      cls: [
        "setting-item",
        "setting-item-heading",
        "novel-word-count-settings-header"
      ]
    });
    mainHeader.createEl("div", { text: "Notes" });
    mainHeader.createEl("div", {
      text: "You can display up to three data types side by side.",
      cls: "setting-item-description"
    });
    new import_obsidian4.Setting(containerEl).setDesc("Use advanced formatting").addToggle(
      (toggle) => toggle.setValue(this.plugin.settings.useAdvancedFormatting).onChange(async (value) => {
        this.plugin.settings.useAdvancedFormatting = value;
        await this.plugin.saveSettings();
        await this.plugin.updateDisplayedCounts();
        this.display();
      })
    );
    this.renderCountTypeSetting(containerEl, {
      name: "1st data type to show",
      oldCountType: this.plugin.settings.countType,
      setNewCountType: (value) => {
        this.plugin.settings.countType = value;
        this.plugin.settings.countConfig.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.countType];
      }
    });
    this.renderSessionCountTypeSetting(containerEl, {
      parentCountType: this.plugin.settings.countType,
      oldCountType: this.plugin.settings.countConfig.$sessionCountType,
      setNewCountType: (value) => {
        this.plugin.settings.countConfig.$sessionCountType = value;
      }
    });
    this.renderFrontmatterKeySetting(containerEl, {
      countType: this.plugin.settings.countType,
      oldKey: this.plugin.settings.countConfig.frontmatterKey,
      setNewKey: (value) => this.plugin.settings.countConfig.frontmatterKey = value
    });
    this.renderCustomFormatSetting(containerEl, {
      countType: this.plugin.settings.countType,
      oldSuffix: this.plugin.settings.countConfig.customSuffix,
      setNewSuffix: (value) => this.plugin.settings.countConfig.customSuffix = value
    });
    this.renderCountTypeSetting(containerEl, {
      name: "2nd data type to show",
      oldCountType: this.plugin.settings.countType2,
      setNewCountType: (value) => {
        this.plugin.settings.countType2 = value;
        this.plugin.settings.countConfig2.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.countType2];
      }
    });
    this.renderSessionCountTypeSetting(containerEl, {
      parentCountType: this.plugin.settings.countType2,
      oldCountType: this.plugin.settings.countConfig2.$sessionCountType,
      setNewCountType: (value) => {
        this.plugin.settings.countConfig2.$sessionCountType = value;
      }
    });
    this.renderFrontmatterKeySetting(containerEl, {
      countType: this.plugin.settings.countType2,
      oldKey: this.plugin.settings.countConfig2.frontmatterKey,
      setNewKey: (value) => this.plugin.settings.countConfig2.frontmatterKey = value
    });
    this.renderCustomFormatSetting(containerEl, {
      countType: this.plugin.settings.countType2,
      oldSuffix: this.plugin.settings.countConfig2.customSuffix,
      setNewSuffix: (value) => this.plugin.settings.countConfig2.customSuffix = value
    });
    this.renderCountTypeSetting(containerEl, {
      name: "3rd data type to show",
      oldCountType: this.plugin.settings.countType3,
      setNewCountType: (value) => {
        this.plugin.settings.countType3 = value;
        this.plugin.settings.countConfig3.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.countType3];
      }
    });
    this.renderSessionCountTypeSetting(containerEl, {
      parentCountType: this.plugin.settings.countType3,
      oldCountType: this.plugin.settings.countConfig3.$sessionCountType,
      setNewCountType: (value) => {
        this.plugin.settings.countConfig3.$sessionCountType = value;
      }
    });
    this.renderFrontmatterKeySetting(containerEl, {
      countType: this.plugin.settings.countType3,
      oldKey: this.plugin.settings.countConfig3.frontmatterKey,
      setNewKey: (value) => this.plugin.settings.countConfig3.frontmatterKey = value
    });
    this.renderCustomFormatSetting(containerEl, {
      countType: this.plugin.settings.countType3,
      oldSuffix: this.plugin.settings.countConfig3.customSuffix,
      setNewSuffix: (value) => this.plugin.settings.countConfig3.customSuffix = value
    });
    if (this.plugin.settings.useAdvancedFormatting) {
      new import_obsidian4.Setting(containerEl).setName("Data type separator").addText(
        (text) => text.setValue(this.plugin.settings.pipeSeparator).onChange(async (value) => {
          this.plugin.settings.pipeSeparator = value;
          await this.plugin.saveSettings();
          await this.plugin.updateDisplayedCounts();
        })
      );
    }
    if (!this.plugin.settings.useAdvancedFormatting) {
      new import_obsidian4.Setting(containerEl).setName("Abbreviate descriptions").setDesc("E.g. show '120w' instead of '120 words'").addToggle(
        (toggle) => toggle.setValue(this.plugin.settings.abbreviateDescriptions).onChange(async (value) => {
          this.plugin.settings.abbreviateDescriptions = value;
          await this.plugin.saveSettings();
          await this.plugin.updateDisplayedCounts();
        })
      );
    }
    new import_obsidian4.Setting(containerEl).setName("Alignment").setDesc(
      "Show data inline with file/folder names, right-aligned, or underneath"
    ).addDropdown((drop) => {
      drop.addOption("inline" /* Inline */, "Inline").addOption("right" /* Right */, "Right-aligned").addOption("below" /* Below */, "Below").setValue(this.plugin.settings.alignment).onChange(async (value) => {
        this.plugin.settings.alignment = value;
        await this.plugin.saveSettings();
        await this.plugin.updateDisplayedCounts();
      });
    });
  }
  renderFolderSettings(containerEl) {
    this.renderSeparator(containerEl);
    new import_obsidian4.Setting(containerEl).setHeading().setName("Folders: Same data as Notes").addToggle(
      (toggle) => toggle.setValue(this.plugin.settings.showSameCountsOnFolders).onChange(async (value) => {
        this.plugin.settings.showSameCountsOnFolders = value;
        await this.plugin.saveSettings();
        this.display();
        await this.plugin.updateDisplayedCounts();
      })
    );
    if (!this.plugin.settings.showSameCountsOnFolders) {
      this.renderCountTypeSetting(containerEl, {
        name: "1st data type to show",
        oldCountType: this.plugin.settings.folderCountType,
        setNewCountType: (value) => {
          this.plugin.settings.folderCountType = value;
          this.plugin.settings.folderCountConfig.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.folderCountType];
        }
      });
      this.renderSessionCountTypeSetting(containerEl, {
        parentCountType: this.plugin.settings.folderCountType,
        oldCountType: this.plugin.settings.folderCountConfig.$sessionCountType,
        setNewCountType: (value) => {
          this.plugin.settings.folderCountConfig.$sessionCountType = value;
        }
      });
      this.renderCustomFormatSetting(containerEl, {
        countType: this.plugin.settings.folderCountType,
        oldSuffix: this.plugin.settings.folderCountConfig.customSuffix,
        setNewSuffix: (value) => this.plugin.settings.folderCountConfig.customSuffix = value
      });
      this.renderCountTypeSetting(containerEl, {
        name: "2nd data type to show",
        oldCountType: this.plugin.settings.folderCountType2,
        setNewCountType: (value) => {
          this.plugin.settings.folderCountType2 = value;
          this.plugin.settings.folderCountConfig2.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.folderCountType2];
        }
      });
      this.renderSessionCountTypeSetting(containerEl, {
        parentCountType: this.plugin.settings.folderCountType2,
        oldCountType: this.plugin.settings.folderCountConfig2.$sessionCountType,
        setNewCountType: (value) => {
          this.plugin.settings.folderCountConfig2.$sessionCountType = value;
        }
      });
      this.renderCustomFormatSetting(containerEl, {
        countType: this.plugin.settings.folderCountType2,
        oldSuffix: this.plugin.settings.folderCountConfig2.customSuffix,
        setNewSuffix: (value) => this.plugin.settings.folderCountConfig2.customSuffix = value
      });
      this.renderCountTypeSetting(containerEl, {
        name: "3rd data type to show",
        oldCountType: this.plugin.settings.folderCountType3,
        setNewCountType: (value) => {
          this.plugin.settings.folderCountType3 = value;
          this.plugin.settings.folderCountConfig3.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.folderCountType3];
        }
      });
      this.renderSessionCountTypeSetting(containerEl, {
        parentCountType: this.plugin.settings.folderCountType3,
        oldCountType: this.plugin.settings.folderCountConfig3.$sessionCountType,
        setNewCountType: (value) => {
          this.plugin.settings.folderCountConfig3.$sessionCountType = value;
        }
      });
      this.renderCustomFormatSetting(containerEl, {
        countType: this.plugin.settings.folderCountType3,
        oldSuffix: this.plugin.settings.folderCountConfig3.customSuffix,
        setNewSuffix: (value) => this.plugin.settings.folderCountConfig3.customSuffix = value
      });
      if (this.plugin.settings.useAdvancedFormatting) {
        new import_obsidian4.Setting(containerEl).setName("Data type separator").addText(
          (text) => text.setValue(this.plugin.settings.folderPipeSeparator).onChange(async (value) => {
            this.plugin.settings.folderPipeSeparator = value;
            await this.plugin.saveSettings();
            await this.plugin.updateDisplayedCounts();
          })
        );
      }
      if (!this.plugin.settings.useAdvancedFormatting) {
        new import_obsidian4.Setting(containerEl).setName("Abbreviate descriptions").addToggle(
          (toggle) => toggle.setValue(this.plugin.settings.folderAbbreviateDescriptions).onChange(async (value) => {
            this.plugin.settings.folderAbbreviateDescriptions = value;
            await this.plugin.saveSettings();
            await this.plugin.updateDisplayedCounts();
          })
        );
      }
      new import_obsidian4.Setting(containerEl).setName("Alignment").addDropdown((drop) => {
        drop.addOption("inline" /* Inline */, "Inline").addOption("right" /* Right */, "Right-aligned").addOption("below" /* Below */, "Below").setValue(this.plugin.settings.folderAlignment).onChange(async (value) => {
          this.plugin.settings.folderAlignment = value;
          await this.plugin.saveSettings();
          await this.plugin.updateDisplayedCounts();
        });
      });
    }
  }
  renderRootSettings(containerEl) {
    this.renderSeparator(containerEl);
    new import_obsidian4.Setting(containerEl).setHeading().setName("Root: Same data as Notes").addToggle(
      (toggle) => toggle.setValue(this.plugin.settings.showSameCountsOnRoot).onChange(async (value) => {
        this.plugin.settings.showSameCountsOnRoot = value;
        await this.plugin.saveSettings();
        this.display();
        await this.plugin.updateDisplayedCounts();
      })
    );
    if (!this.plugin.settings.showSameCountsOnRoot) {
      this.renderCountTypeSetting(containerEl, {
        name: "1st data type to show",
        oldCountType: this.plugin.settings.rootCountType,
        setNewCountType: (value) => {
          this.plugin.settings.rootCountType = value;
          this.plugin.settings.rootCountConfig.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.rootCountType];
        }
      });
      this.renderSessionCountTypeSetting(containerEl, {
        parentCountType: this.plugin.settings.rootCountType,
        oldCountType: this.plugin.settings.rootCountConfig.$sessionCountType,
        setNewCountType: (value) => {
          this.plugin.settings.rootCountConfig.$sessionCountType = value;
        }
      });
      this.renderCustomFormatSetting(containerEl, {
        countType: this.plugin.settings.rootCountType,
        oldSuffix: this.plugin.settings.rootCountConfig.customSuffix,
        setNewSuffix: (value) => this.plugin.settings.rootCountConfig.customSuffix = value
      });
      this.renderCountTypeSetting(containerEl, {
        name: "2nd data type to show",
        oldCountType: this.plugin.settings.rootCountType2,
        setNewCountType: (value) => {
          this.plugin.settings.rootCountType2 = value;
          this.plugin.settings.rootCountConfig2.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.rootCountType2];
        }
      });
      this.renderSessionCountTypeSetting(containerEl, {
        parentCountType: this.plugin.settings.rootCountType2,
        oldCountType: this.plugin.settings.rootCountConfig2.$sessionCountType,
        setNewCountType: (value) => {
          this.plugin.settings.rootCountConfig2.$sessionCountType = value;
        }
      });
      this.renderCustomFormatSetting(containerEl, {
        countType: this.plugin.settings.rootCountType2,
        oldSuffix: this.plugin.settings.rootCountConfig2.customSuffix,
        setNewSuffix: (value) => this.plugin.settings.rootCountConfig2.customSuffix = value
      });
      this.renderCountTypeSetting(containerEl, {
        name: "3rd data type to show",
        oldCountType: this.plugin.settings.rootCountType3,
        setNewCountType: (value) => {
          this.plugin.settings.rootCountType3 = value;
          this.plugin.settings.rootCountConfig3.customSuffix = COUNT_TYPE_DEFAULT_SHORT_SUFFIXES[this.plugin.settings.rootCountType3];
        }
      });
      this.renderSessionCountTypeSetting(containerEl, {
        parentCountType: this.plugin.settings.rootCountType3,
        oldCountType: this.plugin.settings.rootCountConfig3.$sessionCountType,
        setNewCountType: (value) => {
          this.plugin.settings.rootCountConfig3.$sessionCountType = value;
        }
      });
      this.renderCustomFormatSetting(containerEl, {
        countType: this.plugin.settings.rootCountType3,
        oldSuffix: this.plugin.settings.rootCountConfig3.customSuffix,
        setNewSuffix: (value) => this.plugin.settings.rootCountConfig3.customSuffix = value
      });
      if (this.plugin.settings.useAdvancedFormatting) {
        new import_obsidian4.Setting(containerEl).setName("Data type separator").addText(
          (text) => text.setValue(this.plugin.settings.rootPipeSeparator).onChange(async (value) => {
            this.plugin.settings.rootPipeSeparator = value;
            await this.plugin.saveSettings();
            await this.plugin.updateDisplayedCounts();
          })
        );
      }
      if (!this.plugin.settings.useAdvancedFormatting) {
        new import_obsidian4.Setting(containerEl).setName("Abbreviate descriptions").addToggle(
          (toggle) => toggle.setValue(this.plugin.settings.rootAbbreviateDescriptions).onChange(async (value) => {
            this.plugin.settings.rootAbbreviateDescriptions = value;
            await this.plugin.saveSettings();
            await this.plugin.updateDisplayedCounts();
          })
        );
      }
    }
  }
  renderAdvancedSettings(containerEl) {
    this.renderSeparator(containerEl);
    new import_obsidian4.Setting(containerEl).setHeading().setName("Show advanced options").setDesc("Language compatibility and fine-tuning").addToggle(
      (toggle) => toggle.setValue(this.plugin.settings.showAdvanced).onChange(async (value) => {
        this.plugin.settings.showAdvanced = value;
        await this.plugin.saveSettings();
        this.display();
      })
    );
    if (this.plugin.settings.showAdvanced) {
      const opacityChanged = async (value) => {
        this.plugin.settings.labelOpacity = Math.clamp(value, 0, 1);
        await this.plugin.saveSettings();
        await this.plugin.updateDisplayedCounts();
      };
      new import_obsidian4.Setting(containerEl).setName("Label opacity").setDesc("Increase this value to make all count labels in the File Explorer more visible.").addSlider((slider) => {
        slider.setLimits(0, 1, 0.05).setDynamicTooltip().setValue(this.plugin.settings.labelOpacity).onChange((0, import_obsidian4.debounce)(opacityChanged.bind(this), 500));
      });
      const includePathsChanged = async (txt, value) => {
        this.plugin.settings.includeDirectories = value;
        await this.plugin.saveSettings();
        await this.plugin.initialize();
      };
      new import_obsidian4.Setting(containerEl).setName("Include file/folder names").setDesc(
        "Only count paths matching the indicated term(s). Case-sensitive, comma-separated. Defaults to all files. Any term starting with ! will be excluded instead of included."
      ).addText((txt) => {
        txt.setPlaceholder("").setValue(this.plugin.settings.includeDirectories).onChange((0, import_obsidian4.debounce)(includePathsChanged.bind(this, txt), 1e3));
      });
      new import_obsidian4.Setting(containerEl).setName("Exclude comments").setDesc(
        "Exclude %%Obsidian%% and <!--HTML--> comments from counts. May affect performance on large vaults."
      ).addToggle(
        (toggle) => toggle.setValue(this.plugin.settings.excludeComments).onChange(async (value) => {
          this.plugin.settings.excludeComments = value;
          await this.plugin.saveSettings();
          await this.plugin.initialize();
        })
      );
      new import_obsidian4.Setting(containerEl).setName("Exclude code blocks").setDesc(
        "Exclude ```code blocks``` (e.g. DataView snippets) from all counts. May affect performance on large vaults."
      ).addToggle(
        (toggle) => toggle.setValue(this.plugin.settings.excludeCodeBlocks).onChange(async (value) => {
          this.plugin.settings.excludeCodeBlocks = value;
          await this.plugin.saveSettings();
          await this.plugin.initialize();
        })
      );
      new import_obsidian4.Setting(containerEl).setName("Exclude non-visible portions of links").setDesc(
        "For external links, exclude the URI from all counts. For internal links with aliases, only count the alias. May affect performance on large vaults."
      ).addToggle(
        (toggle) => toggle.setValue(this.plugin.settings.excludeNonVisibleLinkPortions).onChange(async (value) => {
          this.plugin.settings.excludeNonVisibleLinkPortions = value;
          await this.plugin.saveSettings();
          await this.plugin.initialize();
        })
      );
      new import_obsidian4.Setting(containerEl).setName("Exclude footnotes").setDesc(
        "Exclude footnotes[^1] from counts. May affect performance on large vaults."
      ).addToggle(
        (toggle) => toggle.setValue(this.plugin.settings.excludeFootnotes).onChange(async (value) => {
          this.plugin.settings.excludeFootnotes = value;
          await this.plugin.saveSettings();
          await this.plugin.initialize();
        })
      );
      new import_obsidian4.Setting(containerEl).setName("Character count method").setDesc("For language compatibility").addDropdown((drop) => {
        drop.addOption("AllCharacters" /* StringLength */, "All characters").addOption(
          "ExcludeWhitespace" /* ExcludeWhitespace */,
          "Exclude whitespace"
        ).setValue(this.plugin.settings.characterCountType).onChange(async (value) => {
          this.plugin.settings.characterCountType = value;
          await this.plugin.saveSettings();
          await this.plugin.initialize();
        });
      });
      new import_obsidian4.Setting(containerEl).setName("Page count method").setDesc("For language compatibility").addDropdown((drop) => {
        drop.addOption("ByWords" /* ByWords */, "Words per page").addOption("ByChars" /* ByChars */, "Characters per page").setValue(this.plugin.settings.pageCountType).onChange(async (value) => {
          this.plugin.settings.pageCountType = value;
          await this.plugin.saveSettings();
          this.display();
          await this.plugin.updateDisplayedCounts();
        });
      });
      const wordsPerMinuteChanged = async (txt, value) => {
        const asNumber = Number(value);
        const isValid = !isNaN(asNumber) && asNumber > 0;
        txt.inputEl.style.borderColor = isValid ? null : "red";
        this.plugin.settings.wordsPerMinute = isValid ? Number(value) : 265;
        await this.plugin.saveSettings();
        await this.plugin.initialize();
      };
      new import_obsidian4.Setting(containerEl).setName("Words per minute").setDesc(
        "Used to calculate Reading Time. 265 is the average speed of an English-speaking adult."
      ).addText((txt) => {
        txt.setPlaceholder("265").setValue(this.plugin.settings.wordsPerMinute.toString()).onChange((0, import_obsidian4.debounce)(wordsPerMinuteChanged.bind(this, txt), 1e3));
      });
      const charsPerMinuteChanged = async (txt, value) => {
        const asNumber = Number(value);
        const isValid = !isNaN(asNumber) && asNumber > 0;
        txt.inputEl.style.borderColor = isValid ? null : "red";
        this.plugin.settings.charsPerMinute = isValid ? Number(value) : 500;
        await this.plugin.saveSettings();
        await this.plugin.initialize();
      };
      new import_obsidian4.Setting(containerEl).setName("CJK characters per minute").setDesc(
        "Used to calculate Reading Time. 500 is the average speed for CJK texts."
      ).addText((txt) => {
        txt.setPlaceholder("500").setValue(this.plugin.settings.charsPerMinute.toString()).onChange((0, import_obsidian4.debounce)(charsPerMinuteChanged.bind(this, txt), 1e3));
      });
      if (this.plugin.settings.pageCountType === "ByWords" /* ByWords */) {
        const wordsPerPageChanged = async (txt, value) => {
          const asNumber = Number(value);
          const isValid = !isNaN(asNumber) && asNumber > 0;
          txt.inputEl.style.borderColor = isValid ? null : "red";
          this.plugin.settings.wordsPerPage = isValid ? Number(value) : 300;
          await this.plugin.saveSettings();
          await this.plugin.initialize();
        };
        new import_obsidian4.Setting(containerEl).setName("Words per page").setDesc(
          "Used for page count. 300 is standard in English language publishing."
        ).addText((txt) => {
          txt.setPlaceholder("300").setValue(this.plugin.settings.wordsPerPage.toString()).onChange((0, import_obsidian4.debounce)(wordsPerPageChanged.bind(this, txt), 1e3));
        });
      }
      if (this.plugin.settings.pageCountType === "ByChars" /* ByChars */) {
        new import_obsidian4.Setting(containerEl).setName("Include whitespace characters in page count").addToggle(
          (toggle) => toggle.setValue(this.plugin.settings.charsPerPageIncludesWhitespace).onChange(async (value) => {
            this.plugin.settings.charsPerPageIncludesWhitespace = value;
            await this.plugin.saveSettings();
            this.display();
            await this.plugin.initialize();
          })
        );
        const charsPerPageChanged = async (txt, value) => {
          const asNumber = Number(value);
          const isValid = !isNaN(asNumber) && asNumber > 0;
          txt.inputEl.style.borderColor = isValid ? null : "red";
          const defaultCharsPerPage = 1500;
          this.plugin.settings.charsPerPage = isValid ? Number(value) : defaultCharsPerPage;
          await this.plugin.saveSettings();
          await this.plugin.initialize();
        };
        new import_obsidian4.Setting(containerEl).setName("Characters per page").setDesc(
          `Used for page count. ${this.plugin.settings.charsPerPageIncludesWhitespace ? "2400 is common in Danish." : "1500 is common in German (Normseite)."}`
        ).addText((txt) => {
          txt.setPlaceholder("1500").setValue(this.plugin.settings.charsPerPage.toString()).onChange((0, import_obsidian4.debounce)(charsPerPageChanged.bind(this, txt), 1e3));
        });
      }
      const dateFormatChanged = async (txt, value) => {
        const isValid = typeof value === "string" && !!value.trim();
        this.plugin.settings.momentDateFormat = isValid ? value : "";
        await this.plugin.saveSettings();
        await this.plugin.initialize();
      };
      new import_obsidian4.Setting(containerEl).setName("Date format").setDesc("MomentJS date format to use for date strings").addText((txt) => {
        txt.setPlaceholder("YYYY/MM/DD").setValue(this.plugin.settings.momentDateFormat).onChange((0, import_obsidian4.debounce)(dateFormatChanged.bind(this, txt), 1e3));
      });
      new import_obsidian4.Setting(containerEl).setName("Debug mode").setDesc("Log debugging information to the developer console").addToggle(
        (toggle) => toggle.setValue(this.plugin.settings.debugMode).onChange(async (value) => {
          this.plugin.settings.debugMode = value;
          this.plugin.debugHelper.setDebugMode(value);
          this.plugin.fileHelper.setDebugMode(value);
          await this.plugin.saveSettings();
        })
      );
    }
  }
  renderReanalyzeButton(containerEl) {
    this.renderSeparator(containerEl);
    new import_obsidian4.Setting(containerEl).setHeading().setName("Recount all documents").setDesc(
      "If changes have occurred outside of Obsidian, you may need to trigger a manual recount"
    ).addButton(
      (button) => button.setButtonText("Recount").setCta().onClick(async () => {
        button.disabled = true;
        await this.plugin.initialize();
        button.setButtonText("Done");
        button.removeCta();
        setTimeout(() => {
          button.setButtonText("Recount");
          button.setCta();
          button.disabled = false;
        }, 1e3);
      })
    );
  }
  renderDonationButton(containerEl) {
    this.renderSeparator(containerEl);
    const label = containerEl.createEl("div", {
      cls: [
        "setting-item",
        "setting-item-heading",
        "novel-word-count-settings-header",
        "novel-word-count-donation-line"
      ]
    });
    label.createEl("div", {
      text: "Enjoying this plugin? Want more features?"
    });
    const button = label.createEl("div");
    button.innerHTML = `<a href='https://ko-fi.com/J3J6OWA5C' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi2.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>`;
  }
  renderCountTypeSetting(containerEl, config) {
    new import_obsidian4.Setting(containerEl).setName(config.name).setDesc(getDescription(config.oldCountType)).addDropdown((drop) => {
      for (const countType of COUNT_TYPES) {
        drop.addOption(countType, COUNT_TYPE_DISPLAY_STRINGS[countType]);
      }
      drop.setValue(config.oldCountType).onChange(async (value) => {
        config.setNewCountType(value);
        await this.plugin.saveSettings();
        this.display();
        await this.plugin.updateDisplayedCounts();
      });
    });
  }
  renderSessionCountTypeSetting(containerEl, config) {
    if (config.parentCountType !== "tracksession" /* TrackSession */) {
      return;
    }
    new import_obsidian4.Setting(containerEl).setDesc("[Track Session] Session count type").addDropdown((drop) => {
      for (const countType of SESSION_COUNT_TYPES) {
        drop.addOption(countType, COUNT_TYPE_DISPLAY_STRINGS[countType]);
      }
      drop.setValue(config.oldCountType).onChange(async (value) => {
        config.setNewCountType(value);
        await this.plugin.saveSettings();
        this.display();
        await this.plugin.updateDisplayedCounts();
      });
    });
  }
  renderCustomFormatSetting(containerEl, config) {
    if (!this.plugin.settings.useAdvancedFormatting || config.countType === "none" /* None */) {
      return;
    }
    if (UNFORMATTABLE_COUNT_TYPES.includes(config.countType)) {
      new import_obsidian4.Setting(containerEl).setDesc(
        `[${COUNT_TYPE_DISPLAY_STRINGS[config.countType]}] can't be formatted.`
      );
    } else {
      new import_obsidian4.Setting(containerEl).setDesc(
        `[${COUNT_TYPE_DISPLAY_STRINGS[config.countType]}] Custom suffix`
      ).addText(
        (text) => text.setValue(config.oldSuffix).onChange(async (value) => {
          config.setNewSuffix(value);
          await this.plugin.saveSettings();
          await this.plugin.updateDisplayedCounts();
        })
      );
    }
  }
  renderFrontmatterKeySetting(containerEl, config) {
    if (config.countType !== "frontmatterKey" /* FrontmatterKey */) {
      return;
    }
    new import_obsidian4.Setting(containerEl).setDesc(
      `[${COUNT_TYPE_DISPLAY_STRINGS["frontmatterKey" /* FrontmatterKey */]}] Key name`
    ).addText(
      (text) => text.setValue(config.oldKey).onChange(async (value) => {
        config.setNewKey(value);
        await this.plugin.saveSettings();
        await this.plugin.updateDisplayedCounts();
      })
    );
  }
  renderSeparator(containerEl) {
    containerEl.createEl("hr", {
      cls: "novel-word-count-hr"
    });
  }
};

// main.ts
var import_obsidian5 = require("obsidian");
var NovelWordCountPlugin = class extends import_obsidian5.Plugin {
  constructor(app, manifest) {
    super(app, manifest);
    this.debugHelper = new DebugHelper();
    this.FIVE_MINUTES = 5 * 60 * 1e3;
    this.saveSettingsDebounced = (0, import_obsidian5.debounce)(this.saveSettings, this.FIVE_MINUTES, false);
    this.fileHelper = new FileHelper(this.app, this);
    this.eventHelper = new EventHelper(
      this,
      app,
      this.debugHelper,
      this.fileHelper
    );
    this.nodeLabelHelper = new NodeLabelHelper(this);
    this.savedDataHelper = new SavedDataHelper(this);
  }
  get settings() {
    return this.savedData.settings;
  }
  // LIFECYCLE
  async onload() {
    this.savedData = await this.savedDataHelper.getSavedData();
    this.fileHelper.setDebugMode(this.savedData.settings.debugMode);
    this.debugHelper.setDebugMode(this.savedData.settings.debugMode);
    this.debugHelper.debug(`Detected locales: [${navigator.languages}]`);
    this.debugHelper.debug("onload lifecycle hook");
    this.addSettingTab(new NovelWordCountSettingTab(this.app, this));
    this.addCommand({
      id: "recount-vault",
      name: "Recount all notes / Reset session",
      callback: async () => {
        this.debugHelper.debug("[Recount] command triggered");
        await this.initialize();
      }
    });
    this.addCommand({
      id: "cycle-count-type",
      name: "Show next data type (1st position)",
      callback: async () => {
        this.debugHelper.debug("[Cycle next data type] command triggered");
        this.settings.countType = COUNT_TYPES[(COUNT_TYPES.indexOf(this.settings.countType) + 1) % COUNT_TYPES.length];
        await this.saveSettings();
        this.updateDisplayedCounts();
      }
    });
    this.addCommand({
      id: "toggle-abbreviate",
      name: "Toggle abbreviation on Notes",
      callback: async () => {
        this.debugHelper.debug(
          "[Toggle abbrevation - Notes] command triggered"
        );
        this.settings.abbreviateDescriptions = !this.settings.abbreviateDescriptions;
        await this.saveSettings();
        this.updateDisplayedCounts();
      }
    });
    for (const countType of COUNT_TYPES) {
      this.addCommand({
        id: `set-count-type-${countType}`,
        name: `Show ${COUNT_TYPE_DISPLAY_STRINGS[countType]} (1st position)`,
        callback: async () => {
          this.debugHelper.debug(
            `[Set count type to ${countType}] command triggered`
          );
          this.settings.countType = countType;
          await this.saveSettings();
          this.updateDisplayedCounts();
        }
      });
    }
    this.eventHelper.handleEvents();
    this.initialize();
  }
  async onunload() {
    await this.saveSettings();
  }
  // SETTINGS
  async saveSettings() {
    this.debugHelper.debug("Saving to data.json.");
    await this.saveData(this.savedData);
  }
  // PUBLIC
  /**
  	Called with (true) when the plugin initializes or the user clicks Reanalyze.
  	Called with (false) every second while waiting for the file explorer to load.
  */
  async initialize(reinitializeAllCounts = true) {
    this.debugHelper.debug("initialize");
    this.app.workspace.onLayoutReady(async () => {
      if (reinitializeAllCounts) {
        await this.eventHelper.reinitializeAllCounts();
      }
      try {
        await this.getFileExplorerLeaf();
        await this.updateDisplayedCounts();
      } catch (err) {
        this.debugHelper.debug("Error while updating displayed counts");
        this.debugHelper.debug(err);
        setTimeout(() => {
          this.initialize(false);
        }, 1e3);
      }
    });
  }
  async updateDisplayedCounts(file = null) {
    var _a, _b;
    const debugEnd = this.debugHelper.debugStart(
      `updateDisplayedCounts [${file == null ? "ALL" : file.path}]`
    );
    if (!Object.keys(this.savedData.cachedCounts).length) {
      this.debugHelper.debug("No cached data found; skipping update.");
      return;
    }
    let fileExplorerLeaf;
    try {
      fileExplorerLeaf = await this.getFileExplorerLeaf();
    } catch (err) {
      this.debugHelper.debug("File explorer leaf not found; skipping update.");
      return;
    }
    const vaultCount = this.fileHelper.getCachedDataForPath(
      this.savedData.cachedCounts,
      "/"
    );
    document.documentElement.style.setProperty("--novel-word-count-opacity", `${this.settings.labelOpacity}`);
    const drawers = [this.app.workspace.leftSplit, this.app.workspace.rightSplit];
    let hasMobileDrawer = false;
    for (const drawer of drawers) {
      this.setContainerClass(drawer.containerEl);
      if (!(drawer == null ? void 0 : drawer.fileCountEl)) {
        continue;
      }
      drawer.fileCountEl.setAttribute(
        "data-novel-word-count-plugin",
        this.nodeLabelHelper.getNodeLabel(vaultCount)
      );
      hasMobileDrawer = true;
    }
    const fileExplorerView = fileExplorerLeaf.view;
    const fileItems = fileExplorerView.fileItems;
    if (!hasMobileDrawer && ((_a = fileExplorerView == null ? void 0 : fileExplorerView.headerDom) == null ? void 0 : _a.navButtonsEl)) {
      fileExplorerView.headerDom.navButtonsEl.setAttribute(
        "data-novel-word-count-plugin",
        this.nodeLabelHelper.getNodeLabel(vaultCount)
      );
    }
    if (file) {
      const relevantItems = Object.keys(fileItems).filter(
        (path) => file.path.includes(path)
      );
      this.debugHelper.debug(
        "Setting display counts for",
        relevantItems.length,
        "fileItems matching path",
        file.path
      );
    } else {
      this.debugHelper.debug(
        `Setting display counts for ${Object.keys(fileItems).length} fileItems`
      );
    }
    for (const path in fileItems) {
      if (file && (!file.path.includes(path) || file.path === "/")) {
        continue;
      }
      const counts = this.fileHelper.getCachedDataForPath(
        this.savedData.cachedCounts,
        path
      );
      const item = fileItems[path];
      ((_b = item.titleEl) != null ? _b : item.selfEl).setAttribute(
        "data-novel-word-count-plugin",
        this.nodeLabelHelper.getNodeLabel(counts)
      );
    }
    debugEnd();
  }
  // FUNCTIONALITY
  async getFileExplorerLeaf() {
    return new Promise((resolve, reject) => {
      let foundLeaf = null;
      this.app.workspace.getLeavesOfType("file-explorer").forEach((leaf) => {
        if (foundLeaf) {
          return;
        }
        const view = leaf.view;
        if (!view || !view.fileItems) {
          return;
        }
        foundLeaf = leaf;
        resolve(foundLeaf);
      });
      if (!foundLeaf) {
        reject(Error("Could not find file explorer leaf."));
      }
    });
  }
  setContainerClass(container) {
    if (!container) {
      this.debugHelper.debug("No container was passed to setContainerClass");
      return;
    }
    container.toggleClass(`novel-word-count--active`, true);
    const notePrefix = `novel-word-count--note-`;
    const folderPrefix = `novel-word-count--folder-`;
    const alignmentClasses = ALIGNMENT_TYPES.map((at) => notePrefix + at).concat(ALIGNMENT_TYPES.map((at) => folderPrefix + at));
    for (const ac of alignmentClasses) {
      container.toggleClass(ac, false);
    }
    container.toggleClass(notePrefix + this.settings.alignment, true);
    const folderAlignment = this.settings.showSameCountsOnFolders ? this.settings.alignment : this.settings.folderAlignment;
    container.toggleClass(folderPrefix + folderAlignment, true);
  }
};

/* nosourcemap */