From b67131f0c83fd5da063d77512e784008b02509b7 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 14 Jan 2016 14:39:58 +0000 Subject: [PATCH] Add a Command class; add Entry.getFillText() getFillText() serves to decouple the text displayed in the auto-complete list via getText() and the text actually filled into the box via getFillText(). This allows us to display command + args on the list but only fill the command part. A Command class has been added to provide some structure when extracting the command name and args. Manually tested and it works. --- src/SlashCommands.js | 104 +++++++++++------- src/TabComplete.js | 4 +- src/TabCompleteEntries.js | 23 +++- src/components/structures/RoomView.js | 2 +- src/components/views/rooms/MessageComposer.js | 2 +- 5 files changed, 86 insertions(+), 49 deletions(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 3de3943b9e..83b4b52ffc 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -20,6 +20,31 @@ var dis = require("./dispatcher"); var encryption = require("./encryption"); var Tinter = require("./Tinter"); + +class Command { + constructor(name, paramArgs, runFn) { + this.name = name; + this.paramArgs = paramArgs; + this.runFn = runFn; + } + + getCommand() { + return "/" + this.name; + } + + getCommandWithArgs() { + return this.getCommand() + " " + this.paramArgs; + } + + run(roomId, args) { + return this.runFn.bind(this)(roomId, args); + } + + getUsage() { + return "Usage: " + this.getCommandWithArgs() + } +} + var reject = function(msg) { return { error: msg @@ -34,18 +59,17 @@ var success = function(promise) { var commands = { // Change your nickname - nick: function(room_id, args) { + nick: new Command("nick", "", function(room_id, args) { if (args) { return success( MatrixClientPeg.get().setDisplayName(args) ); } - return reject("Usage: /nick "); - }, + return reject(this.getUsage()); + }), // Changes the colorscheme of your current room - tint: function(room_id, args) { - + tint: new Command("tint", " []", function(room_id, args) { if (args) { var matches = args.match(/^(#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}))( +(#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})))?$/); if (matches) { @@ -62,10 +86,10 @@ var commands = { ); } } - return reject("Usage: /tint []"); - }, + return reject(this.getUsage()); + }), - encrypt: function(room_id, args) { + encrypt: new Command("encrypt", "", function(room_id, args) { if (args == "on") { var client = MatrixClientPeg.get(); var members = client.getRoom(room_id).currentState.members; @@ -81,21 +105,21 @@ var commands = { ); } - return reject("Usage: encrypt "); - }, + return reject(this.getUsage()); + }), // Change the room topic - topic: function(room_id, args) { + topic: new Command("topic", "", function(room_id, args) { if (args) { return success( MatrixClientPeg.get().setRoomTopic(room_id, args) ); } - return reject("Usage: /topic "); - }, + return reject(this.getUsage()); + }), // Invite a user - invite: function(room_id, args) { + invite: new Command("invite", "", function(room_id, args) { if (args) { var matches = args.match(/^(\S+)$/); if (matches) { @@ -104,11 +128,11 @@ var commands = { ); } } - return reject("Usage: /invite "); - }, + return reject(this.getUsage()); + }), // Join a room - join: function(room_id, args) { + join: new Command("join", "", function(room_id, args) { if (args) { var matches = args.match(/^(\S+)$/); if (matches) { @@ -151,17 +175,17 @@ var commands = { ); } } - return reject("Usage: /join "); - }, + return reject(this.getUsage()); + }), - part: function(room_id, args) { + part: new Command("part", "[#alias:domain]", function(room_id, args) { var targetRoomId; if (args) { var matches = args.match(/^(\S+)$/); if (matches) { var room_alias = matches[1]; if (room_alias[0] !== '#') { - return reject("Usage: /part [#alias:domain]"); + return reject(this.getUsage()); } if (!room_alias.match(/:/)) { var domain = MatrixClientPeg.get().credentials.userId.replace(/^.*:/, ''); @@ -198,10 +222,10 @@ var commands = { dis.dispatch({action: 'view_next_room'}); }) ); - }, + }), // Kick a user from the room with an optional reason - kick: function(room_id, args) { + kick: new Command("kick", " []", function(room_id, args) { if (args) { var matches = args.match(/^(\S+?)( +(.*))?$/); if (matches) { @@ -210,11 +234,11 @@ var commands = { ); } } - return reject("Usage: /kick []"); - }, + return reject(this.getUsage()); + }), // Ban a user from the room with an optional reason - ban: function(room_id, args) { + ban: new Command("ban", " []", function(room_id, args) { if (args) { var matches = args.match(/^(\S+?)( +(.*))?$/); if (matches) { @@ -223,11 +247,11 @@ var commands = { ); } } - return reject("Usage: /ban []"); - }, + return reject(this.getUsage()); + }), // Unban a user from the room - unban: function(room_id, args) { + unban: new Command("unban", "", function(room_id, args) { if (args) { var matches = args.match(/^(\S+)$/); if (matches) { @@ -237,11 +261,11 @@ var commands = { ); } } - return reject("Usage: /unban "); - }, + return reject(this.getUsage()); + }), // Define the power level of a user - op: function(room_id, args) { + op: new Command("op", " []", function(room_id, args) { if (args) { var matches = args.match(/^(\S+?)( +(\d+))?$/); var powerLevel = 50; // default power level for op @@ -266,11 +290,11 @@ var commands = { } } } - return reject("Usage: /op []"); - }, + return reject(this.getUsage()); + }), // Reset the power level of a user - deop: function(room_id, args) { + deop: new Command("deop", "", function(room_id, args) { if (args) { var matches = args.match(/^(\S+)$/); if (matches) { @@ -289,8 +313,8 @@ var commands = { ); } } - return reject("Usage: /deop "); - } + return reject(this.getUsage()); + }) }; // helpful aliases @@ -315,7 +339,7 @@ module.exports = { var args = bits[3]; if (cmd === "me") return null; if (commands[cmd]) { - return commands[cmd](roomId, args); + return commands[cmd].run(roomId, args); } else { return reject("Unrecognised command: " + input); @@ -325,8 +349,8 @@ module.exports = { }, getCommandList: function() { - return Object.keys(commands).map(function(cmd) { - return "/" + cmd; + return Object.keys(commands).map(function(cmdKey) { + return commands[cmdKey]; }); } }; diff --git a/src/TabComplete.js b/src/TabComplete.js index 59f3cec3a0..8886e21af9 100644 --- a/src/TabComplete.js +++ b/src/TabComplete.js @@ -95,7 +95,7 @@ class TabComplete { */ completeTo(entry) { this.textArea.value = this._replaceWith( - entry.getText(), true, entry.getSuffix(this.isFirstWord) + entry.getFillText(), true, entry.getSuffix(this.isFirstWord) ); this.stopTabCompleting(); // keep focus on the text area @@ -222,7 +222,7 @@ class TabComplete { if (!this.inPassiveMode) { // set textarea to this new value this.textArea.value = this._replaceWith( - this.matchedList[this.currentIndex].getText(), + this.matchedList[this.currentIndex].getFillText(), this.currentIndex !== 0, // don't suffix the original text! this.matchedList[this.currentIndex].getSuffix(this.isFirstWord) ); diff --git a/src/TabCompleteEntries.js b/src/TabCompleteEntries.js index 79e0a9a46b..9aef7736a8 100644 --- a/src/TabCompleteEntries.js +++ b/src/TabCompleteEntries.js @@ -28,6 +28,14 @@ class Entry { return this.text; } + /** + * @return {string} The text to insert into the input box. Most of the time + * this is the same as getText(). + */ + getFillText() { + return this.text; + } + /** * @return {ReactClass} Raw JSX */ @@ -59,12 +67,17 @@ class Entry { } class CommandEntry extends Entry { - constructor(command) { - super(command); + constructor(cmd, cmdWithArgs) { + super(cmdWithArgs); + this.cmd = cmd; + } + + getFillText() { + return this.cmd; } getKey() { - return this.getText(); + return this.getFillText(); } getSuffix(isFirstWord) { @@ -72,9 +85,9 @@ class CommandEntry extends Entry { } } -CommandEntry.fromStrings = function(commandArray) { +CommandEntry.fromCommands = function(commandArray) { return commandArray.map(function(cmd) { - return new CommandEntry(cmd); + return new CommandEntry(cmd.getCommand(), cmd.getCommandWithArgs()); }); } diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index abfa2e27f1..6f5f9a97a3 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -417,7 +417,7 @@ module.exports = React.createClass({ } this.tabComplete.setCompletionList( MemberEntry.fromMemberList(room.getJoinedMembers()).concat( - CommandEntry.fromStrings(SlashCommands.getCommandList()) + CommandEntry.fromCommands(SlashCommands.getCommandList()) ) ); }, diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index a3ad033acc..930725570b 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -341,7 +341,7 @@ module.exports = React.createClass({ MatrixClientPeg.get().sendTextMessage(this.props.room.roomId, contentText); } - sendMessagePromise.then(function() { + sendMessagePromise.done(function() { dis.dispatch({ action: 'message_sent' });