diff options
Diffstat (limited to 'jnyqide/NyquistThread.java')
-rw-r--r-- | jnyqide/NyquistThread.java | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/jnyqide/NyquistThread.java b/jnyqide/NyquistThread.java new file mode 100644 index 0000000..e579558 --- /dev/null +++ b/jnyqide/NyquistThread.java @@ -0,0 +1,424 @@ +package jnyqide; + +import java.io.*; +import javax.swing.*; + +/** + * <p>Title: </p> + * <p>Description: </p> + * <p>Copyright: Copyright (c) 2002</p> + * <p>Company: </p> + * @author unascribed + * @version 1.0 + */ + +public class NyquistThread extends Thread { + + Process myProcess; + InputStream stdout; + InputStreamReader isrStdout; + BufferedReader brStdout; + OutputStream stdin; + byte b[]; +// JTextPane textIn; + JTextArea textOut; + Runnable update; + String plotFilename; + boolean plotNow = false; + boolean envelopeNow = false; + boolean editNow = false; + boolean eqNow = false; + boolean preferenceDataSent = false; + boolean initialLoad = false; + String envData; + String eqData; + PlotFrame plotFrame; + MainFrame mainFrame; // used to find current directory + String soundBrowser; // path for sound browser + String scoreEditFileName; + public NyquistThread() { + } + +/* public void setInputArea( JTextPane in ) + { + textIn = in; + }*/ + + public String StringFromFile(String filename, String default_string) { + try { + BufferedReader br = new BufferedReader(new FileReader(filename)); + default_string = br.readLine(); + br.close(); + } catch (Exception e) { + // do nothing + } + return default_string; + } + + public void start(JTextArea out, Runnable u, + PlotFrame plot, MainFrame main) { + textOut = out; + update = u; + plotFrame = plot; + mainFrame = main; + + try { + // Get the current working directory where we can find lib and runtime + // get the "." file present in all directories + //java.io.File f = new java.io.File("."); + // get the absolute path to the "." file + //String cwd2 = f.getAbsolutePath(); + // return the absolute path minus the "." + //cwd2 = cwd2.substring(0, cwd2.length() - 2); + // the code above works, but the following is simpler: + + // find full path to instruments.txt + String cwd = System.getProperty("user.dir"); + soundBrowser = cwd.concat("/lib/instruments.txt"); + System.out.println("soundBrowser file is " + soundBrowser); + + // build XLISPPATH environment specification + String path = System.getenv("XLISPPATH"); // use getenv + if (path == null) { // getenv failed, use a default setting + path = cwd + "/lib/;" + cwd + "/runtime/;"; + } + // if xlisppath file exists, use it instead + path = "XLISPPATH=" + StringFromFile("xlisppath", path); + + // construct SystemRoot for environment from file + String systemroot = StringFromFile("systemroot", "SystemRoot=C:/windows"); + + // See if we can get the USER + String user = System.getenv("USER"); + if (user == null) user = ""; + user = StringFromFile("user", user); // file value overrides all + if (user == "") user = "IGNORE="; // default value + else user = "USER=" + user; + + // Construct the environment for nyquist subprocess + System.out.println(path); + System.out.println(user); + + // make environment from 3 strings + String[] envp = {path, user, systemroot}; + System.out.println("envp has " + systemroot); + + try { + myProcess = Runtime.getRuntime().exec( "./ny", envp ); + } catch (Exception e3) { + System.out.println("no ./ny found, trying ./nyquist"); + try { + myProcess = Runtime.getRuntime().exec("./nyquist", envp); + } catch (Exception e4) { + System.out.println("no ./nyquist found, trying ny"); + // try using PATH to find ny (for linux systems where + // ny is installed) + myProcess = Runtime.getRuntime().exec("ny", envp); + // if this one fails, we'll take the exception below + } + } + System.out.print("myProcess: " + myProcess); + + stdout = myProcess.getInputStream(); + isrStdout = new InputStreamReader(stdout); + brStdout = new BufferedReader(isrStdout); + stdin = myProcess.getOutputStream(); + stdin.write(6); // control-f turns off console echo for Mac and Linux + stdin.flush(); + } + catch( Exception e2 ) { System.out.println(e2); } + + b = new byte[1000]; + if (brStdout != null) { + super.start(); + } else { + textOut.append("Nyquist (ny or nyquist) not found or could not be started."); + } + } + + public void run() { + final int max_buf_len = 256; + StringBuffer buffer = new StringBuffer(max_buf_len); + int buffer_index = 0; + boolean nyquist_is_running = true; + // this is tricky -- we want to accumulate lines to test + // for plot commands, but we want to append chars to + // textOut even if there is no end-of-line. + // + // We're going to flush the buffer after every line. + // That will be expensive if lines are very short, but + // that's pretty rare. So we'll loop until we either + // accumulate a line or there are no characters ready. + // To avoid re-appending characters to textOut, use + // buffer_index to remember how many characters were + // output from the current line. + // + // Algorithm: + // accumulate chars while input is ready and newline not found + // if we have a newline, test for plot command + // append characters to text box + // if we have a newline, reset the buffer + + String line = null; + //String debug_strings[] = new String[100]; + //int debug_strings_x = 0; + while (nyquist_is_running) { + try { + // initialLoad is true when we see text that indicates + // Nyquist has just started. But we want to wait for the + // first prompt. We do this by delaying this process a bit + // hoping that Nyquist will finish output and issue the + // prompt. Then we process the input until we are about to + // block, meaning that (maybe) Nyquist has finished output + // and is waiting at the prompt. + if (initialLoad && !brStdout.ready()) { + mainFrame.sendPreferenceData(); + initialLoad = false; + } + // block until you read at least one character + int ic = brStdout.read(); + //System.out.println("got char"); + if (ic != -1) buffer.append((char) ic); + // read many characters to avoid the overhead of single + // character output. On the other hand, it's expensive + // to build huge buffers if Nyquist outputs a giant + // list, so limit the buffer length to max_buf_len. + while (brStdout.ready() && ic != '\n' && ic != -1 && + buffer.length() < max_buf_len) { + //System.out.println("block on char in while"); + ic = brStdout.read(); + //System.out.println("got it"); + if (ic != -1) buffer.append((char) ic); + } + if ((char) ic == '\n') { + line = new String(buffer); + testForPlot(line); + } else if (buffer.length() >= max_buf_len) { + // pretend we found a line in order to flush + // characters building up in buffer + line = " "; + } else if (ic == -1) { + buffer.append("The Nyquist process has terminated. Please save your files and exit.\n"); + nyquist_is_running = false; + } + textOut.append(buffer.substring(buffer_index)); + buffer_index = buffer.length(); + if (line != null) { // end of line, reset the buffer + line = null; + buffer.setLength(0); + buffer_index = 0; + // limit number of lines and characters in the textOut box + int lines = textOut.getLineCount(); + if (lines > 5000 || + textOut.getLineEndOffset(lines - 1) > 50000) { + // take out about 100 lines at a time: + textOut.replaceRange("", 0, + textOut.getLineStartOffset( + Math.max(1, lines - 4900))); + } + } + // cause the scroll to go to the end of the new text + SwingUtilities.invokeLater(update); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + + private NyquistFile findFile(String filename) { + JInternalFrame[] frames = mainFrame.jDesktop.getAllFrames(); + int i; + for (i = 0; i < frames.length; i++) { + if (frames[i] instanceof NyquistFile) { + NyquistFile nyquistFile = (NyquistFile) frames[i]; + System.out.println("findFile search: " + + nyquistFile.file.getName() + + " file " + nyquistFile.file + " getAbsolutePath " + + nyquistFile.file.getAbsolutePath()); + if (nyquistFile.file.getAbsolutePath().equals(filename)) + return nyquistFile; + } + } + return null; + } + + + // testForPlot looks for Nyquist output that the jNyqIDE wants to know + // about -- originally just plot command output, but now there are many + // Lisp functions that communicate and synchronize with the jNyqIDE + public void testForPlot(String output) { + int iNameStart; + int iNameStop; + //System.out.print("plot's text output:"); + //System.out.println(output); + if (!plotNow) { + iNameStart = output.indexOf("s-plot: writing "); + if (iNameStart >= 0) { + iNameStop = output.indexOf(" ..."); + plotFilename = output.substring(iNameStart + 16, iNameStop); + // Nyquist file should be absolute or current directories + // should be synchronized. Appending the current directory + // causes problems when Nyquist already prints a full path + //if (!mainFrame.currentDir.equals("")) { + // plotFilename = mainFrame.currentDir + plotFilename; + //} + System.out.println("file:" + plotFilename + ":"); + plotNow = true; + } + } + // this is not ...else if... because output can have many lines + if (plotNow) { + iNameStart = output.indexOf(" points from"); + // now, the file is written and closed so we can open it + if (iNameStart >= 0) { + System.out.println("Calling NyqPlot.plot"); + NyqPlot.plot(plotFilename, plotFrame); + plotNow = false; + } + } + // test for loading workspace and saving workspace + if (output.indexOf("workspace loaded") >= 0) { + mainFrame.workspaceLoaded = true; + } else if (output.indexOf("workspace saved") >= 0) { + mainFrame.workspaceSaved = true; + } else if (!envelopeNow) { // test for envelope data + int index = output.indexOf("get-env-data: begin"); + if (index >= 0) { + output = output.substring(index); + envData = ""; + envelopeNow = true; + } + } + if (envelopeNow) { + envData += output; + int index = envData.indexOf("get-env-data: end"); + // remove first line + if (index >= 0) { + int begin = envData.indexOf("\n"); + envData = envData.substring(begin + 1, index); + mainFrame.loadEnvData(envData); + envelopeNow = false; + } + } + if (!eqNow) { + int index = output.indexOf("get-eq-data: begin"); + if (index >= 0) { + output = output.substring(index); + eqData = ""; + eqNow = true; + } + } + if (eqNow) { + eqData += output; + int index = eqData.indexOf("get-eq-data: end"); + // remove first line + if (index >= 0) { + int begin = eqData.indexOf("\n"); + eqData = eqData.substring(begin + 1, index); + mainFrame.loadEqData(eqData); + eqNow = false; + } + } + if (!editNow) { + iNameStart = output.indexOf("score-edit: writing "); + if (iNameStart >= 0) { + iNameStop = output.indexOf(" ..."); + scoreEditFileName = output.substring(iNameStart + 20, iNameStop); + if (!mainFrame.currentDir.equals("")) { + scoreEditFileName = mainFrame.currentDir + scoreEditFileName; + } + System.out.println("file:" + scoreEditFileName + ":"); + editNow = true; + } + } + if (editNow) { + iNameStart = output.indexOf("score-edit: wrote "); + if (iNameStart >= 0) { + Piano_Roll.scoreEdit(scoreEditFileName); + editNow = false; + } + } + if (!preferenceDataSent) { + iNameStart = output.indexOf("by Roger B. Dannenberg"); + if (iNameStart >= 0) { + try { Thread.sleep(200); } + catch (InterruptedException ie) { } + initialLoad = true; + preferenceDataSent = true; + } + } + // System.out.println("OUTPUT FOR PROMPT SEARCH: " + output); + // determine command input mode from prompt by Nyquist: + int promptLoc = output.indexOf("> "); + if (output.indexOf("Entering SAL mode ...") >= 0) { + mainFrame.setSalMode(true); + } else if (output.indexOf("Returning to Lisp ...") >= 0) { + mainFrame.setSalMode(false); + } else if (output.indexOf("[ back to top level ]") >= 0) { + mainFrame.setSalMode(false); + } else if (output.indexOf("if continued: return from BREAK") >= 0) { + mainFrame.setSalMode(false); + } else if (promptLoc == 2 && output.indexOf(">>> in ") == 0) { + System.out.println("... detected >>> in (error line location) "); + int lineLoc = output.indexOf(", line "); + int colLoc = output.indexOf(", col "); + if (lineLoc > 0 && colLoc > 0) { + String filename = output.substring(7, lineLoc); + String lineString = output.substring(lineLoc + 7, colLoc); + String colString = output.substring(colLoc + 6, + output.length() - 2); + NyquistFile nf = findFile(filename); + System.out.println("nf.setCursor line " + lineString + + " col " + colString + " file " + filename + " nf " + nf); + if (isDigits(lineString) && isDigits(colString) && nf != null) { + nf.setCursor(Integer.parseInt(lineString), + Integer.parseInt(colString)); + } + } + } else if (promptLoc >= 0) { + if (output.indexOf("SAL> ") == 0) { + mainFrame.setSalMode(true); + // System.out.println("in SAL mode"); + } else if (isDigits(output.substring(0, promptLoc))) { + mainFrame.setSalMode(false); + // System.out.println("in LISP mode"); + } + } + } + + private boolean isDigits(String s) { + // returns true if all chars in s are digits + for (int i = 0; i < s.length(); i++) + if (!Character.isDigit(s.charAt(i))) return false; + return true; + } + + + public OutputStream getStdin() { + return stdin; + } + + public void sendInput(String s) { + sendInput(s, false); + } + + public void sendInput(String s, boolean hide) { + try { + //System.out.println("Sending:" + hide + ": " + s); + if (!hide) textOut.append(s); + stdin.write( s.getBytes() ); + stdin.flush(); + } catch (Exception e) { + System.out.println(e); + } + } +} + + + + + + + + + |