Skip to content

Commit d064720

Browse files
committed
Inline autocompletion for suggestions
1 parent 338dacf commit d064720

15 files changed

+1456
-28
lines changed

ace.d.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ export namespace Ace {
217217
behavioursEnabled: boolean;
218218
wrapBehavioursEnabled: boolean;
219219
enableAutoIndent: boolean;
220+
defaultAutocompletion: 'none' | 'basic' | 'inline',
220221
enableBasicAutocompletion: boolean | Completer[],
222+
enableInlineAutocompletion: boolean | Completer[],
221223
enableLiveAutocompletion: boolean | Completer[],
222224
enableSnippets: boolean,
223225
autoScrollEditorIntoView: boolean;
@@ -922,6 +924,58 @@ export namespace Ace {
922924
prefix: string,
923925
callback: CompleterCallback): void;
924926
}
927+
928+
type AceInlineAction = "prev" | "next" | "first" | "last";
929+
930+
export declare class AceInline {
931+
constructor(editor: Editor);
932+
prefix: string;
933+
index: number;
934+
readonly length: number;
935+
readonly isOpen: boolean;
936+
getCurrentCompletion(): Completion | undefined;
937+
setData(data: Completion[], prefix?: string): void;
938+
goTo(action: AceInlineAction): void;
939+
close(): void;
940+
hide(): void;
941+
destroy(): void;
942+
}
943+
944+
type TooltipCommandEnabledFunction = (editor: Editor) => boolean;
945+
946+
interface TooltipCommand extends Command {
947+
enabled: TooltipCommandEnabledFunction | boolean
948+
}
949+
950+
export declare class InlineTooltip {
951+
constructor(parentElement: HtmlElement, commands: Record<string, TooltipCommand>);
952+
show(editor: Editor);
953+
isShown(): boolean;
954+
hide(): void;
955+
destroy(): void;
956+
}
957+
958+
interface AutocompleteOptions {
959+
autoInsert?: boolean,
960+
autoSelect?: boolean,
961+
exactMatch?: boolean,
962+
showInline?: "never" | "inlineOnly" | "all";
963+
}
964+
965+
export interface Autocomplete {
966+
show(editor: Editor, options: AutocompleteOptions): void;
967+
detach(): void;
968+
destroy(): void;
969+
}
970+
971+
interface InlineAutocompleteOptions {
972+
showTooltip?: "never" | "hover" | "always",
973+
forceInlineDisplay?: boolean;
974+
}
975+
976+
export interface InlineAutocomplete extends Autocompleete {
977+
show(editor: Editor, options: InlineAutocompleteOptions): void;
978+
}
925979
}
926980

927981

demo/inline_autocompletion.html

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>ACE Inline Autocompletion demo</title>
6+
<style type="text/css" media="screen">
7+
body {
8+
overflow: hidden;
9+
}
10+
11+
#editor {
12+
margin: 0;
13+
position: absolute;
14+
top: 0;
15+
bottom: 0;
16+
left: 0;
17+
right: 0;
18+
}
19+
</style>
20+
</head>
21+
<body>
22+
23+
<pre id="editor"></pre>
24+
25+
<!-- load ace -->
26+
<script src="../build/src-noconflict/ace.js"></script>
27+
<!-- load ace language tools -->
28+
<script src="../build/src-noconflict/ext-language_tools.js"></script>
29+
<script>
30+
// trigger extension
31+
ace.require("ace/ext/language_tools");
32+
var editor = ace.edit("editor");
33+
editor.session.setMode("ace/mode/html");
34+
editor.setTheme("ace/theme/tomorrow");
35+
// enable inline autocompletion
36+
editor.setOptions({
37+
enableBasicAutocompletion: false,
38+
enableInlineAutocompletion: true,
39+
enableSnippets: true,
40+
enableLiveAutocompletion: false
41+
});
42+
</script>
43+
44+
<script src="./show_own_source.js"></script>
45+
</body>
46+
</html>

src/autocomplete.js

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ var dom = require("./lib/dom");
99
var snippetManager = require("./snippets").snippetManager;
1010
var config = require("./config");
1111

