diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index f8a3885ab6..524a22a21a 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -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, diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx index 995760f4b3..2cac817762 100644 --- a/src/autocomplete/CommandProvider.tsx +++ b/src/autocomplete/CommandProvider.tsx @@ -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() + " "; diff --git a/src/components/views/dialogs/SlashCommandHelpDialog.tsx b/src/components/views/dialogs/SlashCommandHelpDialog.tsx index c650e78f41..e59c3178a5 100644 --- a/src/components/views/dialogs/SlashCommandHelpDialog.tsx +++ b/src/components/views/dialogs/SlashCommandHelpDialog.tsx @@ -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 = ({ onFinished }) => { const categories: Record = {}; Commands.forEach((cmd) => { - if (!cmd.isEnabled()) return; + if (!cmd.isEnabled(MatrixClientPeg.get())) return; if (!categories[cmd.category]) { categories[cmd.category] = []; } diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index 484c58756a..7bf01fa3af 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -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 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; } }