Files
ThreadNet-Web/apps/web/src/autocomplete/CommandProvider.tsx
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

115 lines
4.4 KiB
TypeScript
Raw Normal View History

2017-06-01 15:18:06 +01:00
/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
2017-06-01 15:18:06 +01:00
Copyright 2017 Vector Creations Ltd
2017-11-02 18:01:28 +00:00
Copyright 2017 New Vector Ltd
2024-09-09 14:57:16 +01:00
Copyright 2016 Aviral Dasgupta
2017-06-01 15:18:06 +01:00
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
2024-09-09 14:57:16 +01:00
Please see LICENSE files in the repository root for full details.
2017-06-01 15:18:06 +01:00
*/
2020-04-21 10:01:05 +01:00
import React from "react";
2025-02-05 13:25:06 +00:00
import { type Room } from "matrix-js-sdk/src/matrix";
2021-10-22 17:23:32 -05:00
2021-06-29 13:11:58 +01:00
import { _t } from "../languageHandler";
2016-06-01 16:54:21 +05:30
import AutocompleteProvider from "./AutocompleteProvider";
2018-08-13 19:15:42 +01:00
import QueryMatcher from "./QueryMatcher";
2021-06-29 13:11:58 +01:00
import { TextualCompletion } from "./Components";
2025-02-05 13:25:06 +00:00
import { type ICompletion, type ISelectionRange } from "./Autocompleter";
import { type Command, Commands, CommandMap } from "../slash-commands/SlashCommands";
2025-02-05 13:25:06 +00:00
import { type TimelineRenderingType } from "../contexts/RoomContext";
import { MatrixClientPeg } from "../MatrixClientPeg";
2016-06-01 16:54:21 +05:30
2018-06-16 16:40:44 +01:00
const COMMAND_RE = /(^\/\w*)(?: .*)?/g;
2016-06-01 16:54:21 +05:30
export default class CommandProvider extends AutocompleteProvider {
public matcher: QueryMatcher<Command>;
private room: Room;
public constructor(room: Room, renderingType?: TimelineRenderingType) {
super({ commandRegex: COMMAND_RE, renderingType });
this.matcher = new QueryMatcher(Commands, {
keys: ["command", "args", "description"],
2021-06-29 13:11:58 +01:00
funcs: [({ aliases }) => aliases.join(" ")], // aliases
context: renderingType,
2016-06-01 16:54:21 +05:30
});
this.room = room;
2016-06-01 16:54:21 +05:30
}
public async getCompletions(
query: string,
selection: ISelectionRange,
force?: boolean,
limit = -1,
): Promise<ICompletion[]> {
2021-06-29 13:11:58 +01:00
const { command, range } = this.getCurrentCommand(query, selection);
2018-06-16 16:40:44 +01:00
if (!command) return [];
const cli = MatrixClientPeg.get();
let matches: Command[] = [];
2018-07-09 17:50:07 +01:00
// check if the full match differs from the first word (i.e. returns false if the command has args)
2018-07-09 20:14:37 +01:00
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(cli, this.room.roomId)) {
// 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)!];
}
} else {
if (query === "/") {
// If they have just entered `/` show everything
// We exclude the limit on purpose to have a comprehensive list
matches = Commands;
2018-05-20 23:43:42 +01:00
} else {
// otherwise fuzzy match against all of the fields
matches = this.matcher.match(command[1], limit);
2018-05-13 03:18:41 +01:00
}
2016-06-01 16:54:21 +05:30
}
return matches
.filter((cmd) => {
const display = !cmd.renderingTypes || cmd.renderingTypes.includes(this.renderingType);
return cmd.isEnabled(cli, this.room.roomId) && display;
})
.map((result) => {
let completion = result.getCommand() + " ";
const usedAlias = result.aliases.find((alias) => `/${alias}` === command[1]);
// If the command (or an alias) is the same as the one they entered, we don't want to discard their arguments
if (usedAlias || result.getCommand() === command[1]) {
completion = command[0];
}
return {
completion,
type: "command",
component: (
<TextualCompletion
title={`/${usedAlias || result.command}`}
subtitle={result.args}
description={_t(result.description)}
/>
),
range: range!,
};
});
2016-06-01 16:54:21 +05:30
}
public getName(): string {
return "*️⃣ " + _t("composer|autocomplete|command_description");
}
public renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return (
<div
2021-08-25 18:38:20 +02:00
className="mx_Autocomplete_Completion_container_pill"
role="presentation"
aria-label={_t("composer|autocomplete|command_a11y")}
>
{completions}
</div>
);
}
2016-06-01 16:54:21 +05:30
}