Skip to content

Commit d8ddb32

Browse files
authored
Add option to include a table of contents in each gist, defaulting to disabled (#726)
* Add option to include a table of contents in each gist, defaulting to disabled Built entirely with GitHub Copilot Agent Mode in VS Code ❤️🤖 Closes #709. * Update readme with new option * Add headline about tables of contents * Tweak readme headline * Switch to remark-toc and tweak option name and description
1 parent 6865835 commit d8ddb32

File tree

4 files changed

+1345
-18
lines changed

4 files changed

+1345
-18
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This plugin for Obsidian (https://obsidian.md) allows you to share your notes as
66
- 💼 Works with GitHub.com and [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server/admin/overview/about-github-enterprise-server)
77
- 🔄 Update your gist when you make changes to your notes
88
- 🗑️ Delete a gist if you change your mind
9+
- 📜 Optionally include a table of contents in your gist for easy navigation
910

1011
## Usage
1112

@@ -48,6 +49,7 @@ This plugin for Obsidian (https://obsidian.md) allows you to share your notes as
4849
- **Include front matter in gists** (_disabled by default_): Whether your gists should include frontmatter (properties). If this is disabled, the front matter will be stripped from your gists.
4950
- **Enable auto-saving Gists after edit** (_disabled by default_): Whether your gists should be automatically updated when you save your note. If this is disabled, you can update your gists automatically with the normal "share" command.
5051
- **Enable auto-save notice** (_disabled by default_): Whether a notice should be displayed when your gists are automatically updated. This option is only relevant if the "Enable auto-saving Gists after edit" option above is turned on.
52+
- **Include table of contents** (_disabled by default_): Whether to automatically generate and include a table of contents at the start of each gist
5153

5254
## Securing your GitHub personal access token(s)
5355

main.ts

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import {
1414
debounce,
1515
} from 'obsidian';
1616
import matter from 'gray-matter';
17+
import { remark } from 'remark';
18+
import remarkToc from 'remark-toc';
1719
import {
1820
CreateGistResultStatus,
1921
DeleteGistResultStatus,
@@ -45,13 +47,15 @@ interface ShareAsGistSettings {
4547
enableAutoSaving: boolean;
4648
showAutoSaveNotice: boolean;
4749
includeFrontMatter: boolean;
50+
includeTableOfContents: boolean;
4851
}
4952

5053
const DEFAULT_SETTINGS: ShareAsGistSettings = {
5154
includeFrontMatter: false,
5255
enableUpdatingGistsAfterCreation: true,
5356
enableAutoSaving: false,
5457
showAutoSaveNotice: false,
58+
includeTableOfContents: false,
5559
};
5660

5761
interface ShareGistEditorCallbackParams {
@@ -90,6 +94,11 @@ const getLatestSettings = async (
9094
return plugin.settings;
9195
};
9296

97+
const addTableOfContents = async (content: string): Promise<string> => {
98+
const resultAsVFile = await remark().use(remarkToc).process(content);
99+
return String(resultAsVFile);
100+
};
101+
93102
const stripFrontMatter = (content: string): string => matter(content).content;
94103

95104
/*
@@ -209,8 +218,11 @@ const shareGistEditorCallback =
209218
(opts: ShareGistEditorCallbackParams) => async () => {
210219
const { isPublic, app, plugin, target } = opts;
211220

212-
const { enableUpdatingGistsAfterCreation, includeFrontMatter } =
213-
await getLatestSettings(plugin);
221+
const {
222+
enableUpdatingGistsAfterCreation,
223+
includeFrontMatter,
224+
includeTableOfContents,
225+
} = await getLatestSettings(plugin);
214226

215227
const view = app.workspace.getActiveViewOfType(MarkdownView);
216228

@@ -227,10 +239,14 @@ const shareGistEditorCallback =
227239
target,
228240
).filter((sharedGist) => sharedGist.isPublic === isPublic);
229241

230-
const gistContent = includeFrontMatter
242+
const baseContent = includeFrontMatter
231243
? originalContent
232244
: stripFrontMatter(originalContent);
233245

246+
const content = includeTableOfContents
247+
? await addTableOfContents(baseContent)
248+
: baseContent;
249+
234250
if (enableUpdatingGistsAfterCreation && existingSharedGists.length) {
235251
new SelectExistingGistModal(
236252
app,
@@ -240,7 +256,7 @@ const shareGistEditorCallback =
240256
if (sharedGist) {
241257
const result = await updateGist({
242258
sharedGist,
243-
content: gistContent,
259+
content,
244260
});
245261

246262
if (result.status === CreateGistResultStatus.Succeeded) {
@@ -260,7 +276,7 @@ const shareGistEditorCallback =
260276
new SetGistDescriptionModal(app, filename, async (description) => {
261277
const result = await createGist({
262278
target,
263-
content: gistContent,
279+
content,
264280
description,
265281
filename,
266282
isPublic,
@@ -287,7 +303,7 @@ const shareGistEditorCallback =
287303
new SetGistDescriptionModal(app, filename, async (description) => {
288304
const result = await createGist({
289305
target,
290-
content: gistContent,
306+
content,
291307
description,
292308
filename,
293309
isPublic,
@@ -320,18 +336,25 @@ const documentChangedAutoSaveCallback = async (
320336
) => {
321337
const { plugin, file, content: rawContent } = opts;
322338

323-
const { includeFrontMatter, showAutoSaveNotice } =
339+
const { includeFrontMatter, showAutoSaveNotice, includeTableOfContents } =
324340
await getLatestSettings(plugin);
325341

326342
const existingSharedGists = getSharedGistsForFile(rawContent);
327343

328-
const content = includeFrontMatter
344+
const baseContent = includeFrontMatter
329345
? rawContent
330346
: stripFrontMatter(rawContent);
331347

348+
const content = includeTableOfContents
349+
? await addTableOfContents(baseContent)
350+
: baseContent;
351+
332352
if (existingSharedGists.length) {
333353
for (const sharedGist of existingSharedGists) {
334-
const result = await updateGist({ sharedGist, content });
354+
const result = await updateGist({
355+
sharedGist,
356+
content,
357+
});
335358
if (result.status === CreateGistResultStatus.Succeeded) {
336359
const updatedContent = upsertSharedGistForFile(
337360
result.sharedGist,
@@ -757,5 +780,19 @@ class ShareAsGistSettingTab extends PluginSettingTab {
757780
await this.plugin.saveSettings();
758781
}),
759782
);
783+
784+
new Setting(containerEl)
785+
.setName('Include table of contents')
786+
.setDesc(
787+
'Whether to automatically generate and include a table of contents in the shared gist. The table of contents will be inserted directly after the `Contents` or `Table of Contents` heading, if one exists.',
788+
)
789+
.addToggle((toggle) =>
790+
toggle
791+
.setValue(this.plugin.settings.includeTableOfContents)
792+
.onChange(async (value) => {
793+
this.plugin.settings.includeTableOfContents = value;
794+
await this.plugin.saveSettings();
795+
}),
796+
);
760797
}
761798
}

0 commit comments

Comments
 (0)