Fix slash commands not being enabled in certain cases (#11090)

* Fix slash commands not being enabled in certain cases

* Fix import cycle
This commit is contained in:
Michael Telatynski 2023-06-14 13:49:18 +01:00 committed by GitHub
parent 9c48487d85
commit 6486255f54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 16 additions and 10 deletions

View file

@ -69,6 +69,7 @@ import { htmlSerializeFromMdIfNeeded } from "./editor/serialize";
import { leaveRoomBehaviour } from "./utils/leave-behaviour";
import { isLocalRoom } from "./utils/localRoom/isLocalRoom";
import { SdkContextClass } from "./contexts/SDKContext";
import { MatrixClientPeg } from "./MatrixClientPeg";
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
interface HTMLInputEvent extends Event {
@ -122,7 +123,7 @@ interface ICommandOpts {
runFn?: RunFn;
category: string;
hideCompletionAfterSpace?: boolean;
isEnabled?(matrixClient?: MatrixClient): boolean;
isEnabled?(matrixClient: MatrixClient | null): boolean;
renderingTypes?: TimelineRenderingType[];
}
@ -136,7 +137,7 @@ export class Command {
public readonly hideCompletionAfterSpace: boolean;
public readonly renderingTypes?: TimelineRenderingType[];
public readonly analyticsName?: SlashCommandEvent["command"];
private readonly _isEnabled?: (matrixClient?: MatrixClient) => boolean;
private readonly _isEnabled?: (matrixClient: MatrixClient | null) => boolean;
public constructor(opts: ICommandOpts) {
this.command = opts.command;
@ -189,7 +190,7 @@ export class Command {
return _t("Usage") + ": " + this.getCommandWithArgs();
}
public isEnabled(cli?: MatrixClient): boolean {
public isEnabled(cli: MatrixClient | null): boolean {
return this._isEnabled?.(cli) ?? true;
}
}
@ -206,7 +207,7 @@ function successSync(value: any): RunResult {
return success(Promise.resolve(value));
}
const isCurrentLocalRoom = (cli?: MatrixClient): boolean => {
const isCurrentLocalRoom = (cli: MatrixClient | null): boolean => {
const roomId = SdkContextClass.instance.roomViewStore.getRoomId();
if (!roomId) return false;
const room = cli?.getRoom(roomId);
@ -214,7 +215,7 @@ const isCurrentLocalRoom = (cli?: MatrixClient): boolean => {
return isLocalRoom(room);
};
const canAffectPowerlevels = (cli?: MatrixClient): boolean => {
const canAffectPowerlevels = (cli: MatrixClient | null): boolean => {
const roomId = SdkContextClass.instance.roomViewStore.getRoomId();
if (!cli || !roomId) return false;
const room = cli?.getRoom(roomId);
@ -1425,7 +1426,7 @@ interface ICmd {
export function getCommand(input: string): ICmd {
const { cmd, args } = parseCommandString(input);
if (cmd && CommandMap.has(cmd) && CommandMap.get(cmd)!.isEnabled()) {
if (cmd && CommandMap.has(cmd) && CommandMap.get(cmd)!.isEnabled(MatrixClientPeg.get())) {
return {
cmd: CommandMap.get(cmd),
args,

View file

@ -27,6 +27,7 @@ import { TextualCompletion } from "./Components";
import { ICompletion, ISelectionRange } from "./Autocompleter";
import { Command, Commands, CommandMap } from "../SlashCommands";
import { TimelineRenderingType } from "../contexts/RoomContext";
import { MatrixClientPeg } from "../MatrixClientPeg";
const COMMAND_RE = /(^\/\w*)(?: .*)?/g;
@ -51,12 +52,14 @@ export default class CommandProvider extends AutocompleteProvider {
const { command, range } = this.getCurrentCommand(query, selection);
if (!command) return [];
const cli = MatrixClientPeg.get();
let matches: Command[] = [];
// check if the full match differs from the first word (i.e. returns false if the command has args)
if (command[0] !== command[1]) {
// The input looks like a command with arguments, perform exact match
const name = command[1].slice(1); // strip leading `/`
if (CommandMap.has(name) && CommandMap.get(name)!.isEnabled()) {
if (CommandMap.has(name) && CommandMap.get(name)!.isEnabled(cli)) {
// some commands, namely `me` don't suit having the usage shown whilst typing their arguments
if (CommandMap.get(name)!.hideCompletionAfterSpace) return [];
matches = [CommandMap.get(name)!];
@ -75,7 +78,7 @@ export default class CommandProvider extends AutocompleteProvider {
return matches
.filter((cmd) => {
const display = !cmd.renderingTypes || cmd.renderingTypes.includes(this.renderingType);
return cmd.isEnabled() && display;
return cmd.isEnabled(cli) && display;
})
.map((result) => {
let completion = result.getCommand() + " ";

View file

@ -19,6 +19,7 @@ import React from "react";
import { _t } from "../../../languageHandler";
import { Command, CommandCategories, Commands } from "../../../SlashCommands";
import InfoDialog from "./InfoDialog";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
interface IProps {
onFinished(): void;
@ -27,7 +28,7 @@ interface IProps {
const SlashCommandHelpDialog: React.FC<IProps> = ({ onFinished }) => {
const categories: Record<string, Command[]> = {};
Commands.forEach((cmd) => {
if (!cmd.isEnabled()) return;
if (!cmd.isEnabled(MatrixClientPeg.get())) return;
if (!categories[cmd.category]) {
categories[cmd.category] = [];
}

View file

@ -51,6 +51,7 @@ import { ALTERNATE_KEY_NAME, KeyBindingAction } from "../../../accessibility/Key
import { _t } from "../../../languageHandler";
import { linkify } from "../../../linkify-matrix";
import { SdkContextClass } from "../../../contexts/SDKContext";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
// matches emoticons which follow the start of a line or whitespace
const REGEX_EMOTICON_WHITESPACE = new RegExp("(?:^|\\s)(" + EMOTICON_REGEX.source + ")\\s|:^$");
@ -268,7 +269,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
if (isTyping && this.props.model.parts[0].type === "command") {
const { cmd } = parseCommandString(this.props.model.parts[0].text);
const command = CommandMap.get(cmd!);
if (!command?.isEnabled() || command.category !== CommandCategories.messages) {
if (!command?.isEnabled(MatrixClientPeg.get()) || command.category !== CommandCategories.messages) {
isTyping = false;
}
}