Package quarkninja.mode.xqmode

Source Code of quarkninja.mode.xqmode.ErrorCheckerService

package quarkninja.mode.xqmode;

import java.awt.EventQueue;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JFrame;
import javax.swing.table.DefaultTableModel;

import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;

import processing.app.Base;
import processing.app.Editor;
import processing.app.Library;
import processing.app.SketchCode;
import processing.app.SketchException;
import processing.core.PApplet;
import processing.mode.java.preproc.PdePreprocessor;
import processing.mode.java.preproc.PreprocessorResult;
import antlr.RecognitionException;
import antlr.TokenStreamException;

/**
* Error Checking Service for XQMode.<br>
*
* Fetches code from editor every few seconds, converts it into pure java and
* runs it through the Eclipse AST parser. Parser detects the syntax errors.
* Errors are passed on to Error Window to be displayed to the user. If no
* syntax errors are detected, code is further processed into compilable form by
* the P5 preprocessor. Contributed libraries' jars are added to classpath and
* Compiler is loaded by URLCLassLoader putting the extra jars in its classpath.
* Compilation is done are errors are passed on to Error Window to be displayed
* to the user.
*
* All this happens in a separate thread, so that PDE keeps running without any
* hiccups.
*
* @author Manindra Moharana
*/
public class ErrorCheckerService implements Runnable {

  static public String PATH = "E:/TestStuff/HelloPeasy.java";
  /**
   * Error check happens every sleepTime milliseconds
   */
  public static final int sleepTime = 1000;

  /**
   * The amazing eclipse ast parser
   */
  private ASTParser parser;
  public Editor editor;
  /**
   * Used to indirectly stop the Error Checker Thread
   */
  public boolean stopThread = false;

  /**
   * Used to indirectly pause the Error Checking. Calls to checkCode() become
   * useless.
   */
  public boolean pauseThread = false;

  public ErrorWindow errorWindow;
  public ErrorBar errorBar;
  /**
   * IProblem[] returned by parser stored in here
   */
  private IProblem[] problems;
  public String className, sourceCode;
  /**
   * URLs of extra imports jar files stored here.
   */
  public URL[] classpath;
  public boolean compileCheck;

  /**
   * Code preprocessed by the custom preprocessor
   */
  private StringBuffer rawCode;

  private int scPreProcOffset = 0;

  /**
   * Stores all Problems in the sketch
   */
  public ArrayList<Problem> problemsList;

  /**
   * How many lines are present till the initial class declaration? In basic
   * mode, this would include imports, class declaration and setup
   * declaration. In nomral mode, this would include imports, class
   * declaration only. It's fate is decided inside preprocessCode() }:)
   */
  public int mainClassOffset;

  public boolean staticMode = false;
  private CompilationUnit cu;

  // public static final String[] defaultImports = {
  // "import processing.core.*;", "import processing.xml.*;",
  // "import java.applet.*;", "import java.awt.Dimension;",
  // "import java.awt.Frame; ", "import java.awt.event.MouseEvent;",
  // "import java.awt.event.KeyEvent;",
  // "import java.awt.event.FocusEvent;", "import java.awt.Image;",
  // "import java.io.*;", "import java.net.*;", "import java.text.*;",
  // "import java.util.*;", "import java.util.zip.*;",
  // "import java.util.regex.*;", };

  /**
   * List of jar files to be present in compilation checker's classpath
   */
  public ArrayList<URL> classpathJars;

  /**
   * Timestamp - for measuring total overhead
   */
  long lastTimeStamp = System.currentTimeMillis();

  private String[] slashAnimation = { "|", "/", "--", "\\", "|", "/", "--",
      "\\" };
  private int slashAnimationIndex = 0;

