Permalink
Fetching contributors…
Cannot retrieve contributors at this time
133 lines (114 sloc) 3.68 KB
/*
* Copyright 2014, NICTA
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(NICTA_BSD)
*/
/*
* Indent Isabelle apply-style proofs.
* 2013 David Greenaway.
*
* Install by dropping this file (`proof-indent.bsh`) into the directory
* ` ~/.isabelle/jedit/macros/`. After restarting jEdit or rescanning
* macros in jEdit, the macro `proof-indent` shoud appear in the `Macros`
* menu.
*
* You can additionally add a key binding, for instance Command-Shift-I
* (for Indent), to the new macro `proof-indent` by going to
* `Plugins -> Plugin Options -> Global Options -> jEdit/Shortcuts`
*/
import isabelle.*;
import isabelle.jedit.*;
/* Get the number of pending subgoals in the given state. */
int num_subgoals(Command.State state)
{
status_nodes = state.status();
/* Find the "PROOF_STATE" node. */
proof_state = null;
for (node_list = state.status();
node_list.nonEmpty(); node_list = node_list.tail()) {
n = node_list.head();
if (n.name().equals(Markup.PROOF_STATE())) {
proof_state = n;
break;
}
}
if (proof_state == null)
return -1;
/* Find the "subgoals" node. */
for (state_nodes_list = proof_state.properties();
state_nodes_list.nonEmpty(); state_nodes_list = state_nodes_list.tail()) {
n = state_nodes_list.head();
if (n._1.equals(Markup.SUBGOALS())) {
return Integer.parseInt(n._2);
}
}
/* No node found. */
return -1;
}
/* Pad the given string to have "n" spaces. */
String pad(String input, int n)
{
if (input.equals(""))
return "";
char[] spaces = new char[n];
Arrays.fill(spaces, ' ');
return new String(spaces) + input;
}
/* Determine if the given command should be indented. */
Boolean shouldIndent(Command cmd)
{
/* FIXME */
return true;
}
/* Setup. */
model = PIDE.document_model(textArea.buffer).get();
snapshot = model.snapshot();
/* Setup array of pre-calculated indents. */
selectedLines = textArea.getSelectedLines();
int[] padding = new int[selectedLines.length];
Arrays.fill(padding, -1);
/*
* Iterate over selected lines, calculating indents.
*
* We calculate all indents prior to actually touching anything so that
* Isabelle doesn't attempt to re-prove the lines we are trying to query at the
* same time.
*/
for (i = 0; i < selectedLines.length; i++) {
line = selectedLines[i];
lineStart = textArea.getLineStartOffset(line);
lineEnd = textArea.getLineEndOffset(line);
/* Fetch the Isabelle state for this line. */
cmd_range = snapshot.node().command_iterator(lineStart - 1);
if (!cmd_range.hasNext())
continue;
cmd = cmd_range.next()._1;
/* Get the number of subgoals of this line. */
cmd_state = snapshot.state().command_states(snapshot.version(), cmd).productElement(0);
subgoals = num_subgoals(cmd_state);
if (shouldIndent(cmd) && subgoals > 0) {
padding[i] = subgoals + 1;
}
}
/* Actually perform the updates. */
buffer.beginCompoundEdit();
try {
for (i = selectedLines.length - 1; i >= 0; i--) {
line = selectedLines[i];
lineStart = textArea.getLineStartOffset(line);
lineEnd = textArea.getLineEndOffset(line);
/* Skip lines that shouldn't be indented. */
if (padding[i] < 0)
continue;
/* Pad out this line. */
text = pad(textArea.getLineText(line).trim(), padding[i]) + "\n";
/* Insert new line. */
textArea.setSelectedText(new Selection.Range(lineStart, lineEnd), text);
}
} finally {
buffer.endCompoundEdit();
}