rework SlashCommands to better expose aliases
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>pull/21833/head
							parent
							
								
									117ea5dc76
								
							
						
					
					
						commit
						8c2b910c03
					
				|  | @ -2,6 +2,7 @@ | |||
| Copyright 2015, 2016 OpenMarket Ltd | ||||
| Copyright 2018 New Vector Ltd | ||||
| Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> | ||||
| Copyright 2020 The Matrix.org Foundation C.I.C. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
|  | @ -17,7 +18,8 @@ limitations under the License. | |||
| */ | ||||
| 
 | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import * as React from 'react'; | ||||
| 
 | ||||
| import {MatrixClientPeg} from './MatrixClientPeg'; | ||||
| import dis from './dispatcher'; | ||||
| import * as sdk from './index'; | ||||
|  | @ -34,11 +36,16 @@ import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/I | |||
| import {isPermalinkHost, parsePermalink} from "./utils/permalinks/Permalinks"; | ||||
| import {inviteUsersToRoom} from "./RoomInvite"; | ||||
| 
 | ||||
| const singleMxcUpload = async () => { | ||||
| // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
 | ||||
| interface HTMLInputEvent extends Event { | ||||
|     target: HTMLInputElement & EventTarget; | ||||
| } | ||||
| 
 | ||||
| const singleMxcUpload = async (): Promise<any> => { | ||||
|     return new Promise((resolve) => { | ||||
|         const fileSelector = document.createElement('input'); | ||||
|         fileSelector.setAttribute('type', 'file'); | ||||
|         fileSelector.onchange = (ev) => { | ||||
|         fileSelector.onchange = (ev: HTMLInputEvent) => { | ||||
|             const file = ev.target.files[0]; | ||||
| 
 | ||||
|             const UploadConfirmDialog = sdk.getComponent("dialogs.UploadConfirmDialog"); | ||||
|  | @ -62,9 +69,36 @@ export const CommandCategories = { | |||
|     "other": _td("Other"), | ||||
| }; | ||||
| 
 | ||||
| type RunFn = ((roomId: string, args: string, cmd: string) => {error: any} | {promise: Promise<any>}); | ||||
| 
 | ||||
| class Command { | ||||
|     constructor({name, args='', description, runFn, category=CommandCategories.other, hideCompletionAfterSpace=false}) { | ||||
|         this.command = '/' + name; | ||||
|     command: string; | ||||
|     aliases: string[]; | ||||
|     args: undefined | string; | ||||
|     description: string; | ||||
|     runFn: undefined | RunFn; | ||||
|     category: string; | ||||
|     hideCompletionAfterSpace: boolean; | ||||
| 
 | ||||
|     constructor({ | ||||
|         command, | ||||
|         aliases=[], | ||||
|         args='', | ||||
|         description, | ||||
|         runFn=undefined, | ||||
|         category=CommandCategories.other, | ||||
|         hideCompletionAfterSpace=false, | ||||
|     }: { | ||||
|         command: string; | ||||
|         aliases?: string[]; | ||||
|         args?: string; | ||||
|         description: string; | ||||
|         runFn?: RunFn; | ||||
|         category: string; | ||||
|         hideCompletionAfterSpace?: boolean; | ||||
|     }) { | ||||
|         this.command = command; | ||||
|         this.aliases = aliases; | ||||
|         this.args = args; | ||||
|         this.description = description; | ||||
|         this.runFn = runFn; | ||||
|  | @ -73,17 +107,17 @@ class Command { | |||
|     } | ||||
| 
 | ||||
|     getCommand() { | ||||
|         return this.command; | ||||
|         return `/${this.command}`; | ||||
|     } | ||||
| 
 | ||||
|     getCommandWithArgs() { | ||||
|         return this.getCommand() + " " + this.args; | ||||
|     } | ||||
| 
 | ||||
|     run(roomId, args) { | ||||
|     run(roomId: string, args: string, cmd: string) { | ||||
|         // if it has no runFn then its an ignored/nop command (autocomplete only) e.g `/me`
 | ||||
|         if (!this.runFn) return; | ||||
|         return this.runFn.bind(this)(roomId, args); | ||||
|         return this.runFn.bind(this)(roomId, args, cmd); | ||||
|     } | ||||
| 
 | ||||
|     getUsage() { | ||||
|  | @ -95,7 +129,7 @@ function reject(error) { | |||
|     return {error}; | ||||
| } | ||||
| 
 | ||||
| function success(promise) { | ||||
| function success(promise?: Promise<any>) { | ||||
|     return {promise}; | ||||
| } | ||||
| 
 | ||||
|  | @ -103,11 +137,9 @@ function success(promise) { | |||
|  * functions are called with `this` bound to the Command instance. | ||||
|  */ | ||||
| 
 | ||||
| /* eslint-disable babel/no-invalid-this */ | ||||
| 
 | ||||
| export const CommandMap = { | ||||
|     shrug: new Command({ | ||||
|         name: 'shrug', | ||||
| export const Commands = [ | ||||
|     new Command({ | ||||
|         command: 'shrug', | ||||
|         args: '<message>', | ||||
|         description: _td('Prepends ¯\\_(ツ)_/¯ to a plain-text message'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -119,8 +151,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.messages, | ||||
|     }), | ||||
|     plain: new Command({ | ||||
|         name: 'plain', | ||||
|     new Command({ | ||||
|         command: 'plain', | ||||
|         args: '<message>', | ||||
|         description: _td('Sends a message as plain text, without interpreting it as markdown'), | ||||
|         runFn: function(roomId, messages) { | ||||
|  | @ -128,11 +160,11 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.messages, | ||||
|     }), | ||||
|     ddg: new Command({ | ||||
|         name: 'ddg', | ||||
|     new Command({ | ||||
|         command: 'ddg', | ||||
|         args: '<query>', | ||||
|         description: _td('Searches DuckDuckGo for results'), | ||||
|         runFn: function(roomId, args) { | ||||
|         runFn: function() { | ||||
|             const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog'); | ||||
|             // TODO Don't explain this away, actually show a search UI here.
 | ||||
|             Modal.createTrackedDialog('Slash Commands', '/ddg is not a command', ErrorDialog, { | ||||
|  | @ -144,9 +176,8 @@ export const CommandMap = { | |||
|         category: CommandCategories.actions, | ||||
|         hideCompletionAfterSpace: true, | ||||
|     }), | ||||
| 
 | ||||
|     upgraderoom: new Command({ | ||||
|         name: 'upgraderoom', | ||||
|     new Command({ | ||||
|         command: 'upgraderoom', | ||||
|         args: '<new_version>', | ||||
|         description: _td('Upgrades a room to a new version'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -215,9 +246,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     nick: new Command({ | ||||
|         name: 'nick', | ||||
|     new Command({ | ||||
|         command: 'nick', | ||||
|         args: '<display_name>', | ||||
|         description: _td('Changes your display nickname'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -228,9 +258,9 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     myroomnick: new Command({ | ||||
|         name: 'myroomnick', | ||||
|     new Command({ | ||||
|         command: 'myroomnick', | ||||
|         aliases: ['roomnick'], | ||||
|         args: '<display_name>', | ||||
|         description: _td('Changes your display nickname in the current room only'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -239,7 +269,7 @@ export const CommandMap = { | |||
|                 const ev = cli.getRoom(roomId).currentState.getStateEvents('m.room.member', cli.getUserId()); | ||||
|                 const content = { | ||||
|                     ...ev ? ev.getContent() : { membership: 'join' }, | ||||
|                     displayname: args, | ||||
|                     displaycommand: args, | ||||
|                 }; | ||||
|                 return success(cli.sendStateEvent(roomId, 'm.room.member', content, cli.getUserId())); | ||||
|             } | ||||
|  | @ -247,9 +277,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     roomavatar: new Command({ | ||||
|         name: 'roomavatar', | ||||
|     new Command({ | ||||
|         command: 'roomavatar', | ||||
|         args: '[<mxc_url>]', | ||||
|         description: _td('Changes the avatar of the current room'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -265,9 +294,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     myroomavatar: new Command({ | ||||
|         name: 'myroomavatar', | ||||
|     new Command({ | ||||
|         command: 'myroomavatar', | ||||
|         args: '[<mxc_url>]', | ||||
|         description: _td('Changes your avatar in this current room only'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -292,9 +320,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     myavatar: new Command({ | ||||
|         name: 'myavatar', | ||||
|     new Command({ | ||||
|         command: 'myavatar', | ||||
|         args: '[<mxc_url>]', | ||||
|         description: _td('Changes your avatar in all rooms'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -310,9 +337,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     topic: new Command({ | ||||
|         name: 'topic', | ||||
|     new Command({ | ||||
|         command: 'topic', | ||||
|         args: '[<topic>]', | ||||
|         description: _td('Gets or sets the room topic'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -336,9 +362,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     roomname: new Command({ | ||||
|         name: 'roomname', | ||||
|     new Command({ | ||||
|         command: 'roomname', | ||||
|         args: '<name>', | ||||
|         description: _td('Sets the room name'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -349,9 +374,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     invite: new Command({ | ||||
|         name: 'invite', | ||||
|     new Command({ | ||||
|         command: 'invite', | ||||
|         args: '<user-id>', | ||||
|         description: _td('Invites user with given id to current room'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -390,7 +414,7 @@ export const CommandMap = { | |||
|                         } | ||||
|                     } | ||||
|                     const inviter = new MultiInviter(roomId); | ||||
|                     return success(finished.then(([useDefault] = []) => { | ||||
|                     return success(finished.then(([useDefault]: any) => { | ||||
|                         if (useDefault) { | ||||
|                             useDefaultIdentityServer(); | ||||
|                         } else if (useDefault === false) { | ||||
|  | @ -408,9 +432,9 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     join: new Command({ | ||||
|         name: 'join', | ||||
|     new Command({ | ||||
|         command: 'join', | ||||
|         aliases: ['j', 'goto'], | ||||
|         args: '<room-alias>', | ||||
|         description: _td('Joins room with given alias'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -521,9 +545,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     part: new Command({ | ||||
|         name: 'part', | ||||
|     new Command({ | ||||
|         command: 'part', | ||||
|         args: '[<room-alias>]', | ||||
|         description: _td('Leave room'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -569,9 +592,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     kick: new Command({ | ||||
|         name: 'kick', | ||||
|     new Command({ | ||||
|         command: 'kick', | ||||
|         args: '<user-id> [reason]', | ||||
|         description: _td('Kicks user with given id'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -585,10 +607,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     // Ban a user from the room with an optional reason
 | ||||
|     ban: new Command({ | ||||
|         name: 'ban', | ||||
|     new Command({ | ||||
|         command: 'ban', | ||||
|         args: '<user-id> [reason]', | ||||
|         description: _td('Bans user with given id'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -602,10 +622,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     // Unban a user from ythe room
 | ||||
|     unban: new Command({ | ||||
|         name: 'unban', | ||||
|     new Command({ | ||||
|         command: 'unban', | ||||
|         args: '<user-id>', | ||||
|         description: _td('Unbans user with given ID'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -620,9 +638,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     ignore: new Command({ | ||||
|         name: 'ignore', | ||||
|     new Command({ | ||||
|         command: 'ignore', | ||||
|         args: '<user-id>', | ||||
|         description: _td('Ignores a user, hiding their messages from you'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -651,9 +668,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     unignore: new Command({ | ||||
|         name: 'unignore', | ||||
|     new Command({ | ||||
|         command: 'unignore', | ||||
|         args: '<user-id>', | ||||
|         description: _td('Stops ignoring a user, showing their messages going forward'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -683,10 +699,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.actions, | ||||
|     }), | ||||
| 
 | ||||
|     // Define the power level of a user
 | ||||
|     op: new Command({ | ||||
|         name: 'op', | ||||
|     new Command({ | ||||
|         command: 'op', | ||||
|         args: '<user-id> [<power-level>]', | ||||
|         description: _td('Define the power level of a user'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -712,10 +726,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     // Reset the power level of a user
 | ||||
|     deop: new Command({ | ||||
|         name: 'deop', | ||||
|     new Command({ | ||||
|         command: 'deop', | ||||
|         args: '<user-id>', | ||||
|         description: _td('Deops user with given id'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -734,9 +746,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     devtools: new Command({ | ||||
|         name: 'devtools', | ||||
|     new Command({ | ||||
|         command: 'devtools', | ||||
|         description: _td('Opens the Developer Tools dialog'), | ||||
|         runFn: function(roomId) { | ||||
|             const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog'); | ||||
|  | @ -745,9 +756,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.advanced, | ||||
|     }), | ||||
| 
 | ||||
|     addwidget: new Command({ | ||||
|         name: 'addwidget', | ||||
|     new Command({ | ||||
|         command: 'addwidget', | ||||
|         args: '<url>', | ||||
|         description: _td('Adds a custom widget by URL to the room'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -766,10 +776,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.admin, | ||||
|     }), | ||||
| 
 | ||||
|     // Verify a user, device, and pubkey tuple
 | ||||
|     verify: new Command({ | ||||
|         name: 'verify', | ||||
|     new Command({ | ||||
|         command: 'verify', | ||||
|         args: '<user-id> <device-id> <device-signing-key>', | ||||
|         description: _td('Verifies a user, session, and pubkey tuple'), | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -834,20 +842,9 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.advanced, | ||||
|     }), | ||||
| 
 | ||||
|     // Command definitions for autocompletion ONLY:
 | ||||
| 
 | ||||
|     // /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes
 | ||||
|     me: new Command({ | ||||
|         name: 'me', | ||||
|         args: '<message>', | ||||
|         description: _td('Displays action'), | ||||
|         category: CommandCategories.messages, | ||||
|         hideCompletionAfterSpace: true, | ||||
|     }), | ||||
| 
 | ||||
|     discardsession: new Command({ | ||||
|         name: 'discardsession', | ||||
|     new Command({ | ||||
|         command: 'discardsession', | ||||
|         aliases: ['newballsplease'], | ||||
|         description: _td('Forces the current outbound group session in an encrypted room to be discarded'), | ||||
|         runFn: function(roomId) { | ||||
|             try { | ||||
|  | @ -859,9 +856,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.advanced, | ||||
|     }), | ||||
| 
 | ||||
|     rainbow: new Command({ | ||||
|         name: "rainbow", | ||||
|     new Command({ | ||||
|         command: "rainbow", | ||||
|         description: _td("Sends the given message coloured as a rainbow"), | ||||
|         args: '<message>', | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -870,9 +866,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.messages, | ||||
|     }), | ||||
| 
 | ||||
|     rainbowme: new Command({ | ||||
|         name: "rainbowme", | ||||
|     new Command({ | ||||
|         command: "rainbowme", | ||||
|         description: _td("Sends the given emote coloured as a rainbow"), | ||||
|         args: '<message>', | ||||
|         runFn: function(roomId, args) { | ||||
|  | @ -881,9 +876,8 @@ export const CommandMap = { | |||
|         }, | ||||
|         category: CommandCategories.messages, | ||||
|     }), | ||||
| 
 | ||||
|     help: new Command({ | ||||
|         name: "help", | ||||
|     new Command({ | ||||
|         command: "help", | ||||
|         description: _td("Displays list of commands with usages and descriptions"), | ||||
|         runFn: function() { | ||||
|             const SlashCommandHelpDialog = sdk.getComponent('dialogs.SlashCommandHelpDialog'); | ||||
|  | @ -894,36 +888,25 @@ export const CommandMap = { | |||
|         category: CommandCategories.advanced, | ||||
|     }), | ||||
| 
 | ||||
|     whois: new Command({ | ||||
|         name: "whois", | ||||
|         description: _td("Displays information about a user"), | ||||
|         args: '<user-id>', | ||||
|         runFn: function(roomId, userId) { | ||||
|             if (!userId || !userId.startsWith("@") || !userId.includes(":")) { | ||||
|                 return reject(this.getUsage()); | ||||
|             } | ||||
| 
 | ||||
|             const member = MatrixClientPeg.get().getRoom(roomId).getMember(userId); | ||||
| 
 | ||||
|             dis.dispatch({ | ||||
|                 action: 'view_user', | ||||
|                 member: member || {userId}, | ||||
|             }); | ||||
|             return success(); | ||||
|         }, | ||||
|         category: CommandCategories.advanced, | ||||
|     // Command definitions for autocompletion ONLY:
 | ||||
|     // /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes
 | ||||
|     new Command({ | ||||
|         command: 'me', | ||||
|         args: '<message>', | ||||
|         description: _td('Displays action'), | ||||
|         category: CommandCategories.messages, | ||||
|         hideCompletionAfterSpace: true, | ||||
|     }), | ||||
| }; | ||||
| /* eslint-enable babel/no-invalid-this */ | ||||
| ]; | ||||
| 
 | ||||
| 
 | ||||
| // helpful aliases
 | ||||
| const aliases = { | ||||
|     j: "join", | ||||
|     newballsplease: "discardsession", | ||||
|     goto: "join", // because it handles event permalinks magically
 | ||||
|     roomnick: "myroomnick", | ||||
| }; | ||||
| // build a map from names and aliases to the Command objects.
 | ||||
| export const CommandMap = new Map(); | ||||
| Commands.forEach(cmd => { | ||||
|     CommandMap.set(cmd.command, cmd); | ||||
|     cmd.aliases.forEach(alias => { | ||||
|         CommandMap.set(alias, cmd); | ||||
|     }); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  | @ -950,10 +933,7 @@ export function getCommand(roomId, input) { | |||
|         cmd = input; | ||||
|     } | ||||
| 
 | ||||
|     if (aliases[cmd]) { | ||||
|         cmd = aliases[cmd]; | ||||
|     } | ||||
|     if (CommandMap[cmd]) { | ||||
|         return () => CommandMap[cmd].run(roomId, args); | ||||
|     if (CommandMap.has(cmd)) { | ||||
|         return () => CommandMap.get(cmd).run(roomId, args, cmd); | ||||
|     } | ||||
| } | ||||
|  | @ -23,17 +23,16 @@ import AutocompleteProvider from './AutocompleteProvider'; | |||
| import QueryMatcher from './QueryMatcher'; | ||||
| import {TextualCompletion} from './Components'; | ||||
| import type {Completion, SelectionRange} from "./Autocompleter"; | ||||
| import {CommandMap} from '../SlashCommands'; | ||||
| 
 | ||||
| const COMMANDS = Object.values(CommandMap); | ||||
| import {Commands, CommandMap} from '../SlashCommands'; | ||||
| 
 | ||||
| const COMMAND_RE = /(^\/\w*)(?: .*)?/g; | ||||
| 
 | ||||
| export default class CommandProvider extends AutocompleteProvider { | ||||
|     constructor() { | ||||
|         super(COMMAND_RE); | ||||
|         this.matcher = new QueryMatcher(COMMANDS, { | ||||
|            keys: ['command', 'args', 'description'], | ||||
|         this.matcher = new QueryMatcher(Commands, { | ||||
|             keys: ['command', 'args', 'description'], | ||||
|             funcs: [({aliases}) => aliases.join(" ")], // aliases
 | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | @ -46,31 +45,40 @@ export default class CommandProvider extends AutocompleteProvider { | |||
|         if (command[0] !== command[1]) { | ||||
|             // The input looks like a command with arguments, perform exact match
 | ||||
|             const name = command[1].substr(1); // strip leading `/`
 | ||||
|             if (CommandMap[name]) { | ||||
|             if (CommandMap.has(name)) { | ||||
|                 // some commands, namely `me` and `ddg` don't suit having the usage shown whilst typing their arguments
 | ||||
|                 if (CommandMap[name].hideCompletionAfterSpace) return []; | ||||
|                 matches = [CommandMap[name]]; | ||||
|                 if (CommandMap.get(name).hideCompletionAfterSpace) return []; | ||||
|                 matches = [CommandMap.get(name)]; | ||||
|             } | ||||
|         } else { | ||||
|             if (query === '/') { | ||||
|                 // If they have just entered `/` show everything
 | ||||
|                 matches = COMMANDS; | ||||
|                 matches = Commands; | ||||
|             } else { | ||||
|                 // otherwise fuzzy match against all of the fields
 | ||||
|                 matches = this.matcher.match(command[1]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return matches.map((result) => ({ | ||||
|             // If the command is the same as the one they entered, we don't want to discard their arguments
 | ||||
|             completion: result.command === command[1] ? command[0] : (result.command + ' '), | ||||
|             type: "command", | ||||
|             component: <TextualCompletion | ||||
|                 title={result.command} | ||||
|                 subtitle={result.args} | ||||
|                 description={_t(result.description)} />, | ||||
|             range, | ||||
|         })); | ||||
| 
 | ||||
|         return matches.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, | ||||
|             }; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     getName() { | ||||
|  |  | |||
|  | @ -16,14 +16,14 @@ limitations under the License. | |||
| 
 | ||||
| import React from 'react'; | ||||
| import {_t} from "../../../languageHandler"; | ||||
| import {CommandCategories, CommandMap} from "../../../SlashCommands"; | ||||
| import {CommandCategories, Commands} from "../../../SlashCommands"; | ||||
| import * as sdk from "../../../index"; | ||||
| 
 | ||||
| export default ({onFinished}) => { | ||||
|     const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); | ||||
| 
 | ||||
|     const categories = {}; | ||||
|     Object.values(CommandMap).forEach(cmd => { | ||||
|     Commands.forEach(cmd => { | ||||
|         if (!categories[cmd.category]) { | ||||
|             categories[cmd.category] = []; | ||||
|         } | ||||
|  | @ -41,7 +41,7 @@ export default ({onFinished}) => { | |||
| 
 | ||||
|         categories[category].forEach(cmd => { | ||||
|             rows.push(<tr key={cmd.command}> | ||||
|                 <td><strong>{cmd.command}</strong></td> | ||||
|                 <td><strong>{cmd.getCommand()}</strong></td> | ||||
|                 <td>{cmd.args}</td> | ||||
|                 <td>{cmd.description}</td> | ||||
|             </tr>); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Michael Telatynski
						Michael Telatynski