  public static void main(String[] args) {

    try {
      ErrorCheckerService syncheck = new ErrorCheckerService();
      ErrorCheckerService.showClassPath();
      // syncheck.checkCode();
      // syncheck.preprocessCode();
      // File f = new File(
      // "E:/WorkSpaces/Eclipse Workspace 2/AST Test 2/bin");
      File f = new File("resources/CompilationCheckerClasses");

      File f2 = new File(
          "C:/Users/QuarkNinja/Documents/Processing/libraries/peasycam/library/peasycam.jar");

      URL[] classpath;
      classpath = new URL[] { f2.toURI().toURL(), f.toURI().toURL() };
      URLClassLoader classLoader = new URLClassLoader(classpath);
      // quarkninja.mode.xqmode.CompilationChecker
      Class<?> checkerClass = Class.forName("CompilationChecker", true,
          classLoader);
      CompilationCheckerInterface compCheck = (CompilationCheckerInterface) checkerClass
          .newInstance();
      System.out.println(compCheck.getErrors("HelloPeasy",
          syncheck.preprocessCode())[0]);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public ErrorCheckerService() {
    // parser = ASTParser.newParser(AST.JLS4);
    initParser();
    initializeErrorWindow();

  }

  public ErrorCheckerService(String path) {
    PATH = path;
    // parser = ASTParser.newParser(AST.JLS4);
    initParser();
    initializeErrorWindow();
  }

  public ErrorCheckerService(Editor editor, ErrorBar erb) {
    // parser = ASTParser.newParser(AST.JLS4);
    initParser();
    this.editor = editor;
    this.errorBar = erb;
  }

  private void initParser() {
    parser = ASTParser.newParser(AST.JLS4);
    parser.setKind(ASTParser.K_COMPILATION_UNIT);

    @SuppressWarnings("unchecked")
    Map<String, String> options = JavaCore.getOptions();

    // Ben has decided to move on to 1.6. Yay!
    JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options);
    options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6);
    parser.setCompilerOptions(options);
  }

