Skip to content

Commit 5829f78

Browse files
committed
Add snippet support for LaTeX and custom macro completer.
The snippets are copied from the snippets for TeX. The current keywordCompleter for LaTeX is unused because the highlight rules do not give a list of keywords, but color every LaTeX macro, so the completer cannot use the rules to provide completion. This macro completer is inspired by the text completer, but autocomplete only macros (the current text completer do not consider \ to be a part of a word). The interface of Completer is changed so that the keywordCompleter can forward the triggerCharacters and identifiersRegexps of `session.$mode.completer`.
1 parent 0207e6d commit 5829f78

File tree

7 files changed

+99
-11
lines changed

7 files changed

+99
-11
lines changed

ace-internal.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ export namespace Ace {
976976

977977
interface Completer {
978978
/** Regular expressions defining valid identifier characters for completion triggers */
979-
identifierRegexps?: Array<RegExp>,
979+
identifierRegexps?: Array<RegExp> | ((editor: Editor) => Array<RegExp>),
980980

981981
/** Main completion method that provides suggestions for the given context */
982982
getCompletions(editor: Editor,
@@ -999,7 +999,7 @@ export namespace Ace {
999999
/** Unique identifier for this completer */
10001000
id?: string;
10011001
/** Characters that trigger autocompletion when typed */
1002-
triggerCharacters?: string[];
1002+
triggerCharacters?: string[] | ((editor: Editor) => string[]);
10031003
/** Whether to hide inline preview text */
10041004
hideInlinePreview?: boolean;
10051005
/** Custom insertion handler for completion items */

ace.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ declare module "ace-code" {
783783
type CompleterCallback = (error: any, completions: Completion[]) => void;
784784
interface Completer {
785785
/** Regular expressions defining valid identifier characters for completion triggers */
786-
identifierRegexps?: Array<RegExp>;
786+
identifierRegexps?: Array<RegExp> | ((editor: Editor) => Array<RegExp>);
787787
/** Main completion method that provides suggestions for the given context */
788788
getCompletions(editor: Editor, session: EditSession, position: Point, prefix: string, callback: CompleterCallback): void;
789789
/** Returns documentation tooltip for a completion item */
@@ -797,7 +797,7 @@ declare module "ace-code" {
797797
/** Unique identifier for this completer */
798798
id?: string;
799799
/** Characters that trigger autocompletion when typed */
800-
triggerCharacters?: string[];
800+
triggerCharacters?: string[] | ((editor: Editor) => string[]);
801801
/** Whether to hide inline preview text */
802802
hideInlinePreview?: boolean;
803803
/** Custom insertion handler for completion items */

src/autocomplete/util.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,18 @@ exports.getCompletionPrefix = function (editor) {
5454
var prefix;
5555
editor.completers.forEach(function(completer) {
5656
if (completer.identifierRegexps) {
57-
completer.identifierRegexps.forEach(function(identifierRegex) {
58-
if (!prefix && identifierRegex)
59-
prefix = this.retrievePrecedingIdentifier(line, pos.column, identifierRegex);
60-
}.bind(this));
57+
var identifierRegexps;
58+
if (completer.identifierRegexps instanceof Function) {
59+
identifierRegexps = completer.identifierRegexps(editor);
60+
} else {
61+
identifierRegexps = completer.identifierRegexps;
62+
}
63+
if (identifierRegexps && Array.isArray(identifierRegexps)) {
64+
completer.identifierRegexps.forEach(function(identifierRegex) {
65+
if (!prefix && identifierRegex)
66+
prefix = this.retrievePrecedingIdentifier(line, pos.column, identifierRegex);
67+
}.bind(this));
68+
}
6169
}
6270
}.bind(this));
6371
return prefix || this.retrievePrecedingIdentifier(line, pos.column);
@@ -73,8 +81,17 @@ exports.triggerAutocomplete = function (editor, previousChar) {
7381
? editor.session.getPrecedingCharacter()
7482
: previousChar;
7583
return editor.completers.some((completer) => {
76-
if (completer.triggerCharacters && Array.isArray(completer.triggerCharacters)) {
77-
return completer.triggerCharacters.includes(previousChar);
84+
if (completer.triggerCharacters) {
85+
var triggerCharacters;
86+
if (completer.triggerCharacters instanceof Function) {
87+
triggerCharacters = completer.triggerCharacters(editor);
88+
} else {
89+
triggerCharacters = completer.triggerCharacters;
90+
}
91+
92+
if (triggerCharacters && Array.isArray(triggerCharacters)) {
93+
return triggerCharacters.includes(previousChar);
94+
}
7895
}
7996
});
8097
};

src/ext/language_tools.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ var MarkerGroup = require("../marker_group").MarkerGroup;
3737
var textCompleter = require("../autocomplete/text_completer");
3838
/**@type {import("../../ace-internal").Ace.Completer}*/
3939
var keyWordCompleter = {
40+
identifierRegexps(editor) {
41+
var completer = editor.session.$mode.completer;
42+
if (completer) {
43+
if (completer.identifierRegexps instanceof Function) {
44+
return completer.identifierRegexps(editor);
45+
} else {
46+
return completer.identifierRegexps;
47+
}
48+
}
49+
},
4050
getCompletions: function(editor, session, pos, prefix, callback) {
4151
if (session.$mode.completer) {
4252
return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback);
@@ -49,7 +59,17 @@ var keyWordCompleter = {
4959
});
5060
callback(null, completions);
5161
},
52-
id: "keywordCompleter"
62+
id: "keywordCompleter",
63+
triggerCharacters(editor) {
64+
var completer = editor.session.$mode.completer;
65+
if (completer) {
66+
if (completer.triggerCharacters instanceof Function) {
67+
return completer.triggerCharacters(editor);
68+
} else {
69+
return completer.triggerCharacters;
70+
}
71+
}
72+
}
5373
};
5474

5575
var transformSnippetTooltip = function(str) {

src/mode/latex.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ oop.inherits(Mode, TextMode);
1919
this.lineCommentStart = "%";
2020

2121
this.$id = "ace/mode/latex";
22+
23+
this.snippetFileId = "ace/snippets/latex";
2224

2325
this.getMatching = function(session, row, column) {
2426
if (row == undefined)
@@ -35,6 +37,50 @@ oop.inherits(Mode, TextMode);
3537
return this.foldingRules.latexBlock(session, row, column, true);
3638
}
3739
};
40+
41+
function wordDistances(doc, pos) {
42+
var macroName = /\\[a-zA-Z0-9]+/g;
43+
44+
var textBefore = doc.getTextRange(Range.fromPoints({
45+
row: 0,
46+
column: 0
47+
}, pos));
48+
var prefixPos = [...textBefore.matchAll(macroName)].length - 1;
49+
50+
var words = [...doc.getValue().matchAll(macroName)];
51+
var wordScores = Object.create(null);
52+
53+
var currentWord = words[prefixPos];
54+
55+
words.forEach(function (word, idx) {
56+
if (!word || word === currentWord) return;
57+
58+
var distance = Math.abs(prefixPos - idx);
59+
var score = words.length - distance;
60+
wordScores[word] = Math.max(score, wordScores[word] ?? 0);
61+
});
62+
return wordScores;
63+
}
64+
65+
this.completer = {
66+
identifierRegexps: [/[\\a-zA-Z0-0]/g],
67+
getCompletions: (editor, session, pos, prefix, callback) => {
68+
var wordScores = wordDistances(session, pos);
69+
var wordList = Object.keys(wordScores);
70+
callback(null, wordList.map(function (word) {
71+
return {
72+
caption: word,
73+
value: word,
74+
score: wordScores[word],
75+
meta: "macro",
76+
completer: this,
77+
completerId: this.id,
78+
};
79+
}, this));
80+
},
81+
triggerCharacters: ["\\"],
82+
id: "latexMacroCompleter",
83+
};
3884
}).call(Mode.prototype);
3985

4086
exports.Mode = Mode;

src/snippets/latex.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"use strict";
2+
3+
exports.snippetText = require("./latex.snippets");
4+
exports.scope = "latex";

src/snippets/latex.snippets.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require("./tex.snippets");

0 commit comments

Comments
 (0)