web2py-template / new_template.py

# coding: utf-8

quotes = ("'", '"')
string_on_html = 'response.write("%s", escape=False)'
indentation = '    '
unindentation_words_before = ('else', 'elif', 'except')
unindentation_words_after = ('pass', 'break', 'continue', 'return')
open_something = '([{'
close_something = ')]}'

    
def parse_string(text):
    return text.replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"')


def parse_line(line):
    if not line:
        return ''
    if line[0] == '=':
        return 'response.write(%s)' % line[1:].strip()
    else:
        return line


def should_unindent_before(parsed_line):
    return parsed_line.strip().split()[0].replace(':', '') in unindentation_words_before


def should_unindent_after(parsed_line):
    return parsed_line.strip().split()[0].replace(':', '') in unindentation_words_after


def parse_python_code(python_code, indentation_level=0):
    response = []

    in_string = False
    last_quote = ''
    last_character = ''
    line = []
    opened = 0

    for character in python_code:
        line.append(character)
        if not in_string:
            if character in open_something:
                opened += 1
            elif character in close_something:
                opened -= 1
                
            if character == '\n' and last_character != '\\' and not opened:
                parsed_line = parse_line(''.join(line[:-1])).strip()
                if parsed_line:
                    if should_unindent_before(parsed_line):
                        indentation_level -= 1
                    if parsed_line and parsed_line != 'pass':
                        response.append(indentation_level * indentation + parsed_line)
                    if should_unindent_after(parsed_line):
                        indentation_level -= 1
                line = []
                if last_character == ':':
                    indentation_level += 1

        if character in quotes and (not last_quote or character == last_quote):
            last_quote = character
            in_string = not in_string
            if not in_string:
                last_quote = ''
        last_character = character

    if line:
        parsed_line = parse_line(''.join(line)).strip()
        if parsed_line:
            if should_unindent_before(parsed_line):
                indentation_level -= 1
            if parsed_line and parsed_line != 'pass':
                response.append(indentation_level * indentation + parsed_line)
            if should_unindent_after(parsed_line):
                indentation_level -= 1
            if last_character == ':' and not in_string:
                indentation_level += 1

    return indentation_level, response


def parse_template(template_code):
    indentation_level = 0
    response = []
    line = []
    open_tag_count = 0
    close_tag_count = 0
    in_python_code = False
    in_string = False
    last_quote = ''
    in_comment = False
    dict_count = 0
    backslash = False
    last_character = ''

    for character in template_code:

        if in_python_code and not in_string:
            if (character == '\n' or (character == '}' and last_character == '}')) and in_comment:
                in_comment = False
                if line:
                    indentation_level, parsed_code = parse_python_code(''.join(line), indentation_level)
                    response.extend(parsed_code)
                    line = []
                if character == '}' and last_character == '}':
                    in_python_code = False
                last_character = character
                continue
            elif character == '#' or in_comment:
                in_comment = True
                last_character = character
                continue
        
        if not in_python_code and character != '{':
            open_tag_count = 0
        elif in_python_code and character != '}':
            close_tag_count = 0

        line.append(character)

        if in_python_code and character in quotes and not backslash \
           and (not last_quote or character == last_quote):
            last_quote = character
            in_string = not in_string
            if not in_string:
                last_quote = ''
        elif character == '{':
            if in_python_code and not open_tag_count and not in_string:
                dict_count += 1
                last_character = character
                continue
            if not in_string:
                open_tag_count += 1
            if open_tag_count == 2 and not in_python_code and not in_string:
                open_tag_count = 0
                in_python_code = True
                line = line[:-2]
                if line:
                    response.append(indentation_level * indentation + \
                                    string_on_html % parse_string(''.join(line)))
                    line = []
        elif character == '}':
            if in_python_code and dict_count > 0 and not in_string:
                dict_count -= 1
                last_character = character
                continue
            if not in_string:
                close_tag_count += 1
            if close_tag_count == 2 and in_python_code and not in_string:
                in_python_code = False
                close_tag_count = 0
                python_code = ''.join(line[:-2]).strip()
                indentation_level, parsed_code = parse_python_code(python_code,
                        indentation_level)
                response.extend(parsed_code)
                line = []
        if character == '\\':
            backslash = True
        else:
            backslash = False

    if line:
        if in_python_code:
            indentation_level, parsed_code = parse_python_code(''.join(line),
                    indentation_level)
            response.extend(parsed_code)
        else:
            response.append(indentation_level * indentation + \
                            string_on_html % parse_string(''.join(line)))
    return '\n'.join(response)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.