  /**
   * Initialiazes the Error Window from Syntax Checker Service
   */
  public void initializeErrorWindow() {
    if (editor == null)
      return;
    if (errorWindow != null)
      return;

    final ErrorCheckerService thisService = this;
    final Editor thisEditor = editor;

    EventQueue.invokeLater(new Runnable() {
      public void run() {
        try {
          errorWindow = new ErrorWindow(thisEditor, thisService);
          errorWindow.setVisible(true);
          // System.out.println("EW Init");
          System.out.println("XQMode v0.1 alpha");
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
  }

  public static void showClassPath() {
    System.out.println("------Classpath------");
    String cps[] = PApplet.split(System.getProperty("java.class.path"),
        Base.isWindows() ? ';' : ':');
    for (int i = 0; i < cps.length; i++) {
      System.out.println(cps[i]);
    }
    System.out.println("---------------------");
  }

  /**
   * Perform error check
   *
   * @return true - if checking was completed succesfully.
   */
  public boolean checkCode() {
    // Reset stuff here, maybe make reset()?
    String source = "";
    sourceCode = "";
    compileCheck = false;
    lastTimeStamp = System.currentTimeMillis();

    try {
      if (editor != null)
        source = preprocessCode();
      else {
        source = readFile(PATH);
        sourceCode = source;
      }

      parser.setSource(source.toCharArray());
      parser.setKind(ASTParser.K_COMPILATION_UNIT);

      @SuppressWarnings("unchecked")
      Map<String, String> options = JavaCore.getOptions();

      // Ben has decided to move on to 1.6. Yay!
      JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options);
      options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6);
      parser.setCompilerOptions(options);
      cu = (CompilationUnit) parser.createAST(null);

      // Store errors returned by the ast parser
      problems = cu.getProblems();
      // if (problems.length > 0)
      // System.out.println("Syntax error count: " + problems.length
      // + "---" + (System.currentTimeMillis() - lastTimeStamp)
      // + "ms || ");

      // // Populate the probList
      problemsList = new ArrayList<Problem>();
      for (int i = 0; i < problems.length; i++) {
       
        int a[] = calculateTabIndexAndLineNumber(problems[i]);
        problemsList.add(new Problem(problems[i], a[0], a[1]));
      }

      // if (editor == null) {
      // if (problems.length == 0)
      // System.out.println("No syntax errors.");
      // else {
      // System.out.println("Syntax errors: ");
      // for (int i = 0; i < problems.length; i++) {
      // System.out.println(problems[i].getMessage()
      // + " | Line no. "
      // + (problems[i].getSourceLineNumber() - 1));
      // // Class offset is line 1 for now
      // }
      // }
      // }

      if (problems.length == 0) {
        // System.out
        // .println("No syntax errors. Let the compilation begin!");
        sourceCode = preProcessP5style();
        compileCheck();
        // if (problems.length > 0)
        // System.out.print("Compile error count: " + problems.length
        // + "---"
        // + (System.currentTimeMillis() - lastTimeStamp)
        // + "ms || ");
        compileCheck = true;
      }
      // showClassPath();
      if (editor != null) {
        updateErrorTable();
        // if(errorWindow == null)
        //
        // updateErrorTable();
        // if (editor.hasFocus()) {
        // updateErrorTable();
        // System.out.println("updating.");
        // } else
        // System.out.println("Not updating.");

        errorBar.updateErrorPoints(problemsList);
        return true;
      }
    } catch (Exception e) {
      System.out.println("Oops! [SyntaxCheckerThreaded.checkCode]: " + e);
      e.printStackTrace();
    }
    return false;
  }

  /**
   * Preprocess PDE code to pure Java, P5 style. This is used only after
   * eclipse ast parser has okayed the source code. SyntaxError
   */
  private String preProcessP5style() {
    if (problems.length != 0) {
      System.err
          .println("Resolve syntax errors before P5 preprocessor does its thing.");
      return null;
    }
    PdePreprocessor preprocessor = new PdePreprocessor(editor.getSketch()
        .getName());

    String[] codeFolderPackages = null;
    if (editor.getSketch().hasCodeFolder()) {
      File codeFolder = editor.getSketch().getCodeFolder();
      // javaLibraryPath = codeFolder.getAbsolutePath();

      // get a list of .jar files in the "code" folder
      // (class files in subfolders should also be picked up)
      String codeFolderClassPath = Base.contentsToClassPath(codeFolder);
      // append the jar files in the code folder to the class path
      // classPath += File.pathSeparator + codeFolderClassPath;
      // get list of packages found in those jars
      codeFolderPackages = Base
          .packageListFromClassPath(codeFolderClassPath);

    } else {
      // javaLibraryPath = "";
    }

    // String[] sizeInfo;
    // try {
    // sizeInfo = preprocessor.initSketchSize(editor.getSketch()
    // .getCode(0).getProgram(), false);
    // if (sizeInfo != null) {
    // String sketchRenderer = sizeInfo[3];
    // if (sketchRenderer != null) {
    // if (sketchRenderer.equals("P2D")
    // || sketchRenderer.equals("P3D")
    // || sketchRenderer.equals("OPENGL")) {
    // rawCode.insert(0, "import processing.opengl.*; ");
    // }
    // }
    // }
    //
    // } catch (SketchException e) {
    // System.err.println(e);
    // }
    // PdePreprocessor.parseSketchSize(sketch.getMainProgram(), false);
    StringWriter writer = new StringWriter();
    try {
      PreprocessorResult result = preprocessor.write(writer,
          rawCode.toString(), codeFolderPackages);
      className = result.className;
      prepareImports(result.extraImports);
      sourceCode = writer.getBuffer().toString();
      int position = sourceCode.indexOf("{");
      int lines = 0;
      for (int i = 0; i < position; i++) {
        if (sourceCode.charAt(i) == '\n')
          lines++;
      }
      lines += 3;
      // System.out.println("Lines: " + lines);
      mainClassOffset = lines;
      // System.out.println(writer.getBuffer().toString());
      // + "P5 preproc.\n--"
      // + (System.currentTimeMillis() - lastTimeStamp));
      // System.out.println("Result: " + result.extraImports);
    } catch (RecognitionException e) {
      System.err.println(e);
    } catch (TokenStreamException e) {
      System.err.println(e);
    } catch (SketchException e) {
      System.err.println(e);
    }
    return writer.getBuffer().toString();
  }

  public boolean importsAdded = false;
  public boolean loadCompClass = true;
  Class<?> checkerClass;
  CompilationCheckerInterface compCheck;

  private void compileCheck() {
    try {

      // NOTE TO SELF: If classpath contains null Strings
      // URLClassLoader gets angry. Drops NPE bombs.

      // File f = new File(
      // "resources/CompilationCheckerClasses");
      // System.out.println(1);
      // File f = new File(
      // "E:/WorkSpaces/Eclipse Workspace 2/AST Test 2/bin");
      if (loadCompClass) {
        // System.out.println("Loading compcheck files...");
        File f = new File(editor.getBase().getSketchbookFolder()
            .getAbsolutePath()
            + File.separator
            + "modes"
            + File.separator
            + "XQMode"
            + File.separator + "CompilationCheckerClasses");
        classpath = new URL[classpathJars.size() + 1];
        for (int i = 0; i < classpathJars.size(); i++) {
          classpath[i] = classpathJars.get(i);
          // System.out.println(classpathJars.get(i));
        }
        // System.out.println("---------" + classpath.length);
        classpath[classpath.length - 1] = f.toURI().toURL();

        // System.out.println("-- " + classpath.length);
        // System.out.println(2);
        URLClassLoader classLoader = new URLClassLoader(classpath);
        // System.out.println(3);
        checkerClass = Class.forName("CompilationChecker", true,
            classLoader);
        // System.out.println(4);
        compCheck = (CompilationCheckerInterface) checkerClass
            .newInstance();
        loadCompClass = false;
      }
      IProblem[] prob = compCheck.getErrors(className, sourceCode);
      if (problems == null || problems.length == 0) {
        problems = new IProblem[prob.length];
      }
      // int errorCount = 0, warningCount = 0;
      for (int i = 0, k = 0; i < prob.length; i++) {
        IProblem problem = prob[i];
        if (problem == null) {
          System.out.println(i + " is null.");
          continue;
        }
        if (problem.getID() == IProblem.UnusedImport
            || problem.getID() == IProblem.MissingSerialVersion)
          continue;
        problems[k++] = problem;
        int a[] = calculateTabIndexAndLineNumber(problem);
        problemsList.add(new Problem(problem, a[0], a[1]));

        // StringBuffer buffer = new StringBuffer();
        // buffer.append(problem.getMessage());
        // buffer.append(" | line: ");
        // buffer.append(problem.getSourceLineNumber());
        // String msg = buffer.toString();
        // if (problem.isError()) {
        // msg = "Error: " + msg;
        // errorCount++;
        // } else if (problem.isWarning()) {
        // msg = "Warning: " + msg;
        // warningCount++;
        // }
        // System.out.println(msg);
      }

      // System.out.println("Total warnings: " + warningCount
      // + ", Total errors: " + errorCount + " , Len: "
      // + prob.length);

    } catch (Exception e) {
      // e.printStackTrace();
      System.err.println("Compilecheck Problem. " + e);
    }
    // System.out.println("Compilecheck, Done.");
  }

  /**
   * Calculates the tab number and line number of the error in that particular
   * tab.
   *
   * @param problem
   *            - IProblem
   * @return int[0] - tab number, int[1] - line number
   */
  public int[] calculateTabIndexAndLineNumber(IProblem problem) {
    // String[] lines = {};// = PApplet.split(sourceString, '\n');
    int codeIndex = 0;
    int bigCount = 0;

    int x = problem.getSourceLineNumber() - mainClassOffset;

    try {
      for (SketchCode sc : editor.getSketch().getCode()) {
        if (sc.isExtension("pde")) {
          sc.setPreprocOffset(bigCount);
          int len = 0;
          if (editor.getSketch().getCurrentCode().equals(sc)) {
            len = Base.countLines(sc.getDocument().getText(0,
                sc.getDocument().getLength())) + 1;
          } else {
            len = Base.countLines(sc.getProgram()) + 1;
          }

          // System.out.println("x,len, CI: " + x + "," + len + ","
          // + codeIndex);

          if (x >= len) {

            // We're in the last tab and the line count is greater
            // than the no.
            // of lines in the tab,
            if (codeIndex >= editor.getSketch().getCodeCount() - 1) {
              x = len;
              break;
            } else {
              x -= len;
              codeIndex++;
            }
          } else {

            if (codeIndex >= editor.getSketch().getCodeCount())
              codeIndex = editor.getSketch().getCodeCount() - 1;
            break;
          }

        }
        bigCount += sc.getLineCount();
      }
    } catch (Exception e) {
      System.err
          .println("Things got messed up in SyntaxCheckerService.calculateTabIndexAndLineNumber()");
    }

    return new int[] { codeIndex, x };
  }

  /**
   * Starts the Syntax Checker Service thread
   */
  @Override
  public void run() {
    // initializeErrorWindow();
    stopThread = false;
    while (!stopThread) {
      try {
        // Take a nap.
        Thread.sleep(sleepTime);
      } catch (Exception e) {
        System.out.println("Oops! [SyntaxCheckerThreaded]: " + e);
        // e.printStackTrace();
      }

      if(pauseThread)
        continue;
     
      // Check every x seconds     
      checkCode();
    }
  }

  /**
   * Stops the Syntax Checker Service thread
   */
  public void stopThread() {
    stopThread = true;
    System.out.println("Syntax Checker Service stopped.");
  }

  /**
   * Fetches code from the editor tabs and pre-processes it into parsable pure
   * java source. <br>
   * Handles: <li>Removal of import statements <li>Conversion of int(),
   * char(), etc to (int)(), (char)(), etc. <li>Replacing '#' with 0xff for
   * color representation <li>Appends class declaration statement
   *
   * @return String - Pure java representation of PDE code
   */
  private String preprocessCode() {

    String sourceAlt = "";

    if (editor == null) {
      try {
        sourceAlt = readFile(PATH);
      } catch (IOException e) {
        e.printStackTrace();
      }
      System.out.println(sourceAlt);
      System.out.println("-----------PreProcessed----------");
      return sourceAlt;
    }
    // Super wicked regular expressions! (Used from Processing source)
    final String importRegexp = "(?:^|;)\\s*(import\\s+)((?:static\\s+)?\\S+)(\\s*;)";
    final Pattern FUNCTION_DECL = Pattern.compile(
        "(^|;)\\s*((public|private|protected|final|static)\\s+)*"
            + "(void|int|float|double|String|char|byte)"
            + "(\\s*\\[\\s*\\])?\\s+[a-zA-Z0-9]+\\s*\\(",
        Pattern.MULTILINE);

    // Handle code input from editor/java file
    try {
      if (editor == null) {
        System.out.println("Reading .java file: " + PATH);
      } else {
        rawCode = new StringBuffer();

        for (SketchCode sc : editor.getSketch().getCode()) {
          if (sc.isExtension("pde")) {
            sc.setPreprocOffset(scPreProcOffset);

            try {

              if (editor.getSketch().getCurrentCode().equals(sc))
                rawCode.append(sc.getDocument().getText(0,
                    sc.getDocument().getLength()));
              else {
                rawCode.append(sc.getProgram());

              }
              rawCode.append('\n');
            } catch (Exception e) {
              System.err
                  .println("Exception in preprocessCode() - bigCode "
                      + e.toString());
            }
            rawCode.append('\n');
            scPreProcOffset += sc.getLineCount();
          }
        }

        sourceAlt = rawCode.toString();
        // System.out.println("Obtaining source from editor.");
      }
    } catch (Exception e) {

      System.out.println("Exception in preprocessCode()");

    }

    // Replace comments with whitespaces
    // sourceAlt = scrubComments(sourceAlt);

    // Find all int(*), replace with (int)(*)

    // \bint\s*\(\s*\b , i.e all exclusive "int("

    String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" };
    for (String dataType : dataTypeFunc) {
      String dataTypeRegexp = "\\b" + dataType + "\\s*\\(";
      Pattern pattern = Pattern.compile(dataTypeRegexp);
      Matcher matcher = pattern.matcher(sourceAlt);

      // while (matcher.find()) {
      // System.out.print("Start index: " + matcher.start());
      // System.out.println(" End index: " + matcher.end() + " ");
      // System.out.println("-->" + matcher.group() + "<--");
      // }
      sourceAlt = matcher.replaceAll("(" + dataType + ")(");

    }

    // Find all #[web color] and replace with 0xff[webcolor]
    // Should be 6 digits only.
    String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W";
    Pattern webPattern = Pattern.compile(webColorRegexp);
    Matcher webMatcher = webPattern.matcher(sourceAlt);
    while (webMatcher.find()) {
      // System.out.println("Found at: " + webMatcher.start());
      String found = sourceAlt.substring(webMatcher.start(),
          webMatcher.end());
      // System.out.println("-> " + found);
      sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1));
      webMatcher = webPattern.matcher(sourceAlt);
    }

    // Find all import statements and remove them, add them to import list
    ArrayList<String> programImports = new ArrayList<String>();
    //
    do {
      // System.out.println("-->\n" + sourceAlt + "\n<--");
      String[] pieces = PApplet.match(sourceAlt, importRegexp);

      // Stop the loop if we've removed all the import lines
      if (pieces == null)
        break;

      String piece = pieces[1] + pieces[2] + pieces[3];
      int len = piece.length(); // how much to trim out

      programImports.add(piece); // the package name
      // System.out.println("Import -> " + piece);

      // find index of this import in the program
      int idx = sourceAlt.indexOf(piece);

      // Remove the import from the main program
      String whiteSpace = "";
      for (int j = 0; j < piece.length(); j++) {
        whiteSpace += " ";
      }
      sourceAlt = sourceAlt.substring(0, idx) + whiteSpace
          + sourceAlt.substring(idx + len);

    } while (true);

    checkForChangedImports(programImports);

    className = (editor == null) ? "DefaultClass" : editor.getSketch()
        .getName();

    // Check whether the code is being written in STATIC mode(no function
    // declarations) - append class declaration and void setup() declaration
    Matcher matcher = FUNCTION_DECL.matcher(sourceAlt);
    if (!matcher.find()) {
      sourceAlt = "public class " + className + " extends PApplet {\n"
          + "public void setup() {\n" + sourceAlt
          + "\nnoLoop();\n}\n" + "\n}\n";
      staticMode = true;
      mainClassOffset = 2;

    } else {
      sourceAlt = "public class " + className + " extends PApplet {\n"
          + sourceAlt + "\n}";
      staticMode = false;
      mainClassOffset = 1;
    }

    // Handle unicode characters
    sourceAlt = substituteUnicode(sourceAlt);

    // System.out.println("-->\n" + sourceAlt + "\n<--");
    // System.out.println("PDE code processed - "
    // + editor.getSketch().getName());
    sourceCode = sourceAlt;
    return sourceAlt;
  }

