various - add jump method. Change selection behaviour

This commit is contained in:
Tal Wrii 2025-01-21 11:46:25 +01:00
parent aab00fb213
commit a101c2aff9
3 changed files with 121 additions and 21 deletions

View file

@ -79,6 +79,7 @@ Various convenience functions are provided:
* `mark()` - Return the cursor position at the beginning of the selection
* `pointMin()` - Return the minimum cursor in the buffer
* `pointMax()` - Return the maximun cursor in the buffer
* `jump(p: CursorPoint)` - Jump to this point
* `forwardChar(count?: number)` - Move count (or one) character forward
* `selection()` - Get the text contained in the selection
@ -165,6 +166,26 @@ dv = getDv()
dv.pages().filter((x) => x.file.path == "templates/daily.md")[0].file.lists[0]
```
## Templater support
The [Templater](https://github.com/SilentVoid13/Templater) provides functionality to insert javascript. If you have installed Templater you can use
the async `templater_expand` function to expand template strings.
This creates a command that inserts a files tags using a template.
```
newCommand(async function templater_example() {
insert(await templater_expand("The files tags: <% tp.file.tags %>"))
})
```
If you want to expand a template for a file you can use `readFile`
```
newCommand(async function templater_from_file() {
insert(await templater_expand(await readFile("myTemplate")))
})
```
## Importing modules
Modules in Obsidian work in an interesting way that makes installing from NPM a little tricky. There is a [technical explanation here](https://github.com/talwrii/plugin-repl-imports#technical).

70
main.ts
View file

@ -3,8 +3,8 @@ import {
MarkdownPostProcessorContext, Command
} from 'obsidian';
import { execFileSync } from 'child_process'
import { parse as shellParse } from 'shell-quote';
import { execFileSync, execSync } from 'child_process'
import { parse as shellParse, quote as shellQuote } from 'shell-quote';
import { expandRegionWithRegexp } from './editorUtils'
@ -22,6 +22,7 @@ import { promptString } from './prompt'
import { promptCommand } from './promptCommand'
import { popup } from './popup'
import { openSetting } from './settings'
import { templater_expand } from './templater'
export default class ReplPlugin extends Plugin {
@ -102,10 +103,15 @@ export default class ReplPlugin extends Plugin {
}
updateScopeApp() {
let path = this.app.workspace.getLeaf().view.path
this.scope.add("repl", this)
// @ts-ignore path does exist
let path = this.app.workspace.getLeaf().view.path
// @ts-ignore
let frontmatter = this.app.metadataCache.getFileCache(this.app.workspace.getLeaf().view.file)["frontmatter"]
this.scope.add("repl", this)
this.scope.add("path", path)
this.scope.add("frontmatter", frontmatter)
//@ts-ignore
let vaultPath = this.app.vault.adapter.basePath
this.scope.add("vaultPath", vaultPath)
@ -153,7 +159,7 @@ export default class ReplPlugin extends Plugin {
)
this.addToScopeWithDoc(
"runProc", runProc,
"(s: string) or (['prog', 'arg1', 'args2']) run a program and return its output"
"(s: string) or (['prog', 'arg1', 'args2']) run a program and return its output. To send "
)
this.addToScopeWithDoc(
"newCommand", this.makeNewCommand(),
@ -194,11 +200,6 @@ export default class ReplPlugin extends Plugin {
"(title: string, content: string) Add the content to the note with a titel"
)
this.addToScopeWithDoc(
"getDv", getDv.bind(null, this.app),
"Get hold of the dataview object for querying pages"
)
this.addToScopeWithDoc(
"message", message,
"(msg: string) Popup a message with a notification message msg"
@ -216,6 +217,17 @@ export default class ReplPlugin extends Plugin {
"openUrl", openUrl,
"(url: string) Open this url in a browser "
)
this.addToScopeWithDoc(
"getDv", getDv.bind(null, this.app),
"Get hold of the dataview object for querying pages"
)
this.addToScopeWithDoc(
"templater_expand", templater_expand.bind(null, this.app),
"If templater is installed, expand the templater string and return the result."
)
}
updateScopeEditor(editor: Editor, view: MarkdownView) {
@ -268,6 +280,10 @@ export default class ReplPlugin extends Plugin {
"pointMax", pointMax.bind(null, editor),
"Returns the cursor positoin at the beginning of the note"
)
this.addToScopeWithDoc(
"jump", jump.bind(null, editor),
"Jump to the given point."
)
this.addToScopeWithDoc(
"selection", selection.bind(null, editor),
"Returns the text of the selection."
@ -290,13 +306,18 @@ export default class ReplPlugin extends Plugin {
makeNewCommand() {
const plugin = this
function newCommand(f: any) {
let commandName = f.name.replaceAll("_", " ")
plugin.addCommand({
id: f.name,
name: f.name.replaceAll("_", " "),
name: commandName,
editorCallback: (editor: Editor, view: MarkdownView) => {
plugin.updateScopeApp()
plugin.updateScopeEditor(editor, view)
plugin.scope.run(f)
try {
plugin.scope.run(f)
} catch (e) {
message(`${commandName} failed: ${e.message}`)
}
}
});
return f
@ -361,21 +382,27 @@ export default class ReplPlugin extends Plugin {
}
}
function openFile(app: any, name: string) {
app.workspace.openLinkText(name)
async function openFile(app: any, name: string) {
await app.workspace.openLinkText(name)
}
function plugin(app: any, name: string) {
return app.plugins.plugins[name]
}
function runProc(commandAndArgs: string | Array<string>): string {
function runProc(commandAndArgs: string | Array<string>, input?: string): string {
if (typeof commandAndArgs === "string") {
const command = shellParse(commandAndArgs) as string[]
return runProc(command)
return runProc(command, input)
}
if (input == undefined) {
const [command, ...args] = commandAndArgs
return execFileSync(command, args).toString()
} else {
let quoted = shellQuote(commandAndArgs)
return execSync(quoted, { input: input }).toString()
}
const [command, ...args] = commandAndArgs
return execFileSync(command, args).toString()
}
function dir(obj: any) {
@ -407,9 +434,6 @@ function lineAtPoint(editor: Editor) {
function selection(editor: Editor) {
const selection = editor.getSelection()
if (selection === "") {
throw Error("No text is selected")
}
return selection
}
@ -493,6 +517,10 @@ function pointMax(editor: Editor) {
return { line: lastLine, ch: lastChar }
}
function jump(editor: Editor, position: EditorPosition) {
return editor.setCursor(position)
}
function pointMin(): EditorPosition {
return { line: 0, ch: 0 }
}

51
popup.ts Normal file
View file

@ -0,0 +1,51 @@
import { App, Editor, Modal, Setting } from 'obsidian'
export function popup(app: App, editor: Editor, message: string): Promise<void> {
const position = editor.getCursor()
return new Promise<void>((resolve, reject) => {
try {
new Popup(app, message, resolve).open()
editor.setCursor(position)
} catch (e) {
reject(e)
}
})
}
export class Popup extends Modal {
constructor(app: App, msg: string, resolve: () => void) {
super(app);
const el = new DocumentFragment()
const pre = el.createEl("pre")
pre.appendText(msg)
this.setContent(el)
new Setting(this.contentEl).addButton((btn) => {
btn.setButtonText("OK")
const popup = this
let keyDown = false;
function done() {
popup.close()
resolve()
return true
}
btn.buttonEl.addEventListener("keydown", (_) => {
keyDown = true
})
btn.buttonEl.addEventListener('click', (_) => {
return done()
})
btn.buttonEl.addEventListener("keyup", (_) => {
if (keyDown) {
return done()
}
})
})
}
}