~emersion/gamja

00eebc9859be03fb974449c785398e706cf6a14c — Simon Ser 4 months ago 08aefc9
composer: cycle through auto-completions

Closes: https://todo.sr.ht/~emersion/gamja/42
2 files changed, 57 insertions(+), 34 deletions(-)

M components/app.js
M components/composer.js
M components/app.js => components/app.js +4 -10
@@ 1007,13 1007,10 @@ export default class App extends Component {
	autocomplete(prefix) {
		function fromList(l, prefix) {
			prefix = prefix.toLowerCase();
			let repl = null;
			let repl = [];
			for (let item of l) {
				if (item.toLowerCase().startsWith(prefix)) {
					if (repl) {
						return null;
					}
					repl = item;
					repl.push(item);
				}
			}
			return repl;


@@ 1021,15 1018,12 @@ export default class App extends Component {

		if (prefix.startsWith("/")) {
			let repl = fromList(Object.keys(commands), prefix.slice(1));
			if (repl) {
				repl = "/" + repl;
			}
			return repl;
			return repl.map(cmd => "/" + cmd);
		}

		let buf = this.state.buffers.get(this.state.activeBuffer);
		if (!buf || !buf.members) {
			return null;
			return [];
		}
		return fromList(buf.members.keys(), prefix);
	}

M components/composer.js => components/composer.js +53 -24
@@ 5,6 5,7 @@ export default class Composer extends Component {
		text: "",
	};
	textInput = createRef();
	lastAutocomplete = null;

	constructor(props) {
		super(props);


@@ 42,48 43,76 @@ export default class Composer extends Component {

		event.preventDefault();

		let carretIndex = input.selectionStart;
		let carretPos = input.selectionStart;
		let text = this.state.text;
		let wordStart;
		for (wordStart = carretIndex - 1; wordStart >= 0; wordStart--) {
			if (text[wordStart] === " ") {
				break;
		let autocomplete;
		if (this.lastAutocomplete && this.lastAutocomplete.text === text && this.lastAutocomplete.carretPos === carretPos) {
			autocomplete = this.lastAutocomplete;
		} else {
			this.lastAutocomplete = null;

			let wordStart;
			for (wordStart = carretPos - 1; wordStart >= 0; wordStart--) {
				if (text[wordStart] === " ") {
					break;
				}
			}
		}
		wordStart++;
			wordStart++;

		let wordEnd;
		for (wordEnd = carretIndex; wordEnd < text.length; wordEnd++) {
			if (text[wordEnd] === " ") {
				break;
			let wordEnd;
			for (wordEnd = carretPos; wordEnd < text.length; wordEnd++) {
				if (text[wordEnd] === " ") {
					break;
				}
			}
		}

		let word = text.slice(wordStart, wordEnd);
		if (!word) {
			return;
			let word = text.slice(wordStart, wordEnd);
			if (!word) {
				return;
			}

			let replacements = this.props.autocomplete(word);
			if (replacements.length === 0) {
				return;
			}

			autocomplete = {
				text,
				carretPos: input.selectionStart,
				prefix: text.slice(0, wordStart),
				suffix: text.slice(wordEnd),
				replacements,
				replIndex: -1,
			};
		}

		let repl = this.props.autocomplete(word);
		if (!repl) {
			return;
		let n = autocomplete.replacements.length;
		if (event.shiftKey) {
			autocomplete.replIndex--;
		} else {
			autocomplete.replIndex++;
		}
		autocomplete.replIndex = (autocomplete.replIndex + n) % n;

		if (wordStart === 0 && wordEnd === text.length) {
			if (word.startsWith("/")) {
		let repl = autocomplete.replacements[autocomplete.replIndex];
		if (!autocomplete.prefix && !autocomplete.suffix) {
			if (repl.startsWith("/")) {
				repl += " ";
			} else {
				repl += ": ";
			}
		}

		text = text.slice(0, wordStart) + repl + text.slice(wordEnd);
		autocomplete.text = autocomplete.prefix + repl + autocomplete.suffix;
		autocomplete.carretPos = autocomplete.prefix.length + repl.length;

		input.value = text;
		input.selectionStart = wordStart + repl.length;
		input.value = autocomplete.text;
		input.selectionStart = autocomplete.carretPos;
		input.selectionEnd = input.selectionStart;

		this.setState({ text });
		this.lastAutocomplete = autocomplete;

		this.setState({ text: autocomplete.text });
	}

	handleWindowKeyDown(event) {