[C#] Syntax-Highlighter

  • Vorwort
    So hallo an alle, ich hab mir mal überlegt, ich erstell mal ein tut für nen leistungfähigen, aber noc langsammen Syntax-Highlighter, wie wir ihn aus dem VS kennen ^^. Im I-net findet mal nämlich relativ wenig darüber..


    Schritt 1
    Zuerste erstellen wir ein einfaches WinForms Projekt, ich nenne es SyntaxHighlighterDemo.


    Schritt 2
    Jetzt erstellen wir eine neue Codedatei (FixedRichTextBox.cs) und erstetzen den kompletten Text, inklusive den using-Statements hierdurch:



    Wie ihr seht, ist die Klasse von RichTextBox abgeleitet, ist dadurch ein Steuerelement und kann wie eine TextBox, ein Button o.ä. auf einer Winformsanwendung plaziert werden.
    Aber, was haben wir hier gemacht? Weil die Klasse von RichTextBox abgeleitet ist, hat sie auch alle funktionen. Die RichTextBoxklasse hat aber einen Bug: Wenn man AutoWordSelection = false macht, müsste man theoretisch auch einzelne Buchstaben oder halbe Wörter markieren können, das funktioniert aber nicht. Diesen Fehler behebt man, indem man die Eigenschaft manuell auf true und anschließend auf false setzt. Die könnte man theoretisch auch in Form1_Load machen, so müsst ihr euch aber keine Sorgen darum machen das ihr es vergesst, sondern könnt einfach FixedRichTextBox statt RichTextBox verwenden.


    Anyway, jetzt kompilern wir das ganze, entweder mit F5 oder F6, und öffnen Form 1.


    Schritt 3
    Als nächstes öffnen wir die ToolBox, und dadaa, unter SyntaxHighlighterDemo-Komponenten finden wir eine komponente mit dem Namen FixedRichTextBox.
    [Blockierte Grafik: http://www.abload.de/img/fixedgnj3.png]
    Diese platzieren wir wie normale Elemente auf der Form, wenn ihr wollt, platziert daneben eine normale RichTextBox um unseren oberen Fix zu veranschaulichen.


    Schritt 4
    Durch ein Doppelklick auf die FixedRichTextBox, erstellen wir das TextChanged-Event.
    Dort fügen wir SyntaxHighlighter(); ein. Ich erstellle für den Highight eine neue Methode, damit ihr sie mehrmals verwenden könnt, und sie immer nur aufrufen müsst.


    Code
    1. private void fixedRichTextBox1_TextChanged(object sender, EventArgs e)
    2. {
    3. SyntaxHighlighter();
    4. }


    Diese Methode müssen wir auch erstellen, aber befor wir ihrgenwelchen Code eingeben, erstellen wir 1 Membervariable. Membervariablen sind Variablen, die in einer Klasse, und nich in einer Methode deklariert werden. Wir erstellen es also parktisch über dem Konstruktor von Form1.


    Schritt5

    Code
    1. Dictionary<string, Color> colors = new Dictionary<string, Color>(); //Dictionary<Key, Value>


    Ein Dictionary ist das selbe wie eine List, der Vorteil ist aber, das wir mit dem aufruf von colors[key] einfach den Wert auslesen können, der zu dieser Key gehört.


    Im Konstruktor müssen wir einfach Werte dafür festlegen.

    Code
    1. public Form1()
    2. {
    3. colors.Add("Test", Color.Blue);
    4. InitializeComponent();
    5. }


    Das erste Wort (Test) ist unser Keyword, wenn das Wor in der RichTextBox vorkommt, wird es blau markiert (Value).


    Schritt 6
    Als nächstes müssen wir 1 weiteren Fix machen, was ganau passier ist unwichtig, bzw. weiß ich es nicht, weil ich diesen Teil aus dem I-net hab :rolleyes:



    fixedRichTextBox1 müsst ihr durch nameEurerRichTextBox ersetzen.


    Schritt 7
    Jetzt können wir endlich mit dem Code anfangen. Ab jetzt arbeiten wir nurnoch mit der Methode SyntaxHighlighter.


    Zuerst fügen wir

    Code
    1. FreezeDraw();
    2. //...
    3. UnfreezeDraw();


    ein. Dieser Code sorgt dafür, das wir nicht mitbekommen, wie jedes einzelne Wort markiert wir (dazu später mehr). unser kompletter Code kommt zwischen die beiden Freeze-Methoden.


    Schritt 8

    Code
    1. string script = fixedRichTextBox1.Text;
    2. string[] words = script.Split(' ', '\n');
    3. int startChar = 0;


    fügen wir direkt nach FreezeDraw ein. zuerst spalten wir den ganzen Text in einzelne Wörter. Space bzw. ein Absatz sind ein nues Wort.
    startChar ist der anfang des Textes.


    Als nächstes loopen wir durch jedes Wort und ermitteln die länge des Wortes + die länge von Space, die wir anschließend zu startChar hinzufügen:

    Code
    1. foreach (string word in words)
    2. {
    3. int oldWordLength = word.Length + " ".Length;
    4. //...
    5. startChar += oldWordLength;
    6. }


    Hinweis: weiterer Code kommt ab jetzt immer dahin, wo //... steht.


    Jetzt müssen wir durch jedes Keyword, das markiert werden soll loopen. Weil das Keywor immer der erste Wert im colors-Dictionary ist, geht das sehr einfach mit:


    Code
    1. foreach (string kay in colors.Keys)
    2. {
    3. //...
    4. }


    Jetzt müssen wir schauen ob key == word ist, dann heben wir es nämlich farbig hervor. Sonst soll word einfach schwarz bleiben.


    Code
    1. if (word == key)
    2. {
    3. //...
    4. }
    5. else
    6. {
    7. }


    Hier ist der Code für das herausheben, diesen fügen wir in if- und else ein. Erklären werde ich ihn durch Kommentare:


    if-Clause:


    else-Clause


    Wenn wir das ganze ausführen, wird, wenn wir Test schreiben, Test automatisch blau:
    [Blockierte Grafik: http://www.abload.de/img/highlight1wy8s.png]



    Schritt 9
    Ist doch alles ganz schön, but, let's do some more stuff!
    Wie wäre es zum Beispiel mit... grünen Kommentaren?


    Zuerst fügen wir unter startChar = 0; eine boolvariable ein:

    Code
    1. bool isComment = false;


    Bevor wir word == key checken, fügen wir diesen Code ein:



    Das wars auch schon:
    [Blockierte Grafik: http://www.abload.de/img/highlight295qd.png]


    Mit dem selben Prinzip könnt ihr auch etwas rot hervorheben, wenn es sich zwischen " und " befindet.
    Ihr könnt auch eine Funktion einbauen, dass, wenn das vorangegangene Wort blau war, ihr das nächste Wort automatisch schwarz färbt, auch wenn es ein Keyword ist.
    Das alle ist aber sehr einfach zu programmieren, versucht es einfach selbst :)



    Nachwort
    Joa, das wars auch schon mit dem Tut, ist etwas länger geworden als ich dachte... Wenn es Fragen, Anregungen, Feedback, Bugreports oder so etwas gibt, einfach Posten :)
    Rechtschreibfehler bitte ich zu entschuldigen, ich hoffe alles ist gut leserlich und verständlich :)


    (C) Toast, Kopieren ist Ok, allerdings mit meinem Copyright.

  • Ich finde es zwar für den Anfang recht nützlich, für komplexeres Syntaxhighlighting ist das aber allemal nicht geeignet. Ich würde dir raten, in dem Fall auf Regex umzusteigen, weil du dadurch z.B. alle Zahlen oder auch Variablen farblich hervorheben kannst. ;) Außerdem ist es so, wie du es machst, viel zu langsam. Wenn jedesmal der gesamte Text neu eingefärbt wird, dauert das bei 200 Wörtern+ viel zu lange und die Richtextbox friert ein, hier würd ich dir raten, nur die sichtbaren Zeilen einzufärben, oder immer nur die aktuelle und Copy und Paste extra abzufangen.


    MfG