mirror of
https://github.com/ytliu74/obsidian-pseudocode.git
synced 2026-07-22 07:40:25 +00:00
feat: add auto-completion
This commit is contained in:
parent
057c402d1b
commit
c140928b1b
1 changed files with 251 additions and 68 deletions
319
main.ts
319
main.ts
|
|
@ -1,62 +1,88 @@
|
|||
import { App, Notice, Plugin, PluginSettingTab, Setting, MarkdownView, Editor, Modal } from 'obsidian';
|
||||
import {
|
||||
App,
|
||||
Editor,
|
||||
EditorPosition,
|
||||
EditorSuggest,
|
||||
EditorSuggestContext,
|
||||
EditorSuggestTriggerInfo,
|
||||
Plugin,
|
||||
PluginSettingTab,
|
||||
Setting,
|
||||
TFile,
|
||||
} from "obsidian";
|
||||
|
||||
import * as pseudocode from "pseudocode";
|
||||
|
||||
// Remember to rename these classes and interfaces!
|
||||
|
||||
interface PseudocodeSettings {
|
||||
indentSize: string,
|
||||
commentDelimiter: string,
|
||||
lineNumber: boolean,
|
||||
lineNumberPunc: string,
|
||||
noEnd: boolean,
|
||||
captionCount: undefined
|
||||
indentSize: string;
|
||||
commentDelimiter: string;
|
||||
lineNumber: boolean;
|
||||
lineNumberPunc: string;
|
||||
noEnd: boolean;
|
||||
captionCount: undefined;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: PseudocodeSettings = {
|
||||
indentSize: '1.2em',
|
||||
commentDelimiter: '//',
|
||||
indentSize: "1.2em",
|
||||
commentDelimiter: "//",
|
||||
lineNumber: false,
|
||||
lineNumberPunc: ':',
|
||||
lineNumberPunc: ":",
|
||||
noEnd: false,
|
||||
captionCount: undefined
|
||||
}
|
||||
captionCount: undefined,
|
||||
};
|
||||
|
||||
export default class PseudocodePlugin extends Plugin {
|
||||
settings: PseudocodeSettings;
|
||||
|
||||
async pseudocodeHandler(source: string, el: HTMLElement, ctx: any): Promise<any> {
|
||||
async pseudocodeHandler(
|
||||
source: string,
|
||||
el: HTMLElement,
|
||||
ctx: any
|
||||
): Promise<any> {
|
||||
// const rawRows: string[] = source.split("\n");
|
||||
|
||||
const katex = el.createEl("script");
|
||||
katex.src = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.js";
|
||||
katex.src =
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.js";
|
||||
katex.integrity = "sha256-F/Xda58SPdcUCr+xhSGz9MA2zQBPb0ASEYKohl8UCHc=";
|
||||
katex.crossOrigin = "anonymous";
|
||||
|
||||
const preEl = el.createEl("pre", { cls: "code", text: source });
|
||||
|
||||
console.log(el);
|
||||
// console.log(el);
|
||||
pseudocode.renderElement(preEl, this.settings);
|
||||
}
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
||||
this.registerMarkdownCodeBlockProcessor("pcode", this.pseudocodeHandler.bind(this));
|
||||
this.registerMarkdownCodeBlockProcessor(
|
||||
"pcode",
|
||||
this.pseudocodeHandler.bind(this)
|
||||
);
|
||||
|
||||
// Register suggest
|
||||
this.registerEditorSuggest(new PseudocodeSuggestor(this));
|
||||
|
||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||
this.addSettingTab(new PseudocodeSettingTab(this.app, this));
|
||||
|
||||
// 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.registerInterval(
|
||||
// window.setInterval(() => console.log("setInterval"), 5 * 60 * 1000)
|
||||
// );
|
||||
}
|
||||
|
||||
onunload() {
|
||||
|
||||
}
|
||||
onunload() {}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
this.settings = Object.assign(
|
||||
{},
|
||||
DEFAULT_SETTINGS,
|
||||
await this.loadData()
|
||||
);
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
|
|
@ -77,80 +103,237 @@ class PseudocodeSettingTab extends PluginSettingTab {
|
|||
|
||||
containerEl.empty();
|
||||
|
||||
containerEl.createEl('h1', { text: 'Pseudocode Plugin Settings' });
|
||||
containerEl.createEl("h1", { text: "Pseudocode Plugin Settings" });
|
||||
|
||||
// Instantiate Indent Size setting
|
||||
new Setting(containerEl)
|
||||
.setName("Indent Size")
|
||||
.setDesc("The indent size of inside a control block, e.g. if, for, etc. The unit must be in 'em'.")
|
||||
.addText(text => text
|
||||
.setValue(this.plugin.settings.indentSize)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.indentSize = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.setDesc(
|
||||
"The indent size of inside a control block, e.g. if, for, etc. The unit must be in 'em'."
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setValue(this.plugin.settings.indentSize)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.indentSize = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Instantiate Comment Delimiter setting
|
||||
new Setting(containerEl)
|
||||
.setName("Comment Delimiter")
|
||||
.setDesc("The string used to indicate a comment in the pseudocode.")
|
||||
.addText(text => text
|
||||
.setValue(this.plugin.settings.commentDelimiter)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.commentDelimiter = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.addText((text) =>
|
||||
text
|
||||
.setValue(this.plugin.settings.commentDelimiter)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.commentDelimiter = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Instantiate Show Line Numbers setting
|
||||
new Setting(containerEl)
|
||||
.setName("Show Line Numbers")
|
||||
.setDesc("Whether line numbering is enabled.")
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.lineNumber)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lineNumber = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.lineNumber)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lineNumber = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Instantiate Line Number Punctuation setting
|
||||
new Setting(containerEl)
|
||||
.setName("Line Number Punctuation")
|
||||
.setDesc("The punctuation used to separate the line number from the pseudocode.")
|
||||
.addText(text => text
|
||||
.setValue(this.plugin.settings.lineNumberPunc)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lineNumberPunc = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.setDesc(
|
||||
"The punctuation used to separate the line number from the pseudocode."
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setValue(this.plugin.settings.lineNumberPunc)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lineNumberPunc = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Instantiate No End setting
|
||||
new Setting(containerEl)
|
||||
.setName("No End")
|
||||
.setDesc("If enabled, pseudocode blocks will not have an 'end' statement.")
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.noEnd)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.noEnd = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.setDesc(
|
||||
"If enabled, pseudocode blocks will not have an 'end' statement."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.noEnd)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.noEnd = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Instantiate Caption Count setting
|
||||
// new Setting(containerEl)
|
||||
// .setName("Caption Count")
|
||||
// .setDesc("The number to start captioning pseudocode blocks from.")
|
||||
// .addText(text => text
|
||||
// .setValue(this.plugin.settings.captionCount)
|
||||
// .onChange(async (value) => {
|
||||
// this.plugin.settings.captionCount = value;
|
||||
// await this.plugin.saveSettings();
|
||||
// })
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
``
|
||||
class PseudocodeSuggestor extends EditorSuggest<string> {
|
||||
plugin: PseudocodePlugin;
|
||||
|
||||
constructor(plugin: PseudocodePlugin) {
|
||||
super(plugin.app);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
onTrigger(
|
||||
cursor: EditorPosition,
|
||||
editor: Editor,
|
||||
file: TFile
|
||||
): EditorSuggestTriggerInfo | null {
|
||||
// perf: Use the "\" to tell whether to return.
|
||||
const currentLineToCursor = editor
|
||||
.getLine(cursor.line)
|
||||
.slice(0, cursor.ch);
|
||||
const currentLineLastWordStart = currentLineToCursor.lastIndexOf("\\");
|
||||
// if there is no word, return null
|
||||
if (currentLineLastWordStart === -1) return null;
|
||||
|
||||
const currentFileToCursor = editor.getRange({ line: 0, ch: 0 }, cursor);
|
||||
const indexOfLastCodeBlockStart =
|
||||
currentFileToCursor.lastIndexOf("```");
|
||||
|
||||
// check if this is a pcode block
|
||||
const isPcode =
|
||||
currentFileToCursor.slice(
|
||||
indexOfLastCodeBlockStart + 3,
|
||||
indexOfLastCodeBlockStart + 8
|
||||
) == "pcode";
|
||||
|
||||
if (!isPcode) return null;
|
||||
|
||||
// Get last word in current line
|
||||
// const currentLineToCursor = editor
|
||||
// .getLine(cursor.line)
|
||||
// .slice(0, cursor.ch);
|
||||
|
||||
return {
|
||||
start: { line: cursor.line, ch: currentLineLastWordStart },
|
||||
end: cursor,
|
||||
query: currentLineToCursor.slice(currentLineLastWordStart),
|
||||
};
|
||||
}
|
||||
|
||||
getSuggestions(
|
||||
context: EditorSuggestContext
|
||||
): string[] | Promise<string[]> {
|
||||
const query = context.query;
|
||||
|
||||
const suggestions = this.pcodeKeywords.filter((value) =>
|
||||
value.startsWith(query)
|
||||
);
|
||||
|
||||
// console.log(suggestions);
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
renderSuggestion(value: string, el: HTMLElement): void {
|
||||
el.addClass("suggestion");
|
||||
const suggestContent = el.createDiv({ cls: "suggestion-content" });
|
||||
suggestContent.setText(value);
|
||||
}
|
||||
|
||||
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
|
||||
if (this.context) {
|
||||
const editor = this.context.editor;
|
||||
const suggestion = value;
|
||||
const start = this.context.start;
|
||||
const end = editor.getCursor();
|
||||
|
||||
editor.replaceRange(suggestion, start, end);
|
||||
const newCursor = end;
|
||||
newCursor.ch = start.ch + suggestion.length;
|
||||
|
||||
editor.setCursor(newCursor);
|
||||
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
private pcodeKeywords: string[] = [
|
||||
"\\begin{algorithmic}",
|
||||
"\\begin{algorithm}",
|
||||
"\\end{algorithmic}",
|
||||
"\\end{algorithm}",
|
||||
"\\caption{}",
|
||||
"\\PROCEDURE{}{}",
|
||||
"\\ENDPROCEDURE",
|
||||
"\\FUNCTION{}{}",
|
||||
"\\ENDFUNCTION",
|
||||
"\\REQUIRE",
|
||||
"\\ENSURE",
|
||||
"\\INPUT",
|
||||
"\\OUTPUT",
|
||||
"\\STATE",
|
||||
"\\RETURN",
|
||||
"\\PRINT",
|
||||
"\\IF{}",
|
||||
"\\ELIF{}",
|
||||
"\\ENDIF",
|
||||
"\\WHILE{}",
|
||||
"\\ENDWHILE",
|
||||
"\\REPEAT",
|
||||
"\\UNTIL{}",
|
||||
"\\COMMENT{}",
|
||||
"\\{",
|
||||
"\\}",
|
||||
"\\$",
|
||||
"\\&",
|
||||
"\\#",
|
||||
"\\%",
|
||||
"\\_",
|
||||
"\\gets",
|
||||
"\\CALL{}{}",
|
||||
"\\AND",
|
||||
"\\OR",
|
||||
"\\XOR",
|
||||
"\\NOT",
|
||||
"\\TO",
|
||||
"\\DOWNTO",
|
||||
"\\TRUE",
|
||||
"\\FALSE",
|
||||
"\\tiny",
|
||||
"\\scriptsize",
|
||||
"\\footnotesize",
|
||||
"\\small",
|
||||
"\\normalsize",
|
||||
"\\large",
|
||||
"\\Large",
|
||||
"\\LARGE",
|
||||
"\\huge",
|
||||
"\\HUGE",
|
||||
"\\rmfamily",
|
||||
"\\sffamily",
|
||||
"\\ttfamily",
|
||||
"\\upshape",
|
||||
"\\itshape",
|
||||
"\\slshape",
|
||||
"\\scshape",
|
||||
"\\bfseries",
|
||||
"\\mdseries",
|
||||
"\\lfseries",
|
||||
"\\textnormal{}",
|
||||
"\\textrm{}",
|
||||
"\\textsf{}",
|
||||
"\\texttt{}",
|
||||
"\\textup{}",
|
||||
"\\textit{}",
|
||||
"\\textsl{}",
|
||||
"\\textsc{}",
|
||||
"\\uppercase{}",
|
||||
"\\lowercase{}",
|
||||
"\\textbf{}",
|
||||
"\\textmd{}",
|
||||
"\\textlf{}",
|
||||
];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue