weechatRN

Weechat relay client for iOS using websockets https://github.com/mhoran/weechatRN
git clone http://git.hanabi.in/repos/weechatRN.git
Log | Files | Refs | README | LICENSE

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:
Msrc/usecase/buffers/ui/BufferContainer.tsx | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
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}