commit e183a5eb4b45ce2f0a066a4e3685052b614dbf69
parent 67ac8aab3fe3baea695c15768a3765f229b41453
Author: Matthew Horan <matt@matthoran.com>
Date: Mon, 21 Jan 2019 17:58:46 -0500
Improve nick tab completion
This is pretty much a direct port from weechat-android.
* Only add : suffix when completed nick is at the beginning of the line.
* Cycle through all matching nicks until user enters additional text.
* Nicks can be completed in the middle of a sentence.
Closes #1, closes #2
Diffstat:
1 file changed, 58 insertions(+), 13 deletions(-)
diff --git a/src/usecase/buffers/ui/BufferContainer.tsx b/src/usecase/buffers/ui/BufferContainer.tsx
@@ -40,14 +40,25 @@ interface Props {
interface State {
showTabButton: boolean;
textValue: string;
+ selection: {start: number, end: number};
}
class BufferContainer extends React.Component<Props, State> {
state = {
showTabButton: false,
- textValue: ""
+ textValue: "",
+ selection: {
+ start: 0,
+ end: 0
+ }
};
+ tabCompleteInProgress = false;
+ tabCompleteMatches: WeechatNicklist[];
+ tabCompleteIndex = 0;
+ tabCompleteWordStart = 0;
+ tabCompleteWordEnd = 0;
+
parseArgs = getParseArgs(
styles.link,
this.handleOnPress,
@@ -86,6 +97,7 @@ class BufferContainer extends React.Component<Props, State> {
}
handleChangeText = (textValue: string) => {
+ this.tabCompleteInProgress = false;
this.setState({
textValue
});
@@ -100,28 +112,59 @@ class BufferContainer extends React.Component<Props, State> {
};
tabCompleteNick = () => {
- const tokens = this.state.textValue.split(" ");
- const lastIndex = tokens.length - 1;
- const nickcomplete = tokens[lastIndex].toLowerCase();
+ const { textValue, selection } = this.state;
+ const { nicklist } = this.props;
- const alternatives = this.props.nicklist.filter(nick =>
- nick.name.toLowerCase().startsWith(nickcomplete)
- );
+ if (!this.tabCompleteInProgress) {
+ this.tabCompleteWordEnd = selection.start;
+
+ this.tabCompleteWordStart = this.tabCompleteWordEnd;
+ while (this.tabCompleteWordStart > 0 &&
+ textValue.charAt(this.tabCompleteWordStart - 1) != ' ') {
+ this.tabCompleteWordStart--;
+ }
+
+ if (this.tabCompleteWordStart == this.tabCompleteWordEnd)
+ return;
+
+ const prefix = textValue.substring(this.tabCompleteWordStart,
+ this.tabCompleteWordEnd).toLowerCase();
+
+ this.tabCompleteMatches = nicklist.filter(nick =>
+ nick.name.toLowerCase().startsWith(prefix)
+ );
+ if (this.tabCompleteMatches.length == 0) {
+ return;
+ }
- if (alternatives[0]) {
- tokens[lastIndex] = alternatives[0].name + ": ";
+ this.tabCompleteIndex = 0;
+ } else {
+ this.tabCompleteIndex = (this.tabCompleteIndex + 1) %
+ this.tabCompleteMatches.length;
+ }
- this.setState({
- textValue: tokens.join(" ")
- });
+ let nick = this.tabCompleteMatches[this.tabCompleteIndex].name;
+ if (this.tabCompleteWordStart == 0) {
+ nick += ": ";
}
+
+ this.setState({
+ textValue: textValue.substring(0, this.tabCompleteWordStart) +
+ nick + textValue.substring(this.tabCompleteWordEnd)
+ });
+ this.tabCompleteWordEnd = this.tabCompleteWordStart + nick.length;
+ this.tabCompleteInProgress = true;
};
+ handleSelectionChange = ({ nativeEvent: { selection } }) => {
+ this.setState({ selection })
+ }
+
onLongPress = () => {};
render() {
const { bufferId, buffer, showTopic, lines } = this.props;
- const { textValue, showTabButton } = this.state;
+ const { textValue, showTabButton, selection } = this.state;
if (!bufferId) {
return <View style={styles.container} />;
@@ -151,6 +194,8 @@ class BufferContainer extends React.Component<Props, State> {
onChangeText={this.handleChangeText}
onFocus={() => this.handleOnFocus()}
onBlur={() => this.handleOnBlur()}
+ selection={selection}
+ onSelectionChange={this.handleSelectionChange}
returnKeyType="send"
blurOnSubmit={false}
onSubmitEditing={this.handleSubmit}