| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- 'use strict';
- var obsidian = require('obsidian');
- /*! *****************************************************************************
- Copyright (c) Microsoft Corporation.
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
- ***************************************************************************** */
- function __awaiter(thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- }
- const reKey = /\[\^(.+?(?=\]))\]/gi;
- const reDefinition = /\[\^(.+)\]\:/;
- // https://stackoverflow.com/a/1830844
- function isNumeric(value) {
- return !isNaN(value - parseFloat(value));
- }
- function tidyFootnotes(editor) {
- let markers = [];
- let definitions = new Map();
- let firstDefinitionLine = -1;
- let definitionsIndexed = new Map();
- // Iterate through each line
- const lineCount = editor.lineCount();
- let prevKey = '';
- for (let i = 0; i < lineCount; i++) {
- const line = editor.getLine(i);
- let isDefinition = false;
- let match;
- if (prevKey.length) {
- const hasIndent = /^[ \t]/.test(line);
- const isLastLine = i === (lineCount - 1);
- if (hasIndent || (line.length === 0 && !isLastLine)) {
- // Append line to the previous footnote definition
- const value = definitions.get(prevKey);
- definitions.set(prevKey, value + "\n" + line);
- markers[markers.length - 1].length++;
- continue;
- }
- else {
- prevKey = '';
- }
- }
- // Look for footnote definition
- while ((match = reDefinition.exec(line)) !== null) {
- if (match.length < 1)
- return;
- isDefinition = true;
- // Remember definition and where it is
- let key = match[1];
- let value = line.substring(match[0].length);
- definitions.set(key, value);
- prevKey = key;
- let marker = {
- key,
- line: i,
- index: 0,
- length: 0,
- isDefinition: true
- };
- markers.push(marker);
- // Remember first definition line to insert combined list later
- if (firstDefinitionLine === -1) {
- firstDefinitionLine = i;
- }
- break;
- }
- if (isDefinition)
- continue;
- // Look for footnote key
- while ((match = reKey.exec(line)) !== null) {
- if (match.length < 1)
- return;
- // Remember where footnote key is
- let key = match[1];
- let marker = {
- key,
- line: i,
- index: match.index,
- length: match[0].length,
- isDefinition: false
- };
- markers.push(marker);
- if (!definitionsIndexed.has(key)) {
- // Add key into index
- definitionsIndexed.set(key, {
- key,
- newKey: key,
- isNumber: isNumeric(key),
- value: ''
- });
- }
- }
- }
- // Assign definition to key in index
- // If definition has no key, it will be appended with its current key
- definitions.forEach((value, key) => {
- definitionsIndexed.set(key, {
- key,
- newKey: key,
- isNumber: isNumeric(key),
- value
- });
- });
- // Re-index numbers and construct combined definitions output
- let count = 1;
- let definitionsStr = '';
- definitionsIndexed.forEach((definition, marker) => {
- let key = definition.key;
- if (definition.isNumber) {
- const current = definitionsIndexed.get(marker);
- key = count.toString();
- definitionsIndexed.set(marker, Object.assign(Object.assign({}, current), { newKey: key }));
- count++;
- }
- definitionsStr += `[^${key}]:${definition.value}\n`;
- });
- const markersCount = markers.length;
- for (let i = markersCount - 1; i >= 0; i--) {
- const marker = markers[i];
- const markerLine = marker.line;
- if (marker.isDefinition) {
- let rangeStart, rangeEnd;
- const lineEnd = markerLine + 1 + marker.length;
- if (lineEnd === editor.lineCount()) {
- // Replace from previous to current line to fix CodeMirror 6 error
- rangeStart = { line: markerLine, ch: 0 };
- rangeEnd = { line: lineEnd - 1, ch: Infinity };
- }
- else {
- // Replace from current to next line
- rangeStart = { line: markerLine, ch: 0 };
- rangeEnd = { line: lineEnd, ch: 0 };
- }
- if (markerLine === firstDefinitionLine) {
- // Replace first definition line with list of indexed definitions
- editor.replaceRange(definitionsStr, rangeStart, rangeEnd);
- continue;
- }
- // Remove line(s)
- editor.replaceRange('', rangeStart, rangeEnd);
- continue;
- }
- // Check if key has changed
- const definition = definitionsIndexed.get(marker.key);
- const newKey = definition.newKey;
- if (marker.key === newKey)
- continue;
- // Replace footnote key in line with the new one
- const line = editor.getLine(markerLine);
- const prefix = line.substring(0, marker.index);
- const newMarker = `[^${newKey}]`;
- const suffix = line.substr(marker.index + marker.length);
- const newLine = prefix + newMarker + suffix;
- editor.replaceRange(newLine, { line: markerLine, ch: 0 }, { line: markerLine, ch: Infinity });
- }
- if (firstDefinitionLine == -1) {
- // If there are no definitions, add definitions list at the end
- const lineCount = editor.lineCount();
- editor.replaceRange("\n\n" + definitionsStr, { line: lineCount, ch: 0 }, { line: lineCount, ch: Infinity });
- }
- // console.log(markers, definitions, definitionsIndexed, definitionsStr);
- }
- class TidyFootnotes extends obsidian.Plugin {
- onload() {
- return __awaiter(this, void 0, void 0, function* () {
- this.addCommand({
- id: 'tidy-footnotes',
- name: 'Tidy Footnotes',
- checkCallback: (checking) => {
- // Ensure the active view is a Markdown editor
- const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
- if (checking)
- return !!view;
- if (!view || view.sourceMode == undefined)
- return false;
- let editor = view.editor;
- tidyFootnotes(editor);
- }
- });
- });
- }
- }
- module.exports = TidyFootnotes;
|