forked from CringeStudios/gamja
composer: cycle through auto-completions
Closes: https://todo.sr.ht/~emersion/gamja/42
This commit is contained in:
parent
08aefc9dc5
commit
00eebc9859
@ -1007,13 +1007,10 @@ export default class App extends Component {
|
|||||||
autocomplete(prefix) {
|
autocomplete(prefix) {
|
||||||
function fromList(l, prefix) {
|
function fromList(l, prefix) {
|
||||||
prefix = prefix.toLowerCase();
|
prefix = prefix.toLowerCase();
|
||||||
let repl = null;
|
let repl = [];
|
||||||
for (let item of l) {
|
for (let item of l) {
|
||||||
if (item.toLowerCase().startsWith(prefix)) {
|
if (item.toLowerCase().startsWith(prefix)) {
|
||||||
if (repl) {
|
repl.push(item);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
repl = item;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return repl;
|
return repl;
|
||||||
@ -1021,15 +1018,12 @@ export default class App extends Component {
|
|||||||
|
|
||||||
if (prefix.startsWith("/")) {
|
if (prefix.startsWith("/")) {
|
||||||
let repl = fromList(Object.keys(commands), prefix.slice(1));
|
let repl = fromList(Object.keys(commands), prefix.slice(1));
|
||||||
if (repl) {
|
return repl.map(cmd => "/" + cmd);
|
||||||
repl = "/" + repl;
|
|
||||||
}
|
|
||||||
return repl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let buf = this.state.buffers.get(this.state.activeBuffer);
|
let buf = this.state.buffers.get(this.state.activeBuffer);
|
||||||
if (!buf || !buf.members) {
|
if (!buf || !buf.members) {
|
||||||
return null;
|
return [];
|
||||||
}
|
}
|
||||||
return fromList(buf.members.keys(), prefix);
|
return fromList(buf.members.keys(), prefix);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ export default class Composer extends Component {
|
|||||||
text: "",
|
text: "",
|
||||||
};
|
};
|
||||||
textInput = createRef();
|
textInput = createRef();
|
||||||
|
lastAutocomplete = null;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -42,48 +43,76 @@ export default class Composer extends Component {
|
|||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
let carretIndex = input.selectionStart;
|
let carretPos = input.selectionStart;
|
||||||
let text = this.state.text;
|
let text = this.state.text;
|
||||||
let wordStart;
|
let autocomplete;
|
||||||
for (wordStart = carretIndex - 1; wordStart >= 0; wordStart--) {
|
if (this.lastAutocomplete && this.lastAutocomplete.text === text && this.lastAutocomplete.carretPos === carretPos) {
|
||||||
if (text[wordStart] === " ") {
|
autocomplete = this.lastAutocomplete;
|
||||||
break;
|
} else {
|
||||||
|
this.lastAutocomplete = null;
|
||||||
|
|
||||||
|
let wordStart;
|
||||||
|
for (wordStart = carretPos - 1; wordStart >= 0; wordStart--) {
|
||||||
|
if (text[wordStart] === " ") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
wordStart++;
|
||||||
wordStart++;
|
|
||||||
|
|
||||||
let wordEnd;
|
let wordEnd;
|
||||||
for (wordEnd = carretIndex; wordEnd < text.length; wordEnd++) {
|
for (wordEnd = carretPos; wordEnd < text.length; wordEnd++) {
|
||||||
if (text[wordEnd] === " ") {
|
if (text[wordEnd] === " ") {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 word = text.slice(wordStart, wordEnd);
|
let n = autocomplete.replacements.length;
|
||||||
if (!word) {
|
if (event.shiftKey) {
|
||||||
return;
|
autocomplete.replIndex--;
|
||||||
|
} else {
|
||||||
|
autocomplete.replIndex++;
|
||||||
}
|
}
|
||||||
|
autocomplete.replIndex = (autocomplete.replIndex + n) % n;
|
||||||
|
|
||||||
let repl = this.props.autocomplete(word);
|
let repl = autocomplete.replacements[autocomplete.replIndex];
|
||||||
if (!repl) {
|
if (!autocomplete.prefix && !autocomplete.suffix) {
|
||||||
return;
|
if (repl.startsWith("/")) {
|
||||||
}
|
|
||||||
|
|
||||||
if (wordStart === 0 && wordEnd === text.length) {
|
|
||||||
if (word.startsWith("/")) {
|
|
||||||
repl += " ";
|
repl += " ";
|
||||||
} else {
|
} else {
|
||||||
repl += ": ";
|
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.value = autocomplete.text;
|
||||||
input.selectionStart = wordStart + repl.length;
|
input.selectionStart = autocomplete.carretPos;
|
||||||
input.selectionEnd = input.selectionStart;
|
input.selectionEnd = input.selectionStart;
|
||||||
|
|
||||||
this.setState({ text });
|
this.lastAutocomplete = autocomplete;
|
||||||
|
|
||||||
|
this.setState({ text: autocomplete.text });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleWindowKeyDown(event) {
|
handleWindowKeyDown(event) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user