Skip to content

Commit

Permalink
Smaller fixes and additions (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
chhoumann authored Jun 26, 2021
1 parent 52d2146 commit 165bbf7
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 90 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ Quickly add new pages or content to your vault.
You can also do a [manual installation](docs/ManualInstallation.md).

## What's new?
### 0.2.13
- Add error logging for when no macro is in the choice.
- Add 'Add' buttons to Macro Builder.
- Multi choices can now have commands & hotkeys.
- Attempted to address #39 - capture not creating template.
- Suggest files from both core templates folder and templater templates folder when creating a Template choice.
- Fix bug where, if there is an emoji in the folder name, the file sometimes doesn't get created
- Update the API. The suggester can now take a map function for the `displayItems`, which will be executed on the `actualItems`. There is also a utility module now, which currently allows you to set or get your clipboard.


### 0.2.11 - 0.2.12
- Implement Quick Commands - ironically, starting with a Wait command. With this command, you can add a delay to your macros. Useful for commands that may take a while to finish.
- Fix a bug where the command sequence did not save.
Expand All @@ -29,11 +39,6 @@ You can also do a [manual installation](docs/ManualInstallation.md).
- Linebreak formatting no longer occurs in Template choices - it only activates for Capture choices. It caused unnecessary conflicts.
- Fix bug where some Templater functions are activated twice.

### 0.2.6
- Throw error if insert after line can't be found - #22
- Add drag & drop to macro commands
- Support user script member access in macros

## Getting started
The first thing you'll want to do is add a new choice. A choice can be one of four types.
- [Template Choice](docs/Choices/TemplateChoice.md) - A powerful way to insert templates into your vault.
Expand Down
33 changes: 31 additions & 2 deletions docs/QuickAddAPI.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
## QuickAdd API
# QuickAdd API
### `inputPrompt(header: string, placeholder?: string, value?: string): string`
Opens a prompt that asks for an input. Returns a string with the input.

This function is asynchronous. You should ``await`` it.

### `yesNoPrompt: (header: string, text?: string): boolean`
Opens a prompt asking for confirmation. Returns `true` or `false` based on answer.

### `suggester: (displayItems: string[], actualItems: string[])`
This function is asynchronous. You should ``await`` it.

### `suggester: (displayItems: string[] | ((value: string, index?: number, arr?: string[]) => string[]), actualItems: string[])`
Opens a suggester. Displays the `displayItems`, but you map these the other values with `actualItems`.

The ``displayItems`` can either be an array of strings, or a map function that will be executed on the actual items.

This means that the following syntax is possible:
````js
const pickedFile = await params.quickAddApi.suggester(
(file) => file.basename,
params.app.vault.getMarkdownFiles()
);
````

Returns the selected value.

This function is asynchronous. You should ``await`` it.

### `checkboxPrompt: (items: string[], selectedItems: string[])`
Opens a checkbox prompt with the items given. Items in the `selectedItems` array will be selected by default.

Returns an array of the selected items.

This function is asynchronous. You should ``await`` it.

## Utility module
### ``getClipboard()``
Returns the contents of your clipboard.

This function is asynchronous. You should ``await`` it.

### ``setClipboard(text: string)``
Sets the contents of your clipboard to the given input.

This function is asynchronous. You should ``await`` it.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "quickadd",
"name": "QuickAdd",
"version": "0.2.12",
"version": "0.2.13",
"minAppVersion": "0.12.00",
"description": "Quickly add new pages or content to your vault.",
"author": "Christian B. B. Houmann",
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": "quickadd",
"version": "0.2.12",
"version": "0.2.13",
"description": "Quickly add new pages or content to your vault.",
"main": "main.js",
"scripts": {
Expand Down
10 changes: 10 additions & 0 deletions src/choiceExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {TemplateChoiceEngine} from "./engine/TemplateChoiceEngine";
import {CaptureChoiceEngine} from "./engine/CaptureChoiceEngine";
import {MacroChoiceEngine} from "./engine/MacroChoiceEngine";
import type {IChoiceExecutor} from "./IChoiceExecutor";
import type IMultiChoice from "./types/choices/IMultiChoice";
import ChoiceSuggester from "./gui/choiceSuggester";

export class ChoiceExecutor implements IChoiceExecutor {
private variables: Map<string, string> = new Map<string, string>();
Expand All @@ -30,6 +32,10 @@ export class ChoiceExecutor implements IChoiceExecutor {
const macroChoice: IMacroChoice = choice as IMacroChoice;
await this.onChooseMacroType(macroChoice);
break;
case ChoiceType.Multi:
const multiChoice: IMultiChoice = choice as IMultiChoice;
await this.onChooseMultiType(multiChoice);
break
default:
break;
}
Expand Down Expand Up @@ -61,4 +67,8 @@ export class ChoiceExecutor implements IChoiceExecutor {
this.variables.set(key, macroEngine.params.variables[key]);
});
}

private async onChooseMultiType(multiChoice: IMultiChoice) {
ChoiceSuggester.Open(this.plugin, multiChoice.choices, this);
}
}
4 changes: 4 additions & 0 deletions src/engine/MacroChoiceEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export class MacroChoiceEngine extends QuickAddChoiceEngine {
const macroId: string = this.choice.macroId ?? this.choice?.macro?.id;
const macro: IMacro = this.macros.find(m => m.id === macroId);

if (!macro || !macro?.commands) {
log.logError(`No commands in the selected macro. Did you select a macro for '${this.choice.name}'?`)
}

await this.executeCommands(macro.commands);
}

