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