Respond to joethei MR comments. Minor changes, use addNumberFormat, use AbstractInputSuggest.

This commit is contained in:
Ben Stuart 2025-02-24 17:39:37 -06:00
parent 880b1eb3db
commit 0c075ff854
5 changed files with 170 additions and 69 deletions

92
main.ts
View file

@ -1,4 +1,4 @@
import { MarkdownView, Notice, Plugin, TFolder } from "obsidian";
import { MarkdownView, Notice, Plugin, TFolder, Editor } from "obsidian";
import OpenAI from "openai";
import { OnThisDayPluginSettings, DEFAULT_SETTINGS } from "src/settings";
import OnThisDaySettingTab from "src/OnThisDaySettingTab";
@ -17,35 +17,93 @@ export default class OnThisDayPlugin extends Plugin {
await this.loadSettings();
this.addSettingTab(new OnThisDaySettingTab(this.app, this));
// Conditions: placeholder must be defined in settings
this.addCommand({
id: "through-the-years-placeholder",
name: "Add Through The Years Placeholder at Cursor",
callback: () => {
this.addThroughTheYearsPlaceholder();
name: "Add through the years placeholder at cursor",
editorCheckCallback: (
checking: boolean,
editor: Editor,
view: MarkdownView
) => {
const placeholderIsEmpty =
this.settings.placeholder.trim() === "";
if (!placeholderIsEmpty) {
if (!checking) {
this.addThroughTheYearsPlaceholder();
}
return true;
}
return false;
},
});
// Conditions: placeholder must be defined in settings
this.addCommand({
id: "diet-estimates-placeholder",
name: "Add Diet Estimates Placeholder at Cursor",
callback: () => {
this.addDietEstimatesPlaceholder();
name: "Add diet estimates placeholder at cursor",
editorCheckCallback: (
checking: boolean,
editor: Editor,
view: MarkdownView
) => {
const placeholderIsEmpty =
this.settings.dietEstimatePlaceholder.trim() === "";
if (!placeholderIsEmpty) {
if (!checking) {
this.addDietEstimatesPlaceholder();
}
return true;
}
return false;
},
});
// Conditions: date format, daily notes folder, output header, model version, and apiKey
this.addCommand({
id: "generate-date-summaries",
name: "Generate Through The Years",
callback: async () => {
await this.generateDateSummaries();
name: "Generate through The years",
editorCheckCallback: (
checking: boolean,
editor: Editor,
view: MarkdownView
) => {
if (
this.settings.dateFormat.trim() != "" &&
this.settings.dailyNotesFolder.trim() != "" &&
this.settings.throughTheYearsHeader.trim() != "" &&
this.settings.model.trim() != "" &&
this.settings.openaiApiKey.trim() != ""
) {
if (!checking) {
this.generateDateSummaries();
}
return true;
}
return false;
},
});
// Conditions: section header, model version, and apiKey
this.addCommand({
id: "diet-estimates",
name: "Generate Diet Estimates",
callback: async () => {
await this.generateDietEstimates();
name: "Generate diet estimates",
editorCheckCallback: (
checking: boolean,
editor: Editor,
view: MarkdownView
) => {
if (
this.settings.foodHeader.trim() != "" &&
this.settings.model.trim() != "" &&
this.settings.openaiApiKey.trim() != ""
) {
if (!checking) {
this.generateDateSummaries();
}
return true;
}
return false;
},
});
}
@ -202,7 +260,10 @@ export default class OnThisDayPlugin extends Plugin {
);
if (headerIndex === -1) {
new Notice("Food section not found using header: " + this.settings.foodHeader);
new Notice(
"Food section not found using header: " +
this.settings.foodHeader
);
return;
}
@ -219,7 +280,8 @@ export default class OnThisDayPlugin extends Plugin {
if (!foodInfo) {
new Notice(
"No food-related details found under the header: " + this.settings.foodHeader
"No food-related details found under the header: " +
this.settings.foodHeader
);
return;
}

10
package-lock.json generated
View file

@ -1974,16 +1974,6 @@
"node": "*"
}
},
"node_modules/moment": {
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",

47
src/FolderSuggest.ts Normal file
View file

@ -0,0 +1,47 @@
import { App, AbstractInputSuggest } from "obsidian";
export class FolderSuggest extends AbstractInputSuggest<string> {
private folderOptions: string[];
/**
* Constructs a new FolderSuggest.
* @param app - The Obsidian App instance.
* @param textInputEl - The HTMLInputElement (or contentEditable div) to attach the suggestion to.
* @param folderOptions - An array of folder path strings to suggest.
*/
constructor(
app: App,
textInputEl: HTMLInputElement,
folderOptions: string[]
) {
super(app, textInputEl);
this.folderOptions = folderOptions;
this.limit = 20;
}
/**
* Returns an array of folder paths that match the given query.
*/
protected getSuggestions(query: string): string[] {
return this.folderOptions.filter((option) =>
option.toLowerCase().includes(query.toLowerCase())
);
}
/**
* Renders a suggestion item in the suggestion dropdown.
* @param suggestion - The folder path suggestion.
* @param el - The HTMLElement in which to render the suggestion.
*/
renderSuggestion(suggestion: string, el: HTMLElement): void {
el.textContent = suggestion;
}
/**
* Called when the user selects a suggestion.
* Updates the input field with the chosen folder path.
*/
onChooseSuggestion(suggestion: string): void {
this.setValue(suggestion);
}
}

View file

@ -1,6 +1,6 @@
import { App, PluginSettingTab, Setting, TFolder } from "obsidian";
import moment from "moment";
import { App, PluginSettingTab, Setting, TFolder, moment } from "obsidian";
import OnThisDayPlugin from "main";
import { FolderSuggest } from "./FolderSuggest";
export default class OnThisDaySettingTab extends PluginSettingTab {
plugin: OnThisDayPlugin;
@ -13,23 +13,22 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "General Settings" });
const dateSetting = new Setting(containerEl)
.setName("Date Format")
.setName("Date format")
.setDesc(
`Format for daily note filenames. Example: ${moment(
new Date()
).format(this.plugin.settings.dateFormat)}`
)
.addText((text) => {
text.setPlaceholder("MMMM D, YYYY")
.addMomentFormat((momentFormat) => {
momentFormat
.setDefaultFormat("MMMM D, YYYY")
.setValue(this.plugin.settings.dateFormat)
.onChange(async (value) => {
this.plugin.settings.dateFormat = value;
await this.plugin.saveSettings();
// Update the description with a new example using the updated format
const newExample = moment(new Date()).format(value);
// Update the description with a new example using the updated format
dateSetting.setDesc(
`Format for daily note filenames. Example: ${newExample}`
);
@ -37,33 +36,37 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
});
new Setting(containerEl)
.setName("Daily Notes Folder")
.setName("Daily notes folder")
.setDesc("Select the folder where your daily notes are stored.")
.addDropdown((dropdown) => {
// Create an object to hold the folder options
const folderOptions: Record<string, string> = {};
// Get all files from the vault and filter for folders
const allFolders = this.app.vault
.addText((textComponent) => {
textComponent.setValue(
this.plugin.settings.dailyNotesFolder || ""
);
// Set a placeholder to prompt the user.
textComponent.setPlaceholder("Search for folder...");
// Retrieve folder options by filtering all loaded files for TFolder instances.
const folderOptions: string[] = this.app.vault
.getAllLoadedFiles()
.filter((f): f is TFolder => f instanceof TFolder);
// Populate the folderOptions with folder paths
allFolders.forEach((folder) => {
folderOptions[folder.path] = folder.path;
});
// Add each folder option to the dropdown
for (const key in folderOptions) {
dropdown.addOption(key, folderOptions[key]);
}
// Set the current value from the plugin settings
dropdown.setValue(this.plugin.settings.dailyNotesFolder);
dropdown.onChange(async (value: string) => {
this.plugin.settings.dailyNotesFolder = value;
await this.plugin.saveSettings();
});
.filter((f): f is TFolder => f instanceof TFolder)
.map((folder) => folder.path);
const folderSuggest = new FolderSuggest(
this.app,
textComponent.inputEl,
folderOptions
);
// Save to settings and update text when a suggestion is chosen
folderSuggest.onSelect(
(suggestion: string, evt: MouseEvent | KeyboardEvent) => {
textComponent.setValue(suggestion);
this.plugin.settings.dailyNotesFolder = suggestion;
this.plugin.saveSettings();
folderSuggest.close();
}
);
});
new Setting(containerEl)
.setName("Horizontal Lines")
.setName("Horizontal lines")
.setDesc(
"Would you like horizontal lines above or below the output block?"
)
@ -80,7 +83,7 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
});
new Setting(containerEl)
.setName("Custom Prompt Details")
.setName("Custom prompt details")
.setDesc(
"Add custom details to the prompt if you prefer. E.g., Please prioritize things I accomplished or only tell me positive things."
)
@ -96,7 +99,7 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
});
new Setting(containerEl)
.setName("Placeholder Tag")
.setName("Placeholder tag")
.setDesc(
"The plugin will search for this text in your active file to replace with its return block. Otherwise outputs at cursor. Default <!OTDI>"
)
@ -110,13 +113,12 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
);
new Setting(containerEl)
.setName("Through the Years Output Header")
.setName("Through the years output header")
.setDesc(
"How do you want to title the output block of the Through the Years command? The default is `On This Day`"
)
.addText((text) =>
text
.setValue("On This Day")
.setValue(
this.plugin.settings.throughTheYearsHeader ||
"On This Day"
@ -142,7 +144,7 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
);
new Setting(containerEl)
.setName("Output Length (Sentences)")
.setName("Output length (sentences)")
.setDesc(
"Select how many sentences should each year's response be (between 1 and 8)."
)
@ -161,10 +163,10 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
await this.plugin.saveSettings();
});
});
containerEl.createEl("h2", { text: "OpenAI Settings" });
new Setting(containerEl).setName("OpenAI").setHeading();
new Setting(containerEl)
.setName("Model Version")
.setName("Model sersion")
.setDesc("Select the OpenAI model to use.")
.addDropdown((dropdown) => {
dropdown.addOption("gpt-3.5-turbo", "gpt-3.5-turbo");
@ -177,8 +179,8 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
});
new Setting(containerEl)
.setName("OpenAI API Key")
.setDesc("Your OpenAI API key.")
.setName("OpenAI api key")
.setDesc("Your OpenAI api key.")
.addText((text) =>
text
.setPlaceholder("sk-...")
@ -189,9 +191,9 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
})
);
containerEl.createEl("h2", { text: "Health Estimate Settings" });
new Setting(containerEl).setName("Health estimates").setHeading();
new Setting(containerEl)
.setName("Health Estimates Placeholder Tag")
.setName("Health estimates placeholder tag")
.setDesc(
"The plugin will search for this text in your active file to replace with its return block. Otherwise outputs at cursor. Default <!OTDI diet>"
)
@ -209,7 +211,7 @@ export default class OnThisDaySettingTab extends PluginSettingTab {
);
new Setting(containerEl)
.setName("Food Section Header")
.setName("Food section header")
.setDesc(
"Enter the header that marks the food section in your daily note. Default is '### Food'."
)

View file

@ -1,4 +1,4 @@
import moment from "moment";
import { moment } from "obsidian";
//
// Utility Functions