12-
var Autocomplete = function() {
13-
this.autoInsert = false;
14-
this.autoSelect = true;
15-
this.exactMatch = false;
12+
var Autocomplete = function(options) {
13+
if (!options) {
14+
options = {};
15+
}
16+
this.autoInsert = options.autoInsert || false;
17+
this.autoSelect = options.autoSelect || true;
18+
this.exactMatch = options.exactMatch || false;
1619
this.gatherCompletionsId = 0;
1720
this.keyboardHandler = new HashHandler();
1821
this.keyboardHandler.bindKeys(this.commands);
@@ -219,7 +222,7 @@ var Autocomplete = function() {
219222
return true;
220223
};
221224

222-
this.showPopup = function(editor, options) {
225+
this.show = this.showPopup = function(editor, options) {
223226
if (this.editor)
224227
this.detach();
225228

@@ -444,51 +447,75 @@ var Autocomplete = function() {
444447

445448
}).call(Autocomplete.prototype);
446449

450+
var destroyCompleter = function(e, editor) {
451+
editor.completer && editor.completer.destroy();
452+
};
447453

448-
Autocomplete.for = function(editor) {
454+
Autocomplete.for = function(editor, options) {
449455
if (editor.completer) {
450-
return editor.completer;
456+
if (editor.completer instanceof Autocomplete) {
457+
return editor.completer;
458+
} else {
459+
editor.off("destroy", destroyCompleter);
460+
editor.completer.destroy();
461+
}
451462
}
452463
if (config.get("sharedPopups")) {
453-
if (!Autocomplete.$shared)
454-
Autocomplete.$sharedInstance = new Autocomplete();
464+
if (!Autocomplete.$sharedInstance)
465+
Autocomplete.$sharedInstance = new Autocomplete(options);
455466
editor.completer = Autocomplete.$sharedInstance;
456467
} else {
457-
editor.completer = new Autocomplete();
458-
editor.once("destroy", function(e, editor) {
459-
editor.completer.destroy();
460-
});
468+
editor.completer = new Autocomplete(options);
469+
editor.once("destroy", destroyCompleter);
461470
}
462471
return editor.completer;
463472
};
464473

465474
Autocomplete.startCommand = {
466475
name: "startAutocomplete",
467476
exec: function(editor, options) {
468-
var completer = Autocomplete.for(editor);
469-
completer.autoInsert = false;
470-
completer.autoSelect = true;
471-
completer.showPopup(editor, options);
472-
// prevent ctrl-space opening context menu on firefox on mac
473-
completer.cancelContextMenu();
477+
var completer = Autocomplete.for(editor, options);
478+
if (completer instanceof Autocomplete) {
479+
completer.autoInsert = false;
480+
completer.autoSelect = true;
481+
completer.showPopup(editor, options);
482+
// prevent ctrl-space opening context menu on firefox on mac
483+
completer.cancelContextMenu();
484+
}
485+
return completer;
474486
},
475487
bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space"
476488
};
477489

478-
var FilteredList = function(array, filterText) {
490+
var FilteredList = function(array, filterText, prefix) {
479491
this.all = array;
480492
this.filtered = array;
481493
this.filterText = filterText || "";
494+
this.prefix = prefix || "";
482495
this.exactMatch = false;
483496
};
484497
(function(){
498+
this.setPrefix = function(str) {
499+
var nextPrefix = str;
500+
var currentPrefix = this.prefix;
501+
if (nextPrefix.startsWith(currentPrefix)) {
502+
var matches = this.filtered;
503+
} else {
504+
var matches = this.all;
505+
}
506+
this.prefix = str;
507+
matches = this.filterCompletionsByPrefix(matches, this.prefix);
508+
this.filterCompletions(matches, this.filterText);
509+
};
510+
485511
this.setFilter = function(str) {
486512
if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0)
487513
var matches = this.filtered;
488514
else
489515
var matches = this.all;
490516

491517
this.filterText = str;
518+
matches = this.filterCompletionsByPrefix(matches, this.prefix);
492519
matches = this.filterCompletions(matches, this.filterText);
493520
matches = matches.sort(function(a, b) {
494521
return b.exactMatch - a.exactMatch || b.$score - a.$score
@@ -506,6 +533,14 @@ var FilteredList = function(array, filterText) {
506533

507534
this.filtered = matches;
508535
};
536+
537+
this.filterCompletionsByPrefix = function(items, prefix) {
538+
return items.filter(function (item) {
539+
var testItem = item.snippet || item.value;
540+
return testItem.startsWith(prefix);
541+
});
542+
};
543+
509544
this.filterCompletions = function(items, needle) {
510545
var results = [];
511546
var upper = needle.toUpperCase();

0 commit comments

Comments
 (0)