re-arrange to split the async task into two and only wait on the user-blocking one

This commit is contained in:
Michael Telatynski 2020-01-21 16:57:07 +00:00
parent b34fe45518
commit 9f7df33bc3
2 changed files with 52 additions and 58 deletions

View file

@ -907,14 +907,14 @@ const aliases = {
/**
* Process the given text for /commands and perform them.
* Process the given text for /commands and return a bound method to perform them.
* @param {string} roomId The room in which the command was performed.
* @param {string} input The raw text input by the user.
* @return {Object|null} An object with the property 'error' if there was an error
* @return {null|function(): Object} Function returning an object with the property 'error' if there was an error
* processing the command, or 'promise' if a request was sent out.
* Returns null if the input didn't match a command.
*/
export function processCommandInput(roomId, input) {
export function getCommand(roomId, input) {
// trim any trailing whitespace, as it can confuse the parser for
// IRC-style commands
input = input.replace(/\s+$/, '');
@ -934,8 +934,6 @@ export function processCommandInput(roomId, input) {
cmd = aliases[cmd];
}
if (CommandMap[cmd]) {
return CommandMap[cmd].run(roomId, args);
return () => CommandMap[cmd].run(roomId, args);
}
return null;
// return reject(_t('Unrecognised command:') + ' ' + input);
}

View file

@ -35,7 +35,7 @@ import ReplyThread from "../elements/ReplyThread";
import {parseEvent} from '../../../editor/deserialize';
import {findEditableEvent} from '../../../utils/EventUtils';
import SendHistoryManager from "../../../SendHistoryManager";
import {processCommandInput} from '../../../SlashCommands';
import {getCommand} from '../../../SlashCommands';
import * as sdk from '../../../index';
import Modal from '../../../Modal';
import {_t, _td} from '../../../languageHandler';
@ -197,12 +197,7 @@ export default class SendMessageComposer extends React.Component {
return false;
}
/**
* Parses and executes current input as a Slash Command
* @returns {Promise<Symbol|void>} UNKNOWN_CMD if the command is not known,
* SEND_ANYWAY if the input should be sent as message instead
*/
async _tryRunSlashCommand() {
_getSlashCommand() {
const commandText = this.model.parts.reduce((text, part) => {
// use mxid to textify user pills in a command
if (part.type === "user-pill") {
@ -210,51 +205,41 @@ export default class SendMessageComposer extends React.Component {
}
return text + part.text;
}, "");
const cmd = processCommandInput(this.props.room.roomId, commandText);
return [getCommand(this.props.room.roomId, commandText), commandText];
}
if (cmd) {
let error = cmd.error;
if (cmd.promise) {
try {
await cmd.promise;
} catch (err) {
error = err;
}
async _runSlashCommand(fn) {
const cmd = fn();
let error = cmd.error;
if (cmd.promise) {
try {
await cmd.promise;
} catch (err) {
error = err;
}
if (error) {
console.error("Command failure: %s", error);
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// assume the error is a server error when the command is async
const isServerError = !!cmd.promise;
const title = isServerError ? _td("Server error") : _td("Command error");
}
if (error) {
console.error("Command failure: %s", error);
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// assume the error is a server error when the command is async
const isServerError = !!cmd.promise;
const title = isServerError ? _td("Server error") : _td("Command error");
let errText;
if (typeof error === 'string') {
errText = error;
} else if (error.message) {
errText = error.message;
} else {
errText = _t("Server unavailable, overloaded, or something else went wrong.");
}
Modal.createTrackedDialog(title, '', ErrorDialog, {
title: _t(title),
description: errText,
});
let errText;
if (typeof error === 'string') {
errText = error;
} else if (error.message) {
errText = error.message;
} else {
console.log("Command success.");
errText = _t("Server unavailable, overloaded, or something else went wrong.");
}
} else {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
// unknown command, ask the user if they meant to send it as a message
const {finished} = Modal.createTrackedDialog("Unknown command", "", QuestionDialog, {
title: _t("Unknown Command"),
description: _t("Unrecognised command: ") + commandText,
button: _t('Send as message'),
danger: true,
Modal.createTrackedDialog(title, '', ErrorDialog, {
title: _t(title),
description: errText,
});
const [sendAnyway] = await finished;
return sendAnyway ? SEND_ANYWAY : UNKNOWN_CMD;
} else {
console.log("Command success.");
}
}
@ -266,13 +251,24 @@ export default class SendMessageComposer extends React.Component {
let shouldSend = true;
if (!containsEmote(this.model) && this._isSlashCommand()) {
const resp = await this._tryRunSlashCommand();
if (resp === UNKNOWN_CMD) {
// unknown command, bail to let the user modify it
return;
const [cmd, commandText] = this._getSlashCommand();
if (cmd) {
shouldSend = false;
this._runSlashCommand(cmd);
} else {
// ask the user if their unknown command should be sent as a message instead
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
// unknown command, ask the user if they meant to send it as a message
const {finished} = Modal.createTrackedDialog("Unknown command", "", QuestionDialog, {
title: _t("Unknown Command"),
description: _t("Unrecognised command: ") + commandText,
button: _t('Send as message'),
danger: true,
});
const [sendAnyway] = await finished;
// if !sendAnyway bail to let the user edit the composer and try again
if (!sendAnyway) return;
}
shouldSend = resp === SEND_ANYWAY;
}
if (shouldSend) {