  ArrayList<String> previousImports = new ArrayList<String>();

  private void checkForChangedImports(ArrayList<String> programImports) {
    // System.out.println("Imports: " + programImports.size() +
    // " Prev Imp: "
    // + previousImports.size());
    if (programImports.size() != previousImports.size()) {
      loadCompClass = true;
      previousImports = programImports;
    } else {
      for (int i = 0; i < programImports.size(); i++) {
        if (!programImports.get(i).equals(previousImports.get(i))) {
          loadCompClass = true;
          previousImports = programImports;
          break;
        }
      }
    }
    // System.out.println("load..? " + loadCompClass);
  }

  private void prepareImports(List<String> programImports) {
    if (!loadCompClass)
      return;
    classpathJars = new ArrayList<URL>();
    String entry = "";

    for (String item : programImports) {
      int dot = item.lastIndexOf('.');
      entry = (dot == -1) ? item : item.substring(0, dot);

      // entry = entry.substring(6).trim();
      // System.out.println("Entry--" + entry);
      if (ignorableImport(entry)) {
        // System.out.println("Ignoring: " + entry);
        continue;
      }
      Library library = null;
      try {
        library = editor.getMode().getLibrary(entry);
        // System.out.println("lib->" + library.getClassPath() + "<-");
        String libraryPath[] = PApplet.split(library.getClassPath()
            .substring(1).trim(), (Base.isWindows() ? ';' : ':'));
        // TODO: Investigate the jar path added twice issue here
        for (int i = 0; i < libraryPath.length / 2; i++) {
          // System.out.println(entry+" ::"+new
          // File(libraryPath[i]).toURI().toURL());
          classpathJars.add(new File(libraryPath[i]).toURI().toURL());
        }
        // System.out.println("-- ");
        // classpath[count] = (new File(library.getClassPath()
        // .substring(1))).toURI().toURL();
        // System.out.println("  found ");
        // System.out.println(library.getClassPath().substring(1));
      } catch (Exception e) {
        if (library == null) {
          System.err.println("XQMODE: Yikes! Can't find \"" + entry
              + "\" library!");
          return;
        }
        System.out.println("Yikes!" + e);
        System.out.println("Was processing: " + entry);
        // e.printStackTrace();
      }

    }

  }

