Skip to content

Commit

Permalink
verions 1.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
macrojd committed Jun 2, 2022
1 parent d7ee39e commit 4233dc2
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 53 deletions.
44 changes: 34 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is a plugin for [Obsidian](https://obsidian.md).

Tag Summary creates summaries with paragraphs or blocks of text that share the same tag. This plugin scans your files looking for blocks of text (text separated by empty lines) and creates a summary with all the blocks that contain the specified tag(s). For example, if you have the following paragraphs in your notes:
Tag Summary creates summaries with paragraphs or blocks of text that share the same tag(s). This plugin scans your files looking for blocks of text (text separated by empty lines) and creates a summary with all the blocks that contain the specified tag(s). For example, if you have the following paragraphs in your notes:

```
Monsters are real, and ghosts are real too. They live inside us, and sometimes, they win.
Expand All @@ -16,14 +16,14 @@ People think that I must be a very strange person. This is not correct. I have t

```
Great minds discuss ideas; average minds discuss events; small minds discuss people.
#chapter1
#chapter1 #crazy
```

You can create summaries for the #chapter1 and #crazy tags. For instance, if you create a summary with the #chapter1 tag, the first and third paragraphs will be included, but if you create a summary with the #crazy tag, only the second paragraph will be included.
You can create summaries with the paragraphs that include the #chapter1 and #crazy tags. For instance, if you create a summary with the #chapter1 tag, the first and third paragraphs will be included, but if you create a summary with the #crazy tag, the second and third paragraphs will be included instead.

## Add a Summary to a Note

Summaries are added to a note by a code block with the add-summary identifier, and the tags are specified with the tags: label, as shown next.
Summaries are added to a note with a code block and the **add-summary** identifier. The tags are specified inside the code block with the **tags:** label, as shown next.

````markdown
```add-summary
Expand All @@ -39,7 +39,32 @@ tags: #chapter1 #crazy
```
````

(The summary created by this last example would include the three paragraphs listed above)
A summary includes every block of text that contains any of the tags specified by the **tags:** label. In the last example, the summary will include the three paragraphs listed above, because each paragrah contains at least one of the tags specified by the label (#chapter1 OR #crazy). If you want to include only the blocks of text that contain all the tags on the list, you can declare the **include:** label instead, as in the following example.

````markdown
```add-summary
include: #chapter1 #crazy
```
````

In this case, only the blocks of text that include both tags will be added to the summary. If you process the paragraphs listed above, only the third paragraph will be added to the summary because it is the only one that includes the #chapter1 AND #crazy tags. If what you want instead is to exclude the blocks of text that contain a specific tag(s), you can add the **exclude:** label, as shown next.

````markdown
```add-summary
tags: #chapter1
exclude: #crazy
```
````

This will add to the summary every block of text that includes the #chapter1 tag but does NOT include the #crazy tag. If you process the paragraphs listed above, only the first paragraph will be added to the summary. The **exclude:** label can be combined with the **tags:** and **include:** labels to specify complex conditions. The following example creates a summary with the blocks of text that include the #chapter1 OR #chapter2 tags and also contain both the #chapter3 AND #chapter4 tags, but do NOT contain the #crazy tag.

````markdown
```add-summary
tags: #chapter1 #chapter2
include: #chapter3 #chapter4
exclude: #crazy
```
````

## Command to Add a Summary

Expand All @@ -49,21 +74,21 @@ The plugin includes the Add Summary command to add a summary to a note.
- Move the cursor to the position where you want to add the summary.
- Press Command+P (Mac) or Control+P (Windows) to open the Command palette.
- Search for the Tag Summary: Add Summary command and click on it.
- On the popup window, select the tag you want to use to create the summary and press the Add Summary button.
- On the popup window, select the tags you want to include and exclude to create the summary and press the Add Summary button.

Now your note should include a code block like the examples above. The Add Summary command allows you to select only one tag, but you can manually add all the tags you want separated by a space, as in tags: #chapter1 #chapter2.
After this, your note should include a code block like the examples above. The Add Summary command allows you to select only one tag to include and another to exclude, but you can manually add all the tags you want separated by a space, as in **tags: #chapter1 #chapter2**.

## Summary Configuration

The plugin includes three options for configuration.

- Show Callouts: Shows each block of text inside a callout box (default). If disabled, the blocks are shown as plain text.
- Show Link: Includes a link to open the note where the paragraph was taken from.
- Show Link: Includes a link at the top to open the note where the paragraph was taken from.
- Remove Tags: Removes the original tags from the text.

## Usage

This plugin does not affect the way Obsidian, links, and tags work. You can still organize your notes the way you always do, but now you can assign a tag to a paragraph or a block of text and then create summaries with all the paragraphs in your notes that include that specific tag.
This plugin does not affect the way Obsidian, links, and tags work. You can still organize your notes the way you always do, but now you can assign tags to paragraphs or blocks of text and then create summaries with those that include a specific list of tags.

When structuring your notes, please consider the following:

Expand All @@ -88,4 +113,3 @@ If you enjoy this plugin and want to support my work, you can buy me a coffee!

<a href="https://www.buymeacoffee.com/JDGauchat" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>


149 changes: 115 additions & 34 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

// Only tags
import { Editor, Plugin, MarkdownRenderer } from 'obsidian';
import { match } from 'assert';
import { Editor, Plugin, MarkdownRenderer, getAllTags } from 'obsidian';
import { SummarySettingTab } from "./settings";
import { SummaryModal } from "./summarytags";

Expand All @@ -27,9 +28,17 @@ export default class SummaryPlugin extends Plugin {
id: "summary-modal",
name: "Add Summary",
editorCallback: (editor: Editor) => {
new SummaryModal(this.app, (result) => {
new SummaryModal(this.app, (include, exclude) => {
// Format code block to add summary
let summary = "```add-summary\n";
summary += "tags: " + result + "\n";

// Add the tags label with the tag selected by the user
summary += "tags: " + include + "\n";

// Add the exclude label with the tags to exclude
if (exclude != "None") {
summary += "exclude: " + exclude + "\n";
}
summary += "```\n";
editor.replaceRange(summary, editor.getCursor());
}).open();
Expand All @@ -40,11 +49,13 @@ export default class SummaryPlugin extends Plugin {
this.registerMarkdownCodeBlockProcessor("add-summary", async (source, el, ctx) => {
// Initialize tag list
let tags: string[] = Array();
let include: string[] = Array();
let exclude: string[] = Array();

// Process rows inside codeblock
const rows = source.split("\n").filter((row) => row.length > 0);
rows.forEach((line) => {
// Check if the line specifies the tags
// Check if the line specifies the tags (OR)
if (line.match(/^\s*tags:[a-zA-Z0-9_\-/# ]+$/g)) {
const content = line.replace(/^\s*tags:/, "").trim();

Expand All @@ -59,36 +70,77 @@ export default class SummaryPlugin extends Plugin {
});
tags = list;
}
// Check if the line specifies the tags to include (AND)
if (line.match(/^\s*include:[a-zA-Z0-9_\-/# ]+$/g)) {
const content = line.replace(/^\s*include:/, "").trim();

// Get the list of valid tags and assign them to the include variable
let list = content.split(/\s+/).map((tag) => tag.trim());
list = list.filter((tag) => {
if (tag.match(/^#[a-zA-Z]+[^#]*$/)) {
return true;
} else {
return false;
}
});
include = list;
}
// Check if the line specifies the tags to exclude (NOT)
if (line.match(/^\s*exclude:[a-zA-Z0-9_\-/# ]+$/g)) {
const content = line.replace(/^\s*exclude:/, "").trim();

// Get the list of valid tags and assign them to the exclude variable
let list = content.split(/\s+/).map((tag) => tag.trim());
list = list.filter((tag) => {
if (tag.match(/^#[a-zA-Z]+[^#]*$/)) {
return true;
} else {
return false;
}
});
exclude = list;
}
});
if (tags.length > 0) {
await this.createSummary(el, tags, ctx.sourcePath);

// Create summary only if the user specified some tags
if (tags.length > 0 || include.length > 0) {
await this.createSummary(el, tags, include, exclude, ctx.sourcePath);
} else {
await this.createEmptySummary(el);
this.createEmptySummary(el);
}
});
}
// Show empty summary when the tags are not found
async createEmptySummary(element: HTMLElement) {
createEmptySummary(element: HTMLElement) {
const container = createEl("div");
container.createEl("span", {
attr: { style: 'color: var(--text-error) !important;' },
text: "There are no blocks with the specified tags."
text: "There are no blocks that match the specified tags."
});
element.replaceWith(container);
}
// Load the blocks and create the summary
async createSummary(element: HTMLElement, tags: string[], filePath: string) {
// Initialize regular expression to search for tags
const exList = tags.map((tag) => {
return "(" + tag + "([^a-zA-Z0-9_\\-#/]+|$))"
});
const tagsEx = exList.join("|");
async createSummary(element: HTMLElement, tags: string[], include: string[], exclude: string[], filePath: string) {
const validTags = tags.concat(include); // All the tags selected by the user

// Read files
// Get files
let listFiles = this.app.vault.getMarkdownFiles();

// Remove host file and sort the files alphabetically
listFiles = listFiles.filter((file) => file.path != filePath);
// Filter files
listFiles = listFiles.filter((file) => {
// Do not process host file
if (file.path != filePath) {
// Remove files that do not contain the tags selected by the user
const cache = app.metadataCache.getFileCache(file);
const tagsInFile = getAllTags(cache);
if (validTags.some((value) => tagsInFile.includes(value))) {
return true;
}
}
return false;
});

// Sort files alphabetically
listFiles = listFiles.sort((file1, file2) => {
if (file1.path < file2.path) {
return -1;
Expand All @@ -99,21 +151,27 @@ export default class SummaryPlugin extends Plugin {
}
});

// Get files contents and name (without extension)
let listContents: [string, string][] = [];
await listFiles.forEach(async (file) => {
let name = file.name.replace(/.md$/g, "");
let content = await this.app.vault.cachedRead(file);
listContents.push([name, content]);
});
// Get files content
const listContents = await Promise.all(
listFiles.map(
async (file) => [file, await app.vault.cachedRead(file)] as const,
),
);

// Create summary
let summary: string = "";
listContents.forEach((item) => {
const rows = item[1].split(/\n\s*\n/).filter((row) => row.trim().length > 0);
rows.forEach((paragraph) => {
let matchEx = new RegExp(tagsEx, "g");
if (paragraph.match(matchEx)) {
// Get files name
const fileName = item[0].name.replace(/.md$/g, "");
const filePath = item[0].path;

// Get process each block of text
const block = item[1].split(/\n\s*\n/).filter((row) => row.trim().length > 0);
block.forEach((paragraph) => {
const listTags = paragraph.match(/#[a-zA-Z0-9_\-/#]+/g);
const valid = this.isValid(listTags, tags, include, exclude);

if (valid) {
// Restore new line at the end
paragraph += "\n";

Expand All @@ -124,13 +182,13 @@ export default class SummaryPlugin extends Plugin {

// Add link to original note
if (this.settings.includelink) {
paragraph = "**Source:** [[" + item[0] + "]]\n" + paragraph;
paragraph = "**Source:** [[" + filePath + "|" + fileName + "]]\n" + paragraph;
}

// Insert the text in a callout
if (this.settings.includecallout) {
// Insert the text in a callout box
let callout = "> [!" + item[0] + "]\n";
let callout = "> [!" + fileName + "]\n";
const rows = paragraph.split("\n");
rows.forEach((row) => {
callout += "> " + row + "\n";
Expand All @@ -148,9 +206,32 @@ export default class SummaryPlugin extends Plugin {
});

// Add Summary
let summaryContainer = createEl("div");
await MarkdownRenderer.renderMarkdown(summary, summaryContainer, null, null);
element.replaceWith(summaryContainer);
if (summary != "") {
let summaryContainer = createEl("div");
await MarkdownRenderer.renderMarkdown(summary, summaryContainer, this.app.workspace.getActiveFile()?.path, null);
element.replaceWith(summaryContainer);
} else {
this.createEmptySummary(element);
}
}

// Check if tags are valid
isValid(listTags: string[], tags: string[], include: string[], exclude: string[]): boolean {
let valid = true;

// Check OR (tags)
if (tags.length > 0) {
valid = valid && tags.some((value) => listTags.includes(value));
}
// Check AND (include)
if (include.length > 0) {
valid = valid && include.every((value) => listTags.includes(value));
}
// Check NOT (exclude)
if (valid && exclude.length > 0) {
valid = !exclude.some((value) => listTags.includes(value));
}
return valid;
}

// Settings
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "tag-summary-plugin",
"name": "Tag Summary",
"version": "0.2.1",
"version": "1.0.1",
"minAppVersion": "0.12.0",
"description": "This plugin creates summaries with paragraphs or blocks of text that share the same tag(s).",
"author": "J.D Gauchat",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tag-summary-plugin",
"version": "0.2.1",
"version": "1.0.1",
"description": "This plugin creates summaries with paragraphs or blocks of text that share the same tag(s).",
"main": "main.js",
"scripts": {
Expand Down
Loading

0 comments on commit 4233dc2

Please sign in to comment.