diff --git a/README.md b/README.md
index 1a39523..26cc16c 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ This hotkey lets you:
- Places your cursor so you can fill in the details quickly
- Jump from your footnote TO the footnote detail
- Jump from your footnote detail BACK to the footnote
+- New in January 2022: Automatic re-indexing of footnotes

@@ -36,6 +37,9 @@ I personally use Command+Shift+6 because "6" on
- And a new footnote details marker (e.g. `[^2]: `) is inserted on the last line of the document
- And my cursor is now placed at the end of the detail marker (e.g. `[^2]: ▊`)
+### Scenario: Footnote is inserted in between existing footnotes
+- All existing footnotes get updated and the new one inserted as in the previous Scenarios
+
### Scenario: Jumping TO a footnote detail
- Given I'm on a footnote detail line (e.g. `[^1]: ▊`)
- When I hit `my footnote hotkey`
@@ -47,93 +51,8 @@ I personally use Command+Shift+6 because "6" on
- Then my cursor is placed to the right of the footnote (e.g. `[^1]: ▊`)
### Known Limitations or Untested Scenarios
-#### Indices are not updated
-Inserting new footnote in-between two existing footnotes will insert the next numeric index (e.g. `1, 3, 2`).
-
-It will NOT update the indices according to their natural order (e.g. `1, 2, 3`).
-
-```markdown
-Example sentence[^1] with two▊ footnotes[^2] already.
-
-[^1]: Foo
-[^2]: Bar
-```
-
-After insertion:
-
-```markdown
-Example sentence[^1] with two[^3] footnotes[^2] already.
-
-[^1]: Foo
-[^2]: Bar
-[^3]: Baz
-```
-
-See "Automatically Re-Index Footnotes" below for a proposed feature
-
-## Future Possible Feature Ideas
-### Automatically Re-Index Footnotes
-Re-index and re-sort all footnotes when you insert a new one in-between one or more existing numbered footnotes:
-
-```markdown
-Example sentence[^1] with two▊ footnotes[^2] already.
-
-[^1]: Foo
-[^2]: Bar
-```
-#### Base Scenario
-- Given there are two footnotes already
-- When I enter a new footnote in-between those two
-- Then the NEW footnote gets the index "2"
-- And the previously second footnote gets the index "3"
-- And the NEW footnote detail is inserted as the second entry at the bottom
-- And the previously second footnote detail at the bottom is updated to be "3"
-- And the previously second footnote detail at the bottom is updated to be in third position
-
-```markdown
-Example sentence[^1] with two[^2] footnotes[^3] already.
-
-[^1]: Foo
-[^2]: Baz
-[^3]: Bar▊
-```
-
-#### Edge Cases to consider ("What if...?")
-##### What if... new footnote is inserted before the first footnote?
- ```markdown
- Some sentence▊ with existing note[^1]
-
- [^1]: Details
- ```
-##### What if... text has the same footnote at several places?
- ```markdown
- Some sentence with existing note[^1] and the same▊ footnote re-appears later[^1].
-
-
- [^1]: Details
- ```
-##### What if...Footnote details are spread across the text?
- ```markdown
- Some sentence with existing note[^1] some more text▊
-
- [^1]: Inline footnote details
-
- Another text part▊
- ```
-##### What if... the footnote details are multi-line on the bottom?
- ```markdown
- Some sentence with existing note[^1] some more text▊
-
- [^1]: The details that
- Span across
- Multiple lines
- ```
-##### What if... there are non-numeric footnotes in the text?
- ```markdown
- Some sentence with existing note[^✝] some more text▊
-
- [^✝]: Details
- ```
+#### Manually Deleting Footnotes or Copy-Pasting Text Chunks
+Because the plugin only gets triggered when it is manually invoked for example by pressing the hotkey, this is an unsolved issue.
## Background
This plugin is based on the great idea by [jacob.4ristotle](https://forum.obsidian.md/u/jacob.4ristotle/summary) posted in the ["Footnote Shortcut"](https://forum.obsidian.md/t/footnote-shortcut/8872) thread.
diff --git a/main.ts b/main.ts
index 8c931af..3694e5c 100644
--- a/main.ts
+++ b/main.ts
@@ -3,6 +3,7 @@ import { MarkdownView, Plugin } from 'obsidian';
export default class MyPlugin extends Plugin {
private detailLineRegex = /\[\^(\d+)\]\:/;
+ private reOnlyDetails = /\[\^(\d+)\]\:/gi;
private reOnlyMarkers = /\[\^(\d+)\]/gi;
private numericalRe = /(\d+)/
@@ -27,12 +28,11 @@ export default class MyPlugin extends Plugin {
const doc = mdView.sourceMode.cmEditor;
const cursorPosition = doc.getCursor();
const lineText = doc.getLine(cursorPosition.line);
- const markdownText = mdView.data;
if (this.shouldJumpFromDetailToMarker(lineText, cursorPosition, doc)) return;
if (this.shouldJumpFromMarkerToDetail(lineText, cursorPosition, doc)) return;
- return this.shouldCreateNewFootnote(lineText, cursorPosition, doc, markdownText);
+ return this.shouldCreateNewFootnote(lineText, cursorPosition, doc);
}
private shouldJumpFromDetailToMarker(lineText: string, cursorPosition: CodeMirror.Position, doc: CodeMirror.Editor) {
@@ -116,43 +116,56 @@ export default class MyPlugin extends Plugin {
return false;
}
- private shouldCreateNewFootnote(lineText: string, cursorPosition: CodeMirror.Position, doc: CodeMirror.Editor, markdownText: string) {
+ private shouldCreateNewFootnote(lineText: string, cursorPosition: CodeMirror.Position, doc: CodeMirror.Editor) {
// create new footnote with the next numerical index
- let matches = markdownText.match(this.reOnlyMarkers);
let numbers: Array = [];
let currentMax = 1;
+ let match
- if (matches != null) {
- for (let i = 0; i <= matches.length - 1; i++) {
- let match = matches[i];
- match = match.replace("[^", "");
- match = match.replace("]", "");
- let matchNumber = Number(match);
- numbers[i] = matchNumber;
- if (matchNumber + 1 > currentMax) {
- currentMax = matchNumber + 1;
- }
+ // search highest footnote ID of footnotes before the cursor position
+ let beforeCursor = doc.getRange({line: 0, ch: 0}, doc.getCursor());
+
+ while ((match = this.reOnlyMarkers.exec(beforeCursor)) !== null) {
+ if (Number(match[1]) + 1 > currentMax) {
+ currentMax = Number(match[1]) + 1;
}
}
-
let footNoteId = currentMax;
- let footnoteMarker = `[^${footNoteId}]`;
- let linePart1 = lineText.substr(0, cursorPosition.ch)
- let linePart2 = lineText.substr(cursorPosition.ch);
- let newLine = linePart1 + footnoteMarker + linePart2
- doc.replaceRange(newLine, {line: cursorPosition.line, ch: 0}, {line: cursorPosition.line, ch: lineText.length})
+ // increment footnote IDs after the cursor position
+ // only IDs bigger or equal to the new ID will be incremented in case an earlier one is used more than once
+ // this also includes the footnote details which is fine since we need to increment those anyways
+ let afterCursor = doc.getRange(doc.getCursor(), {line: doc.lastLine(), ch: doc.getLine(doc.lastLine()).length});
- let lastLine = doc.getLine(doc.lineCount() - 1);
+ while ((match = this.reOnlyMarkers.exec(afterCursor)) !== null) {
+ if (Number(match[1]) >= footNoteId) {
+ const p = doc.offsetToPos(beforeCursor.length+match.index);
+ doc.replaceRange(String(Number(match[1])+1), {line: p.line, ch: p.ch + 2}, {line: p.line, ch: p.ch + 3});
+ }
+ }
+ // add new footnote marker
+ let footnoteMarker = `[^${footNoteId}]`;
+ doc.replaceRange(footnoteMarker, doc.getCursor())
+
+ // add new footnote detail
+ // search for the correct place first
let footnoteDetail = `[^${footNoteId}]: `;
- if (lastLine.length > 0) {
- doc.replaceRange("\n" + footnoteDetail, {line: doc.lineCount(), ch: 0})
- } else {
- doc.replaceRange(footnoteDetail, {line: doc.lineCount(), ch: 0})
+ while ((match = this.reOnlyDetails.exec(afterCursor)) !== null) {
+ if (Number(match[1]) == footNoteId) {
+ const p = doc.offsetToPos(beforeCursor.length + match.index + footnoteMarker.length);
+ doc.replaceRange(footnoteDetail + '\n', {line: p.line, ch: 0});
+ doc.setCursor({line: p.line, ch: footnoteDetail.length});
+ return;
+ }
}
-
- doc.setCursor({line: doc.lineCount(), ch: footnoteDetail.length});
+ // if no footnote details where found just add a line to the bottom of the document
+ if (footNoteId == 1) {
+ // this is just for aesthetics
+ doc.replaceRange('\n', {line: doc.lastLine(), ch: doc.getLine(doc.lastLine()).length});
+ }
+ doc.replaceRange('\n' + footnoteDetail, {line: doc.lastLine(), ch: doc.getLine(doc.lastLine()).length});
+ doc.setCursor({line: doc.lastLine(), ch: footnoteDetail.length});
}
}
\ No newline at end of file