  /**
   * Ignore processing packages, java.*.*. etc.
   *
   * @param packageName
   * @return boolean
   */
  private boolean ignorableImport(String packageName) {
    if (packageName.startsWith("processing.")
        || packageName.startsWith("java.")
        || packageName.startsWith("javax.")) {
      return true;
    }
    return false;
  }

  /**
   * Updates the error table in the Error Window. And Crashes PDE on OS X.
   * Sad. Frustrating! Issue Solved! :D
   */
  public void updateErrorTable() {

    try {
      String[][] errorData = new String[problemsList.size()][3];
      for (int i = 0; i < problems.length; i++) {
        // TODO: Make this message more natural.
        errorData[i][0] = problemsList.get(i).iProblem.getMessage();
        errorData[i][1] = editor.getSketch()
            .getCode(problemsList.get(i).tabIndex).getPrettyName();
        errorData[i][2] = problemsList.get(i).lineNumber + "";
      }

      initializeErrorWindow();

      if (errorWindow != null) {
        DefaultTableModel tm = new DefaultTableModel(errorData,
            ErrorWindow.columnNames);
        errorWindow.updateTable(tm);

        // A nifty rotating slash animation on the title bar to show
        // that error checker thread is running

        slashAnimationIndex++;
        if (slashAnimationIndex == slashAnimation.length)
          slashAnimationIndex = 0;
        if (editor != null) {
          String info = slashAnimation[slashAnimationIndex] + " T:"
              + (System.currentTimeMillis() - lastTimeStamp)
              + "ms";
          errorWindow.setTitle("Problems - "
              + editor.getSketch().getName() + " " + info);
        }
      }

    } catch (Exception e) {
      System.out.println("Exception at updateErrorTable() " + e);
      e.printStackTrace();
      stopThread();
    }

  }

