-
Notifications
You must be signed in to change notification settings - Fork 22
/
main.ts
158 lines (132 loc) · 5.2 KB
/
main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import { MarkdownView, Plugin } from 'obsidian';
export default class MyPlugin extends Plugin {
private detailLineRegex = /\[\^(\d+)\]\:/;
private reOnlyMarkers = /\[\^(\d+)\]/gi;
private numericalRe = /(\d+)/
async onload() {
this.addCommand({
id: 'insert-footnote',
name: 'Insert and Navigate Footnote',
checkCallback: (checking: boolean) => {
if (checking) return !!this.app.workspace.getActiveViewOfType(MarkdownView);
this.insertFootnote();
}
});
}
insertFootnote() {
const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (!mdView) return false
if (mdView.sourceMode == undefined) return false;
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);
}
private shouldJumpFromDetailToMarker(lineText: string, cursorPosition: CodeMirror.Position, doc: CodeMirror.Editor) {
// check if we're in a footnote detail line ("[^1]: footnote")
// if so, jump cursor back to the footnote in the text
// https://github.com/akaalias/obsidian-footnotes#improved-quick-navigation
let match = lineText.match(this.detailLineRegex)
if (match) {
let s = match[0]
let index = s.replace("[^", "");
index = index.replace("]:", "");
let footnote = s.replace(":", "");
let returnLineIndex = cursorPosition.line;
// find the FIRST OCCURENCE where this footnote exists in the text
for (let i = 0; i < doc.lineCount(); i++) {
let scanLine = doc.getLine(i);
if (scanLine.contains(footnote)) {
let cursorLocationIndex = scanLine.indexOf(footnote);
returnLineIndex = i;
doc.setCursor({line: returnLineIndex, ch: cursorLocationIndex + footnote.length});
return true;
}
}
}
return false;
}
private shouldJumpFromMarkerToDetail(lineText: string, cursorPosition: CodeMirror.Position, doc: CodeMirror.Editor) {
// Jump cursor TO detail marker
// check if the cursor is inside or left or right of a footnote in a line
// if so, jump cursor to the footnote detail line
// https://github.com/akaalias/obsidian-footnotes#improved-quick-navigation
// does this line have a footnote marker?
// does the cursor overlap with one of them?
// if so, which one?
// find this footnote marker's detail line
// place cursor there
let reOnlyMarkersMatches = lineText.match(this.reOnlyMarkers);
let markerTarget = null;
if (reOnlyMarkersMatches) {
for (let i = 0; i <= reOnlyMarkersMatches.length; i++) {
let marker = reOnlyMarkersMatches[i];
if (marker != undefined) {
let indexOfMarkerInLine = lineText.indexOf(marker);
if (cursorPosition.ch >= indexOfMarkerInLine && cursorPosition.ch <= indexOfMarkerInLine + marker.length) {
markerTarget = marker;
break;
}
}
}
}
if (markerTarget != null) {
// extract index
let match = markerTarget.match(this.numericalRe);
if (match) {
let indexString = match[0];
let markerIndex = Number(indexString);
// find the first line with this detail marker index in it.
for (let i = 0; i < doc.lineCount(); i++) {
let theLine = doc.getLine(i);
let lineMatch = theLine.match(this.detailLineRegex);
if (lineMatch) {
// compare to the index
let indexMatch = lineMatch[1];
let indexMatchNumber = Number(indexMatch);
if (indexMatchNumber == markerIndex) {
doc.setCursor({line: i, ch: lineMatch[0].length});
return true;
}
}
}
}
}
return false;
}
private shouldCreateNewFootnote(lineText: string, cursorPosition: CodeMirror.Position, doc: CodeMirror.Editor, markdownText: string) {
// create new footnote with the next numerical index
let matches = markdownText.match(this.reOnlyMarkers);
let numbers: Array<number> = [];
let currentMax = 1;
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;
}
}
}
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})
let lastLine = doc.getLine(doc.lineCount() - 1);
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})
}
doc.setCursor({line: doc.lineCount(), ch: footnoteDetail.length});
}
}