Skip to content

Commit

Permalink
first_commit
Browse files Browse the repository at this point in the history
committing the plugin to the repo for the first time.
  • Loading branch information
eleanorkonik committed May 5, 2021
1 parent 1c30d19 commit 6ed9798
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 2 deletions.
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Intellij
*.iml
.idea

# npm
node_modules
package-lock.json

# build
main.js
*.js.map
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,27 @@
# concatenate
A plugin for Obsidian.md to allow you to put the contents of sections together in one file
## Obsidian Concatenate Plugin

### Manual Installation

- Download the latest `main.js, mainfest.json and styles.css` from releases.
- Create a new folder named 'obsidian-concatenate'
- Place the three files in the folder (although honestly styles.css doesn’t matter)
- Place the folder in your .obsidian/plugins directory
- Reload plugins
- Activate the "Concatenate" plugin

### How to use the plugin

1. Navigate to plugin settings.
2. Assign a value for which header you want to concatenate the contents of. (i.e. `## Reflections` or `### Meeting Logs`)
3. Assign a folder you want to limit the concatenation to (i.e. `Calendar/2021/January`)
4. Use the command palette (`ctrl+p` on windows by default) to `Concatenate Headings`.
5. View, rename, and/or move the outputted file, which will be created in your vault’s root directory with a name like “Concatenated_Note-Timestamp.” There will be a popup in the top right hand corner telling you the filename.

### Disclaimer

This is my _very first code project of any kind_. A few months ago I had never done any programming more complex than simple lua scripts for video games. Please install at your own risk, and understand that updates & bugfixes will be slow and awkward unless someone is willing to submit a pull request.

### Credits

