var: Tutorial oder Tipps zu Syntax-Highlighting?

Ahoi.

Da Fragen zu stellen mir hier zweifellos besser steht als Antworten zu geben, hier mal etwas, was mich sehr interessieren würde:

Da ich ja an einem WebGL-Editor tüftele, bzw. im Zuge dessen an einer API für GLSL ES / JavaScript, und ich mich darum ohnehin mit der Syntax und sonstigen Feinheiten der Sprachen vertraut machen muss und will, dachte ich, ich könnte ja auch mal versuchen, für meinen seiteneigenen "Texteditor" eine (rudimentäre) Syntax-Highlighting-Funktion basteln.

Schon um meine GLSL ES Repräsentation optisch etwas vom restlichen JS abzuheben wäre das eine nette Sache! Aber das Thema interessiert mich auch davon abgesehen schon länger, da ich eigentlich das Ziel habe, nach Möglichkeit keine fremden Scripte in mein Programm einzubinden, sondern soweit wie möglich alles was ich brauche selbst zu erstellen. ;-)

Bei meiner bisherigen Recherche hierzu habe ich nun zwar unzählige fertige Programme gefunden, aber praktisch keine brauchbaren Tutorials oder wirklich aufschlussreiche Artikel. Die Codeanalyse der gefundenen Programme war auch nur begrenzt informativ, da hier viel mehr Funktionen enthalten sind, als ich eigentlich brauche und diese dann so ineinander verwurschtelt sind, dass es kaum möglich erscheint, diejenigen Teile heraus zu destillieren, die mir irgendwie weiterhelfen würden.

Also, falls jemand Tipps oder Links zu nützlichen Tutorials auf Lager hat - ich wäre für jede Hilfe dankbar!

Gruß

