mit pygments ein Markup bauen...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hier http://www.python-forum.de/post-58201.html#58201 hatte ich ja die Idee, pygments zu nutzten um damit ein Markup aufzubauen...

Hab mal angefangen, klappt aber noch nicht so richtig:

Code: Alles auswählen

import sys, cgi, re

from pygments import highlight
from pygments.lexer import RegexLexer#, bygroups, include, combined
from pygments.token import Token, Generic
from pygments.formatter import Formatter


Escaped         = Token.Escaped
Text            = Token.Text


class TextileLexer(RegexLexer):
    name = 'Textile Lexer'

    def headline_callback(lexer, match):
        """
        <h1>Headlines</h1>
        """
        headline = "<h%(no)s>%(txt)s</h%(no)s>\n" % {
            "no": match.group(1),
            "txt": match.group(2)
        }
        yield match.start(), Generic.Headline, headline

    def escape_callback(lexer, match):
        """
        cgi.escape()
        """
        #~ print match.groups()
        yield match.start(), Text, cgi.escape(match.group(2))

    def small_callback(lexer, match):
        """
        <small>txt</small>
        """
        txt = "<small>%s</small>" % match.group(1)
        yield match.start(), Text, txt

    def strong_callback(lexer, match):
        """
        <strong>txt</strong>
        """
        txt = "<strong>%s</strong>" % match.group(1)
        yield match.start(), Text, txt

    tokens = {
        'root': [
            (r'\*(.*?)\*', strong_callback),
            (r'\-\-(.*?)\-\-', small_callback),
            (r'(==(.*?)==)(?usm)', escape_callback),
            (r'h(\d)\. (.+)\n', headline_callback),
            (r'.+', Text),
        ],
    }


class TextileFormatter(Formatter):
    def __init__(self, **options):
        Formatter.__init__(self, **options)

    def write(self, ttype, value, outfile):
        if ttype != Text:
            outfile.write("%s\n" % value)
            return

        value = value.strip()
        blocks = re.split("\n{2,}", value)
        for block in blocks:
            block = block.replace("\n", "<br />\n")
            outfile.write("<p>%s</p>\n\n" % block)

    def format(self, tokensource, outfile):
        lasttype = None
        lastval = u''
        for ttype, value in tokensource:
            #~ outfile.write(">%s\n" % repr(ttype))

            if ttype is lasttype:
                lastval += value
            else:
                if lasttype:
                    self.write(lasttype, lastval, outfile)

                lastval = value
                lasttype = ttype

        self.write(lasttype, lastval, outfile)


if __name__ == "__main__":
    test_text = '''h1. Test
Blabla

blabla
blubblub

h2. headline 2
ein --kleines-- Wort, ein *fettes* Wort
--klein--
*fett*
Das wird ==<p>== Escaped:
==<a href="URL">txt</a>==
wow
==
Table: <table width="90%" border="0" align="center">
Link: <a href="URL">txt</a>
Input: <input type="submit" value="preview" />
==
und noch mehr
'''

    lexer = TextileLexer()
    formatter = TextileFormatter()

    #~ for i, t, v in lexer.get_tokens_unprocessed(test_text):
        #~ print "%4s %-22s %s" % (i, t, v)

    highlight(test_text, lexer, formatter, sys.stdout)
Ausgaben:

Code: Alles auswählen

<h1>Test</h1>

<p>Blabla</p>

<p>blabla<br />
blubblub</p>

<h2>headline 2</h2>

<p>ein --kleines-- Wort, ein *fettes* Wort<br />
<small>klein</small><br />
<strong>fett</strong><br />
Das wird ==<p>== Escaped:<br />
<a href="URL">txt</a><br />
wow</p>

<p>Table: <table width="90%" border="0" align="center"><br />
Link: <a href="URL">txt</a><br />
Input: <input type="submit" value="preview" /></p>

<p>und noch mehr</p>
Irgendwie verstehe ich noch nicht so ganz, wie man die tokens im Lexer zusammen baut.
Außerdem denke ich, mache ich zu viel im Lexer, oder? Also dort z.B. die Headline schon fertig zusammen bauen. Aber ich weiß nicht genau, wie ich die Informationen der Headline richtig in den Formatter übergeben kann.

Edit: http://www.ubuntuusers.de/paste/7359/
Zuletzt geändert von jens am Mittwoch 7. Februar 2007, 13:11, insgesamt 1-mal geändert.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Der Lexer baut keine Tokens zusammen, er teilt den Text in solche auf.

Dein Lexer funktioniert nicht, weil '.+' alles matcht und nicht bei "=" oder "-" aufhört. Das muss also erst mal '[^=*-]+' sein,
und dann brauchst du noch Regexes für einzelne solche Zeichen, falls das Markup nicht matcht.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

