diff --git a/ide.html b/ide.html
index 28c8242..b1a8927 100644
--- a/ide.html
+++ b/ide.html
@@ -11,6 +11,7 @@
+
diff --git a/web/ide_injections.js b/web/ide_injections.js
index a69bc96..04e38c6 100644
--- a/web/ide_injections.js
+++ b/web/ide_injections.js
@@ -172,6 +172,39 @@ function preparation_exception(e) {
}
function attachKeyWatcher(elt, f, config_64) {
+ // autocompletion
+ elt.keyup(function (e) {
+ var kc = e.keyCode;
+ // keys we want to ignore:
+ // <^>v 37->40
+ // ALTGR 17 18, | 220, autres: 16
+ if (kc == 16 || kc == 17 || kc == 18 ||
+ (kc>= 37 && kc <= 40) || kc == 220 + ) return; + // keys at which we want to react: + // DEL 8, ENTER 13, SUPPR 46, SHIFT 16 + // SPACE 32 + // é->0
+ // 0->9 48->57
+ // A->Z 65->90
+ // = 161
+ // _ 173
+ // < 188> 190 . 190
+ // / 191
+ if (kc == 8 || kc == 13 || kc == 46 || kc == 16 ||
+ kc == 32 ||
+ kc == 0 ||
+ (kc>= 48 && kc <= 57) || (kc>= 65 && kc <= 90) || + kc == 161 || kc == 173 || kc == 188 || kc == 190 || kc == 191 + ) { + var src = elt[0].value + console.log(propo_type(src)); + // elt[0].value = src; + } else { + console.log(kc); + } + }); + // run source, complete abbreviation or build blocks elt.keydown(function (e) { if (!e.ctrlKey) return; if (e.keyCode == 10 || e.keyCode == 13) { @@ -383,11 +416,16 @@ function inject_microalg_editor_in(elt_id, config) { '
' +
+ '' +
+ '' +
+ ' sugg.' +
+ '' +
' ' +
+ '
' +
'' +
diff --git a/web/style.css b/web/style.css
index 4ca410b..8b95aad 100644
--- a/web/style.css
+++ b/web/style.css
@@ -110,12 +110,21 @@ body.microalg {
width: 100%;
}
.malg-ok-editor {
- width: 75%;
+ width: 73%;
}
-.malg-output-type {
+.malg-tools {
float: right;
margin: 2px;
- width: 20%;
+ width: 25%;
+ text-align: right;
+}
+.malg-suggestions {
+ margin-right: 1em;
+ padding: 2px;
+ border: solid 1px #aaa;
+}
+.malg-output-type {
+ text-align: center;
}
.malg-error {
color: red;
diff --git a/web/suggestions.js b/web/suggestions.js
new file mode 100644
index 0000000..17267ba
--- /dev/null
+++ b/web/suggestions.js
@@ -0,0 +1,243 @@
+// apparence différent de Sugg pour ESPACE et
+// pour commandes sans arg car "RAZ)"
+// certaines cmds forcément suivies de SPACE
+// pas plus de 10 Sugg?, au moins 2 chars?
+// ! commandes à accents (détection slt, pas Sugg)
+
+function valid(char)
+{
+ return char.match(/\w/);
+}
+var cmdInfo = {
+ "Afficher": {
+ "maxArgs": 1,
+ "sigs": [["?"]]}
+};
+function maxArgs(cmd) {
+ try {
+ return cmdInfo[cmd]['maxArgs'];
+ } catch (e) {
+ return 666;
+ }
+}
+
+/* Returns type, prefix
+
+Types can be
+? for no suggestion
+val for any value
+txt for text
+nl for the need of a new line
+sp for the need of a space
+( for the need of a paren
+) for the need of a paren
+cmd for any command
+any intermediate keyword
+*/
+function propo_type(src)
+{
+ var toReturn = ["?", ""];
+ // Split on parens or whitespace
+ // and keep separators
+ var tokensTmp = src.split(/(\s|\(|\))/)
+ .filter(function (str) { return str.trim(); })
+ .filter(Boolean);
+ // Merge text containing spaces -> "texte"
+ var tokens = [];
+ var inString = false;
+ for (var i = 0; i < tokensTmp.length; i++) + { + if (!inString) { + if (tokensTmp[i].slice(0, 1) == '"' && + tokensTmp[i].slice(-1) != '"') { + inString = true; + } else { + tokens.push(tokensTmp[i]); + } + } else { + if (tokensTmp[i].slice(0, 1) != '"' && + tokensTmp[i].slice(-1) == '"') { + inString = false; + tokens.push('"texte"'); + } + } + } + // Trivial cases + if (tokens.length == 0) + return ["(", ""]; + if (inString) + return ["?", ""]; + // Currently in a word? + var lastChar = src.slice(-1); + if (valid(lastChar)) + { + // Set the prefix + toReturn[1] = tokens.slice(-1); + // Delete the prefix from the tokens + tokens = tokens.slice(0, -1); + } + var lastToken = tokens.slice(-1); + // Brand new instruction? + if (lastToken == "(") + { + // TODO: use code below to detect + // if we are in a sub command for + // refining the command to return + toReturn[0] = "cmd"; + return toReturn; + } + // We need the command of the instruction + // Find the last opening solo paren + var cursor = tokens.length - 1; + var openParens = 0; + var openParensOld = 0; + var tokensAfterLastOpen = 0; + while (cursor>= 0)
+ {
+ var token = tokens[cursor];
+ if (token == "(") openParens++;
+ if (token == ")") openParens--;
+ if (openParens == 0 &&
+ (token == "(" || token != ")"))
+ tokensAfterLastOpen++;
+ if (openParens == 1) break;
+ cursor--;
+ }
+ // We already tested if "(" was the last token,
+ // so we can safely add 1.
+ var cmd = tokens[cursor+1];
+ if (lastChar == ")")
+ {
+ if (openParens == 0)
+ return ["nl", ""];
+ else if (maxArgs(cmd) == 1)
+ return [")", ""];
+ else return ["sp", ""];
+ }
+ else if (lastChar == " ")
+ {
+ if (openParens == 1 &&
+ maxArgs(cmd) + 1 == tokensAfterLastOpen)
+ return [")", ""];
+ else if (cmd == '!!!')
+ return ["txt", ""];
+ // TODO: gérer Si avec ses sigs
+ else if (cmd == 'Si' && tokensAfterLastOpen == 1)
+ toReturn[0] = "bool";
+ else if (cmd == 'Si' && tokensAfterLastOpen == 2)
+ toReturn[0] = "alors";
+ else if (cmd == 'Si' && tokensAfterLastOpen>= 4)
+ toReturn[0] = "sinon";
+ else
+ toReturn[0] = "val";
+ }
+ else if (lastChar == '"')
+ {
+ if (lastToken.length != 1 &&
+ lastToken.slice(0, 1) == '"')
+ return [" ", ""]; // todo check nb args
+ }
+ // TODO: gérer Si avec ses sigs
+ // TODO: gérer aussi les accents
+ // Affecter_à
+ // Concaténer
+ // Déclarer
+ // Définir
+ // Répéter
+ else if (cmd == "Si")
+ {
+ if (tokens.indexOf("Alors", cursor) == -1) {
+ toReturn[0] = "alors";
+ } else if (lastToken != "Alors" && tokens.indexOf("Sinon", cursor) == -1) {
+ toReturn[0] = "sinon";
+ }
+ }
+ return toReturn;
+}
+
+var cmds = "1000Cosinus 1000Sinus AV BC LC TD TG Affecter_a Afficher Aide Ajouter_a Cercle Concatener Contour Declarer Definir Demander Demander_un_nombre Ellipse Entier@ Epaisseur Et Exemples_de Faire Geler Initialiser@ Liste Longueur Millisecondes Nieme Nieme@ Nombre Non Ou Queue RAZ Rectangle Remplissage Repere Repeter Retirer_de Retourner Segment Si Tant_que Tester Tete Texte Triangle Type Vide? Affecter_à Concaténer Déclarer Définir Répéter".split(' ');
+var vals = '( " Vrai Faux valeur_utilisateur credit_iterations sequence_tirages@ Rien'.split(' ');
+var bools = '( Vrai Faux'.split(' ');
+
+/* predicate generator */
+function beginsWith(prefix)
+{
+ return function(str) {
+ var beginning = str.slice(0, prefix.toString().length);
+ return beginning == prefix;
+ }
+}
+
+function matches(prefix, list)
+{
+ return list.filter(beginsWith(prefix));
+}
+
+/* Returns a completion (display and actual text)
+
+*/
+function suggestion(propo_type) {
+ var type = propo_type[0];
+ var prefix = propo_type[1];
+ if (type == 'cmd')
+ return matches(prefix, cmds);
+ if (type == 'val')
+ return matches(prefix, vals);
+ if (type == 'bool')
+ return matches(prefix, bools);
+ if (type == ' ')
+ return ["Espace"];
+ if (type == 'alors')
+ return ["Alors"]; // 'Sinon' factoriser!
+ return [];
+}
+
+// tests
+
+var src_propo_pairs = [
+ ["", "("],
+ [" ", "("],
+ ["(bla)", "nl"],
+ ["(bla (", "cmd"],
+ ["(bla ( ", "cmd"],
+ ["(Demander) (Affi", "cmd"],
+ ["(Afficher ", "val"],
+ ["(Afficher tavu", "?"],
+ ["(Afficher tavu ", ")"],
+ ['(Afficher "tavu" ', ")"],
+ ["(Afficher (+ 1 1)", ")"],
+ ['(Afficher "ta vu ', "?"],
+ ["(Afficher tavu)", "nl"],
+ ["(Si ", "bool"],
+ ["(Si Vrai ", "alors"],
+ ["(Si Vrai Al", "alors"],
+ ["(Si (Et Vrai Faux)", "sp"],
+ ["(Si (Et Vrai Faux) ", "alors"],
+ ["(Si Vrai Alors Rien) (Si Vrai ", "alors"],
+ ["(Si (Et Vrai Faux) Alors ", "val"],
+ ["(Si (Et Vrai Faux) Alors (Afficher 1) ", "sinon"],
+ ["(Si (Et (Ou Vrai) Faux) ", "alors"],
+ ["ok"]
+];
+
+if (typeof console !== "undefined") {
+ print = console.log;
+}
+
+function callback(elt, i)
+{
+ var src = elt[0];
+ if (src === "ok")
+ {
+ print("ok");
+ return;
+ }
+ var target_propo = elt[1];
+ var attempted_propo = propo_type(src)[0];
+ if (target_propo != attempted_propo)
+ {
+ print (src + ': ' + attempted_propo + ' != ' + target_propo);
+ }
+}
+
+src_propo_pairs.forEach(callback);
\ No newline at end of file