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.
pull/21833/head
Kegan Dougal 2016-01-13 17:46:36 +00:00
parent 11025e2ba9
commit 53f31e49da
4 changed files with 59 additions and 15 deletions

View File

@ -322,5 +322,11 @@ module.exports = {
} }
} }
return null; // not a command return null; // not a command
},
getCommandList: function() {
return Object.keys(commands).map(function(cmd) {
return "/" + cmd;
});
} }
}; };

View File

@ -58,7 +58,7 @@ class TabComplete {
// assign onClick listeners for each entry to complete the text // assign onClick listeners for each entry to complete the text
this.list.forEach((l) => { this.list.forEach((l) => {
l.onClick = () => { 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. * 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) { completeTo(entry) {
this.textArea.value = this._replaceWith(someVal, true); this.textArea.value = this._replaceWith(entry.getText(), true, entry.getOverrideSuffix());
this.stopTabCompleting(); this.stopTabCompleting();
// keep focus on the text area // keep focus on the text area
this.textArea.focus(); this.textArea.focus();
@ -222,8 +222,9 @@ class TabComplete {
if (!this.inPassiveMode) { if (!this.inPassiveMode) {
// set textarea to this new value // set textarea to this new value
this.textArea.value = this._replaceWith( this.textArea.value = this._replaceWith(
this.matchedList[this.currentIndex].text, this.matchedList[this.currentIndex].getText(),
this.currentIndex !== 0 // don't suffix the original text! 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 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 // 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 // replace the partial word AND the character of whitespace. We want to
@ -258,13 +259,17 @@ class TabComplete {
boundaryChar = ""; boundaryChar = "";
} }
var replacementText = ( var suffix = "";
boundaryChar + newVal + ( if (includeSuffix) {
includeSuffix ? if (overrideSuffix) {
(this.isFirstWord ? this.opts.startingWordSuffix : this.opts.wordSuffix) : 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 this.originalText.replace(MATCH_REGEX, function() {
return replacementText; // function form to avoid `$` special-casing return replacementText; // function form to avoid `$` special-casing
}); });

View File

@ -42,6 +42,14 @@ class Entry {
return null; 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. * 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 { class MemberEntry extends Entry {
constructor(member) { constructor(member) {
super(member.name || member.userId); super(member.name || member.userId);
@ -99,3 +127,4 @@ MemberEntry.fromMemberList = function(members) {
module.exports.Entry = Entry; module.exports.Entry = Entry;
module.exports.MemberEntry = MemberEntry; module.exports.MemberEntry = MemberEntry;
module.exports.CommandEntry = CommandEntry;

View File

@ -35,7 +35,9 @@ var sdk = require('../../index');
var CallHandler = require('../../CallHandler'); var CallHandler = require('../../CallHandler');
var TabComplete = require("../../TabComplete"); var TabComplete = require("../../TabComplete");
var MemberEntry = require("../../TabCompleteEntries").MemberEntry; var MemberEntry = require("../../TabCompleteEntries").MemberEntry;
var CommandEntry = require("../../TabCompleteEntries").CommandEntry;
var Resend = require("../../Resend"); var Resend = require("../../Resend");
var SlashCommands = require("../../SlashCommands");
var dis = require("../../dispatcher"); var dis = require("../../dispatcher");
var Tinter = require("../../Tinter"); var Tinter = require("../../Tinter");
@ -416,7 +418,9 @@ module.exports = React.createClass({
return; return;
} }
this.tabComplete.setCompletionList( this.tabComplete.setCompletionList(
MemberEntry.fromMemberList(room.getJoinedMembers()) MemberEntry.fromMemberList(room.getJoinedMembers()).concat(
CommandEntry.fromStrings(SlashCommands.getCommandList())
)
); );
}, },