001package Torello.JavaDoc.SyntaxHiLite;
002
003import Torello.Java.OSCommands;
004import Torello.Java.OSExtras;
005import Torello.Java.OSResponse;
006import Torello.Java.StrCmpr;
007import Torello.Java.OSJavaPipe;
008import Torello.Java.FileRW;
009
010import Torello.Java.ReadOnly.ReadOnlyArrayList;
011import Torello.Java.ReadOnly.ReadOnlyList;
012import Torello.JavaDoc.Annotations.LinkJavaSource;
013import Torello.HTML.HTMLNode;
014import Torello.HTML.HTMLPage;
015import Torello.HTML.Util;
016
017import java.util.Objects;
018import java.util.Vector;
019import java.io.IOException;
020
021/**
022 * Java-Adapter for a Python-Tool which Hi-Lites Source Code.
023 * 
024 * <BR /><BR />
025 * Visit <A HREF='pygments.org' TARGET=_blank>http://Pygments.org</A> for details.
026 * 
027 * <EMBED CLASS='external-html' DATA-FILE-ID=CLI_HELP>
028 * <EMBED CLASS='external-html' DATA-FILE-ID=PYGMENTIZE_CLASSES>
029 * 
030 * @see OSCommands
031 * @see OSJavaPipe
032 */
033public class Pygmentize extends OSCommands
034{
035    public static final ReadOnlyList<String> CODE_TYPES = new ReadOnlyArrayList<>(
036        "java", "html", "js", "css", "json", "properties", "xml", "py", "c", "cpp", "csharp", "go",
037        "php", "ruby", "bash", "sh", "sql", "yaml", "toml", "ini", "docker", "make", "gradle",
038        "swift", "kotlin", "rust", "scala", "perl", "r", "ts", "tsx", "jsx", "md", "txt"
039    );
040
041
042    // ********************************************************************************************
043    // ********************************************************************************************
044    // Constructor
045    // ********************************************************************************************
046    // ********************************************************************************************
047
048
049    public static void main(String[] argv) throws IOException
050    {
051        if (argv.length != 1)
052        {
053            System.out.println("You must pass the file-name of a Java-File");
054            System.exit(1);
055        }
056
057        final Pygmentize        p = new Pygmentize();
058        final String            f = FileRW.loadFileToString(argv[0]);
059        final Vector<HTMLNode>  h = p.hiLite(f, "java", true, (byte) 1);
060        final String            s = Util.pageToString(h);
061
062        System.out.println(s);
063    }
064
065    public Pygmentize() { super(null, null); }
066
067    public Pygmentize clone()
068    { throw new RuntimeException(new CloneNotSupportedException()); }
069
070
071    // ********************************************************************************************
072    // ********************************************************************************************
073    // Convert Source-Code (as a String) into an HiLited HTML-String
074    // ********************************************************************************************
075    // ********************************************************************************************
076
077
078    // NON-HTML-TEXT Output Save ...
079    //  new String[] { "pygmentize", "-l", codeTypeParam,  "-O", dashO }
080
081    @LinkJavaSource(handle="CleanHTML", name="clean")
082    public synchronized Vector<HTMLNode> hiLite(
083            final String    codeText,
084            final String    codeTypeParam,
085            final boolean   useLineNumbers,
086            final byte      styleNum
087        )
088        throws IOException
089    {
090        Objects.requireNonNull(codeText,        "'codeText' Parameter has been passed null.");
091        Objects.requireNonNull(codeTypeParam,   "'codeTypeParam' Parameter has been passed null.");
092
093        final String dashO =
094            "classprefix=H" + styleNum + "-" +
095            (useLineNumbers ? ",linenos=table" : "");
096
097        final String[] cmdArr =
098            { "pygmentize", "-l", codeTypeParam, "-f", "html",  "-O", dashO };
099
100        // This "Pipes" the input to the CLI Command
101        this.osExtras           = new OSExtras();
102        this.osExtras.javaPipe  = new OSJavaPipe(codeText);
103
104        // Run Python's "pygmentize" - downloaded via 'pip' from Pygments.org
105        final OSResponse osr = super.printAndRun(cmdArr);
106
107        if (osr.response != 0) throw new PygmentizeException(
108            "The O/S Process for 'pygmentize' has returned a non-zero Status\n" +
109            THROW.HORIZ_SEP +
110            "OSResponse.response: " +       osr.response + '\n' +
111            "OSResponse.errorOutpu:\n" +    osr.errorOutput + '\n' +
112            THROW.paramsAsStr(codeText, codeTypeParam, styleNum, useLineNumbers)
113        );
114
115        try 
116        {
117            final String html               = osr.standardOutput;
118            final Vector<HTMLNode> retVec   = HTMLPage.getPageTokens(html, false);
119
120            CleanHTML.clean(retVec, useLineNumbers);
121
122            return retVec;
123        }
124
125        catch (Exception e) 
126        {
127            throw new PygmentizeException(
128                "An error has occured while attempting to parse and simplify the returned HTML" +
129                THROW.paramsAsStr(codeText, codeTypeParam, styleNum, useLineNumbers),
130                e
131            );
132        }
133    }
134
135    public synchronized Vector<HTMLNode> hiLite(
136            final String        codeText,
137            final String        codeTypeParam,
138            final boolean       includeLineNumbers,
139            final byte          styleNum,
140            final HiLiteCache   cache
141        )
142        throws IOException
143    {
144        Objects.requireNonNull(codeText,        "'codeText' Parameter has been passed null.");
145        Objects.requireNonNull(codeTypeParam,   "'codeTypeParam' Parameter has been passed null.");
146        Objects.requireNonNull(cache,           "'cache' Parameter has been passed null.");
147
148        // FIRST: Check the Cache, to see if the exact String has been hilited!
149        final String cached =
150            cache.get(codeText, codeTypeParam, includeLineNumbers, styleNum);
151
152        // If there was a Cache hit -> return that String rather than querying the server.
153        if (cached != null) return HTMLPage.getPageTokens(cached, false);
154
155
156        // NO?  ==>  Then query the server.
157        // 
158        // final Vector<HTMLNode> retVec = RESTToVector.run
159        //     (codeText, codeTypeParam, styleTypeParam, includeLineNumbers);
160
161        final Vector<HTMLNode> html =
162            this.hiLite(codeText, codeTypeParam, includeLineNumbers, styleNum);
163
164        // Make sure to save the response in the Cache for next time
165        cache.checkIn
166            (codeText, Util.pageToString(html), codeTypeParam, includeLineNumbers, styleNum);
167
168        return html;
169    }
170}