Enormous thanks to `@pjeby`, `@mrjackphil`, and all the [Obsidian.md moderators](https://help.obsidian.md/Obsidian/Credits) for their encouragement, support, code tips, refactoring help, handholding with git, and more.

10 changes: 10 additions & 0 deletions buildandload.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@echo off
start /wait "building plugin" cmd /c npm run build
rem npm run build
echo errorlevel after npm run build is %errorlevel%
if not errorlevel 0 exit

rem If we get this far then the .js file got created
echo copy /Y main.js D:\js_projs\sample_plugin\test-vault\.obsidian\plugins\sample-plugin
copy /Y main.js D:\js_projs\sample_plugin\test-vault\.obsidian\plugins\sample-plugin
echo errorlevel after copy is %errorlevel%
153 changes: 153 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import {
App, HeadingCache, MetadataCache, Notice,
Plugin,
PluginSettingTab,
Setting,
TFile,
} from 'obsidian';

interface MyPluginSettings {
concatHeader: string;
pathIncluded: string;
}

const DEFAULT_SETTINGS: MyPluginSettings = {
concatHeader: '## Reading Log',
pathIncluded: ''
}
async function asyncForEach(array:TFile[], callback: (markFile: TFile) => void) {
for (let index = 0; index < array.length; index++) {
await callback(array[index]);
}
}

export default class MyPlugin extends Plugin {
settings: MyPluginSettings;

async performConcatenation() {
let markdownFiles = this.app.vault.getMarkdownFiles();
if (this.settings.pathIncluded) {
markdownFiles = markdownFiles.filter(e => e.path.startsWith(this.settings.pathIncluded))
}

if (!markdownFiles.length) {
new Notice("Can't find files which fit the filter")
return
}

let content = Array();
let timenow = Date.now();
// Await lets you block further execution until this thing is done. It must be paired with async.

const level = this.settings.concatHeader.split(' ').filter(e => /^#/.test(e))[0]?.split('#').length - 1 || 0
const title = this.settings.concatHeader.split(' ').slice(1).join(' ')

await asyncForEach(markdownFiles, async (markFile: TFile) => {
const metadata = this.app.metadataCache.getFileCache(markFile)

type HeadingWithOffset = [HeadingCache, { sectionEndLine: number }]

const matchedHeadings: HeadingWithOffset[] = metadata.headings
?.filter(h => h.level >= level)
.map((h, i, arr) => {
return [
h,
{ sectionEndLine: arr[i + 1]?.position.start.line || undefined }
] as HeadingWithOffset
})
.filter(h => h[0].level === level && h[0].heading === title)
|| []

if (matchedHeadings.length) {
const fileContent = await this.app.vault.read(markFile)
content.push(
matchedHeadings.map(h => {
return fileContent
.split('\n')
.slice(h[0].position.start.line + 1, h[1].sectionEndLine)
.join('\n')
}).join('\n')
)
}
});

const finalizedContents = content.join('\n')

await this.app.vault.create("Concatenated_Note-" + timenow + ".md", finalizedContents);
new Notice('File: "' + 'Concatenated_Note-' + timenow + '.md' + '" created.');
}

async onload() {
console.log('loading plugin');

await this.loadSettings();

this.addCommand({
id: 'concatenate-headings',
name: 'Concatenate Headings',
checkCallback: (checking: boolean) => {
let leaf = this.app.workspace.activeLeaf;
if (leaf) {
if (!checking) {
this.performConcatenation();
}
return true;
}
return false;
},
callback: () => this.performConcatenation(),
});

this.addSettingTab(new SampleSettingTab(this.app, this));
}

onunload() {
console.log('unloading plugin');
}

async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}

async saveSettings() {
await this.saveData(this.settings);
}
}

class SampleSettingTab extends PluginSettingTab {
plugin: MyPlugin;

constructor(app: App, plugin: MyPlugin) {
super(app, plugin);
this.plugin = plugin;
}

display(): void {
let {containerEl} = this;

containerEl.empty();

containerEl.createEl('h2', {text: 'Settings for my awesome plugin.'});

new Setting(containerEl)
.setName('Heading Title')
.setDesc('Type the heading (including the hashtags) you would like to concatenate')
.addText(text => text
.setValue(this.plugin.settings.concatHeader)
.onChange(async (value) => {
this.plugin.settings.concatHeader = value;
await this.plugin.saveSettings();
}));

new Setting(containerEl)
.setName('Folder in which search for')
.setDesc('Specify the folder where plugin will search headers')
.addText(text => text
.setPlaceholder('path/folder/deep')
.setValue(this.plugin.settings.pathIncluded)
.onChange(async (value) => {
this.plugin.settings.pathIncluded = value;
await this.plugin.saveSettings();
}));
}
}
10 changes: 10 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "obsidian-concatenate",
"name": "Concatenate",
"version": "0.0.1",
"minAppVersion": "0.0.1",
"description": "This plugin will allow you to put the contents of sections together in one file",
"author": "Eleanor Konik",
"authorUrl": "https://github.com/eleanorkonik/-concatenate",
"isDesktopOnly": false
}
23 changes: 23 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "obsidian-sample-plugin",
"version": "0.9.7",
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"main": "main.js",
"scripts": {
"dev": "rollup --config rollup.config.js -w",
"build": "rollup --config rollup.config.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@rollup/plugin-commonjs": "^15.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-typescript": "^6.0.0",
"@types/node": "^14.14.2",
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
"rollup": "^2.32.1",
"tslib": "^2.0.3",
"typescript": "^4.0.3"
}
}
19 changes: 19 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import typescript from '@rollup/plugin-typescript';
import {nodeResolve} from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

export default {
input: 'main.ts',
output: {
dir: '.',
sourcemap: 'inline',
format: 'cjs',
exports: 'default'
},
external: ['obsidian'],
plugins: [
typescript(),
nodeResolve({browser: true}),
commonjs(),
]
};
Empty file added styles.css
Empty file.
23 changes: 23 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "es6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"lib": [
"dom",
"es5",
"scripthost",
"es2015"
],
"noEmitOnError": true,
},
"include": [
"**/*.ts"
]
}
4 changes: 4 additions & 0 deletions versions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"1.0.1": "0.9.12",
"1.0.0": "0.9.7"
}

0 comments on commit 6ed9798

Please sign in to comment.