Skip to content

Commit

Permalink
feat: ✨ Initial working plugin!
Browse files Browse the repository at this point in the history
  • Loading branch information
SkepticMystic committed Oct 20, 2021
1 parent 8271941 commit 7ad983e
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 132 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Publish plugin

on:
push:
# Sequence of patterns matched against refs/tags
tags:
- "*" # Push events to matching any tag format, i.e. 1.0, 20.15.10

env:
PLUGIN_NAME: ${{ github.event.repository.name }}
RELEASE_VER: ${{ github.ref }}

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Create release and Upload
id: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME=${RELEASE_VER##*/}
mkdir "${PLUGIN_NAME}"
assets=()
for f in main.js manifest.json styles.css; do
if [[ -f $f ]]; then
cp $f "${PLUGIN_NAME}/"
assets+=(-a "$f")
fi
done
zip -r "$PLUGIN_NAME".zip "$PLUGIN_NAME"
hub release create "${assets[@]}" -a "$PLUGIN_NAME".zip -m "$TAG_NAME" "$TAG_NAME"
32 changes: 32 additions & 0 deletions SampleSettingTab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { App, PluginSettingTab, Setting } from "obsidian";
import MyPlugin from "./main";

export class SettingTab 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(this.plugin.settings.mySetting)
// .onChange(async (value) => {
// console.log("Secret: " + value);
// this.plugin.settings.mySetting = value;
// await this.plugin.saveSettings();
// })
// );
}
}
201 changes: 103 additions & 98 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,135 +1,140 @@
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';

interface MyPluginSettings {
import {
App,
Editor,
EditorPosition,
EditorSelectionOrCaret,
Modal,
Plugin,
View,
} from "obsidian";
import { SettingTab } from "./SampleSettingTab";

interface Settings {
mySetting: string;
}

const DEFAULT_SETTINGS: MyPluginSettings = {
mySetting: 'default'
}
const DEFAULT_SETTINGS: Settings = {
mySetting: "default",
};

export default class MyPlugin extends Plugin {
settings: MyPluginSettings;
settings: Settings;

async onload() {
await this.loadSettings();

// This creates an icon in the left ribbon.
let ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => {
// Called when the user clicks the icon.
new Notice('This is a notice!');
});
// Perform additional things with the ribbon
ribbonIconEl.addClass('my-plugin-ribbon-class');

// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
let statusBarItemEl = this.addStatusBarItem();
statusBarItemEl.setText('Status Bar Text');

// This adds a simple command that can be triggered anywhere
this.addCommand({
id: 'open-sample-modal-simple',
name: 'Open sample modal (simple)',
callback: () => {
new SampleModal(this.app).open();
}
});
// This adds an editor command that can perform some operation on the current editor instance
this.addCommand({
id: 'sample-editor-command',
name: 'Sample editor command',
editorCallback: (editor: Editor, view: MarkdownView) => {
console.log(editor.getSelection());
editor.replaceSelection('Sample Editor Command');
}
});
// This adds a complex command that can check whether the current state of the app allows execution of the command
this.addCommand({
id: 'open-sample-modal-complex',
name: 'Open sample modal (complex)',
checkCallback: (checking: boolean) => {
// Conditions to check
let markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (markdownView) {
// If checking is true, we're simply "checking" if the command can be run.
// If checking is false, then we want to actually perform the operation.
if (!checking) {
new SampleModal(this.app).open();
}

// This command will only show up in Command Palette when the check function returns true
return true;
}
}
id: "open-sample-modal-simple",
name: "Open sample modal (simple)",
editorCallback: (editor: Editor, view: View) => {
const query = "test";
new CursorsModal(this.app, editor).open();
},
});

// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new SampleSettingTab(this.app, this));

// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
// Using this function will automatically remove the event listener when this plugin is disabled.
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
console.log('click', evt);
});

// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
this.addSettingTab(new SettingTab(this.app, this));
}