  public void scrollToErrorLine(int errorIndex) {
    if (editor == null)
      return;
    if (errorIndex < problemsList.size() && errorIndex >= 0) {

      int offset1 = xyToOffset(
          problemsList.get(errorIndex).iProblem.getSourceLineNumber(),
          0);
      int offset2 = xyToOffset(
          problemsList.get(errorIndex).iProblem.getSourceLineNumber() + 1,
          0);

      if (editor.getCaretOffset() != offset1) {
        // System.out.println("offset unequal");
        editor.toFront();
        editor.setSelection(offset1, offset2 - 1);
        // System.out.println("---");
      }
    }
  }

  /**
   * Converts a row no, column no. representation of cursor location to offset
   * representation. Editor uses JTextArea internally which deals only with
   * caret offset, not row no. and column no.
   *
   * @param x
   *            - row no.
   * @param y
   *            - column no.
   *
   * @return int - Offset
   */

  public int xyToOffset(int x, int y) {

    String[] lines = {};// = PApplet.split(sourceString, '\n');
    int offset = 0;
    int codeIndex = 0;
    int bigCount = 0;
    int len = 0; // No. of lines in each tab
    x -= mainClassOffset;
    try {
      for (SketchCode sc : editor.getSketch().getCode()) {
        if (sc.isExtension("pde")) {
          sc.setPreprocOffset(bigCount);

          if (editor.getSketch().getCurrentCode().equals(sc)) {
            lines = PApplet.split(
                sc.getDocument().getText(0,
                    sc.getDocument().getLength()), '\n');
            // System.out.println("Getting from document "
            // + sc.getLineCount() + "," + lines.length);
            len = Base.countLines(sc.getDocument().getText(0,
                sc.getDocument().getLength())) + 1;
          } else {
            lines = PApplet.split(sc.getProgram(), '\n');
            len = Base.countLines(sc.getProgram()) + 1;
          }

          // System.out.println("x,len, CI: " + x + "," + len + ","
          // + codeIndex);

          // Adding + 1 to len because \n gets appended for each
          // sketchcode extracted during processPDECode()
          if (x >= len) {

            // We're in the last tab and the line count is greater
            // than the no.
            // of lines in the tab,
            if (codeIndex >= editor.getSketch().getCodeCount() - 1) {
              editor.getSketch().setCurrentCode(
                  editor.getSketch().getCodeCount() - 1);
              x = len;
              break;
            } else {
              x -= len;
              codeIndex++;
            }
          } else {

            if (codeIndex >= editor.getSketch().getCodeCount())
              codeIndex = editor.getSketch().getCodeCount() - 1;
            editor.getSketch().setCurrentCode(codeIndex);
            break;
          }

        }
        bigCount += sc.getLineCount();
      }

      // Count chars till the end of previous line(x-1), keeping in mind x
      // starts from 1
      for (int i = 0; i < x - 1; i++) {
        if (i < lines.length)
          offset += lines[i].length() + 1;
      }
      // Line Columns start from 1
      offset += y == 0 ? 0 : y - 1;
    } catch (Exception e) {
      System.out.println("Exception in xyToOffset");
      e.printStackTrace();
    }
    // System.out.println("---");
    return offset;
  }

