Command API ​
Commands are the actions that can be triggered by the user. With the command API, you can define chainable commands and execute them.
Command Chain ​
Commands are executed in a chain, and each command can decide whether to continue the chain or not.
std.command.pipe().command1().command2().command3().run();
std.command.pipe().command1().command2().command3().run();
You will need to call pipe()
to start a new chain. Then, you can call any command defined in the Commands
interface. And finally, call run()
to execute the chain.
Try ​
If a command fails, the chain will be interrupted. However, you can use try()
to call a list of commands until one of them succeeds.
std.command
.pipe()
.try(cmd => [cmd.command1(), cmd.command2()])
.command3()
.run();
std.command
.pipe()
.try(cmd => [cmd.command1(), cmd.command2()])
.command3()
.run();
In this chain, command3
will be executed only if command1
or command2
succeeds.
Writing Commands ​
Commands are defined as pure functions.
import type { Command } from '@blocksuite/block-std';
export const myCommand: Command = (ctx, next) => {
if (fail) {
return;
}
return next();
};
declare global {
namespace BlockSuite {
interface Commands {
my: typeof myCommand;
}
}
}
// Add the command to the std command list
std.command.add('my', myCommand);
// You can call it with
std.command.pipe().my().run();
import type { Command } from '@blocksuite/block-std';
export const myCommand: Command = (ctx, next) => {
if (fail) {
return;
}
return next();
};
declare global {
namespace BlockSuite {
interface Commands {
my: typeof myCommand;
}
}
}
// Add the command to the std command list
std.command.add('my', myCommand);
// You can call it with
std.command.pipe().my().run();
Only when the command calls next()
, the next command in the chain will be executed.
Command Context ​
When a list of commands are executed, they share a context object. This object is standalone for each command execution, and you can use it to store temporary data.
import type { Command } from '@blocksuite/block-std';
export const myCommand: Command<never, 'myCommandData'> = (ctx, next) => {
if (fail) {
return;
}
return next({ myCommandData: 'hello' });
};
declare global {
namespace BlockSuite {
interface CommandData {
myCommandData: string;
}
interface Commands {
myCommand: typeof myCommand;
}
}
}
import type { Command } from '@blocksuite/block-std';
export const myCommand: Command<never, 'myCommandData'> = (ctx, next) => {
if (fail) {
return;
}
return next({ myCommandData: 'hello' });
};
declare global {
namespace BlockSuite {
interface CommandData {
myCommandData: string;
}
interface Commands {
myCommand: typeof myCommand;
}
}
}
Then, commands executed after myCommand
can access the data:
export const myCommand: Command<'myCommandData'> = (ctx, next) => {
const data = ctx.myCommandData;
console.log(data);
};
export const myCommand: Command<'myCommandData'> = (ctx, next) => {
const data = ctx.myCommandData;
console.log(data);
};
Command Options ​
You can pass options to a command when calling it:
import type { Command } from '@blocksuite/block-std';
type MyCommandOptions = {
configA: number;
configB: string;
};
export const myCommand: Command<never, never, MyCommandOptions> = (
ctx,
next
) => {
const { configA, configB } = ctx;
if (fail) {
return;
}
return next();
};
// You can call it with
std.command.pipe().my({ configA: 0, configB: 'hello' }).run();
import type { Command } from '@blocksuite/block-std';
type MyCommandOptions = {
configA: number;
configB: string;
};
export const myCommand: Command<never, never, MyCommandOptions> = (
ctx,
next
) => {
const { configA, configB } = ctx;
if (fail) {
return;
}
return next();
};
// You can call it with
std.command.pipe().my({ configA: 0, configB: 'hello' }).run();
Please notice that commands take only one argument, so you need to wrap the options in an object if you want to pass multiple options.
Inline Command ​
You can also use inline command for some temporary commands.
std.command
.pipe()
.inline((ctx, next) => {
// ...
return next();
})
.run();
std.command
.pipe()
.inline((ctx, next) => {
// ...
return next();
})
.run();