var

  1. Nicht gerade ein Tutorial, aber dazu wird es kaum eins geben denke ich:
    http://esprima.org/

  2. Ob es hilft ????????????

    http://www.andre-simon.de/doku/highlight/highlight.php#ch1_1

    http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi

    http://alexgorbatchev.com/SyntaxHighlighter/

    https://github.com/blog/1932-syntax-highlighted-diffs

    Auf githup und Co sollte einiges zu finden sein.

    1. Heja

      Auf githup und Co sollte einiges zu finden sein.

      Sollte man annehmen...

      Dank auch dir für die Tips! ( Wobei ich die ersten Links schon durchgekaut hatte ;-)

      Gruß

      var

  3. da ich eigentlich das Ziel habe, nach Möglichkeit keine fremden Scripte in mein Programm einzubinden, sondern soweit wie möglich alles was ich brauche selbst zu erstellen. ;-)

    Das hatte ich übersehen. Das macht es aufwendiger.
    Du brauchst als erstes einen Scanner + Parser. Den erstellt man in der Regel mit einem Scanner/Parser-Generator. Dort ist Lex/Yacc(Gnu Flex/Bison) verbreitet. Einen größtenteils Bisonkompatieblen Parser-Generator mit inline Scannersyntax für JS gibt es auch: Jison. Mit dem kannst du dein JS bzw. alles andere selbst parsen.
    Den Parser-Generator auch noch selbst zu implementieren (eigentlich alles was es schon gibt nochmal selbst zu erfinden) ist nicht sinnvoll.

    1. Hi

      Du brauchst als erstes einen Scanner + Parser. Den erstellt man in der Regel mit einem Scanner/Parser-Generator. Dort ist Lex/Yacc(Gnu Flex/Bison) verbreitet. Einen größtenteils Bisonkompatieblen Parser-Generator mit inline Scannersyntax für JS gibt es auch: Jison. Mit dem kannst du dein JS bzw. alles andere selbst parsen.
      Den Parser-Generator auch noch selbst zu implementieren (eigentlich alles was es schon gibt nochmal selbst zu erfinden) ist nicht sinnvoll.

      Tja, ich hab mich halt gefragt, ob das alles nicht auch 'ne Nummer einfacher geht.

      Mein erster Gedanke war, dass oninput-Event zu nehmen, die Eingabe zu cachen, dann ein halbwegs smarter RegExp-Abgleich, und schließlich das ganze wieder zusammenzusetzen. ;-)

      Brauche ja weder auto-complete, noch automatische Einrückungen oder eine Überprüfung auf valide Syntax ( letzteres macht mein Program sowieso )...

      Hmmm...

      Jedenfalls Danke für die Tips!

      Gruß

      var

      1. Tja, ich hab mich halt gefragt, ob das alles nicht auch 'ne Nummer einfacher geht.

        Mein erster Gedanke war, dass oninput-Event zu nehmen, die Eingabe zu cachen, dann ein halbwegs smarter RegExp-Abgleich, und schließlich das ganze wieder zusammenzusetzen. ;-)

        Naja, und der halbwegs smarte RegExp-Abgleich ist eben ziemlich komplex.
        Recht einfach wäre alle Kommentare (// bis Zeilenende, /* bis */) filtern, alle Schlüsselwörter zu suchen, alles zw. "" und '' als String(auch geschachtelte beachten) erkennen, Zahlen raussuchen(hex, [oct] beachten) und den Rest als Identifer annehmen.

        1. Heja

          Naja, und der halbwegs smarte RegExp-Abgleich ist eben ziemlich komplex.
          Recht einfach wäre alle Kommentare (// bis Zeilenende, /* bis */) filtern, alle Schlüsselwörter zu suchen, alles zw. "" und '' als String(auch geschachtelte beachten) erkennen, Zahlen raussuchen(hex, [oct] beachten) und den Rest als Identifer annehmen.

          So in etwa, ja. Wesentlich schwieriger fand ich halt die Frage nach der Konkatenation, daher die etwas flapsige Formulierung. ;-)

          Gruß

          var

          1. So in etwa, ja. Wesentlich schwieriger fand ich halt die Frage nach der Konkatenation, daher die etwas flapsige Formulierung. ;-)

            Schwierig ist eher das Aufdröseln, wenn ich dich richtig verstehe.
            Ungefähr so sollte es gehen:
            * du hast ein Array mit einem Element(der gesammte Text) [{ text:"...", type: NORMAL_TEXT }]
            * du filterst alle Kommentare und trennst jeweil vor und hinter diesen ab und erzeugst neue Einträge [{ text:"alles vor Kommentar 1", type: NORMAL_TEXT }, { text:"Kommentar 1", type: COMMENT }, { text:"alles nach Kommentar 1", type: NORMAL_TEXT }]
            * über den abgetrennten text nach Kommentar 1 suchst du den nächsten, usw
            * dann fängst du vorne wieder an und suchst in allen Einträgen vom Typ NORMAL_TEXT nach Schlüsselwörtern, trennst wieder ab und fügst weitere Einträge ein [{ text:"alles vor Schlüsselwort 1", type: NORMAL_TEXT }, [{ text:"Schlüsselwort 1", type: KEYWORD }, { text:"alles nach Schlüsselwort 1", type: NORMAL_TEXT }, { text:"Kommentar 1", type: COMMENT }, { text:"alles nach Kommentar 1", type: NORMAL_TEXT }]
            * ...

            1. Hi

              Schwierig ist eher das Aufdröseln, wenn ich dich richtig verstehe.

              Jein, und nicht ganz. ;-)

              Ungefähr so sollte es gehen:
              * du hast ein Array mit einem Element(der gesammte Text) [{ text:"...", type: NORMAL_TEXT }]
              * du filterst alle Kommentare und trennst jeweil vor und hinter diesen ab und erzeugst neue Einträge [{ text:"alles vor Kommentar 1", type: NORMAL_TEXT }, { text:"Kommentar 1", type: COMMENT }, { text:"alles nach Kommentar 1", type: NORMAL_TEXT }]
              * über den abgetrennten text nach Kommentar 1 suchst du den nächsten, usw
              * dann fängst du vorne wieder an und suchst in allen Einträgen vom Typ NORMAL_TEXT nach Schlüsselwörtern, trennst wieder ab und fügst weitere Einträge ein [{ text:"alles vor Schlüsselwort 1", type: NORMAL_TEXT }, [{ text:"Schlüsselwort 1", type: KEYWORD }, { text:"alles nach Schlüsselwort 1", type: NORMAL_TEXT }, { text:"Kommentar 1", type: COMMENT }, { text:"alles nach Kommentar 1", type: NORMAL_TEXT }]
              * ...

              Ganz genau! Bloß das grundlegende Problem ist in meinen Augen aber hier:

              * du hast ein Array mit einem Element(der gesammte Text)

              Solange der 'gesamte' Text ein halbwegs überschaubares Maß hat, wie bei den (meisten) Code-Snippeds hier im Forum beispielsweise, dann ist das absolut praktikabel, keine Frage.

              Aber bedenke, wir reden hier nicht nur über JavaScript, sondern auch über WebGL-Programming! :D

              Das ist ziemlich low-level! Shader, Buffer (!). Die Berechnung der Vertices. Etc.
              Wir reden hier über wahre Code-Monster! ;-)

              Da jedesmal den ganzen Text durchzusieben wird nicht funktionieren. Das heißt, man braucht ein System, den Text vielfach zu untergliedern und die einzelnen Sektoren einzeln zu 'verwalten'.

              Gruß

              var

              1. Da jedesmal den ganzen Text durchzusieben wird nicht funktionieren. Das heißt, man braucht ein System, den Text vielfach zu untergliedern und die einzelnen Sektoren einzeln zu 'verwalten'.

                Entweder machst du das asynchron so etwa jede Sekunde über den gesammten Text, aber den zerlegten Text hast du ja eigentlich auch schon. Editierst du irgendwo, dann editierst du ja letztendlich einen Eintrag in deinem Array, musst also erst mal nur diesen updaten und neu auswerten. Bei manchen Sachen musst du zusätzlich die nächsten Bereiche mit auswerten (z.B. bei //) und seltener die davor (bei */).
                Du musst nur im Text vermerkt haben, welchen Eintrag du gerade bearbeitest, z.B. als Data-Attribut.

  4. @@var:

    nuqneH

    Also, falls jemand Tipps oder Links zu nützlichen Tutorials auf Lager hat - ich wäre für jede Hilfe dankbar!

    Prism hast du dir angesehen? Artikel | Homepage | Github

    Qapla'

    --
    „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
    1. nuqneH

      Hallo Gunnar

      Prism hast du dir angesehen? Artikel | Homepage | Github

      Du hast gerade meinen 'Favoriten' ins Spiel gebracht. ;-)

      In der Tat ist Prism das Programm, dass ich seit einiger Zeit zu verstehen versuche, da es mir von allen Lösungen am nutzversprechendsten erschien. - Leider bislang noch nicht mit durchschlagendem Erfolg.

      Gruß

      var

  5. Lieber var,

    kennst Du ace noch nicht? Oder CodeMirror?

    Liebe Grüße,

    Felix Riesterer.

    --
    "Wäre die EU ein Staat, der die Aufnahme in die EU beantragen würde, müsste der Antrag zurückgewiesen werden - aus Mangel an demokratischer Substanz." (Martin Schulz, Präsident des EU-Parlamentes)
    1. Lieber var,

      Hallo Felix

      kennst Du ace noch nicht? Oder CodeMirror?

      Doch. Natürlich.

      Und ich könnte 30 verschiedene vorgefertigte Scripte und Stylesheets in meine Seite einbinden, die alle gewünschten Features abdecken. Die Seite selbst wäre dann natürlich auch via CMS erstellt.

      Wenn dann meine 20min Arbeit getan sind, setze ich mich vor meine schön bunt blinkende Seite und freue mich. :)

      Der Weg ist das Ziel! Ich beschäftige mich mit dem Thema, weil es mich ganz einfach interessiert!
      Und wenn mein Text bunt blinken soll, dann will ich das schon selbst so hinbekommen, denn für mich ist der Erkenntnisgewinn entscheidend, nicht so sehr das entgültige Resultat. ;)

      Beste Grüße

      var

  6. Moin var,

    das ist in der Tat ein interessantes Thema. Zum generellen Syntax higlighting hast du ja schon so einiges bekommen, im Grunde reicht dafür ein einfacher lexer aus. Also eine Funktion, dass den Quelltext in Wörter (Tokens) zerlegt und die Art des Tokens bestimmt. Damit nicht immer der komplette Text neu geparsed werden muss, verwenden die meisten Editoren jedoch sogenannte „Milestones.“ Dabei wird der parse state bis zu bestimmten Punkten im Text gespeichert, etwa an Newlines. Wenn dann etwas am Text geändert wird, geht man zurück zum letzten Milestone, nimmt den parse state und parsed dann darauf basierend den Rest des Textes. Die rendering engine kann genau so arbeiten (und das tut sie auch in den meisten Editoren).

    Es gibt aber auch Editoren, die ein Verfahren implementiert haben, dass sich inkrementelles Parsing nennt. Dabei wird ein AST generiert, der sich on the fly partiell ändert und es wird nicht jedes mal wieder der komplette Text geparsed. Das besondere daran ist, dass diese Art ein semantisches Verständnis des Sourcecodes hat, so dass man damit deutlich mehr machen kann, siehe z.B. das umbenennen einer Variablen im aktuellen Scope ohne die Variablen ausserhalb des Scopes zu ändern. Einen kleinen Einblick mag dieses Video geben: https://www.youtube.com/watch?v=-7yMWD1wUu4 Das nutzt den AST, der von Emacs js2-mode erzeugt wird, um ein paar Eindrucksvolle Dinge zu tun.

    Auf die schnelle habe ich allerdings nur dieses Paper zum Thema gefunden.

    LG,
     CK

    1. Moin var

      Moinsen

      Also erstmal vielen Dank für die Hinweise und die perspektivische Verortung! ;-)

      Da ich ohnehin für meine GLSL ES Repräsentation einen abstrakten Syntaxbaum erstelle, liegt es dann natürlich nahe, diesen auch gleich für inkrementelles Parsing eines im Editor eingegebenen Textes zu verwenden.

      Und da ich ja auch bestrebt bin, meine Fähigkeiten bezüglich und mein Wissen über ECMAScript zu vertiefen, erscheint mir das geradezu als _geniale_ Lernmethode! ;-)

      Insbesondere wäre es das, wenn man nicht bloß sprachspezifisch dabei vorgeht, sondern darüber hinaus auch generelle semantische Prinzipien funktional einbindet.

      Nochmal Danke!

      Gruß

      var