onunload() {

}
onunload() {}

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

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

class SampleModal extends Modal {
constructor(app: App) {
class CursorsModal extends Modal {
editor: Editor;
constructor(app: App, editor: Editor) {
super(app);
this.editor = editor;
}

onOpen() {
let {contentEl} = this;
contentEl.setText('Woah!');
}

onClose() {
let {contentEl} = this;
contentEl.empty();
async getSelectionAndOffset() {
const selection = this.editor.getSelection();
const offset = this.editor.getCursor("from").line;
if (selection !== "") {
return { selection, offset };
} else {
const currFile = this.app.workspace.getActiveFile();
const content = await this.app.vault.cachedRead(currFile);
return { selection: content, offset: 0 };
}
}
}

class SampleSettingTab extends PluginSettingTab {
plugin: MyPlugin;
getSelectionsFromQuery(content: string, offset: number, query: string) {
const regex = new RegExp(query, "g");
const lines = content.split("\n");
const selections: EditorSelectionOrCaret[] = [];

lines.forEach((line, i) => {
const matches = line.matchAll(regex);
const matchesArr = [...matches];

matchesArr.forEach((matchArr) => {
const from = matchArr.index;
if (from !== undefined) {
const anchor: EditorPosition = {
ch: from,
line: i + offset,
};
const head: EditorPosition = {
ch: from + matchArr[0].length,
line: i + offset,
};
selections.push({ anchor, head });
}
});
});

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

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

containerEl.empty();
const { selection, offset } = await this.getSelectionAndOffset();
console.log({ selection });

const inputEl = contentEl.createEl("input", {
type: "text",
title: "Search Query",
attr: { placeholder: "Search Query" },
});

containerEl.createEl('h2', {text: 'Settings for my awesome plugin.'});
const submitButton = contentEl.createEl(
"input",
{
type: "submit",
text: "submit",
},
(submitEl) => {
submitEl.addEventListener("click", async () => {
const query = inputEl.value;
const selections = this.getSelectionsFromQuery(
selection,
offset,
query
);

console.log({ selections });
this.editor.setSelections(selections);
this.close();
});
}
);
}

new Setting(containerEl)
.setName('Setting #1')
.setDesc('It\'s a secret')
.addText(text => text
.setPlaceholder('Enter your secret')
.setValue(this.plugin.settings.mySetting)
.onChange(async (value) => {
console.log('Secret: ' + value);
this.plugin.settings.mySetting = value;
await this.plugin.saveSettings();
}));
onClose() {
let { contentEl } = this;
contentEl.empty();
}
}
16 changes: 8 additions & 8 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"id": "obsidian-sample-plugin",
"name": "Sample Plugin",
"version": "1.0.1",
"minAppVersion": "0.12.0",
"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",
"id": "advanced-cursors",
"name": "Advanced Cursors",
"version": "0.0.1",
"minAppVersion": "0.12.18",
"description": "Use multiple cursors even more powerfully.",
"author": "SkepticMystic",
"authorUrl": "https://github.com/SkepticMystic/advanced-cursors",
"isDesktopOnly": false
}
}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "obsidian-sample-plugin",
"version": "0.12.0",
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"name": "advanced-cursors",
"version": "0.0.1",
"description": "Use multiple cursors even more powerfully",
"main": "main.js",
"scripts": {
"dev": "esbuild main.ts --bundle --external:obsidian --outdir=. --target=es2016 --format=cjs --sourcemap=inline --watch",
Expand Down
3 changes: 0 additions & 3 deletions styles.css
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
/* Sets all the text color to red! */
body {
color: red;
}
33 changes: 13 additions & 20 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"lib": [
"dom",
"es5",
"scripthost",
"es2015"
]
},
"include": [
"**/*.ts"
]
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"lib": ["dom", "es5", "scripthost", "es2015"]
},
"include": ["**/*.ts"]
}

0 comments on commit 7ad983e

Please sign in to comment.