  /**
   * Replaces non-ascii characters with their unicode escape sequences and
   * stuff. Used as it is from
   * processing.src.processing.mode.java.preproc.PdePreprocessor
   *
   * @param program
   *            - Input String containing non ascii characters
   * @return String - Converted String
   */
  public static String substituteUnicode(String program) {
    // check for non-ascii chars (these will be/must be in unicode format)
    char p[] = program.toCharArray();
    int unicodeCount = 0;
    for (int i = 0; i < p.length; i++) {
      if (p[i] > 127)
        unicodeCount++;
    }
    if (unicodeCount == 0)
      return program;
    // if non-ascii chars are in there, convert to unicode escapes
    // add unicodeCount * 5.. replacing each unicode char
    // with six digit uXXXX sequence (xxxx is in hex)
    // (except for nbsp chars which will be a replaced with a space)
    int index = 0;
    char p2[] = new char[p.length + unicodeCount * 5];
    for (int i = 0; i < p.length; i++) {
      if (p[i] < 128) {
        p2[index++] = p[i];
      } else if (p[i] == 160) { // unicode for non-breaking space
        p2[index++] = ' ';
      } else {
        int c = p[i];
        p2[index++] = '\\';
        p2[index++] = 'u';
        char str[] = Integer.toHexString(c).toCharArray();
        // add leading zeros, so that the length is 4
        // for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0';
        for (int m = 0; m < 4 - str.length; m++)
          p2[index++] = '0';
        System.arraycopy(str, 0, p2, index, str.length);
        index += str.length;
      }
    }
    return new String(p2, 0, index);
  }

  public static String readFile(File file) throws IOException {
    System.out.println("File: " + file.getAbsolutePath());
    BufferedReader reader = new BufferedReader(new InputStreamReader(
        new FileInputStream(file)));
    try {
      StringBuilder ret = new StringBuilder();
      String line;
      while ((line = reader.readLine()) != null) {
        ret.append(line);
        ret.append("\n");
      }
      return ret.toString();
    } finally {
      reader.close();
    }
  }

  public static String readFile(String path) throws IOException {
    return readFile(new File(path));
  }

}
TOP

Related Classes of quarkninja.mode.xqmode.ErrorCheckerService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.