diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
diff --git a/LICENSE b/LICENSE
new file mode 100755
index 0000000..00d2e13
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
\ No newline at end of file
diff --git a/README.md b/README.md
old mode 100644
new mode 100755
index 9e4fe9c..ac372eb
--- a/README.md
+++ b/README.md
@@ -1,57 +1,44 @@
-## Obsidian Sample Plugin
+# ObsidianTweaks
-This is a sample plugin for Obsidian (https://obsidian.md).
+This is a small plugin that implements some features of Obsidian that I believe
+should've been (perhaps in the future they will be? ❤️).
-This project uses Typescript to provide type checking and documentation.
-The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does.
+## Features
-**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
+Below is a list of the current functionality that has been implemented.
-This sample plugin demonstrates some of the basic functionality the plugin API can do.
-- Changes the default font color to red using `styles.css`.
-- Adds a ribbon icon, which shows a Notice when clicked.
-- Adds a command "Open Sample Modal" which opens a Modal.
-- Adds a plugin setting tab to the settings page.
-- Registers a global click event and output 'click' to the console.
-- Registers a global interval which logs 'setInterval' to the console.
+Note that hotkeys cannot be 'disabled', but they can be set to Blank.
+They are all set to blank by default.
-### First time developing plugins?
+### Hotkeys
+| Recommended hotkey | Action |
+| --- | --- |
+| Shift + Alt + ↓ | Copy Current Line(s) Down |
+| Shift + Alt + ↑ | Copy Current Line(s) Up |
+| Ctrl + Shift + A | Select Current Line(s) |
+| Ctrl + Alt + 1 | Toggle Heading - H1 |
+| Ctrl + Alt + 2 | Toggle Heading - H2 |
+| Ctrl + Alt + 3 | Toggle Heading - H3 |
+| Ctrl + Alt + 4 | Toggle Heading - H4 |
+| Ctrl + Alt + 5 | Toggle Heading - H5 |
+| Ctrl + Alt + 6 | Toggle Heading - H6 |
-Quick starting guide for new plugin devs:
+## Philosophy
-- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
-- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
-- Install NodeJS, then run `npm i` in the command line under your repo folder.
-- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
-- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
-- Reload Obsidian to load the new version of your plugin.
-- Enable plugin in settings window.
-- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
+- By default no features are enabled. You can enable the features you want.
+ - Thus all features can also be disabled.
+- All code is released into public domain without any requirement for attribution using the [Unlicense](https://unlicense.org/).
-### Releasing new releases
+## Why Unlicense?
-- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
-- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
-- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
-- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments.
-- Publish the release.
+In case the developers of Obsidian want to just straight copy some code into Obsidian, they can do that without worrying about licensing at all.
-### Adding your plugin to the community plugin list
+**Note that any contributions to ObsidianTweaks will thus also be Unlicensed.**
-- Publish an initial version.
-- Make sure you have a `README.md` file in the root of your repo.
-- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
+## Honorable Mentions
-### How to use
+I initally planned to contribute to the [Hotkeys++](https://github.com/argenos/hotkeysplus-obsidian) plugin, but since I don't necessarily want ObsidianTweaks to be limited to hotkeys in the future, I decided to make my own.
-- Clone this repo.
-- `npm i` or `yarn` to install dependencies
-- `npm run dev` to start compilation in watch mode.
+## Contributors
-### Manually installing the plugin
-
-- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
-
-### API Documentation
-
-See https://github.com/obsidianmd/obsidian-api
+- [Jeppe Klitgaard](https://github.com/JeppeKlitgaard)
\ No newline at end of file
diff --git a/main.ts b/main.ts
deleted file mode 100644
index eeb3dda..0000000
--- a/main.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-import { App, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
-
-interface MyPluginSettings {
- mySetting: string;
-}
-
-const DEFAULT_SETTINGS: MyPluginSettings = {
- mySetting: 'default'
-}
-
-export default class MyPlugin extends Plugin {
- settings: MyPluginSettings;
-
- async onload() {
- console.log('loading plugin');
-
- await this.loadSettings();
-
- this.addRibbonIcon('dice', 'Sample Plugin', () => {
- new Notice('This is a notice!');
- });
-
- this.addStatusBarItem().setText('Status Bar Text');
-
- this.addCommand({
- id: 'open-sample-modal',
- name: 'Open Sample Modal',
- // callback: () => {
- // console.log('Simple Callback');
- // },
- checkCallback: (checking: boolean) => {
- let leaf = this.app.workspace.activeLeaf;
- if (leaf) {
- if (!checking) {
- new SampleModal(this.app).open();
- }
- return true;
- }
- return false;
- }
- });
-
- this.addSettingTab(new SampleSettingTab(this.app, this));
-
- this.registerCodeMirror((cm: CodeMirror.Editor) => {
- console.log('codemirror', cm);
- });
-
- this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
- console.log('click', evt);
- });
-
- this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
- }
-
- onunload() {
- console.log('unloading plugin');
- }
-
- async loadSettings() {
- this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
- }
-
- async saveSettings() {
- await this.saveData(this.settings);
- }
-}
-
-class SampleModal extends Modal {
- constructor(app: App) {
- super(app);
- }
-
- onOpen() {
- let {contentEl} = this;
- contentEl.setText('Woah!');
- }
-
- onClose() {
- let {contentEl} = this;
- contentEl.empty();
- }
-}
-
-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('Setting #1')
- .setDesc('It\'s a secret')
- .addText(text => text
- .setPlaceholder('Enter your secret')
- .setValue('')
- .onChange(async (value) => {
- console.log('Secret: ' + value);
- this.plugin.settings.mySetting = value;
- await this.plugin.saveSettings();
- }));
- }
-}
diff --git a/manifest.json b/manifest.json
old mode 100644
new mode 100755
index 4ca4889..4be0f43
--- a/manifest.json
+++ b/manifest.json
@@ -1,10 +1,10 @@
{
- "id": "obsidian-sample-plugin",
- "name": "Sample Plugin",
- "version": "1.0.1",
- "minAppVersion": "0.9.12",
- "description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.",
- "author": "Obsidian",
- "authorUrl": "https://obsidian.md/about",
+ "id": "obsidian-tweaks",
+ "name": "Obsidian Tweaks",
+ "version": "0.1.0",
+ "minAppVersion": "0.12.3",
+ "description": "A small plugin that implements some sorely missed features.",
+ "author": "Jeppe Klitgaard",
+ "authorUrl": "jeppe.science",
"isDesktopOnly": false
}
diff --git a/package.json b/package.json
old mode 100644
new mode 100755
index 29e2406..df3012d
--- a/package.json
+++ b/package.json
@@ -1,15 +1,15 @@
{
- "name": "obsidian-sample-plugin",
- "version": "0.12.0",
- "description": "This is a sample plugin for Obsidian (https://obsidian.md)",
+ "name": "obsidian-tweaks",
+ "version": "0.1.0",
+ "description": "A small plugin that implements some sorely missed features.",
"main": "main.js",
"scripts": {
"dev": "rollup --config rollup.config.js -w",
"build": "rollup --config rollup.config.js --environment BUILD:production"
},
- "keywords": [],
- "author": "",
- "license": "MIT",
+ "keywords": ["obsidian"],
+ "author": "Jeppe Klitgaard",
+ "license": "Unlicense",
"devDependencies": {
"@rollup/plugin-commonjs": "^18.0.0",
"@rollup/plugin-node-resolve": "^11.2.1",
diff --git a/rollup.config.js b/rollup.config.js
old mode 100644
new mode 100755
index dd4d041..851225e
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -4,7 +4,7 @@ import commonjs from '@rollup/plugin-commonjs';
const isProd = (process.env.BUILD === 'production');
-const banner =
+const banner =
`/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
@@ -12,7 +12,7 @@ if you want to view the source visit the plugins github repository
`;
export default {
- input: 'main.ts',
+ input: 'src/main.ts',
output: {
dir: '.',
sourcemap: 'inline',
diff --git a/src/DirectionalCopy.ts b/src/DirectionalCopy.ts
new file mode 100755
index 0000000..b08f428
--- /dev/null
+++ b/src/DirectionalCopy.ts
@@ -0,0 +1,65 @@
+import { App, EditableFileView, Editor, MarkdownView } from "obsidian";
+import ObsidianTweaksPlugin from "./main";
+
+export enum Direction {
+ Up,
+ Down,
+}
+
+export class DirectionalCopy {
+ public app: App;
+ private plugin: ObsidianTweaksPlugin;
+
+ constructor(app: App, plugin: ObsidianTweaksPlugin) {
+ this.app = app;
+ this.plugin = plugin;
+ }
+
+ directionalCopy(direction: Direction): void {
+ const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
+ if (!activeView) {
+ return;
+ }
+
+ var anchor = activeView.editor.getCursor("from");
+ var head = activeView.editor.getCursor("to");
+
+ var headLength = activeView.editor.getLine(head.line).length;
+
+ var textToCopy = activeView.editor.getRange(
+ {line: anchor.line, ch: 0},
+ {line: head.line, ch: headLength}
+ )
+
+ // Copy up
+ if (direction === Direction.Up) {
+ activeView.editor.replaceRange(
+ textToCopy + '\n',
+ {line: anchor.line, ch: 0}
+ );
+ activeView.editor.setSelection(
+ {line: anchor.line, ch: anchor.ch},
+ {line: head.line, ch: head.ch},
+ );
+ }
+ // Copy down
+ else if (direction === Direction.Down) {
+ var addedLines = head.line - anchor.line;
+ console.log(addedLines);
+
+ activeView.editor.replaceRange(
+ '\n' + textToCopy,
+ {line: head.line, ch: headLength}
+ );
+ activeView.editor.setSelection(
+ {line: anchor.line + addedLines + 1, ch: anchor.ch},
+ {line: head.line + addedLines + 1, ch: head.ch},
+ );
+ }
+ else {
+ console.log("Something went wrong...");
+ }
+
+ return;
+ }
+}
\ No newline at end of file
diff --git a/src/SelectLine.ts b/src/SelectLine.ts
new file mode 100755
index 0000000..a9252a1
--- /dev/null
+++ b/src/SelectLine.ts
@@ -0,0 +1,34 @@
+import { App, MarkdownView } from "obsidian";
+import ObsidianTweaksPlugin from "./main";
+
+export class SelectLine {
+ public app: App;
+ private plugin: ObsidianTweaksPlugin;
+
+ constructor(app: App, plugin: ObsidianTweaksPlugin) {
+ this.app = app;
+ this.plugin = plugin;
+ }
+
+ selectLine(): void {
+ const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
+ if (!activeView) {
+ return;
+ }
+
+ var anchor = activeView.editor.getCursor("from");
+ var head = activeView.editor.getCursor("to");
+
+ var headLength = activeView.editor.getLine(head.line).length;
+
+ // Modifying and passing the EditorPosition objects does not work
+ // reliably.
+ // Use this approach instead.
+ activeView.editor.setSelection(
+ {line: anchor.line, ch: 0},
+ {line: head.line, ch: headLength}
+ )
+
+ return;
+ }
+}
\ No newline at end of file
diff --git a/src/ToggleHeading.ts b/src/ToggleHeading.ts
new file mode 100755
index 0000000..0d44698
--- /dev/null
+++ b/src/ToggleHeading.ts
@@ -0,0 +1,69 @@
+import { App, EditableFileView, Editor, MarkdownView } from "obsidian";
+import ObsidianTweaksPlugin from "./main";
+
+export enum Heading {
+ H1 = 1,
+ H2,
+ H3,
+ H4,
+ H5,
+ H6,
+}
+
+export class ToggleHeading {
+ public app: App;
+ private plugin: ObsidianTweaksPlugin;
+
+ constructor(app: App, plugin: ObsidianTweaksPlugin) {
+ this.app = app;
+ this.plugin = plugin;
+ }
+
+ toggleHeading(heading: Heading): void {
+ // Three possibilities:
+ // 1: Currently no heading text. Set the heading.
+ // 2: Currently this heading text. Remove the heading.
+ // 3: Currently some other heading. Remove the heading and set this heading.
+
+ const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
+ if (!activeView) {
+ return;
+ }
+
+ var headingText = "#".repeat(heading);
+ var anchor = activeView.editor.getCursor("from");
+
+ var lineText = activeView.editor.getLine(anchor.line);
+
+ var regex: RegExp = /^((#*) )?.*/;
+ var matches = regex.exec(lineText);
+
+ if (matches[2] !== undefined) {
+ // Some heading
+ if (matches[2] === headingText) {
+ // Option 2
+ activeView.editor.replaceRange(
+ '',
+ {line: anchor.line, ch: 0},
+ {line: anchor.line, ch: matches[2].length + 1}
+ )
+ return;
+ } else {
+ // Option 3
+ activeView.editor.replaceRange(
+ headingText + " ",
+ {line: anchor.line, ch: 0},
+ {line: anchor.line, ch: matches[2].length + 1}
+ )
+ return;
+
+ }
+ }
+
+ activeView.editor.replaceRange(
+ headingText + " ",
+ {line: anchor.line, ch: 0},
+ )
+ return;
+ }
+}
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
new file mode 100755
index 0000000..466fe37
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,127 @@
+import { App, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
+import { SelectLine } from 'SelectLine';
+import { DirectionalCopy, Direction } from 'DirectionalCopy';
+import { ToggleHeading, Heading } from 'ToggleHeading';
+
+interface ObsidianTweaksSettings {
+}
+
+const DEFAULT_SETTINGS: ObsidianTweaksSettings = {
+}
+
+export default class ObsidianTweaksPlugin extends Plugin {
+ public settings: ObsidianTweaksSettings;
+
+ private selectLine: SelectLine;
+ private directionalCopy: DirectionalCopy;
+ private toggleHeading: ToggleHeading;
+
+ async onload() {
+ await this.loadSettings();
+
+ this.selectLine = new SelectLine(this.app, this);
+ this.directionalCopy = new DirectionalCopy(this.app, this);
+ this.toggleHeading = new ToggleHeading(this.app, this);
+
+ // Select line
+ this.addCommand({
+ id: 'select-line',
+ name: 'Select Current Line(s)',
+ callback: () => {
+ this.selectLine.selectLine();
+ }
+ });
+
+ // Directional Copy
+ this.addCommand({
+ id: 'copy-line-up',
+ name: 'Copy Current Line(s) Up',
+ callback: () => {
+ this.directionalCopy.directionalCopy(Direction.Up);
+ }
+ });
+ this.addCommand({
+ id: 'copy-line-down',
+ name: 'Copy Current Line(s) Down',
+ callback: () => {
+ this.directionalCopy.directionalCopy(Direction.Down);
+ }
+ });
+
+ // Set heading
+ this.addCommand({
+ id: 'toggle-heading-1',
+ name: 'Toggle Heading - H1',
+ callback: () => {
+ this.toggleHeading.toggleHeading(Heading.H1);
+ }
+ });
+ this.addCommand({
+ id: 'toggle-heading-2',
+ name: 'Toggle Heading - H2',
+ callback: () => {
+ this.toggleHeading.toggleHeading(Heading.H2);
+ }
+ });
+ this.addCommand({
+ id: 'toggle-heading-3',
+ name: 'Toggle Heading - H3',
+ callback: () => {
+ this.toggleHeading.toggleHeading(Heading.H3);
+ }
+ });
+ this.addCommand({
+ id: 'toggle-heading-4',
+ name: 'Toggle Heading - H4',
+ callback: () => {
+ this.toggleHeading.toggleHeading(Heading.H4);
+ }
+ });
+ this.addCommand({
+ id: 'toggle-heading-5',
+ name: 'Toggle Heading - H5',
+ callback: () => {
+ this.toggleHeading.toggleHeading(Heading.H5);
+ }
+ });
+ this.addCommand({
+ id: 'toggle-heading-6',
+ name: 'Toggle Heading - H6',
+ callback: () => {
+ this.toggleHeading.toggleHeading(Heading.H6);
+ }
+ });
+
+ this.addSettingTab(new SampleSettingTab(this.app, this));
+ }
+
+ onunload() {
+ }
+
+ async loadSettings() {
+ this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
+ }
+
+ async saveSettings() {
+ await this.saveData(this.settings);
+ }
+}
+
+class SampleSettingTab extends PluginSettingTab {
+ plugin: ObsidianTweaksPlugin;
+
+ constructor(app: App, plugin: ObsidianTweaksPlugin) {
+ super(app, plugin);
+ this.plugin = plugin;
+ }
+
+ display(): void {
+ let {containerEl} = this;
+
+ containerEl.empty();
+
+ containerEl.createEl('h2', {text: 'Obsidian Tweaks'});
+
+ containerEl.createEl('p', {text: 'Currently nothing here!'});
+ }
+}
diff --git a/styles.css b/styles.css
old mode 100644
new mode 100755
index cfd0fd7..e69de29
--- a/styles.css
+++ b/styles.css
@@ -1,4 +0,0 @@
-/* Sets all the text color to red! */
-body {
- color: red;
-}
diff --git a/tsconfig.json b/tsconfig.json
old mode 100644
new mode 100755
index 09cf7ec..4cdb3c8
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "baseUrl": ".",
+ "baseUrl": "src",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
@@ -17,6 +17,6 @@
]
},
"include": [
- "**/*.ts"
+ "src/**/*.ts"
]
}
diff --git a/versions.json b/versions.json
old mode 100644
new mode 100755
index ba14785..906f859
--- a/versions.json
+++ b/versions.json
@@ -1,4 +1,3 @@
{
- "1.0.1": "0.9.12",
- "1.0.0": "0.9.7"
+ "0.1.0": "0.12.3"
}