birkenfeld hat geschrieben:Der Lexer baut keine Tokens zusammen, er teilt den Text in solche auf.
Ja, das dachte ich mir auch eigentlich... Aber ich schaffe es nicht die Daten gescheit an den Formatter zu übergeben...

z.B.: "h1. Überschrift" -> r'h(\d)\. (.+)\n'

match.groups(): (u'1', u'Überschrift')

Den tuple kann ich so im Formatter gut gebrauchen um daraus den HTML Code zu bilden. Aber wie bekomme ich diese Daten dahin?

EDIT:
birkenfeld hat geschrieben:Dein Lexer funktioniert nicht, weil '.+' alles matcht und nicht bei "=" oder "-" aufhört.
Das stelle ich mir jetzt allerdings schwer vor. Ich muß also eine re bauen, die nur auf Text-Teile passt. Je nach dem wieviele inline-Formate ich hab, wird das sehr umfangreich... z.B. muß ich noch [Links] rausfiltern...
Kann ich das nicht anders machen?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

jens hat geschrieben:
birkenfeld hat geschrieben:Der Lexer baut keine Tokens zusammen, er teilt den Text in solche auf.
Ja, das dachte ich mir auch eigentlich... Aber ich schaffe es nicht die Daten gescheit an den Formatter zu übergeben...

z.B.: "h1. Überschrift" -> r'h(\d)\. (.+)\n'

match.groups(): (u'1', u'Überschrift')

Den tuple kann ich so im Formatter gut gebrauchen um daraus den HTML Code zu bilden. Aber wie bekomme ich diese Daten dahin?
Indem du einen passenden Tokentyp verwendest, z.B. Heading.Level1
EDIT:
birkenfeld hat geschrieben:Dein Lexer funktioniert nicht, weil '.+' alles matcht und nicht bei "=" oder "-" aufhört.
Das stelle ich mir jetzt allerdings schwer vor. Ich muß also eine re bauen, die nur auf Text-Teile passt. Je nach dem wieviele inline-Formate ich hab, wird das sehr umfangreich... z.B. muß ich noch [Links] rausfiltern...
Kann ich das nicht anders machen?
Nein, so arbeiten regexes. Aber so umfangreich ist das doch auch nicht... du musst halt jedes Zeichen, das eine Formatierung einleitet aus der Sammel-Regex ausnehmen.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

birkenfeld hat geschrieben:Indem du einen passenden Tokentyp verwendest, z.B. Heading.Level1
Ah! Das ist es...

Aber so einfach hab ich das nicht Lösen können:

Code: Alles auswählen

import sys

from pygments import highlight
from pygments.lexer import RegexLexer
from pygments.token import Token
from pygments.formatter import Formatter


Headlines = {
    "1": Token.Headlines.Level1,
    "2": Token.Headlines.Level2,
    "3": Token.Headlines.Level3,
}
Headlines_html = {
    "Level1": 1,
    "Level2": 2,
    "Level3": 3,
}


class TextileLexer(RegexLexer):
    def headline_callback(lexer, match):
        ttype = Headlines[match.group(1)]
        yield match.start(), ttype, match.group(2)

    tokens = {
        'root': [
            (r'h(\d)\. (.+)\n', headline_callback),
        ],
    }


class TextileFormatter(Formatter):
    def write(self, ttype, value, outfile):
        if ttype in Token.Headlines:
            self.write_headline(ttype, value, outfile)
        else:
            outfile.write("%s\n" % value)

    def write_headline(self, ttype, value, outfile):
        level = tuple(ttype)[1]
        level = Headlines_html[level]
        outfile.write(
            "<h%(level)s>%(txt)s</h%(level)s>\n" % {
                "level": level,
                "txt": value,
            }
        )

    def format(self, tokensource, outfile):
        lasttype = None
        lastval = u''
        for ttype, value in tokensource:
            if ttype is lasttype:
                lastval += value
            else:
                if lasttype:
                    self.write(lasttype, lastval, outfile)

                lastval = value
                lasttype = ttype

        self.write(lasttype, lastval, outfile)


test_text = '''
h1. h1-test
h2. h2-test
h3. h3-test
'''

highlight(test_text, TextileLexer(), TextileFormatter(), sys.stdout)
Das geht doch bestimmt einfacher, oder nicht???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Ich wage mal zu bezweilfen, dass pygments einen guten Lexer für Textile ähnliche Sprachen bereitstellt. Solche Markup Sache werden in der Regel anders implementiert.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Viel kürzer wirds nicht gehen.

Pygments ist nunmal kein universeller Lexing-Parsing-Toolkit, sondern auf eine Anforderung zugeschnitten.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also sollte ich es am besten gleich sein lassen?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Du kannst den RegexLexer ja übernehmen und etwas umbauen.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Antworten