leforestier / yattag

Python library to generate HTML or XML in a readable, concise and pythonic way.
333 stars 31 forks source link

New line inside a code block has not the correct indentation #38

Closed vincentcox closed 6 years ago

vincentcox commented 6 years ago

For a opensource project I need to display code on a HTML page. I am using http://prismjs.com/ to get a nice markup for the code reviewers.

So I used yattag in python to write the content of a code file inside the html:

image

This is the result: image

As you can see, the HTML is not properly indented at the code block:

image

When I edit my HTML file manually to fix the intendation: image

I get the intended (not indented, sorry for the pun) result:

image

Is there a way I can properly indent this with Yattag?

Or if I know how much "tabs" it is, how do I add the tab's with Yattag?

leforestier commented 6 years ago

Hi Vincent,

I think it should work using:

from yattag import indent

html_output = indent(doc.getvalue(), indent_text = True)

If not, could you copy paste the code of your example (instead of linking an image)? This way I could test it.

vincentcox commented 6 years ago

The code that builds the html main content (header, navigation and footer is another function):

    def get_source_code_from_file(self, file_path):
        with self.tag('div', klass="row"):
            with self.tag("div", klass="col s10 offset-s1"):
                with self.tag("div", klass="card-content"):
                    with self.tag('pre',('data-src', os.path.basename(file_path)), klass='code line-numbers'):
                        try:
                            with open(file_path, "r") as file:
                                lines_in_file = file.read().splitlines()
                        except:
                            Logger.log("could not open file '%s'" % self.file_path, 1)
                        with self.tag('code'):
                            for line in lines_in_file:
                                self.text(line)
                                self.doc.nl()

The function that sends back the HTML:

 def gethtml(self):
        return indent(self.doc.getvalue(), indent_text = True)

The file which content is read out:


package com.google.android.gms.auth.api.signin.internal;

import android.os.Parcel;
import android.os.Parcelable.Creator;
import android.text.TextUtils;
import com.google.android.gms.auth.api.signin.EmailSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
import com.google.android.gms.common.internal.zzx;
import org.json.JSONObject;

public final class SignInConfiguration implements SafeParcelable {
    public static final Creator<SignInConfiguration> CREATOR = new zzp();
    final int versionCode;
    private final String zzXL;
    private EmailSignInOptions zzXM;
    private GoogleSignInOptions zzXN;
    private String zzXO;
    private String zzXd;

    SignInConfiguration(int versionCode, String consumerPkgName, String serverClientId, EmailSignInOptions emailConfig, GoogleSignInOptions googleConfig, String apiKey) {
        this.versionCode = versionCode;
        this.zzXL = zzx.zzcM(consumerPkgName);
        this.zzXd = serverClientId;
        this.zzXM = emailConfig;
        this.zzXN = googleConfig;
        this.zzXO = apiKey;
    }

    public SignInConfiguration(String consumerPkgName) {
        this(2, consumerPkgName, null, null, null, null);
    }

Everything in the code tag is not formatted.

Unfortunately, if I try a <p> tag, I got the same result:

image

vincentcox commented 6 years ago

I managed to fix the issue.

PrismJS has an extension http://prismjs.com/plugins/normalize-whitespace/ which takes care of this exact problem.

Thank you for your time and for this great project.

This can be closed.

leforestier commented 6 years ago

Actually, I think I'm going to look into this when I have some time. Maybe instead of having indent_text = True or indent_text = False, we could have three options:

indent_text = NO (same as current False option)
indent_text = FIRST_LINE (same as current True option)
indent_text = EACH_LINE (would do what you were looking for)
vincentcox commented 6 years ago

Great, that would be a nice idea. I would use "indent_text = True/False" and use an additional (and optional) parameter "EACH_LINE = True/false". This to keep compatibility when people upgrading to the latest version. If people use True/False for the indent_text their code will break. I don't know much about python package development, but I just mention this, just in case.

leforestier commented 6 years ago

To avoid breaking existing code, I intended to define

NO = False
FIRST_LINE = True
EACH_LINE = 2

and use the is comparator in the function to test the value of the option. This way there would be no change for people who used the True/False values. But your way would work too.

vincentcox commented 6 years ago

Cool, I read over it in the previous message. That would be great, looking forward!

leforestier commented 6 years ago

Done. It works like stated in my previous comment. By the way, I used your Java code sample in the tests_indentation.py file. I hope it's ok with you.

vincentcox commented 6 years ago

Thanks for the new version. I will now test this in my entire program now. I will keep you updated. The test_indentation is fine, no worries.

vincentcox commented 6 years ago

I can confirm this is perfectly working. By this new feature, an annoying bug got fixed in my project. Thanks man! Appreciate your time and effort. Will surely mention you in the README file. Feel free to close this issue.