2010-11-22 5 views
0

J'écris ma propre syntaxe surligneur en javascript pour m'amuser et voir quelques approches mais elles ont toutes les deux des avantages et quelques inconvénients assez sérieux que je ne peux pas contourner. Que pensez-vous de ces approches et y a-t-il de meilleures méthodes qui me manquent?syntaxe en surbrillance design

Assomption

code pour mettre en évidence existe dans une seule chaîne.

approches

  1. code Traiter dans sa forme de chaîne et d'utiliser des expressions régulières pour trouver des modèles.
    Pros
    simple à définir et à rechercher des modèles
    Moins
    Difficile de ne pas tenir compte des mots-clés à l'intérieur des citations ou commentaires

  2. diviser la chaîne par des espaces et des sauts de ligne et de la boucle sur la tableau.
    Pros
    Facile à garder une trace de la portée
    Moins
    dur de garder une trace des espaces et des sauts de ligne après la scission


EDIT:Donc, si je comprends bien, en utilisant l'analyse lexicale, vous cassez la chaîne en jetons. Cela ressemble beaucoup à l'approche numéro 2? Comment abordez-vous le réassemblage des jetons dans la chaîne d'origine?

+7

3. Parse En fait, le code source en jetons et les traiter correctement. Avantages: Correct. Les inconvénients: dur. –

+1

Votre # 2, si vous voulez vraiment dire littéralement * "... par des espaces et des sauts de ligne ..." * va casser fondamentalement n'importe quelle langue avec la syntaxe dérivée de B (C, C++, C#, Java, JavaScript, D, et environ une douzaine d'autres). Considérons 'if (x> y) {foo();} else {bar();}'. –

+0

À droite, pouvez-vous élaborer ou donner un exemple de ce que vous entendez par «jetons»? – Scott

Répondre

1

Remarque: Ceci utilise jQuery. Il peut très bien être réécrit pour travailler avec javascript directement si vous le souhaitez.

j'ai écrit un petit plugin pour le plaisir qui fait cela:

(function($) { 
$.fn.codeBlock = function(blockComment) { 

    // Setup keyword regex 
    var keywords = /(abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|default|delete|do|double|else|enum|export|extends|final|finally|float|for|function|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|super|switch|synchronized|this|throw|throws|transient|try|typeof|var|void|volatile|while|with|true|false|prototype)(?!\w|=)/gi; 

    // Booleans to toggle comment, regex, quote exclusions 
    var comment = false; 
    var quote = false; 
    var regex = false; 

    /* Array used to store values of regular expressions, quotes, etc. 
    so they can be used to ID locations to be skipped durring keyword 
    regexing. 
    */ 
    var locator = new Array(); 
    var locatorIndex = 0; 

    if (blockComment) locator[locatorIndex++] = 0; 

    var text = $(this).html(); 
    var continuation; 
    var numerals = /[0-9]/; 

    var arr = ($(this).html()).split(""); 
    var outhtml = ""; 

    for (key in arr) { 
    // Assign three variables common 'lookup' values for faster aquisition 
    var keyd = key; 
    var val = arr[keyd]; 
    var nVal = arr[keyd - 1]; 
    var pVal = arr[++keyd]; 

    if ((val == "\"" || val == "'") && nVal != "\\") { 
    if (quote == false) { 
    quote = true; 
    outhtml += val; 
    } 
    else { 
    outhtml += val; 
    quote = false; 
    } 
    locator[locatorIndex++] = parseInt(key); 
    } 
    else if (numerals.test(val) && quote == false && blockComment == false && regex == false) { 
    outhtml += '<span class="num">' + val + '</span>'; 
    } 
    else if (val == "/" && nVal != "<") { 
    var keys = key; 
    if (pVal == "/") { 
    comment = true; 
    continuation = key; 
    break; 
    } 
    else if (pVal == "*") { 
    outhtml += "/"; 
    blockComment = true; 
    locator[locatorIndex++] = parseInt(key); 
    } 
    else if (nVal == "*") { 
    outhtml += "/"; 
    blockComment = false; 
    locator[locatorIndex++] = parseInt(key); 
    } 
    else if (pVal == "[" && regex == false) { 
    outhtml += "<span class='res'>/"; 
    regex = true; 
    } 
    else { 
    outhtml += "/"; 
    } 
    } 
    else if (val == "," || val == ";" && regex == true) { 
    outhtml += "</span>" + val; 
    regex = false; 
    } 
    else { 
    outhtml += val; 
    } 
    } 

    if (comment == true) { 
    outhtml = outhtml.replace(keywords, "<span class='res'>$1</span>"); 
    outhtml += '<span class="com">'; 
    outhtml += text.substring(continuation, text.length); 
    outhtml += '</span>'; 
    } 
    else { 
    if ((locator.length % 2) != 0) locator[locator.length] = (text.length - 1); 

    if (locator.length != 0) { 
    text = outhtml; 

    outhtml = text.substring(0, locator[0]).replace(keywords, "<span class=\"res\">$1</span>"); 

    for (var i = 0; i < locator.length;) { 
    qTest = text.substring(locator[i], locator[i] + 1); 
    if (qTest == "'" || qTest == "\"") outhtml += "<span class=\"quo\">"; 
    else outhtml += "<span class=\"com\">"; 

    outhtml += text.substring(locator[i], locator[++i] + 1) + "</span>"; 

    outhtml += text.substring(locator[i] + 1, locator[++i]).replace(keywords, "<span class=\"res\">$1</span>"); 
    } 
    } 
    else { 
    outhtml = outhtml.replace(keywords, "<span class=\"res\">$1</span>"); 
    } 
    } 

    text = outhtml; 
    $(this).html(text); 
    return blockComment; 
} 
})(jQuery); 

Je ne vais pas réclamer est le moyen le plus efficace de le faire ou le meilleur, mais il fonctionne. Il y a probablement encore quelques bugs là-dedans que je n'ai pas encore identifié (et je connais mais je n'ai pas encore eu de problème), mais cela devrait vous donner une idée de la façon dont vous pouvez faire cela si vous comme.

Ma suggestion de mise en œuvre de ceci est de créer un textarea ou quelque chose et d'avoir le plugin exécuté lorsque vous cliquez sur un bouton ou quelque chose (dans la mesure où ça passe c'est une bonne idée) et bien sûr vous pouvez définir le texte la zone de texte à un code de démarrage pour s'assurer que cela fonctionne (Astuce: Vous pouvez mettre des balises entre les balises <textarea> et il s'affichera en texte, pas en HTML). En outre, blockComment est un booléen, assurez-vous de transmettre false car true déclenchera la citation du bloc. Si vous avez décidé d'analyser la ligne de quelque chose en ligne, comme:

<a>code</a> 
<a>some more code</a> 

faire quelque chose comme:

blockComment = false; 
$("a").each(function() { 
    blockComment = $(this).codeBlock(blockComment); 
}); 
+0

Merci d'avoir pris le temps de publier ce message, Glenn. Voyant que la solution est un peu plus grande que prévu, je pense que je vais utiliser une bibliothèque pour l'instant. Peut-être un projet pour un jour de pluie :) – Scott

+0

Oui, j'ai écrit plusieurs scripts pour Javascript, CSS, HTML/XML. Javascript était le premier que j'ai essayé et aussi le plus dur. Malgré la longueur, il vaut la peine d'apprendre à faire des choses comme ça. L'expérience peut également facilement se ramifier dans d'autres langages de programmation. –

Questions connexes