What are all the command strings that can be passed to "joplin.commands.execute"?

I've built several custom UI components in my userstyle.css and I'm now taking a journey into plugin development so I can automatically insert/surround selected text with my custom HTML and CSS class definitions to avoid the process of manually typing out my desired HTML.

I only want this to work in the markdown editor, not in the RTE editor.

Looking at the API reference editor.execCommand is what I'm looking for. But I can't for the life of me find a list of all commands that can be passed to this. Just skimming other plugins on GitHub I found the following:

// Some commands here: https://github.com/laurent22/joplin/blob/2014fbf480fc57f5b87f2c900baf486631332cc1/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx#L172
// More commands here: https://github.com/laurent22/joplin/blob/2014fbf480fc57f5b87f2c900baf486631332cc1/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.ts#L31
await joplin.commands.execute('textSelectAll');                        // Selects all text
await joplin.commands.execute("selectedText");                         // Returns currently selected text
await joplin.commands.execute("replaceSelection", "replacement_text"); // Replaces current selection with text
await joplin.commands.execute('editor.setText', 'something');          // Not sure what this command is?
await joplin.commands.execute('editor.focus');                         // Also not sure what this command is?

Based on what I've found, I think I can accomplish what I need with this - but I'm not sure if this is the best way to do it:

import joplin from 'api';
import { MenuItemLocation, ToolbarButtonLocation } from 'api/types';

joplin.plugins.register({
	onStart: async function() {
		await joplin.commands.register({
			name: 'CreateButton',
			label: 'Creates a button.',
			iconName: 'fas fa-drum',
			execute: async () => {
                const tag_start = "<span class=\"fm-enhanced-link theme-blue-filled-1 br-6px\">"
                const tag_end = "</span>"
				var selectedText = await joplin.commands.execute("selectedText");
                var newButtonDef = tag_start + selectedText + tag_end
                await joplin.commands.execute("replaceSelection", newButtonDef);
			},
		});
        await joplin.views.toolbarButtons.create('CreateHTMLButton', 'CreateButton', ToolbarButtonLocation.EditorToolbar);
	},
});

Am I on the right track?

And can someone please provide a reference page that actually lists all commands that can be passed to joplin.commands.execute?

The doc lists the places that contain the list of commands:

1 Like

Yeah, I've looked through that link. But I can't find any proper documentation on what all the commands are, and there are multiple command types. There are NoteEditor Command Declarations and CodeMirror Editor Commands, and the syntax differs. There is also codeMirrorWrapper command registration shown here.

Commands can be called in several ways:

editorRef.current.execCommand(EditorCommandType.SomeCommand, ...argsHere)
await joplin.commands.execute('editor.execCommand', {
    name: 'CodemirrorCommand',
    args: [],
});
joplin.commands.execute('editor.execCommand', { name: 'name-here', args: [] })

And then you can wrap CodeMirror 6, and register a command that can be called with joplin.commands.execute :

export default (_context: ContentScriptContext): MarkdownEditorContentScriptModule => {
    return {
        // - codeMirrorWrapper: A thin wrapper around CodeMirror 6, designed to be similar to the
        //     CodeMirror 5 API. If running in CodeMirror 5, a CodeMirror object is provided instead.
        //     If running in CodeMirror 6, codeMirrorWrapper.editor points to a CodeMirror 6 EditorView.
        plugin: (codeMirrorWrapper) => {
            // We can also register editor commands. These commands can be later executed with:
            // joplin.commands.execute('editor.execCommand', { name: 'name-here', args: [] })
            codeMirrorWrapper.registerCommand('wrap-selection-with-tag', (tagName: string) => {
                const editor: EditorView = codeMirrorWrapper.editor;
                editor.dispatch(editor.state.changeByRange(range => {
                    const insertBefore = `<${tagName}>`;
                    const insertAfter = `</${tagName}>`;
                    return {
                        changes: [
                            {from: range.from, insert: insertBefore},
                            {from: range.to, insert: insertAfter},
                        ],
                        range: range.extend(
                            range.from,
                            range.to + insertBefore.length + insertAfter.length,
                        ),
                    };
                }));
            });
        },
    };
};

There is just so much to take in, I wish there was a detailed list of all commands and ways to invoke them, I'm just lost on which route to take.

I think I'm over my head. If any of you are on Discord I would really like to pick your brain on the best way to structure the plugin I want to create.

Checkout this plugin:

I bet you can easily make sense of what is going on with those editor commands, not too much code, you can easily work any AI agent to learn what's going on there.
I personally worked with Grok in DeeperSearch mode.

I didn't knew all that stuff you mentioned yesterday, now after playing with this plugin I get most of it. And it works on mobile too.
Plugin by itself is very useful and underrated.

Hope it helps. You can DM me here I'll try to help.

P.S. if you'll go with Grok, don't hesitate to ask him about what plugin you try to do and force him to work with data from this forum only - I personally saved myself so much time this way. That's actually how I found Resume Note plugin, lol.

Hmm, but why not start with the documentation? We only list one way of calling a command:

Then if you want to do something specific, you can check the examples or ask here. But generally it's not much more complicated than joplin.commands.execute(...)