From 53f31e49dad440ae3bf87d6511d02c73139ecd05 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 13 Jan 2016 17:46:36 +0000 Subject: [PATCH] Implement tab-complete for slash commands This needed a new interface function `getOverrideSuffix()` so we didn't suffix commands at the start with ": ". All seems to work. --- src/SlashCommands.js | 6 +++++ src/TabComplete.js | 33 +++++++++++++++------------ src/TabCompleteEntries.js | 29 +++++++++++++++++++++++ src/components/structures/RoomView.js | 6 ++++- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 1dd7ecb08f..3de3943b9e 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -322,5 +322,11 @@ module.exports = { } } return null; // not a command + }, + + getCommandList: function() { + return Object.keys(commands).map(function(cmd) { + return "/" + cmd; + }); } }; diff --git a/src/TabComplete.js b/src/TabComplete.js index 6690802d5d..3b117ca689 100644 --- a/src/TabComplete.js +++ b/src/TabComplete.js @@ -58,7 +58,7 @@ class TabComplete { // assign onClick listeners for each entry to complete the text this.list.forEach((l) => { l.onClick = () => { - this.completeTo(l.getText()); + this.completeTo(l); } }); } @@ -93,10 +93,10 @@ class TabComplete { /** * Do an auto-complete with the given word. This terminates the tab-complete. - * @param {string} someVal + * @param {Entry} entry The tab-complete entry to complete to. */ - completeTo(someVal) { - this.textArea.value = this._replaceWith(someVal, true); + completeTo(entry) { + this.textArea.value = this._replaceWith(entry.getText(), true, entry.getOverrideSuffix()); this.stopTabCompleting(); // keep focus on the text area this.textArea.focus(); @@ -222,8 +222,9 @@ class TabComplete { if (!this.inPassiveMode) { // set textarea to this new value this.textArea.value = this._replaceWith( - this.matchedList[this.currentIndex].text, - this.currentIndex !== 0 // don't suffix the original text! + this.matchedList[this.currentIndex].getText(), + this.currentIndex !== 0, // don't suffix the original text! + this.matchedList[this.currentIndex].getOverrideSuffix() ); } @@ -243,7 +244,7 @@ class TabComplete { } } - _replaceWith(newVal, includeSuffix) { + _replaceWith(newVal, includeSuffix, overrideSuffix) { // The regex to replace the input matches a character of whitespace AND // the partial word. If we just use string.replace() with the regex it will // replace the partial word AND the character of whitespace. We want to @@ -258,13 +259,17 @@ class TabComplete { boundaryChar = ""; } - var replacementText = ( - boundaryChar + newVal + ( - includeSuffix ? - (this.isFirstWord ? this.opts.startingWordSuffix : this.opts.wordSuffix) : - "" - ) - ); + var suffix = ""; + if (includeSuffix) { + if (overrideSuffix) { + suffix = overrideSuffix; + } + else { + suffix = (this.isFirstWord ? this.opts.startingWordSuffix : this.opts.wordSuffix); + } + } + + var replacementText = boundaryChar + newVal + suffix; return this.originalText.replace(MATCH_REGEX, function() { return replacementText; // function form to avoid `$` special-casing }); diff --git a/src/TabCompleteEntries.js b/src/TabCompleteEntries.js index d3efc0d2f1..4b7fbc5d0e 100644 --- a/src/TabCompleteEntries.js +++ b/src/TabCompleteEntries.js @@ -42,6 +42,14 @@ class Entry { return null; } + /** + * @return {?string} The suffix to override whatever the default is, or null to + * not do this. + */ + getOverrideSuffix() { + return null; + } + /** * Called when this entry is clicked. */ @@ -50,6 +58,26 @@ class Entry { } } +class CommandEntry extends Entry { + constructor(command) { + super(command); + } + + getKey() { + return this.getText(); + } + + getOverrideSuffix() { + return " "; // force a space after the command. + } +} + +CommandEntry.fromStrings = function(commandArray) { + return commandArray.map(function(cmd) { + return new CommandEntry(cmd); + }); +} + class MemberEntry extends Entry { constructor(member) { super(member.name || member.userId); @@ -99,3 +127,4 @@ MemberEntry.fromMemberList = function(members) { module.exports.Entry = Entry; module.exports.MemberEntry = MemberEntry; +module.exports.CommandEntry = CommandEntry; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 8e193b25ab..bc6438a97c 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -35,7 +35,9 @@ var sdk = require('../../index'); var CallHandler = require('../../CallHandler'); var TabComplete = require("../../TabComplete"); var MemberEntry = require("../../TabCompleteEntries").MemberEntry; +var CommandEntry = require("../../TabCompleteEntries").CommandEntry; var Resend = require("../../Resend"); +var SlashCommands = require("../../SlashCommands"); var dis = require("../../dispatcher"); var Tinter = require("../../Tinter"); @@ -416,7 +418,9 @@ module.exports = React.createClass({ return; } this.tabComplete.setCompletionList( - MemberEntry.fromMemberList(room.getJoinedMembers()) + MemberEntry.fromMemberList(room.getJoinedMembers()).concat( + CommandEntry.fromStrings(SlashCommands.getCommandList()) + ) ); },