Expand Down
5 changes: 2 additions & 3 deletions src/engine/TemplateChoiceEngine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type ITemplateChoice from "../types/choices/ITemplateChoice";
import type {App, TFile} from "obsidian";
import {appendToCurrentLine, getAllFolders} from "../utility";
import {MARKDOWN_FILE_EXTENSION_REGEX} from "../constants";
import {MARKDOWN_FILE_EXTENSION_REGEX, VALUE_SYNTAX} from "../constants";
import {log} from "../logger/logManager";
import type QuickAdd from "../main";
import {TemplateEngine} from "./TemplateEngine";
Expand Down Expand Up @@ -34,8 +34,7 @@ export class TemplateChoiceEngine extends TemplateEngine {
if (this.choice.fileNameFormat.enabled) {
filePath = await this.getFormattedFilePath(folderPath, this.choice.fileNameFormat.format, this.choice.name);
} else {
const fileNameValueFormat: string = "{{VALUE}}";
filePath = await this.getFormattedFilePath(folderPath, fileNameValueFormat, this.choice.name);
filePath = await this.getFormattedFilePath(folderPath, VALUE_SYNTAX, this.choice.name);
}

if (this.choice.incrementFileName)
Expand Down
2 changes: 1 addition & 1 deletion src/engine/TemplateEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export abstract class TemplateEngine extends QuickAddEngine {
else
folderPath = "";

return folderPath;
return `/${folderPath}`;
}

protected async getFormattedFilePath(folderPath: string, format: string, promptHeader: string): Promise<string> {
Expand Down
7 changes: 6 additions & 1 deletion src/formatters/captureChoiceFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {App, TFile} from "obsidian";
import {log} from "../logger/logManager";
import type QuickAdd from "../main";
import type {IChoiceExecutor} from "../IChoiceExecutor";
import {templaterParseTemplate} from "../utility";

export class CaptureChoiceFormatter extends CompleteFormatter {
private choice: ICaptureChoice;
Expand All @@ -20,7 +21,11 @@ export class CaptureChoiceFormatter extends CompleteFormatter {
this.fileContent = fileContent;
if (!choice || !file || fileContent === null) return input;

return await this.formatFileContent(input);
const formatted = await this.formatFileContent(input);
const templaterFormatted = templaterParseTemplate(this.app, formatted, this.file);
if (!templaterFormatted) return formatted;

return templaterFormatted;
}

public async formatContent(input: string, choice: ICaptureChoice): Promise<string> {
Expand Down
142 changes: 88 additions & 54 deletions src/gui/MacroGUIs/MacroBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {IMacro} from "../../types/macros/IMacro";
import {App, ButtonComponent, Modal, Setting, TFile} from "obsidian";
import {App, ButtonComponent, Modal, SearchComponent, Setting, TextComponent, TFile} from "obsidian";
import type {IObsidianCommand} from "../../types/macros/IObsidianCommand";
import {GenericTextSuggester} from "../genericTextSuggester";
import {UserScript} from "../../types/macros/UserScript";
Expand Down Expand Up @@ -40,6 +40,14 @@ export class MacroBuilder extends Modal {
this.open();
}

onClose() {
super.onClose();
this.resolvePromise(this.macro);
this.svelteElements.forEach(el => {
if (el && el.$destroy) el.$destroy();
})
}

protected display() {
this.contentEl.empty();
this.addCenteredHeader(this.macro.name);
Expand All @@ -50,10 +58,6 @@ export class MacroBuilder extends Modal {
this.addAddChoiceSetting();
}

private reload() {
this.display();
}

protected addCenteredHeader(header: string): void {
const headerEl = this.contentEl.createEl('h2');
headerEl.style.textAlign = "center";
Expand All @@ -69,75 +73,109 @@ export class MacroBuilder extends Modal {
});
}

private reload() {
this.display();
}

private addAddObsidianCommandSetting() {
let input: TextComponent;

const addObsidianCommandFromInput = () => {
const value: string = input.getValue();
const command: IObsidianCommand = this.commands.find(v => v.name === value);

this.addCommandToMacro(command);

input.setValue("");
}

new Setting(this.contentEl)
.setName("Obsidian command")
.setDesc("Add an Obsidian command")
.addSearch(searchComponent => {
searchComponent.setPlaceholder("Obsidian command");
new GenericTextSuggester(this.app, searchComponent.inputEl, this.commands.map(c => c.name));
.addText(textComponent => {
input = textComponent;
textComponent.inputEl.style.marginRight = "1em";
textComponent.setPlaceholder("Obsidian command");
new GenericTextSuggester(this.app, textComponent.inputEl, this.commands.map(c => c.name));

searchComponent.inputEl.addEventListener('keypress', (e: KeyboardEvent) => {
textComponent.inputEl.addEventListener('keypress', (e: KeyboardEvent) => {
if (e.key === 'Enter') {
const value: string = searchComponent.getValue();
const command: IObsidianCommand = this.commands.find(v => v.name === value);

this.macro.commands.push(command);
this.commandListEl.updateCommandList(this.macro.commands);

searchComponent.setValue("");
addObsidianCommandFromInput();
}
});
});
})
.addButton(button => button.setCta().setButtonText("Add").onClick(addObsidianCommandFromInput));
}

private addAddUserScriptSetting() {
let input: TextComponent;

const addUserScriptFromInput = () => {
const value: string = input.getValue();
const scriptBasename = getUserScriptMemberAccess(value).basename;

const file = this.javascriptFiles.find(f => f.basename === scriptBasename);
if (!file) return;

this.addCommandToMacro(new UserScript(value, file.path));

input.setValue("");
}

new Setting(this.contentEl)
.setName("User Scripts")
.setDesc("Add user script")
.addSearch(searchComponent => {
searchComponent.setPlaceholder("User script");
new GenericTextSuggester(this.app, searchComponent.inputEl, this.javascriptFiles.map(f => f.basename));
.addText(textComponent => {
input = textComponent;
textComponent.inputEl.style.marginRight = "1em";
textComponent.setPlaceholder("User script");
new GenericTextSuggester(this.app, textComponent.inputEl, this.javascriptFiles.map(f => f.basename));

searchComponent.inputEl.addEventListener('keypress', (e: KeyboardEvent) => {
textComponent.inputEl.addEventListener('keypress', (e: KeyboardEvent) => {
if (e.key === 'Enter') {
const value: string = searchComponent.getValue();
const scriptBasename = getUserScriptMemberAccess(value).basename;

const file = this.javascriptFiles.find(f => f.basename === scriptBasename);
if (!file) return;

this.macro.commands.push(new UserScript(value, file.path));
this.commandListEl.updateCommandList(this.macro.commands);

searchComponent.setValue("");
addUserScriptFromInput();
}
})
})
.addButton(button => button
.setButtonText("Add")
.setCta()
.onClick(addUserScriptFromInput)
);
}

private addAddChoiceSetting() {
let input: TextComponent;

const addChoiceFromInput = () => {
const value: string = input.getValue();
const choice = this.choices.find(c => c.name === value);
if (!choice) return;

this.addCommandToMacro(new ChoiceCommand(choice.name, choice.id))

input.setValue("");
}

new Setting(this.contentEl)
.setName("Choices")
.setDesc("Add choice")
.addSearch(searchComponent => {
searchComponent.setPlaceholder("Choice");
new GenericTextSuggester(this.app, searchComponent.inputEl, this.choices.map(c => c.name));
.addText(textComponent => {
input = textComponent;
textComponent.inputEl.style.marginRight = "1em";
textComponent.setPlaceholder("Choice");
new GenericTextSuggester(this.app, textComponent.inputEl, this.choices.map(c => c.name));

searchComponent.inputEl.addEventListener('keypress', (e: KeyboardEvent) => {
textComponent.inputEl.addEventListener('keypress', (e: KeyboardEvent) => {
if (e.key === 'Enter') {
const value: string = searchComponent.getValue();
const choice = this.choices.find(c => c.name === value);
if (!choice) return;

this.macro.commands.push(new ChoiceCommand(choice.name, choice.id));
this.commandListEl.updateCommandList(this.macro.commands);

searchComponent.setValue("");
addChoiceFromInput();
}
})
});
})
.addButton(button => button.setCta()
.setButtonText("Add")
.onClick(addChoiceFromInput)
);
}

private getObsidianCommands(): void {
Expand Down Expand Up @@ -175,21 +213,17 @@ export class MacroBuilder extends Modal {
this.svelteElements.push(this.commandListEl);
}

onClose() {
super.onClose();
this.resolvePromise(this.macro);
this.svelteElements.forEach(el => {
if (el && el.$destroy) el.$destroy();
})
}

private addAddWaitCommandButton() {
const quickCommandContainer: HTMLDivElement = this.contentEl.createDiv('quickCommandContainer');

const button: ButtonComponent = new ButtonComponent(quickCommandContainer);
button.setIcon('clock').setTooltip("Add wait command").onClick(() => {
this.macro.commands.push(new WaitCommand(100));
this.commandListEl.updateCommandList(this.macro.commands);
this.addCommandToMacro(new WaitCommand(100));
});
}

private addCommandToMacro(command: ICommand) {
this.macro.commands.push(command);
this.commandListEl.updateCommandList(this.macro.commands);
}
}
Loading

0 comments on commit 165bbf7

Please sign in to comment.