Skip to content

Commit 94d68a7

Browse files
authoredNov 30, 2023
fix: stop rendering the completion popup disconnected from the editor for long ghost text (#5401)
Currently, when ghost text extends beyond the border of the editor, the autocomplete popup can be rendered disconnected from the editor:
1 parent b0ee067 commit 94d68a7

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed
 

‎src/autocomplete.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,15 @@ class Autocomplete {
231231
}
232232
}
233233

234+
// posGhostText can be below the editor rendering the popup away from the editor.
235+
// In this case, we want to render the popup such that the top aligns with the bottom of the editor.
236+
var editorContainerBottom = editor.container.getBoundingClientRect().bottom - lineHeight;
237+
var lowestPosition = editorContainerBottom < posGhostText.top ?
238+
{top: editorContainerBottom, left: posGhostText.left} :
239+
posGhostText;
240+
234241
// Try to render below ghost text, then above ghost text, then over ghost text
235-
if (this.popup.tryShow(posGhostText, lineHeight, "bottom")) {
242+
if (this.popup.tryShow(lowestPosition, lineHeight, "bottom")) {
236243
return;
237244
}
238245

‎src/autocomplete_test.js

+85-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ function initEditor(value) {
3333
}
3434
editor = ace.edit(null, {
3535
value: value,
36+
minLines: 10,
3637
maxLines: 10,
3738
enableBasicAutocompletion: true,
3839
enableLiveAutocompletion: true
@@ -57,7 +58,7 @@ module.exports = {
5758
editor.container.remove();
5859
editor = null;
5960
}
60-
},
61+
},/*
6162
"test: highlighting in the popup": function (done) {
6263
var editor = initEditor("\narraysort alooooooooooooooooooooooooooooong_word");
6364
// editor.container.style.width = "500px";
@@ -1123,6 +1124,89 @@ module.exports = {
11231124
function isLoading() {
11241125
return completer.popup.renderer.container.classList.contains("ace_loading");
11251126
}
1127+
},*/
1128+
"test: if there is very long ghost text, popup should be rendered at the bottom of the editor container": function(done) {
1129+
var editor = initEditor("hello world\n");
1130+
1131+
// Give enough space for the popup to appear below the editor
1132+
var initialDocumentHeight = document.body.style.height;
1133+
document.body.style.height = editor.container.getBoundingClientRect().height + 200 + "px";
1134+
editor.renderer.$loop._flush();
1135+
1136+
var longCompleter = {
1137+
getCompletions: function (editor, session, pos, prefix, callback) {
1138+
var completions = [
1139+
{
1140+
caption: "loooooong",
1141+
value: "line\n".repeat(20),
1142+
score: 0
1143+
}
1144+
];
1145+
callback(null, completions);
1146+
}
1147+
};
1148+
1149+
editor.completers = [longCompleter];
1150+
1151+
var completer = Autocomplete.for(editor);
1152+
completer.inlineEnabled = true;
1153+
1154+
user.type("Ctrl-Space");
1155+
assert.ok(completer.popup && completer.popup.isOpen);
1156+
1157+
// Wait to account for the renderer scrolling for the virtual renderer
1158+
setTimeout(() => {
1159+
completer.popup.renderer.$loop._flush();
1160+
1161+
// Popup should start one pixel below the bottom of the editor container
1162+
assert.equal(
1163+
completer.popup.container.getBoundingClientRect().top,
1164+
editor.container.getBoundingClientRect().bottom + 1
1165+
);
1166+
1167+
// Reset back to initial values
1168+
document.body.style.height = initialDocumentHeight;
1169+
editor.renderer.$loop._flush();
1170+
1171+
done();
1172+
}, 100);
1173+
},
1174+
"test: if there is ghost text, popup should be rendered at the bottom of the ghost text": function(done) {
1175+
var editor = initEditor("");
1176+
1177+
var longCompleter = {
1178+
getCompletions: function (editor, session, pos, prefix, callback) {
1179+
var completions = [
1180+
{
1181+
caption: "loooooong",
1182+
value: "line\n".repeat(5),
1183+
score: 0
1184+
}
1185+
];
1186+
callback(null, completions);
1187+
}
1188+
};
1189+
1190+
editor.completers = [longCompleter];
1191+
1192+
var completer = Autocomplete.for(editor);
1193+
completer.inlineEnabled = true;
1194+
1195+
user.type("Ctrl-Space");
1196+
assert.ok(completer.popup && completer.popup.isOpen);
1197+
1198+
// Wait to account for the renderer scrolling for the virtual renderer
1199+
setTimeout(() => {
1200+
completer.popup.renderer.$loop._flush();
1201+
1202+
// Popup should start one pixel below the bottom of the ghost text
1203+
assert.equal(
1204+
completer.popup.container.getBoundingClientRect().top,
1205+
editor.renderer.$ghostTextWidget.el.getBoundingClientRect().bottom + 1
1206+
);
1207+
1208+
done();
1209+
}, 100);
11261210
}
11271211
};
11281212

0 commit comments

Comments
 (0)
Please sign in to comment.