<s> """<STR_LIT>""" <EOL> import re <EOL> from jinja2 . ext import Extension <EOL> from jinja2 . lexer import Token , describe_token <EOL> from jinja2 import TemplateSyntaxError <EOL> _tag_re = re . compile ( r'<STR_LIT>' ) <EOL> _ws_normalize_re = re . compile ( r'<STR_LIT>' ) <EOL> class StreamProcessContext ( object ) : <EOL> def __init__ ( self , stream ) : <EOL> self . stream = stream <EOL> self . token = None <EOL> self . stack = [ ] <EOL> def fail ( self , message ) : <EOL> raise TemplateSyntaxError ( message , self . token . lineno , <EOL> self . stream . name , self . stream . filename ) <EOL> def _make_dict_from_listing ( listing ) : <EOL> rv = { } <EOL> for keys , value in listing : <EOL> for key in keys : <EOL> rv [ key ] = value <EOL> return rv <EOL> class HTMLCompress ( Extension ) : <EOL> isolated_elements = set ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) <EOL> void_elements = set ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT:input>' , <EOL> '<STR_LIT>' , '<STR_LIT>' ] ) <EOL> block_elements = set ( [ '<STR_LIT>' , '<STR_LIT:p>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) <EOL> breaking_rules = _make_dict_from_listing ( [ <EOL> ( [ '<STR_LIT:p>' ] , set ( [ '<STR_LIT>' ] ) ) , <EOL> ( [ '<STR_LIT>' ] , set ( [ '<STR_LIT>' ] ) ) , <EOL> ( [ '<STR_LIT>' , '<STR_LIT>' ] , set ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) ) , <EOL> ( [ '<STR_LIT>' ] , set ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) ) , <EOL> ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] , set ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) ) , <EOL> ( [ '<STR_LIT>' , '<STR_LIT>' ] , set ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] ) ) <EOL> ] ) <EOL> def is_isolated ( self , stack ) : <EOL> for tag in reversed ( stack ) : <EOL> if tag in self . isolated_elements : <EOL> return True <EOL> return False <EOL> def is_breaking ( self , tag , other_tag ) : <EOL> breaking = self . breaking_rules . get ( other_tag ) <EOL> return breaking and ( tag in breaking or <EOL> ( '<STR_LIT>' in breaking and tag in self . block_elements ) ) <EOL> def enter_tag ( self , tag , ctx ) : <EOL> while ctx . stack and self . is_breaking ( tag , ctx . stack [ - <NUM_LIT:1> ] ) : <EOL> self . leave_tag ( ctx . stack [ - <NUM_LIT:1> ] , ctx ) <EOL> if tag not in self . void_elements : <EOL> ctx . stack . append ( tag ) <EOL> def leave_tag ( self , tag , ctx ) : <EOL> if not ctx . stack : <EOL> ctx . fail ( '<STR_LIT>' <EOL> '<STR_LIT>' % tag ) <EOL> if tag == ctx . stack [ - <NUM_LIT:1> ] : <EOL> ctx . stack . pop ( ) <EOL> return <EOL> for idx , other_tag in enumerate ( reversed ( ctx . stack ) ) : <EOL> if other_tag == tag : <EOL> for num in xrange ( idx + <NUM_LIT:1> ) : <EOL> ctx . stack . pop ( ) <EOL> elif not self . breaking_rules . get ( other_tag ) : <EOL> break <EOL> def normalize ( self , ctx ) : <EOL> pos = <NUM_LIT:0> <EOL> buffer = [ ] <EOL> def write_data ( value ) : <EOL> if not self . is_isolated ( ctx . stack ) : <EOL> value = _ws_normalize_re . sub ( '<STR_LIT:U+0020>' , value . strip ( ) ) <EOL> buffer . append ( value ) <EOL> for match in _tag_re . finditer ( ctx . token . value ) : <EOL> closes , tag , sole = match . groups ( ) <EOL> preamble = ctx . token . value [ pos : match . start ( ) ] <EOL> write_data ( preamble ) <EOL> if sole : <EOL> write_data ( sole ) <EOL> else : <EOL> buffer . append ( match . group ( ) ) <EOL> ( closes and self . leave_tag or self . enter_tag ) ( tag , ctx ) <EOL> pos = match . end ( ) <EOL> write_data ( ctx . token . value [ pos : ] ) <EOL> return u'<STR_LIT>' . join ( buffer ) <EOL> def filter_stream ( self , stream ) : <EOL> ctx = StreamProcessContext ( stream ) <EOL> for token in stream : <EOL> if token . type != '<STR_LIT:data>' : <EOL> yield token <EOL> continue <EOL> ctx . token = token <EOL> value = self . normalize ( ctx ) <EOL> yield Token ( token . lineno , '<STR_LIT:data>' , value ) <EOL> class SelectiveHTMLCompress ( HTMLCompress ) : <EOL> def filter_stream ( self , stream ) : <EOL> ctx = StreamProcessContext ( stream ) <EOL> strip_depth = <NUM_LIT:0> <EOL> while <NUM_LIT:1> : <EOL> if stream . current . type == '<STR_LIT>' : <EOL> if stream . look ( ) . test ( '<STR_LIT>' ) or stream . look ( ) . test ( '<STR_LIT>' ) : <EOL> stream . skip ( ) <EOL> if stream . current . value == '<STR_LIT>' : <EOL> strip_depth += <NUM_LIT:1> <EOL> else : <EOL> strip_depth -= <NUM_LIT:1> <EOL> if strip_depth < <NUM_LIT:0> : <EOL> ctx . fail ( '<STR_LIT>' ) <EOL> stream . skip ( ) <EOL> if stream . current . type != '<STR_LIT>' : <EOL> ctx . fail ( '<STR_LIT>' % <EOL> describe_token ( stream . current ) ) <EOL> stream . skip ( ) <EOL> if strip_depth > <NUM_LIT:0> and stream . current . type == '<STR_LIT:data>' : <EOL> ctx . token = stream . current <EOL> value = self . normalize ( ctx ) <EOL> yield Token ( stream . current . lineno , '<STR_LIT:data>' , value ) <EOL> else : <EOL> yield stream . current <EOL> stream . next ( ) <EOL> def test ( ) : <EOL> from jinja2 import Environment <EOL> env = Environment ( extensions = [ HTMLCompress ] ) <EOL> tmpl = env . from_string ( '''<STR_LIT>''' ) <EOL> print tmpl . render ( title = <NUM_LIT> , href = '<STR_LIT>' ) <EOL> env = Environment ( extensions = [ SelectiveHTMLCompress ] ) <EOL> tmpl = env . from_string ( '''<STR_LIT>''' ) <EOL> print tmpl . render ( foo = <NUM_LIT> ) <EOL> if __name__ == '<STR_LIT:__main__>' : <EOL> test ( ) </s>
