/*
* Copyright (C) 2011 Alasdair C. Hamilton
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package ketUI.modes;
import java.io.*;
import java.util.regex.*;
import java.net.URLEncoder;
import ket.*;
import ketUI.Ket;
import ket.math.*;
import ketUI.Clipboard;
import ketUI.chord.Chord;
import ketUI.Document;
import ketUI.DocumentManager;
public class CommandMode {
//////////////////////////////////////////////
// COMMAND LINE REGULAR EXPRESSION PATTERNS //
//////////////////////////////////////////////
static final Pattern commandSetPattern = Pattern.compile("set\\s+(\\w+)\\s?=\\s?(.*)");
static final Pattern commandHelpPattern = Pattern.compile("help\\s+(.*)");
static final Pattern commandQuitPattern = Pattern.compile("qu?i?t?(\\!)?");
static final Pattern commandClearPattern = Pattern.compile("clear");
static final Pattern commandReadPattern = Pattern.compile("r(?:ead)?\\s+(.+)");
static final Pattern commandLabelPattern = Pattern.compile("l(?:abel)?\\s+(.+)");
static final Pattern commandWritePattern = Pattern.compile("w(?:rite)?\\s+(.+)");
static final Pattern commandRegisterPattern = Pattern.compile("reg(?:ister)?(?:\\s+(.))?");
static final Pattern commandAddressPattern = Pattern.compile("-?\\d+\\s*");
/////////////////////
// LOCAL VARIABLES //
/////////////////////
Modes modes;
MathCollection mathCollection;
Clipboard clipboard;
public CommandMode(Modes modes, MathCollection mathCollection) {
this.modes = modes;
this.mathCollection = mathCollection;
this.clipboard = modes.getClipboard();
}
static final String[] helpFiles = new String[]{"/data/chords.template"}; // Denote help files by folder, extension or similar.
/**
* Search help for the given string.
*/
public boolean help(String topic) {
// TODO: Be more systematic about creating new documents.
// Possibly use factory methods to avoid opening the same file
// twice (through that is useful in other contexts). Instead,
// move to a specific part of the file if appropriate.
// Search this file;
boolean matchInThisDocument = modes.getSearch().search(topic, Search.FORWARDS);
if (matchInThisDocument) {
return true;
}
DocumentManager documentManager = modes.getDocumentManager();
// FUTURE: It is possible to use a document manager
// specifically to coordinate help files when the program is
// embedded in another program. The document manager would no
// longer be null.
if (documentManager==null) {
Ket.out.println(" !!! Can't load another document: document manager is null !!! ");
return false;
}
// BUG: Restrict search to help files: check that these files are help files.
// Search (via document manager) all other open documents;
// Request focus for that frame [how]?
for (Document document : documentManager.getDocs()) {
if (document!=modes.getDocument()) { // Don't bother re-checking this document.
boolean ok = selectWithinAnotherDocument(document, topic);
if (ok) {
return true;
}
}
}
// Load the non-open help files as plain text;
for (String filename : helpFiles) {
boolean helpFileMatches = searchJar(filename, topic);
//?+ boolean helpFileMatches = searchPlainText(filename, topic);
if (helpFileMatches) {
Document document = new Document(documentManager, null, filename); // TODO: Use this.getDocument()'s clipboard?
documentManager.addDocument(document);
//- boolean ok = selectWithinAnotherDocument(document, topic);
selectWithinAnotherDocument(document, topic);
return true;
}
}
Ket.out.println(" !!! No match with the help files to '"+topic+"' !!! ");
return false;
}
/**
* Search through a given document for a pattern and return true if the
* pattern was found.
*/
private boolean selectWithinAnotherDocument(Document document, String topic) {
// NOTE: Searches in plain text are slightly different to using the Search class.
Search search = document.getModes().getSearch();
Selection selection = document.getSelection();
boolean matchInOpenDocument = search.search(topic, Search.FORWARDS);
if (matchInOpenDocument) {
Ket.out.println("[match]");
document.getKetPanel().fromMiddle(document.getCursor().getEquationIndex());
// TODO: Request window focus of document.
document.getKetPanel().updateAndRepaint();
return true;
} else {
Ket.out.println("[no match]");
return false;
}
}
/**
* Search the given text file for a string of text.
*/
private boolean searchPlainText(String filename, String topic) {
try {
FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = bufferedReader.readLine();
while (line!=null) {
if (line.contains(topic)) { // Could regular expressions be useful?
return true;
}
line = bufferedReader.readLine();
}
fileReader.close();
return false;
} catch (IOException e) {
Ket.out.println(" !!! Failure to read file: " + filename + ". !!!");
Ket.out.println("exception: " + e);
e.printStackTrace();
return false;
}
}
private boolean searchJar(String filename, String topic) {
// Note: Jar filenames always start with a slash.
try {
InputStream inputStream = MathCollection.class.getResourceAsStream(filename);
if (inputStream==null) {
Ket.out.println(" !!! File not found within Jar !!! ");
Ket.out.println(filename);
return false;
}
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = bufferedReader.readLine();
while (line!=null) {
if (line.contains(topic)) { // Could regular expressions be useful?
return true;
}
line = bufferedReader.readLine();
}
return false;
} catch (IOException e) {
Ket.out.println(" !!! Failure to read jar file: '" + filename + "'. !!!");
Ket.out.println("exception: " + e);
e.printStackTrace();
return false;
}
}
public void processCommand(String message, Chord chord) {
Ket.out.printf("Command responder:\n\tmessage='%s'\n", message);
Matcher commandHelpMatch = commandHelpPattern.matcher(message);
if (commandHelpMatch.matches() && commandHelpMatch.groupCount()==1) {
// TODO: Handle ^help$ regular expression here too.
Ket.out.println();
Ket.out.println(" ------------------- ");
Ket.out.println(" --- HELP LOOKUP --- ");
Ket.out.println(" ------------------- ");
String helpTopic = commandHelpMatch.group(1).trim();
Ket.out.println("\t'" + helpTopic + "'.");
if (helpTopic!=null && !helpTopic.equals("")) {
if (helpTopic.matches("'.+'")) {
Ket.out.println("[quote]");
help(helpTopic);
} else {
Ket.out.println("[star]");
help("*" + helpTopic + "*");
}
} else {
Ket.out.println(" !!! Help search pattern was wrong !!! ");
}
Ket.out.println(" ------------------- ");
Ket.out.println();
return;
}
Matcher commandReadMatch = commandReadPattern.matcher(message);
if (commandReadMatch.matches()) {
Ket.out.println("[READ]");
if (commandReadMatch.groupCount()==1) {
String filename = commandReadMatch.group(1);
Ket.out.printf("read filename=\"%s\"\n", filename);
Ket.out.println("reading file...");
boolean ok = mathCollection.read(filename);
if (ok) {
Ket.out.println("done");
} else {
Ket.out.println("reading failed");
}
}
}
Matcher commandLabelMatch = commandLabelPattern.matcher(message);
if (commandLabelMatch.matches()) {
Ket.out.println("[LABEL]");
if (commandLabelMatch.groupCount()==1) {
String label = commandLabelMatch.group(1);
Equation equation = getCursor().getEquation();
if (equation!=null) {
equation.setLabel(label);
}
}
}
Matcher commandWriteMatch = commandWritePattern.matcher(message);
if (commandWriteMatch.matches()) {
Ket.out.println("[WRITE]");
if (commandWriteMatch.groupCount()==1) {
String filename = commandWriteMatch.group(1);
Ket.out.printf("write filename=\"%s\"\n", filename);
Ket.out.println("writting file...");
boolean isEquationFileSaved = mathCollection.writeText(filename);
if (isEquationFileSaved) {
Ket.out.println("done");
} else {
Ket.out.println(" [Save failed]");
}
}
}
Matcher commandSetMatch = commandSetPattern.matcher(message);
if (commandSetMatch.matches() && commandSetMatch.groupCount()==2) {
String command = commandSetMatch.group(1).toLowerCase();
String variable = commandSetMatch.group(2).trim();
Ket.out.printf("[MATCH :set \"%s\" = \"%s\"]\n", command, variable);
if ("hfs".equals(command) || "htmlfontsize".equals(command)) {
Ket.out.println("[CHANGING FONT SIZE]");
//+ htmlFontSize = Integer.parseInt(variable);
throw new RuntimeException("!!! unfinished code !!! ");
}
return;
}
Matcher commandRegisterMatch = commandRegisterPattern.matcher(message);
if (commandRegisterMatch.matches()) {
Ket.out.println("[DISPLAY REGISTERS]");
if (commandRegisterMatch.groupCount()==1 && commandRegisterMatch.group(1)!=null) {
Ket.out.println("[one argument = '"+commandRegisterMatch.group(1)+"']");
Ket.out.println(clipboard.getArgument(commandRegisterMatch.group(1)));
Argument argument = clipboard.getArgument(commandRegisterMatch.group(1));
if (argument!=null) {
modes.echo("\""+commandRegisterMatch.group(1)+" = '"+argument+"'");
} else {
modes.echo("\""+commandRegisterMatch.group(1)+" is empty.");
}
} else {
Ket.out.println(clipboard.toString());
}
}
Matcher commandClearMatch = commandClearPattern.matcher(message);
if (commandClearMatch.matches()) {
//+ modes.getDocument().clear();
chord.setComplete(false);
return;
}
Matcher commandQuitMatch = commandQuitPattern.matcher(message);
if (commandQuitMatch.matches()) {
Ket.out.println("done.");
if (commandQuitMatch.groupCount()==1) {
if ("!".equals(commandQuitMatch.group(1))) {
Ket.out.println("[forced exit]");
}
System.exit(0);
}
System.exit(0);
}
Matcher commandAddressMatch = commandAddressPattern.matcher(message);
if (commandAddressMatch.matches()) {
int equationNumber = Integer.parseInt(message);
if (equationNumber > 0) {
equationNumber = (equationNumber-1) % getEquationList().size();
setCurrent(getEquationList().getEquation(equationNumber).getVisibleRoot());
} else if (equationNumber < 0) {
equationNumber = (getEquationList().size() + equationNumber);
if (equationNumber>=0 && equationNumber<getEquationList().size() ) {
Ket.out.println("[new index = "+equationNumber+"]");
setCurrent(getEquationList().getEquation(equationNumber).getVisibleRoot());
}
} else {
Ket.out.println(" !!! Can't move to equation (0) !!! ");
}
}
}
private EquationList getEquationList() {
return getSelection().getEquationList();
}
private void setCurrent(Argument current) {
getSelection().setCurrent(current);
}
private Cursor getCursor() {
return mathCollection.getCursor();
}
private Selection getSelection() {
return mathCollection.getSelection();
}
}